HarmonyX icon indicating copy to clipboard operation
HarmonyX copied to clipboard

Merging upstream

Open kohanis opened this issue 1 year ago • 32 comments

As far as I can see there are no incompatible changes. But now additional target - net5.0

kohanis avatar Dec 18 '23 09:12 kohanis

Okay, there is one thing. core 3.1 sdk does not support file-scoped namespaces even with preview. There are already file-scoped namespaces in master. Should I convert them to block-scoped namespaces or drop 3.1 sdk support?

kohanis avatar Dec 18 '23 18:12 kohanis

Fair, removed it for now. As for 79, I don't see any incompatibilities, but better check later. I was actually planning to do a full merge to 2.3-prerelease.3 later, but I was finding some regressions in my tests with 2.3, so haven't yet I'd prefer to move this to draft for now, as it's something to think about. There's a reason why original harmony doesn't distribute standard versions (or rather now they do, but only ref ones), might have to do the same here. Because of net5+ directives. It will probably need to be split into net5.0, netcoreapp3.1 and net45

kohanis avatar Dec 20 '23 13:12 kohanis

Now it should be okay. Used same method as in harmony. Main targets are now net35;net45;netcoreapp3.0;net5.0, and netstandard2.0 is now ref only

Edit: It might be worth adding mention of "ref only" netstandard2.0 to nuget with the next release

kohanis avatar Dec 20 '23 16:12 kohanis

I merged the previous PR, looks like it created some conflicts. I'll merge this one as well if you can resolve them.

Edit: The PR added net7.0 target but actions seem to be set up for net6.0 max. It should be fine if you pick your net5.0 change instead when merging, assuming it still builds fine.

ManlyMarco avatar Dec 20 '23 19:12 ManlyMarco

I'll wait a bit for discussion on 79

kohanis avatar Dec 22 '23 09:12 kohanis

@kohanis Everything's merged now so it should be fine to revisit this.

ManlyMarco avatar Jan 19 '24 14:01 ManlyMarco

Just noting that I currently have everything synchronized with master of harmony, but I'm waiting for 2.3, which I understand should be out soon https://github.com/pardeike/Harmony/commit/ff82ff4f85bb077c632fae6aa5e8c81b7b03aa7f

kohanis avatar Feb 22 '24 18:02 kohanis

Well, it's basically done, maybe just add github workflows later on

Binary incompatibilities(kind of): HarmonyLib.InlineSignature removed (moved to internal in harmony, not used at all in harmonyx) HarmonyLib.MethodType.Async / HarmonyLib.AccessTools.AsyncMoveNext hidden from net35 build

Comments: ValueTuple shims removed - they are now in MonoMod.Backports __args now unpacks itself back as in harmony netstandard2.0 build is now ref only

// Also, harmony now embeds pdb into the release dll(for thin version, but harmonyx doesn't have fat version anyway). Should it be here?

kohanis avatar Mar 03 '24 09:03 kohanis

On a glance it seems fine, but looks like this will need some testing in different heavily modded games before a merge.

ValueTuple shims removed - they are now in MonoMod.Backports

Is there a chance those shims were used by plugins, which will now break?

Also, harmony now embeds pdb into the release dll(for thin version, but harmonyx doesn't have fat version anyway). Should it be here?

Embedding debug symbols in release is fine, yes.

ManlyMarco avatar Mar 04 '24 11:03 ManlyMarco

Is there a chance those shims were used by plugins, which will now break?

Oh, those were internal, I missed it. So, no

Embedding debug symbols in release is fine, yes.

Well, it's not embedded in 2.3.1 now) Will merge up to 2.3.1.1 soon, only changes for project files, not sources

kohanis avatar Mar 04 '24 18:03 kohanis

Merged up to 2.3.1.1. Also fixed StackTraceFixes(hopefully) But it is now split into 2 packages, HarmonyX and HarmonyX.Ref, alike Lib.Harmony and Lib.Harmony.Ref. And since there is no HarmonyX.Ref yet, you cannot build netstandard2.0 not in a ReleaseRef configuration yet

kohanis avatar Mar 07 '24 10:03 kohanis

@Meivyn you can try this. Here is different approach to GetExecutingAssembly, and one another master fix. Might help. Based on the log, I doubt it, but maybe.

kohanis avatar Mar 07 '24 10:03 kohanis

That does indeed not fix the issue. I can't tell if your replacement works how it's intended to because I'm not sure to understand what that's even fixing. But it fixes the Unity crash as well.

If you can look at the native patcher while you're here, it's also broken for the same reason (#107).

Meivyn avatar Mar 07 '24 14:03 Meivyn

I believe last push should fix #107 And @Meivyn, if your reverse patch target is extern(and I think it is, there was a regression in #79), that should help too

Yes, it should be calli and not a generated shenanigans, but there are currently some issues with managed calli with DynamicMethodDefinition. EDIT: actually, calli is not supported by the current transpiler anyway, so NativeHookOriginalProxy will be needed anyway. But calli inside it will still be better. Currently I only use delegate because otherwise mono inline throw before the actual alt entry hook

kohanis avatar Mar 10 '24 15:03 kohanis

The target method is not an extern method, it's a random method I choose to test the reverse patch:

image

I also confirm that your latest push fixes the issue with the native methods patches for me.

Meivyn avatar Mar 11 '24 16:03 Meivyn

Using a reverse patch on my own method doesn't throw but also doesn't work.

image image image image

Meivyn avatar Mar 11 '24 17:03 Meivyn

It looks like inlining. Try calling through a delegate to check, instead of directly

kohanis avatar Mar 11 '24 21:03 kohanis

That indeed did the trick. Though why is that required now? It was working fine in the previous version of Harmony (and it breaks existing patches). That didn't solve the exception when patching though.

Meivyn avatar Mar 11 '24 21:03 Meivyn

Looks like @kohanis fixes to native detour patcher indeed fixes issue #107, thanks. Could you also use <MonoModRuntimeDetour>25.1.0</MonoModRuntimeDetour> instead of the prelease version, as it includes a vital unity+linux fix.

CptMoore avatar Mar 13 '24 23:03 CptMoore

That indeed did the trick. Though why is that required now? It was working fine in the previous version of Harmony (and it breaks existing patches).

Frankly I don't see any reason why mono wouldn't inline a purely throwing method without [MethodImpl(MethodImplOptions.NoInlining)]. Is the usage exactly the same? If method with reverse patch call is called at least once before patching itself, this behaviour is not surprising // But the fact that it is called before patching is, imho, misuse of it

kohanis avatar Mar 14 '24 05:03 kohanis

Watch out, bumping the MonoMod.RuntimeDetour version requires Harmony to target net452 instead of net45, otherwise it won't use the correct version of Mono.Cecil.

Is the usage exactly the same? If method with reverse patch call is called at least once before patching itself, this behaviour is not surprising

Yes, the usage is the same, as I said it was breaking patches that did work before and it breaks my test one as well, and as you can see that method isn't called before patching. Patching happens in Init which is always called before OnEnable as it's the constructor.

[Plugin(RuntimeOptions.DynamicInit)]
public class Plugin
{
    internal static IPALogger Log { get; private set; } = null!;

    [Init]
    public Plugin(IPALogger logger, PluginMetadata metadata)
    {
        Log = logger;
        Harmony.CreateAndPatchAll(metadata.Assembly, "com.meivyn.BeatSaber.BSPlugin5");
    }

    [OnEnable]
    public void OnEnable()
    {
        Patch.ReversePatch();
    }

    [OnDisable]
    public void OnDisable()
    {
    }

    public void TestMethod()
    {
        Log.Notice(nameof(TestMethod));
    }
}


[HarmonyPatch(typeof(Plugin), nameof(Plugin.TestMethod))]
internal class Patch
{
    [HarmonyReversePatch]
    [MethodImpl(MethodImplOptions.NoInlining)] // breaks without this
    public static void ReversePatch()
    {
        throw new NotImplementedException("Reverse patch has not been executed.");

        IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
        {
            return new CodeMatcher(instructions)
                .MatchStartForward(new CodeMatch(OpCodes.Ldstr))
                .SetOperandAndAdvance("Reverse patched")
                .InstructionEnumeration();
        }
    }
}

Meivyn avatar Mar 14 '24 14:03 Meivyn

Yes, the usage is the same, as I said it was breaking patches that did work before and it breaks my test one as well, and as you can see that method isn't called before patching. Patching happens in Init which is always called before OnEnable as it's the constructor.

Cannot confirm it. Used latest BSIPA 4.3.2 with your sample without MethodImplOptions.NoInlining on PlateUp, got NotImplementedException

kohanis avatar Mar 14 '24 18:03 kohanis

Yeah, I actually cannot reproduce the same behavior with my patch as well. It seems to happen only to this patch: https://github.com/Aeroluna/Heck/blob/master/Heck/HarmonyPatches/PlayViewInterrupter.cs#L76, at least from my testing. Using Harmony 2.12.0 broke this patch, and it was not throwing before that. Reverting to Harmony 2.10.2 fixes it.

Meivyn avatar Mar 14 '24 19:03 Meivyn

Okay, reverse patches are broken in general in 1.11.0+, affirmative. GC collects them. I'll see what I can come up with

kohanis avatar Mar 15 '24 14:03 kohanis

Far from perfect, but let's call it a hotfix for now // btw, it wasn't previously implemented correctly either, it's just that ILHook didn't have a finalizer previously

kohanis avatar Mar 15 '24 15:03 kohanis

That doesn't fix the inline issue with my test patch, however it seems to have fixed the broken patch I mentioned earlier. Guess I'm only missing a fix for the IL error that happens when reverse patching some methods before using this PR in BSIPA.

I highly doubt those are the only bugs we are gonna encounter, but I guess it is usable enough. Thanks for your fixes.

Meivyn avatar Mar 15 '24 17:03 Meivyn

Restructured. Last push in this PR, unless fixes related to it are needed. I'm planning some structural changes of project based on this PR, but as separate one

kohanis avatar Mar 15 '24 22:03 kohanis

Pardon, that fix was important. Also, friendly reminder that without HarmonyX.Ref package project will not be built as is, and CI is also not adapted for this

kohanis avatar Mar 17 '24 20:03 kohanis

As far as I can tell it should work the same way, but with two packages. Not sure about integration with jenkins though

kohanis avatar Mar 18 '24 04:03 kohanis

whats missing for this to be merged? CI? HarmonyX.Ref?

CptMoore avatar Apr 14 '24 09:04 CptMoore