HookInstance: Clean up generated patch code

This commit is contained in:
Sinai 2022-04-22 09:12:38 +10:00
parent 8b861f7c77
commit 97cb14d6fc

View File

@ -1,6 +1,7 @@
using HarmonyLib; using HarmonyLib;
using Mono.CSharp; using Mono.CSharp;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -20,6 +21,7 @@ namespace UnityExplorer.Hooks
static HookInstance() static HookInstance()
{ {
scriptEvaluator.Run("using System;"); scriptEvaluator.Run("using System;");
scriptEvaluator.Run("using System.Text;");
scriptEvaluator.Run("using System.Reflection;"); scriptEvaluator.Run("using System.Reflection;");
scriptEvaluator.Run("using System.Collections;"); scriptEvaluator.Run("using System.Collections;");
scriptEvaluator.Run("using System.Collections.Generic;"); scriptEvaluator.Run("using System.Collections.Generic;");
@ -39,10 +41,12 @@ namespace UnityExplorer.Hooks
private MethodInfo finalizer; private MethodInfo finalizer;
private MethodInfo transpiler; private MethodInfo transpiler;
private static readonly HashSet<string> namespaceUsings = new();
public HookInstance(MethodInfo targetMethod) public HookInstance(MethodInfo targetMethod)
{ {
this.TargetMethod = targetMethod; this.TargetMethod = targetMethod;
this.shortSignature = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}"; this.shortSignature = TargetMethod.FullDescription();
GenerateDefaultPatchSourceCode(targetMethod); GenerateDefaultPatchSourceCode(targetMethod);
@ -59,13 +63,17 @@ namespace UnityExplorer.Hooks
{ {
Unpatch(); Unpatch();
StringBuilder codeBuilder = new();
namespaceUsings.Clear();
try try
{ {
patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod); patchProcessor = ExplorerCore.Harmony.CreateProcessor(TargetMethod);
// Dynamically compile the patch method // Dynamically compile the patch method
StringBuilder codeBuilder = new(); foreach (string ns in namespaceUsings)
codeBuilder.AppendLine($"using {ns};");
codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}"); codeBuilder.AppendLine($"public class DynamicPatch_{DateTime.Now.Ticks}");
codeBuilder.AppendLine("{"); codeBuilder.AppendLine("{");
@ -108,6 +116,9 @@ namespace UnityExplorer.Hooks
catch (Exception ex) catch (Exception ex)
{ {
ExplorerCore.LogWarning($"Exception creating patch processor for target method {TargetMethod.FullDescription()}!\r\n{ex}"); ExplorerCore.LogWarning($"Exception creating patch processor for target method {TargetMethod.FullDescription()}!\r\n{ex}");
ExplorerCore.Log(codeBuilder.ToString());
return false; return false;
} }
} }
@ -115,15 +126,19 @@ namespace UnityExplorer.Hooks
private string GenerateDefaultPatchSourceCode(MethodInfo targetMethod) private string GenerateDefaultPatchSourceCode(MethodInfo targetMethod)
{ {
StringBuilder codeBuilder = new(); StringBuilder codeBuilder = new();
// Arguments
codeBuilder.Append("public static void Postfix(System.Reflection.MethodBase __originalMethod"); codeBuilder.Append("public static void Postfix("); // System.Reflection.MethodBase __originalMethod
if (!targetMethod.IsStatic) bool isStatic = targetMethod.IsStatic;
codeBuilder.Append($", {targetMethod.DeclaringType.FullName} __instance"); if (!isStatic)
codeBuilder.Append($"{targetMethod.DeclaringType.FullDescription()} __instance");
if (targetMethod.ReturnType != typeof(void)) if (targetMethod.ReturnType != typeof(void))
codeBuilder.Append($", {targetMethod.ReturnType.FullName} __result"); {
if (!isStatic)
codeBuilder.Append(", ");
codeBuilder.Append($"{targetMethod.ReturnType.FullDescription()} __result");
}
ParameterInfo[] parameters = targetMethod.GetParameters(); ParameterInfo[] parameters = targetMethod.GetParameters();
@ -139,42 +154,39 @@ namespace UnityExplorer.Hooks
// Patch body // Patch body
codeBuilder.AppendLine("{"); codeBuilder.AppendLine("{");
codeBuilder.AppendLine(" try {"); codeBuilder.AppendLine(" try {");
codeBuilder.AppendLine(" StringBuilder sb = new StringBuilder();");
// Log message codeBuilder.AppendLine($" sb.AppendLine(\"---- Patched called ----\");");
codeBuilder.AppendLine($" sb.AppendLine(\"{shortSignature}\");");
StringBuilder logMessage = new();
logMessage.Append($"Patch called: {shortSignature}\\n");
if (!targetMethod.IsStatic) if (!targetMethod.IsStatic)
logMessage.Append("__instance: {__instance.ToString()}\\n"); codeBuilder.AppendLine($" sb.Append(\"- __instance: \").AppendLine(__instance.ToString());");
paramIdx = 0; paramIdx = 0;
foreach (ParameterInfo param in parameters) foreach (ParameterInfo param in parameters)
{ {
logMessage.Append($"Parameter {paramIdx} {param.Name}: "); codeBuilder.Append($" sb.Append(\"- Parameter {paramIdx} '{param.Name}': \")");
Type pType = param.ParameterType; Type pType = param.ParameterType;
if (pType.IsByRef) pType = pType.GetElementType(); if (pType.IsByRef) pType = pType.GetElementType();
if (pType.IsValueType) if (pType.IsValueType)
logMessage.Append($"{{__{paramIdx}.ToString()}}"); codeBuilder.AppendLine($".AppendLine(__{paramIdx}.ToString());");
else else
logMessage.Append($"{{__{paramIdx}?.ToString() ?? \"null\"}}"); codeBuilder.AppendLine($".AppendLine(__{paramIdx}?.ToString() ?? \"null\");");
logMessage.Append("\\n");
paramIdx++; paramIdx++;
} }
if (targetMethod.ReturnType != typeof(void)) if (targetMethod.ReturnType != typeof(void))
{ {
logMessage.Append("Return value: "); codeBuilder.Append(" sb.Append(\"- Return value: \")");
if (targetMethod.ReturnType.IsValueType) if (targetMethod.ReturnType.IsValueType)
logMessage.Append("{__result.ToString()}"); codeBuilder.AppendLine(".AppendLine(__result.ToString());");
else else
logMessage.Append("{__result?.ToString() ?? \"null\"}"); codeBuilder.AppendLine(".AppendLine(__result?.ToString() ?? \"null\");");
logMessage.Append("\\n");
} }
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log($\"{logMessage}\");"); codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.Log(sb.ToString());");
codeBuilder.AppendLine(" }"); codeBuilder.AppendLine(" }");
codeBuilder.AppendLine(" catch (System.Exception ex) {"); codeBuilder.AppendLine(" catch (System.Exception ex) {");
codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.LogWarning($\"Exception in patch of {shortSignature}:\\n{{ex}}\");"); codeBuilder.AppendLine($" UnityExplorer.ExplorerCore.LogWarning($\"Exception in patch of {shortSignature}:\\n{{ex}}\");");