Log in to reply
 

[SHVDN3] NullReferenceException when calling Notification.Show from websocket eventhandler



  • Hey, i want to run a websocket server and recieve commands/messages made by some other client. The websockt server runs fine and i can connect to it but it seems like i can not execute anything GTA related inside the eventhandler and i dont know why or how to fix it. Help is apprechiated!

    Error:

    [01:32:26] [ERROR] Caught fatal unhandled exception:
    System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
       bei SHVDN.ScriptDomain.ExecuteTask(IScriptTask task)
       bei SHVDN.NativeFunc.Invoke(UInt64 hash, UInt64* argPtr, Int32 argCount)
       bei GTA.Native.Function.Call(Hash hash, InputArgument argument0)
       bei GTA.UI.Notification.Show(String message, Boolean blinking)
       bei Cmod.WebsocketServer.OnWebsocketEvent(Object sender, WebSocketEventArg args)
       bei SimpleWebSocketServerLibrary.SimpleWebSocketHandler.WebSocketHandler.OnWebsocketEvent(Object sender, WebSocketEventArg arg)
       bei SimpleWebSocketServerLibrary.WSocketServer.WebSocketServer.<StartServerAsync>d__10.MoveNext()
    --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
       bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       bei System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       bei SimpleWebSocketServerLibrary.SimpleWebSocketHandler.WebSocketHandler.<StartConnection>d__6.MoveNext()
    --- Ende der Stapelüberwachung vom vorhergehenden Ort, an dem die Ausnahme ausgelöst wurde ---
       bei System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       bei System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
       bei System.Threading.ThreadPoolWorkQueue.Dispatch()
    
    

    Code:

    
    using System;
    using GTA;
    using GTA.Native;
    using System.Windows.Forms;
    using SimpleWebSocketServerLibrary;
    using System.Text;
    
    namespace Cmod {
    
    
    // Other code.
    
    
        public class WebsocketServer : Script
        {
            public SimpleWebSocketServer websocketServer;
    
            public WebsocketServer()
            {
                // this.KeyUp += onKeyUp;
    
                SimpleWebSocketServerSettings settings = new SimpleWebSocketServerSettings();
                settings.port = 9091;
    
                websocketServer = new SimpleWebSocketServer(settings);
                websocketServer.WebsocketServerEvent += OnWebsocketEvent;
                websocketServer.StartServer();
                GTA.UI.Notification.Show("WS STARTED");
    
            }
    
            public static void OnWebsocketEvent(object sender, WebSocketEventArg args)
            {
                try
                {
                    if (args.data != null && args.isText)
                    {
                        string received = Encoding.UTF8.GetString(args.data);
                        // _WebsocketServer.SendTextMessage("Client: " + args.clientId + " on url: " + args.clientBaseUrl + ", says: " + received);
                        GTA.UI.Notification.Show("MSG: " + received);
                    }
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
    }
    


  • @Slluxx Because the code executed on the socket event is not running on the main thread, and you can only call GTA functions from the main thread



  • @JustDancePC Ah i see, thanks! Is there a good/efficient way around that (eg can i
    somehow execute code back on the main thread from within the socket thread)? Or is there nothing i can do about that?



  • @Slluxx Probably not the best solution, but what I do in these cases is use a static variable as a flag inside a function that runs on tick, that way I can check every frame if my GTA-related code should run:

    private static bool _flag;
    
    private void MyEvent() {
      //Event triggered
      _flag = true;
    }
    
    private void OnTick() {
      if (_flag) {
        //Call GTA functions
        _flag = false;
      }
    }
    


  • @JustDancePC Yeah i guess that would work but as you said, its kind of jank. With websockets i would like to get 2 variables (socket & whatever has been transmitted). storing those inside classes to get them from a different thread by looking at it every tick is probably not smart. I have found synchronization context but didnt manage to make that work either.



  • I finally did it myself with the help of this SO thread.

    Here is an example snippe, but PLEASE read the SO thread. This example always assumes to be in a different thread, which might or might not (always) be the case for you.

        public class MyClass : Script
        {
    
            private Dispatcher _uiDispatcher = Dispatcher.CurrentDispatcher;
    
            public MyClass ()
            {
                var thing = new SomeThing();
                thing.runInDifferentThread(socket =>
                {
                    socket.OnMessage = message =>
                    {
                        _uiDispatcher.Invoke(delegate ()
                        {
                            OnMessage_Worker(socket, message);
                        });
                    };
                });
            }
    
            public void OnMessage_Worker(IWebSocketConnection socket, string message){
                GTA.UI.Notification.Show(message);
                socket.Send("OK");
            }
        }
    
    


  • @Slluxx Oh, awesome 👌


Log in to reply
 

Looks like your connection to GTA5-Mods.com Forums was lost, please wait while we try to reconnect.