diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemSyncManager.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemSyncManager.cs new file mode 100644 index 00000000..29ababc5 --- /dev/null +++ b/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemSyncManager.cs @@ -0,0 +1,15 @@ +using Cysharp.Threading.Tasks; +using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects; +using QSB.WorldSync; +using System.Threading; + +namespace QSB.EchoesOfTheEye.AlarmTotemSync; + +public class SarcophagusManager : WorldObjectManager +{ + public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem; + public override bool DlcOnly => true; + + public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) => + QSBWorldSync.Init(); +} diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetEnabledMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetEnabledMessage.cs new file mode 100644 index 00000000..c8784298 --- /dev/null +++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetEnabledMessage.cs @@ -0,0 +1,12 @@ +using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects; +using QSB.Messaging; + +namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages; + +public class SetEnabledMessage : QSBWorldObjectMessage +{ + public SetEnabledMessage(bool data) : base(data) { } + + public override void OnReceiveRemote() => + WorldObject.SetEnabled(Data); +} diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetFaceOpenMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetFaceOpenMessage.cs new file mode 100644 index 00000000..7cc0a6a2 --- /dev/null +++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetFaceOpenMessage.cs @@ -0,0 +1,13 @@ +using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects; +using QSB.Messaging; +using QSB.Patches; + +namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages; + +public class SetFaceOpenMessage : QSBWorldObjectMessage +{ + public SetFaceOpenMessage(bool data) : base(data) { } + + public override void OnReceiveRemote() => + QSBPatch.RemoteCall(() => WorldObject.AttachedObject.SetFaceOpen(Data)); +} diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs new file mode 100644 index 00000000..7e3b29cc --- /dev/null +++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using QSB.EchoesOfTheEye.AlarmTotemSync.Messages; +using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects; +using QSB.Messaging; +using QSB.Patches; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.AlarmTotemSync.Patches; + +public class AlarmTotemPatches : QSBPatch +{ + public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; + + [HarmonyPrefix] + [HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.SetFaceOpen))] + private static void SetFaceOpen(AlarmTotem __instance, bool open) + { + if (Remote) + { + return; + } + + if (__instance._isFaceOpen == open) + { + return; + } + + if (!QSBWorldSync.AllObjectsReady) + { + return; + } + + __instance.GetWorldObject() + .SendMessage(new SetFaceOpenMessage(open)); + } +} diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs new file mode 100644 index 00000000..d64730fc --- /dev/null +++ b/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs @@ -0,0 +1,45 @@ +using QSB.EchoesOfTheEye.AlarmTotemSync.Messages; +using QSB.Messaging; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects; + +public class QSBAlarmTotem : WorldObject +{ + public override void SendInitialState(uint to) + { + this.SendMessage(new SetFaceOpenMessage(AttachedObject._isFaceOpen) { To = to }); + this.SendMessage(new SetEnabledMessage(AttachedObject.enabled) { To = to }); + } + + public void SetEnabled(bool enabled) + { + if (AttachedObject.enabled == enabled) + { + return; + } + + if (!enabled && + AttachedObject._sector && + AttachedObject._sector.ContainsOccupant(DynamicOccupant.Player)) + { + // local player is in sector, do not disable + return; + } + + AttachedObject.enabled = enabled; + + if (!enabled) + { + AttachedObject._pulseLightController.SetIntensity(0f); + AttachedObject._simTotemMaterials[0] = AttachedObject._origSimEyeMaterial; + AttachedObject._simTotemRenderer.sharedMaterials = AttachedObject._simTotemMaterials; + AttachedObject._simVisionConeRenderer.SetColor(AttachedObject._simVisionConeRenderer.GetOriginalColor()); + if (AttachedObject._isPlayerVisible) + { + AttachedObject._isPlayerVisible = false; + Locator.GetAlarmSequenceController().DecreaseAlarmCounter(); + } + } + } +} diff --git a/QSB/EchoesOfTheEye/DreamLantern/Patches/DreamLanternPatches.cs b/QSB/EchoesOfTheEye/DreamLantern/Patches/DreamLanternPatches.cs index 3bcc50cb..4999684c 100644 --- a/QSB/EchoesOfTheEye/DreamLantern/Patches/DreamLanternPatches.cs +++ b/QSB/EchoesOfTheEye/DreamLantern/Patches/DreamLanternPatches.cs @@ -5,11 +5,6 @@ using QSB.Messaging; using QSB.Patches; using QSB.Player; using QSB.WorldSync; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using UnityEngine; namespace QSB.EchoesOfTheEye.DreamLantern.Patches; @@ -42,9 +37,9 @@ internal class DreamLanternPatches : QSBPatch var isHoldingItem = Locator.GetToolModeSwapper().IsInToolMode(ToolMode.Item); __instance._wasFocusing = __instance._focusing; - __instance._focusing = OWInput.IsPressed(InputLibrary.toolActionPrimary, InputMode.Character, 0f) && Time.time > __instance._forceUnfocusTime + 1f && isHoldingItem; + __instance._focusing = OWInput.IsPressed(InputLibrary.toolActionPrimary, InputMode.Character) && Time.time > __instance._forceUnfocusTime + 1f && isHoldingItem; - var concealActionPressed = OWInput.IsPressed(InputLibrary.toolActionSecondary, InputMode.Character, 0f) && isHoldingItem; + var concealActionPressed = OWInput.IsPressed(InputLibrary.toolActionSecondary, InputMode.Character) && isHoldingItem; if (concealActionPressed && !__instance._lanternController.IsConcealed()) { Locator.GetPlayerAudioController().OnArtifactConceal(); @@ -55,7 +50,7 @@ internal class DreamLanternPatches : QSBPatch { Locator.GetPlayerAudioController().OnArtifactUnconceal(); __instance._lanternController.SetConcealed(false); - new DreamLanternStateMessage(DreamLanternActionType.CONCEAL, false).Send(); + new DreamLanternStateMessage(DreamLanternActionType.CONCEAL).Send(); } if (__instance._focusing != __instance._wasFocusing) @@ -102,6 +97,16 @@ internal class DreamLanternPatches : QSBPatch return; } + if (__instance._lanternController.IsLit() == lit) + { + return; + } + + if (!QSBWorldSync.AllObjectsReady) + { + return; + } + __instance.GetWorldObject().SendMessage(new DreamLanternLitMessage(lit)); } } diff --git a/QSB/EchoesOfTheEye/LightSensorSync/Messages/SetEnabledMessage.cs b/QSB/EchoesOfTheEye/LightSensorSync/Messages/SetEnabledMessage.cs index ea345a9d..df03e1ca 100644 --- a/QSB/EchoesOfTheEye/LightSensorSync/Messages/SetEnabledMessage.cs +++ b/QSB/EchoesOfTheEye/LightSensorSync/Messages/SetEnabledMessage.cs @@ -1,12 +1,10 @@ using QSB.EchoesOfTheEye.LightSensorSync.WorldObjects; using QSB.Messaging; -using QSB.Patches; namespace QSB.EchoesOfTheEye.LightSensorSync.Messages; internal class SetEnabledMessage : QSBWorldObjectMessage { public SetEnabledMessage(bool data) : base(data) { } - public override void OnReceiveRemote() => - QSBPatch.RemoteCall(WorldObject.AttachedObject.OnSectorOccupantsUpdated, Data); + public override void OnReceiveRemote() => WorldObject.SetEnabled(Data); } diff --git a/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs index a45241ae..079932a3 100644 --- a/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs +++ b/QSB/EchoesOfTheEye/LightSensorSync/Patches/LightSensorPatches.cs @@ -19,31 +19,26 @@ internal class LightSensorPatches : QSBPatch [HarmonyPatch(nameof(SingleLightSensor.OnSectorOccupantsUpdated))] private static bool OnSectorOccupantsUpdated(SingleLightSensor __instance) { - var enable = !Remote - ? __instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe) - : (bool)RemoteData; - if (enable && !__instance.enabled) + if (!QSBWorldSync.AllObjectsReady) + { + return true; + } + + var flag = __instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe); + if (flag && !__instance.enabled) { __instance.enabled = true; - if (!Remote && QSBWorldSync.AllObjectsReady) - { - __instance.GetWorldObject().SendMessage(new SetEnabledMessage(true)); - } - + __instance.GetWorldObject().SendMessage(new SetEnabledMessage(true)); __instance._lightDetector.GetShape().enabled = true; if (__instance._preserveStateWhileDisabled) { __instance._fixedUpdateFrameDelayCount = 10; } } - else if (!enable && __instance.enabled) + else if (!flag && __instance.enabled) { __instance.enabled = false; - if (!Remote && QSBWorldSync.AllObjectsReady) - { - __instance.GetWorldObject().SendMessage(new SetEnabledMessage(false)); - } - + __instance.GetWorldObject().SendMessage(new SetEnabledMessage(false)); __instance._lightDetector.GetShape().enabled = false; if (!__instance._preserveStateWhileDisabled) { diff --git a/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBLightSensor.cs b/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBLightSensor.cs index 61148c92..c8b5ca29 100644 --- a/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBLightSensor.cs +++ b/QSB/EchoesOfTheEye/LightSensorSync/WorldObjects/QSBLightSensor.cs @@ -14,4 +14,38 @@ internal class QSBLightSensor : WorldObject public override void SendInitialState(uint to) => this.SendMessage(new SetEnabledMessage(AttachedObject.enabled) { To = to }); + + public void SetEnabled(bool enabled) + { + if (enabled && !AttachedObject.enabled) + { + AttachedObject.enabled = true; + AttachedObject._lightDetector.GetShape().enabled = true; + if (AttachedObject._preserveStateWhileDisabled) + { + AttachedObject._fixedUpdateFrameDelayCount = 10; + } + } + else if (!enabled && AttachedObject.enabled) + { + if (AttachedObject._sector && + AttachedObject._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe)) + { + // local player is in sector, do not disable + return; + } + + AttachedObject.enabled = false; + AttachedObject._lightDetector.GetShape().enabled = false; + if (!AttachedObject._preserveStateWhileDisabled) + { + if (AttachedObject._illuminated) + { + AttachedObject.OnDetectDarkness.Invoke(); + } + + AttachedObject._illuminated = false; + } + } + } } diff --git a/QSB/EchoesOfTheEye/Sarcophagus/Messages/OpenMessage.cs b/QSB/EchoesOfTheEye/Sarcophagus/Messages/OpenMessage.cs new file mode 100644 index 00000000..1a13c105 --- /dev/null +++ b/QSB/EchoesOfTheEye/Sarcophagus/Messages/OpenMessage.cs @@ -0,0 +1,11 @@ +using QSB.EchoesOfTheEye.Sarcophagus.WorldObjects; +using QSB.Messaging; +using QSB.Patches; + +namespace QSB.EchoesOfTheEye.Sarcophagus.Messages; + +public class OpenMessage : QSBWorldObjectMessage +{ + public override void OnReceiveRemote() => + QSBPatch.RemoteCall(WorldObject.AttachedObject.OnPressInteract); +} diff --git a/QSB/EchoesOfTheEye/Sarcophagus/Patches/SarcophagusPatches.cs b/QSB/EchoesOfTheEye/Sarcophagus/Patches/SarcophagusPatches.cs new file mode 100644 index 00000000..d55947fc --- /dev/null +++ b/QSB/EchoesOfTheEye/Sarcophagus/Patches/SarcophagusPatches.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using QSB.EchoesOfTheEye.Sarcophagus.Messages; +using QSB.EchoesOfTheEye.Sarcophagus.WorldObjects; +using QSB.Messaging; +using QSB.Patches; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.Sarcophagus.Patches; + +public class SarcophagusPatches : QSBPatch +{ + public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; + + [HarmonyPrefix] + [HarmonyPatch(typeof(SarcophagusController), nameof(SarcophagusController.OnPressInteract))] + private static void OnPressInteract(SarcophagusController __instance) + { + if (Remote) + { + return; + } + + if (__instance._isOpen) + { + return; + } + + if (!QSBWorldSync.AllObjectsReady) + { + return; + } + + __instance.GetWorldObject() + .SendMessage(new OpenMessage()); + } +} diff --git a/QSB/EchoesOfTheEye/Sarcophagus/SarcophagusManager.cs b/QSB/EchoesOfTheEye/Sarcophagus/SarcophagusManager.cs new file mode 100644 index 00000000..e6484b89 --- /dev/null +++ b/QSB/EchoesOfTheEye/Sarcophagus/SarcophagusManager.cs @@ -0,0 +1,15 @@ +using Cysharp.Threading.Tasks; +using QSB.EchoesOfTheEye.Sarcophagus.WorldObjects; +using QSB.WorldSync; +using System.Threading; + +namespace QSB.EchoesOfTheEye.Sarcophagus; + +public class SarcophagusManager : WorldObjectManager +{ + public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem; + public override bool DlcOnly => true; + + public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) => + QSBWorldSync.Init(); +} diff --git a/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs b/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs new file mode 100644 index 00000000..21adaa72 --- /dev/null +++ b/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs @@ -0,0 +1,16 @@ +using QSB.EchoesOfTheEye.Sarcophagus.Messages; +using QSB.Messaging; +using QSB.WorldSync; + +namespace QSB.EchoesOfTheEye.Sarcophagus.WorldObjects; + +public class QSBSarcophagus : WorldObject +{ + public override void SendInitialState(uint to) + { + if (AttachedObject._isOpen) + { + this.SendMessage(new OpenMessage()); + } + } +} diff --git a/QSB/WorldSync/QSBWorldSync.cs b/QSB/WorldSync/QSBWorldSync.cs index dd74ebd6..f63b07a4 100644 --- a/QSB/WorldSync/QSBWorldSync.cs +++ b/QSB/WorldSync/QSBWorldSync.cs @@ -231,7 +231,7 @@ public static class QSBWorldSync if (!worldObjects.Any(x => x is TWorldObject)) { - DebugLog.ToConsole($"Error - WorldObjectsToUnityObjects does not contain \"{unityObject.name}\"! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Error); + DebugLog.ToConsole($"Error - UnityObjectsToWorldObjects does not contain \"{unityObject.name}\"! TWorldObject:{typeof(TWorldObject).Name}, TUnityObject:{unityObject.GetType().Name}, Stacktrace:\r\n{Environment.StackTrace}", MessageType.Error); return default; }