diff --git a/Directory.Build.props b/Directory.Build.props
index 7c78cd3d..2cbffd1a 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,7 +1,7 @@
- 21.1.12.5
+ 21.6.21.1
diff --git a/Harmony/Harmony.csproj b/Harmony/Harmony.csproj
index 7b098527..6282c8d9 100644
--- a/Harmony/Harmony.csproj
+++ b/Harmony/Harmony.csproj
@@ -11,13 +11,13 @@
Andreas Pardeike
0Harmony
true
- 2.0.5.0
+ 2.1.0.0
LICENSE
https://github.com/pardeike/Harmony
false
Harmony,Mono,Patch,Patching,Runtime,Detour,Detours,Aspect,Aspects
- 2.0.5.0
- 2.0.5.0
+ 2.1.0.0
+ 2.1.0.0
HarmonyLogo.png
https://raw.githubusercontent.com/pardeike/Harmony/master/HarmonyLogo.png
true
diff --git a/Harmony/Internal/MethodPatcher.cs b/Harmony/Internal/MethodPatcher.cs
index 411c812b..362019fa 100644
--- a/Harmony/Internal/MethodPatcher.cs
+++ b/Harmony/Internal/MethodPatcher.cs
@@ -17,6 +17,7 @@ internal class MethodPatcher
const string RESULT_VAR = "__result";
const string STATE_VAR = "__state";
const string EXCEPTION_VAR = "__exception";
+ const string RUN_ORIGINA_VAR = "__runOriginal";
const string PARAM_INDEX_PREFIX = "__";
const string INSTANCE_FIELD_PREFIX = "___";
@@ -92,14 +93,14 @@ internal MethodInfo CreateReplacement(out Dictionary final
prefixes.Union(postfixes).Union(finalizers).ToList().ForEach(fix =>
{
- if (fix.DeclaringType is object && privateVars.ContainsKey(fix.DeclaringType.FullName) is false)
+ if (fix.DeclaringType is object && privateVars.ContainsKey(fix.DeclaringType.AssemblyQualifiedName) is false)
{
fix.GetParameters()
.Where(patchParam => patchParam.Name == STATE_VAR)
.Do(patchParam =>
{
var privateStateVariable = DeclareLocalVariable(patchParam.ParameterType);
- privateVars[fix.DeclaringType.FullName] = privateStateVariable;
+ privateVars[fix.DeclaringType.AssemblyQualifiedName] = privateStateVariable;
});
}
});
@@ -358,7 +359,7 @@ bool EmitOriginalBaseMethod()
return true;
}
- void EmitCallParameter(MethodInfo patch, Dictionary variables, bool allowFirsParamPassthrough, out LocalBuilder tmpObjectVar, List> tmpBoxVars)
+ void EmitCallParameter(MethodInfo patch, Dictionary variables, LocalBuilder runOriginalVariable, bool allowFirsParamPassthrough, out LocalBuilder tmpObjectVar, List> tmpBoxVars)
{
tmpObjectVar = null;
var isInstance = original.IsStatic is false;
@@ -381,6 +382,15 @@ void EmitCallParameter(MethodInfo patch, Dictionary variab
continue;
}
+ if (patchParam.Name == RUN_ORIGINA_VAR)
+ {
+ if (runOriginalVariable != null)
+ emitter.Emit(OpCodes.Ldloc, runOriginalVariable);
+ else
+ emitter.Emit(OpCodes.Ldc_I4_0);
+ continue;
+ }
+
if (patchParam.Name == INSTANCE_PARAM)
{
if (original.IsStatic)
@@ -415,13 +425,13 @@ void EmitCallParameter(MethodInfo patch, Dictionary variab
// field access by index only works for declared fields
fieldInfo = AccessTools.DeclaredField(original.DeclaringType, int.Parse(fieldName));
if (fieldInfo is null)
- throw new ArgumentException($"No field found at given index in class {original.DeclaringType.FullName}", fieldName);
+ throw new ArgumentException($"No field found at given index in class {original.DeclaringType.AssemblyQualifiedName}", fieldName);
}
else
{
fieldInfo = AccessTools.Field(original.DeclaringType, fieldName);
if (fieldInfo is null)
- throw new ArgumentException($"No such field defined in class {original.DeclaringType.FullName}", fieldName);
+ throw new ArgumentException($"No such field defined in class {original.DeclaringType.AssemblyQualifiedName}", fieldName);
}
if (fieldInfo.IsStatic)
@@ -438,7 +448,7 @@ void EmitCallParameter(MethodInfo patch, Dictionary variab
if (patchParam.Name == STATE_VAR)
{
var ldlocCode = patchParam.ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc;
- if (variables.TryGetValue(patch.DeclaringType.FullName, out var stateVar))
+ if (variables.TryGetValue(patch.DeclaringType.AssemblyQualifiedName, out var stateVar))
emitter.Emit(ldlocCode, stateVar);
else
emitter.Emit(OpCodes.Ldnull);
@@ -642,7 +652,7 @@ void AddPrefixes(Dictionary variables, LocalBuilder runOri
}
var tmpBoxVars = new List>();
- EmitCallParameter(fix, variables, false, out var tmpObjectVar, tmpBoxVars);
+ EmitCallParameter(fix, variables, runOriginalVariable, false, out var tmpObjectVar, tmpBoxVars);
emitter.Emit(OpCodes.Call, fix);
if (tmpObjectVar != null)
{
@@ -685,7 +695,7 @@ bool AddPostfixes(Dictionary variables, bool passthroughPa
throw new Exception("Methods without body cannot have postfixes. Use a transpiler instead.");
var tmpBoxVars = new List>();
- EmitCallParameter(fix, variables, true, out var tmpObjectVar, tmpBoxVars);
+ EmitCallParameter(fix, variables, null, true, out var tmpObjectVar, tmpBoxVars);
emitter.Emit(OpCodes.Call, fix);
if (tmpObjectVar != null)
{
@@ -732,7 +742,7 @@ bool AddFinalizers(Dictionary variables, bool catchExcepti
emitter.MarkBlockBefore(new ExceptionBlock(ExceptionBlockType.BeginExceptionBlock), out var label);
var tmpBoxVars = new List>();
- EmitCallParameter(fix, variables, false, out var tmpObjectVar, tmpBoxVars);
+ EmitCallParameter(fix, variables, null, false, out var tmpObjectVar, tmpBoxVars);
emitter.Emit(OpCodes.Call, fix);
if (tmpObjectVar != null)
{
diff --git a/Harmony/Public/Harmony.cs b/Harmony/Public/Harmony.cs
index d0c7f87f..e1f63809 100644
--- a/Harmony/Public/Harmony.cs
+++ b/Harmony/Public/Harmony.cs
@@ -1,3 +1,4 @@
+using MonoMod.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -50,7 +51,9 @@ public Harmony(string id)
#if !NET5_0
if (string.IsNullOrEmpty(location)) location = new Uri(assembly.CodeBase).LocalPath;
#endif
- FileLog.Log($"### Harmony id={id}, version={version}, location={location}, env/clr={environment}, platform={platform}");
+ var ptr_runtime = IntPtr.Size;
+ var ptr_env = PlatformHelper.Current;
+ FileLog.Log($"### Harmony id={id}, version={version}, location={location}, env/clr={environment}, platform={platform}, ptrsize:runtime/env={ptr_runtime}/{ptr_env}");
var callingMethod = AccessTools.GetOutsideCaller();
if (callingMethod.DeclaringType is object)
{
@@ -68,6 +71,7 @@ public Harmony(string id)
}
/// Searches the current assembly for Harmony annotations and uses them to create patches
+ /// This method can fail to use the correct assembly when being inlined. It calls StackTrace.GetFrame(1) which can point to the wrong method/assembly. If you are unsure or run into problems, use PatchAll(Assembly.GetExecutingAssembly())
instead.
///
public void PatchAll()
{
diff --git a/HarmonyTests/Patching/Assets/PatchClasses.cs b/HarmonyTests/Patching/Assets/PatchClasses.cs
index 94082c1b..13605e42 100644
--- a/HarmonyTests/Patching/Assets/PatchClasses.cs
+++ b/HarmonyTests/Patching/Assets/PatchClasses.cs
@@ -1129,6 +1129,35 @@ public static void Postfix(ref object __result)
}
}
+ public class Class22
+ {
+ public static bool? bool1 = null;
+ public static bool? bool2 = null;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Method22()
+ {
+ try
+ {
+ }
+ catch
+ {
+ throw;
+ }
+ }
+
+ public static bool Prefix1(bool __runOriginal)
+ {
+ bool1 = __runOriginal;
+ return false;
+ }
+
+ public static void Prefix2(bool __runOriginal)
+ {
+ bool2 = __runOriginal;
+ }
+ }
+
public class InjectDelegateBaseClass
{
public string pre;
diff --git a/HarmonyTests/Patching/StaticPatches.cs b/HarmonyTests/Patching/StaticPatches.cs
index bb962993..e77b76c7 100644
--- a/HarmonyTests/Patching/StaticPatches.cs
+++ b/HarmonyTests/Patching/StaticPatches.cs
@@ -402,5 +402,34 @@ public void Test_Class18()
Assert.IsTrue(Class18Patch.prefixExecuted, "prefixExecuted");
Assert.AreEqual((float)1, color.r);
}
+
+ [Test]
+ public void Test_Class22()
+ {
+ var instance = new Harmony("test");
+ Assert.NotNull(instance, "instance");
+
+ var original = SymbolExtensions.GetMethodInfo(() => Class22.Method22());
+ Assert.NotNull(original, "original");
+ var prefix1 = SymbolExtensions.GetMethodInfo(() => Class22.Prefix1(false));
+ Assert.NotNull(original, "prefix1");
+ var prefix2 = SymbolExtensions.GetMethodInfo(() => Class22.Prefix2(false));
+ Assert.NotNull(original, "prefix2");
+
+ var patched1 = instance.Patch(original, new HarmonyMethod(prefix1));
+ Assert.NotNull(patched1, "patched1");
+
+ var patched2 = instance.Patch(original, new HarmonyMethod(prefix2));
+ Assert.NotNull(patched2, "patched2");
+
+ Class22.bool1 = null;
+ Class22.bool2 = null;
+ Class22.Method22();
+
+ Assert.NotNull(Class22.bool1, "Class22.bool1");
+ Assert.NotNull(Class22.bool2, "Class22.bool2");
+ Assert.IsTrue(Class22.bool1.Value, "Class22.bool1.Value");
+ Assert.IsFalse(Class22.bool2.Value, "Class22.bool2.Value");
+ }
}
}