Fix Release launcher dependency loading from lib#2749
Conversation
|
I also created a temporary draft integration/testing PR that combines the current related fixes for anyone who wants to test them together before they land individually:
This is not intended to replace the focused PRs. It is only a convenience branch for combined Release/modded testing. |
|
Is it possible to add test steps to this PR? Or at least an error / crash log? We've never seen the server crash on latest master so taking the word of AI on these changes is a hard sell as it is. |
I get it, I write documentation all day for a living so I use AI to help me with that part as it adds years back to my life I feel. I hope the following helps though, as I have used AI to keep track of all my steps and logs to make this documentation process easier, so it also helps me answer this easier. Please do not take offense to that or see it as me being lazy, just faster. This was not based on AI speculation. I reproduced this locally in a Release build from the packaged launcher output layout. Before this change, the Release launcher started, but existing saves were skipped because the launcher hit runtime missing-method errors while reading server entries. Example from my local log: Because the save entries failed to initialize, existing servers did not show correctly in the launcher. The same Release dependency-loading issue also caused server creation/startup paths to fail because the launcher/runtime could see mismatched Nitrox assembly API surfaces. Test steps I used:
|
|
Unable to reproduce this on Windows and Mac :/ |
|
That just doesn't make any sense. I have tried deploying master on 3 different Windows 11 Pro builds, and every single one of them the master Release build does not show server saves, and will crash if you try to create one. Period. I get that a lot of y'all are building in debug, but release build should work as well. Also, just simply the fact that the libs aren't where they should be is obviously going to cause a ton of problems. As it stands right now, this is the single most important fix I have made, and I am unable to create a working Release build on a fresh copy of master without it. |
|
The problem for me is that we don't know what's causing the "MissingMethodException". Maybe we can list the assembly versions + locations it loads compared to without the change? That would be helpful to get an understanding. And if the versions are different, why? The screenshot shows the files in release mode. How is it possible that the files are suddenly changing position when loading them differently at runtime (done by this PR change)? Or do you mean a different PR? |
Thanks, that makes sense. I’ll try to explain the distinction more clearly. The Release/Debug file layout is not being changed at runtime by this PR. That layout is determined by the project/MSBuild/publish configuration before the launcher ever runs: the .csproj settings, shared props/targets, copy-local behavior, publish/build configuration, and whatever packaging logic places dependencies in the root versus /lib, /Resources, etc. So when I say “Release layout,” I mean the physical output produced by the Release build/package. In the Release output I was testing, most dependency assemblies were already placed under /lib, while the launcher executable and a smaller set of core files were in the root. This PR does not move those files around at runtime. It only changes how the launcher resolves assemblies when the runtime asks for one that is not already loadable from the default probing path. On the MissingMethodException: the issue was not visible in the same way as the UWE prefab probability issue. The UWE issue produced a direct visible error in the normal flow once the bad call path was hit. For this launcher/lib-loading issue, the visible symptom was higher level: fresh Release builds from current master could start, but server saves were not discovered correctly and creating a server could crash/fail. To see the underlying assembly issue clearly, we had to add/enable more assembly-resolution logging around what the launcher was actually loading and where from. That is what showed the important part: the runtime was not consistently loading the intended Nitrox assemblies from the Release layout. A reproducible test should be: Start from a fresh clone/current master. The important comparison is not just “does a DLL exist somewhere,” but “which physical DLL path did the process actually load for this assembly identity?” That is why listing assembly versions plus locations would be useful. I agree that it would make the diagnosis clearer. On The issue is not simply “open this DLL from this exact path.” The launcher needs failed assembly resolution to be satisfied from the Release layout’s That is why the PR uses the assembly resolution event and returns the resolved assembly from Edit: This totally changes files and my freaking Notetaker was on drugs when it wrote this. I have update the PR with the relevant info but am leaving this here so Measurity doesn't look like they are crazy lol. |
|
Can you stop using AI and use your own words please? I have a lot of patience for humans, but almost zero for AI. So using AI isn't in your favor replying to human messages. |
I use AI draft my long technical responses so that they do not leave anything out since I use it to take notes. Makes life easier for something I do all day in my real work and this is something I do for fun. Have messaged you about this in discord. |
|
Whoops, wrong button! Reopened! Yikes! |
|
Updated the PR body to clarify the concrete assembly/version/method failures and to remove the confusing wording around "Release layout." The important specifics now included are:
Also clarified that the PR is not intended to arbitrarily move files around at runtime; it is intended to make the Release output/package resolve the correct assemblies consistently. |

Summary
Fixes Release launcher dependency loading so the launcher/server side resolves the correct assemblies from the Release output layout.
This PR is specifically about the Release build/package output, not Debug. In the broken Release output, the launcher/server path could load stale or incompatible assemblies from the wrong deployed location. That caused runtime
MissingMethodExceptions even though the DLL files existed.Problem
The failure was not a simple missing-file issue. The runtime was finding assemblies, but some of them were the wrong version / wrong target asset for the code that was calling them.
The concrete mismatches observed were:
Grpc.Core.Api.dllThe stale/bad loaded version was:
Grpc.Core.Api.dllversion2.57.0The dependent library involved was:
MagicOnion 7.0.6The concrete missing method was:
Grpc.Core.IAsyncStreamWriter<T>.WriteAsync(T, CancellationToken)This means the runtime had loaded a gRPC API assembly, but not one with the API surface expected by the newer MagicOnion dependency.
Nitrox.Model.dllThe launcher/server path also resolved a stale or wrong
Nitrox.Model.dll.The expected methods included:
Nitrox.Model.Serialization.NitroxConfig.Load(string, ILogger)Nitrox.Model.Serialization.NitroxConfig.Load<T>(string, ILogger)The failure mode was a
MissingMethodExceptionbecause the assembly that got loaded did not contain the overloads expected by the current launcher/server code.Release layout detail
The important layout issue is that the root
libside needs the current net10/server-facing assets, whilelib/net472needs to keep the legacy/net472-facing assets.The layout must not collapse those into one effective resolution pool where the launcher/server can accidentally load stale net472-era assets or incompatible dependency versions.
The observed distinction included:
libasset:Grpc.Core.Api.dllfrom the newernetstandard2.1dependency asset path;Nitrox.Model.dll;lib/net472/Nitrox.Model.dllfor the net472-facing side.The practical problem was that the Release deployment/layout allowed the launcher/server runtime path to resolve incompatible assemblies, producing
MissingMethodExceptions instead of clear file-not-found errors.What this PR changes
This PR fixes the Release dependency layout/resolution behavior so the launcher/server side loads the intended assemblies from the Release output.
It is not intended to dynamically reshuffle files at runtime. The goal is for the Release package/output to place and resolve the correct assemblies consistently.
Symptoms fixed locally
This fixed the Release-only behavior where:
MissingMethodExceptions.Why this matters
Debug builds did not expose the issue in the same way because the Debug output layout and probing behavior did not match the broken Release package behavior.
The Release build/package is what users actually run, so fixing the Release output layout is necessary even if Debug appears fine.
Testing
Tested on fresh Release deployments.
Before this fix:
MissingMethodExceptions caused by incompatible loaded assemblies.After this fix:
Clarification from follow-up discussion
The earlier wording around "Release layout" was confusing. By "Release layout," I mean the physical output produced by the Release build/package and the way that output causes assemblies to be resolved at runtime.
The important point is:
Grpc.Core.Api.dll/ MagicOnion andNitrox.Model.dlloverload mismatches.