Merge pull request #332 from amazingalek/unpatch

Unpatching
This commit is contained in:
AmazingAlek 2020-12-23 11:04:16 +01:00 committed by GitHub
commit 1f5b4bdbc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 30 deletions

View File

@ -0,0 +1,13 @@
namespace OWML.Common
{
public enum PatchType
{
All = 0,
Prefix = 1,
Postfix = 2,
Transpiler = 3
}
}

View File

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

View File

@ -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>

View File

@ -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"

View File

@ -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 @@ namespace OWML.ModHelper.Events
_console = console;
_manifest = manifest;
_owmlConfig = owmlConfig;
_harmony = CreateInstance();
}
@ -43,30 +45,8 @@ namespace OWML.ModHelper.Events
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)
{
@ -79,7 +59,7 @@ namespace OWML.ModHelper.Events
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)
@ -93,13 +73,13 @@ namespace OWML.ModHelper.Events
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)
@ -113,6 +93,38 @@ namespace OWML.ModHelper.Events
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)
@ -134,5 +146,25 @@ namespace OWML.ModHelper.Events
_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;
}
}
}
}

View File

@ -44,5 +44,8 @@ namespace OWML.Utils
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);
}
}

View File

@ -58,6 +58,13 @@ namespace OWML.EnableDebugMode
CycleGUIMode();
}
HandleWarping();
TestUnpatching();
}
private void HandleWarping()
{
if (ModHelper.Input.IsNewlyPressed(_inputs["Warp to Interloper"]))
{
WarpTo(SpawnLocation.Comet);
@ -112,5 +119,20 @@ namespace OWML.EnableDebugMode
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");
}
}
}
}
}