using System.Reflection; using System.Text; using GameNetworkLayer.Shared; using HarmonyLib; using Svelto.DataStructures; using Svelto.DataStructures.Experimental; namespace CLre_server.API.Tools { public class NetServerListener { internal static bool isEnabled = false; private static FasterDictionary> callbacks = new FasterDictionary>(); public delegate void NetReceiveMessageCallback(NetworkDispatcherCode code, byte[] data, int playerId); public static void Enable() { isEnabled = true; } public static void Disable() { isEnabled = false; } public static void DebugReceiveMessage(NetworkDispatcherCode code, NetReceiveMessageCallback callback) { short key = (short)code; if (callbacks.TryGetValue(key, out FasterList handlers)) { handlers.Add(callback); } else { FasterList newHandlers = new FasterList(new [] {callback}); callbacks.Add(key, newHandlers); } } internal static bool RunDebugCallbacks(NetworkDispatcherCode code, byte[] data, int playerId) { short key = (short)code; if (callbacks.TryGetValue(key, out FasterList handlers)) { foreach (NetReceiveMessageCallback callback in handlers) { callback(code, data, playerId); } return true; } else { return false; } } public static void Log(NetworkDispatcherCode code, byte[] data, int playerId) { StringBuilder sb = new StringBuilder("Received "); sb.Append(code.ToString()); sb.Append(" for player #"); sb.Append(playerId); sb.Append(": 0x"); foreach (byte b in data) { sb.Append(b.ToString("X")); } Utility.Logging.Log(sb.ToString()); } } [HarmonyPatch] class NetMessageClientListener_HandleAllMessages_Patch { [HarmonyPrefix] public static void BeforeMethodCall(object ____deserializer, int playerId, object value) { if (!NetServerListener.isEnabled) return; // TODO optimize this to not use Traverse Traverse result = Traverse.Create(____deserializer).Method("Deserialize", value); NetworkDispatcherCode code = result.Field("dispatcherCode").Value; byte[] data = result.Field("bytes").Value; if (data == null) { Utility.Logging.LogWarning("Network message data was deserialized as null"); return; } bool isHandled = NetServerListener.RunDebugCallbacks(code, data, playerId); if (!isHandled) Utility.Logging.Log($"Received network message for player {playerId} (code: {code.ToString()}, len: {data.Length})"); } [HarmonyTargetMethod] public static MethodBase Target() { return AccessTools.Method("GameNetworkLayer.Server.NetMessageServerListener:HandleAllMessages"); } } }