From 8b873b72488096714eedcf40f652db4b274a14bd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Jul 2025 13:33:56 -0500 Subject: [PATCH] feat: modify plugin loading process --- .../Devices/EssentialsDevice.cs | 48 ------------------- .../Devices/EssentialsDeviceFactory.cs | 32 +++++++++++++ .../Factory/IDeviceFactory.cs | 25 ++++++++-- .../Plugins/IPluginDeviceFactory.cs | 17 +------ .../Plugins/PluginLoader.cs | 44 ++++++++++++----- 5 files changed, 86 insertions(+), 80 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs index 778f9226..f23ac71d 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs @@ -121,43 +121,6 @@ namespace PepperDash.Essentials.Core } } - /// - /// Devices the basic needs for a Device Factory - /// - public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice - { - #region IDeviceFactory Members - - /// - /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device - /// - public List TypeNames { get; protected set; } - - /// - /// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list - /// - public void LoadTypeFactories() - { - foreach (var typeName in TypeNames) - { - //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); - var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; - string description = descriptionAttribute[0].Description; - var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; - DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); - } - } - - /// - /// The method that will build the device - /// - /// The device config - /// An instance of the device - public abstract EssentialsDevice BuildDevice(DeviceConfig dc); - - #endregion - } - public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T: EssentialsDevice { #region IProcessorExtensionDeviceFactory Members @@ -203,15 +166,4 @@ namespace PepperDash.Essentials.Core /// public string MinimumEssentialsFrameworkVersion { get; protected set; } } - - public abstract class EssentialsPluginDevelopmentDeviceFactory : EssentialsDeviceFactory, IPluginDevelopmentDeviceFactory where T : EssentialsDevice - { - /// - /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") - /// - public string MinimumEssentialsFrameworkVersion { get; protected set; } - - public List DevelopmentEssentialsFrameworkVersions { get; protected set; } - } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs new file mode 100644 index 00000000..4b291f11 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core +{ + /// + /// Devices the basic needs for a Device Factory + /// + public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice + { + #region IDeviceFactory Members + + /// + public Type FactoryType => typeof(T); + + /// + /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device + /// + public List TypeNames { get; protected set; } + + /// + /// The method that will build the device + /// + /// The device config + /// An instance of the device + public abstract EssentialsDevice BuildDevice(DeviceConfig dc); + + #endregion + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs index 9f7eec58..9743aa43 100644 --- a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs @@ -1,13 +1,30 @@ -namespace PepperDash.Essentials.Core +using PepperDash.Essentials.Core.Config; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core { /// /// Defines a class that is capable of loading device types /// public interface IDeviceFactory { - /// - /// Loads all the types to the DeviceFactory + /// + /// Gets the type of the factory associated with the current instance. /// - void LoadTypeFactories(); + Type FactoryType { get; } + + /// + /// Gets a list of type names associated with the current plugin. + /// + List TypeNames { get; } + + /// + /// Builds and returns an instance based on the provided configuration. + /// + /// The configuration settings used to initialize the device. This parameter cannot be null. + /// An instance configured according to the specified . + EssentialsDevice BuildDevice(DeviceConfig deviceConfig); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs index a4e1e551..caee2dcd 100644 --- a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs @@ -1,3 +1,4 @@ +using PepperDash.Essentials.Core.Config; using System.Collections.Generic; @@ -7,25 +8,11 @@ namespace PepperDash.Essentials.Core /// Defines a class that is capable of loading custom plugin device types /// public interface IPluginDeviceFactory : IDeviceFactory - { + { /// /// Required to define the minimum version for Essentials in the format xx.yy.zz /// string MinimumEssentialsFrameworkVersion { get; } - - } - - /// - /// Defines a factory for creating plugin development devices, including support for specific framework versions. - /// - /// This interface extends to provide additional functionality - /// specific to plugin development environments. - public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory - { - /// - /// Gets a list of Essentials versions that this device is compatible with. - /// - List DevelopmentEssentialsFrameworkVersions { get; } } } diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs index 8843ba29..bf273678 100644 --- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs +++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs @@ -808,35 +808,53 @@ public static class PluginLoader /// This method verifies that the plugin meets the minimum required Essentials framework version /// before loading it. If the plugin fails the dependency check, it is skipped, and a log message is generated. If /// the plugin passes the check, it is loaded, and its type factories are initialized. - /// The plugin to be loaded, implementing the interface. If the plugin also + /// The plugin to be loaded, implementing the interface. If the plugin also /// implements , additional checks for development versions are /// performed. /// The assembly associated with the plugin being loaded. This is used for logging and tracking purposes. - private static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly) + private static void LoadCustomPlugin(IPluginDeviceFactory deviceFactory, LoadedAssembly loadedAssembly) { - var passed = plugin is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion - (developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion) - : Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion); + var passed = Global.IsRunningMinimumVersionOrHigher(deviceFactory.MinimumEssentialsFrameworkVersion); if (!passed) { - Debug.LogMessage(LogEventLevel.Information, - "\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************", - plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); + Debug.LogInformation( + "\r\n********************\r\n\tPlugin indicates minimum Essentials version {minimumEssentialsVersion}. Dependency check failed. Skipping Plugin {pluginName}\r\n********************", + deviceFactory.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); return; } else { - Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", plugin.MinimumEssentialsFrameworkVersion); + Debug.LogInformation("Passed plugin passed dependency check (required version {essentialsMinimumVersion})", deviceFactory.MinimumEssentialsFrameworkVersion); } - Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name); - plugin.LoadTypeFactories(); + Debug.LogInformation("Loading plugin: {pluginName}", loadedAssembly.Name); + + LoadDeviceFactories(deviceFactory); if(!EssentialsPluginAssemblies.Contains(loadedAssembly)) EssentialsPluginAssemblies.Add(loadedAssembly); - } - + } + + /// + /// Loads device factories from the specified plugin device factory and registers them for use. + /// + /// This method retrieves metadata from the provided , including + /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type + /// names are converted to lowercase for registration. + /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered. + private static void LoadDeviceFactories(IPluginDeviceFactory deviceFactory) + { + foreach (var typeName in deviceFactory.TypeNames) + { + //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); + var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; + string description = descriptionAttribute[0].Description; + var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; + DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice); + } + } + /// /// Loads plugins from the designated plugin directory, processes them, and integrates them into the application. ///