From c7cfdaaa9ed7e067d6bfdaa00d818ef9e61e6c8f Mon Sep 17 00:00:00 2001 From: hazre <37149950+hazre@users.noreply.github.com> Date: Wed, 17 Dec 2025 14:09:27 +0100 Subject: [PATCH 1/2] refactor(BepisLoader): remove Hardware.Info dependency --- .gitmodules | 4 ---- Hardware.Info | 1 - Runtimes/NET/BepisLoader/BepisLoader.cs | 9 +++++++++ Runtimes/NET/BepisLoader/BepisLoader.csproj | 10 ---------- 4 files changed, 9 insertions(+), 15 deletions(-) delete mode 160000 Hardware.Info diff --git a/.gitmodules b/.gitmodules index 6079211f..362a8e01 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,3 @@ path = HarmonyX url = https://github.com/ResoniteModding/HarmonyX.git branch = patchy -[submodule "Hardware.Info"] - path = Hardware.Info - url = https://github.com/ResoniteModding/Hardware.Info.git - branch = patchy diff --git a/Hardware.Info b/Hardware.Info deleted file mode 160000 index b0e99d8c..00000000 --- a/Hardware.Info +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b0e99d8c1eb2a5eb1e55efe144d38f47d52ec1c4 diff --git a/Runtimes/NET/BepisLoader/BepisLoader.cs b/Runtimes/NET/BepisLoader/BepisLoader.cs index a243b9d7..d0342e24 100644 --- a/Runtimes/NET/BepisLoader/BepisLoader.cs +++ b/Runtimes/NET/BepisLoader/BepisLoader.cs @@ -7,6 +7,7 @@ namespace BepisLoader; public class BepisLoader { internal static string resoDir = string.Empty; + private static readonly string tfmFolder = "net10.0"; internal static AssemblyLoadContext alc = null!; static void Main(string[] args) { @@ -18,6 +19,14 @@ static void Main(string[] args) alc = new BepisLoadContext(); + // Load System.Management explicitly for Windows to avoid PlatformNotSupportedException + var systemManagementPath = RuntimeInformation.RuntimeIdentifier.StartsWith("win") + ? new FileInfo(Path.Combine(resoDir, "runtimes", "win", "lib", tfmFolder, "System.Management.dll")) + : new FileInfo(Path.Combine(resoDir, "System.Management.dll")); + + if (systemManagementPath.Exists) + alc.LoadFromAssemblyPath(systemManagementPath.FullName); + // TODO: removing this breaks stuff, idk why AppDomain.CurrentDomain.AssemblyResolve += ResolveGameDll; diff --git a/Runtimes/NET/BepisLoader/BepisLoader.csproj b/Runtimes/NET/BepisLoader/BepisLoader.csproj index a2617df8..e5a7da5a 100644 --- a/Runtimes/NET/BepisLoader/BepisLoader.csproj +++ b/Runtimes/NET/BepisLoader/BepisLoader.csproj @@ -12,16 +12,6 @@ embedded - - - - - - - - - - From 28b61378c0e6191efca019b1555563db497db49e Mon Sep 17 00:00:00 2001 From: hazre <37149950+hazre@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:00:00 +0100 Subject: [PATCH 2/2] refactor(BepisLoader): simplify assembly resolution using AssemblyDependencyResolver Replace custom ResolveInternal method with System.Runtime.Loader's AssemblyDependencyResolver for cleaner dependency resolution. --- Runtimes/NET/BepisLoader/BepisLoader.cs | 100 +++++++----------------- 1 file changed, 30 insertions(+), 70 deletions(-) diff --git a/Runtimes/NET/BepisLoader/BepisLoader.cs b/Runtimes/NET/BepisLoader/BepisLoader.cs index d0342e24..fa1e7698 100644 --- a/Runtimes/NET/BepisLoader/BepisLoader.cs +++ b/Runtimes/NET/BepisLoader/BepisLoader.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.InteropServices; using System.Runtime.Loader; namespace BepisLoader; @@ -7,7 +6,6 @@ namespace BepisLoader; public class BepisLoader { internal static string resoDir = string.Empty; - private static readonly string tfmFolder = "net10.0"; internal static AssemblyLoadContext alc = null!; static void Main(string[] args) { @@ -19,15 +17,7 @@ static void Main(string[] args) alc = new BepisLoadContext(); - // Load System.Management explicitly for Windows to avoid PlatformNotSupportedException - var systemManagementPath = RuntimeInformation.RuntimeIdentifier.StartsWith("win") - ? new FileInfo(Path.Combine(resoDir, "runtimes", "win", "lib", tfmFolder, "System.Management.dll")) - : new FileInfo(Path.Combine(resoDir, "System.Management.dll")); - - if (systemManagementPath.Exists) - alc.LoadFromAssemblyPath(systemManagementPath.FullName); - - // TODO: removing this breaks stuff, idk why + // The game runs in the Default AssemblyLoadContext, not our custom BepisLoadContext. When code in the Default ALC requests a dependency, BepisLoadContext.Load() is never called, only this global AssemblyResolve event fires as a fallback. AppDomain.CurrentDomain.AssemblyResolve += ResolveGameDll; var bepinPath = Path.Combine(resoDir, "BepInEx"); @@ -40,8 +30,7 @@ static void Main(string[] args) var asm = alc.LoadFromAssemblyPath(Path.Combine(bepinPath, "core", "BepInEx.NET.CoreCLR.dll")); - var resoDllPath = Path.Combine(resoDir, "Renderite.Host.dll"); - if (!File.Exists(resoDllPath)) resoDllPath = Path.Combine(resoDir, "Resonite.dll"); + var resoDllPath = GetResoDllPath(); var t = asm.GetType("StartupHook"); var m = t.GetMethod("Initialize", BindingFlags.Public | BindingFlags.Static, [typeof(string), typeof(string), typeof(AssemblyLoadContext)]); @@ -80,8 +69,6 @@ static void Main(string[] args) return found; } - if (assemblyName.Name == "System.Management") return null; - var targetPath = Path.Combine(resoDir, assemblyName.Name + ".dll"); if (File.Exists(targetPath)) { @@ -92,74 +79,47 @@ static void Main(string[] args) return null; } + private static string GetResoDllPath() + { + var path = Path.Combine(resoDir, "Renderite.Host.dll"); + return File.Exists(path) ? path : Path.Combine(resoDir, "Resonite.dll"); + } + private class BepisLoadContext : AssemblyLoadContext { + private readonly AssemblyDependencyResolver? _resolver; + + public BepisLoadContext() : base(isCollectible: false) + { + var resoDllPath = GetResoDllPath(); + + if (File.Exists(resoDllPath)) + _resolver = new AssemblyDependencyResolver(resoDllPath); + } + protected override Assembly? Load(AssemblyName assemblyName) { - return ResolveInternal(assemblyName); + // Check already-loaded assemblies first + var found = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(x => x.GetName().Name == assemblyName.Name); + if (found != null) return found; + + // Use deps.json resolution + string? assemblyPath = _resolver?.ResolveAssemblyToPath(assemblyName); + return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null; } protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) { - var rid = GetRuntimeIdentifier(); - - var nativeLibs = Path.Join(resoDir, "runtimes", rid, "native"); - IEnumerable potentialPaths = [unmanagedDllName, Path.Combine(nativeLibs, GetUnmanagedLibraryName(unmanagedDllName))]; - if (unmanagedDllName.EndsWith("steam_api64.so")) potentialPaths = ((IEnumerable)["libsteam_api.so"]).Concat(potentialPaths); - Log("NativeLib " + unmanagedDllName); - foreach (var path in potentialPaths) + string? libraryPath = _resolver?.ResolveUnmanagedDllToPath(unmanagedDllName); + if (libraryPath != null) { - Log(" Testing: " + path); - if (File.Exists(path)) - { - Log(" Exists! " + path); - var dll = LoadUnmanagedDllFromPath(path); - if (dll != IntPtr.Zero) - { - Log(" Loaded! " + path); - return dll; - } - } + Log(" Resolved: " + libraryPath); + return LoadUnmanagedDllFromPath(libraryPath); } - return IntPtr.Zero; } - - - private static string GetRuntimeIdentifier() - { - string os; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - os = "win"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - os = "osx"; - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - os = "linux"; - else - throw new PlatformNotSupportedException(); - - string arch = RuntimeInformation.OSArchitecture switch - { - Architecture.X86 => "-x86", - Architecture.X64 => "-x64", - Architecture.Arm64 => "-arm64", - _ => "" - }; - - return $"{os}{arch}"; - } - private static string GetUnmanagedLibraryName(string name) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return $"{name}.dll"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - return $"lib{name}.so"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - return $"lib{name}.dylib"; - - throw new PlatformNotSupportedException(); - } } #if DEBUG