From 84168f9c2d4e690cab0c2d35a7acce3c6feb0389 Mon Sep 17 00:00:00 2001 From: Aleksander Waage Date: Wed, 23 Dec 2020 10:02:39 +0100 Subject: [PATCH] unpatching works --- src/OWML.Common/{ => Enums}/Events.cs | 0 src/OWML.Common/{ => Enums}/MessageType.cs | 0 src/OWML.Common/Enums/PatchType.cs | 13 +++ src/OWML.Common/Interfaces/IHarmonyHelper.cs | 6 ++ .../OWML.Common.csproj.DotSettings | 3 + src/OWML.ModHelper.Events/HarmonyHelper.cs | 88 +++++++++++++------ .../OWML.EnableDebugMode/EnableDebugMode.cs | 24 ++++- 7 files changed, 105 insertions(+), 29 deletions(-) rename src/OWML.Common/{ => Enums}/Events.cs (100%) rename src/OWML.Common/{ => Enums}/MessageType.cs (100%) create mode 100644 src/OWML.Common/Enums/PatchType.cs create mode 100644 src/OWML.Common/OWML.Common.csproj.DotSettings diff --git a/src/OWML.Common/Events.cs b/src/OWML.Common/Enums/Events.cs similarity index 100% rename from src/OWML.Common/Events.cs rename to src/OWML.Common/Enums/Events.cs diff --git a/src/OWML.Common/MessageType.cs b/src/OWML.Common/Enums/MessageType.cs similarity index 100% rename from src/OWML.Common/MessageType.cs rename to src/OWML.Common/Enums/MessageType.cs diff --git a/src/OWML.Common/Enums/PatchType.cs b/src/OWML.Common/Enums/PatchType.cs new file mode 100644 index 000000000..4c80f361d --- /dev/null +++ b/src/OWML.Common/Enums/PatchType.cs @@ -0,0 +1,13 @@ +namespace OWML.Common +{ + public enum PatchType + { + All = 0, + + Prefix = 1, + + Postfix = 2, + + Transpiler = 3 + } +} diff --git a/src/OWML.Common/Interfaces/IHarmonyHelper.cs b/src/OWML.Common/Interfaces/IHarmonyHelper.cs index 2d8ebb81a..525851704 100644 --- a/src/OWML.Common/Interfaces/IHarmonyHelper.cs +++ b/src/OWML.Common/Interfaces/IHarmonyHelper.cs @@ -6,15 +6,21 @@ namespace OWML.Common public interface IHarmonyHelper { void AddPrefix(string methodName, Type patchType, string patchMethodName); + void AddPrefix(MethodBase methodInfo, Type patchType, string patchMethodName); void AddPostfix(string methodName, Type patchType, string patchMethodName); + void AddPostfix(MethodBase methodInfo, Type patchType, string patchMethodName); void EmptyMethod(string methodName); + void EmptyMethod(MethodBase methodInfo); void Transpile(string methodName, Type patchType, string patchMethodName); + void Transpile(MethodBase methodInfo, Type patchType, string patchMethodName); + + void Unpatch(string methodName, PatchType patchType = PatchType.All); } } diff --git a/src/OWML.Common/OWML.Common.csproj.DotSettings b/src/OWML.Common/OWML.Common.csproj.DotSettings new file mode 100644 index 000000000..725864905 --- /dev/null +++ b/src/OWML.Common/OWML.Common.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/src/OWML.ModHelper.Events/HarmonyHelper.cs b/src/OWML.ModHelper.Events/HarmonyHelper.cs index 6f9dfa67a..35da5f521 100644 --- a/src/OWML.ModHelper.Events/HarmonyHelper.cs +++ b/src/OWML.ModHelper.Events/HarmonyHelper.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; using Harmony; using OWML.Common; @@ -17,7 +19,7 @@ public HarmonyHelper(IModConsole console, IModManifest manifest, IOwmlConfig owm _console = console; _manifest = manifest; _owmlConfig = owmlConfig; - + _harmony = CreateInstance(); } @@ -43,30 +45,8 @@ private HarmonyInstance CreateInstance() return harmony; } - private MethodInfo GetMethod(string methodName) - { - var targetType = typeof(T); - MethodInfo result = null; - try - { - _console.WriteLine($"Getting method {methodName} of {targetType.Name}", MessageType.Debug); - result = Utils.TypeExtensions.GetAnyMethod(targetType, methodName); - } - catch (Exception ex) - { - _console.WriteLine($"Exception while getting method {methodName} of {targetType.Name}: {ex}", MessageType.Error); - } - if (result == null) - { - _console.WriteLine($"Error - Original method {methodName} of class {targetType} not found.", MessageType.Error); - } - return result; - } - - public void AddPrefix(string methodName, Type patchType, string patchMethodName) - { + public void AddPrefix(string methodName, Type patchType, string patchMethodName) => AddPrefix(GetMethod(methodName), patchType, patchMethodName); - } public void AddPrefix(MethodBase original, Type patchType, string patchMethodName) { @@ -79,7 +59,7 @@ public void AddPrefix(MethodBase original, Type patchType, string patchMethodNam Patch(original, prefix, null, null); } - public void AddPostfix(string methodName, Type patchType, string patchMethodName) => + public void AddPostfix(string methodName, Type patchType, string patchMethodName) => AddPostfix(GetMethod(methodName), patchType, patchMethodName); public void AddPostfix(MethodBase original, Type patchType, string patchMethodName) @@ -93,13 +73,13 @@ public void AddPostfix(MethodBase original, Type patchType, string patchMethodNa Patch(original, null, postfix, null); } - public void EmptyMethod(string methodName) => + public void EmptyMethod(string methodName) => EmptyMethod(GetMethod(methodName)); - public void EmptyMethod(MethodBase methodInfo) => + public void EmptyMethod(MethodBase methodInfo) => Transpile(methodInfo, typeof(Patches), nameof(Patches.EmptyMethod)); - public void Transpile(string methodName, Type patchType, string patchMethodName) => + public void Transpile(string methodName, Type patchType, string patchMethodName) => Transpile(GetMethod(methodName), patchType, patchMethodName); public void Transpile(MethodBase original, Type patchType, string patchMethodName) @@ -113,6 +93,38 @@ public void Transpile(MethodBase original, Type patchType, string patchMethodNam Patch(original, null, null, patchMethod); } + public void Unpatch(string methodName, PatchType patchType = PatchType.All) + { + _console.WriteLine($"Unpatching {typeof(T).Name}.{methodName}", MessageType.Debug); + + var sharedState = (Dictionary)typeof(HarmonySharedState).GetAnyMethod("GetState").Invoke(null, null); // todo TypeExtension + var method = sharedState.Keys.First(m => m.DeclaringType == typeof(T) && m.Name == methodName); + var patchInfo = PatchInfoSerialization.Deserialize(sharedState.GetValueSafe(method)); + + switch (patchType) + { + case PatchType.Prefix: + patchInfo.RemovePrefix(_manifest.UniqueName); + break; + case PatchType.Postfix: + patchInfo.RemovePostfix(_manifest.UniqueName); + break; + case PatchType.Transpiler: + patchInfo.RemoveTranspiler(_manifest.UniqueName); + break; + case PatchType.All: + patchInfo.RemovePostfix(_manifest.UniqueName); + patchInfo.RemovePrefix(_manifest.UniqueName); + patchInfo.RemoveTranspiler(_manifest.UniqueName); + break; + } + + PatchFunctions.UpdateWrapper(method, patchInfo, _manifest.UniqueName); + sharedState[method] = patchInfo.Serialize(); + + _console.WriteLine($"Unpatched {typeof(T).Name}.{methodName}!", MessageType.Debug); + } + private void Patch(MethodBase original, MethodInfo prefix, MethodInfo postfix, MethodInfo transpiler) { if (original == null) @@ -134,5 +146,25 @@ private void Patch(MethodBase original, MethodInfo prefix, MethodInfo postfix, M _console.WriteLine($"Exception while patching {fullName}: {ex}", MessageType.Error); } } + + private MethodInfo GetMethod(string methodName) + { + var fullName = $"{typeof(T).Name}.{methodName}"; + try + { + _console.WriteLine($"Getting method {fullName}", MessageType.Debug); + var result = Utils.TypeExtensions.GetAnyMethod(typeof(T), methodName); + if (result == null) + { + _console.WriteLine($"Error - method {fullName} not found.", MessageType.Error); + } + return result; + } + catch (Exception ex) + { + _console.WriteLine($"Exception while getting method {fullName}: {ex}", MessageType.Error); + return null; + } + } } } diff --git a/src/SampleMods/OWML.EnableDebugMode/EnableDebugMode.cs b/src/SampleMods/OWML.EnableDebugMode/EnableDebugMode.cs index b169f4b2a..9433002be 100644 --- a/src/SampleMods/OWML.EnableDebugMode/EnableDebugMode.cs +++ b/src/SampleMods/OWML.EnableDebugMode/EnableDebugMode.cs @@ -58,6 +58,13 @@ public void Update() CycleGUIMode(); } + HandleWarping(); + + TestUnpatching(); + } + + private void HandleWarping() + { if (ModHelper.Input.IsNewlyPressed(_inputs["Warp to Interloper"])) { WarpTo(SpawnLocation.Comet); @@ -112,5 +119,20 @@ private void WarpTo(SpawnLocation location) ModHelper.Console.WriteLine($"Warping to {location}!"); _playerSpawner.DebugWarp(_playerSpawner.GetSpawnPoint(location)); } + + private void TestUnpatching() + { + if (Input.GetKeyDown(KeyCode.F7)) + { + ModHelper.Console.WriteLine("Removing Jump"); + ModHelper.HarmonyHelper.EmptyMethod("ApplyJump"); + } + + if (Input.GetKeyDown(KeyCode.F8)) + { + ModHelper.Console.WriteLine("Restoring Jump"); + ModHelper.HarmonyHelper.Unpatch("ApplyJump"); + } + } } -} +} \ No newline at end of file