diff --git a/QSB/Anglerfish/Patches/AnglerPatches.cs b/QSB/Anglerfish/Patches/AnglerPatches.cs index 5aafa580..eb0a142a 100644 --- a/QSB/Anglerfish/Patches/AnglerPatches.cs +++ b/QSB/Anglerfish/Patches/AnglerPatches.cs @@ -38,7 +38,7 @@ namespace QSB.Anglerfish.Patches __instance.gameObject.SetActive(true); __instance._anglerBody.Unsuspend(); __instance.RaiseEvent(nameof(__instance.OnAnglerUnsuspended), __instance._currentState); - QSBEventManager.FireEvent(EventNames.QSBSuspensionChange, qsbAngler.TransformSync.NetIdentity, false); + QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, false); return false; } if (__instance.gameObject.activeSelf && !__instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship)) @@ -46,7 +46,7 @@ namespace QSB.Anglerfish.Patches __instance._anglerBody.Suspend(); __instance.gameObject.SetActive(false); __instance.RaiseEvent(nameof(__instance.OnAnglerSuspended), __instance._currentState); - QSBEventManager.FireEvent(EventNames.QSBSuspensionChange, qsbAngler.TransformSync.NetIdentity, true); + QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, true); } return false; diff --git a/QSB/Anglerfish/WorldObjects/QSBAngler.cs b/QSB/Anglerfish/WorldObjects/QSBAngler.cs index 7e60d5a9..811d2dc2 100644 --- a/QSB/Anglerfish/WorldObjects/QSBAngler.cs +++ b/QSB/Anglerfish/WorldObjects/QSBAngler.cs @@ -1,4 +1,6 @@ using QSB.Anglerfish.TransformSync; +using QSB.Events; +using QSB.SuspendableSync; using QSB.Utility; using QSB.WorldSync; using QuantumUNET; @@ -21,14 +23,21 @@ namespace QSB.Anglerfish.WorldObjects if (QSBCore.IsHost) { + QSBCore.UnityEvents.RunWhen(() => TransformSync, () => + SuspendableManager.Register(TransformSync.NetIdentity)); Object.Instantiate(QSBNetworkManager.Instance.AnglerPrefab).SpawnWithServerAuthority(); } + + // for when you host/connect mid-game + QSBCore.UnityEvents.RunWhen(() => TransformSync, () => + QSBEventManager.FireEvent(EventNames.QSBSuspendChange, TransformSync.NetIdentity, AttachedObject._anglerBody.IsSuspended())); } public override void OnRemoval() { if (QSBCore.IsHost) { + SuspendableManager.Unregister(TransformSync.NetIdentity); QNetworkServer.Destroy(TransformSync.gameObject); } } diff --git a/QSB/Events/EventNames.cs b/QSB/Events/EventNames.cs index 5d8f5a73..4b73735a 100644 --- a/QSB/Events/EventNames.cs +++ b/QSB/Events/EventNames.cs @@ -101,6 +101,6 @@ public static string QSBLearnLaunchCodes = "QSBLearnLaunchCodes"; public static string QSBSatelliteRepairTick = "QSBSatelliteRepairTick"; public static string QSBSatelliteRepaired = "QSBSatelliteRepairTick"; - public static string QSBSuspensionChange = "QSBSuspensionChange"; + public static string QSBSuspendChange = "QSBSuspendChange"; } } diff --git a/QSB/Events/QSBEventManager.cs b/QSB/Events/QSBEventManager.cs index 6fea7d34..aefa7493 100644 --- a/QSB/Events/QSBEventManager.cs +++ b/QSB/Events/QSBEventManager.cs @@ -22,7 +22,7 @@ using QSB.ShipSync.Events; using QSB.ShipSync.Events.Component; using QSB.ShipSync.Events.Hull; using QSB.StatueSync.Events; -using QSB.SuspensionAuthoritySync; +using QSB.SuspendableSync; using QSB.TimeSync.Events; using QSB.Tools.FlashlightTool.Events; using QSB.Tools.ProbeLauncherTool.Events; @@ -112,7 +112,7 @@ namespace QSB.Events new IdentifyFrequencyEvent(), new IdentifySignalEvent(), new NpcAnimationEvent(), - new SuspensionChangeEvent(), + new SuspendChangeEvent(), // Ship new FlyShipEvent(), new HatchEvent(), diff --git a/QSB/SuspendableSync/SuspendChangeEvent.cs b/QSB/SuspendableSync/SuspendChangeEvent.cs new file mode 100644 index 00000000..54aaccb4 --- /dev/null +++ b/QSB/SuspendableSync/SuspendChangeEvent.cs @@ -0,0 +1,84 @@ +using System.Linq; +using QSB.Events; +using QSB.Player; +using QSB.Utility; +using QuantumUNET; +using QuantumUNET.Components; + +namespace QSB.SuspendableSync +{ + public class SuspendChangeEvent : QSBEvent + { + public override void SetupListener() => + GlobalMessenger.AddListener(EventNames.QSBSuspendChange, Handler); + + public override void CloseListener() => + GlobalMessenger.RemoveListener(EventNames.QSBSuspendChange, Handler); + + private void Handler(QNetworkIdentity identity, bool suspended) => SendEvent(CreateMessage(identity, suspended)); + + private SuspendChangeMessage CreateMessage(QNetworkIdentity identity, bool unsuspended) => new() + { + OnlySendToHost = true, + Identity = identity, + Suspended = unsuspended + }; + + + public override void OnReceiveLocal(bool isHost, SuspendChangeMessage message) => OnReceive(message); + public override void OnReceiveRemote(bool isHost, SuspendChangeMessage message) => OnReceive(message); + + private static void OnReceive(SuspendChangeMessage message) + { + if (!QSBCore.WorldObjectsReady) + { + return; + } + + var unsuspendedFor = SuspendableManager._unsuspendedFor[message.Identity]; + + var suspended = !unsuspendedFor.Contains(message.FromId); + if (message.Suspended == suspended) + { + return; + } + + if (!message.Suspended) + { + unsuspendedFor.Add(message.FromId); + } + else + { + unsuspendedFor.Remove(message.FromId); + } + + var newOwner = unsuspendedFor.Count != 0 ? unsuspendedFor[0] : uint.MaxValue; + SetAuthority(message.Identity, newOwner); + } + + private static void SetAuthority(QNetworkIdentity identity, uint id) + { + var oldConn = identity.ClientAuthorityOwner; + var newConn = id != uint.MaxValue + ? QNetworkServer.connections.First(x => x.GetPlayerId() == id) + : null; + + if (oldConn == newConn) + { + return; + } + + if (oldConn != null) + { + identity.RemoveClientAuthority(oldConn); + } + + if (newConn != null) + { + identity.AssignClientAuthority(newConn); + } + + DebugLog.DebugWrite($"{QSBPlayerManager.LocalPlayerId}.{identity.NetId}:{identity.gameObject.name} - set authority to {id}"); + } + } +} diff --git a/QSB/SuspensionAuthoritySync/SuspensionChangeMessage.cs b/QSB/SuspendableSync/SuspendChangeMessage.cs similarity index 83% rename from QSB/SuspensionAuthoritySync/SuspensionChangeMessage.cs rename to QSB/SuspendableSync/SuspendChangeMessage.cs index 62eaf9ac..9382d800 100644 --- a/QSB/SuspensionAuthoritySync/SuspensionChangeMessage.cs +++ b/QSB/SuspendableSync/SuspendChangeMessage.cs @@ -2,9 +2,9 @@ using QuantumUNET.Components; using QuantumUNET.Transport; -namespace QSB.SuspensionAuthoritySync +namespace QSB.SuspendableSync { - public class SuspensionChangeMessage : PlayerMessage + public class SuspendChangeMessage : PlayerMessage { public QNetworkIdentity Identity; public bool Suspended; diff --git a/QSB/SuspendableSync/SuspendableManager.cs b/QSB/SuspendableSync/SuspendableManager.cs new file mode 100644 index 00000000..fd5f77ca --- /dev/null +++ b/QSB/SuspendableSync/SuspendableManager.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using QuantumUNET.Components; + +namespace QSB.SuspendableSync +{ + /// all of this is host only + public static class SuspendableManager + { + internal static readonly Dictionary> _unsuspendedFor = new(); + + public static void Register(QNetworkIdentity identity) => _unsuspendedFor.Add(identity, new List()); + public static void Unregister(QNetworkIdentity identity) => _unsuspendedFor.Remove(identity); + } +} diff --git a/QSB/SuspensionAuthoritySync/SuspensionChangeEvent.cs b/QSB/SuspensionAuthoritySync/SuspensionChangeEvent.cs deleted file mode 100644 index f3340036..00000000 --- a/QSB/SuspensionAuthoritySync/SuspensionChangeEvent.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using QSB.Events; -using QSB.Player; -using QSB.Utility; -using QuantumUNET; -using QuantumUNET.Components; - -namespace QSB.SuspensionAuthoritySync -{ - public class SuspensionChangeEvent : QSBEvent - { - private static Dictionary> _potentialOwners; - - public override void SetupListener() - { - if (QSBCore.IsHost) - { - _potentialOwners = new Dictionary>(); - } - GlobalMessenger.AddListener(EventNames.QSBSuspensionChange, Handler); - } - - public override void CloseListener() - { - if (QSBCore.IsHost) - { - _potentialOwners = null; - } - GlobalMessenger.RemoveListener(EventNames.QSBSuspensionChange, Handler); - } - - private void Handler(QNetworkIdentity identity, bool suspended) => SendEvent(CreateMessage(identity, suspended)); - - private SuspensionChangeMessage CreateMessage(QNetworkIdentity identity, bool suspended) => new() - { - OnlySendToHost = true, - Identity = identity, - Suspended = suspended - }; - - - public override void OnReceiveLocal(bool isHost, SuspensionChangeMessage message) => OnReceive(message); - public override void OnReceiveRemote(bool isHost, SuspensionChangeMessage message) => OnReceive(message); - - private static void OnReceive(SuspensionChangeMessage message) - { - if (!QSBCore.WorldObjectsReady) - { - return; - } - - // init owner list for this identity - if (!_potentialOwners.TryGetValue(message.Identity, out var potentialOwners)) - { - potentialOwners = new List(); - _potentialOwners[message.Identity] = potentialOwners; - } - - if (!message.Suspended) - { - potentialOwners.Add(message.FromId); - } - else - { - potentialOwners.Remove(message.FromId); - } - - var newOwner = potentialOwners.Count != 0 ? potentialOwners[0] : uint.MaxValue; - SetAuthority(message.Identity, newOwner); - } - - private static void SetAuthority(QNetworkIdentity identity, uint id) - { - var oldConn = identity.ClientAuthorityOwner; - var newConn = id != uint.MaxValue - ? QNetworkServer.connections.First(x => x.GetPlayerId() == id) - : null; - - if (oldConn == newConn) - { - return; - } - - if (oldConn != null) - { - identity.RemoveClientAuthority(oldConn); - } - - if (newConn != null) - { - identity.AssignClientAuthority(newConn); - } - - DebugLog.DebugWrite($"{QSBPlayerManager.LocalPlayerId}.{identity.NetId}:{identity.gameObject.name} - set authority to {id}"); - } - } -}