Using .NET resources (resx files) crashes the FiveM resource

Information

I was trying to create a Client+Server resource with .NET Resources to support localizations and all, but it ended up crashing because FiveM was trying to load the stuff from the resx as a separate file.

Repro Steps

The short one

  • Create a FiveM resource with Client, Server and Shared dlls
  • Add a Resources.resx
  • Build the solution and create a __resource.lua
  • Put the resource on server-data\resources and start it

The long one

  • Clone the code of GGOMP at 852a93c65a61c1e89dfd3dd88bf65add8ec95418
  • Restore the Git Submodules
  • Restore the NuGet packages on the solution
  • Build the GGOMP.sln solution on Visual Studio 2017
  • Copy the bin\Debug folder and paste it on your server-data\resources folder as “ggo”
  • Add start ggo on your server.cfg

Expected Behaviour

The resource boots up without problems.

Actual Behaviour

Exception loading assembly GGO.Shared.net.resources: System.IO.FileNotFoundException: Unable to find the specified file.


Server stack trace:
  at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR (System.Int32 errorCode) [0x0000a] in <0123fd5b1a1040fe9d70a7e0d4b28acb>:0
  at (wrapper cominterop) CitizenFX.Core.IScriptHost:OpenHostFile (string)
  at (wrapper cominterop-invoke) CitizenFX.Core.IScriptHost:OpenHostFile (string)
  at CitizenFX.Core.MonoScriptRuntime+WrapScriptHost.OpenHostFile (System.String fileName) [0x00000] in C:\gl\builds\4ff63adb\0\cfx\fivem\code\client\clrcore\MonoScriptRuntime.cs:266
  at (wrapper remoting-invoke-with-check) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (string)
  at (wrapper xdomain-dispatch) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (object,byte[]&,byte[]&,string)

Exception rethrown at [0]:
  at (wrapper xdomain-invoke) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (string)
  at CitizenFX.Core.InternalManager.LoadAssembly (System.String name) [0x00000] in C:\gl\builds\4ff63adb\0\cfx\fivem\code\client\clrcore\InternalManager.cs:120
Exception loading assembly GGO.Shared.net.resources: System.IO.FileNotFoundException: Unable to find the specified file.


Server stack trace:
  at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR (System.Int32 errorCode) [0x0000a] in <0123fd5b1a1040fe9d70a7e0d4b28acb>:0
  at (wrapper cominterop) CitizenFX.Core.IScriptHost:OpenHostFile (string)
  at (wrapper cominterop-invoke) CitizenFX.Core.IScriptHost:OpenHostFile (string)
  at CitizenFX.Core.MonoScriptRuntime+WrapScriptHost.OpenHostFile (System.String fileName) [0x00000] in C:\gl\builds\4ff63adb\0\cfx\fivem\code\client\clrcore\MonoScriptRuntime.cs:266
  at (wrapper remoting-invoke-with-check) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (string)
  at (wrapper xdomain-dispatch) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (object,byte[]&,byte[]&,string)

Exception rethrown at [0]:
  at (wrapper xdomain-invoke) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:OpenHostFile (string)
  at CitizenFX.Core.InternalManager.LoadAssembly (System.String name) [0x00000] in C:\gl\builds\4ff63adb\0\cfx\fivem\code\client\clrcore\InternalManager.cs:120

Versions

  • Windows 10 Pro Version 1803 Build 17134.376
  • FiveM Client Build 846-02ffd61d969ef76e4ccdda513957b8f34a40d3f3
  • FiveM Server Build 838-50fae9743a7e34b5e7a9d0799a7d46019ad5838f

FiveM loads .NET assemblies using Assembly:Load(byte[]), are resources meant to work like this?

If you mean .NET resource files, no.

They are part of the DLL and not a separate file, but for some reason FiveM thinks that it is.

Loaded GGO.Server.net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null into ScriptDomain_1823114472
Symbol file LoadedFromMemory is not a mono symbol file
Loaded GGO.Shared.net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null into ScriptDomain_1823114472
Instantiated instance of script GGO.Server.ScriptServer.
Loaded GGO.Shared.net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null into ScriptDomain_1823114472
Started gametype GGO
Started resource ggo
We need 1 more players to start a game. Checking again in 1 more minute(s).
hitch warning: frame time of 557 milliseconds

Is it the client that’s erroring out like this?

Ignore the last post - it seems git clone -b doesn’t like revision numbers.

You were asking about the client, so here is some info on the client/side:

Once you finish loading stuff from the server like the stuff in the stream folder, it stays on the loading screen indefinitely.
This happens because the server script (GGO.Server.net.dll) is on a “zombie” state after the exception and is not triggering some events to the client.

… in fact, even the specified revision runs fine here. :confused:

852a93c65a61c1e89dfd3dd88bf65add8ec95418 works ok for you?

↳ git status
HEAD detached at 852a93c

Yep.

Hmm… strange. Is there any other information that I can send to you guys?

Ah - found out what happens. If the resource is started from the server thread, it doesn’t except; if it’s started from the initialization/main thread as happens when using +exec/+start, it shows this exception (but still loads and continues the resource fine, as the message from said resource prints fine; this is probably just Mono trying to load an assembly in case it’s external, but being fine without it being external at all).

It confuses me, however, to see this not be printed at all if running post-initialization.

Either way, this shouldn’t be impacting the resource’s functioning, since ticks still seem to get executed, and typically these are non-fatal.

Yeah - in fact, even with these exceptions, the client loads and spawns fine.

There should be a way to make sure that is really an assembly.

Correct, but is still a problem to see a traceback every first run :wink: