using System; using NitroxClient.GameLogic; using UnityEngine; using static PlayerCinematicController; namespace NitroxClient.MonoBehaviours.CinematicController; /// /// Override for /// public class RemotePlayerCinematicController : MonoBehaviour, IManagedUpdateBehaviour, IManagedLateUpdateBehaviour { [AssertNotNull] public Transform animatedTransform; public GameObject informGameObject; public Transform endTransform; public bool onlyUseEndTransformInVr; public bool playInVr; public string playerViewAnimationName = ""; public string playerViewInterpolateAnimParam = ""; public string animParam = "cinematicMode"; public string interpolateAnimParam = ""; public float interpolationTime = 0.25f; public float interpolationTimeOut = 0.25f; public string receiversAnimParam = ""; public GameObject[] animParamReceivers; public bool interpolateDuringAnimation; public bool debug; public Animator animator; [NonSerialized] public bool cinematicModeActive; private Vector3 playerFromPosition = Vector3.zero; private Quaternion playerFromRotation = Quaternion.identity; private bool onCinematicModeEndCall; private float timeStateChanged; private State _state; private RemotePlayer player; private bool subscribed; private bool _animState; public static int cinematicModeCount { get; private set; } public static float cinematicActivityStart { get; private set; } private State state { get => _state; set { timeStateChanged = Time.time; _state = value; } } public bool animState { get => _animState; private set { if (value == _animState) { return; } if (debug) { Debug.Log($"setting cinematic controller {gameObject.name} to: {value}"); } _animState = value; if (animParam.Length > 0) { SafeAnimator.SetBool(animator, animParam, value); } if (receiversAnimParam.Length > 0) { for (int i = 0; i < animParamReceivers.Length; i++) { animParamReceivers[i].GetComponent()?.ForwardAnimationParameterBool(receiversAnimParam, value); } } if (playerViewAnimationName.Length > 0 && player != null) { Animator componentInChildren = player.Body.GetComponentInChildren(); if (componentInChildren != null && componentInChildren.gameObject.activeInHierarchy) { SafeAnimator.SetBool(componentInChildren, playerViewAnimationName, value); } } SetVrActiveParam(); } } public int managedUpdateIndex { get; set; } public int managedLateUpdateIndex { get; set; } public string GetProfileTag() { return nameof(RemotePlayerCinematicController); } public void SetPlayer(RemotePlayer setplayer) { if (subscribed && player != setplayer) { Subscribe(player, false); Subscribe(setplayer, true); } player = setplayer; } public RemotePlayer GetPlayer() { return player; } private void AddToUpdateManager() { BehaviourUpdateUtils.Register((IManagedUpdateBehaviour)this); BehaviourUpdateUtils.Register((IManagedLateUpdateBehaviour)this); } private void RemoveFromUpdateManager() { BehaviourUpdateUtils.Deregister((IManagedUpdateBehaviour)this); BehaviourUpdateUtils.Deregister((IManagedLateUpdateBehaviour)this); } private void OnEnable() { AddToUpdateManager(); } private void OnDestroy() { RemoveFromUpdateManager(); } private void Start() { SetVrActiveParam(); } private void SetVrActiveParam() { string paramaterName = "vr_active"; bool vrAnimationMode = GameOptions.GetVrAnimationMode(); if (animator != null) { animator.SetBool(paramaterName, vrAnimationMode); } foreach (GameObject animatedObject in animParamReceivers) { animatedObject.GetComponent()?.ForwardAnimationParameterBool(paramaterName, vrAnimationMode); } } private bool UseEndTransform() { if (endTransform == null) { return false; } if (onlyUseEndTransformInVr) { return GameOptions.GetVrAnimationMode(); } return true; } private void SkipCinematic(RemotePlayer player) { this.player = player; if (player != null) { Transform component = player.Body.GetComponent(); if (UseEndTransform()) { component.position = endTransform.position; component.rotation = endTransform.rotation; } } if (informGameObject != null) { informGameObject.SendMessage(nameof(CinematicModeTriggerBase.OnPlayerCinematicModeEnd), this, SendMessageOptions.DontRequireReceiver); } } public void StartCinematicMode(RemotePlayer setplayer) { if (debug) { Debug.Log($"{gameObject.name}.StartCinematicMode"); } if (!cinematicModeActive) { player = null; if (!playInVr && GameOptions.GetVrAnimationMode()) { if (debug) { Debug.Log($"{gameObject.name} skip cinematic"); } SkipCinematic(setplayer); return; } animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; cinematicModeActive = true; if (setplayer != null) { SetPlayer(setplayer); Subscribe(player, true); } state = State.In; if (informGameObject != null) { informGameObject.SendMessage(nameof(DockedVehicleHandTarget.OnPlayerCinematicModeStart), this, SendMessageOptions.DontRequireReceiver); } if (player != null) { Transform component = player.Body.GetComponent(); playerFromPosition = component.position; playerFromRotation = component.rotation; if (playerViewInterpolateAnimParam.Length > 0) { SafeAnimator.SetBool(player.Body.GetComponentInChildren(), playerViewInterpolateAnimParam, true); } } if (interpolateAnimParam.Length > 0) { SafeAnimator.SetBool(animator, interpolateAnimParam, true); } if (interpolateDuringAnimation) { animState = true; } if (debug) { Debug.Log($"{gameObject.name} successfully started cinematic"); } if (cinematicModeCount == 0) { cinematicActivityStart = Time.time; } cinematicModeCount++; } else if (debug) { Debug.Log($"{gameObject.name} cinematic already active!"); } } public void EndCinematicMode(bool reset = false) { if (cinematicModeActive) { if (reset) // Added by us { animator.Rebind(); animator.Update(0f); } animator.cullingMode = AnimatorCullingMode.CullCompletely; animState = false; state = State.None; cinematicModeActive = false; cinematicModeCount--; } } public void OnPlayerCinematicModeEnd() { if (!cinematicModeActive || onCinematicModeEndCall) { return; } if (player != null) { UpdatePlayerPosition(); } animState = false; if (UseEndTransform()) { state = State.Out; if (player != null) { Transform component = player.Body.GetComponent(); playerFromPosition = component.position; playerFromRotation = component.rotation; } } else { EndCinematicMode(); } if (informGameObject != null) { onCinematicModeEndCall = true; informGameObject.SendMessage(nameof(DockedVehicleHandTarget.OnPlayerCinematicModeEnd), this, SendMessageOptions.DontRequireReceiver); onCinematicModeEndCall = false; } } private void UpdatePlayerPosition() { Transform component = player.Body.GetComponent(); component.position = animatedTransform.position; component.rotation = animatedTransform.rotation; } public void ManagedLateUpdate() { if (!cinematicModeActive) { return; } float num = Time.time - timeStateChanged; float timedOutScalar; Transform transform = null; if (player != null && player.Body) { transform = player.Body.GetComponent(); } bool isVrAnimationMode = !GameOptions.GetVrAnimationMode(); switch (state) { case State.In: timedOutScalar = interpolationTime != 0f && isVrAnimationMode ? Mathf.Clamp01(num / interpolationTime) : 1f; if (player != null && transform) { transform.position = Vector3.Lerp(playerFromPosition, animatedTransform.position, timedOutScalar); transform.rotation = Quaternion.Slerp(playerFromRotation, animatedTransform.rotation, timedOutScalar); } if (timedOutScalar == 1f) { state = State.Update; animState = true; if (interpolateAnimParam.Length > 0) { SafeAnimator.SetBool(animator, interpolateAnimParam, false); } if (playerViewInterpolateAnimParam.Length > 0 && player != null) { SafeAnimator.SetBool(player.Body.GetComponentInChildren(), playerViewInterpolateAnimParam, false); } } break; case State.Update: if (player != null) { UpdatePlayerPosition(); } break; case State.Out: timedOutScalar = interpolationTimeOut != 0f && isVrAnimationMode ? Mathf.Clamp01(num / interpolationTimeOut) : 1f; if (player != null && transform) { transform.position = Vector3.Lerp(playerFromPosition, endTransform.position, timedOutScalar); transform.rotation = Quaternion.Slerp(playerFromRotation, endTransform.rotation, timedOutScalar); } if (timedOutScalar == 1f) { EndCinematicMode(); } break; } } public bool IsCinematicModeActive() { return cinematicModeActive; } private void OnDisable() { RemoveFromUpdateManager(); if (subscribed) { Subscribe(player, false); } EndCinematicMode(); } private void OnPlayerDeath(RemotePlayer player) { EndCinematicMode(); animator.Rebind(); } private void Subscribe(RemotePlayer player, bool state) { if (player == null) { subscribed = false; } else if (subscribed != state) { if (state) { player.PlayerDeathEvent.AddHandler(gameObject, OnPlayerDeath); } else { player.PlayerDeathEvent.RemoveHandler(gameObject, OnPlayerDeath); } subscribed = state; } } public void ManagedUpdate() { if (!cinematicModeActive && subscribed) { Subscribe(player, false); } } }