Jump to content

PostScreenMessage() crashes when called in .Net event handler


Recommended Posts

Would anyone have any idea why ScreenMessages.PostScreenMessage() works fine in the handler for OnFlightReady, but crashes in the handler for FileSystemWatcher.Changed? That event handler works fine too, other than the PostScreenMessage() call. It's only the combination of the two that crashes.

from error.log:

Spoiler

Kerbal Space Program by Squad [version: Unity 2019.4.18f1_3310a4d4f880]

UnityPlayer.dll caused an Access Violation (0xc0000005)
  in module UnityPlayer.dll at 0033:f105faa4.

Error occurred at 2022-08-01_065236.
C:\Program Files\KerbalSpaceProgram\KSP_x64.exe, run by admin.

66% physical memory in use.
10188 MB physical memory [3404 MB free].
9365 MB process peak paging file [9310 MB used].
6171 MB process peak working set [2772 MB used].
System Commit Total/Limit/Peak: 16562MB/18741MB/29046MB
System Physical Total/Available: 10188MB/3404MB
System Process Count: 195
System Thread Count: 2414
System Handle Count: 95091
Disk space data for 'C:\Users\admin\AppData\Local\Temp\Squad\Kerbal Space Program\Crashes\Crash_2022-08-01_105231739\': 267893669888 bytes free of 510979805184 total.

Read from location 0000000000000000 caused an access violation.

[snip]

0x00007FFE9212FAA4 (UnityPlayer) UnityMain
0x00007FFE9212D2BD (UnityPlayer) UnityMain
0x00007FFE92387BF9 (UnityPlayer) UnityMain
0x0000019A60C4FDFA (Mono JIT Code) (wrapper managed-to-native) UnityEngine.Mesh:Internal_Create (UnityEngine.Mesh)
0x0000019A60C4FD4B (Mono JIT Code) UnityEngine.Mesh:.ctor ()
0x0000019B48DEFCD3 (Mono JIT Code) TMPro.TextMeshProUGUI:Awake ()
0x00000198F89DEC30 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007FFE913ED6D0 (mono-2.0-bdwgc) mono_get_runtime_build_info
0x00007FFE91372932 (mono-2.0-bdwgc) mono_perfcounters_init
0x00007FFE9137B98F (mono-2.0-bdwgc) mono_runtime_invoke
0x00007FFE922F9A6D (UnityPlayer) UnityMain
0x00007FFE922F6E23 (UnityPlayer) UnityMain
0x00007FFE922F6EEE (UnityPlayer) UnityMain
0x00007FFE923203C5 (UnityPlayer) UnityMain
0x00007FFE922DFD90 (UnityPlayer) UnityMain
0x00007FFE922DF41D (UnityPlayer) UnityMain
0x00007FFE922DF6EC (UnityPlayer) UnityMain
0x00007FFE9233394B (UnityPlayer) UnityMain
0x00007FFE9206FC7E (UnityPlayer) UnityMain
0x00007FFE920702D8 (UnityPlayer) UnityMain
0x00007FFE9238B078 (UnityPlayer) UnityMain
0x0000019B48E0F4FA (Mono JIT Code) (wrapper managed-to-native) UnityEngine.Object:Internal_CloneSingle (UnityEngine.Object)
0x0000019B48E0F323 (Mono JIT Code) UnityEngine.Object:Instantiate<T_REF> (T_REF)
0x0000019E34CB045B (Mono JIT Code) ScreenMessages:CreateTextInstance (ScreenMessage)
0x0000019E2C4501FB (Mono JIT Code) ScreenMessages:PostMessage (ScreenMessage,string,ScreenMessagesText,single,ScreenMessageStyle,UnityEngine.Color)
0x0000019E25FFFCAB (Mono JIT Code) ScreenMessages:PostMessage (ScreenMessage,string,ScreenMessagesText,single,ScreenMessageStyle)
0x0000019E34CA708B (Mono JIT Code) ScreenMessages:PostScreenMessage (string,single,ScreenMessageStyle,bool)
0x0000019E34CA6AF3 (Mono JIT Code) JasonAMelancon_KerbalPlugins.AxisModeMessage:ShowMessage ()
0x0000019E36C80C3B (Mono JIT Code) JasonAMelancon_KerbalPlugins.AxisModeMessage:OnNewMessage_Handler (object,System.IO.FileSystemEventArgs)

[snip]

from my code:

Spoiler
using System;
using System.IO;
using UnityEngine;

namespace MyNamespace
{
	[KSPAddon(KSPAddon.Startup.Flight, once: true)]
    public class MyPlugin : MonoBehaviour
    {
        private FileSystemWatcher messageListener = null;

        public MyPlugin()
        {
            GameObject.DontDestroyOnLoad(this); 
            messageListener = new FileSystemWatcher();
        }

        private static readonly string msgFilename = "message.txt";
        private static string msgPath;

        public void Awake()
        {
            print($"[MyPlugin] Awake() executing");
            // get the full filename with path of the message file 
            string dll = System.Reflection.Assembly.GetExecutingAssembly().Location;
            msgPath = Path.GetDirectoryName(dll);
        }

        public void Start()
        {
            print("[MyPlugin] Start() executing");
            // register event listeners
            print("[MyPlugin] Initializing flight mode listener");
            GameEvents.onFlightReady.Add(OnFlightReady_Handler);
            print("[MyPlugin] Initializing message listener");
            messageListener.Path = msgPath;
            messageListener.Filter = msgFilename;
            messageListener.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
            messageListener.Changed += OnNewMessage_Handler;
            messageListener.EnableRaisingEvents = true;
        }

        public void OnDisable()
        {
            // un-register event listeners
            GameEvents.onFlightReady.Remove(OnFlightReady_Handler);
            messageListener.Changed -= OnNewMessage_Handler;
            messageListener.Dispose();
            messageListener = null;
        }

        public void OnFlightReady_Handler()
        {
            print($"[MyPlugin] OnFlightReady_Handler executing");
            ScreenMessages.PostScreenMessage(
                "Printing by Flight Ready Handler",
                duration: 5.0f,
                ScreenMessageStyle.LOWER_CENTER
            );
        }
        
        private void OnNewMessage_Handler(object _, FileSystemEventArgs e)
        {
            if (e.ChangeType != WatcherChangeTypes.Changed) return;
            print($"[MyPlugin] OnNewMessage_Handler executing");
            ScreenMessages.PostScreenMessage(
                "Printing by New Message Handler",
                duration: 5.0f,
                ScreenMessageStyle.LOWER_CENTER
            );
        }
    }  
}

 

 

Edited by Jason Melancon
typo
Link to comment
Share on other sites

  • 2 weeks later...

FileSystemWatcher events are called from separate thread.
Unity/KSP APIs are not thread safe and can't be called from another thread than the Unity main thread, that's why your ScreenMessages.PostScreenMessage() call in OnNewMessage_Handler is causing a crash.

To make that work, you can instead set a flag from the event handler and check that flag from an Update() method in your plugin class.
But I assume you will want to pass more data than a simple flag around, so you will likely need to implement thread safety mechanisms (like a lock) to make that work reliably.

Edited by Gotmachine
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...