Implement networking API functionality
This commit is contained in:
parent
8b470aa690
commit
6db837b11a
24 changed files with 1147 additions and 10 deletions
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using User;
|
||||||
|
|
||||||
namespace CLre.API.App
|
namespace CLre.API.App
|
||||||
{
|
{
|
||||||
|
@ -53,6 +54,12 @@ namespace CLre.API.App
|
||||||
add => GameFrameworkEngine.gameFrameworkExit += value;
|
add => GameFrameworkEngine.gameFrameworkExit += value;
|
||||||
remove => GameFrameworkEngine.gameFrameworkExit += value;
|
remove => GameFrameworkEngine.gameFrameworkExit += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static event EventHandler<GameJoin> GameJoin
|
||||||
|
{
|
||||||
|
add => ClientGameJoinSequence_OnUserValidated_Patch.gameJoin += value;
|
||||||
|
remove => ClientGameJoinSequence_OnUserValidated_Patch.gameJoin += value;
|
||||||
|
}
|
||||||
|
|
||||||
public static string Version
|
public static string Version
|
||||||
{
|
{
|
||||||
|
@ -114,4 +121,27 @@ namespace CLre.API.App
|
||||||
return AccessTools.Method("FrontEnd.FrontEndGuiEngine:SetMainMenuEnabled");
|
return AccessTools.Method("FrontEnd.FrontEndGuiEngine:SetMainMenuEnabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO patch OnUserValidationFailed as well
|
||||||
|
[HarmonyPatch]
|
||||||
|
class ClientGameJoinSequence_OnUserValidated_Patch
|
||||||
|
{
|
||||||
|
internal static event EventHandler<GameJoin> gameJoin;
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(object __instance, ref SerializedAccountInfo validated)
|
||||||
|
{
|
||||||
|
if (gameJoin != null) gameJoin(__instance, new GameJoin
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Data = validated,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("MultiplayerClient.ClientGameJoinSequence:OnUserValidated");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
using User;
|
||||||
|
|
||||||
namespace CLre.API.App
|
namespace CLre.API.App
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -8,4 +10,10 @@ namespace CLre.API.App
|
||||||
public struct GameExit{}
|
public struct GameExit{}
|
||||||
|
|
||||||
public struct MenuReady{}
|
public struct MenuReady{}
|
||||||
|
|
||||||
|
public struct GameJoin
|
||||||
|
{
|
||||||
|
public bool Success;
|
||||||
|
public SerializedAccountInfo Data;
|
||||||
|
}
|
||||||
}
|
}
|
83
CLre/API/Synergy/ClientHandshakeEngine.cs
Normal file
83
CLre/API/Synergy/ClientHandshakeEngine.cs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
using System.Collections;
|
||||||
|
using CLre.API.Engines;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy
|
||||||
|
{
|
||||||
|
public class ClientHandshakeEngine : GameObsoleteEnginePreBuild
|
||||||
|
{
|
||||||
|
internal static ClientHandshakeEngine Instance = null;
|
||||||
|
|
||||||
|
internal const NetworkDispatcherCode CLre_HANDSHAKE_NETCODE = (NetworkDispatcherCode) 218;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgClientSender_SendMessage<SerializedCLreHandshake> _sendMessage;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgClientListener_RegisterListener<SerializedCLreHandshake> _registerListener;
|
||||||
|
|
||||||
|
public override void Ready()
|
||||||
|
{
|
||||||
|
//Utility.Logging.MetaLog("Building send message delegate");
|
||||||
|
_sendMessage =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgClientSender_SendMessage<SerializedCLreHandshake>>(
|
||||||
|
"GameNetworkLayer.Client.NetMessageClientSender:SendMessage",
|
||||||
|
generics: new [] {typeof(SerializedCLreHandshake)},
|
||||||
|
instance: MainLevel_BuildClasses_Patch.netMessageSender);
|
||||||
|
|
||||||
|
//Utility.Logging.MetaLog("Building register listener delegate");
|
||||||
|
_registerListener =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgClientListener_RegisterListener<SerializedCLreHandshake>>(
|
||||||
|
"GameNetworkLayer.Client.NetMessageClientListener:RegisterListener",
|
||||||
|
generics: new [] {typeof(SerializedCLreHandshake)},
|
||||||
|
instance: MainLevel_BuildClasses_Patch.netMessageListener);
|
||||||
|
_registerListener(CLre_HANDSHAKE_NETCODE, OnHandshakeReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnHandshakeReceived(ref SerializedCLreHandshake p)
|
||||||
|
{
|
||||||
|
// TODO validate handshake msg
|
||||||
|
Utility.Logging.MetaLog($"Received CLre handshake! {p}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEntitiesDB entitiesDB { get; set; }
|
||||||
|
public override IEntityFactory entityFactory { get; set; }
|
||||||
|
|
||||||
|
public IEnumerator Sender(SerializedCLreHandshake payload)
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
Utility.Logging.MetaLog("Sending Client CLre handshake");
|
||||||
|
_sendMessage(CLre_HANDSHAKE_NETCODE, ref payload);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
Instance = new ClientHandshakeEngine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientHandshakeEngine(): base()
|
||||||
|
{
|
||||||
|
App.Client.GameJoin += (_, __) =>
|
||||||
|
{
|
||||||
|
SerializedCLreHandshake payload = SerializedCLreHandshake.Current();
|
||||||
|
Sender(payload).Run();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GameFramework.MainLevel), "BuildClasses")]
|
||||||
|
class MainLevel_BuildClasses_Patch
|
||||||
|
{
|
||||||
|
internal static object netMessageListener;
|
||||||
|
|
||||||
|
internal static object netMessageSender;
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender)
|
||||||
|
{
|
||||||
|
netMessageListener = ____netMessageListener;
|
||||||
|
netMessageSender = ____netMessageSender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
CLre/API/Synergy/ClientMessagingEngine.cs
Normal file
94
CLre/API/Synergy/ClientMessagingEngine.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy
|
||||||
|
{
|
||||||
|
class ClientMessagingEngine: Engines.GameObsoleteEnginePostBuild, IWaitForFrameworkDestruction, IWaitForFrameworkInitialization
|
||||||
|
{
|
||||||
|
private struct MessageQueueItem
|
||||||
|
{
|
||||||
|
public SerializedCLreMessage msg;
|
||||||
|
public NetworkDispatcherCode code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgClientSender_SendMessage<SerializedCLreMessage> _sendMessage;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgClientListener_RegisterListener<SerializedCLreMessage> _registerListener;
|
||||||
|
|
||||||
|
private Queue<MessageQueueItem> _messageQueue = new Queue<MessageQueueItem>(10);
|
||||||
|
|
||||||
|
private bool _isRunning = false;
|
||||||
|
|
||||||
|
public override void Ready()
|
||||||
|
{
|
||||||
|
//Utility.Logging.MetaLog("Building send message delegate");
|
||||||
|
_sendMessage =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgClientSender_SendMessage<SerializedCLreMessage>>(
|
||||||
|
"GameNetworkLayer.Client.NetMessageClientSender:SendMessage",
|
||||||
|
generics: new [] {typeof(SerializedCLreMessage)},
|
||||||
|
instance: MainLevel_BuildClasses_Patch.netMessageSender);
|
||||||
|
|
||||||
|
//Utility.Logging.MetaLog("Building register listener delegate");
|
||||||
|
_registerListener =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgClientListener_RegisterListener<SerializedCLreMessage>>(
|
||||||
|
"GameNetworkLayer.Client.NetMessageClientListener:RegisterListener",
|
||||||
|
generics: new [] {typeof(SerializedCLreMessage)},
|
||||||
|
instance: MainLevel_BuildClasses_Patch.netMessageListener);
|
||||||
|
_registerListener(Message.CLre_MESSAGE_NETCODE, OnMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMessageReceived(ref SerializedCLreMessage data)
|
||||||
|
{
|
||||||
|
Message.HandleMessageReceive(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void EnqueueMessage(ref SerializedCLreMessage msg)
|
||||||
|
{
|
||||||
|
_messageQueue.Enqueue(new MessageQueueItem
|
||||||
|
{
|
||||||
|
msg = msg,
|
||||||
|
code = Message.CLre_MESSAGE_NETCODE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEntitiesDB entitiesDB { get; set; }
|
||||||
|
public override IEntityFactory entityFactory { get; set; }
|
||||||
|
|
||||||
|
public ClientMessagingEngine(): base()
|
||||||
|
{
|
||||||
|
App.Client.GameJoin += (_, __) => { MessageSender().Run(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator MessageSender()
|
||||||
|
{
|
||||||
|
while (!_isRunning)
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
while (_isRunning)
|
||||||
|
{
|
||||||
|
while (_messageQueue.Count != 0)
|
||||||
|
{
|
||||||
|
MessageQueueItem item = _messageQueue.Dequeue();
|
||||||
|
API.Utility.Logging.MetaLog($"Sending message with id {item.msg.Id}");
|
||||||
|
_sendMessage(item.code, ref item.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFrameworkDestroyed()
|
||||||
|
{
|
||||||
|
_isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFrameworkInitialized()
|
||||||
|
{
|
||||||
|
_isRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
CLre/API/Synergy/Message.cs
Normal file
51
CLre/API/Synergy/Message.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy
|
||||||
|
{
|
||||||
|
public static class Message
|
||||||
|
{
|
||||||
|
internal const NetworkDispatcherCode CLre_MESSAGE_NETCODE = (NetworkDispatcherCode) 219;
|
||||||
|
|
||||||
|
private static readonly Dictionary<uint, Action<ReceiveMessageArgs>> handlers =
|
||||||
|
new Dictionary<uint, Action<ReceiveMessageArgs>>();
|
||||||
|
|
||||||
|
private static readonly ClientMessagingEngine msgEngine = new ClientMessagingEngine();
|
||||||
|
|
||||||
|
public static void SendCLreMessage(ref SerializedCLreMessage message)
|
||||||
|
{
|
||||||
|
msgEngine.EnqueueMessage(ref message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterListener(uint id, Action<ReceiveMessageArgs> handler)
|
||||||
|
{
|
||||||
|
if (handlers.TryGetValue(id, out Action<ReceiveMessageArgs> existing))
|
||||||
|
{
|
||||||
|
existing += handler;
|
||||||
|
handlers[id] = existing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlers[id] = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void HandleMessageReceive(ref SerializedCLreMessage msg)
|
||||||
|
{
|
||||||
|
ReceiveMessageArgs payload = new ReceiveMessageArgs
|
||||||
|
{
|
||||||
|
Message = msg,
|
||||||
|
};
|
||||||
|
if (handlers.TryGetValue(msg.Id, out Action<ReceiveMessageArgs> h))
|
||||||
|
{
|
||||||
|
h(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ReceiveMessageArgs
|
||||||
|
{
|
||||||
|
public SerializedCLreMessage Message;
|
||||||
|
}
|
||||||
|
}
|
161
CLre/API/Synergy/SerializedCLreHandshake.cs
Normal file
161
CLre/API/Synergy/SerializedCLreHandshake.cs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy
|
||||||
|
{
|
||||||
|
public struct SerializedCLreHandshake: ISerializedNetData
|
||||||
|
{
|
||||||
|
private byte major;
|
||||||
|
private byte minor;
|
||||||
|
private byte patch;
|
||||||
|
|
||||||
|
private HandshakeFlag flags;
|
||||||
|
|
||||||
|
private List<string> modInfo;
|
||||||
|
|
||||||
|
public Version Version
|
||||||
|
{
|
||||||
|
get => new Version(major, minor, patch);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
major = (byte)value.Major;
|
||||||
|
minor = (byte)value.Minor;
|
||||||
|
patch = (byte)value.Build;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> Mods
|
||||||
|
{
|
||||||
|
get => modInfo.ToArray();
|
||||||
|
set
|
||||||
|
{
|
||||||
|
modInfo.Clear();
|
||||||
|
foreach (var mod in value)
|
||||||
|
{
|
||||||
|
modInfo.Add(mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
// version
|
||||||
|
writer.Write(major);
|
||||||
|
writer.Write(minor);
|
||||||
|
writer.Write(patch);
|
||||||
|
writer.Write((uint)flags);
|
||||||
|
writer.Write(modInfo.Count);
|
||||||
|
foreach (string mod in modInfo)
|
||||||
|
{
|
||||||
|
writer.Write(mod);
|
||||||
|
}
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
// version
|
||||||
|
major = reader.ReadByte();
|
||||||
|
minor = reader.ReadByte();
|
||||||
|
patch = reader.ReadByte();
|
||||||
|
flags = (HandshakeFlag) reader.ReadUInt32();
|
||||||
|
int modCount = reader.ReadInt32();
|
||||||
|
modInfo = new List<string>(modCount);
|
||||||
|
for (int i = 0; i < modCount; i++)
|
||||||
|
{
|
||||||
|
modInfo.Add(reader.ReadString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
return (flags & f) != HandshakeFlag.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
flags |= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsetFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
flags &= ~f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake Current()
|
||||||
|
{
|
||||||
|
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
List<string> mods = new List<string>();
|
||||||
|
foreach (var plugin in IllusionInjector.PluginManager.Plugins)
|
||||||
|
{
|
||||||
|
mods.Add(plugin.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = (byte) v.Major,
|
||||||
|
minor = (byte) v.Minor,
|
||||||
|
patch = (byte) v.Build,
|
||||||
|
flags = HandshakeFlag.Client,
|
||||||
|
modInfo = mods,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake RequireCLre()
|
||||||
|
{
|
||||||
|
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
List<string> mods = new List<string>(new []{Assembly.GetExecutingAssembly().GetName().Name});
|
||||||
|
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = (byte) v.Major,
|
||||||
|
minor = (byte) v.Minor,
|
||||||
|
patch = (byte) v.Build,
|
||||||
|
flags = HandshakeFlag.Client | HandshakeFlag.RequireAll,
|
||||||
|
modInfo = mods,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake Empty()
|
||||||
|
{
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = 0,
|
||||||
|
minor = 0,
|
||||||
|
patch = 0,
|
||||||
|
modInfo = new List<string>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"CLre {Version} ({modInfo.Count} mods)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum HandshakeFlag : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Client = 1,
|
||||||
|
Server = 1 << 1,
|
||||||
|
RequireAll = 1 << 2,
|
||||||
|
OptionalAll = 1 << 3,
|
||||||
|
Confirm = 1 << 4,
|
||||||
|
}
|
||||||
|
}
|
44
CLre/API/Synergy/SerializedCLreMessage.cs
Normal file
44
CLre/API/Synergy/SerializedCLreMessage.cs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
using System.IO;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
|
||||||
|
namespace CLre.API.Synergy
|
||||||
|
{
|
||||||
|
public struct SerializedCLreMessage: ISerializedNetData
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public byte[] Data;
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
writer.Write(Id);
|
||||||
|
writer.Write(Data.Length);
|
||||||
|
foreach (byte b in Data)
|
||||||
|
{
|
||||||
|
writer.Write(b);
|
||||||
|
}
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
Id = reader.ReadUInt32();
|
||||||
|
Data = new byte[reader.ReadInt32()];
|
||||||
|
for (int i = 0; i < Data.Length; i++)
|
||||||
|
{
|
||||||
|
Data[i] = reader.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,13 +98,23 @@ namespace CLre.API.Tools
|
||||||
{
|
{
|
||||||
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||||
Traverse d = Traverse.Create(data);
|
Traverse d = Traverse.Create(data);
|
||||||
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
string codeName = (short) code > 217 ? "CUSTOM" : code.ToString();
|
||||||
|
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {codeName} {(short)code})");
|
||||||
foreach (string fieldName in d.Fields())
|
foreach (string fieldName in d.Fields())
|
||||||
{
|
{
|
||||||
Traverse field = d.Field(fieldName);
|
Traverse field = d.Field(fieldName);
|
||||||
sb.Append("\n");
|
sb.Append("\n");
|
||||||
sb.Append("\"");
|
sb.Append("\"");
|
||||||
sb.Append(fieldName.Substring(fieldName.IndexOf('<')+1, fieldName.LastIndexOf('>')-1));
|
int start = fieldName.IndexOf('<');
|
||||||
|
int len = fieldName.LastIndexOf('>');
|
||||||
|
if (start != -1 && len > 0)
|
||||||
|
{
|
||||||
|
sb.Append(fieldName.Substring(start+1, len-1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(fieldName);
|
||||||
|
}
|
||||||
sb.Append("\": ");
|
sb.Append("\": ");
|
||||||
sb.Append(field.GetValue());
|
sb.Append(field.GetValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using GameNetworkLayer.Client;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using NetworkFramework.Shared;
|
using NetworkFramework.Shared;
|
||||||
|
@ -28,6 +29,10 @@ namespace CLre.API.Utility
|
||||||
public delegate T[] QueryEntitiesV1<T>(ExclusiveGroup.ExclusiveGroupStruct group, out int count) where T : IEntityStruct;
|
public delegate T[] QueryEntitiesV1<T>(ExclusiveGroup.ExclusiveGroupStruct group, out int count) where T : IEntityStruct;
|
||||||
|
|
||||||
public delegate object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;
|
public delegate object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate void INetMsgClientSender_SendMessage<T>(NetworkDispatcherCode code, ref T value) where T : struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate void INetMsgClientListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBClient<T> proc) where T: struct, ISerializedNetData;
|
||||||
|
|
||||||
// useful reflection functions
|
// useful reflection functions
|
||||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
||||||
|
|
17
CLre/CLre.cs
17
CLre/CLre.cs
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using CLre.API.Characters;
|
using CLre.API.Characters;
|
||||||
|
using CLre.API.Synergy;
|
||||||
using CLre.API.Tools;
|
using CLre.API.Tools;
|
||||||
using GameNetworkLayer.Shared;
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
@ -51,6 +52,9 @@ namespace CLre
|
||||||
Fixes.MiniScreenHelper.Init();
|
Fixes.MiniScreenHelper.Init();
|
||||||
Fixes.UnderStructureCollider.Init();
|
Fixes.UnderStructureCollider.Init();
|
||||||
|
|
||||||
|
// API init
|
||||||
|
API.Synergy.ClientHandshakeEngine.Init();
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
LogIPAPlugins();
|
LogIPAPlugins();
|
||||||
Fixes.BugfixAttributeUtility.LogBugfixes();
|
Fixes.BugfixAttributeUtility.LogBugfixes();
|
||||||
|
@ -71,10 +75,23 @@ namespace CLre
|
||||||
NetClientSender.DebugSendMessage(netData, harmonyInstance,
|
NetClientSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
NetClientSender.GetLogMethod(netData));
|
NetClientSender.GetLogMethod(netData));
|
||||||
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
||||||
|
|
||||||
|
netData = typeof(API.Synergy.SerializedCLreHandshake);
|
||||||
|
NetClientSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
|
NetClientSender.GetLogMethod(netData));
|
||||||
|
API.Utility.Logging.MetaLog("Patched SendMessage<SerializedCLreHandshake>");
|
||||||
|
|
||||||
NetClientListener.DebugReceiveMessage(NetworkDispatcherCode.EACMessageServerToClient,
|
NetClientListener.DebugReceiveMessage(NetworkDispatcherCode.EACMessageServerToClient,
|
||||||
NetClientListener.Log);
|
NetClientListener.Log);
|
||||||
|
|
||||||
|
NetClientListener.DebugReceiveMessage(API.Synergy.ClientHandshakeEngine.CLre_HANDSHAKE_NETCODE,
|
||||||
|
NetClientListener.Log);
|
||||||
|
|
||||||
|
NetClientListener.DebugReceiveMessage(NetworkDispatcherCode.SendIsPvEToClient,
|
||||||
|
NetClientListener.Log);
|
||||||
|
|
||||||
|
API.Utility.Logging.MetaLog($"Highest NetworkDispatcherCode number is {(int) NetworkDispatcherCode.StructureDestroyed} damn it Photon");
|
||||||
|
|
||||||
// API debug and testing
|
// API debug and testing
|
||||||
API.App.Client.InitComplete += (_, __) =>
|
API.App.Client.InitComplete += (_, __) =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<Version>0.0.2</Version>
|
<Version>0.0.3</Version>
|
||||||
<Authors>NGnius</Authors>
|
<Authors>NGnius</Authors>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageProjectUrl>https://git.exmods.org/NGnius/CLre</PackageProjectUrl>
|
<PackageProjectUrl>https://git.exmods.org/NGnius/CLre</PackageProjectUrl>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
using GameServer;
|
using GameServer;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using NetworkFramework.Server;
|
||||||
using Svelto.Context;
|
using Svelto.Context;
|
||||||
|
|
||||||
namespace CLre_server.API.MainServer
|
namespace CLre_server.API.MainServer
|
||||||
|
@ -45,6 +47,24 @@ namespace CLre_server.API.MainServer
|
||||||
add => ServerReadyEngine.serverFrameworkDestroyed += value;
|
add => ServerReadyEngine.serverFrameworkDestroyed += value;
|
||||||
remove => ServerReadyEngine.serverFrameworkDestroyed -= value;
|
remove => ServerReadyEngine.serverFrameworkDestroyed -= value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler<StartedEventArgs> Connected
|
||||||
|
{
|
||||||
|
add => PhotonNetwork_ConnectUsingSettings_Patch.postConnect += value;
|
||||||
|
remove => PhotonNetwork_ConnectUsingSettings_Patch.postConnect -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<PlayerConnectArgs> PlayerConnect
|
||||||
|
{
|
||||||
|
add => MainGameServer_SetupContainer_Patch.playerConnected += value;
|
||||||
|
remove => MainGameServer_SetupContainer_Patch.playerConnected -= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<PlayerConnectArgs> PlayerDisconnect
|
||||||
|
{
|
||||||
|
add => MainGameServer_SetupContainer_Patch.playerDisconnected += value;
|
||||||
|
remove => MainGameServer_SetupContainer_Patch.playerDisconnected -= value;
|
||||||
|
}
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
|
|
||||||
|
@ -73,6 +93,9 @@ namespace CLre_server.API.MainServer
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
public static void AfterMethodCall(GameServerSettings ____gameServerSettings)
|
public static void AfterMethodCall(GameServerSettings ____gameServerSettings)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Utility.Logging.MetaLog("Got GameServerSettings");
|
||||||
|
#endif
|
||||||
_gameServerSettings = ____gameServerSettings;
|
_gameServerSettings = ____gameServerSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,4 +167,38 @@ namespace CLre_server.API.MainServer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GameServer.GameFramework.MainGameServer), "SetupContainer")]
|
||||||
|
class MainGameServer_SetupContainer_Patch
|
||||||
|
{
|
||||||
|
internal static event EventHandler<PlayerConnectArgs> playerConnected;
|
||||||
|
|
||||||
|
internal static event EventHandler<PlayerConnectArgs> playerDisconnected;
|
||||||
|
|
||||||
|
private static GameServer.GameFramework.MainGameServer mgs = null;
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(GameServer.GameFramework.MainGameServer __instance, ref IPlayerConnectedCallbacks ____playerConnectedCallbacks)
|
||||||
|
{
|
||||||
|
mgs = __instance;
|
||||||
|
____playerConnectedCallbacks.OnPlayerConnected += OnConnect;
|
||||||
|
____playerConnectedCallbacks.OnPlayerDisconnected += OnDisconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnConnect(int playerId)
|
||||||
|
{
|
||||||
|
if (playerConnected != null) playerConnected(mgs, new PlayerConnectArgs
|
||||||
|
{
|
||||||
|
PlayerId = playerId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnDisconnect(int playerId)
|
||||||
|
{
|
||||||
|
if (playerDisconnected != null) playerDisconnected(mgs, new PlayerConnectArgs
|
||||||
|
{
|
||||||
|
PlayerId = playerId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using CLre_server.API.Engines;
|
using CLre_server.API.Engines;
|
||||||
using Game.DataLoader;
|
using Game.DataLoader;
|
||||||
using GameServer;
|
using GameServer;
|
||||||
|
@ -22,8 +23,8 @@ namespace CLre_server.API.MainServer
|
||||||
{
|
{
|
||||||
photonVersion = PhotonNetwork.gameVersion,
|
photonVersion = PhotonNetwork.gameVersion,
|
||||||
photonRegion = PhotonNetwork.CloudRegion,
|
photonRegion = PhotonNetwork.CloudRegion,
|
||||||
gameGuid = gss.GetGameGuid(),
|
gameGuid = gss == null ? "" : gss.GetGameGuid(),
|
||||||
worldName = gss.GetWorldName(),
|
worldName = gss == null ? "" : gss.GetWorldName(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +38,8 @@ namespace CLre_server.API.MainServer
|
||||||
{
|
{
|
||||||
photonVersion = PhotonNetwork.gameVersion,
|
photonVersion = PhotonNetwork.gameVersion,
|
||||||
photonRegion = PhotonNetwork.CloudRegion,
|
photonRegion = PhotonNetwork.CloudRegion,
|
||||||
gameGuid = gss.GetGameGuid(),
|
gameGuid = gss == null ? "" : gss.GetGameGuid(),
|
||||||
worldName = gss.GetWorldName(),
|
worldName = gss == null ? "" : gss.GetWorldName(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,4 +11,9 @@ namespace CLre_server.API.MainServer
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct StopEventArgs{}
|
public struct StopEventArgs{}
|
||||||
|
|
||||||
|
public struct PlayerConnectArgs
|
||||||
|
{
|
||||||
|
public int PlayerId;
|
||||||
|
}
|
||||||
}
|
}
|
95
CLre_server/API/MainServer/UserVerification.cs
Normal file
95
CLre_server/API/MainServer/UserVerification.cs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace CLre_server.API.MainServer
|
||||||
|
{
|
||||||
|
public class UserVerification
|
||||||
|
{
|
||||||
|
public static UserVerification Instance { get; internal set; }
|
||||||
|
|
||||||
|
private delegate void DisconnectPlayer_VerificationFailedProto(int playerId, string error);
|
||||||
|
private delegate void DisconnectPlayerProto(int playerId, NetworkDispatcherCode code);
|
||||||
|
|
||||||
|
private readonly DisconnectPlayer_VerificationFailedProto _disconnectPlayerVerificationFailed;
|
||||||
|
private readonly DisconnectPlayerProto _disconnectPlayer;
|
||||||
|
|
||||||
|
// This doesn't seem to do actually generate a popup, but it will stop the player from loading in
|
||||||
|
/*public void DisconnectPlayer_VerificationFailed(int playerId, string error)
|
||||||
|
{
|
||||||
|
_disconnectPlayerVerificationFailed(playerId, error);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public void DisconnectPlayer(int playerId, NetworkDispatcherCode code = NetworkDispatcherCode.ModVerificationFail)
|
||||||
|
{
|
||||||
|
_disconnectPlayer(playerId, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal UserVerification(IQueryingEntitiesEngine uvs)
|
||||||
|
{
|
||||||
|
Type uvsType = AccessTools.TypeByName("User.Server.UserVerificationServer");
|
||||||
|
_disconnectPlayerVerificationFailed =
|
||||||
|
Utility.Reflection.MethodAsDelegate<DisconnectPlayer_VerificationFailedProto>(uvsType,
|
||||||
|
"DisconnectPlayer_VerificationFailed",
|
||||||
|
//parameters: new [] {typeof(int), typeof(string)},
|
||||||
|
instance: uvs);
|
||||||
|
|
||||||
|
_disconnectPlayer =
|
||||||
|
Utility.Reflection.MethodAsDelegate<DisconnectPlayerProto>(uvsType, "DisconnectPlayer", instance: uvs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This seems to think that __instance is always simply a System.Object (caused by Harmony?), which doesn't work
|
||||||
|
/*[HarmonyPatch]
|
||||||
|
class UserVerificationServer_Constructor_Patch
|
||||||
|
{
|
||||||
|
|
||||||
|
private static IQueryingEntitiesEngine uvs = null;
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(IQueryingEntitiesEngine __instance)
|
||||||
|
{
|
||||||
|
uvs = __instance;
|
||||||
|
UserVerification.Instance = new UserVerification(__instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Constructor(AccessTools.TypeByName("User.Server.UserVerificationServer"));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
class MainGameServer_CreatePlayerDisconnectionSequence_Patch
|
||||||
|
{
|
||||||
|
|
||||||
|
private static IQueryingEntitiesEngine uvs = null;
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(IQueryingEntitiesEngine userVerificationEng)
|
||||||
|
{
|
||||||
|
uvs = userVerificationEng;
|
||||||
|
UserVerification.Instance = new UserVerification(userVerificationEng);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("GameServer.GameFramework.MainGameServer:CreatePlayerDisconnectionSequence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
CLre_server/API/Synergy/Message.cs
Normal file
68
CLre_server/API/Synergy/Message.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
|
||||||
|
namespace CLre_server.API.Synergy
|
||||||
|
{
|
||||||
|
public static class Message
|
||||||
|
{
|
||||||
|
internal const NetworkDispatcherCode CLre_MESSAGE_NETCODE = (NetworkDispatcherCode) 219;
|
||||||
|
|
||||||
|
private static readonly Dictionary<uint, Action<ReceiveMessageArgs>> handlers =
|
||||||
|
new Dictionary<uint, Action<ReceiveMessageArgs>>();
|
||||||
|
|
||||||
|
private static readonly ServerMessagingEngine msgEngine = new ServerMessagingEngine();
|
||||||
|
|
||||||
|
private static readonly List<int> clrePlayers = new List<int>();
|
||||||
|
|
||||||
|
public static void SendToAllCLreClients(ref SerializedCLreMessage message)
|
||||||
|
{
|
||||||
|
foreach (var playerId in clrePlayers)
|
||||||
|
{
|
||||||
|
SendCLreMessage(playerId, ref message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendCLreMessage(int playerId, ref SerializedCLreMessage message)
|
||||||
|
{
|
||||||
|
msgEngine.EnqueueMessage(playerId, ref message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterListener(uint id, Action<ReceiveMessageArgs> handler)
|
||||||
|
{
|
||||||
|
if (handlers.TryGetValue(id, out Action<ReceiveMessageArgs> existing))
|
||||||
|
{
|
||||||
|
existing += handler;
|
||||||
|
handlers[id] = existing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlers[id] = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void HandleMessageReceive(int playerId, ref SerializedCLreMessage msg)
|
||||||
|
{
|
||||||
|
ReceiveMessageArgs payload = new ReceiveMessageArgs
|
||||||
|
{
|
||||||
|
Message = msg,
|
||||||
|
PlayerId = playerId,
|
||||||
|
};
|
||||||
|
if (handlers.TryGetValue(msg.Id, out Action<ReceiveMessageArgs> h))
|
||||||
|
{
|
||||||
|
h(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void RegisterCLreClient(int playerId)
|
||||||
|
{
|
||||||
|
clrePlayers.Add(playerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ReceiveMessageArgs
|
||||||
|
{
|
||||||
|
public SerializedCLreMessage Message;
|
||||||
|
public int PlayerId;
|
||||||
|
}
|
||||||
|
}
|
161
CLre_server/API/Synergy/SerializedCLreHandshake.cs
Normal file
161
CLre_server/API/Synergy/SerializedCLreHandshake.cs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
|
||||||
|
namespace CLre_server.API.Synergy
|
||||||
|
{
|
||||||
|
struct SerializedCLreHandshake: ISerializedNetData
|
||||||
|
{
|
||||||
|
private byte major;
|
||||||
|
private byte minor;
|
||||||
|
private byte patch;
|
||||||
|
|
||||||
|
private HandshakeFlag flags;
|
||||||
|
|
||||||
|
private List<string> modInfo;
|
||||||
|
|
||||||
|
public Version Version
|
||||||
|
{
|
||||||
|
get => new Version(major, minor, patch);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
major = (byte)value.Major;
|
||||||
|
minor = (byte)value.Minor;
|
||||||
|
patch = (byte)value.Build;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> Mods
|
||||||
|
{
|
||||||
|
get => modInfo.ToArray();
|
||||||
|
set
|
||||||
|
{
|
||||||
|
modInfo.Clear();
|
||||||
|
foreach (var mod in value)
|
||||||
|
{
|
||||||
|
modInfo.Add(mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
// version
|
||||||
|
writer.Write(major);
|
||||||
|
writer.Write(minor);
|
||||||
|
writer.Write(patch);
|
||||||
|
writer.Write((uint)flags);
|
||||||
|
writer.Write(modInfo.Count);
|
||||||
|
foreach (string mod in modInfo)
|
||||||
|
{
|
||||||
|
writer.Write(mod);
|
||||||
|
}
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
// version
|
||||||
|
major = reader.ReadByte();
|
||||||
|
minor = reader.ReadByte();
|
||||||
|
patch = reader.ReadByte();
|
||||||
|
flags = (HandshakeFlag) reader.ReadUInt32();
|
||||||
|
int modCount = reader.ReadInt32();
|
||||||
|
modInfo = new List<string>(modCount);
|
||||||
|
for (int i = 0; i < modCount; i++)
|
||||||
|
{
|
||||||
|
modInfo.Add(reader.ReadString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
return (flags & f) != HandshakeFlag.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
flags |= f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsetFlag(HandshakeFlag f)
|
||||||
|
{
|
||||||
|
flags &= ~f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake Current()
|
||||||
|
{
|
||||||
|
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
List<string> mods = new List<string>();
|
||||||
|
foreach (var plugin in IllusionInjector.PluginManager.Plugins)
|
||||||
|
{
|
||||||
|
mods.Add(plugin.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = (byte) v.Major,
|
||||||
|
minor = (byte) v.Minor,
|
||||||
|
patch = (byte) v.Build,
|
||||||
|
flags = HandshakeFlag.Server,
|
||||||
|
modInfo = mods,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake RequireCLre()
|
||||||
|
{
|
||||||
|
Version v = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
List<string> mods = new List<string>(new []{Assembly.GetExecutingAssembly().GetName().Name});
|
||||||
|
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = (byte) v.Major,
|
||||||
|
minor = (byte) v.Minor,
|
||||||
|
patch = (byte) v.Build,
|
||||||
|
flags = HandshakeFlag.Client | HandshakeFlag.RequireAll,
|
||||||
|
modInfo = mods,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SerializedCLreHandshake Empty()
|
||||||
|
{
|
||||||
|
return new SerializedCLreHandshake
|
||||||
|
{
|
||||||
|
major = 0,
|
||||||
|
minor = 0,
|
||||||
|
patch = 0,
|
||||||
|
modInfo = new List<string>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"CLre {Version} ({modInfo.Count} mods)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
enum HandshakeFlag : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Client = 1,
|
||||||
|
Server = 1 << 1,
|
||||||
|
RequireAll = 1 << 2,
|
||||||
|
OptionalAll = 1 << 3,
|
||||||
|
Confirm = 1 << 4,
|
||||||
|
}
|
||||||
|
}
|
44
CLre_server/API/Synergy/SerializedCLreMessage.cs
Normal file
44
CLre_server/API/Synergy/SerializedCLreMessage.cs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
using System.IO;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
|
||||||
|
namespace CLre_server.API.Synergy
|
||||||
|
{
|
||||||
|
public struct SerializedCLreMessage: ISerializedNetData
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public byte[] Data;
|
||||||
|
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
writer.Write(Id);
|
||||||
|
writer.Write(Data.Length);
|
||||||
|
foreach (byte b in Data)
|
||||||
|
{
|
||||||
|
writer.Write(b);
|
||||||
|
}
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
Id = reader.ReadUInt32();
|
||||||
|
Data = new byte[reader.ReadInt32()];
|
||||||
|
for (int i = 0; i < Data.Length; i++)
|
||||||
|
{
|
||||||
|
Data[i] = reader.ReadByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
78
CLre_server/API/Synergy/ServerHandshakeEngine.cs
Normal file
78
CLre_server/API/Synergy/ServerHandshakeEngine.cs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
using System.Collections;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace CLre_server.API.Synergy
|
||||||
|
{
|
||||||
|
class ServerHandshakeEngine : Engines.ServerEnginePreBuild
|
||||||
|
{
|
||||||
|
internal static ServerHandshakeEngine Instance = null;
|
||||||
|
|
||||||
|
internal const NetworkDispatcherCode CLre_HANDSHAKE_NETCODE = (NetworkDispatcherCode) 218;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreHandshake> _sendMessage;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgServerListener_RegisterListener<SerializedCLreHandshake> _registerListener;
|
||||||
|
|
||||||
|
public override void Ready()
|
||||||
|
{
|
||||||
|
Utility.Logging.MetaLog("Building send message delegate");
|
||||||
|
_sendMessage =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreHandshake>>(
|
||||||
|
"GameNetworkLayer.Server.NetMessageServerSender:SendMessage",
|
||||||
|
generics: new [] {typeof(SerializedCLreHandshake)},
|
||||||
|
instance: MainGameServer_SetupContainer_Patch.netMessageSender);
|
||||||
|
|
||||||
|
Utility.Logging.MetaLog("Building register listener delegate");
|
||||||
|
_registerListener =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgServerListener_RegisterListener<SerializedCLreHandshake>>(
|
||||||
|
"GameNetworkLayer.Server.NetMessageServerListener:RegisterListener",
|
||||||
|
generics: new [] {typeof(SerializedCLreHandshake)},
|
||||||
|
instance: MainGameServer_SetupContainer_Patch.netMessageListener);
|
||||||
|
_registerListener(CLre_HANDSHAKE_NETCODE, OnHandshakeReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnHandshakeReceived(int playerId, ref SerializedCLreHandshake p)
|
||||||
|
{
|
||||||
|
// TODO validate handshake msg
|
||||||
|
Utility.Logging.MetaLog($"Received CLre handshake from player {playerId}! {p}");
|
||||||
|
Message.RegisterCLreClient(playerId);
|
||||||
|
SerializedCLreHandshake payload = SerializedCLreHandshake.Current();
|
||||||
|
payload.SetFlag(HandshakeFlag.Confirm);
|
||||||
|
Sender(payload, playerId).Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEntitiesDB entitiesDB { get; set; }
|
||||||
|
public override IEntityFactory entityFactory { get; set; }
|
||||||
|
|
||||||
|
public IEnumerator Sender(SerializedCLreHandshake payload, int playerId)
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
Utility.Logging.MetaLog("Sending Server CLre handshake");
|
||||||
|
_sendMessage(CLre_HANDSHAKE_NETCODE, ref payload, playerId);
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Init()
|
||||||
|
{
|
||||||
|
Instance = new ServerHandshakeEngine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(GameServer.GameFramework.MainGameServer), "SetupContainer")]
|
||||||
|
class MainGameServer_SetupContainer_Patch
|
||||||
|
{
|
||||||
|
internal static object netMessageListener;
|
||||||
|
|
||||||
|
internal static object netMessageSender;
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(object ____netMessageListener, object ____netMessageSender)
|
||||||
|
{
|
||||||
|
Utility.Logging.MetaLog($"Got NetMessage objects");
|
||||||
|
netMessageListener = ____netMessageListener;
|
||||||
|
netMessageSender = ____netMessageSender;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
CLre_server/API/Synergy/ServerMessagingEngine.cs
Normal file
96
CLre_server/API/Synergy/ServerMessagingEngine.cs
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using Svelto.Context;
|
||||||
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
namespace CLre_server.API.Synergy
|
||||||
|
{
|
||||||
|
class ServerMessagingEngine: Engines.ServerEnginePreBuild, IWaitForFrameworkDestruction, IWaitForFrameworkInitialization
|
||||||
|
{
|
||||||
|
private struct MessageQueueItem
|
||||||
|
{
|
||||||
|
public SerializedCLreMessage msg;
|
||||||
|
public int playerId;
|
||||||
|
public NetworkDispatcherCode code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreMessage> _sendMessage;
|
||||||
|
|
||||||
|
private Utility.Reflection.INetMsgServerListener_RegisterListener<SerializedCLreMessage> _registerListener;
|
||||||
|
|
||||||
|
private Queue<MessageQueueItem> _messageQueue = new Queue<MessageQueueItem>(10);
|
||||||
|
|
||||||
|
private bool _isRunning = false;
|
||||||
|
|
||||||
|
public override void Ready()
|
||||||
|
{
|
||||||
|
//Utility.Logging.MetaLog("Building send message delegate");
|
||||||
|
_sendMessage =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgServerSender_SendMessage<SerializedCLreMessage>>(
|
||||||
|
"GameNetworkLayer.Server.NetMessageServerSender:SendMessage",
|
||||||
|
generics: new [] {typeof(SerializedCLreMessage)},
|
||||||
|
instance: MainGameServer_SetupContainer_Patch.netMessageSender);
|
||||||
|
|
||||||
|
//Utility.Logging.MetaLog("Building register listener delegate");
|
||||||
|
_registerListener =
|
||||||
|
Utility.Reflection.MethodAsDelegate<Utility.Reflection.INetMsgServerListener_RegisterListener<SerializedCLreMessage>>(
|
||||||
|
"GameNetworkLayer.Server.NetMessageServerListener:RegisterListener",
|
||||||
|
generics: new [] {typeof(SerializedCLreMessage)},
|
||||||
|
instance: MainGameServer_SetupContainer_Patch.netMessageListener);
|
||||||
|
_registerListener(Message.CLre_MESSAGE_NETCODE, OnMessageReceived);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMessageReceived(int playerId, ref SerializedCLreMessage data)
|
||||||
|
{
|
||||||
|
Message.HandleMessageReceive(playerId, ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void EnqueueMessage(int playerId, ref SerializedCLreMessage msg)
|
||||||
|
{
|
||||||
|
_messageQueue.Enqueue(new MessageQueueItem
|
||||||
|
{
|
||||||
|
msg = msg,
|
||||||
|
playerId = playerId,
|
||||||
|
code = Message.CLre_MESSAGE_NETCODE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEntitiesDB entitiesDB { get; set; }
|
||||||
|
public override IEntityFactory entityFactory { get; set; }
|
||||||
|
|
||||||
|
public ServerMessagingEngine(): base()
|
||||||
|
{
|
||||||
|
MainServer.Server.Instance.Connected += (_, __) => { MessageSender().Run(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator MessageSender()
|
||||||
|
{
|
||||||
|
while (!_isRunning)
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
while (_isRunning)
|
||||||
|
{
|
||||||
|
while (_messageQueue.Count != 0)
|
||||||
|
{
|
||||||
|
MessageQueueItem item = _messageQueue.Dequeue();
|
||||||
|
API.Utility.Logging.MetaLog($"Sending message with id {item.msg.Id}");
|
||||||
|
_sendMessage(item.code, ref item.msg, item.playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFrameworkDestroyed()
|
||||||
|
{
|
||||||
|
_isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnFrameworkInitialized()
|
||||||
|
{
|
||||||
|
_isRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,13 +98,23 @@ namespace CLre_server.API.Tools
|
||||||
{
|
{
|
||||||
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||||
Traverse d = Traverse.Create(data);
|
Traverse d = Traverse.Create(data);
|
||||||
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
string codeName = (short) code > 217 ? "CUSTOM" : code.ToString();
|
||||||
|
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {codeName} {(short)code})");
|
||||||
foreach (string fieldName in d.Fields())
|
foreach (string fieldName in d.Fields())
|
||||||
{
|
{
|
||||||
Traverse field = d.Field(fieldName);
|
Traverse field = d.Field(fieldName);
|
||||||
sb.Append("\n");
|
sb.Append("\n");
|
||||||
sb.Append("\"");
|
sb.Append("\"");
|
||||||
sb.Append(fieldName.Substring(fieldName.IndexOf('<')+1, fieldName.LastIndexOf('>')-1));
|
int start = fieldName.IndexOf('<');
|
||||||
|
int len = fieldName.LastIndexOf('>');
|
||||||
|
if (start != -1 && len > 0)
|
||||||
|
{
|
||||||
|
sb.Append(fieldName.Substring(start+1, len-1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(fieldName);
|
||||||
|
}
|
||||||
sb.Append("\": ");
|
sb.Append("\": ");
|
||||||
sb.Append(field.GetValue());
|
sb.Append(field.GetValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ namespace CLre_server.API.Utility
|
||||||
public delegate T[] QueryEntitiesV1<T>(ExclusiveGroup.ExclusiveGroupStruct group, out int count) where T : IEntityStruct;
|
public delegate T[] QueryEntitiesV1<T>(ExclusiveGroup.ExclusiveGroupStruct group, out int count) where T : IEntityStruct;
|
||||||
|
|
||||||
public delegate object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;
|
public delegate object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate void INetMsgServerSender_SendMessage<T>(NetworkDispatcherCode code, ref T value, int playerId) where T : struct, ISerializedNetData;
|
||||||
|
|
||||||
|
public delegate void INetMsgServerListener_RegisterListener<T>(NetworkDispatcherCode code, NetCBServer<T> proc) where T: struct, ISerializedNetData;
|
||||||
|
|
||||||
|
|
||||||
// useful reflection functions
|
// useful reflection functions
|
||||||
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
|
||||||
|
|
|
@ -44,6 +44,9 @@ namespace CLre_server
|
||||||
// patches for bugs
|
// patches for bugs
|
||||||
Fixes.InitLogSooner.Init();
|
Fixes.InitLogSooner.Init();
|
||||||
|
|
||||||
|
// API init
|
||||||
|
API.Synergy.ServerHandshakeEngine.Init();
|
||||||
|
|
||||||
// misc
|
// misc
|
||||||
LogIPAPlugins(); // log plugins again so they show up in the log, and not just stdout
|
LogIPAPlugins(); // log plugins again so they show up in the log, and not just stdout
|
||||||
Fixes.BugfixAttributeUtility.LogBugfixes(); // log bugfixes that are applied
|
Fixes.BugfixAttributeUtility.LogBugfixes(); // log bugfixes that are applied
|
||||||
|
@ -59,10 +62,21 @@ namespace CLre_server
|
||||||
NetServerSender.DebugSendMessage(netData, harmonyInstance,
|
NetServerSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
NetServerSender.GetLogMethod(netData));
|
NetServerSender.GetLogMethod(netData));
|
||||||
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
||||||
|
|
||||||
|
netData = typeof(API.Synergy.SerializedCLreHandshake);
|
||||||
|
NetServerSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
|
NetServerSender.GetLogMethod(netData));
|
||||||
|
API.Utility.Logging.MetaLog("Patched SendMessage<SerializedCLreHandshake>");
|
||||||
|
|
||||||
NetServerListener.DebugReceiveMessage(NetworkDispatcherCode.EACMessageServerToClient,
|
NetServerListener.DebugReceiveMessage(NetworkDispatcherCode.EACMessageServerToClient,
|
||||||
NetServerListener.Log);
|
NetServerListener.Log);
|
||||||
|
|
||||||
|
NetServerListener.DebugReceiveMessage(NetworkDispatcherCode.SendIsPvEToClient,
|
||||||
|
NetServerListener.Log);
|
||||||
|
|
||||||
|
NetServerListener.DebugReceiveMessage(API.Synergy.ServerHandshakeEngine.CLre_HANDSHAKE_NETCODE,
|
||||||
|
NetServerListener.Log);
|
||||||
|
|
||||||
// API debug and testing
|
// API debug and testing
|
||||||
API.MainServer.Server.Instance.FrameworkReady += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework ready for business");
|
API.MainServer.Server.Instance.FrameworkReady += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework ready for business");
|
||||||
API.MainServer.Server.Instance.FrameworkExit += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework shutting down"); // this seems to never happen
|
API.MainServer.Server.Instance.FrameworkExit += (_, __) => API.Utility.Logging.MetaLog("(!) Server framework shutting down"); // this seems to never happen
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net472</TargetFramework>
|
<TargetFramework>net472</TargetFramework>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<Version>0.0.2</Version>
|
<Version>0.0.3</Version>
|
||||||
<Authors>NGnius</Authors>
|
<Authors>NGnius</Authors>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<PackageProjectUrl>https://git.exmods.org/NGnius/CLre</PackageProjectUrl>
|
<PackageProjectUrl>https://git.exmods.org/NGnius/CLre</PackageProjectUrl>
|
||||||
|
|
Loading…
Reference in a new issue