diff --git a/QSB/Anglerfish/Patches/AnglerPatches.cs b/QSB/Anglerfish/Patches/AnglerPatches.cs index 5cdfda1d..56f2f349 100644 --- a/QSB/Anglerfish/Patches/AnglerPatches.cs +++ b/QSB/Anglerfish/Patches/AnglerPatches.cs @@ -53,6 +53,7 @@ namespace QSB.Anglerfish.Patches { return true; } + var qsbAngler = __instance.GetWorldObject(); switch (__instance._currentState) @@ -64,6 +65,7 @@ namespace QSB.Anglerfish.Patches qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } + break; case AnglerfishController.AnglerState.Chasing: if (qsbAngler.TargetTransform == null) @@ -72,6 +74,7 @@ namespace QSB.Anglerfish.Patches qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } + if ((qsbAngler.TargetTransform.position - __instance._anglerBody.GetPosition()).sqrMagnitude > __instance._escapeDistance * __instance._escapeDistance) { qsbAngler.TargetTransform = null; @@ -79,6 +82,7 @@ namespace QSB.Anglerfish.Patches qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } + break; case AnglerfishController.AnglerState.Consuming: if (!__instance._consumeComplete) @@ -89,6 +93,7 @@ namespace QSB.Anglerfish.Patches qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } + var num = Time.time - __instance._consumeStartTime; if (qsbAngler.TargetTransform.CompareTag("Player") && num > __instance._consumeDeathDelay) { @@ -96,18 +101,21 @@ namespace QSB.Anglerfish.Patches __instance._consumeComplete = true; return false; } + if (qsbAngler.TargetTransform.CompareTag("Ship")) { if (num > __instance._consumeShipCrushDelay) { qsbAngler.TargetTransform.GetComponentInChildren().TriggerSystemFailure(); } + if (num > __instance._consumeDeathDelay) { if (PlayerState.IsInsideShip()) { Locator.GetDeathManager().KillPlayer(DeathType.Digestion); } + __instance._consumeComplete = true; return false; } @@ -118,6 +126,7 @@ namespace QSB.Anglerfish.Patches qsbAngler.TargetTransform = null; qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); } + break; case AnglerfishController.AnglerState.Stunned: __instance._stunTimer -= Time.deltaTime; @@ -129,9 +138,11 @@ namespace QSB.Anglerfish.Patches qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } + __instance.ChangeState(AnglerfishController.AnglerState.Lurking); qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); } + break; default: return false; @@ -148,6 +159,7 @@ namespace QSB.Anglerfish.Patches { return true; } + var qsbAngler = __instance.GetWorldObject(); qsbAngler.UpdateTargetVelocity(); @@ -155,6 +167,7 @@ namespace QSB.Anglerfish.Patches { __instance.ApplyDrag(10f); } + switch (__instance._currentState) { case AnglerfishController.AnglerState.Lurking: @@ -169,6 +182,7 @@ namespace QSB.Anglerfish.Patches __instance.MoveTowardsTarget(targetPos, __instance._investigateSpeed, __instance._acceleration); return false; } + break; } case AnglerfishController.AnglerState.Chasing: @@ -200,6 +214,7 @@ namespace QSB.Anglerfish.Patches d = Mathf.Lerp(num4, 0f, num8 * num8); } } + __instance._targetPos = qsbAngler.TargetTransform.position + normalized * d; __instance.RotateTowardsTarget(__instance._targetPos, __instance._turnSpeed, __instance._quickTurnSpeed); if (!__instance._turningInPlace) @@ -207,6 +222,7 @@ namespace QSB.Anglerfish.Patches __instance.MoveTowardsTarget(__instance._targetPos, __instance._chaseSpeed, __instance._acceleration); return false; } + break; } case AnglerfishController.AnglerState.Consuming: @@ -254,6 +270,7 @@ namespace QSB.Anglerfish.Patches { return false; } + if ((noiseMaker.GetNoiseOrigin() - __instance.transform.position).sqrMagnitude < __instance._pursueDistance * __instance._pursueDistance) { if (qsbAngler.TargetTransform != noiseMaker.GetAttachedBody().transform) @@ -263,6 +280,7 @@ namespace QSB.Anglerfish.Patches { __instance.ChangeState(AnglerfishController.AnglerState.Chasing); } + qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); return false; } @@ -274,6 +292,7 @@ namespace QSB.Anglerfish.Patches { __instance.ChangeState(AnglerfishController.AnglerState.Investigating); } + qsbAngler.SendMessage(new AnglerChangeStateMessage(qsbAngler)); } @@ -293,8 +312,10 @@ namespace QSB.Anglerfish.Patches { Locator.GetDeathManager().KillPlayer(DeathType.Digestion); } + return false; } + if (caughtBody.CompareTag("Player") || caughtBody.CompareTag("Ship")) { qsbAngler.TargetTransform = caughtBody.transform; diff --git a/QSB/Anglerfish/TransformSync/AnglerTransformSync.cs b/QSB/Anglerfish/TransformSync/AnglerTransformSync.cs index 7bbecba3..29cbbb95 100644 --- a/QSB/Anglerfish/TransformSync/AnglerTransformSync.cs +++ b/QSB/Anglerfish/TransformSync/AnglerTransformSync.cs @@ -35,6 +35,7 @@ namespace QSB.Anglerfish.TransformSync { NetIdentity.UnregisterAuthQueue(); } + AttachedObject.OnUnsuspendOWRigidbody -= OnUnsuspend; AttachedObject.OnSuspendOWRigidbody -= OnSuspend; } @@ -53,6 +54,7 @@ namespace QSB.Anglerfish.TransformSync { NetIdentity.RegisterAuthQueue(); } + AttachedObject.OnUnsuspendOWRigidbody += OnUnsuspend; AttachedObject.OnSuspendOWRigidbody += OnSuspend; NetIdentity.SendAuthQueueMessage(AttachedObject.IsSuspended() ? AuthQueueAction.Remove : AuthQueueAction.Add); diff --git a/QSB/Animation/NPC/Patches/CharacterAnimationPatches.cs b/QSB/Animation/NPC/Patches/CharacterAnimationPatches.cs index 2337ea54..1c9f6caa 100644 --- a/QSB/Animation/NPC/Patches/CharacterAnimationPatches.cs +++ b/QSB/Animation/NPC/Patches/CharacterAnimationPatches.cs @@ -110,6 +110,7 @@ namespace QSB.Animation.NPC.Patches var qsbObj = __instance.GetWorldObject(); new EnterLeaveMessage(EnterLeaveType.EnterNonNomaiHeadZone, qsbObj.ObjectId).Send(); } + return false; } diff --git a/QSB/Animation/NPC/Patches/SolanumPatches.cs b/QSB/Animation/NPC/Patches/SolanumPatches.cs index 3bd3cc54..08f43fa4 100644 --- a/QSB/Animation/NPC/Patches/SolanumPatches.cs +++ b/QSB/Animation/NPC/Patches/SolanumPatches.cs @@ -63,6 +63,7 @@ namespace QSB.Animation.NPC.Patches var qsbObj = __instance._solanumAnimController.GetWorldObject(); new EnterLeaveMessage(EnterLeaveType.ExitNomaiHeadZone, qsbObj.ObjectId).Send(); } + return false; } diff --git a/QSB/Animation/NPC/Patches/TravelerControllerPatches.cs b/QSB/Animation/NPC/Patches/TravelerControllerPatches.cs index 7f448135..516604e6 100644 --- a/QSB/Animation/NPC/Patches/TravelerControllerPatches.cs +++ b/QSB/Animation/NPC/Patches/TravelerControllerPatches.cs @@ -32,7 +32,6 @@ namespace QSB.Animation.NPC.Patches return false; } - [HarmonyPrefix] [HarmonyPatch(typeof(TravelerController), nameof(TravelerController.StartConversation))] public static bool StartConversation(TravelerController __instance) @@ -44,6 +43,7 @@ namespace QSB.Animation.NPC.Patches : __instance._animator.GetCurrentAnimatorStateInfo(0).fullPathHash; __instance._animator.SetTrigger("Talking"); } + Locator.GetTravelerAudioManager().StopTravelerAudio(__instance); return false; @@ -58,6 +58,7 @@ namespace QSB.Animation.NPC.Patches __instance._animator.CrossFadeInFixedTime("Gabbro_Talking", 1.8f); __instance._hammockAnimator.CrossFadeInFixedTime("GabbroHammock_Talking", 1.8f); } + Locator.GetTravelerAudioManager().StopTravelerAudio(__instance); return false; @@ -78,6 +79,7 @@ namespace QSB.Animation.NPC.Patches __instance._animator.SetTrigger("Playing"); } } + Locator.GetTravelerAudioManager().PlayTravelerAudio(__instance, audioDelay); return false; @@ -92,6 +94,7 @@ namespace QSB.Animation.NPC.Patches __instance._animator.CrossFadeInFixedTime("Gabbro_Playing", audioDelay, -1, -audioDelay); __instance._hammockAnimator.CrossFadeInFixedTime("GabbroHammock_Playing", audioDelay, -1, -audioDelay); } + Locator.GetTravelerAudioManager().PlayTravelerAudio(__instance, audioDelay); if (DialogueConditionManager.SharedInstance.GetConditionState("MAP_PROMPT_REMINDER") || DialogueConditionManager.SharedInstance.GetConditionState("MAP_PROMPT_ATTENTION")) { diff --git a/QSB/ClientServerStateSync/ClientStateManager.cs b/QSB/ClientServerStateSync/ClientStateManager.cs index e7f7f32d..34195bf4 100644 --- a/QSB/ClientServerStateSync/ClientStateManager.cs +++ b/QSB/ClientServerStateSync/ClientStateManager.cs @@ -135,6 +135,7 @@ namespace QSB.ClientServerStateSync { newState = ClientState.AliveInEye; } + break; default: newState = ClientState.NotLoaded; diff --git a/QSB/DeathSync/Messages/PlayerDeathMessage.cs b/QSB/DeathSync/Messages/PlayerDeathMessage.cs index f6b97b9b..61b5d765 100644 --- a/QSB/DeathSync/Messages/PlayerDeathMessage.cs +++ b/QSB/DeathSync/Messages/PlayerDeathMessage.cs @@ -11,7 +11,11 @@ namespace QSB.DeathSync.Messages { private int NecronomiconIndex; - public PlayerDeathMessage(DeathType type) => NecronomiconIndex = Necronomicon.GetRandomIndex(type); + public PlayerDeathMessage(DeathType type) + { + Value = type; + NecronomiconIndex = Necronomicon.GetRandomIndex(type); + } public override void Serialize(QNetworkWriter writer) { @@ -37,7 +41,7 @@ namespace QSB.DeathSync.Messages var player = QSBPlayerManager.GetPlayer(From); var playerName = player.Name; var deathMessage = Necronomicon.GetPhrase(Value, NecronomiconIndex); - if (deathMessage != string.Empty) + if (deathMessage != null) { DebugLog.ToAll(string.Format(deathMessage, playerName)); } diff --git a/QSB/DeathSync/Necronomicon.cs b/QSB/DeathSync/Necronomicon.cs index ee66ac9f..4b3e7fe4 100644 --- a/QSB/DeathSync/Necronomicon.cs +++ b/QSB/DeathSync/Necronomicon.cs @@ -144,11 +144,13 @@ namespace QSB.DeathSync }; public static string GetPhrase(DeathType deathType, int index) - => !Darkhold.ContainsKey(deathType) - ? string.Empty - : Darkhold[deathType][index]; + => Darkhold.ContainsKey(deathType) + ? Darkhold[deathType][index] + : null; public static int GetRandomIndex(DeathType deathType) - => new Random().Next(0, Darkhold[deathType].Length); + => Darkhold.ContainsKey(deathType) + ? new Random().Next(0, Darkhold[deathType].Length) + : -1; } } \ No newline at end of file diff --git a/QSB/EyeOfTheUniverse/CosmicInflation/InflationManager.cs b/QSB/EyeOfTheUniverse/CosmicInflation/InflationManager.cs new file mode 100644 index 00000000..fb259a67 --- /dev/null +++ b/QSB/EyeOfTheUniverse/CosmicInflation/InflationManager.cs @@ -0,0 +1,127 @@ +using QSB.Messaging; +using QSB.Player; +using QSB.Player.Messages; +using QSB.Utility; +using QSB.WorldSync; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace QSB.EyeOfTheUniverse.CosmicInflation +{ + internal class InflationManager : WorldObjectManager + { + public static InflationManager Instance { get; private set; } + + private readonly List _playersInFog = new(); + private CosmicInflationController _controller; + + public override WorldObjectType WorldObjectType => WorldObjectType.Eye; + + public override void Awake() + { + base.Awake(); + Instance = this; + + QSBPlayerManager.OnRemovePlayer += OnPlayerLeave; + } + + private void OnPlayerLeave(uint id) + { + _playersInFog.Remove(QSBPlayerManager.GetPlayer(id)); + + // wait 1 frame for player to be removed + QSBCore.UnityEvents.FireOnNextUpdate(() => + { + if (QSBCore.IsInMultiplayer && _playersInFog.Count == QSBPlayerManager.PlayerList.Count) + { + StartCollapse(); + } + }); + } + + protected override void RebuildWorldObjects(OWScene scene) + { + _playersInFog.Clear(); + + if (_controller != null) + { + _controller._smokeSphereTrigger.OnEntry -= OnEntry; + } + + _controller = QSBWorldSync.GetUnityObjects().First(); + _controller._smokeSphereTrigger.OnEntry -= _controller.OnEnterFogSphere; + + _controller._smokeSphereTrigger.OnEntry += OnEntry; + } + + private void OnEntry(GameObject hitObj) + { + if (hitObj.CompareTag("PlayerCameraDetector") && _controller._state == CosmicInflationController.State.ReadyToCollapse) + { + _controller._smokeSphereTrigger.SetTriggerActivation(false); + _controller._probeDestroyTrigger.SetTriggerActivation(false); + new EnterLeaveMessage(EnterLeaveType.EnterCosmicFog).Send(); + + DebugLog.DebugWrite("disable input, wait for other players to enter"); + + var repelVolume = (WhiteHoleFluidVolume)_controller._repelVolume; + repelVolume._flowSpeed = -repelVolume._flowSpeed; + repelVolume._massiveFlowSpeed = -repelVolume._massiveFlowSpeed; + repelVolume.SetVolumeActivation(true); + QSBPlayerManager.HideAllPlayers(); + + ReticleController.Hide(); + Locator.GetFlashlight().TurnOff(false); + Locator.GetPromptManager().SetPromptsVisible(false); + OWInput.ChangeInputMode(InputMode.None); + } + } + + public void Enter(PlayerInfo player) + { + _playersInFog.Add(player); + + if (player != QSBPlayerManager.LocalPlayer) + { + DebugLog.DebugWrite($"fade out player {player.PlayerId}"); + player.DitheringAnimator.SetVisible(false, 3); + } + + if (_playersInFog.Count == QSBPlayerManager.PlayerList.Count) + { + StartCollapse(); + } + } + + private void StartCollapse() + { + DebugLog.DebugWrite("fade in everyone, fog sphere collapse"); + + var repelVolume = (WhiteHoleFluidVolume)_controller._repelVolume; + repelVolume.SetVolumeActivation(false); + QSBPlayerManager.ShowAllPlayers(); + + _controller._state = CosmicInflationController.State.Collapsing; + _controller._stateChangeTime = Time.time; + _controller._collapseStartPos = _controller._possibilitySphereRoot.localPosition; + _controller._smokeSphereTrigger.SetTriggerActivation(false); + _controller._inflationLight.FadeTo(1f, 1f); + _controller._possibilitySphereController.OnCollapse(); + if (_controller._campsiteController.GetUseAltPostCollapseSocket()) + { + _controller._playerPostCollapseSocket = _controller._altPlayerPostCollapseSocket; + _controller._altTravelerToHidePostCollapse.SetActive(false); + } + + Locator.GetPlayerBody().SetPosition(_controller._playerPostCollapseSocket.position); + Locator.GetPlayerBody().SetRotation(_controller._playerPostCollapseSocket.rotation); + Locator.GetPlayerBody().SetVelocity(-_controller._playerPostCollapseSocket.forward); + Locator.GetPlayerTransform().GetRequiredComponent().LockOn(_controller._possibilitySphereRoot, 2f); + foreach (var particles in _controller._smokeSphereParticles) + { + particles.Stop(); + } + } + } +} diff --git a/QSB/EyeOfTheUniverse/CosmicInflation/Patches/InflationPatches.cs b/QSB/EyeOfTheUniverse/CosmicInflation/Patches/InflationPatches.cs new file mode 100644 index 00000000..1d561d09 --- /dev/null +++ b/QSB/EyeOfTheUniverse/CosmicInflation/Patches/InflationPatches.cs @@ -0,0 +1,9 @@ +using QSB.Patches; + +namespace QSB.EyeOfTheUniverse.CosmicInflation.Patches +{ + internal class InflationPatches : QSBPatch + { + public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect; + } +} diff --git a/QSB/EyeOfTheUniverse/EyeStateSync/Messages/EyeStateMessage.cs b/QSB/EyeOfTheUniverse/EyeStateSync/Messages/EyeStateMessage.cs index 90406d4d..7f93814b 100644 --- a/QSB/EyeOfTheUniverse/EyeStateSync/Messages/EyeStateMessage.cs +++ b/QSB/EyeOfTheUniverse/EyeStateSync/Messages/EyeStateMessage.cs @@ -17,7 +17,6 @@ namespace QSB.EyeOfTheUniverse.EyeStateSync.Messages } } - private EyeStateMessage(EyeState state) => Value = state; public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; diff --git a/QSB/EyeOfTheUniverse/EyeStateSync/Messages/FlickerMessage.cs b/QSB/EyeOfTheUniverse/EyeStateSync/Messages/FlickerMessage.cs new file mode 100644 index 00000000..8fe4543c --- /dev/null +++ b/QSB/EyeOfTheUniverse/EyeStateSync/Messages/FlickerMessage.cs @@ -0,0 +1,85 @@ +using QSB.Messaging; +using QSB.Player.TransformSync; +using QSB.Utility; +using QSB.WorldSync; +using QuantumUNET.Transport; +using System; +using UnityEngine; + +namespace QSB.EyeOfTheUniverse.EyeStateSync.Messages +{ + internal class FlickerMessage : QSBMessage + { + static FlickerMessage() => GlobalMessenger.AddListener(OWEvents.FlickerOffAndOn, Handler); + + private static void Handler(float offDuration, float onDuration) + { + if (PlayerTransformSync.LocalInstance) + { + new FlickerMessage(offDuration, onDuration).Send(); + } + } + + private float _offDuration; + private float _onDuration; + + private FlickerMessage(float offDuration, float onDuration) + { + _offDuration = offDuration; + _onDuration = onDuration; + } + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(_offDuration); + writer.Write(_onDuration); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + _offDuration = reader.ReadSingle(); + _onDuration = reader.ReadSingle(); + } + + public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; + + public override void OnReceiveRemote() + { + // manually fire callbacks + var eventTable = GlobalMessenger.eventTable; + lock (eventTable) + { + var eventData = eventTable[OWEvents.FlickerOffAndOn]; + if (eventData.isInvoking) + { + throw new InvalidOperationException("GlobalMessenger does not support recursive FireEvent calls to the same eventType."); + } + + eventData.isInvoking = true; + eventData.temp.AddRange(eventData.callbacks); + foreach (var callback in eventData.temp) + { + // ignore callback for this message to prevent infinite loop + if (callback == Handler) + { + continue; + } + + try + { + callback(_offDuration, _onDuration); + } + catch (Exception exception) + { + Debug.LogException(exception); + } + } + + eventData.temp.Clear(); + eventData.isInvoking = false; + } + } + } +} diff --git a/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/EyeCloneSeenMessage.cs b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/EyeCloneSeenMessage.cs new file mode 100644 index 00000000..53125d83 --- /dev/null +++ b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/EyeCloneSeenMessage.cs @@ -0,0 +1,22 @@ +using QSB.Messaging; +using QSB.Utility; +using QSB.WorldSync; +using System.Linq; +using UnityEngine; + +namespace QSB.EyeOfTheUniverse.ForestOfGalaxies.Messages +{ + internal class EyeCloneSeenMessage : QSBMessage + { + + public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; + + public override void OnReceiveRemote() + { + var controller = QSBWorldSync.GetUnityObjects().First(); + + controller._warpFlickerActivated = true; + controller._warpTime = Time.time + 0.5f; + } + } +} diff --git a/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/KillGalaxiesMessage.cs b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/KillGalaxiesMessage.cs index 42be5ff6..9be60d1b 100644 --- a/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/KillGalaxiesMessage.cs +++ b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Messages/KillGalaxiesMessage.cs @@ -9,12 +9,10 @@ namespace QSB.EyeOfTheUniverse.ForestOfGalaxies.Messages { internal class KillGalaxiesMessage : QSBMessage { - private List _deathDelays = new(); + private List _deathDelays; public KillGalaxiesMessage(List deathDelays) => _deathDelays = deathDelays; - public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; - public override void Serialize(QNetworkWriter writer) { base.Serialize(writer); @@ -29,20 +27,22 @@ namespace QSB.EyeOfTheUniverse.ForestOfGalaxies.Messages { base.Deserialize(reader); var length = reader.ReadInt32(); - _deathDelays = new List(); + _deathDelays = new List(length); for (var i = 0; i < length; i++) { _deathDelays.Add(reader.ReadSingle()); } } + public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; + public override void OnReceiveRemote() { var galaxyController = QSBWorldSync.GetUnityObjects().First(); galaxyController._killTrigger.OnEntry -= galaxyController.OnEnterKillTrigger; - galaxyController._galaxies = galaxyController.GetComponentsInChildren(true); + galaxyController._galaxies = galaxyController.GetComponentsInChildren(true); for (var i = 0; i < galaxyController._galaxies.Length; i++) { galaxyController._galaxies[i].DieAfterSeconds(_deathDelays[i], true, AudioType.EyeGalaxyBlowAway); @@ -52,7 +52,7 @@ namespace QSB.EyeOfTheUniverse.ForestOfGalaxies.Messages galaxyController.enabled = true; galaxyController._musicSource.SetLocalVolume(0f); - galaxyController._musicSource.FadeIn(5f, false, false, 1f); + galaxyController._musicSource.FadeIn(5f); } } } diff --git a/QSB/EyeOfTheUniverse/ForestOfGalaxies/Patches/ForestPatches.cs b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Patches/ForestPatches.cs index 7519b0a1..7d9edfc0 100644 --- a/QSB/EyeOfTheUniverse/ForestOfGalaxies/Patches/ForestPatches.cs +++ b/QSB/EyeOfTheUniverse/ForestOfGalaxies/Patches/ForestPatches.cs @@ -69,21 +69,52 @@ namespace QSB.EyeOfTheUniverse.ForestOfGalaxies.Patches [HarmonyPatch(typeof(MiniGalaxyController), nameof(MiniGalaxyController.KillGalaxies))] public static bool KillGalaxiesReplacement(MiniGalaxyController __instance) { - var num = 60f; + const float delay = 60f; __instance._galaxies = __instance.GetComponentsInChildren(true); var delayList = new List(); - for (var i = 0; i < __instance._galaxies.Length; i++) + foreach (var galaxy in __instance._galaxies) { - var rnd = Random.Range(30f, num); + var rnd = Random.Range(30f, delay); delayList.Add(rnd); - __instance._galaxies[i].DieAfterSeconds(rnd, true, AudioType.EyeGalaxyBlowAway); + galaxy.DieAfterSeconds(rnd, true, AudioType.EyeGalaxyBlowAway); } - new KillGalaxiesMessage(delayList).Send(); - __instance._forestIsDarkTime = Time.time + num + 5f; + new KillGalaxiesMessage(delayList).Send(); + __instance._forestIsDarkTime = Time.time + delay + 5f; __instance.enabled = true; return false; } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PlayerCloneController), nameof(PlayerCloneController.FixedUpdate))] + public static bool CloneFixedUpdate(PlayerCloneController __instance) + { + var playerTransform = Locator.GetPlayerTransform(); + var vector = __instance.transform.parent.InverseTransformPoint(playerTransform.position); + var b = __instance._localMirrorPos - vector; + var position = __instance._localMirrorPos + b; + position.y = vector.y; + __instance.transform.position = __instance.transform.parent.TransformPoint(position); + var normalized = (__instance.transform.position - playerTransform.position).normalized; + var forward = Vector3.Reflect(playerTransform.forward, normalized); + var upwards = Vector3.Reflect(playerTransform.up, normalized); + __instance.transform.rotation = Quaternion.LookRotation(forward, upwards); + var num = Vector3.Distance(__instance.transform.position, playerTransform.position); + if (!__instance._warpFlickerActivated && num < 10f) + { + __instance._warpFlickerActivated = true; + __instance._warpTime = Time.time + 0.5f; + GlobalMessenger.FireEvent(OWEvents.FlickerOffAndOn, 0.5f, 0.5f); + new EyeCloneSeenMessage().Send(); + } + + if (__instance._warpPlayerNextFrame) + { + __instance.WarpPlayerToCampfire(); + } + + return false; + } } } diff --git a/QSB/EyeOfTheUniverse/GalaxyMap/QSBCharacterDialogueTree.cs b/QSB/EyeOfTheUniverse/GalaxyMap/QSBCharacterDialogueTree.cs index 388f1d3c..9dd6ebfb 100644 --- a/QSB/EyeOfTheUniverse/GalaxyMap/QSBCharacterDialogueTree.cs +++ b/QSB/EyeOfTheUniverse/GalaxyMap/QSBCharacterDialogueTree.cs @@ -22,7 +22,6 @@ namespace QSB.EyeOfTheUniverse.GalaxyMap private DialogueBoxVer2 _currentDialogueBox; private bool _wasFlashlightOn; private bool _timeFrozen; - private bool _isRecording; private const string SIGN_NAME = "SIGN"; private const string RECORDING_NAME = "RECORDING"; @@ -356,7 +355,7 @@ namespace QSB.EyeOfTheUniverse.GalaxyMap Locator.GetToolModeSwapper().UnequipTool(); GlobalMessenger.FireEvent("EnterConversation"); - Locator.GetPlayerAudioController().PlayDialogueEnter(_isRecording); + Locator.GetPlayerAudioController().PlayDialogueEnter(); _wasFlashlightOn = Locator.GetFlashlight().IsFlashlightOn(); if (_wasFlashlightOn && _turnOffFlashlight) { @@ -394,7 +393,7 @@ namespace QSB.EyeOfTheUniverse.GalaxyMap _interactVolume.ResetInteraction(); Locator.GetPlayerTransform().GetRequiredComponent().BreakLock(); GlobalMessenger.FireEvent("ExitConversation"); - Locator.GetPlayerAudioController().PlayDialogueExit(_isRecording); + Locator.GetPlayerAudioController().PlayDialogueExit(); if (_wasFlashlightOn && _turnOffFlashlight && _turnOnFlashlight) { Locator.GetFlashlight().TurnOn(false); diff --git a/QSB/EyeOfTheUniverse/VesselSync/VesselManager.cs b/QSB/EyeOfTheUniverse/VesselSync/VesselManager.cs index 867a4990..df1313cc 100644 --- a/QSB/EyeOfTheUniverse/VesselSync/VesselManager.cs +++ b/QSB/EyeOfTheUniverse/VesselSync/VesselManager.cs @@ -3,6 +3,7 @@ using QSB.Player; using QSB.Player.Messages; using QSB.WorldSync; using System.Collections.Generic; +using System.Linq; using UnityEngine; namespace QSB.EyeOfTheUniverse.VesselSync @@ -24,13 +25,15 @@ namespace QSB.EyeOfTheUniverse.VesselSync protected override void RebuildWorldObjects(OWScene scene) { + _playersInCage.Clear(); + if (_warpController != null) { _warpController._cageTrigger.OnEntry -= OnEntry; _warpController._cageTrigger.OnExit -= OnExit; } - _warpController = FindObjectOfType(); + _warpController = QSBWorldSync.GetUnityObjects().First(); _warpController._cageTrigger.OnExit -= _warpController.OnExitCageTrigger; _warpController._cageTrigger.OnEntry += OnEntry; @@ -53,7 +56,6 @@ namespace QSB.EyeOfTheUniverse.VesselSync } } - public void Enter(PlayerInfo player) { _playersInCage.Add(player); diff --git a/QSB/JellyfishSync/Patches/JellyfishPatches.cs b/QSB/JellyfishSync/Patches/JellyfishPatches.cs index f84f1bb0..17edbacd 100644 --- a/QSB/JellyfishSync/Patches/JellyfishPatches.cs +++ b/QSB/JellyfishSync/Patches/JellyfishPatches.cs @@ -19,6 +19,7 @@ namespace QSB.JellyfishSync.Patches { return true; } + var qsbJellyfish = __instance.GetWorldObject(); var sqrMagnitude = (__instance._jellyfishBody.GetPosition() - __instance._planetBody.GetPosition()).sqrMagnitude; diff --git a/QSB/JellyfishSync/TransformSync/JellyfishTransformSync.cs b/QSB/JellyfishSync/TransformSync/JellyfishTransformSync.cs index c0c2fe1f..1535a264 100644 --- a/QSB/JellyfishSync/TransformSync/JellyfishTransformSync.cs +++ b/QSB/JellyfishSync/TransformSync/JellyfishTransformSync.cs @@ -36,6 +36,7 @@ namespace QSB.JellyfishSync.TransformSync { NetIdentity.UnregisterAuthQueue(); } + AttachedObject.OnUnsuspendOWRigidbody -= OnUnsuspend; AttachedObject.OnSuspendOWRigidbody -= OnSuspend; } @@ -54,6 +55,7 @@ namespace QSB.JellyfishSync.TransformSync { NetIdentity.RegisterAuthQueue(); } + AttachedObject.OnUnsuspendOWRigidbody += OnUnsuspend; AttachedObject.OnSuspendOWRigidbody += OnSuspend; NetIdentity.SendAuthQueueMessage(AttachedObject.IsSuspended() ? AuthQueueAction.Remove : AuthQueueAction.Add); @@ -138,7 +140,6 @@ namespace QSB.JellyfishSync.TransformSync return true; } - protected override void OnRenderObject() { if (!QSBCore.ShowLinesInDebug diff --git a/QSB/JellyfishSync/WorldObjects/QSBJellyfish.cs b/QSB/JellyfishSync/WorldObjects/QSBJellyfish.cs index 3ca72758..4e6ea16f 100644 --- a/QSB/JellyfishSync/WorldObjects/QSBJellyfish.cs +++ b/QSB/JellyfishSync/WorldObjects/QSBJellyfish.cs @@ -32,7 +32,6 @@ namespace QSB.JellyfishSync.WorldObjects } } - public bool IsRising { get => AttachedObject._isRising; diff --git a/QSB/Menus/MenuManager.cs b/QSB/Menus/MenuManager.cs index e977f0a7..05d1512d 100644 --- a/QSB/Menus/MenuManager.cs +++ b/QSB/Menus/MenuManager.cs @@ -49,6 +49,15 @@ namespace QSB.Menus private void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool isUniverse) { + if (newScene == OWScene.EyeOfTheUniverse) + { + GlobalMessenger.AddListener(OWEvents.EyeStateChanged, OnEyeStateChanged); + } + else + { + GlobalMessenger.RemoveListener(OWEvents.EyeStateChanged, OnEyeStateChanged); + } + if (isUniverse) { InitPauseMenus(); @@ -68,6 +77,7 @@ namespace QSB.Menus _nowLoadingSB = new StringBuilder(); return; } + _nowLoadingSB.Length = 0; } @@ -199,6 +209,14 @@ namespace QSB.Menus DisconnectPopup._labelText.text = popupText; } + private void OnEyeStateChanged(EyeState state) + { + if (state >= EyeState.IntoTheVortex) + { + SetButtonActive(HostButton, false); + } + } + private void MakeTitleMenus() { CreateCommonPopups(); @@ -294,7 +312,13 @@ namespace QSB.Menus private void Connect() { - QSBNetworkManager.Instance.networkAddress = string.Concat((IPPopup as PopupInputMenu).GetInputText().Where(c => !char.IsWhiteSpace(c))); + var address = string.Concat(((PopupInputMenu)IPPopup).GetInputText().Where(c => !char.IsWhiteSpace(c))); + if (address.Length == 0) + { + address = QSBCore.DefaultServerIP; + } + + QSBNetworkManager.Instance.networkAddress = address; QSBNetworkManager.Instance.StartClient(); if (QSBSceneManager.CurrentScene == OWScene.TitleScreen) diff --git a/QSB/Messaging/OWEvents.cs b/QSB/Messaging/OWEvents.cs index 10885c86..f398be38 100644 --- a/QSB/Messaging/OWEvents.cs +++ b/QSB/Messaging/OWEvents.cs @@ -29,5 +29,6 @@ public const string EnterShip = nameof(EnterShip); public const string ExitShip = nameof(ExitShip); public const string EyeStateChanged = nameof(EyeStateChanged); + public const string FlickerOffAndOn = nameof(FlickerOffAndOn); } } diff --git a/QSB/Messaging/QSBMessage.cs b/QSB/Messaging/QSBMessage.cs index 989cc0c0..39a7609b 100644 --- a/QSB/Messaging/QSBMessage.cs +++ b/QSB/Messaging/QSBMessage.cs @@ -47,7 +47,6 @@ namespace QSB.Messaging public override string ToString() => GetType().Name; } - public abstract class QSBBoolMessage : QSBMessage { protected bool Value; diff --git a/QSB/Messaging/QSBMessageManager.cs b/QSB/Messaging/QSBMessageManager.cs index 07383042..75c8650f 100644 --- a/QSB/Messaging/QSBMessageManager.cs +++ b/QSB/Messaging/QSBMessageManager.cs @@ -104,6 +104,7 @@ namespace QSB.Messaging DebugLog.ToConsole($"SendTo unknown player! id: {msg.To}, message: {msg}", MessageType.Error); return; } + conn.Send(msgType, msg); } } @@ -158,7 +159,6 @@ namespace QSB.Messaging #endregion - public static void SendRaw(this M msg) where M : QSBMessageRaw { diff --git a/QSB/Messaging/QSBWorldObjectMessage.cs b/QSB/Messaging/QSBWorldObjectMessage.cs index ccea9e7b..e35b631c 100644 --- a/QSB/Messaging/QSBWorldObjectMessage.cs +++ b/QSB/Messaging/QSBWorldObjectMessage.cs @@ -42,7 +42,6 @@ namespace QSB.Messaging } } - public abstract class QSBBoolWorldObjectMessage : QSBWorldObjectMessage where T : IWorldObject { protected bool Value; diff --git a/QSB/MeteorSync/Patches/MeteorPatches.cs b/QSB/MeteorSync/Patches/MeteorPatches.cs index d67881a8..4110675b 100644 --- a/QSB/MeteorSync/Patches/MeteorPatches.cs +++ b/QSB/MeteorSync/Patches/MeteorPatches.cs @@ -168,7 +168,6 @@ namespace QSB.MeteorSync.Patches } } - /// /// client only /// @@ -271,7 +270,6 @@ namespace QSB.MeteorSync.Patches } } - /// /// both server and client /// @@ -320,6 +318,7 @@ namespace QSB.MeteorSync.Patches { return true; } + if (!WorldObjectManager.AllObjectsReady) { return true; diff --git a/QSB/OrbSync/Patches/OrbPatches.cs b/QSB/OrbSync/Patches/OrbPatches.cs index a6aa22bd..6cac6466 100644 --- a/QSB/OrbSync/Patches/OrbPatches.cs +++ b/QSB/OrbSync/Patches/OrbPatches.cs @@ -21,10 +21,12 @@ namespace QSB.OrbSync.Patches { return; } + if (!__instance._isBeingDragged) { return; } + var qsbOrb = __instance.GetWorldObject(); qsbOrb.SendMessage(new OrbDragMessage(true)); } @@ -37,15 +39,18 @@ namespace QSB.OrbSync.Patches { return true; } + if (!__instance._isBeingDragged) { return false; } + var qsbOrb = __instance.GetWorldObject(); if (!qsbOrb.TransformSync.HasAuthority) { return false; } + qsbOrb.SendMessage(new OrbDragMessage(false)); return true; } @@ -58,6 +63,7 @@ namespace QSB.OrbSync.Patches { return true; } + var qsbOrb = __instance.GetWorldObject(); if (!qsbOrb.TransformSync.HasAuthority) { @@ -77,10 +83,12 @@ namespace QSB.OrbSync.Patches { __instance.CancelDrag(); } + if (__instance._orbAudio != null && slot.GetPlayActivationAudio()) { __instance._orbAudio.PlaySlotActivatedClip(); } + qsbOrb.SendMessage(new OrbSlotMessage(slotIndex)); break; } @@ -91,6 +99,7 @@ namespace QSB.OrbSync.Patches __instance._occupiedSlot = null; qsbOrb.SendMessage(new OrbSlotMessage(-1)); } + __instance._owCollider.SetActivation(__instance._occupiedSlot == null || !__instance._occupiedSlot.IsAttractive() || __instance._isBeingDragged); return false; diff --git a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs index 155dc21f..3e737119 100644 --- a/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs +++ b/QSB/OrbSync/TransformSync/NomaiOrbTransformSync.cs @@ -38,6 +38,7 @@ namespace QSB.OrbSync.TransformSync { NetIdentity.UnregisterAuthQueue(); } + _attachedBody.OnUnsuspendOWRigidbody -= OnUnsuspend; _attachedBody.OnSuspendOWRigidbody -= OnSuspend; } @@ -50,6 +51,7 @@ namespace QSB.OrbSync.TransformSync DebugLog.ToConsole($"Error - No orb at index {index}.", MessageType.Error); return; } + _qsbOrb = orb.GetWorldObject(); _qsbOrb.TransformSync = this; @@ -68,6 +70,7 @@ namespace QSB.OrbSync.TransformSync { NetIdentity.RegisterAuthQueue(); } + _attachedBody.OnUnsuspendOWRigidbody += OnUnsuspend; _attachedBody.OnSuspendOWRigidbody += OnSuspend; NetIdentity.SendAuthQueueMessage(_attachedBody.IsSuspended() ? AuthQueueAction.Remove : AuthQueueAction.Add); diff --git a/QSB/OrbSync/WorldObjects/QSBOrb.cs b/QSB/OrbSync/WorldObjects/QSBOrb.cs index 5def3f59..20565b18 100644 --- a/QSB/OrbSync/WorldObjects/QSBOrb.cs +++ b/QSB/OrbSync/WorldObjects/QSBOrb.cs @@ -83,6 +83,7 @@ namespace QSB.OrbSync.WorldObjects { AttachedObject.CancelDrag(); } + if (AttachedObject._orbAudio != null && newSlot.GetPlayActivationAudio()) { AttachedObject._orbAudio.PlaySlotActivatedClip(); diff --git a/QSB/Patches/QSBPatchManager.cs b/QSB/Patches/QSBPatchManager.cs index b4423ce1..a9e47dda 100644 --- a/QSB/Patches/QSBPatchManager.cs +++ b/QSB/Patches/QSBPatchManager.cs @@ -65,6 +65,7 @@ namespace QSB.Patches DebugLog.ToConsole($"Error while patching {patch.GetType().Name} :\r\n{ex}", MessageType.Error); } } + _patchedTypes.Add(type); } diff --git a/QSB/Player/EnterLeaveType.cs b/QSB/Player/EnterLeaveType.cs index eef74267..672dc875 100644 --- a/QSB/Player/EnterLeaveType.cs +++ b/QSB/Player/EnterLeaveType.cs @@ -15,6 +15,7 @@ EnterNomaiHeadZone = 10, ExitNomaiHeadZone = 11, EnterVesselCage = 12, - ExitVesselCage = 13 + ExitVesselCage = 13, + EnterCosmicFog = 14, } } diff --git a/QSB/Player/Messages/EnterLeaveMessage.cs b/QSB/Player/Messages/EnterLeaveMessage.cs index 4e7be642..3c133d99 100644 --- a/QSB/Player/Messages/EnterLeaveMessage.cs +++ b/QSB/Player/Messages/EnterLeaveMessage.cs @@ -1,5 +1,6 @@ using OWML.Common; using QSB.Animation.NPC.WorldObjects; +using QSB.EyeOfTheUniverse.CosmicInflation; using QSB.EyeOfTheUniverse.VesselSync; using QSB.Messaging; using QSB.Player.TransformSync; @@ -29,7 +30,6 @@ namespace QSB.Player.Messages } } - private int ObjectId; public EnterLeaveMessage(EnterLeaveType type, int objectId = -1) @@ -103,6 +103,9 @@ namespace QSB.Player.Messages case EnterLeaveType.ExitVesselCage: VesselManager.Instance.Exit(player); break; + case EnterLeaveType.EnterCosmicFog: + InflationManager.Instance.Enter(player); + break; default: DebugLog.ToConsole($"Warning - Unknown EnterLeaveType : {Value}", MessageType.Warning); break; diff --git a/QSB/Player/Messages/PlayerJoinMessage.cs b/QSB/Player/Messages/PlayerJoinMessage.cs index e43a9245..58d4fb43 100644 --- a/QSB/Player/Messages/PlayerJoinMessage.cs +++ b/QSB/Player/Messages/PlayerJoinMessage.cs @@ -75,7 +75,7 @@ namespace QSB.Player.Messages return; } - if (QSBPlayerManager.PlayerList.Any(x => x.EyeState > EyeState.WarpedToSurface)) + if (QSBPlayerManager.PlayerList.Any(x => x.EyeState >= EyeState.IntoTheVortex)) { DebugLog.ToConsole($"Error - Client {PlayerName} connecting too late into eye scene.", MessageType.Error); new PlayerKickMessage(From, KickReason.InEye).Send(); diff --git a/QSB/Player/PlayerInfo.cs b/QSB/Player/PlayerInfo.cs index 23c65aec..35701ac0 100644 --- a/QSB/Player/PlayerInfo.cs +++ b/QSB/Player/PlayerInfo.cs @@ -35,12 +35,13 @@ namespace QSB.Player public ClientState State { get; set; } public EyeState EyeState { get; set; } public bool IsDead { get; set; } - public bool Visible { get; set; } = true; + public bool Visible => DitheringAnimator != null && DitheringAnimator._visible; public bool IsReady { get; set; } public bool IsInMoon { get; set; } public bool IsInShrine { get; set; } public IQSBQuantumObject EntangledObject { get; set; } public QSBPlayerAudioController AudioController { get; set; } + public DitheringAnimator DitheringAnimator { get; set; } // Body Objects public OWCamera Camera diff --git a/QSB/Player/QSBPlayerManager.cs b/QSB/Player/QSBPlayerManager.cs index 4122f0c3..8d7229a8 100644 --- a/QSB/Player/QSBPlayerManager.cs +++ b/QSB/Player/QSBPlayerManager.cs @@ -88,27 +88,10 @@ namespace QSB.Player => new(Locator.GetFlashlight(), PlayerList.Where(x => x.FlashLight != null).Select(x => x.FlashLight)); public static void ShowAllPlayers() - => PlayerList.Where(x => x != LocalPlayer).ToList().ForEach(x => ChangePlayerVisibility(x.PlayerId, true)); + => PlayerList.Where(x => x != LocalPlayer && x.DitheringAnimator != null).ForEach(x => x.DitheringAnimator.SetVisible(true, 0.5f)); public static void HideAllPlayers() - => PlayerList.Where(x => x != LocalPlayer).ToList().ForEach(x => ChangePlayerVisibility(x.PlayerId, false)); - - public static void ChangePlayerVisibility(uint playerId, bool visible) - { - var player = GetPlayer(playerId); - player.Visible = visible; - - if (player.Body == null) - { - DebugLog.ToConsole($"Warning - Player {playerId} has a null player model!", MessageType.Warning); - return; - } - - foreach (var renderer in player.Body.GetComponentsInChildren()) - { - renderer.enabled = visible; - } - } + => PlayerList.Where(x => x != LocalPlayer && x.DitheringAnimator != null).ForEach(x => x.DitheringAnimator.SetVisible(false, 0.5f)); public static PlayerInfo GetClosestPlayerToWorldPoint(Vector3 worldPoint, bool includeLocalPlayer) => includeLocalPlayer ? GetClosestPlayerToWorldPoint(PlayerList, worldPoint) diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs index fb4529ac..77c4c105 100644 --- a/QSB/Player/TransformSync/PlayerTransformSync.cs +++ b/QSB/Player/TransformSync/PlayerTransformSync.cs @@ -166,11 +166,9 @@ namespace QSB.Player.TransformSync Player.AnimationSync.InitRemote(REMOTE_Traveller_HEA_Player_v2); Player.InstrumentsManager.InitRemote(REMOTE_Player_Body.transform); - var marker = REMOTE_Player_Body.AddComponent(); - marker.Init(Player); - + REMOTE_Player_Body.AddComponent().Init(Player); REMOTE_Player_Body.AddComponent().PlayerName = Player.Name; - + Player.DitheringAnimator = REMOTE_Player_Body.AddComponent(); Player.AudioController = PlayerAudioManager.InitRemote(REMOTE_Player_Body.transform); /* diff --git a/QSB/QuantumSync/Messages/EyeProxyMoonStateChangeMessage.cs b/QSB/QuantumSync/Messages/EyeProxyMoonStateChangeMessage.cs index 033c1c38..6f29c7db 100644 --- a/QSB/QuantumSync/Messages/EyeProxyMoonStateChangeMessage.cs +++ b/QSB/QuantumSync/Messages/EyeProxyMoonStateChangeMessage.cs @@ -33,7 +33,6 @@ namespace QSB.QuantumSync.Messages public override void OnReceiveRemote() { - DebugLog.DebugWrite($"Get moon state active:{Active} angle:{Angle}"); WorldObject.AttachedObject._moonStateRoot.SetActive(Active); if (Angle != -1f) { diff --git a/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs b/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs index f13c2bf1..a1826a0b 100644 --- a/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs +++ b/QSB/QuantumSync/WorldObjects/QSBQuantumObject.cs @@ -60,7 +60,7 @@ namespace QSB.QuantumSync.WorldObjects { if (shape is BoxShape boxShape) { - var newCube = UnityEngine.Object.Instantiate(cube); + var newCube = Object.Instantiate(cube); newCube.transform.parent = shape.transform; newCube.transform.localPosition = Vector3.zero; newCube.transform.localRotation = Quaternion.Euler(0, 0, 0); @@ -68,7 +68,7 @@ namespace QSB.QuantumSync.WorldObjects } else if (shape is SphereShape sphereShape) { - var newSphere = UnityEngine.Object.Instantiate(sphere); + var newSphere = Object.Instantiate(sphere); newSphere.transform.parent = shape.transform; newSphere.transform.localPosition = Vector3.zero; newSphere.transform.localRotation = Quaternion.Euler(0, 0, 0); @@ -180,33 +180,34 @@ namespace QSB.QuantumSync.WorldObjects ((IQSBQuantumObject)this).SendMessage(new QuantumAuthorityMessage(QSBPlayerManager.LocalPlayerId)); } - private void OnDisable(Shape s) - { - if (!IsEnabled) + private void OnDisable(Shape s) => + // we wait a frame here in case the shapes get disabled as we switch from 1 visibility tracker to another + QSBCore.UnityEvents.FireOnNextUpdate(() => { - return; - } + if (!IsEnabled) + { + return; + } - if (GetAttachedShapes().Any(x => x.isActiveAndEnabled)) - { - return; - } + if (GetAttachedShapes().Any(x => x.isActiveAndEnabled)) + { + return; + } - IsEnabled = false; - if (!WorldObjectManager.AllObjectsReady && !QSBCore.IsHost) - { - return; - } + IsEnabled = false; + if (!WorldObjectManager.AllObjectsReady && !QSBCore.IsHost) + { + return; + } - if (ControllingPlayer != QSBPlayerManager.LocalPlayerId) - { - // not being controlled by us, don't care if we leave area - return; - } + if (ControllingPlayer != QSBPlayerManager.LocalPlayerId) + { + // not being controlled by us, don't care if we leave area + return; + } - var id = ObjectId; - // send event to other players that we're releasing authority - ((IQSBQuantumObject)this).SendMessage(new QuantumAuthorityMessage(0u)); - } + // send event to other players that we're releasing authority + ((IQSBQuantumObject)this).SendMessage(new QuantumAuthorityMessage(0u)); + }); } } diff --git a/QSB/RespawnSync/RespawnManager.cs b/QSB/RespawnSync/RespawnManager.cs index c3aa0177..8e81eb38 100644 --- a/QSB/RespawnSync/RespawnManager.cs +++ b/QSB/RespawnSync/RespawnManager.cs @@ -153,7 +153,14 @@ namespace QSB.RespawnSync return; } - QSBPlayerManager.ChangePlayerVisibility(player.PlayerId, false); + if (player.DitheringAnimator != null) + { + player.DitheringAnimator.SetVisible(false, 1); + } + else + { + DebugLog.ToConsole($"Warning - {player.PlayerId}.DitheringAnimator is null!", OWML.Common.MessageType.Warning); + } } public void OnPlayerRespawn(PlayerInfo player) @@ -169,7 +176,14 @@ namespace QSB.RespawnSync _playersPendingRespawn.Remove(player); UpdateRespawnNotification(); - QSBPlayerManager.ChangePlayerVisibility(player.PlayerId, true); + if (player.DitheringAnimator != null) + { + player.DitheringAnimator.SetVisible(true, 1); + } + else + { + DebugLog.ToConsole($"Warning - {player.PlayerId}.DitheringAnimator is null!", OWML.Common.MessageType.Warning); + } } public void RespawnSomePlayer() diff --git a/QSB/StatueSync/Messages/StartStatueMessage.cs b/QSB/StatueSync/Messages/StartStatueMessage.cs index 5b1e1727..d373c088 100644 --- a/QSB/StatueSync/Messages/StartStatueMessage.cs +++ b/QSB/StatueSync/Messages/StartStatueMessage.cs @@ -35,7 +35,6 @@ namespace QSB.StatueSync.Messages CameraDegrees = reader.ReadSingle(); } - public override bool ShouldReceive => WorldObjectManager.AllObjectsReady; public override void OnReceiveLocal() diff --git a/QSB/Tools/PlayerToolsManager.cs b/QSB/Tools/PlayerToolsManager.cs index c29b6c06..21fbab3e 100644 --- a/QSB/Tools/PlayerToolsManager.cs +++ b/QSB/Tools/PlayerToolsManager.cs @@ -26,23 +26,14 @@ namespace QSB.Tools { CreateStowTransforms(player.CameraBody.transform); - Props_HEA_PlayerTool_mat = GameObject.Find("Props_HEA_ProbeLauncher_ProbeCamera/ProbeLauncherChassis").GetComponent().materials[0]; - Props_HEA_Lightbulb_OFF_mat = GameObject.Find("Props_HEA_Probe_Prelaunch").GetComponent().materials[1]; + var surfaceData = Locator.GetSurfaceManager()._surfaceLookupAsset; + var metal = surfaceData.surfaceTypeGroups[15].materials; + var glass = surfaceData.surfaceTypeGroups[19].materials; - if (QSBSceneManager.CurrentScene == OWScene.SolarSystem) - { - Structure_HEA_PlayerShip_Screens_mat = GameObject.Find("ProbeScreen (1)/ProbeScreenPivot/ProbeScreen").GetComponent().materials[2]; - Props_HEA_Lightbulb_mat = GameObject.Find("Props_HEA_Lantern (10)/Lantern_Lamp").GetComponent().materials[0]; - Props_HEA_Lightbulb_OFF_mat = GameObject.Find("NomaiResearchExhibit/Props_HEA_Probe_STATIC").GetComponent().materials[1]; - } - else if (QSBSceneManager.CurrentScene == OWScene.EyeOfTheUniverse) - { - Props_HEA_Lightbulb_mat = GameObject.Find("lantern_lamp").GetComponent().materials[0]; - - // BUG : uhhhhh fuckin' uhhhhhhhh (find a material) - Props_HEA_Lightbulb_OFF_mat = null; - Structure_HEA_PlayerShip_Screens_mat = null; - } + Props_HEA_PlayerTool_mat = metal[27]; + Props_HEA_Lightbulb_mat = glass[47]; + Props_HEA_Lightbulb_OFF_mat = glass[48]; + Structure_HEA_PlayerShip_Screens_mat = glass[41]; } catch (Exception ex) { diff --git a/QSB/Tools/QSBTool.cs b/QSB/Tools/QSBTool.cs index c9ae35fc..59d97a21 100644 --- a/QSB/Tools/QSBTool.cs +++ b/QSB/Tools/QSBTool.cs @@ -7,7 +7,20 @@ namespace QSB.Tools { public PlayerInfo Player { get; set; } public ToolType Type { get; set; } - public GameObject ToolGameObject { get; set; } + public GameObject ToolGameObject + { + get => _toolGameObject; + + set + { + _toolGameObject = value; + QSBCore.UnityEvents.FireInNUpdates( + () => DitheringAnimator = _toolGameObject.AddComponent(), + 5); + } + } + private GameObject _toolGameObject; + public DitheringAnimator DitheringAnimator { get; set; } public DampedSpringQuat MoveSpring { @@ -33,8 +46,23 @@ namespace QSB.Tools set => _arrivalDegrees = value; } + protected bool _isDitheringOut; + + public override void Start() + { + base.Start(); + ToolGameObject?.SetActive(false); + } + public virtual void OnEnable() => ToolGameObject?.SetActive(true); - public virtual void OnDisable() => ToolGameObject?.SetActive(false); + + public virtual void OnDisable() + { + if (!_isDitheringOut) + { + ToolGameObject?.SetActive(false); + } + } public void ChangeEquipState(bool equipState) { @@ -50,13 +78,34 @@ namespace QSB.Tools public override void EquipTool() { base.EquipTool(); + + if (DitheringAnimator != null && DitheringAnimator._renderers != null) + { + ToolGameObject?.SetActive(true); + DitheringAnimator.SetVisible(true, 5f); + } + Player.AudioController.PlayEquipTool(); } public override void UnequipTool() { base.UnequipTool(); + + if (DitheringAnimator != null && DitheringAnimator._renderers != null) + { + _isDitheringOut = true; + DitheringAnimator.SetVisible(false, 5f); + QSBCore.UnityEvents.RunWhen(() => DitheringAnimator._visibleFraction == 0, FinishDitherOut); + } + Player.AudioController.PlayUnequipTool(); } + + public virtual void FinishDitherOut() + { + ToolGameObject?.SetActive(false); + _isDitheringOut = false; + } } } \ No newline at end of file diff --git a/QSB/Tools/TranslatorTool/QSBNomaiTranslator.cs b/QSB/Tools/TranslatorTool/QSBNomaiTranslator.cs index 1578e485..dd0b6506 100644 --- a/QSB/Tools/TranslatorTool/QSBNomaiTranslator.cs +++ b/QSB/Tools/TranslatorTool/QSBNomaiTranslator.cs @@ -25,7 +25,12 @@ namespace QSB.Tools.TranslatorTool } public override void OnDisable() - => _translatorProp.OnFinishUnequipAnimation(); + { + if (!_isDitheringOut) + { + _translatorProp.OnFinishUnequipAnimation(); + } + } public override void EquipTool() { @@ -39,6 +44,12 @@ namespace QSB.Tools.TranslatorTool _translatorProp.OnUnequipTool(); } + public override void FinishDitherOut() + { + base.FinishDitherOut(); + _translatorProp.OnFinishUnequipAnimation(); + } + public override void Update() { base.Update(); diff --git a/QSB/Tools/TranslatorTool/TranslationSync/Patches/SpiralPatches.cs b/QSB/Tools/TranslatorTool/TranslationSync/Patches/SpiralPatches.cs index 122d4cb2..2bb0d0d3 100644 --- a/QSB/Tools/TranslatorTool/TranslationSync/Patches/SpiralPatches.cs +++ b/QSB/Tools/TranslatorTool/TranslationSync/Patches/SpiralPatches.cs @@ -19,6 +19,7 @@ namespace QSB.Tools.TranslatorTool.TranslationSync.Patches { return; } + if (__instance.IsTranslated(id)) { return; diff --git a/QSB/TornadoSync/Patches/TornadoPatches.cs b/QSB/TornadoSync/Patches/TornadoPatches.cs index 01335064..0aef1e11 100644 --- a/QSB/TornadoSync/Patches/TornadoPatches.cs +++ b/QSB/TornadoSync/Patches/TornadoPatches.cs @@ -37,6 +37,7 @@ namespace QSB.TornadoSync.Patches { __instance.UpdateFormation(); } + if (__instance._isSectorOccupied) { __instance.UpdateAnimation(); @@ -53,7 +54,6 @@ namespace QSB.TornadoSync.Patches return false; } - [HarmonyPrefix] [HarmonyPatch(typeof(TornadoController), nameof(TornadoController.OnEnterCollapseTrigger))] public static bool OnEnterCollapseTrigger(TornadoController __instance, diff --git a/QSB/TornadoSync/TornadoManager.cs b/QSB/TornadoSync/TornadoManager.cs index 85b865c8..f44bcee9 100644 --- a/QSB/TornadoSync/TornadoManager.cs +++ b/QSB/TornadoSync/TornadoManager.cs @@ -32,6 +32,7 @@ namespace QSB.TornadoSync { SpawnOccasional(proxy.transform.root.GetAttachedOWRigidbody(), gdBody); } + SpawnOccasional(cannon._probeBody, gdBody); // islands diff --git a/QSB/TornadoSync/TransformSync/OccasionalTransformSync.cs b/QSB/TornadoSync/TransformSync/OccasionalTransformSync.cs index 7fc16920..fac8a1f3 100644 --- a/QSB/TornadoSync/TransformSync/OccasionalTransformSync.cs +++ b/QSB/TornadoSync/TransformSync/OccasionalTransformSync.cs @@ -116,14 +116,17 @@ namespace QSB.TornadoSync.TransformSync { QueueMove(Locator._playerBody); } + if (_sectors.Contains(ShipTransformSync.LocalInstance?.ReferenceSector?.AttachedObject)) { QueueMove(Locator._shipBody); } + if (_sectors.Contains(PlayerProbeSync.LocalInstance?.ReferenceSector?.AttachedObject)) { QueueMove(Locator._probe._owRigidbody); } + foreach (var child in _childBodies) { QueueMove(child); @@ -140,7 +143,6 @@ namespace QSB.TornadoSync.TransformSync return true; } - private readonly List _toMove = new(); private struct MoveData @@ -186,6 +188,7 @@ namespace QSB.TornadoSync.TransformSync data.Child.SetVelocity(AttachedObject.FromRelVel(data.RelVel, pos)); data.Child.SetAngularVelocity(AttachedObject.FromRelAngVel(data.RelAngVel)); } + _toMove.Clear(); } } diff --git a/QSB/Utility/DebugSettings.cs b/QSB/Utility/DebugSettings.cs index ffbe8a43..b71805cc 100644 --- a/QSB/Utility/DebugSettings.cs +++ b/QSB/Utility/DebugSettings.cs @@ -5,24 +5,24 @@ namespace QSB.Utility public class DebugSettings { [JsonProperty("debugMode")] - public bool DebugMode { get; set; } = false; + public bool DebugMode { get; set; } [JsonProperty("drawLines")] - public bool DrawLines { get; set; } = false; + public bool DrawLines { get; set; } [JsonProperty("showQuantumVisibilityObjects")] - public bool ShowQuantumVisibilityObjects { get; set; } = false; + public bool ShowQuantumVisibilityObjects { get; set; } [JsonProperty("showDebugLabels")] - public bool ShowDebugLabels { get; set; } = false; + public bool ShowDebugLabels { get; set; } [JsonProperty("avoidTimeSync")] - public bool AvoidTimeSync { get; set; } = false; + public bool AvoidTimeSync { get; set; } [JsonProperty("skipTitleScreen")] - public bool SkipTitleScreen { get; set; } = false; + public bool SkipTitleScreen { get; set; } [JsonProperty("greySkybox")] - public bool GreySkybox { get; set; } = false; + public bool GreySkybox { get; set; } } } diff --git a/QSB/debugsettings.json b/QSB/debugsettings.json index b6ff6311..0f80bf2e 100644 --- a/QSB/debugsettings.json +++ b/QSB/debugsettings.json @@ -4,5 +4,6 @@ "showQuantumVisibilityObjects": false, "showDebugLabels": true, "avoidTimeSync": false, - "skipTitleScreen": true + "skipTitleScreen": true, + "greySkybox": false } \ No newline at end of file diff --git a/QSB/manifest.json b/QSB/manifest.json index ecbb5460..b1d99183 100644 --- a/QSB/manifest.json +++ b/QSB/manifest.json @@ -7,7 +7,7 @@ "body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications.\n- Make sure you have forwarded/opened the correct ports. (See the GitHub readme.)" }, "uniqueName": "Raicuparta.QuantumSpaceBuddies", - "version": "0.14.1", - "owmlVersion": "2.3.0", + "version": "0.15.0", + "owmlVersion": "2.2.0", "dependencies": [ "_nebula.MenuFramework" ] } diff --git a/QSBTests/MessageTests.cs b/QSBTests/MessageTests.cs new file mode 100644 index 00000000..4eefe65f --- /dev/null +++ b/QSBTests/MessageTests.cs @@ -0,0 +1,114 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using QSB.Messaging; +using QSB.Utility; +using System; +using System.Linq; +using System.Reflection; + +namespace QSBTests +{ + [TestClass] + public class MessageTests + { + [TestMethod] + public void TestMessages() + { + var module = ModuleDefinition.ReadModule("QSB.dll"); + var messageTypes = typeof(QSBMessage).GetDerivedTypes(); + + var fromField = module.ImportReference(typeof(QSBMessage).GetField("From", Util.Flags)); + var toField = module.ImportReference(typeof(QSBMessage).GetField("To", Util.Flags)); + var objectIdField = module.ImportReference(typeof(QSBWorldObjectMessage<>).GetField("ObjectId", Util.Flags)); + + foreach (var type in messageTypes) + { + var fields = type.GetFields(Util.Flags) + .Select(x => module.ImportReference(x)); + + var constructor = module.ImportReference(type.GetConstructors(Util.Flags).Single()).Resolve(); + var serialize = module.ImportReference(type.GetMethod("Serialize", Util.Flags)).Resolve(); + var deserialize = module.ImportReference(type.GetMethod("Deserialize", Util.Flags)).Resolve(); + + foreach (var field in fields) + { + if (!field.Eq(fromField) && !field.Eq(toField) && !field.Eq(objectIdField)) + { + constructor.CheckUses(field, Util.UseType.Store); + } + + serialize.CheckUses(field, Util.UseType.Load); + deserialize.CheckUses(field, Util.UseType.Store); + } + } + } + } + + internal static class Util + { + public const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + + public static bool Eq(this MemberReference a, MemberReference b) => + a.DeclaringType.Namespace == b.DeclaringType.Namespace && + a.DeclaringType.Name == b.DeclaringType.Name && + a.Name == b.Name; + + public static bool IsOp(this Instruction instruction, OpCode opCode, out T operand) + { + if (instruction.OpCode == opCode) + { + operand = (T)instruction.Operand; + return true; + } + + operand = default; + return false; + } + + public enum UseType { Store, Load }; + + public static void CheckUses(this MethodDefinition method, FieldReference field, UseType useType) + { + var opCode = useType switch + { + UseType.Store => OpCodes.Stfld, + UseType.Load => OpCodes.Ldfld, + _ => throw new ArgumentOutOfRangeException(nameof(useType), useType, null) + }; + + while (true) + { + var il = method.Body.Instructions; + var uses = il.Any(x => + x.IsOp(opCode, out FieldReference f) && + f.Eq(field) + ); + if (uses) + { + return; + } + + var baseMethod = method.GetBaseMethod(); + if (baseMethod.Eq(method)) + { + break; + } + + var callsBase = il.Any(x => + x.IsOp(OpCodes.Call, out MethodReference m) && + m.Eq(baseMethod) + ); + if (!callsBase) + { + break; + } + + method = baseMethod; + } + + Assert.Fail($"{method} does not {useType} {field}"); + } + } +} diff --git a/QuantumUNET/Transport/QNetworkHash128.cs b/QuantumUNET/Transport/QNetworkHash128.cs index d6329169..b3919298 100644 --- a/QuantumUNET/Transport/QNetworkHash128.cs +++ b/QuantumUNET/Transport/QNetworkHash128.cs @@ -66,6 +66,7 @@ namespace QuantumUNET.Transport { result = 0; } + return result; } @@ -79,8 +80,10 @@ namespace QuantumUNET.Transport { str += "0"; } + text = str + text; } + QNetworkHash128 result; result.i0 = (byte)(HexToNumber(text[0]) * 16 + HexToNumber(text[1])); result.i1 = (byte)(HexToNumber(text[2]) * 16 + HexToNumber(text[3]));