From 990f91c80c079e00a36349a0e7dc629ef7cff256 Mon Sep 17 00:00:00 2001 From: JohnCorby Date: Fri, 10 Dec 2021 23:28:42 -0800 Subject: [PATCH] - message manager - automatically add patches, events, world object managers, messages - qsbevent uses message manager - remove RepeatingManager, merge it into QSBSectorManager since it's only used there --- QSB/Events/BaseQSBEvent.cs | 10 -- QSB/Events/QSBEvent.cs | 133 ++++++++++--------------- QSB/Events/QSBEventManager.cs | 129 ++---------------------- QSB/Messaging/MessageHandler.cs | 108 -------------------- QSB/Messaging/QSBMessage.cs | 80 +++++++++++++++ QSB/Messaging/QSBMessageManager.cs | 124 +++++++++++++++++++++++ QSB/Messaging/QSBWorldObjectMessage.cs | 92 +++++++++++++++++ QSB/Patches/QSBPatchManager.cs | 70 +------------ QSB/QSBCore.cs | 44 +------- QSB/QSBNetworkManager.cs | 2 + QSB/SectorSync/QSBSectorManager.cs | 27 ++++- QSB/Utility/Extensions.cs | 4 + QSB/Utility/IRepeating.cs | 7 -- QSB/Utility/RepeatingManager.cs | 29 ------ QSBTests/EventTests.cs | 41 -------- QSBTests/PatchTests.cs | 41 -------- 16 files changed, 394 insertions(+), 547 deletions(-) delete mode 100644 QSB/Events/BaseQSBEvent.cs delete mode 100644 QSB/Messaging/MessageHandler.cs create mode 100644 QSB/Messaging/QSBMessage.cs create mode 100644 QSB/Messaging/QSBMessageManager.cs create mode 100644 QSB/Messaging/QSBWorldObjectMessage.cs delete mode 100644 QSB/Utility/IRepeating.cs delete mode 100644 QSB/Utility/RepeatingManager.cs delete mode 100644 QSBTests/EventTests.cs delete mode 100644 QSBTests/PatchTests.cs diff --git a/QSB/Events/BaseQSBEvent.cs b/QSB/Events/BaseQSBEvent.cs deleted file mode 100644 index 99c192b5..00000000 --- a/QSB/Events/BaseQSBEvent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace QSB.Events -{ - public abstract class BaseQSBEvent : IQSBEvent - { - internal static int _msgType; - - public abstract void SetupListener(); - public abstract void CloseListener(); - } -} diff --git a/QSB/Events/QSBEvent.cs b/QSB/Events/QSBEvent.cs index c2df5ffa..f02c9553 100644 --- a/QSB/Events/QSBEvent.cs +++ b/QSB/Events/QSBEvent.cs @@ -1,35 +1,36 @@ using System; -using OWML.Common; -using QSB.ClientServerStateSync; +using JetBrains.Annotations; +using OWML.Utils; using QSB.Messaging; using QSB.Player; -using QSB.Player.Events; using QSB.Player.TransformSync; -using QSB.Utility; using QSB.WorldSync; -using QuantumUNET.Components; +using QuantumUNET.Transport; namespace QSB.Events { - public abstract class QSBEvent : BaseQSBEvent where T : PlayerMessage, new() + public abstract class QSBEvent : IQSBEvent where T : PlayerMessage, new() { public uint LocalPlayerId => QSBPlayerManager.LocalPlayerId; - private readonly MessageHandler _eventHandler; + [UsedImplicitly] + private Type _messageType => typeof(T); + + [UsedImplicitly] + private readonly int _msgType; protected QSBEvent() { - if (UnitTestDetector.IsInUnitTest) - { - return; - } - - _eventHandler = new MessageHandler(_msgType++); - _eventHandler.OnClientReceiveMessage += message => OnReceive(false, message); - _eventHandler.OnServerReceiveMessage += message => OnReceive(true, message); + _msgType = QSBEventManager._eventList.Count; } + public abstract void SetupListener(); + public abstract void CloseListener(); + + [UsedImplicitly] public virtual void OnReceiveRemote(bool isHost, T message) { } + + [UsedImplicitly] public virtual void OnReceiveLocal(bool isHost, T message) { } public abstract bool RequireWorldObjectsReady { get; } @@ -43,83 +44,51 @@ namespace QSB.Events { message.ForId = QSBEventManager.ForIdOverride; } - _eventHandler.SendToServer(message); + if (message.OnlySendToHost) + { + message.ForId = 0; + } + new QSBEventRelay + { + Event = this, + Message = message + }.Send(message.ForId); }); /// /// Checks whether the message should be processed by the executing client. /// /// True if the message should be processed. + [UsedImplicitly] public virtual bool CheckMessage(T message) => !RequireWorldObjectsReady || WorldObjectManager.AllObjectsReady; + } - private void OnReceive(bool isServer, T message) + internal class QSBEventRelay : QSBMessage + { + public IQSBEvent Event; + public PlayerMessage Message; + + public override void Serialize(QNetworkWriter writer) { - /* Explanation : - * if is true, this message has been received on the server *server*. - * Therefore, we don't want to do any event handling code - that should be dealt - * with on the server *client* and any other client. So just forward the message - * onto all clients. This way, the server *server* just acts as the distribution - * hub for all events. - */ - - if (isServer) - { - if (message.OnlySendToHost) - { - _eventHandler.SendToHost(message); - } - else if (message.ForId != uint.MaxValue) - { - _eventHandler.SendTo(message.ForId, message); - } - else - { - _eventHandler.SendToAll(message); - } - return; - } - - if (!CheckMessage(message)) - { - return; - } - - if (PlayerTransformSync.LocalInstance == null || PlayerTransformSync.LocalInstance.GetComponent() == null) - { - DebugLog.ToConsole($"Warning - Tried to handle message of type <{GetType().Name}> before localplayer was established.", MessageType.Warning); - return; - } - - if (QSBPlayerManager.PlayerExists(message.FromId)) - { - var player = QSBPlayerManager.GetPlayer(message.FromId); - - if (!player.IsReady - && player.PlayerId != LocalPlayerId - && player.State is ClientState.AliveInSolarSystem or ClientState.AliveInEye or ClientState.DeadInSolarSystem - && this is not PlayerInformationEvent or PlayerReadyEvent) - { - DebugLog.ToConsole($"Warning - Got message from player {message.FromId}, but they were not ready. Asking for state resync, just in case.", MessageType.Warning); - QSBEventManager.FireEvent(EventNames.QSBRequestStateResync); - } - } - - try - { - if (QSBPlayerManager.IsBelongingToLocalPlayer(message.FromId)) - { - OnReceiveLocal(QSBCore.IsHost, message); - } - else - { - OnReceiveRemote(QSBCore.IsHost, message); - } - } - catch (Exception ex) - { - DebugLog.ToConsole($"Error - Exception handling message {GetType().Name} : {ex}", MessageType.Error); - } + base.Serialize(writer); + var msgType = Event.GetValue("_msgType"); + writer.Write(msgType); + Message.Serialize(writer); } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + var msgType = reader.ReadInt32(); + Event = QSBEventManager._eventList[msgType]; + var messageType = Event.GetValue("_messageType"); + Message = (PlayerMessage)Activator.CreateInstance(messageType); + Message.Deserialize(reader); + } + + public override bool ShouldReceive => Event.Invoke("CheckMessage", Message); + public override void OnReceiveRemote() => Event.Invoke("OnReceiveRemote", QSBCore.IsHost, Message); + public override void OnReceiveLocal() => Event.Invoke("OnReceiveLocal", QSBCore.IsHost, Message); } } diff --git a/QSB/Events/QSBEventManager.cs b/QSB/Events/QSBEventManager.cs index 308e29f9..2ff00210 100644 --- a/QSB/Events/QSBEventManager.cs +++ b/QSB/Events/QSBEventManager.cs @@ -1,40 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using OWML.Common; -using QSB.Anglerfish.Events; -using QSB.Animation.NPC.Events; -using QSB.Animation.Player.Events; -using QSB.AuthoritySync; -using QSB.CampfireSync.Events; -using QSB.ClientServerStateSync.Events; -using QSB.ConversationSync.Events; -using QSB.DeathSync.Events; -using QSB.ElevatorSync.Events; -using QSB.GeyserSync.Events; -using QSB.ItemSync.Events; -using QSB.JellyfishSync.Events; -using QSB.LogSync.Events; -using QSB.MeteorSync.Events; -using QSB.OrbSync.Events; -using QSB.Player.Events; -using QSB.QuantumSync.Events; -using QSB.RespawnSync.Events; -using QSB.RoastingSync.Events; -using QSB.SatelliteSync.Events; -using QSB.ShipSync.Events; -using QSB.ShipSync.Events.Component; -using QSB.ShipSync.Events.Hull; -using QSB.StatueSync.Events; -using QSB.TimeSync.Events; -using QSB.Tools.FlashlightTool.Events; -using QSB.Tools.ProbeLauncherTool.Events; -using QSB.Tools.ProbeTool.Events; -using QSB.Tools.SignalscopeTool.Events; -using QSB.Tools.SignalscopeTool.FrequencySync.Events; -using QSB.Tools.TranslatorTool.Events; -using QSB.Tools.TranslatorTool.TranslationSync.Events; using QSB.Utility; -using QSB.Utility.Events; -using QSB.ZeroGCaveSync.Events; namespace QSB.Events { @@ -42,94 +10,15 @@ namespace QSB.Events { public static bool Ready { get; private set; } - private static List _eventList = new(); + private static readonly Type[] _types = typeof(IQSBEvent).GetDerivedTypes().ToArray(); + internal static readonly List _eventList = new(); public static void Init() { - BaseQSBEvent._msgType = 0; - _eventList = new List + foreach (var type in _types) { - // Player - new PlayerReadyEvent(), - new PlayerJoinEvent(), - new PlayerSuitEvent(), - new PlayerFlashlightEvent(), - new PlayerSignalscopeEvent(), - new PlayerTranslatorEvent(), - new EquipProbeLauncherEvent(), - new PlayerProbeEvent(), - new PlayerDeathEvent(), - new RequestStateResyncEvent(), - new PlayerInformationEvent(), - new ChangeAnimTypeEvent(), - new ServerTimeEvent(), - new PlayerEntangledEvent(), - new PlayerKickEvent(), - new EnterExitRoastingEvent(), - new MarshmallowEventEvent(), - new AnimationTriggerEvent(), - new PlayerRespawnEvent(), - new ProbeStartRetrieveEvent(), - new RetrieveProbeEvent(), - new LaunchProbeEvent(), - new PlayerRetrieveProbeEvent(), - new PlayerLaunchProbeEvent(), - new EndLoopEvent(), - new StartLoopEvent(), - new ServerStateEvent(), - new ClientStateEvent(), - new DebugEvent(), - new SatelliteProjectorEvent(), - new SatelliteProjectorSnapshotEvent(), - new LaunchCodesEvent(), - // World Objects - new ElevatorEvent(), - new GeyserEvent(), - new OrbSlotEvent(), - new OrbUserEvent(), - new SocketStateChangeEvent(), - new MultiStateChangeEvent(), - new SetAsTranslatedEvent(), - new QuantumShuffleEvent(), - new MoonStateChangeEvent(), - new EnterLeaveEvent(), - new QuantumAuthorityEvent(), - new DropItemEvent(), - new SocketItemEvent(), - new MoveToCarryEvent(), - new StartStatueEvent(), - new CampfireStateEvent(), - new AnglerChangeStateEvent(), - new MeteorPreLaunchEvent(), - new MeteorLaunchEvent(), - new MeteorSpecialImpactEvent(), - new FragmentDamageEvent(), - new FragmentResyncEvent(), - new JellyfishRisingEvent(), - // Conversation/dialogue/exploration - new ConversationEvent(), - new ConversationStartEndEvent(), - new DialogueConditionEvent(), - new RevealFactEvent(), - new IdentifyFrequencyEvent(), - new IdentifySignalEvent(), - new NpcAnimationEvent(), - new AuthorityQueueEvent(), - // Ship - new FlyShipEvent(), - new HatchEvent(), - new FunnelEnableEvent(), - new HullImpactEvent(), - new HullDamagedEvent(), - new HullChangeIntegrityEvent(), - new HullRepairedEvent(), - new HullRepairTickEvent(), - new ComponentDamagedEvent(), - new ComponentRepairedEvent(), - new ComponentRepairTickEvent(), - new SatelliteNodeRepairTick(), - new SatelliteNodeRepaired() - }; + _eventList.Add((IQSBEvent)Activator.CreateInstance(type)); + } if (UnitTestDetector.IsInUnitTest) { @@ -147,7 +36,7 @@ namespace QSB.Events { Ready = false; _eventList.ForEach(ev => ev.CloseListener()); - _eventList = new List(); + _eventList.Clear(); } public static void FireEvent(string eventName) diff --git a/QSB/Messaging/MessageHandler.cs b/QSB/Messaging/MessageHandler.cs deleted file mode 100644 index 545f6607..00000000 --- a/QSB/Messaging/MessageHandler.cs +++ /dev/null @@ -1,108 +0,0 @@ -using QSB.Utility; -using QuantumUNET; -using QuantumUNET.Components; -using QuantumUNET.Messages; -using System; -using System.Linq; - -namespace QSB.Messaging -{ - public class MessageHandler where T : QMessageBase, new() - { - public event Action OnClientReceiveMessage; - public event Action OnServerReceiveMessage; - - private readonly short _eventType; - - public MessageHandler(int msgType) - { - - _eventType = (short)(msgType + QMsgType.Highest + 1); - if (_eventType >= short.MaxValue) - { - DebugLog.ToConsole($"Hey, uh, maybe don't create 32,767 events? You really should never be seeing this." + - $"If you are, something has either gone terrible wrong or QSB somehow needs more events that classes in Outer Wilds." + - $"In either case, I guess something has gone terribly wrong...", OWML.Common.MessageType.Error); - } - - if (QSBNetworkManager.Instance.IsReady) - { - Init(); - } - else - { - QSBNetworkManager.Instance.OnNetworkManagerReady += Init; - } - } - - private void Init() - { - if (QNetworkServer.handlers.Keys.Contains(_eventType)) - { - QNetworkServer.handlers.Remove(_eventType); - QNetworkManager.singleton.client.handlers.Remove(_eventType); - } - - QNetworkServer.RegisterHandler(_eventType, OnServerReceiveMessageHandler); - QNetworkManager.singleton.client.RegisterHandler(_eventType, OnClientReceiveMessageHandler); - } - - public void SendToAll(T message) - { - if (!QSBNetworkManager.Instance.IsReady) - { - return; - } - - QNetworkServer.SendToAll(_eventType, message); - } - - public void SendToHost(T message) - { - if (!QSBNetworkManager.Instance.IsReady) - { - return; - } - - QNetworkServer.SendToClient(0, _eventType, message); - } - - public void SendTo(uint id, T message) - { - if (!QSBNetworkManager.Instance.IsReady) - { - return; - } - - var conn = QNetworkServer.connections.FirstOrDefault(x => x.GetPlayerId() == id); - if (conn == null) - { - DebugLog.ToConsole($"SendTo unknown player! id: {id}, message: {message.GetType().Name}", OWML.Common.MessageType.Error); - return; - } - QNetworkServer.SendToClient(conn.connectionId, _eventType, message); - } - - public void SendToServer(T message) - { - if (!QSBNetworkManager.Instance.IsReady) - { - return; - } - - QNetworkManager.singleton.client.Send(_eventType, message); - } - - private void OnClientReceiveMessageHandler(QNetworkMessage netMsg) - { - var message = netMsg.ReadMessage(); - OnClientReceiveMessage?.SafeInvoke(message); - } - - private void OnServerReceiveMessageHandler(QNetworkMessage netMsg) - { - var message = netMsg.ReadMessage(); - OnServerReceiveMessage?.SafeInvoke(message); - } - } -} \ No newline at end of file diff --git a/QSB/Messaging/QSBMessage.cs b/QSB/Messaging/QSBMessage.cs new file mode 100644 index 00000000..ba866f5e --- /dev/null +++ b/QSB/Messaging/QSBMessage.cs @@ -0,0 +1,80 @@ +using System; +using QuantumUNET.Messages; +using QuantumUNET.Transport; + +namespace QSB.Messaging +{ + public abstract class QSBMessage : QMessageBase + { + public uint From; + public uint To; + + public override void Serialize(QNetworkWriter writer) + { + writer.Write(From); + writer.Write(To); + } + + public override void Deserialize(QNetworkReader reader) + { + From = reader.ReadUInt32(); + To = reader.ReadUInt32(); + } + + public virtual bool ShouldReceive => true; + public virtual void OnReceiveRemote() { } + public virtual void OnReceiveLocal() { } + } + + + public abstract class QSBBoolMessage : QSBMessage + { + public bool Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = reader.ReadBoolean(); + } + } + + public abstract class QSBFloatMessage : QSBMessage + { + public float Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = reader.ReadSingle(); + } + } + + public abstract class QSBEnumMessage : QSBMessage where E : Enum + { + public E Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write((int)(object)Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = (E)(object)reader.ReadInt32(); + } + } +} diff --git a/QSB/Messaging/QSBMessageManager.cs b/QSB/Messaging/QSBMessageManager.cs new file mode 100644 index 00000000..e2f9cee5 --- /dev/null +++ b/QSB/Messaging/QSBMessageManager.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OWML.Common; +using QSB.Player; +using QSB.Utility; +using QSB.WorldSync; +using QuantumUNET; +using QuantumUNET.Components; +using QuantumUNET.Messages; + +namespace QSB.Messaging +{ + public static class QSBMessageManager + { + #region inner workings + + private static readonly Dictionary _msgTypeToMsg = new(); + private static readonly Dictionary _typeToMsgType = new(); + + static QSBMessageManager() + { + var types = typeof(QSBMessage).GetDerivedTypes().ToArray(); + for (var i = 0; i < types.Length; i++) + { + var msgType = (short)(QMsgType.Highest + 1 + i); + if (msgType >= short.MaxValue) + { + DebugLog.ToConsole("Hey, uh, maybe don't create 32,767 events? You really should never be seeing this." + + "If you are, something has either gone terrible wrong or QSB somehow needs more events that classes in Outer Wilds." + + "In either case, I guess something has gone terribly wrong...", MessageType.Error); + } + + var type = types[i]; + var msg = (QSBMessage)Activator.CreateInstance(type); + _msgTypeToMsg.Add(msgType, msg); + _typeToMsgType.Add(type, msgType); + } + } + + public static void Init() + { + foreach (var msgType in _msgTypeToMsg.Keys) + { + QNetworkServer.RegisterHandlerSafe(msgType, OnServerReceive); + QNetworkManager.singleton.client.RegisterHandlerSafe(msgType, OnClientReceive); + } + } + + private static void OnServerReceive(QNetworkMessage netMsg) + { + var msgType = netMsg.MsgType; + var msg = _msgTypeToMsg[msgType]; + netMsg.ReadMessage(msg); + + if (msg.To == 0) + { + QNetworkServer.SendToClient(0, msgType, msg); + } + else if (msg.To == uint.MaxValue) + { + QNetworkServer.SendToAll(msgType, msg); + } + else + { + var conn = QNetworkServer.connections.FirstOrDefault(x => msg.To == x.GetPlayerId()); + if (conn == null) + { + DebugLog.ToConsole($"SendTo unknown player! id: {msg.To}, message: {msg.GetType().Name}", MessageType.Error); + return; + } + conn.Send(msgType, msg); + } + } + + private static void OnClientReceive(QNetworkMessage netMsg) + { + var msgType = netMsg.MsgType; + var msg = _msgTypeToMsg[msgType]; + netMsg.ReadMessage(msg); + + try + { + if (!msg.ShouldReceive) + { + return; + } + + if (msg.From != QSBPlayerManager.LocalPlayerId) + { + msg.OnReceiveRemote(); + } + else + { + msg.OnReceiveLocal(); + } + } + catch (Exception ex) + { + DebugLog.ToConsole($"Error - Exception handling message {msg.GetType().Name} : {ex}", MessageType.Error); + } + } + + #endregion + + + public static void Send(this M message, uint to = uint.MaxValue) + where M : QSBMessage, new() + { + var msgType = _typeToMsgType[typeof(M)]; + message.From = QSBPlayerManager.LocalPlayerId; + message.To = to; + QNetworkManager.singleton.client.Send(msgType, message); + } + + public static void SendMessage(this T worldObject, M message, uint to = uint.MaxValue) + where M : QSBWorldObjectMessage, new() + where T : IWorldObject + { + message.ObjectId = worldObject.ObjectId; + Send(message, to); + } + } +} diff --git a/QSB/Messaging/QSBWorldObjectMessage.cs b/QSB/Messaging/QSBWorldObjectMessage.cs new file mode 100644 index 00000000..a2bc9958 --- /dev/null +++ b/QSB/Messaging/QSBWorldObjectMessage.cs @@ -0,0 +1,92 @@ +using System; +using QSB.WorldSync; +using QuantumUNET.Transport; + +namespace QSB.Messaging +{ + public abstract class QSBWorldObjectMessage : QSBMessage where T : IWorldObject + { + public int ObjectId; + public T WorldObject { get; private set; } + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(ObjectId); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + ObjectId = reader.ReadInt32(); + } + + public override bool ShouldReceive + { + get + { + if (!WorldObjectManager.AllObjectsReady) + { + return false; + } + + WorldObject = QSBWorldSync.GetWorldFromId(ObjectId); + return true; + } + } + } + + + public abstract class QSBBoolWorldObjectMessage : QSBWorldObjectMessage where T : IWorldObject + { + public bool Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = reader.ReadBoolean(); + } + } + + public abstract class QSBFloatWorldObjectMessage : QSBWorldObjectMessage where T : IWorldObject + { + public float Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write(Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = reader.ReadSingle(); + } + } + + public abstract class QSBEnumWorldObjectMessage : QSBWorldObjectMessage + where T : IWorldObject + where E : Enum + { + public E Value; + + public override void Serialize(QNetworkWriter writer) + { + base.Serialize(writer); + writer.Write((int)(object)Value); + } + + public override void Deserialize(QNetworkReader reader) + { + base.Deserialize(reader); + Value = (E)(object)reader.ReadInt32(); + } + } +} diff --git a/QSB/Patches/QSBPatchManager.cs b/QSB/Patches/QSBPatchManager.cs index 9712fdb5..43fd4ab7 100644 --- a/QSB/Patches/QSBPatchManager.cs +++ b/QSB/Patches/QSBPatchManager.cs @@ -3,34 +3,7 @@ using System.Collections.Generic; using System.Linq; using HarmonyLib; using OWML.Common; -using QSB.Anglerfish.Patches; -using QSB.Animation.NPC.Patches; -using QSB.Animation.Patches; -using QSB.CampfireSync.Patches; -using QSB.ConversationSync.Patches; -using QSB.DeathSync.Patches; -using QSB.EchoesOfTheEye.LightSensorSync.Patches; -using QSB.ElevatorSync.Patches; -using QSB.GeyserSync.Patches; -using QSB.Inputs.Patches; -using QSB.ItemSync.Patches; -using QSB.JellyfishSync.Patches; -using QSB.LogSync.Patches; -using QSB.MeteorSync.Patches; -using QSB.OrbSync.Patches; -using QSB.Player.Patches; -using QSB.PoolSync.Patches; -using QSB.QuantumSync.Patches; -using QSB.RoastingSync.Patches; -using QSB.SatelliteSync.Patches; -using QSB.ShipSync.Patches; -using QSB.StatueSync.Patches; -using QSB.TimeSync.Patches; -using QSB.Tools.ProbeLauncherTool.Patches; -using QSB.Tools.SignalscopeTool.FrequencySync.Patches; -using QSB.Tools.TranslatorTool.TranslationSync.Patches; using QSB.Utility; -using QSB.ZeroGCaveSync.Patches; namespace QSB.Patches { @@ -39,50 +12,17 @@ namespace QSB.Patches public static event Action OnPatchType; public static event Action OnUnpatchType; - private static List _patchList = new(); - private static List _patchedTypes = new(); + private static readonly List _patchList = new(); + private static readonly List _patchedTypes = new(); public static Dictionary TypeToInstance = new(); public static void Init() { - _patchList = new List + foreach (var type in typeof(QSBPatch).GetDerivedTypes()) { - new ConversationPatches(), - new DeathPatches(), - new ElevatorPatches(), - new OrbPatches(), - new LogPatches(), - new QuantumVisibilityPatches(), - new ServerQuantumPatches(), - new ClientQuantumPatches(), - new FrequencyPatches(), - new SpiralPatches(), - new QuantumPatches(), - new ItemPatches(), - new StatuePatches(), - new GeyserPatches(), - new PoolPatches(), - new CampfirePatches(), - new RoastingPatches(), - new PlayerPatches(), - new PlayerAnimationPatches(), - new CharacterAnimationPatches(), - new ShipPatches(), - new InputPatches(), - new TimePatches(), - new MapPatches(), - new LauncherPatches(), - new SolanumPatches(), - new SatelliteProjectorPatches(), - new LightSensorPatches(), - new AnglerPatches(), - new MeteorClientPatches(), - new MeteorServerPatches(), - new JellyfishPatches(), - new TravelerControllerPatches(), - new ZeroGCavePatches() - }; + _patchList.Add((QSBPatch)Activator.CreateInstance(type)); + } TypeToInstance = new Dictionary { diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index 746cddda..191e0d09 100644 --- a/QSB/QSBCore.cs +++ b/QSB/QSBCore.cs @@ -2,36 +2,17 @@ using OWML.Common; using OWML.ModHelper; using OWML.ModHelper.Input; -using QSB.Anglerfish; -using QSB.Animation.NPC; -using QSB.CampfireSync; using QSB.ConversationSync; -using QSB.EchoesOfTheEye.AirlockSync; -using QSB.EchoesOfTheEye.LightSensorSync; -using QSB.ElevatorSync; -using QSB.GeyserSync; using QSB.Inputs; -using QSB.ItemSync; -using QSB.JellyfishSync; using QSB.Menus; -using QSB.MeteorSync; -using QSB.OrbSync; using QSB.Patches; using QSB.Player; -using QSB.Player.TransformSync; -using QSB.PoolSync; -using QSB.QuantumSync; using QSB.RespawnSync; using QSB.SatelliteSync; -using QSB.SectorSync; -using QSB.ShipSync; using QSB.StatueSync; using QSB.TimeSync; -using QSB.Tools.ProbeLauncherTool; -using QSB.Tools.TranslatorTool.TranslationSync; using QSB.Utility; using QSB.WorldSync; -using QSB.ZeroGCaveSync; using QuantumUNET; using QuantumUNET.Components; using UnityEngine; @@ -116,33 +97,18 @@ namespace QSB gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); - gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); gameObject.AddComponent(); + gameObject.AddComponent(); // WorldObject managers - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); - gameObject.AddComponent(); + foreach (var type in typeof(WorldObjectManager).GetDerivedTypes()) + { + gameObject.AddComponent(type); + } DebugBoxManager.Init(); diff --git a/QSB/QSBNetworkManager.cs b/QSB/QSBNetworkManager.cs index 6abaab80..8917f6c5 100644 --- a/QSB/QSBNetworkManager.cs +++ b/QSB/QSBNetworkManager.cs @@ -6,6 +6,7 @@ using QSB.AuthoritySync; using QSB.ClientServerStateSync; using QSB.DeathSync; using QSB.Events; +using QSB.Messaging; using QSB.OrbSync.TransformSync; using QSB.Patches; using QSB.Player; @@ -140,6 +141,7 @@ namespace QSB OnClientConnected?.SafeInvoke(); QSBEventManager.Init(); + QSBMessageManager.Init(); gameObject.AddComponent(); gameObject.AddComponent(); diff --git a/QSB/SectorSync/QSBSectorManager.cs b/QSB/SectorSync/QSBSectorManager.cs index ad8a54a2..aa5dbdc9 100644 --- a/QSB/SectorSync/QSBSectorManager.cs +++ b/QSB/SectorSync/QSBSectorManager.cs @@ -9,17 +9,34 @@ using UnityEngine; namespace QSB.SectorSync { - public class QSBSectorManager : WorldObjectManager, IRepeating + public class QSBSectorManager : WorldObjectManager { public static QSBSectorManager Instance { get; private set; } public bool IsReady { get; private set; } public List FakeSectors = new(); - private void OnEnable() => RepeatingManager.Repeatings.Add(this); - private void OnDisable() => RepeatingManager.Repeatings.Remove(this); - public List SectoredSyncs = new(); + #region repeating timer + + private const float TimeInterval = 0.4f; + private float _checkTimer = TimeInterval; + + private void Update() + { + _checkTimer += Time.unscaledDeltaTime; + if (_checkTimer < TimeInterval) + { + return; + } + + Invoke(); + + _checkTimer = 0; + } + + #endregion + public void Invoke() { if (!Instance.IsReady || !AllObjectsReady) @@ -91,4 +108,4 @@ namespace QSB.SectorSync transformSync.SetReferenceSector(closestSector); } } -} \ No newline at end of file +} diff --git a/QSB/Utility/Extensions.cs b/QSB/Utility/Extensions.cs index aa0adb50..d9b6813b 100644 --- a/QSB/Utility/Extensions.cs +++ b/QSB/Utility/Extensions.cs @@ -3,6 +3,7 @@ using QSB.Player; using QSB.Player.TransformSync; using QuantumUNET; using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; @@ -128,6 +129,9 @@ namespace QSB.Utility multiDelegate.GetInvocationList().ToList().ForEach(dl => dl.DynamicInvoke(args)); } + public static IEnumerable GetDerivedTypes(this Type type) => type.Assembly.GetTypes() + .Where(x => !x.IsInterface && !x.IsAbstract && type.IsAssignableFrom(x)); + // OW public static Vector3 GetRelativeAngularVelocity(this OWRigidbody baseBody, OWRigidbody relativeBody) diff --git a/QSB/Utility/IRepeating.cs b/QSB/Utility/IRepeating.cs deleted file mode 100644 index da45c714..00000000 --- a/QSB/Utility/IRepeating.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace QSB.Utility -{ - public interface IRepeating - { - void Invoke(); - } -} diff --git a/QSB/Utility/RepeatingManager.cs b/QSB/Utility/RepeatingManager.cs deleted file mode 100644 index 54703c8e..00000000 --- a/QSB/Utility/RepeatingManager.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace QSB.Utility -{ - internal class RepeatingManager : MonoBehaviour - { - public static List Repeatings = new(); - - private const float TimeInterval = 0.4f; - private float _checkTimer = TimeInterval; - - private void Update() - { - _checkTimer += Time.unscaledDeltaTime; - if (_checkTimer < TimeInterval) - { - return; - } - - foreach (var repeat in Repeatings) - { - repeat.Invoke(); - } - - _checkTimer = 0; - } - } -} diff --git a/QSBTests/EventTests.cs b/QSBTests/EventTests.cs deleted file mode 100644 index c3b15ab6..00000000 --- a/QSBTests/EventTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using QSB.Events; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace QSBTests -{ - [TestClass] - public class EventTests - { - [TestMethod] - public void CheckUnreferencedEvents() - { - var qsbAssembly = Assembly.Load("QSB"); - var allEventTypes = qsbAssembly - .GetTypes() - .Where(x => typeof(IQSBEvent).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); - - QSBEventManager.Init(); - var eventInstances = (List)typeof(QSBEventManager) - .GetField("_eventList", BindingFlags.NonPublic | BindingFlags.Static) - .GetValue(typeof(QSBEventManager)); - - var failedTypes = new List(); - foreach (var type in allEventTypes) - { - if (!eventInstances.Any(x => x.GetType() == type)) - { - failedTypes.Add(type); - } - } - - if (failedTypes.Count > 0) - { - Assert.Fail(string.Join(", ", failedTypes.Select(x => x.Name))); - } - } - } -} diff --git a/QSBTests/PatchTests.cs b/QSBTests/PatchTests.cs deleted file mode 100644 index 29d3ebdd..00000000 --- a/QSBTests/PatchTests.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using QSB.Patches; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace QSBTests -{ - [TestClass] - public class PatchTests - { - [TestMethod] - public void CheckUnreferencedPatches() - { - var qsbAssembly = Assembly.Load("QSB"); - var allPatchTypes = qsbAssembly - .GetTypes() - .Where(x => typeof(QSBPatch).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract); - - QSBPatchManager.Init(); - var patchInstances = (List)typeof(QSBPatchManager) - .GetField("_patchList", BindingFlags.NonPublic | BindingFlags.Static) - .GetValue(typeof(QSBPatchManager)); - - var failedTypes = new List(); - foreach (var type in allPatchTypes) - { - if (!patchInstances.Any(x => x.GetType() == type)) - { - failedTypes.Add(type); - } - } - - if (failedTypes.Count > 0) - { - Assert.Fail(string.Join(", ", failedTypes.Select(x => x.Name))); - } - } - } -}