diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index abcdc3557..8f64f0e51 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -8,6 +8,7 @@ import java.io.InputStreamReader; import java.net.InetSocketAddress; import emu.grasscutter.command.CommandMap; +import emu.grasscutter.plugin.PluginManager; import emu.grasscutter.utils.Utils; import org.reflections.Reflections; import org.slf4j.LoggerFactory; @@ -33,6 +34,7 @@ public final class Grasscutter { public static RunMode MODE = RunMode.BOTH; private static DispatchServer dispatchServer; private static GameServer gameServer; + private static PluginManager pluginManager; public static final Reflections reflector = new Reflections(); @@ -52,15 +54,11 @@ public final class Grasscutter { for (String arg : args) { switch (arg.toLowerCase()) { - case "-auth": - MODE = RunMode.AUTH; - break; - case "-game": - MODE = RunMode.GAME; - break; - case "-handbook": - Tools.createGmHandbook(); - return; + case "-auth" -> MODE = RunMode.AUTH; + case "-game" -> MODE = RunMode.GAME; + case "-handbook" -> { + Tools.createGmHandbook(); return; + } } } @@ -71,19 +69,21 @@ public final class Grasscutter { ResourceLoader.loadAll(); // Database DatabaseManager.initialize(); + + // Create server instances. + dispatchServer = new DispatchServer(); + gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port)); + + // Create plugin manager instance. + pluginManager = new PluginManager(); // Start servers. if(getConfig().RunMode.equalsIgnoreCase("HYBRID")) { - dispatchServer = new DispatchServer(); dispatchServer.start(); - - gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port)); gameServer.start(); - } else if(getConfig().RunMode.equalsIgnoreCase("DISPATCH_ONLY")) { - dispatchServer = new DispatchServer(); + } else if (getConfig().RunMode.equalsIgnoreCase("DISPATCH_ONLY")) { dispatchServer.start(); - } else if(getConfig().RunMode.equalsIgnoreCase("GAME_ONLY")) { - gameServer = new GameServer(new InetSocketAddress(getConfig().getGameServerOptions().Ip, getConfig().getGameServerOptions().Port)); + } else if (getConfig().RunMode.equalsIgnoreCase("GAME_ONLY")) { gameServer.start(); } else { getLogger().error("Invalid server run mode. " + getConfig().RunMode); @@ -91,12 +91,23 @@ public final class Grasscutter { getLogger().error("Shutting down..."); System.exit(1); } - - + + // Enable all plugins. + pluginManager.enablePlugins(); // Open console. startConsole(); + // Hook into shutdown event. + Runtime.getRuntime().addShutdownHook(new Thread(Grasscutter::onShutdown)); } + + /** + * Server shutdown event. + */ + private static void onShutdown() { + // Disable all plugins. + pluginManager.disablePlugins(); + } public static void loadConfig() { try (FileReader file = new FileReader(configFile)) { @@ -112,7 +123,7 @@ public final class Grasscutter { try (FileWriter file = new FileWriter(configFile)) { file.write(gson.toJson(config)); } catch (Exception e) { - Grasscutter.getLogger().error("Config save error"); + Grasscutter.getLogger().error("Unable to save config file."); } } @@ -122,13 +133,13 @@ public final class Grasscutter { while ((input = br.readLine()) != null) { try { if(getConfig().RunMode.equalsIgnoreCase("DISPATCH_ONLY")) { - getLogger().error("Commands are not supported in dispatch only mode"); + getLogger().error("Commands are not supported in dispatch only mode."); return; } + CommandMap.getInstance().invoke(null, input); } catch (Exception e) { - Grasscutter.getLogger().error("Command error: "); - e.printStackTrace(); + Grasscutter.getLogger().error("Command error:", e); } } } catch (Exception e) { @@ -161,4 +172,8 @@ public final class Grasscutter { public static GameServer getGameServer() { return gameServer; } + + public static PluginManager getPluginManager() { + return pluginManager; + } } diff --git a/src/main/java/emu/grasscutter/plugin/Plugin.java b/src/main/java/emu/grasscutter/plugin/Plugin.java index 145a06eb8..a3160d7c7 100644 --- a/src/main/java/emu/grasscutter/plugin/Plugin.java +++ b/src/main/java/emu/grasscutter/plugin/Plugin.java @@ -7,22 +7,18 @@ import emu.grasscutter.server.game.GameServer; * The base class for all plugins to extend. */ public abstract class Plugin { - private final PluginIdentifier identifier; + private PluginIdentifier identifier; /** - * Empty constructor for developers. - * Should not be called by users. - */ - public Plugin() { - this(new PluginIdentifier("", "", "", new String[]{})); - } - - /** - * Constructor for plugins. + * This method is reflected into. + * + * Set plugin variables. * @param identifier The plugin's identifier. */ - public Plugin(PluginIdentifier identifier) { - this.identifier = identifier; + private void initializePlugin(PluginIdentifier identifier) { + if(this.identifier == null) + this.identifier = identifier; + else Grasscutter.getLogger().warn(this.identifier.name + " had a reinitialization attempt."); } /** diff --git a/src/main/java/emu/grasscutter/plugin/PluginManager.java b/src/main/java/emu/grasscutter/plugin/PluginManager.java index 3177bb291..3e55e4ad8 100644 --- a/src/main/java/emu/grasscutter/plugin/PluginManager.java +++ b/src/main/java/emu/grasscutter/plugin/PluginManager.java @@ -5,13 +5,13 @@ import emu.grasscutter.utils.Utils; import java.io.File; import java.io.InputStreamReader; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; /** * Manages the server's plugins & the event system. @@ -42,7 +42,7 @@ public final class PluginManager { List plugins = Arrays.stream(files) .filter(file -> file.getName().endsWith(".jar")) - .collect(Collectors.toList()); + .toList(); plugins.forEach(plugin -> { try { @@ -59,9 +59,8 @@ public final class PluginManager { } Class pluginClass = loader.loadClass(pluginConfig.mainClass); - Plugin pluginInstance = (Plugin) pluginClass.getDeclaredConstructor(PluginIdentifier.class) - .newInstance(PluginIdentifier.fromPluginConfig(pluginConfig)); - this.loadPlugin(pluginInstance); + Plugin pluginInstance = (Plugin) pluginClass.getDeclaredConstructor().newInstance(); + this.loadPlugin(pluginInstance, PluginIdentifier.fromPluginConfig(pluginConfig)); fileReader.close(); // Close the file reader. } catch (ClassNotFoundException ignored) { @@ -77,11 +76,20 @@ public final class PluginManager { * Load the specified plugin. * @param plugin The plugin instance. */ - private void loadPlugin(Plugin plugin) { - Grasscutter.getLogger().info("Loading plugin: " + plugin.getName()); + private void loadPlugin(Plugin plugin, PluginIdentifier identifier) { + Grasscutter.getLogger().info("Loading plugin: " + identifier.name); + + // Add the plugin's identifier. + try { + Class pluginClass = Plugin.class; + Method method = pluginClass.getDeclaredMethod("initializePlugin", PluginIdentifier.class); + method.setAccessible(true); method.invoke(plugin, identifier); method.setAccessible(false); + } catch (Exception ignored) { + Grasscutter.getLogger().warn("Failed to add plugin identifier: " + identifier.name); + } // Add the plugin to the list of loaded plugins. - this.plugins.put(plugin.getName(), plugin); + this.plugins.put(identifier.name, plugin); // Call the plugin's onLoad method. plugin.onLoad(); } @@ -90,13 +98,19 @@ public final class PluginManager { * Enables all registered plugins. */ public void enablePlugins() { - + this.plugins.forEach((name, plugin) -> { + Grasscutter.getLogger().info("Enabling plugin: " + name); + plugin.onEnable(); + }); } /** * Disables all registered plugins. */ public void disablePlugins() { - + this.plugins.forEach((name, plugin) -> { + Grasscutter.getLogger().info("Disabling plugin: " + name); + plugin.onDisable(); + }); } } \ No newline at end of file