ManlyMarco / RuntimeUnityEditor

In-game inspector and debugging tools for applications made with Unity3D game engine
GNU General Public License v3.0
810 stars 99 forks source link

System.IO.FileNotFoundException: Could not load file or assembly 'RuntimeUnityEditor.Core' #62

Closed AMacro closed 5 months ago

AMacro commented 11 months ago

When adding RUE 5.2.1 to a game with Unity Mod Manager, the mod does not load.

The issue can be resolved by copying 'RuntimeUnityEditor.Core.dll' to the '\_Data\Managed' folder, however, this is not the expected behaviour (IMHO). The assembly load fine from the '\Mods\RuntimeUnityEditor' folder that UMM creates without manual intervention.

Log

[Manager] Starting.
[Manager] Parsing mods.
[Manager] Reading file 'C:\Program Files (x86)\Steam\steamapps\common\Railroader\Mods\RuntimeUnityEditor\Info.json'.
[Manager] Sorting mods.
[Manager] Loading mods.
[RuntimeUnityEditor] Version '5.2.1.0'. Loading.
[RuntimeUnityEditor] [Error] Error loading file 'C:\Program Files (x86)\Steam\steamapps\common\Railroader\Mods\RuntimeUnityEditor\RuntimeUnityEditor.UMM.dll'.
[RuntimeUnityEditor] [Exception] ReflectionTypeLoadException - Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
System.Reflection.ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
  at (wrapper managed-to-native) System.Reflection.Assembly.GetTypes(System.Reflection.Assembly,bool)
  at System.Reflection.Assembly.GetTypes () [0x00000] in <7e05db41a20b45108859fa03b97088d4>:0 
  at UnityModManagerNet.UnityModManager+ModEntry.Load () [0x00593] in <41afed0fd6f44664b4330828e6d4dd7c>:0 
System.IO.FileNotFoundException: Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
File name: 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null'
System.IO.FileNotFoundException: Could not load file or assembly 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
File name: 'RuntimeUnityEditor.Core, Version=5.2.1.0, Culture=neutral, PublicKeyToken=null'
[RuntimeUnityEditor] Loading time 0.09 s.
[Manager] FINISH. SUCCESSFUL LOADED 0/1 MODS.
ManlyMarco commented 11 months ago

What's your environment? Make sure you don't have duplicate core dlls.

AMacro commented 11 months ago

Running Windows 11 Home. UMM: 0.27.8.0 I have only installed the mod to one game.

Is there something specific I should be checking?

ManlyMarco commented 11 months ago

I don't use UMM so can't help. Maybe try asking someone that got it to run in UMM.

t0stiman commented 10 months ago

@AMacro Did you ever find a solution for this error? (apart from the workaround you mentioned)

ManlyMarco commented 10 months ago

No, as I said I don't use UMM.

AMacro commented 10 months ago

@AMacro Did you ever find a solution for this error? (apart from the workaround you mentioned)

Ok, so I've had a little look at this, as well as doing some work on another mod that targets both BepInEx and UMM.

There does seem to be an issue with how UMM is loading the DLL, maybe not recursively mapping the dependencies?

The simple fix I found for the other mod was to

  1. Add the nuget package 'MSBuild.ILMerge.Task' to the UMM project
  2. Set the core dll reference to 'Copy Local' = true
  3. Clean build

This merges the core dll into the UMM loader DLL making a single clean file and then UMM seems to have no issues resolving dependencies.

I have yet to test this solution with RUE, but I think it should work. I might get a chance later today to test it; if it works, I'll submit a pull request.

ManlyMarco commented 10 months ago

Oh, you're a Marco too, I thought the ping was for me :)

This merges the core dll into the UMM loader DLL making a single clean file and then UMM seems to have no issues resolving dependencies.

Wouldn't this still have issues with other required dlls? I'd guess you would have to merge everything. This is already done in this project for merging mcs.dll into the core dll. Maybe it's related to that?

A better solution would be to figure out why UMM doesn't resolve it and maybe add an assembly resolve event handler to fix it.

AMacro commented 10 months ago

@ManlyMarco Hahaha - I'm actually an 'Andrew' with a surname beginning with 'Mac' - Electrical engineer who enjoys programming, I was the only person in the office who could write macros for MS Office so nickname 'AMac' became 'AMacro'.

I totally agree, UMM should be fixed - I'll file an issue there, but if the dev doesn't fix it themselves, it's unlikely I'll work out the fix any time soon.

In the meantime, I've looked at how the RUE project is set up for ILRepack and I've made a few tweaks:

  1. Copied ILRepack.targets from RUE.Core to RUE.UMM and changed an include from MCS to the RUE.Core dll
  2. Set the CopyLocal for UnityEngine.dll and RUE.Core to 'true'
  3. Added a reference to ILRepack.Lib.MSBuild.Task.targets (version 2.0.16.1 to match RUE.Core, though a newer version is available)
  4. Increased RUE.Core project version from 5.2.1 to 5.2.2

I know this is a bandaid and the real fix should be in UMM, but I hope you'll accept my pull request.

On a side note, it appears with the above changes, the UMM mod only needs the following files to work:

"\Mods\RuntimeUnityEditor\RuntimeUnityEditor.UMM.dll"
"\Mods\RuntimeUnityEditor\Info.json"

I suspect that without the above changes you only need 'RuntimeUnityEditor.Core.dll' added to that list - i.e. the 'Mono.*' and 'MonoMod.*' files don't appear to be used.

ManlyMarco commented 10 months ago

I suspect that without the above changes you only need 'RuntimeUnityEditor.Core.dll' added to that list - i.e. the 'Mono.' and 'MonoMod.' files don't appear to be used.

They are definitely used in some games or UMM setups. It can also depend on the configuration, e.g. forcing a different harmony backend. If the assembly resolver is borked then it will likely break again in those cases.

The current UMM releases do work in the games they were tested in so it might just be game dependent?

mricher-git commented 9 months ago

Hey @ManlyMarco, I was just going to look into this as it's an issue for Railroader as well. By merging Core it fixes some problems, but REPL still relies on the other libraries and the function gets disabled. In BIE, Mono.*, MonoMod.* are already loaded since it uses those itself so it doesn't cause a problem, but in UMM, I've had to copy all the DLLs to the Managed directory to get full functionality. This wasn't an issue when working with Derail Valley though.

Perhaps just merge all the dlls into one, not just core? Also, with the latest commit, Core is merged but the seperate DLL is still packaged into the zip. Another solution to the problem which I used for another project is to add RUE's folder to the AssemblyResolve path:

public static bool OnToggle(UnityModManager.ModEntry modEntry, bool value)
{
    if (value)
    {
        AppDomain.CurrentDomain.AssemblyResolve += LoadFromSameFolder;
        HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
    }
    else
    {
        HarmonyInstance.UnpatchAll(modEntry.Info.Id);
        AppDomain.CurrentDomain.AssemblyResolve -= LoadFromSameFolder;
    }

    Enabled = value;

    return true;
}
static Assembly LoadFromSameFolder(object sender, ResolveEventArgs args)
{

    string folderPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory + @"\Mods\RuntimeUnityEditor");
    string assemblyPath = Path.Combine(folderPath, new AssemblyName(args.Name).Name + ".dll");
    if (!File.Exists(assemblyPath)) return null;
    Assembly assembly = Assembly.LoadFrom(assemblyPath);
    return assembly;
}
ManlyMarco commented 9 months ago

RUEs folder should definitely be in the assembly resolve list, I assumed that UMM would do this already just like BIE does. In that case adding the assembly resolve event would remove the need for merging altogether, though it could cause unintended consequences since it already works in some games.

mricher-git commented 9 months ago

Somsone else just opened an issue for it. https://github.com/newman55/unity-mod-manager/issues/133

It seems when using Doorstop it works fine, when UMM uses Assembly injection, it doesn't. Let's see what comes of newman's inventigation.

mricher-git commented 9 months ago

@AMacro may I ask what game you were running and whether you used doorstop proxy or assembly method?

AMacro commented 9 months ago

@mricher-git Railroader, Doorstop

t0stiman commented 9 months ago

@mricher-git your url is broken
https://github.com/newman55/unity-mod-manager/issues/133

mricher-git commented 9 months ago

Not sure what the deal is, I have both Derai Valley and Railroader at UMM v27.10.0 with RUE 5.2.1.0 and DV loads RuntimeUnityEditor.Core.dll no issue, and RR does not. dnSpy shows the Core .dll being resolved normally, no fancy Assembly.Loadfile/Loadfrom or AppDomain.CurrentDomain.AssemblyResolve being used from what I can tell. I've looked all over my environment to figure out if I have the search path in some dotnet config locally or something but no such luck. Will update issue on UMM side and see if newman55 can make sense of it.

BTW @t0stiman, I can't use UMM on Railroaders unless I manually upgrade doorstop's winhttp.dll to 4.0.0. You don't have such issues?

t0stiman commented 9 months ago

For me, UMM just works on Railroader. I don't have to perform any workarounds. Both assembly and doorstop work.

AMacro commented 5 months ago

This now seems to be resolved with a UMM update