Game crashed when a zipped mod trying to load native library
NoMathExpectation opened this issue · comments
My mods and Everest install are up to date
Yes
I have recreated the bug with only Everest OR a minimum number of mods enabled
Yes
Describe the bug
I am developing a mod and I need to use some native library.
I implemented this by extracting libraries to mod cache and referencing using DllImport
. code
The library loading works fine when running the mod in an unzipped form.
But when I zip the mod and run, the native library loading will fail and the game will crash:
Ver 1.4.0.0-fna [Everest: 4739-azure-62e69]
04/26/2024 19:22:13
System.InvalidOperationException: Sequence contains no matching element
at System.Linq.ThrowHelper.ThrowNoMatchException()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedFromThisMod(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 516
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedLocal(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 372
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedDll(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 309
at System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll(String unmanagedDllName, IntPtr gchManagedAssemblyLoadContext)
at NoMathExpectation.Celeste.Celestibility.Speech.ZDSRSpeechProvider.InitTTS(Int32 type, String channelName, Boolean bKeyDownInterrupt)
at NoMathExpectation.Celeste.Celestibility.Speech.ZDSRSpeechProvider..ctor()
at NoMathExpectation.Celeste.Celestibility.Speech.SpeechEngine.Init()
at NoMathExpectation.Celeste.Celestibility.CelestibilityModule.Load()
at Celeste.Mod.Everest.Register(EverestModule module)
at Celeste.Mod.Everest.Loader.LoadModAssembly(EverestModuleMetadata meta, Assembly asm)
at Celeste.Mod.Everest.Loader.LoadMod(EverestModuleMetadata meta)
at Celeste.Mod.Everest.Loader.LoadModDelayed(EverestModuleMetadata meta, Action callback)
at Celeste.Mod.Everest.Loader.LoadZip(String archive)
at Celeste.Mod.Everest.Loader.LoadAuto()
at Celeste.Mod.Everest.Boot()
at Celeste.Celeste..ctor()
at Celeste.Celeste.orig_Main(String[] args)
Steps to reproduce
- Go to the mod repository, compile the source code and pack to a zip.
- Put the zipped mod to the mod folder and run the game.
Expected behavior
The mod will load correctly just like in unzipped form.
Operating System
Windows 11
Everest Version
4739
Mods required to reproduce
No response
Additional context
private const string dll = "Mods/Cache/Celestibility/nativebin/ZDSRAPI_x64";
99% sure thats your issue. The DLL name should just be the the name, not the full path.
You can look at ImGuiHelper or TASRecorder on how to properly use native libraries.
Theses are the paths, file names you'll need (with the root being the directory of your mod DLL):
Everest/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs
Lines 34 to 39 in c735065
Everest/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs
Lines 510 to 515 in c735065
I have changed and committed the code according to your suggestion, but the game still crashes and throws the same exception.
Code: https://github.com/NoMathExpectation/Celestibility/blob/75969d0e4c7c49f4e3c6e82ce2373fd0c63b4341/Source/Speech/ZDSRSpeechProvider.cs#L45
Ver 1.4.0.0-fna [Everest: 4739-azure-62e69]
04/26/2024 21:53:36
System.InvalidOperationException: Sequence contains no matching element
at System.Linq.ThrowHelper.ThrowNoMatchException()
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedFromThisMod(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 516
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedLocal(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 372
at Celeste.Mod.EverestModuleAssemblyContext.LoadUnmanagedDll(String name) in /home/vsts/work/1/s/Celeste.Mod.mm/Mod/Module/EverestModuleAssemblyContext.cs:line 309
at System.Runtime.Loader.AssemblyLoadContext.ResolveUnmanagedDll(String unmanagedDllName, IntPtr gchManagedAssemblyLoadContext)
at NoMathExpectation.Celeste.Celestibility.Speech.ZDSRSpeechProvider.InitTTS(Int32 type, String channelName, Boolean bKeyDownInterrupt)
at NoMathExpectation.Celeste.Celestibility.Speech.ZDSRSpeechProvider..ctor()
at NoMathExpectation.Celeste.Celestibility.Speech.SpeechEngine.Init()
at NoMathExpectation.Celeste.Celestibility.CelestibilityModule.Load()
at Celeste.Mod.Everest.Register(EverestModule module)
at Celeste.Mod.Everest.Loader.LoadModAssembly(EverestModuleMetadata meta, Assembly asm)
at Celeste.Mod.Everest.Loader.LoadMod(EverestModuleMetadata meta)
at Celeste.Mod.Everest.Loader.LoadModDelayed(EverestModuleMetadata meta, Action callback)
at Celeste.Mod.Everest.Loader.LoadZip(String archive)
at Celeste.Mod.Everest.Loader.LoadAuto()
at Celeste.Mod.Everest.Boot()
at Celeste.Celeste..ctor()
at Celeste.Celeste.orig_Main(String[] args)
This seems to be the cause of the crash. The mod's Hash
es are null
and as such the LINQ query crashes.
The stacktrace tells most of the story. Here's a section of Everest.Loader.LoadMod()
:
Everest/Celeste.Mod.mm/Mod/Everest/Everest.Loader.cs
Lines 491 to 507 in c735065
Hash
es are calculated in EverestModuleMetadata.RegisterMod()
:
Everest/Celeste.Mod.mm/Mod/Module/EverestModuleMetadata.cs
Lines 127 to 137 in c735065
Everest.Loader.LoadModAssembly()
is called, which invokesEverest.Register(EverestModule)
, which then callsEverestModule.Load()
.- Skipping ahead,
ZDSRSpeechProvider.InitTTS(int, string, bool)
is P/Invoked, which triggers the unmanaged DLL resolution. - Skipping further ahead,
EverestModuleAssemblyContext.LoadUnmanagedFromThisMod(string)
is called, which tries to retrieve the mod'sHash
. - Because
EverestModuleMetadata.RegisterMod()
has not been called yet, the mod'sHash
isnull
and the game crashes.