Merge branch 'dev' into initial-eye-stuff

This commit is contained in:
Mister_Nebula 2021-12-21 19:00:40 +00:00
commit a75ecf143e
16 changed files with 466 additions and 563 deletions

View File

@ -1,10 +0,0 @@
namespace QSB.Events
{
public abstract class BaseQSBEvent : IQSBEvent
{
internal static int _msgType;
public abstract void SetupListener();
public abstract void CloseListener();
}
}

View File

@ -1,129 +1,99 @@
using OWML.Common;
using QSB.ClientServerStateSync;
using QSB.ClientServerStateSync.Events;
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;
using System;
using QSB.Utility;
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; }
public void SendEvent(T message) => QSBCore.UnityEvents.RunWhen(
() => PlayerTransformSync.LocalInstance != null,
() =>
public void SendEvent(T message)
{
message.FromId = LocalPlayerId;
if (QSBEventManager.ForIdOverride != uint.MaxValue)
{
message.ForId = QSBEventManager.ForIdOverride;
}
if (message.OnlySendToHost)
{
message.FromId = LocalPlayerId;
if (QSBEventManager.ForIdOverride != uint.MaxValue)
{
message.ForId = QSBEventManager.ForIdOverride;
DebugLog.ToConsole($"Warning - {typeof(T).Name} is OnlySendToHost, but we are trying to ForIdOverride!");
}
_eventHandler.SendToServer(message);
});
message.ForId = 0;
}
new QSBEventRelay
{
To = message.ForId,
Event = this,
Message = message
}.Send();
}
/// <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
and not PlayerReadyEvent
and not RequestStateResyncEvent
and not ServerStateEvent)
{
DebugLog.ToConsole($"Warning - Got message (type:{GetType().Name}) 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);
}
protected override bool ShouldReceive => Event.Invoke<bool>("CheckMessage", Message);
protected override void OnReceiveRemote() => Event.Invoke("OnReceiveRemote", QSBCore.IsHost, Message);
protected override void OnReceiveLocal() => Event.Invoke("OnReceiveLocal", QSBCore.IsHost, Message);
public override string ToString() => Event.GetType().Name;
}
}

View File

@ -1,43 +1,8 @@
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.EyeOfTheUniverse.InstrumentSync.Event;
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.SaveSync.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.TornadoSync.Events;
using QSB.Utility;
using QSB.Utility.Events;
using QSB.ZeroGCaveSync.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using OWML.Common;
using QSB.Utility;
namespace QSB.Events
{
@ -45,99 +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(),
new RequestGameStateEvent(),
new GameStateEvent(),
// World Objects
new ElevatorEvent(),
new GeyserEvent(),
new OrbDragEvent(),
new OrbSlotEvent(),
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(),
new TornadoFormStateEvent(),
new GatherInstrumentEvent(),
// Conversation/dialogue/exploration
new ConversationEvent(),
new ConversationStartEndEvent(),
new DialogueConditionEvent(),
new RevealFactEvent(),
new IdentifyFrequencyEvent(),
new IdentifySignalEvent(),
new NpcAnimationEvent(),
new AuthQueueEvent(),
new EnterRemoteDialogueEvent(),
// 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)
{
@ -155,13 +36,14 @@ namespace QSB.Events
{
Ready = false;
_eventList.ForEach(ev => ev.CloseListener());
_eventList = new List<IQSBEvent>();
_eventList.Clear();
}
public static void FireEvent(string eventName)
{
if (!QSBCore.IsInMultiplayer)
{
DebugLog.ToConsole($"Warning - Tried to send event {eventName} while not connected to/hosting server.", MessageType.Warning);
return;
}

View File

@ -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);
}
}
}

103
QSB/Messaging/QSBMessage.cs Normal file
View File

@ -0,0 +1,103 @@
using System;
using QSB.Player;
using QuantumUNET.Transport;
namespace QSB.Messaging
{
public abstract class QSBMessage : QSBMessageRaw
{
/// set automatically when sending a message
public uint From;
/// <summary>
/// uint.MaxValue = send to everyone <br/>
/// 0 = send to host
/// </summary>
public uint To = uint.MaxValue;
/// call the base method when overriding
public override void Serialize(QNetworkWriter writer)
{
writer.Write(From);
writer.Write(To);
}
/// call the base method when overriding
public override void Deserialize(QNetworkReader reader)
{
From = reader.ReadUInt32();
To = reader.ReadUInt32();
}
public sealed override void OnReceive()
{
if (ShouldReceive)
{
if (From != QSBPlayerManager.LocalPlayerId)
{
OnReceiveRemote();
}
else
{
OnReceiveLocal();
}
}
}
/// checked before calling either OnReceive
protected virtual bool ShouldReceive => true;
protected virtual void OnReceiveRemote() { }
protected 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();
}
}
}

View File

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OWML.Common;
using QSB.ClientServerStateSync;
using QSB.ClientServerStateSync.Events;
using QSB.Events;
using QSB.Player;
using QSB.Player.Events;
using QSB.Player.TransformSync;
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, Type> _msgTypeToType = new();
private static readonly Dictionary<Type, short> _typeToMsgType = new();
static QSBMessageManager()
{
var types = typeof(QSBMessageRaw).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);
}
_msgTypeToType.Add(msgType, types[i]);
_typeToMsgType.Add(types[i], msgType);
}
}
public static void Init()
{
foreach (var msgType in _msgTypeToType.Keys)
{
QNetworkServer.RegisterHandlerSafe(msgType, OnServerReceive);
QNetworkManager.singleton.client.RegisterHandlerSafe(msgType, OnClientReceive);
}
}
private static void OnServerReceive(QNetworkMessage netMsg)
{
var msgType = netMsg.MsgType;
var msg = (QSBMessageRaw)Activator.CreateInstance(_msgTypeToType[msgType]);
netMsg.ReadMessage(msg);
if (msg is QSBMessage m)
{
if (m.To == uint.MaxValue)
{
QNetworkServer.SendToAll(msgType, m);
}
else if (m.To == 0)
{
OnReceive(m);
}
else
{
var conn = QNetworkServer.connections.FirstOrDefault(x => m.To == x.GetPlayerId());
if (conn == null)
{
DebugLog.ToConsole($"SendTo unknown player! id: {m.To}, message: {m}", MessageType.Error);
return;
}
conn.Send(msgType, m);
}
}
else
{
QNetworkServer.SendToAll(msgType, msg);
}
}
private static void OnClientReceive(QNetworkMessage netMsg)
{
var msgType = netMsg.MsgType;
var msg = (QSBMessageRaw)Activator.CreateInstance(_msgTypeToType[msgType]);
netMsg.ReadMessage(msg);
OnReceive(msg);
}
private static void OnReceive(QSBMessageRaw msg)
{
if (PlayerTransformSync.LocalInstance == null)
{
DebugLog.ToConsole($"Warning - Tried to handle message {msg} before local player was established.", MessageType.Warning);
return;
}
if (msg is QSBMessage m)
{
if (QSBPlayerManager.PlayerExists(m.From))
{
var player = QSBPlayerManager.GetPlayer(m.From);
if (!player.IsReady
&& player.PlayerId != QSBPlayerManager.LocalPlayerId
&& player.State is ClientState.AliveInSolarSystem or ClientState.AliveInEye or ClientState.DeadInSolarSystem
&& m is not QSBEventRelay { Event: PlayerInformationEvent or PlayerReadyEvent or RequestStateResyncEvent or ServerStateEvent })
{
DebugLog.ToConsole($"Warning - Got message {m} from player {m.From}, but they were not ready. Asking for state resync, just in case.", MessageType.Warning);
QSBEventManager.FireEvent(EventNames.QSBRequestStateResync);
}
}
}
try
{
msg.OnReceive();
}
catch (Exception ex)
{
DebugLog.ToConsole($"Error - Exception handling message {msg} : {ex}", MessageType.Error);
}
}
#endregion
public static void Send<M>(this M msg)
where M : QSBMessageRaw, new()
{
if (PlayerTransformSync.LocalInstance == null)
{
DebugLog.ToConsole($"Warning - Tried to send message {msg} before local player was established.", MessageType.Warning);
return;
}
if (msg is QSBMessage m)
{
m.From = QSBPlayerManager.LocalPlayerId;
}
var msgType = _typeToMsgType[typeof(M)];
QNetworkManager.singleton.client.Send(msgType, msg);
}
public static void SendMessage<T, M>(this T worldObject, M msg)
where T : IWorldObject
where M : QSBWorldObjectMessage<T>, new()
{
msg.ObjectId = worldObject.ObjectId;
Send(msg);
}
}
/// <summary>
/// message that will be sent to every client
/// </summary>
public abstract class QSBMessageRaw : QMessageBase
{
public abstract void OnReceive();
public override string ToString() => GetType().Name;
}
}

View 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();
}
protected 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();
}
}
}

View File

@ -1,38 +1,9 @@
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.EyeOfTheUniverse.InstrumentSync.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.TornadoSync.Patches;
using QSB.Utility;
using QSB.ZeroGCaveSync.Patches;
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using OWML.Common;
using QSB.Utility;
namespace QSB.Patches
{
@ -41,52 +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(),
new TornadoPatches(),
new QuantumInstrumentPatches()
};
_patchList.Add((QSBPatch)Activator.CreateInstance(type));
}
TypeToInstance = new Dictionary<QSBPatchTypes, Harmony>
{

View File

@ -1,36 +1,16 @@
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.EyeOfTheUniverse.InstrumentSync;
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.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.TornadoSync;
using QSB.Utility;
using QSB.ZeroGCaveSync;
using QSB.WorldSync;
using QuantumUNET;
using QuantumUNET.Components;
using System.Linq;
@ -125,27 +105,10 @@ namespace QSB
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<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>();
gameObject.AddComponent<TornadoManager>();
gameObject.AddComponent<ConversationManager>();
gameObject.AddComponent<QuantumInstrumentManager>();
foreach (var type in typeof(WorldObjectManager).GetDerivedTypes())
{
gameObject.AddComponent(type);
}
DebugBoxManager.Init();

View File

@ -6,6 +6,7 @@ using QSB.ClientServerStateSync;
using QSB.DeathSync;
using QSB.Events;
using QSB.JellyfishSync.TransformSync;
using QSB.Messaging;
using QSB.OrbSync.TransformSync;
using QSB.Patches;
using QSB.Player;
@ -165,6 +166,7 @@ namespace QSB
OnClientConnected?.SafeInvoke();
QSBEventManager.Init();
QSBMessageManager.Init();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<ServerStateManager>();

View File

@ -145,6 +145,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)

View File

@ -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)));
}
}
}
}

View File

@ -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)));
}
}
}
}

View File

@ -631,14 +631,12 @@ namespace QuantumUNET.Components
}
}
foreach (var networkConnection2 in QNetworkServer.localConnections)
var networkConnection2 = QNetworkServer.localConnection;
if (networkConnection2 != null)
{
if (networkConnection2 != null)
if (networkConnection2.isReady)
{
if (networkConnection2.isReady)
{
AddObserver(networkConnection2);
}
AddObserver(networkConnection2);
}
}
}
@ -674,12 +672,10 @@ namespace QuantumUNET.Components
if (initialize)
{
foreach (var connection in QNetworkServer.localConnections)
var connection = QNetworkServer.localConnection;
if (!hashSet.Contains(connection))
{
if (!hashSet.Contains(connection))
{
OnSetLocalVisibility(false);
}
OnSetLocalVisibility(false);
}
}

View File

@ -17,7 +17,7 @@ namespace QuantumUNET
}
m_AsyncConnect = ConnectState.Disconnected;
m_LocalServer.RemoveLocalClient(m_Connection);
m_LocalServer.RemoveLocalClient();
}
internal void InternalConnectLocalServer(bool generateConnectMsg)

View File

@ -22,7 +22,7 @@ namespace QuantumUNET
m_SimpleServerSimple = new ServerSimpleWrapper(this);
}
public static List<QNetworkConnection> localConnections => instance.m_LocalConnectionsFakeList;
public static QNetworkConnection localConnection => instance.m_LocalConnection;
public static int listenPort => instance.m_SimpleServerSimple.listenPort;
@ -151,7 +151,7 @@ namespace QuantumUNET
internal int AddLocalClient(QLocalClient localClient)
{
int result;
if (m_LocalConnectionsFakeList.Count != 0)
if (m_LocalConnection != null)
{
QLog.Error("Local Connection already exists");
result = -1;
@ -163,7 +163,6 @@ namespace QuantumUNET
connectionId = 0
};
m_SimpleServerSimple.SetConnectionAtIndex(m_LocalConnection);
m_LocalConnectionsFakeList.Add(m_LocalConnection);
m_LocalConnection.InvokeHandlerNoData(32);
result = 0;
}
@ -171,17 +170,8 @@ namespace QuantumUNET
return result;
}
internal void RemoveLocalClient(QNetworkConnection localClientConnection)
internal void RemoveLocalClient()
{
for (var i = 0; i < m_LocalConnectionsFakeList.Count; i++)
{
if (m_LocalConnectionsFakeList[i].connectionId == localClientConnection.connectionId)
{
m_LocalConnectionsFakeList.RemoveAt(i);
break;
}
}
if (m_LocalConnection != null)
{
m_LocalConnection.Disconnect();
@ -1351,8 +1341,6 @@ namespace QuantumUNET
private bool m_LocalClientActive;
private readonly List<QNetworkConnection> m_LocalConnectionsFakeList = new();
private QULocalConnectionToClient m_LocalConnection;
private readonly QNetworkScene m_NetworkScene;