Files
Nitrox/NitroxClient/MonoBehaviours/CinematicController/RemotePlayerCinematicController.cs
2025-07-06 00:23:46 +02:00

472 lines
12 KiB
C#

using System;
using NitroxClient.GameLogic;
using UnityEngine;
using static PlayerCinematicController;
namespace NitroxClient.MonoBehaviours.CinematicController;
/// <summary>
/// Override for <see cref="PlayerCinematicController"/>
/// </summary>
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<IAnimParamReceiver>()?.ForwardAnimationParameterBool(receiversAnimParam, value);
}
}
if (playerViewAnimationName.Length > 0 && player != null)
{
Animator componentInChildren = player.Body.GetComponentInChildren<Animator>();
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<IAnimParamReceiver>()?.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<Transform>();
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<Transform>();
playerFromPosition = component.position;
playerFromRotation = component.rotation;
if (playerViewInterpolateAnimParam.Length > 0)
{
SafeAnimator.SetBool(player.Body.GetComponentInChildren<Animator>(), 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<Transform>();
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<Transform>();
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<Transform>();
}
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<Animator>(), 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);
}
}
}