Browse Source

Add network debugging tools

tags/v0.0.2
NGnius (Graham) 3 years ago
parent
commit
84dec875b9
6 changed files with 240 additions and 6 deletions
  1. +55
    -0
      CLre/API/Tools/AccessToolsWarnings.cs
  2. +47
    -0
      CLre/API/Tools/NetClientListener.cs
  3. +114
    -0
      CLre/API/Tools/NetClientSender.cs
  4. +4
    -0
      CLre/API/Utility/Reflection.cs
  5. +19
    -2
      CLre/CLre.cs
  6. +1
    -4
      CLre/CLre.csproj

+ 55
- 0
CLre/API/Tools/AccessToolsWarnings.cs View 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
- 0
CLre/API/Tools/NetClientListener.cs View 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
- 0
CLre/API/Tools/NetClientSender.cs View 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());
}
}
}

+ 4
- 0
CLre/API/Utility/Reflection.cs View File

@@ -1,6 +1,8 @@
using System;
using System.Reflection;
using GameNetworkLayer.Shared;
using HarmonyLib;
using NetworkFramework.Shared;
using Svelto.DataStructures;
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 object[] SendMessage<T>(NetworkDispatcherCode dispatcherCode, ref T value) where T : struct, ISerializedNetData;

// useful reflection functions
public static TFuncProto BuildDelegate<TFuncProto>(MethodInfo method) where TFuncProto : Delegate
{


+ 19
- 2
CLre/CLre.cs View File

@@ -4,6 +4,8 @@ using System.Linq;
using System.Reflection;
using System.Text;
using CLre.API.Characters;
using CLre.API.Tools;
using GameNetworkLayer.Shared;
using HarmonyLib;
using Svelto.ECS;
using UnityEngine;
@@ -16,7 +18,7 @@ namespace CLre

public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();

private Harmony harmonyInstance = null;
internal static Harmony harmonyInstance = null;
// called when Cardlife shuts down
public override void OnApplicationQuit()
{
@@ -29,6 +31,9 @@ namespace CLre
#if DEBUG
FileLog.Reset();
Harmony.DEBUG = true;
// enable CLre debug functionality
AccessToolsWarnings.Enable();
NetClientListener.Enable();
Stopwatch startup = Stopwatch.StartNew();
#endif
// init all Harmony patches in project
@@ -46,10 +51,22 @@ namespace CLre
API.Utility.Logging.MetaLog($"{Name} init complete.");

#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 += (_, __) =>
{
startup.Stop();
API.Utility.Logging.MetaLog($"Startup took {startup.ElapsedMilliseconds}ms");
API.Utility.Logging.Log($"Startup took {startup.ElapsedMilliseconds}ms");
API.Utility.Logging.Log(
$"EAC has detected code mods? {EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated}" +
(EasyAntiCheat.Client.Hydra.Runtime.Integrity.Violated


+ 1
- 4
CLre/CLre.csproj View File

@@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.0.0.10" />
<PackageReference Include="Lib.Harmony" Version="2.0.4" />
</ItemGroup>
<ItemGroup>
@@ -281,9 +281,6 @@
<HintPath>..\..\cl\Cardlife_Data\Managed\IllusionPlugin.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Folder Include="API\Debug" />
</ItemGroup>
<!--End Dependencies-->

</Project>

Loading…
Cancel
Save