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

179 lines
7.5 KiB
C#

using System.Collections;
using NitroxClient.GameLogic;
using NitroxModel.Core;
using UnityEngine;
namespace NitroxClient.MonoBehaviours;
public class IntroCinematicUpdater : MonoBehaviour
{
public static RemotePlayer Partner;
private static Transform modelRoot;
private static readonly Transform playerTransform = Player.main.transform;
private static readonly Quaternion rotateOtherSide = Quaternion.Euler(0, 180, 0);
private Transform introEndTarget;
private Vector3 introRemoteEndPosition;
private Transform[] seatPartsLeft;
private Transform[] seatPartsRight;
private Transform seatArmRestLeft;
private Transform seatArmRestRight;
private SkinnedMeshRenderer[] seatBarRendererRight = [];
private SkinnedMeshRenderer remotePlayerHeadRenderer;
private GameObject remotePlayerCustomHead;
private SkinnedMeshRenderer[] remoteRenders = [];
public void Awake()
{
if (Partner == null)
{
Log.Error($"[{nameof(IntroCinematicUpdater)}.Awake()]: Partner was null. Disabling MonoBehaviour.");
enabled = false;
return;
}
modelRoot = EscapePod.main.transform.Find("models/Life_Pod_damaged_03/root");
Transform seatLeft = modelRoot.Find("life_pod_seat_01_left_damaged_jnt1");
Transform seatRight = modelRoot.Find("life_pod_seat_01_right_damaged_jnt1");
seatPartsLeft = new[]
{
seatLeft.Find("life_pod_seat_01_left_damaged_jnt2"),
seatLeft.Find("life_pod_seat_01_left_damaged_jnt3")
};
seatPartsRight = new[]
{
seatRight.Find("life_pod_seat_01_right_damaged_jnt2"),
seatRight.Find("life_pod_seat_01_right_damaged_jnt3")
};
seatArmRestLeft = modelRoot.Find("life_pod_seat_01_left_damaged_jnt4/life_pod_seat_01_left_damaged_jnt5");
seatArmRestRight = modelRoot.Find("life_pod_seat_01_right_damaged_jnt4/life_pod_seat_01_right_damaged_jnt5");
seatBarRendererRight = modelRoot.parent.Find("lifepod_damaged_03_geo/life_pod_seat_01_R").GetComponentsInChildren<SkinnedMeshRenderer>();
remoteRenders = Partner.PlayerModel.GetComponentsInChildren<SkinnedMeshRenderer>();
remotePlayerHeadRenderer = Partner.PlayerModel.transform.Find("male_geo/diveSuit/diveSuit_head_geo").GetComponent<SkinnedMeshRenderer>();
remotePlayerCustomHead = Instantiate(new GameObject("diveSuit_custom_head_geo"), Partner.PlayerModel.transform.Find("export_skeleton/head_rig"));
remotePlayerCustomHead.transform.localPosition = new Vector3(1.0941f, -0.1163f, -1.2107f);
remotePlayerCustomHead.transform.localRotation = new Quaternion(-0.05750692f, -0.5272675f, -0.6740523f, -0.5141357f);
MeshFilter mesh = remotePlayerCustomHead.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = remotePlayerCustomHead.AddComponent<MeshRenderer>();
mesh.mesh = remotePlayerHeadRenderer.sharedMesh;
meshRenderer.materials = remotePlayerHeadRenderer.materials;
remotePlayerCustomHead.SetActive(false);
bool isLeftPlayer = NitroxServiceLocator.Cache<LocalPlayer>.Value.PlayerId < Partner.PlayerId;
introEndTarget = EscapePod.main.transform.Find("EscapePodCinematics/intro_end");
Vector3 introEndDiff = isLeftPlayer ? new Vector3(0, 0, 0.3f) : new Vector3(0, 0, -0.3f);
introRemoteEndPosition = introEndTarget.position - introEndDiff;
introEndTarget.position += introEndDiff;
}
private Vector3 remotePlayerDestinationPos;
private Quaternion remotePlayerDestinationRot;
private bool shouldDisplaceLocalPlayer;
private float localPlayerDisplacementTime;
private bool shouldDisplaceRemotePlayer;
private Vector3 remotePlayerDisplacement = Vector3.zero;
private IEnumerator Start()
{
remoteRenders.ForEach(smr => smr.enabled = false);
seatBarRendererRight.ForEach(smr => smr.updateWhenOffscreen = true);
yield return new WaitForSecondsRealtime(11f); //Local player in seat
remoteRenders.ForEach(smr => smr.enabled = true);
yield return new WaitForSecondsRealtime(33.45f - 11f); //Remote Player deadly hit => disable original head
remotePlayerHeadRenderer.enabled = false;
yield return new WaitForSecondsRealtime(33.58f - 33.45f); //Remote Player visible => enable custom head
remotePlayerCustomHead.SetActive(true);
yield return new WaitForSecondsRealtime(40f - 33.58f); //Seatbelt appears => enable position sync & switch to original head
remotePlayerCustomHead.SetActive(false);
remotePlayerHeadRenderer.enabled = true;
Destroy(remotePlayerCustomHead);
yield return new WaitForSecondsRealtime(50.5f - 40f); //Slowly move remote player backwards
shouldDisplaceRemotePlayer = true;
yield return new WaitForSecondsRealtime(50.72f - 50.5f); //Disable and move remote player
shouldDisplaceRemotePlayer = false;
remotePlayerDisplacement = Vector3.zero;
remoteRenders.ForEach(smr => smr.enabled = false);
yield return new WaitForSecondsRealtime(53f - 50.72f); //Slowly move local player to modified cin-end
shouldDisplaceLocalPlayer = true;
}
private void LateUpdate()
{
Vector3 modelRootPos = modelRoot.position;
Quaternion modelRootRot = modelRoot.rotation;
// Coping the global rotation, inverting the y and adding 180° to it
Quaternion InverseRotateAroundEscapePod(Quaternion from)
{
Quaternion offset = Quaternion.Inverse(modelRootRot) * from;
return modelRootRot * rotateOtherSide * new Quaternion(-offset.x, offset.y, offset.z, -offset.w);
}
// Mirror animate the remote like the local player
Vector3 posDiff = playerTransform.position - modelRootPos;
remotePlayerDestinationPos = modelRootPos + new Vector3(posDiff.x, posDiff.y, -posDiff.z) + remotePlayerDisplacement;
remotePlayerDestinationRot = InverseRotateAroundEscapePod(playerTransform.rotation);
transform.SetPositionAndRotation(remotePlayerDestinationPos, remotePlayerDestinationRot);
// Mirror animate the seat parts and stop it before the animation ends so the SN animator resets our manipulations
if (!shouldDisplaceLocalPlayer)
{
for (int i = 0; i < seatPartsLeft.Length; i++)
{
seatPartsRight[i].localRotation = seatPartsLeft[i].localRotation;
}
seatArmRestRight.localPosition = -seatArmRestLeft.localPosition;
}
if (shouldDisplaceRemotePlayer) remotePlayerDisplacement += new Vector3(0, 0, 0.05f);
if (shouldDisplaceLocalPlayer)
{
Vector3 introEndTargetPos = introEndTarget.position;
playerTransform.position = Vector3.Lerp(playerTransform.position, introEndTargetPos, localPlayerDisplacementTime);
MainCameraControl.main.transform.position = Vector3.Lerp(MainCameraControl.main.transform.position, introEndTargetPos, localPlayerDisplacementTime);
localPlayerDisplacementTime += 0.01f;
}
}
private void OnDestroy()
{
foreach (SkinnedMeshRenderer renderer in remoteRenders)
{
if (renderer)
{
renderer.enabled = true;
}
}
foreach (SkinnedMeshRenderer renderer in seatBarRendererRight)
{
if (renderer)
{
renderer.updateWhenOffscreen = false;
}
}
transform.position = introRemoteEndPosition;
}
}