stigzler Posted Sunday at 09:21 PM Posted Sunday at 09:21 PM (edited) This may be useful to other amateur coders like myself for making plugins. The problem: You have different classes which implement the interfaces with the Launchbox Plugin system (e.g. ISystemEventsPlugin, IGameLaunchingPlugin, IGameMenu). You want to unify these events into a single 'entry point' for your plugin's application (e.g. you may need to receive results from the different plugin interfaces in a single class or return results form a centralised point). The issue is, when events fire, they fire in the instance created in Launchbox, not in any instances that are created with your plugin. Thus, even if you create an instance of the class you've authored which implements the interface, you will not receive the events. The solution: A Singleton Class I had a bit of knowledge about singletons, but not really how to apply them. However, this is just the ticket. The way I think about them for this application is that it's almost like a static class, but you can have class members outside of any methods. Clearly, each plugin interface class cannot know about each other, thus cannot share a common instance of a class. You cannot use a static class for obvious reasons. Thus, a singleton saved the day. It kinda instantiates itself the first time it is referenced (that is you don't have to instantiate it anywhere) and all other references to it in any class will end up only refencing that one class instance. It's also thread safe. It's a little hard to explain, but there's a good video here: So - the code I hear you cry? Your 'entry point' singleton: internal sealed class PluginController { private PluginController() { } private static PluginController _instance = null; private static readonly object _padlock = new object(); private Guid Guid = Guid.NewGuid(); internal static PluginController Instance { get { lock (_padlock) { if (_instance == null) { _instance = new PluginController(); } return _instance; } } } internal void SystemEventRaised(string eventType) { Logger.Log($"[{Guid.ToString()}] System Event received: {eventType}"); } internal void SystemMenuItemSelected() { Logger.Log($"[{Guid.ToString()}] System Menu Item selected"); } } The GUID is just there to show you that it's the same instance when referenced from other classes. Obs, you'll need to use Debug.WriteLine or something instead of my Logger class. Examples of the plugin interface classes: internal class SystemEventsPlugin : Unbroken.LaunchBox.Plugins.ISystemEventsPlugin { public SystemEventsPlugin() { } public void OnEventRaised(string eventType) { Logger.Log($"Received event: {eventType} on thread {System.Threading.Thread.CurrentThread.ManagedThreadId}"); PluginController.Instance.ProcessSystemEvent(eventType); } } and internal class SystemMenuItemPlugin : PluginHookBase, Unbroken.LaunchBox.Plugins.ISystemMenuItemPlugin { public SystemMenuItemPlugin() { } public string Caption => "Your Plugin"; public System.Drawing.Image IconImage => Gearbox.Presentation.Properties.Resources.icon; public bool ShowInLaunchBox => true; public bool ShowInBigBox => false; public bool AllowInBigBoxWhenLocked => false; public void OnSelected() { PluginController.Instance.ProcessSystemMenuItemSelected(); } } What you will notice with SystemEvent is that it's sent from numerous different threads, but the Singleton seems to be reasonably thread agnostic. Anyways, I'm sure there are software engineers on here who can rip this apart, but for all you other code grifters like me - hope it helps. P.S. Sorry to those of you viewing in dark mode + the poor syntax highlighting colors - nothing I can do about that- it's about how it's set up at LB's end. Edited Sunday at 09:24 PM by stigzler Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.