Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in exported Godot Engine build when attempting to patch method #562

Closed
Awarets opened this issue Dec 30, 2023 · 5 comments
Closed
Assignees

Comments

@Awarets
Copy link

Awarets commented Dec 30, 2023

Describe the bug
An exception (detailed below) is thrown when attempting to perform a patch in an exported Godot Build.

To Reproduce
Use the following code with Harmony 2.3-prerelease.4 in Godot 4.2.1:

using System;
using System.Collections;
using System.Collections.Generic;
using Godot;
using HarmonyLib;

public partial class Main : Node
{
    public sealed override void _Ready()
    {
        HarmonyLib.Harmony.DEBUG = true;

        var harmony = new HarmonyLib.Harmony(id: "com.rumbler.patch");

        var original = typeof(Main).GetMethod(name: nameof(MethodToTryPatching), bindingAttr: System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        var prefix = new HarmonyLib.HarmonyMethod(method: typeof(Main).GetMethod(name: nameof(PrefixPatchMethod), bindingAttr: System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic));

        harmony.Patch(
            original: original,
            prefix: prefix);
    }

    private static void MethodToTryPatching()
    {

    }

    private static void PrefixPatchMethod()
    {

    }
}

Harmony debug log:

### Harmony id=com.rumbler.patch, version=2.3.0.0, location=C:\HarmonyExportIssueBuild\data_HarmonyExportIssue_windows_x86_64\0Harmony.dll, env/clr=6.0.21, platform=Win32NT
### Started from virtual System.Void Main::_Ready(), location C:\HarmonyExportIssueBuild\data_HarmonyExportIssue_windows_x86_64\HarmonyExportIssue.dll
### At 2023-12-30 12.35.44
### Patch: static System.Void Main::MethodToTryPatching()
### Replacement: static System.Void Main::Main.MethodToTryPatching_Patch1()

Exception StackTrace:

ERROR: System.ArgumentException: GenericArguments[0], 'MonoMod.Utils.Cil.CecilILGenerator', on 'MonoMod.Utils.Cil.ILGeneratorProxy[TTarget]' violates the constraint of type 'TTarget'.
 ---> System.TypeLoadException: GenericArguments[0], 'MonoMod.Utils.Cil.CecilILGenerator', on 'MonoMod.Utils.Cil.ILGeneratorProxy[TTarget]' violates the constraint of type parameter 'TTarget'.
   at System.RuntimeTypeHandle.Instantiate(RuntimeType inst)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   --- End of inner exception stack trace ---
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.RuntimeType.MakeGenericType(Type[] instantiation)
   at MonoMod.Utils.Cil.ILGeneratorShim.GetProxy()
   at MonoMod.Utils.DynamicMethodDefinition.GetILGenerator()
   at HarmonyLib.MethodPatcher..ctor(MethodBase original, MethodBase source, List`1 prefixes, List`1 postfixes, List`1 transpilers, List`1 finalizers, Boolean debug)
   at HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
   at HarmonyLib.PatchProcessor.Patch()
   at HarmonyLib.Harmony.Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer)
   at Main._Ready() in C:\Godot Projects\HarmonyExportIssue\Main.cs:line 18
   at Godot.Node.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret)
   at Main.InvokeGodotClassMethod(godot_string_name& method, NativeVariantPtrArgs args, godot_variant& ret) in C:\Godot Projects\HarmonyExportIssue\Godot.SourceGenerators\Godot.SourceGenerators.ScriptMethodsGenerator\Main_ScriptMethods.generated.cs:line 58
   at Godot.Bridge.CSharpInstanceBridge.Call(IntPtr godotObjectGCHandle, godot_string_name* method, godot_variant** args, Int32 argCount, godot_variant_call_error* refCallError, godot_variant* ret)
   at: void Godot.NativeInterop.ExceptionUtils.LogException(System.Exception) (:0)

Runtime environment (please complete the following information):

  • OS: Windows 10, 64bit
  • .NET version: .NET 6.0
  • Harmony 2.3-prerelease.4
  • Godot 4.2.1

Additional context
The exception only appears to be thrown in an exported build. No exception is thrown within the editor, and everything behaves as expected.

@pardeike
Copy link
Owner

Could it be that the empty methods are optimised away or inlined when you build a release build (I assume that’s what Godot exported build means). Can you try to add some code and maybe some try/catch code that is known to prevent inlining?

@pardeike
Copy link
Owner

A more likely reason is a mismatch of dependency version. Harmony needs and uses some dependencies and I guess one of them does not match the one that is actually loaded and present at runtime.

@Awarets
Copy link
Author

Awarets commented Jan 2, 2024

The problem still occurs even with non-empty methods. (Harmony log and exception stacktrace are identical)

I think I may have identified the mismatched dependency though. Harmony in .NET 6 is dependent on System.Text.Json 5.0.2, but that version of System.Text.Json doesn't appear to be compatible with .NET 6. The version of System.Text.Json in the release build is 6.0.2123.36311 instead.

@pardeike
Copy link
Owner

fixed in next prerelease

@Awarets
Copy link
Author

Awarets commented Jan 12, 2024

Issue is unfortunately still occurring even in the newest prerelease.

The only other lead I have is that Mono.Cecil doesn't seem to support .NET 6.0 (or any base .NET version), however that leaves me confused as to how patching is able to even function within the godot editor itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants