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(); remoteRenders = Partner.PlayerModel.GetComponentsInChildren(); remotePlayerHeadRenderer = Partner.PlayerModel.transform.Find("male_geo/diveSuit/diveSuit_head_geo").GetComponent(); 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(); MeshRenderer meshRenderer = remotePlayerCustomHead.AddComponent(); mesh.mesh = remotePlayerHeadRenderer.sharedMesh; meshRenderer.materials = remotePlayerHeadRenderer.materials; remotePlayerCustomHead.SetActive(false); bool isLeftPlayer = NitroxServiceLocator.Cache.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; } }