From 8f41d3432558e169fb890bd9ee92508dfb7e5e82 Mon Sep 17 00:00:00 2001 From: itsRevela Date: Fri, 10 Apr 2026 02:03:44 -0500 Subject: [PATCH] fix: redirect AppContext.BaseDirectory to server root for FourKit plugins AppContext.BaseDirectory pointed to the runtime/ subfolder where the self-contained .NET payload lives, causing plugins that use it for file paths to write to the wrong directory. Now set to the server exe directory at startup via AppContext.SetData. Also adds serverDirectory and dataDirectory properties to ServerPlugin so plugin authors have convenient access to the server root and a per-plugin data folder (plugins//) without needing to resolve paths manually. --- Minecraft.Server.FourKit/FourKitHost.cs | 8 +++++++- Minecraft.Server.FourKit/Plugin/ServerPlugin.cs | 16 ++++++++++++++++ Minecraft.Server.FourKit/PluginLoader.cs | 16 ++++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Minecraft.Server.FourKit/FourKitHost.cs b/Minecraft.Server.FourKit/FourKitHost.cs index 51f1b128..15f49637 100644 --- a/Minecraft.Server.FourKit/FourKitHost.cs +++ b/Minecraft.Server.FourKit/FourKitHost.cs @@ -25,9 +25,15 @@ public static partial class FourKitHost // host exe's directory instead so end users see a top-level plugins/. string hostExePath = Environment.ProcessPath ?? AppContext.BaseDirectory; string serverRoot = Path.GetDirectoryName(hostExePath) ?? AppContext.BaseDirectory; + + // Redirect AppContext.BaseDirectory to the server root so that + // plugins using AppContext.BaseDirectory get the exe directory + // instead of the runtime/ subfolder. + AppContext.SetData("APP_CONTEXT_BASE_DIRECTORY", serverRoot + Path.DirectorySeparatorChar); + string pluginsDir = Path.Combine(serverRoot, "plugins"); s_loader = new PluginLoader(); - s_loader.LoadPlugins(pluginsDir); + s_loader.LoadPlugins(pluginsDir, serverRoot); s_loader.EnableAll(); ServerLog.Info("fourkit", "Plugin system ready."); diff --git a/Minecraft.Server.FourKit/Plugin/ServerPlugin.cs b/Minecraft.Server.FourKit/Plugin/ServerPlugin.cs index a4fd94f2..c3358039 100644 --- a/Minecraft.Server.FourKit/Plugin/ServerPlugin.cs +++ b/Minecraft.Server.FourKit/Plugin/ServerPlugin.cs @@ -28,6 +28,22 @@ public abstract class ServerPlugin /// public virtual string author { get; } = "Unknown"; + /// + /// The server's root directory (where the server executable lives). + /// Use this instead of AppContext.BaseDirectory which points + /// to the .NET runtime subfolder. Set automatically before + /// is called. + /// + public string serverDirectory { get; internal set; } = string.Empty; + + /// + /// A per-plugin data directory (plugins/<PluginName>/). + /// Created automatically if it does not exist. Use this for config + /// files, logs, databases, or any plugin-specific storage. + /// Set automatically before is called. + /// + public string dataDirectory { get; internal set; } = string.Empty; + /// /// Called when this plugin is enabled /// diff --git a/Minecraft.Server.FourKit/PluginLoader.cs b/Minecraft.Server.FourKit/PluginLoader.cs index baecfcd0..9dd89af9 100644 --- a/Minecraft.Server.FourKit/PluginLoader.cs +++ b/Minecraft.Server.FourKit/PluginLoader.cs @@ -10,11 +10,16 @@ internal sealed class PluginLoader BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; private readonly List _plugins = new(); + private string _serverRoot = string.Empty; + private string _pluginsDirectory = string.Empty; public IReadOnlyList Plugins => _plugins.AsReadOnly(); - public void LoadPlugins(string pluginsDirectory) + public void LoadPlugins(string pluginsDirectory, string serverRoot) { + _serverRoot = serverRoot; + _pluginsDirectory = pluginsDirectory; + if (!Directory.Exists(pluginsDirectory)) { ServerLog.Info("fourkit", $"Creating plugins directory: {pluginsDirectory}"); @@ -136,8 +141,15 @@ internal sealed class PluginLoader { try { - InvokePluginMethod(plugin, "onEnable", "OnEnable"); string pName = GetPluginString(plugin, "name", "getName", "GetName", plugin.GetType().Name); + + plugin.serverDirectory = _serverRoot; + string dataDir = Path.Combine(_pluginsDirectory, pName); + if (!Directory.Exists(dataDir)) + Directory.CreateDirectory(dataDir); + plugin.dataDirectory = dataDir; + + InvokePluginMethod(plugin, "onEnable", "OnEnable"); ServerLog.Info("fourkit", $"Enabled: {pName}"); FourKit.FireEvent(new PluginEnableEvent(plugin));