Add network debugging tools
This commit is contained in:
parent
9506d3af76
commit
84dec875b9
6 changed files with 240 additions and 6 deletions
55
CLre/API/Tools/AccessToolsWarnings.cs
Normal file
55
CLre/API/Tools/AccessToolsWarnings.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
namespace CLre.API.Tools
|
||||||
|
{
|
||||||
|
public static class AccessToolsWarnings
|
||||||
|
{
|
||||||
|
internal static bool isEnabled = false;
|
||||||
|
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Disable()
|
||||||
|
{
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AccessTools), "TypeByName")]
|
||||||
|
class AccessTools_TypeByName_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(Type __result, string name)
|
||||||
|
{
|
||||||
|
if (!AccessToolsWarnings.isEnabled) return;
|
||||||
|
if (__result == null)
|
||||||
|
{
|
||||||
|
var method = (new StackTrace()).GetFrame(2).GetMethod();
|
||||||
|
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.TypeByName(\"{name}\") returned null result");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(AccessTools), "Method",
|
||||||
|
new Type[] {typeof(string), typeof(Type[]), typeof(Type[])})]
|
||||||
|
class AccessTools_Method_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void AfterMethodCall(MethodInfo __result, string typeColonMethodname)
|
||||||
|
{
|
||||||
|
if (!AccessToolsWarnings.isEnabled) return;
|
||||||
|
if (__result == null)
|
||||||
|
{
|
||||||
|
var method = (new StackTrace()).GetFrame(2).GetMethod();
|
||||||
|
Utility.Logging.LogWarning($"[{method.DeclaringType.FullName}.{method.Name}] AccessTools.Method(\"{typeColonMethodname}\") returned null result");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
47
CLre/API/Tools/NetClientListener.cs
Normal file
47
CLre/API/Tools/NetClientListener.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace CLre.API.Tools
|
||||||
|
{
|
||||||
|
public class NetClientListener
|
||||||
|
{
|
||||||
|
internal static bool isEnabled = false;
|
||||||
|
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
isEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Disable()
|
||||||
|
{
|
||||||
|
isEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
class NetMessageClientListener_HandleAllMessages_Patch
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static void BeforeMethodCall(object ____deserializer, int playerId, object value)
|
||||||
|
{
|
||||||
|
if (!NetClientListener.isEnabled) return;
|
||||||
|
// TODO optimize this to not use Traverse
|
||||||
|
Traverse result = Traverse.Create(____deserializer).Method("Deserialize", value);
|
||||||
|
NetworkDispatcherCode code = result.Field<NetworkDispatcherCode>("dispatcherCode").Value;
|
||||||
|
byte[] data = result.Field<byte[]>("bytes").Value;
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
Utility.Logging.LogWarning("Network message data was deserialized as null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Utility.Logging.Log($"Received network message for player {playerId} (code: {code.ToString()}, len: {data.Length})");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyTargetMethod]
|
||||||
|
public static MethodBase Target()
|
||||||
|
{
|
||||||
|
return AccessTools.Method("GameNetworkLayer.Client.NetMessageClientListener:HandleAllMessages");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
CLre/API/Tools/NetClientSender.cs
Normal file
114
CLre/API/Tools/NetClientSender.cs
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
|
using HarmonyLib;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
|
|
||||||
|
namespace CLre.API.Tools
|
||||||
|
{
|
||||||
|
public class NetClientSender
|
||||||
|
{
|
||||||
|
private struct DummyNetDataStruct : ISerializedNetData
|
||||||
|
{
|
||||||
|
public byte[] Serialize()
|
||||||
|
{
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deserialize(byte[] data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly MethodInfo _genericSendMessage = AccessTools.Method("GameNetworkLayer.Client.NetMessageClientSender:SendMessage");
|
||||||
|
|
||||||
|
private static readonly MethodInfo _genericGetSendMessageMethod =
|
||||||
|
AccessTools.Method(typeof(NetClientSender), "GetSendMessageMethod",parameters: new Type[0]);/*
|
||||||
|
/*((Func<MethodInfo>) GetSendMessageMethod<DummyNetDataStruct>).Method
|
||||||
|
.GetBaseDefinition()
|
||||||
|
.GetGenericMethodDefinition();*/
|
||||||
|
|
||||||
|
private static readonly MethodInfo _genericLog =
|
||||||
|
AccessTools.Method(typeof(NetClientSender), "Log");/*
|
||||||
|
((Action<NetworkDispatcherCode, DummyNetDataStruct>) Log<DummyNetDataStruct>).Method
|
||||||
|
.GetBaseDefinition()
|
||||||
|
.GetGenericMethodDefinition();*/
|
||||||
|
|
||||||
|
private static readonly MethodInfo _genericGetLogMethod =
|
||||||
|
AccessTools.Method(typeof(NetClientSender), "GetLogMethod", new Type[0]);/*
|
||||||
|
((Func<MethodInfo>) GetLogMethod<DummyNetDataStruct>).Method
|
||||||
|
.GetBaseDefinition()
|
||||||
|
.GetGenericMethodDefinition();*/
|
||||||
|
|
||||||
|
public static MethodInfo GetSendMessageMethod(Type t)
|
||||||
|
{
|
||||||
|
return (MethodInfo) _genericGetSendMessageMethod.MakeGenericMethod(t)
|
||||||
|
.Invoke(null, new object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo GetSendMessageMethod<T>() where T : struct, ISerializedNetData
|
||||||
|
{
|
||||||
|
return _genericSendMessage.MakeGenericMethod(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo DebugSendMessage<T>(Harmony instance = null, MethodInfo before = null, MethodInfo after = null, MethodInfo transpiler = null, MethodInfo finalizer = null) where T : struct, ISerializedNetData
|
||||||
|
{
|
||||||
|
return DebugSendMessage(typeof(T), instance, before, after, transpiler, finalizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo DebugSendMessage(Type generic, Harmony instance = null, MethodInfo before = null, MethodInfo after = null, MethodInfo transpiler = null, MethodInfo finalizer = null)
|
||||||
|
{
|
||||||
|
return DebugSendMessage(
|
||||||
|
generic, instance,
|
||||||
|
before == null ? null : new HarmonyMethod(before),
|
||||||
|
after == null ? null : new HarmonyMethod(after),
|
||||||
|
transpiler == null ? null : new HarmonyMethod(transpiler),
|
||||||
|
finalizer == null ? null : new HarmonyMethod(finalizer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo DebugSendMessage<T>(Harmony instance = null, HarmonyMethod before = null, HarmonyMethod after = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null) where T : struct, ISerializedNetData
|
||||||
|
{
|
||||||
|
return DebugSendMessage(typeof(T), instance, before, after, transpiler, finalizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo DebugSendMessage(Type generic, Harmony instance = null, HarmonyMethod before = null, HarmonyMethod after = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null)
|
||||||
|
{
|
||||||
|
if (instance == null) instance = CLre.harmonyInstance;
|
||||||
|
MethodInfo target = GetSendMessageMethod(generic);
|
||||||
|
return instance.Patch(target,
|
||||||
|
before,
|
||||||
|
after,
|
||||||
|
transpiler,
|
||||||
|
finalizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo GetLogMethod(Type t)
|
||||||
|
{
|
||||||
|
return (MethodInfo) _genericGetLogMethod.MakeGenericMethod(t)
|
||||||
|
.Invoke(null, new object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodInfo GetLogMethod<T>() where T : struct, ISerializedNetData
|
||||||
|
{
|
||||||
|
return _genericLog.MakeGenericMethod(typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Log<T>(NetworkDispatcherCode code, ref T data) where T : struct, ISerializedNetData
|
||||||
|
{
|
||||||
|
//Utility.Logging.Log($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||||
|
Traverse d = Traverse.Create(data);
|
||||||
|
StringBuilder sb = new StringBuilder($"Sending ISerializedNetData {data.GetType().FullName} (code: {code.ToString()})");
|
||||||
|
foreach (string fieldName in d.Fields())
|
||||||
|
{
|
||||||
|
Traverse field = d.Field(fieldName);
|
||||||
|
sb.Append("\n");
|
||||||
|
sb.Append("\"");
|
||||||
|
sb.Append(fieldName.Substring(fieldName.IndexOf('<')+1, fieldName.LastIndexOf('>')-1));
|
||||||
|
sb.Append("\": ");
|
||||||
|
sb.Append(field.GetValue());
|
||||||
|
}
|
||||||
|
Utility.Logging.Log(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
|
using NetworkFramework.Shared;
|
||||||
using Svelto.DataStructures;
|
using Svelto.DataStructures;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
|
|
||||||
|
@ -25,6 +27,8 @@ 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;
|
||||||
|
|
||||||
// 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
|
||||||
{
|
{
|
||||||
|
|
21
CLre/CLre.cs
21
CLre/CLre.cs
|
@ -4,6 +4,8 @@ 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.Tools;
|
||||||
|
using GameNetworkLayer.Shared;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Svelto.ECS;
|
using Svelto.ECS;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -16,7 +18,7 @@ namespace CLre
|
||||||
|
|
||||||
public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||||
|
|
||||||
private Harmony harmonyInstance = null;
|
internal static Harmony harmonyInstance = null;
|
||||||
// called when Cardlife shuts down
|
// called when Cardlife shuts down
|
||||||
public override void OnApplicationQuit()
|
public override void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
|
@ -29,6 +31,9 @@ namespace CLre
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
FileLog.Reset();
|
FileLog.Reset();
|
||||||
Harmony.DEBUG = true;
|
Harmony.DEBUG = true;
|
||||||
|
// enable CLre debug functionality
|
||||||
|
AccessToolsWarnings.Enable();
|
||||||
|
NetClientListener.Enable();
|
||||||
Stopwatch startup = Stopwatch.StartNew();
|
Stopwatch startup = Stopwatch.StartNew();
|
||||||
#endif
|
#endif
|
||||||
// init all Harmony patches in project
|
// init all Harmony patches in project
|
||||||
|
@ -46,10 +51,22 @@ namespace CLre
|
||||||
API.Utility.Logging.MetaLog($"{Name} init complete.");
|
API.Utility.Logging.MetaLog($"{Name} init complete.");
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
// configure CLre debug functionality
|
||||||
|
Type netData = AccessTools.TypeByName("Game.Handhelds.DrawingStateMessage");
|
||||||
|
NetClientSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
|
NetClientSender.GetLogMethod(netData));
|
||||||
|
API.Utility.Logging.MetaLog("Patched SendMessage<Game.Handhelds.DrawingStateMessage>");
|
||||||
|
|
||||||
|
netData = AccessTools.TypeByName("Shared.Inventory.HandheldEquipmentRequest");
|
||||||
|
NetClientSender.DebugSendMessage(netData, harmonyInstance,
|
||||||
|
NetClientSender.GetLogMethod(netData));
|
||||||
|
API.Utility.Logging.MetaLog("Patched SendMessage<Shared.Inventory.HandheldEquipmentRequest>");
|
||||||
|
|
||||||
|
// API debug and testing
|
||||||
API.App.Client.InitComplete += (_, __) =>
|
API.App.Client.InitComplete += (_, __) =>
|
||||||
{
|
{
|
||||||
startup.Stop();
|
startup.Stop();
|
||||||
API.Utility.Logging.MetaLog($"Startup took {startup.ElapsedMilliseconds}ms");
|
API.Utility.Logging.Log($"Startup took {startup.ElapsedMilliseconds}ms");
|
||||||
API.Utility.Logging.Log(
|
API.Utility.Logging.Log(
|
||||||
$"EAC has detected code mods? {EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated}" +
|
$"EAC has detected code mods? {EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated}" +
|
||||||
(EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated
|
(EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Lib.Harmony" Version="2.0.0.10" />
|
<PackageReference Include="Lib.Harmony" Version="2.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -281,9 +281,6 @@
|
||||||
<HintPath>..\..\cl\Cardlife_Data\Managed\IllusionPlugin.dll</HintPath>
|
<HintPath>..\..\cl\Cardlife_Data\Managed\IllusionPlugin.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="API\Debug" />
|
|
||||||
</ItemGroup>
|
|
||||||
<!--End Dependencies-->
|
<!--End Dependencies-->
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in a new issue