Skip to content

Commit

Permalink
Merge pull request #332 from amazingalek/unpatch
Browse files Browse the repository at this point in the history
Unpatching
  • Loading branch information
amazingalek authored Dec 23, 2020
2 parents 1b5121b + 5da0ca0 commit 1f5b4bd
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 30 deletions.
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions src/OWML.Common/Enums/PatchType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace OWML.Common
{
public enum PatchType
{
All = 0,

Prefix = 1,

Postfix = 2,

Transpiler = 3
}
}
6 changes: 6 additions & 0 deletions src/OWML.Common/Interfaces/IHarmonyHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@ namespace OWML.Common
public interface IHarmonyHelper
{
void AddPrefix<T>(string methodName, Type patchType, string patchMethodName);

void AddPrefix(MethodBase methodInfo, Type patchType, string patchMethodName);

void AddPostfix<T>(string methodName, Type patchType, string patchMethodName);

void AddPostfix(MethodBase methodInfo, Type patchType, string patchMethodName);

void EmptyMethod<T>(string methodName);

void EmptyMethod(MethodBase methodInfo);

void Transpile<T>(string methodName, Type patchType, string patchMethodName);

void Transpile(MethodBase methodInfo, Type patchType, string patchMethodName);

void Unpatch<T>(string methodName, PatchType patchType = PatchType.All);
}
}
3 changes: 3 additions & 0 deletions src/OWML.Common/OWML.Common.csproj.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=enums/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=interfaces/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
2 changes: 1 addition & 1 deletion src/OWML.Launcher/OWML.Manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"author": "Alek",
"name": "OWML",
"uniqueName": "Alek.OWML",
"version": "1.1.4",
"version": "1.1.5",
"description": "The mod loader and mod framework for Outer Wilds",
"minGameVersion": "1.0.7.0",
"maxGameVersion": "1.0.7.481"
Expand Down
88 changes: 60 additions & 28 deletions src/OWML.ModHelper.Events/HarmonyHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Harmony;
using OWML.Common;
Expand All @@ -17,7 +19,7 @@ public HarmonyHelper(IModConsole console, IModManifest manifest, IOwmlConfig owm
_console = console;
_manifest = manifest;
_owmlConfig = owmlConfig;

_harmony = CreateInstance();
}

Expand All @@ -43,30 +45,8 @@ private HarmonyInstance CreateInstance()
return harmony;
}

private MethodInfo GetMethod<T>(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<T>(string methodName, Type patchType, string patchMethodName)
{
public void AddPrefix<T>(string methodName, Type patchType, string patchMethodName) =>
AddPrefix(GetMethod<T>(methodName), patchType, patchMethodName);
}

public void AddPrefix(MethodBase original, Type patchType, string patchMethodName)
{
Expand All @@ -79,7 +59,7 @@ public void AddPrefix(MethodBase original, Type patchType, string patchMethodNam
Patch(original, prefix, null, null);
}

public void AddPostfix<T>(string methodName, Type patchType, string patchMethodName) =>
public void AddPostfix<T>(string methodName, Type patchType, string patchMethodName) =>
AddPostfix(GetMethod<T>(methodName), patchType, patchMethodName);

public void AddPostfix(MethodBase original, Type patchType, string patchMethodName)
Expand All @@ -93,13 +73,13 @@ public void AddPostfix(MethodBase original, Type patchType, string patchMethodNa
Patch(original, null, postfix, null);
}

public void EmptyMethod<T>(string methodName) =>
public void EmptyMethod<T>(string methodName) =>
EmptyMethod(GetMethod<T>(methodName));

public void EmptyMethod(MethodBase methodInfo) =>
public void EmptyMethod(MethodBase methodInfo) =>
Transpile(methodInfo, typeof(Patches), nameof(Patches.EmptyMethod));

public void Transpile<T>(string methodName, Type patchType, string patchMethodName) =>
public void Transpile<T>(string methodName, Type patchType, string patchMethodName) =>
Transpile(GetMethod<T>(methodName), patchType, patchMethodName);

public void Transpile(MethodBase original, Type patchType, string patchMethodName)
Expand All @@ -113,6 +93,38 @@ public void Transpile(MethodBase original, Type patchType, string patchMethodNam
Patch(original, null, null, patchMethod);
}

public void Unpatch<T>(string methodName, PatchType patchType = PatchType.All)
{
_console.WriteLine($"Unpatching {typeof(T).Name}.{methodName}", MessageType.Debug);

var sharedState = Utils.TypeExtensions.Invoke<Dictionary<MethodBase, byte[]>>(typeof(HarmonySharedState), "GetState");
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)
Expand All @@ -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<T>(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;
}
}
}
}
3 changes: 3 additions & 0 deletions src/OWML.Utils/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ public static void Invoke(this object obj, string name, params object[] paramete

public static T Invoke<T>(this object obj, string name, params object[] parameters) =>
(T)obj.GetType().GetAnyMethod(name)?.Invoke(obj, parameters);

public static T Invoke<T>(this Type type, string name, params object[] parameters) =>
(T)type.GetAnyMethod(name).Invoke(null, parameters);
}
}
24 changes: 23 additions & 1 deletion src/SampleMods/OWML.EnableDebugMode/EnableDebugMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ public void Update()
CycleGUIMode();
}

HandleWarping();

TestUnpatching();
}

private void HandleWarping()
{
if (ModHelper.Input.IsNewlyPressed(_inputs["Warp to Interloper"]))
{
WarpTo(SpawnLocation.Comet);
Expand Down Expand Up @@ -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<PlayerCharacterController>("ApplyJump");
}

if (Input.GetKeyDown(KeyCode.F8))
{
ModHelper.Console.WriteLine("Restoring Jump");
ModHelper.HarmonyHelper.Unpatch<PlayerCharacterController>("ApplyJump");
}
}
}
}
}

0 comments on commit 1f5b4bd

Please sign in to comment.