separate libs, internal plugins, and shutdown improvements

This commit is contained in:
zontreck 2024-12-18 16:19:34 -07:00
parent b0e8a4d459
commit b3bddfc5d1
7 changed files with 108 additions and 12 deletions

View file

@ -5,8 +5,8 @@ using System.Reflection;
[assembly: AssemblyCompany("Piccari Creations")] [assembly: AssemblyCompany("Piccari Creations")]
[assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)] [assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)]
[assembly: AssemblyCopyright("(C) 2020 Tara Piccari")] [assembly: AssemblyCopyright("(C) 2020-2024 Tara Piccari")]
[assembly: AssemblyFileVersion("6.0.1.0001")] [assembly: AssemblyFileVersion("6.0.1.0002")]
[assembly: AssemblyDescription("ForgeCore Bot Server")] [assembly: AssemblyDescription("ForgeCore Bot Server")]
namespace ForgeCore.Assemble namespace ForgeCore.Assemble
@ -14,6 +14,6 @@ namespace ForgeCore.Assemble
public class ASMInfo public class ASMInfo
{ {
public static string BotName = "ForgeCore"; public static string BotName = "ForgeCore";
public static string BotVer = "2.0.121724.1716"; public static string BotVer = "2.0.121824.1617";
} }
} }

View file

@ -23,8 +23,9 @@ public class ForgeCore
ArgumentBuilder builder = new ArgumentBuilder(); ArgumentBuilder builder = new ArgumentBuilder();
builder.withVersionArgument().withHelpArgument(); builder.withVersionArgument().withHelpArgument();
builder.withStringArgument("plugindir", "Plugins", true); builder.withStringArgument("plugindir", "Plugins", false);
builder.withBooleanArgument("daemon", true); builder.withBooleanArgument("daemon", true);
builder.withStringArgument("libdir", "Libs", false);
Arguments defaults = builder.Build(); Arguments defaults = builder.Build();
@ -41,20 +42,37 @@ public class ForgeCore
if (arguments.HasArg("plugindir")) if (arguments.HasArg("plugindir"))
PluginSystem.PluginDirectory = arguments.GetArgument("plugindir").GetValue() as string; PluginSystem.PluginDirectory = arguments.GetArgument("plugindir").GetValue() as string;
if (!Directory.Exists("Plugins")) if(arguments.HasArg("libdir"))
Directory.CreateDirectory("Plugins"); 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); PluginSystem.InitializeSystem(PluginSystem.PluginDirectory);
SharedSessionData sessionData = SharedSessionData.GetInstance(); 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 // Start the server tick loop
while (!sessionData.ShouldShutdown) while (!sessionData.ShouldShutdown)
{ {
long tasksExecuted = 0; long tasksExecuted = 0;
if (sessionData.TotalTasksPerTick == 0 && sessionData.TotalTicks > 0) if (!sessionData.HasShutdownMethod)
{ {
sessionData.ShouldShutdown = true; 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) foreach (var plugin in PluginSystem.Plugins)

View file

@ -4,8 +4,8 @@ using System.Reflection;
[assembly:AssemblyCompany("Piccari Creations")] [assembly:AssemblyCompany("Piccari Creations")]
[assembly:AssemblyProduct("ForgeCoreAPI")] [assembly:AssemblyProduct("ForgeCoreAPI")]
[assembly:AssemblyCopyright("Copyright (c) 2024 Piccari Creations")] [assembly:AssemblyCopyright("Copyright (c) 2024 Piccari Creations")]
[assembly:AssemblyVersion("2.0.0.0")] [assembly:AssemblyVersion("2.0.0.1")]
[assembly:AssemblyFileVersion("2.0.0.0")] [assembly:AssemblyFileVersion("2.0.0.1")]
[assembly:AssemblyDescription("API Library for ForgeCore")] [assembly:AssemblyDescription("API Library for ForgeCore")]
@ -14,5 +14,7 @@ namespace ForgeCoreAPI.ASM
public class ASMInfo public class ASMInfo
{ {
// Static readonly assembly attributes // Static readonly assembly attributes
public static readonly string ASSEMBLY_NAME = "ForgeCoreAPI";
public static readonly string ASSEMBLY_VERSION = "2.0.121824.1618";
} }
} }

View file

@ -57,8 +57,10 @@ public interface IPlugin
public class ForgeCorePluginAttribute : Attribute public class ForgeCorePluginAttribute : Attribute
{ {
public string pluginName; public string pluginName;
public ForgeCorePluginAttribute(string PluginName) public bool providesShutdownMethod = false;
public ForgeCorePluginAttribute(string PluginName, bool ProvidesShutdownMethod = false)
{ {
this.pluginName = PluginName; this.pluginName = PluginName;
this.providesShutdownMethod = ProvidesShutdownMethod;
} }
} }

View file

@ -5,4 +5,5 @@ public class PluginContainer
public IPlugin plugin; public IPlugin plugin;
public bool enabled = true; public bool enabled = true;
public string pluginName; public string pluginName;
public bool providesShutdownMethod = false;
} }

View file

@ -9,13 +9,14 @@ public class PluginSystem
public static string PluginDirectory { get; set; } = "Plugins"; public static string PluginDirectory { get; set; } = "Plugins";
public static List<PluginContainer> Plugins = new List<PluginContainer>(); public static List<PluginContainer> Plugins = new List<PluginContainer>();
public static string LibraryDir { get; set; } = "Libs";
private static void PSysLog(string Message) private static void PSysLog(string Message)
{ {
Console.WriteLine($"[PLUGINS] {Message}"); Console.WriteLine($"[PLUGINS] {Message}");
} }
public static void InitializeSystem(string pluginDirectory) public static void InitializeSystem(string pluginDirectory, string libraryDirectory = "Libs")
{ {
CompoundTag pluginsData = new CompoundTag(); CompoundTag pluginsData = new CompoundTag();
if (!File.Exists("PluginStorage.dat")) if (!File.Exists("PluginStorage.dat"))
@ -24,6 +25,66 @@ public class PluginSystem
// Leave pluginsData empty // Leave pluginsData empty
} else pluginsData = NbtIo.Read("PluginStorage.dat"); } 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<ForgeCorePluginAttribute>() != null)
{
ForgeCorePluginAttribute attr = type.GetCustomAttribute<ForgeCorePluginAttribute>();
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 // Search the Plugins directory for DLL files
string[] files = Directory.GetFiles(pluginDirectory, "*.dll"); string[] files = Directory.GetFiles(pluginDirectory, "*.dll");
@ -48,6 +109,7 @@ public class PluginSystem
Tag? pluginStore = pluginsData.Get(attrib.pluginName); Tag? pluginStore = pluginsData.Get(attrib.pluginName);
nPlugin.pluginName = attrib.pluginName; nPlugin.pluginName = attrib.pluginName;
nPlugin.providesShutdownMethod = attrib.providesShutdownMethod;
PSysLog($"> Loading plugin: {nPlugin.pluginName}"); PSysLog($"> Loading plugin: {nPlugin.pluginName}");
@ -55,6 +117,10 @@ public class PluginSystem
if (pluginStore == null) if (pluginStore == null)
{ {
plugin.ResetMemory(); plugin.ResetMemory();
plugin.Enable();
nPlugin.enabled = true;
PSysLog($"> Loaded plugin: {nPlugin.pluginName}");
PSysLog($"> No existing settings found for plugin: {nPlugin.pluginName}");
} }
else 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;
}
} }
} }

View file

@ -18,4 +18,5 @@ public class SharedSessionData
public long TotalTicks { get; set; } = 0; public long TotalTicks { get; set; } = 0;
public long TasksLastTick { get; set; } = 0; public long TasksLastTick { get; set; } = 0;
public long TotalTasksPerTick { get; set; } = 0; public long TotalTasksPerTick { get; set; } = 0;
public bool HasShutdownMethod { get; set; } = false;
} }