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