mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-02-09 09:39:57 +00:00
- 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
This commit is contained in:
parent
fde9efa599
commit
990f91c80c
@ -1,10 +0,0 @@
|
||||
namespace QSB.Events
|
||||
{
|
||||
public abstract class BaseQSBEvent : IQSBEvent
|
||||
{
|
||||
internal static int _msgType;
|
||||
|
||||
public abstract void SetupListener();
|
||||
public abstract void CloseListener();
|
||||
}
|
||||
}
|
@ -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<T> : BaseQSBEvent where T : PlayerMessage, new()
|
||||
public abstract class QSBEvent<T> : IQSBEvent where T : PlayerMessage, new()
|
||||
{
|
||||
public uint LocalPlayerId => QSBPlayerManager.LocalPlayerId;
|
||||
|
||||
private readonly MessageHandler<T> _eventHandler;
|
||||
[UsedImplicitly]
|
||||
private Type _messageType => typeof(T);
|
||||
|
||||
[UsedImplicitly]
|
||||
private readonly int _msgType;
|
||||
|
||||
protected QSBEvent()
|
||||
{
|
||||
if (UnitTestDetector.IsInUnitTest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_eventHandler = new MessageHandler<T>(_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);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the message should be processed by the executing client.
|
||||
/// </summary>
|
||||
/// <returns>True if the message should be processed.</returns>
|
||||
[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 <isServer> 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<QNetworkIdentity>() == 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<int>("_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<Type>("_messageType");
|
||||
Message = (PlayerMessage)Activator.CreateInstance(messageType);
|
||||
Message.Deserialize(reader);
|
||||
}
|
||||
|
||||
public override bool ShouldReceive => Event.Invoke<bool>("CheckMessage", Message);
|
||||
public override void OnReceiveRemote() => Event.Invoke("OnReceiveRemote", QSBCore.IsHost, Message);
|
||||
public override void OnReceiveLocal() => Event.Invoke("OnReceiveLocal", QSBCore.IsHost, Message);
|
||||
}
|
||||
}
|
||||
|
@ -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<IQSBEvent> _eventList = new();
|
||||
private static readonly Type[] _types = typeof(IQSBEvent).GetDerivedTypes().ToArray();
|
||||
internal static readonly List<IQSBEvent> _eventList = new();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
BaseQSBEvent._msgType = 0;
|
||||
_eventList = new List<IQSBEvent>
|
||||
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<IQSBEvent>();
|
||||
_eventList.Clear();
|
||||
}
|
||||
|
||||
public static void FireEvent(string eventName)
|
||||
|
@ -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<T> where T : QMessageBase, new()
|
||||
{
|
||||
public event Action<T> OnClientReceiveMessage;
|
||||
public event Action<T> 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<T>();
|
||||
OnClientReceiveMessage?.SafeInvoke(message);
|
||||
}
|
||||
|
||||
private void OnServerReceiveMessageHandler(QNetworkMessage netMsg)
|
||||
{
|
||||
var message = netMsg.ReadMessage<T>();
|
||||
OnServerReceiveMessage?.SafeInvoke(message);
|
||||
}
|
||||
}
|
||||
}
|
80
QSB/Messaging/QSBMessage.cs
Normal file
80
QSB/Messaging/QSBMessage.cs
Normal file
@ -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<E> : 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();
|
||||
}
|
||||
}
|
||||
}
|
124
QSB/Messaging/QSBMessageManager.cs
Normal file
124
QSB/Messaging/QSBMessageManager.cs
Normal file
@ -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<short, QSBMessage> _msgTypeToMsg = new();
|
||||
private static readonly Dictionary<Type, short> _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<M>(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<T, M>(this T worldObject, M message, uint to = uint.MaxValue)
|
||||
where M : QSBWorldObjectMessage<T>, new()
|
||||
where T : IWorldObject
|
||||
{
|
||||
message.ObjectId = worldObject.ObjectId;
|
||||
Send(message, to);
|
||||
}
|
||||
}
|
||||
}
|
92
QSB/Messaging/QSBWorldObjectMessage.cs
Normal file
92
QSB/Messaging/QSBWorldObjectMessage.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using QSB.WorldSync;
|
||||
using QuantumUNET.Transport;
|
||||
|
||||
namespace QSB.Messaging
|
||||
{
|
||||
public abstract class QSBWorldObjectMessage<T> : 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<T>(ObjectId);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract class QSBBoolWorldObjectMessage<T> : QSBWorldObjectMessage<T> 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<T> : QSBWorldObjectMessage<T> 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<T, E> : QSBWorldObjectMessage<T>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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<QSBPatchTypes> OnPatchType;
|
||||
public static event Action<QSBPatchTypes> OnUnpatchType;
|
||||
|
||||
private static List<QSBPatch> _patchList = new();
|
||||
private static List<QSBPatchTypes> _patchedTypes = new();
|
||||
private static readonly List<QSBPatch> _patchList = new();
|
||||
private static readonly List<QSBPatchTypes> _patchedTypes = new();
|
||||
|
||||
public static Dictionary<QSBPatchTypes, Harmony> TypeToInstance = new();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_patchList = new List<QSBPatch>
|
||||
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<QSBPatchTypes, Harmony>
|
||||
{
|
||||
|
@ -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<ConversationManager>();
|
||||
gameObject.AddComponent<QSBInputManager>();
|
||||
gameObject.AddComponent<TimeSyncUI>();
|
||||
gameObject.AddComponent<RepeatingManager>();
|
||||
gameObject.AddComponent<PlayerEntanglementWatcher>();
|
||||
gameObject.AddComponent<DebugGUI>();
|
||||
gameObject.AddComponent<MenuManager>();
|
||||
gameObject.AddComponent<RespawnManager>();
|
||||
gameObject.AddComponent<SatelliteProjectorManager>();
|
||||
gameObject.AddComponent<StatueManager>();
|
||||
|
||||
// WorldObject managers
|
||||
gameObject.AddComponent<QuantumManager>();
|
||||
gameObject.AddComponent<SpiralManager>();
|
||||
gameObject.AddComponent<ElevatorManager>();
|
||||
gameObject.AddComponent<GeyserManager>();
|
||||
gameObject.AddComponent<OrbManager>();
|
||||
gameObject.AddComponent<QSBSectorManager>();
|
||||
gameObject.AddComponent<ItemManager>();
|
||||
gameObject.AddComponent<StatueManager>();
|
||||
gameObject.AddComponent<PoolManager>();
|
||||
gameObject.AddComponent<CampfireManager>();
|
||||
gameObject.AddComponent<CharacterAnimManager>();
|
||||
gameObject.AddComponent<ShipManager>();
|
||||
gameObject.AddComponent<ProbeLauncherManager>();
|
||||
gameObject.AddComponent<LightSensorManager>();
|
||||
gameObject.AddComponent<AirlockManager>();
|
||||
gameObject.AddComponent<AnglerManager>();
|
||||
gameObject.AddComponent<MeteorManager>();
|
||||
gameObject.AddComponent<JellyfishManager>();
|
||||
gameObject.AddComponent<ZeroGCaveManager>();
|
||||
foreach (var type in typeof(WorldObjectManager).GetDerivedTypes())
|
||||
{
|
||||
gameObject.AddComponent(type);
|
||||
}
|
||||
|
||||
DebugBoxManager.Init();
|
||||
|
||||
|
@ -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<RespawnOnDeath>();
|
||||
gameObject.AddComponent<ServerStateManager>();
|
||||
|
@ -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<QSBSector> FakeSectors = new();
|
||||
|
||||
private void OnEnable() => RepeatingManager.Repeatings.Add(this);
|
||||
private void OnDisable() => RepeatingManager.Repeatings.Remove(this);
|
||||
|
||||
public List<BaseSectoredSync> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Type> 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)
|
||||
|
@ -1,7 +0,0 @@
|
||||
namespace QSB.Utility
|
||||
{
|
||||
public interface IRepeating
|
||||
{
|
||||
void Invoke();
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.Utility
|
||||
{
|
||||
internal class RepeatingManager : MonoBehaviour
|
||||
{
|
||||
public static List<IRepeating> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<IQSBEvent>)typeof(QSBEventManager)
|
||||
.GetField("_eventList", BindingFlags.NonPublic | BindingFlags.Static)
|
||||
.GetValue(typeof(QSBEventManager));
|
||||
|
||||
var failedTypes = new List<Type>();
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<QSBPatch>)typeof(QSBPatchManager)
|
||||
.GetField("_patchList", BindingFlags.NonPublic | BindingFlags.Static)
|
||||
.GetValue(typeof(QSBPatchManager));
|
||||
|
||||
var failedTypes = new List<Type>();
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user