[C#] Multi-threading error thrown from FiveM

In my script I want to tell the user something that is in a Task that is then in a Thread. From what I can tell, it seems that the exception is not being thrown from my code but being thrown from FiveM. I used a Try Catch statement to figure out the exact exception and so that it wouldn’t crash my entire server and I got this:

                 System.ArgumentException: Value does not fall within the expected range.


                Server stack trace:
                  at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR (System.Int32 errorCode) [0x0000a] in <fb0d2884a2b44d8db375bbed7cc70740>:0
                  at (wrapper cominterop) CitizenFX.Core.IScriptHost:InvokeNative (CitizenFX.Core.fxScriptContext&)
                  at (wrapper cominterop-invoke) CitizenFX.Core.IScriptHost:InvokeNative (CitizenFX.Core.fxScriptContext&)
                  at CitizenFX.Core.MonoScriptRuntime+WrapScriptHost.InvokeNative (CitizenFX.Core.fxScriptContext& context) [0x00000] in /src/code/client/clrcore/MonoScriptRuntime.cs:242
                  at (wrapper remoting-invoke-with-check) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:InvokeNative (CitizenFX.Core.fxScriptContext&)
                  at (wrapper xdomain-dispatch) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:InvokeNative (object,byte[]&,byte[]&)

                Exception rethrown at [0]:
                  at (wrapper xdomain-invoke) CitizenFX.Core.MonoScriptRuntime+WrapScriptHost:InvokeNative (CitizenFX.Core.fxScriptContext&)
                  at CitizenFX.Core.ScriptContext.InvokeInternal (System.UInt64 nativeIdentifier, CitizenFX.Core.IScriptHost scriptHost) [0x0000c] in /src/code/client/clrcore/ScriptContext.cs:173
                  at CitizenFX.Core.ScriptContext.Invoke (System.UInt64 nativeIdentifier, CitizenFX.Core.IScriptHost scriptHost) [0x00000] in /src/code/client/clrcore/ScriptContext.cs:166
                  at CitizenFX.Core.Native.Function.InvokeInternal (CitizenFX.Core.Native.Hash nativeHash, System.Type returnType, CitizenFX.Core.Native.InputArgument[] args) [0x00026] in /src/code/client/clrcore/Native.cs:28
                  at CitizenFX.Core.Native.Function.Call[T] (CitizenFX.Core.Native.Hash hash, CitizenFX.Core.Native.InputArgument[] arguments) [0x00000] in /src/code/client/clrcore/Native.cs:11
                  at CitizenFX.Core.PlayerList+<GetEnumerator>d__0.MoveNext () [0x00017] in /src/code/client/clrcore/Server/ServerWrappers.cs:92
                  at System.Collections.Generic.List`1[T]..ctor (System.Collections.Generic.IEnumerable`1[T] collection) [0x00077] in <fb0d2884a2b44d8db375bbed7cc70740>:0
                  at System.Linq.Enumerable.ToList[TSource] (System.Collections.Generic.IEnumerable`1[T] source) [0x00018] in <fe779a58d2d54ffea553ee896d1fee6a>:0
                  at MyScript.External.Server+<RemoveOfficer>d__15.MoveNext () [0x00101] in <6d1c79d51ea640bc9a8386320a589c0d>:0

My Code:

               try
                {
                    Player p = new PlayerList().ToList().Find(x => x.Identifiers["ip"] == ofc.SourceIP); // Throws at this

                    if (p != null)
                    {
                        BaseScript.TriggerClientEvent(p, "chatMessage", "", new[] { 0,0,0}, "test"); // Never invokes this
                    }
                }
                catch (Exception e)
                {
                    Log.WriteLine(e.ToString()); // Writing the exception to the console so that I can see
                }

You can only invoke CitizenFX natives from the main resource thread, so you’ll need a dispatch queue to put your result back on the main thread.

1 Like

I knew it was going to be something like this. Could you give me an example of how I would go about invoking something on the main thread from a worker thread? (I don’t have much knowledge of this).

The short answer is that you need to have the execution of natives n stuff on the main thread of your program. I made a little workaround for you guys so that you can execute theses all in the same thread

        /*
         * Below is just for executing something on the main thread
        */

        private static volatile ConcurrentQueue<Action> callbacks;
        async Task OnTick()
        {
            // Executing all of the callback methods available
            while (callbacks.TryDequeue(out Action queue))
                queue();

            await Delay(0);
        }
        internal static void Invoke(Action method) => callbacks.Enqueue(method); // Adding method for execution in main thread

Make sure to put all of the in the class that inherits the BaseScript class. Also make sure to add the line

this.Tick += OnTick;

To your constructor.

please use a ConcurrentQueue instead, this might actually lead to race conditions corrupting the List :frowning:

1 Like