diff --git a/.gitignore b/.gitignore
index 0b29ae8..9a15be8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -351,4 +351,5 @@ MigrationBackup/
.ionide/
.idea
-.vscode
\ No newline at end of file
+.vscode
+run
\ No newline at end of file
diff --git a/Assembly/ASMInfo.cs b/Assembly/ASMInfo.cs
index 2cce9b2..4a37a74 100644
--- a/Assembly/ASMInfo.cs
+++ b/Assembly/ASMInfo.cs
@@ -6,7 +6,7 @@ using System.Reflection;
[assembly: AssemblyCompany("Piccari Creations")]
[assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)]
[assembly: AssemblyCopyright("(C) 2020 Tara Piccari")]
-[assembly: AssemblyFileVersion("5.0.7.9200")]
+[assembly: AssemblyFileVersion("6.0.1.0001")]
[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.121524.1636";
+ public static string BotVer = "2.0.121724.1716";
}
}
diff --git a/ForgeCore.cs b/ForgeCore.cs
index c9e1e47..ad6c26b 100644
--- a/ForgeCore.cs
+++ b/ForgeCore.cs
@@ -1,15 +1,19 @@
using System;
+using System.IO;
using System.Linq;
+using ForgeCore.Assemble;
using ForgeCoreAPI;
using LibAC.Arguments;
+using LibAC.NBT;
+using LibAC.NBT.API;
namespace ForgeCore;
public class ForgeCore
{
+
public static int Main(string[] args)
{
- PluginSystem.InitializeSystem();
Arguments arguments = ArgumentParser.Parse(args);
if (arguments.HasArg("help") || arguments.Count == 0)
@@ -18,11 +22,76 @@ public class ForgeCore
ArgumentBuilder builder = new ArgumentBuilder();
builder.withVersionArgument().withHelpArgument();
+ builder.withStringArgument("plugindir", "Plugins", true);
+ builder.withBooleanArgument("daemon", true);
Arguments defaults = builder.Build();
Console.WriteLine(ArgumentHelpers.GenerateHelpMessage(defaults.GetAllArguments().ToList(), "ForgeCore"));
+ return 0;
}
+
+ if (arguments.HasArg("version"))
+ {
+ Console.WriteLine($"ForgeCore Version {ASMInfo.BotVer}");
+ return 0;
+ }
+
+ if (arguments.HasArg("plugindir"))
+ PluginSystem.PluginDirectory = arguments.GetArgument("plugindir").GetValue() as string;
+
+ if (!Directory.Exists("Plugins"))
+ Directory.CreateDirectory("Plugins");
+
+ PluginSystem.InitializeSystem(PluginSystem.PluginDirectory);
+
+ SharedSessionData sessionData = SharedSessionData.GetInstance();
+ // Start the server tick loop
+ while (!sessionData.ShouldShutdown)
+ {
+ long tasksExecuted = 0;
+ if (sessionData.TotalTasksPerTick == 0 && sessionData.TotalTicks > 0)
+ {
+ 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");
+ }
+
+ foreach (var plugin in PluginSystem.Plugins)
+ {
+ if (plugin.enabled)
+ {
+ plugin.plugin.tick();
+ tasksExecuted++;
+ }
+ }
+
+ sessionData.TasksLastTick = tasksExecuted;
+ sessionData.TotalTicks++;
+
+ if(sessionData.TotalTasksPerTick == 0)
+ sessionData.TotalTasksPerTick = tasksExecuted;
+ }
+
+ Console.WriteLine("Preparing to shut down... Please wait...");
+ Console.WriteLine("Gathering plugin settings...");
+
+ CompoundTag saveData = new CompoundTag();
+ foreach (var pluginContainer in PluginSystem.Plugins)
+ {
+ pluginContainer.plugin.TearDown();
+
+ CompoundTag entry = new CompoundTag();
+ NbtUtils.WriteBoolean(entry, "enabled", pluginContainer.enabled);
+ entry.Add("data", pluginContainer.plugin.SaveConfig());
+ saveData.Add(pluginContainer.pluginName, entry);
+ }
+
+ Console.WriteLine("Saving plugin data...");
+ NbtIo.Write("PluginStorage.dat", saveData);
+
+ Console.WriteLine("> Plugin Storage saved.");
+ Console.WriteLine("> Exiting server...");
+
return 0;
}
diff --git a/ForgeCoreAPI/IPlugin.cs b/ForgeCoreAPI/IPlugin.cs
index 0b6f53b..59734b6 100644
--- a/ForgeCoreAPI/IPlugin.cs
+++ b/ForgeCoreAPI/IPlugin.cs
@@ -27,6 +27,11 @@ public interface IPlugin
/// Called every 5 seconds by the master server
///
void tick();
+
+ ///
+ /// Called when the server is starting the shutdown process. This operation cannot be aborted, all plugin tasks should be immediately stopped. SaveConfig will follow this instruction.
+ ///
+ void TearDown();
///
/// Provides the plugin with a copy of its saved configuration data
diff --git a/ForgeCoreAPI/PluginContainer.cs b/ForgeCoreAPI/PluginContainer.cs
new file mode 100644
index 0000000..b37c261
--- /dev/null
+++ b/ForgeCoreAPI/PluginContainer.cs
@@ -0,0 +1,8 @@
+namespace ForgeCoreAPI;
+
+public class PluginContainer
+{
+ public IPlugin plugin;
+ public bool enabled = true;
+ public string pluginName;
+}
\ No newline at end of file
diff --git a/ForgeCoreAPI/PluginSystem.cs b/ForgeCoreAPI/PluginSystem.cs
index 7b9dbe0..559efbd 100644
--- a/ForgeCoreAPI/PluginSystem.cs
+++ b/ForgeCoreAPI/PluginSystem.cs
@@ -6,13 +6,22 @@ namespace ForgeCoreAPI;
public class PluginSystem
{
- public static List Plugins = new List();
+ public static string PluginDirectory { get; set; } = "Plugins";
+
+ public static List Plugins = new List();
- public static void InitializeSystem()
+ public static void InitializeSystem(string pluginDirectory)
{
- CompoundTag pluginsData = NbtIo.Read("PluginStorage.dat");
+ CompoundTag pluginsData = new CompoundTag();
+ if (!File.Exists("PluginStorage.dat"))
+ {
+ // We have no existing saved config for plugins, or this is the first run
+ // Leave pluginsData empty
+ } else pluginsData = NbtIo.Read("PluginStorage.dat");
+
+
// Search the Plugins directory for DLL files
- string[] files = Directory.GetFiles("Plugins", "*.dll");
+ string[] files = Directory.GetFiles(pluginDirectory, "*.dll");
// Begin loading assemblies
foreach (var file in files)
@@ -24,12 +33,17 @@ public class PluginSystem
{
if (types.GetCustomAttribute() != null)
{
+ PluginContainer nPlugin = new PluginContainer();
IPlugin plugin = Activator.CreateInstance(types) as IPlugin;
plugin.Initialize();
+ nPlugin.plugin = plugin;
ForgeCorePluginAttribute attrib = types.GetCustomAttribute();
Tag? pluginStore = pluginsData.Get(attrib.pluginName);
+ nPlugin.pluginName = attrib.pluginName;
+
+
if (pluginStore == null)
{
plugin.ResetMemory();
@@ -40,11 +54,19 @@ public class PluginSystem
CompoundTag dataTag = tag["data"] as CompoundTag;
plugin.LoadConfig(dataTag);
- if(tag.Get("enabled").AsByte() == 1) plugin.Enable();
- else plugin.Disable();
+ if (NbtUtils.ReadBoolean(tag, "enabled"))
+ {
+ nPlugin.enabled = true;
+ plugin.Enable();
+ }
+ else
+ {
+ plugin.Disable();
+ nPlugin.enabled = false;
+ }
}
- Plugins.Add(plugin);
+ Plugins.Add(nPlugin);
}
}
}
diff --git a/ForgeCoreAPI/SharedSessionData.cs b/ForgeCoreAPI/SharedSessionData.cs
new file mode 100644
index 0000000..2a2bf92
--- /dev/null
+++ b/ForgeCoreAPI/SharedSessionData.cs
@@ -0,0 +1,21 @@
+namespace ForgeCoreAPI;
+
+public class SharedSessionData
+{
+ private static readonly object _lock = new object();
+ private static SharedSessionData? _instance;
+
+ public static SharedSessionData GetInstance()
+ {
+ lock (_lock)
+ {
+ if(_instance == null) _instance = new SharedSessionData();
+ return _instance;
+ }
+ }
+
+ public bool ShouldShutdown { get; set; } = false;
+ public long TotalTicks { get; set; } = 0;
+ public long TasksLastTick { get; set; } = 0;
+ public long TotalTasksPerTick { get; set; } = 0;
+}
\ No newline at end of file
diff --git a/localtest b/localtest
new file mode 100755
index 0000000..221ddc3
--- /dev/null
+++ b/localtest
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+rm -rf run || true
+
+mkdir run
+
+rm -rf bin
+dotnet restore
+
+dotnet publish ForgeCore.csproj --nologo -c Release --self-contained true /p:PublishSingleFile=true
+cp bin/Release/net8.0/linux-x64/publish/ForgeCore run/
+
+cd run
+
+chmod +x ForgeCore
+./ForgeCore --version
+./ForgeCore --help
+./ForgeCore --daemon
diff --git a/test b/test
new file mode 100755
index 0000000..efc81aa
--- /dev/null
+++ b/test
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+rm -rf run || true
+
+mkdir run
+cd run
+
+wget https://ci.zontreck.com/job/Projects/job/CSharp/job/ForgeCore/job/master/lastSuccessfulBuild/artifact/bin/Release/net8.0/linux-x64/publish/ForgeCore
+
+chmod +x ForgeCore
+./ForgeCore --version
+./ForgeCore --help
+./ForgeCore
\ No newline at end of file