From b3bddfc5d15747981ead903cb318d6b8b4712588 Mon Sep 17 00:00:00 2001 From: zontreck Date: Wed, 18 Dec 2024 16:19:34 -0700 Subject: [PATCH] separate libs, internal plugins, and shutdown improvements --- Assembly/ASMInfo.cs | 6 +-- ForgeCore.cs | 28 +++++++++--- ForgeCoreAPI/ASM/ASMInfo.cs | 6 ++- ForgeCoreAPI/IPlugin.cs | 4 +- ForgeCoreAPI/PluginContainer.cs | 1 + ForgeCoreAPI/PluginSystem.cs | 74 ++++++++++++++++++++++++++++++- ForgeCoreAPI/SharedSessionData.cs | 1 + 7 files changed, 108 insertions(+), 12 deletions(-) diff --git a/Assembly/ASMInfo.cs b/Assembly/ASMInfo.cs index 4a37a74..a823718 100644 --- a/Assembly/ASMInfo.cs +++ b/Assembly/ASMInfo.cs @@ -5,8 +5,8 @@ using System.Reflection; [assembly: AssemblyCompany("Piccari Creations")] [assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)] -[assembly: AssemblyCopyright("(C) 2020 Tara Piccari")] -[assembly: AssemblyFileVersion("6.0.1.0001")] +[assembly: AssemblyCopyright("(C) 2020-2024 Tara Piccari")] +[assembly: AssemblyFileVersion("6.0.1.0002")] [assembly: AssemblyDescription("ForgeCore Bot Server")] namespace ForgeCore.Assemble @@ -14,6 +14,6 @@ namespace ForgeCore.Assemble public class ASMInfo { public static string BotName = "ForgeCore"; - public static string BotVer = "2.0.121724.1716"; + public static string BotVer = "2.0.121824.1617"; } } diff --git a/ForgeCore.cs b/ForgeCore.cs index c6878c6..9fc96b7 100644 --- a/ForgeCore.cs +++ b/ForgeCore.cs @@ -23,8 +23,9 @@ public class ForgeCore ArgumentBuilder builder = new ArgumentBuilder(); builder.withVersionArgument().withHelpArgument(); - builder.withStringArgument("plugindir", "Plugins", true); + builder.withStringArgument("plugindir", "Plugins", false); builder.withBooleanArgument("daemon", true); + builder.withStringArgument("libdir", "Libs", false); Arguments defaults = builder.Build(); @@ -41,20 +42,37 @@ public class ForgeCore if (arguments.HasArg("plugindir")) PluginSystem.PluginDirectory = arguments.GetArgument("plugindir").GetValue() as string; - if (!Directory.Exists("Plugins")) - Directory.CreateDirectory("Plugins"); + if(arguments.HasArg("libdir")) + PluginSystem.LibraryDir = arguments.GetArgument("libdir").GetValue() as string; + + if (!Directory.Exists(PluginSystem.PluginDirectory)) + Directory.CreateDirectory(PluginSystem.PluginDirectory); + + if(!Directory.Exists(PluginSystem.LibraryDir)) + Directory.CreateDirectory(PluginSystem.LibraryDir); PluginSystem.InitializeSystem(PluginSystem.PluginDirectory); SharedSessionData sessionData = SharedSessionData.GetInstance(); + + // Subscribe to the interrupt event + Console.CancelKeyPress += delegate + { + Console.WriteLine("CTRL+C Detected. Processing shutdown request..."); + SharedSessionData.GetInstance().ShouldShutdown = true; + }; + + + + // Start the server tick loop while (!sessionData.ShouldShutdown) { long tasksExecuted = 0; - if (sessionData.TotalTasksPerTick == 0 && sessionData.TotalTicks > 0) + if (!sessionData.HasShutdownMethod) { sessionData.ShouldShutdown = true; - Console.WriteLine("FATAL ERROR\n\nNo plugins are loaded. This server would be doing nothing in a infinite loop with no way to exit. Aborting startup procedure. \n\n\n>> Recommendation: Add one of the standard ForgeCore Plugins which include methods of executing a shutdown"); + Console.WriteLine("/!\\ FATAL ERROR /!\\\n\nNo plugin has a method for shutting down. This server would be unable to cleanly shut down. Consider adding a plugin with a shutdown method of any kind\n\nCTRL+C is not advised, as server settings may not get saved with an interrupt"); } foreach (var plugin in PluginSystem.Plugins) diff --git a/ForgeCoreAPI/ASM/ASMInfo.cs b/ForgeCoreAPI/ASM/ASMInfo.cs index 831e18b..0afc5b7 100644 --- a/ForgeCoreAPI/ASM/ASMInfo.cs +++ b/ForgeCoreAPI/ASM/ASMInfo.cs @@ -4,8 +4,8 @@ using System.Reflection; [assembly:AssemblyCompany("Piccari Creations")] [assembly:AssemblyProduct("ForgeCoreAPI")] [assembly:AssemblyCopyright("Copyright (c) 2024 Piccari Creations")] -[assembly:AssemblyVersion("2.0.0.0")] -[assembly:AssemblyFileVersion("2.0.0.0")] +[assembly:AssemblyVersion("2.0.0.1")] +[assembly:AssemblyFileVersion("2.0.0.1")] [assembly:AssemblyDescription("API Library for ForgeCore")] @@ -14,5 +14,7 @@ namespace ForgeCoreAPI.ASM public class ASMInfo { // Static readonly assembly attributes + public static readonly string ASSEMBLY_NAME = "ForgeCoreAPI"; + public static readonly string ASSEMBLY_VERSION = "2.0.121824.1618"; } } \ No newline at end of file diff --git a/ForgeCoreAPI/IPlugin.cs b/ForgeCoreAPI/IPlugin.cs index 59734b6..227ce1e 100644 --- a/ForgeCoreAPI/IPlugin.cs +++ b/ForgeCoreAPI/IPlugin.cs @@ -57,8 +57,10 @@ public interface IPlugin public class ForgeCorePluginAttribute : Attribute { public string pluginName; - public ForgeCorePluginAttribute(string PluginName) + public bool providesShutdownMethod = false; + public ForgeCorePluginAttribute(string PluginName, bool ProvidesShutdownMethod = false) { this.pluginName = PluginName; + this.providesShutdownMethod = ProvidesShutdownMethod; } } \ No newline at end of file diff --git a/ForgeCoreAPI/PluginContainer.cs b/ForgeCoreAPI/PluginContainer.cs index b37c261..287e0ce 100644 --- a/ForgeCoreAPI/PluginContainer.cs +++ b/ForgeCoreAPI/PluginContainer.cs @@ -5,4 +5,5 @@ public class PluginContainer public IPlugin plugin; public bool enabled = true; public string pluginName; + public bool providesShutdownMethod = false; } \ No newline at end of file diff --git a/ForgeCoreAPI/PluginSystem.cs b/ForgeCoreAPI/PluginSystem.cs index 5ba2833..388d5ab 100644 --- a/ForgeCoreAPI/PluginSystem.cs +++ b/ForgeCoreAPI/PluginSystem.cs @@ -9,13 +9,14 @@ public class PluginSystem public static string PluginDirectory { get; set; } = "Plugins"; public static List Plugins = new List(); + public static string LibraryDir { get; set; } = "Libs"; private static void PSysLog(string Message) { Console.WriteLine($"[PLUGINS] {Message}"); } - public static void InitializeSystem(string pluginDirectory) + public static void InitializeSystem(string pluginDirectory, string libraryDirectory = "Libs") { CompoundTag pluginsData = new CompoundTag(); if (!File.Exists("PluginStorage.dat")) @@ -24,6 +25,66 @@ public class PluginSystem // Leave pluginsData empty } else pluginsData = NbtIo.Read("PluginStorage.dat"); + // Search the primary executable for non-removable plugins + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var type in asm.GetTypes()) + { + if (type.GetCustomAttribute() != null) + { + ForgeCorePluginAttribute attr = type.GetCustomAttribute(); + PluginContainer container = new PluginContainer(); + container.pluginName = attr.pluginName; + container.providesShutdownMethod = attr.providesShutdownMethod; + + IPlugin plugin = Activator.CreateInstance(type) as IPlugin; + container.plugin = plugin; + plugin.Initialize(); + + + PSysLog($"> Loading plugin: {container.pluginName}"); + + Tag? store = pluginsData.Get(container.pluginName); + if (store == null) + { + plugin.ResetMemory(); + } + else + { + CompoundTag plugTag = (CompoundTag)store; + CompoundTag data = (CompoundTag)plugTag.Get("data"); + + bool enabled = NbtUtils.ReadBoolean(plugTag, "enabled"); + container.enabled = enabled; + plugin.LoadConfig(data); + PSysLog($"> Loaded plugin: {container.pluginName}"); + + if (enabled) + { + plugin.Enable(); + PSysLog($"> Enabled plugin: {container.pluginName}"); + } + else + { + plugin.Disable(); + PSysLog($"> Disabled plugin: {container.pluginName}"); + } + } + + Plugins.Add(container); + } + } + } + + + // Search library folder for any libraries required to be loaded before the plugins + string[] libs = Directory.GetFiles(libraryDirectory, "*.dll"); + foreach (string lib in libs) + { + Assembly.LoadFile(lib); + // We do not need to do anything else with the loaded library. + } + // Search the Plugins directory for DLL files string[] files = Directory.GetFiles(pluginDirectory, "*.dll"); @@ -48,6 +109,7 @@ public class PluginSystem Tag? pluginStore = pluginsData.Get(attrib.pluginName); nPlugin.pluginName = attrib.pluginName; + nPlugin.providesShutdownMethod = attrib.providesShutdownMethod; PSysLog($"> Loading plugin: {nPlugin.pluginName}"); @@ -55,6 +117,10 @@ public class PluginSystem if (pluginStore == null) { plugin.ResetMemory(); + plugin.Enable(); + nPlugin.enabled = true; + PSysLog($"> Loaded plugin: {nPlugin.pluginName}"); + PSysLog($"> No existing settings found for plugin: {nPlugin.pluginName}"); } else { @@ -82,5 +148,11 @@ public class PluginSystem } } } + + // Check if any plugin provides a shutdown method + foreach (var plugin in Plugins) + { + if (plugin.providesShutdownMethod) SharedSessionData.GetInstance().HasShutdownMethod = true; + } } } \ No newline at end of file diff --git a/ForgeCoreAPI/SharedSessionData.cs b/ForgeCoreAPI/SharedSessionData.cs index 2a2bf92..8df5350 100644 --- a/ForgeCoreAPI/SharedSessionData.cs +++ b/ForgeCoreAPI/SharedSessionData.cs @@ -18,4 +18,5 @@ public class SharedSessionData public long TotalTicks { get; set; } = 0; public long TasksLastTick { get; set; } = 0; public long TotalTasksPerTick { get; set; } = 0; + public bool HasShutdownMethod { get; set; } = false; } \ No newline at end of file