From 79a66952324b02ead43a5ad1e67eaa3cbe7750b6 Mon Sep 17 00:00:00 2001 From: tornac1234 <24827220+tornac1234@users.noreply.github.com> Date: Wed, 1 Jan 2025 15:42:42 +0100 Subject: [PATCH 1/2] Fix keypad sync --- .../Extractor/KeypadMetadataExtractor.cs | 20 +++++++++ .../Processor/KeypadMetadataProcessor.cs | 33 +++++++++----- .../Entities/Metadata/KeypadMetadata.cs | 45 ++++++++++--------- ...ypadDoorConsole_AcceptNumberField_Patch.cs | 20 +++++++-- 4 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 NitroxClient/GameLogic/Spawning/Metadata/Extractor/KeypadMetadataExtractor.cs diff --git a/NitroxClient/GameLogic/Spawning/Metadata/Extractor/KeypadMetadataExtractor.cs b/NitroxClient/GameLogic/Spawning/Metadata/Extractor/KeypadMetadataExtractor.cs new file mode 100644 index 0000000000..e13367d4ba --- /dev/null +++ b/NitroxClient/GameLogic/Spawning/Metadata/Extractor/KeypadMetadataExtractor.cs @@ -0,0 +1,20 @@ +using NitroxClient.GameLogic.Spawning.Metadata.Extractor.Abstract; +using NitroxClient.Unity.Helper; +using NitroxModel.DataStructures.GameLogic.Entities.Metadata; + +namespace NitroxClient.GameLogic.Spawning.Metadata.Extractor; + +public class KeypadMetadataExtractor : EntityMetadataExtractor +{ + public override KeypadMetadata Extract(KeypadDoorConsole keypadDoorConsole) + { + string pathToRoot = string.Empty; + + if (keypadDoorConsole.root) + { + pathToRoot = keypadDoorConsole.gameObject.GetHierarchyPath(keypadDoorConsole.root); + } + + return new(keypadDoorConsole.unlocked, pathToRoot); + } +} diff --git a/NitroxClient/GameLogic/Spawning/Metadata/Processor/KeypadMetadataProcessor.cs b/NitroxClient/GameLogic/Spawning/Metadata/Processor/KeypadMetadataProcessor.cs index 28878294b3..0a202f908c 100644 --- a/NitroxClient/GameLogic/Spawning/Metadata/Processor/KeypadMetadataProcessor.cs +++ b/NitroxClient/GameLogic/Spawning/Metadata/Processor/KeypadMetadataProcessor.cs @@ -8,23 +8,32 @@ public class KeypadMetadataProcessor : EntityMetadataProcessor { public override void ProcessMetadata(GameObject gameObject, KeypadMetadata metadata) { - Log.Debug($"Received keypad metadata change for {gameObject.name} with data of {metadata}"); + GameObject keypadObject = gameObject; - KeypadDoorConsole keypad = gameObject.GetComponent(); - keypad.unlocked = metadata.Unlocked; - - if (metadata.Unlocked) + if (metadata.PathFromRoot.Length > 0) { - if (keypad.root) - { - keypad.root.BroadcastMessage("UnlockDoor"); - } - else + Transform child = gameObject.transform.Find(metadata.PathFromRoot); + if (!child) { - keypad.BroadcastMessage("UnlockDoor"); + Log.Error($"Could not find child at path \"{child}\" from {gameObject}"); + return; } + keypadObject = child.gameObject; + } - keypad.UnlockDoor(); + if (!keypadObject.TryGetComponent(out KeypadDoorConsole keypadDoorConsole)) + { + Log.Error($"Could not find {nameof(KeypadDoorConsole)} on {gameObject}"); + return; + } + + keypadDoorConsole.unlocked = metadata.Unlocked; + + if (metadata.Unlocked) + { + keypadDoorConsole.keypadUI.SetActive(false); + keypadDoorConsole.unlockIcon.SetActive(true); + keypadDoorConsole.AcceptNumberField(); } } } diff --git a/NitroxModel/DataStructures/GameLogic/Entities/Metadata/KeypadMetadata.cs b/NitroxModel/DataStructures/GameLogic/Entities/Metadata/KeypadMetadata.cs index 9e8b600293..f7d622616f 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/Metadata/KeypadMetadata.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/Metadata/KeypadMetadata.cs @@ -1,30 +1,33 @@ -using System; +using System; using System.Runtime.Serialization; using BinaryPack.Attributes; -namespace NitroxModel.DataStructures.GameLogic.Entities.Metadata +namespace NitroxModel.DataStructures.GameLogic.Entities.Metadata; + +[Serializable] +[DataContract] +public class KeypadMetadata : EntityMetadata { - [Serializable] - [DataContract] - public class KeypadMetadata : EntityMetadata - { - [DataMember(Order = 1)] - public bool Unlocked { get; } + [DataMember(Order = 1)] + public bool Unlocked { get; } - [IgnoreConstructor] - protected KeypadMetadata() - { - // Constructor for serialization. Has to be "protected" for json serialization. - } + [DataMember(Order = 2)] + public string PathFromRoot { get; } + + [IgnoreConstructor] + protected KeypadMetadata() + { + // Constructor for serialization. Has to be "protected" for json serialization. + } - public KeypadMetadata(bool unlocked) - { - Unlocked = unlocked; - } + public KeypadMetadata(bool unlocked, string pathFromRoot) + { + Unlocked = unlocked; + PathFromRoot = pathFromRoot; + } - public override string ToString() - { - return $"[KeypadMetadata isOpen: {Unlocked}]"; - } + public override string ToString() + { + return $"[{nameof(KeypadMetadata)} Unlocked: {Unlocked}, PathFromRoot: {PathFromRoot}]"; } } diff --git a/NitroxPatcher/Patches/Dynamic/KeypadDoorConsole_AcceptNumberField_Patch.cs b/NitroxPatcher/Patches/Dynamic/KeypadDoorConsole_AcceptNumberField_Patch.cs index adcac543cb..be628fc33b 100644 --- a/NitroxPatcher/Patches/Dynamic/KeypadDoorConsole_AcceptNumberField_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/KeypadDoorConsole_AcceptNumberField_Patch.cs @@ -1,5 +1,6 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; +using NitroxClient.GameLogic.Spawning.Metadata.Extractor; using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic.Entities.Metadata; using NitroxModel.Helper; @@ -12,10 +13,21 @@ public sealed partial class KeypadDoorConsole_AcceptNumberField_Patch : NitroxPa public static void Postfix(KeypadDoorConsole __instance) { - if (__instance.TryGetIdOrWarn(out NitroxId id)) + KeypadMetadata keypadMetadata = Resolve().Extract(__instance); + + NitroxId entityId; + if (keypadMetadata.PathFromRoot.Length > 0) + { + if (!__instance.root.TryGetIdOrWarn(out entityId)) + { + return; + } + } + else if (!__instance.TryGetIdOrWarn(out entityId)) { - KeypadMetadata keypadMetadata = new(__instance.unlocked); - Resolve().BroadcastMetadataUpdate(id, keypadMetadata); + return; } + + Resolve().BroadcastMetadataUpdate(entityId, keypadMetadata); } } From 146f6a1eac8bce54c2c3bb5aa5fcb15f18a8240f Mon Sep 17 00:00:00 2001 From: tornac1234 <24827220+tornac1234@users.noreply.github.com> Date: Wed, 1 Jan 2025 15:43:54 +0100 Subject: [PATCH 2/2] Fix falling through before the Aurora's entities have spawned --- NitroxClient/GameLogic/Terrain.cs | 21 +++++++++++++++++++-- NitroxClient/MonoBehaviours/Multiplayer.cs | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/NitroxClient/GameLogic/Terrain.cs b/NitroxClient/GameLogic/Terrain.cs index 9876a860d5..288fd342ca 100644 --- a/NitroxClient/GameLogic/Terrain.cs +++ b/NitroxClient/GameLogic/Terrain.cs @@ -2,10 +2,13 @@ using System.Collections.Generic; using NitroxClient.Communication.Abstract; using NitroxClient.Map; +using NitroxClient.Unity.Helper; +using NitroxModel.Core; using NitroxModel.DataStructures.GameLogic; using NitroxModel.Packets; using NitroxModel_Subnautica.DataStructures; using UnityEngine; +using UWE; using WorldStreaming; namespace NitroxClient.GameLogic; @@ -77,11 +80,23 @@ public void UpdateVisibility() } + public static void WaitForEntities() + { + // In case the player is spawned in the air, we need to hold them up while all the entities load around them + if (Player.main && !Player.main.IsUnderwater() && !Player.main.groundMotor.grounded) + { + Player.main.cinematicModeActive = true; + CoroutineHost.StartCoroutine(WaitForWorldLoad(Yielders.WaitFor2Seconds)); + } + } + /// /// Forces world streamer's to load the terrain around the MainCamera and waits until it's done to unfreeze the player. /// - public static IEnumerator WaitForWorldLoad() + public static IEnumerator WaitForWorldLoad(WaitForSeconds initialWait = null) { + Entities entities = NitroxServiceLocator.LocateService(); + // In WorldStreamer.CreateStreamers() three coroutines are created to constantly call UpdateCenter() on the streamers // We force these updates so that the world streamer gets busy instantly WorldStreamer streamerV2 = LargeWorldStreamer.main.streamerV2; @@ -90,7 +105,9 @@ public static IEnumerator WaitForWorldLoad() streamerV2.lowDetailOctreesStreamer.UpdateCenter(streamerV2.streamingCenter); streamerV2.clipmapStreamer.UpdateCenter(streamerV2.streamingCenter); - yield return new WaitUntil(() => LargeWorldStreamer.main.IsWorldSettled()); + yield return initialWait; + + yield return new WaitUntil(() => LargeWorldStreamer.main.IsWorldSettled() && entities.EntitiesToSpawn.Count == 0); Player.main.cinematicModeActive = false; } } diff --git a/NitroxClient/MonoBehaviours/Multiplayer.cs b/NitroxClient/MonoBehaviours/Multiplayer.cs index 7c21778c87..64a7fe9fd5 100644 --- a/NitroxClient/MonoBehaviours/Multiplayer.cs +++ b/NitroxClient/MonoBehaviours/Multiplayer.cs @@ -199,6 +199,8 @@ private static void SetLoadingComplete() LoadingScreenVersionText.DisableWarningText(); DiscordClient.InitializeRPInGame(Main.multiplayerSession.AuthenticationContext.Username, remotePlayerManager.GetTotalPlayerCount(), Main.multiplayerSession.SessionPolicy.MaxConnections); CoroutineHost.StartCoroutine(NitroxServiceLocator.LocateService().LoadChatKeyHint()); + + GameLogic.Terrain.WaitForEntities(); } private IEnumerator InitializeLocalPlayerState()