diff --git a/plugins/example.lua b/plugins/example.lua index 5415fdf..8833fdb 100644 --- a/plugins/example.lua +++ b/plugins/example.lua @@ -1,6 +1,7 @@ -- Example plugin stub. This function is called and passed the input message. -- If nil is returned, the plugin is considered to have not run, but if any -- other value is returned, it's interpreted as a string and sent back to the user. +-- 'local' Variables inside of this file persiste between plugin calls. function plugin(message) return nil; end diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java index dac2714..5e79a7c 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -74,35 +74,40 @@ public class CommandManager } // Calls the command but on a whole new thread! - public void InvokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) + public boolean InvokeOnNewThread(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) { // This is here to prevent spinning up a thread if this wasn't even a command. if(input == null || !input.IsValid()) - return; + return false; - // Spin up a thread and begin it. The thread carries the info needed to invoke the command. - CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext); - threadAccumulator.add(newThread); - newThread.start(); + Command command = commands.get(input.key); + if(command != null) + { + // Spin up a thread and begin it. The thread carries the info needed to invoke the command. + CommandThread newThread = new CommandThread(this, input, guild, channel, user, responseContext); + threadAccumulator.add(newThread); + newThread.start(); + return true; + } + else + { + GlobalLog.Warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key); + return false; + } } // Calls the command specified with the key, providing user information arguments, etc. - public void Invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) + void Invoke(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response responseContext) { if(input == null || !input.IsValid()) return; Command command = commands.get(input.key); - if(command != null) { ++invokeCount; command.Invoke(guild, channel, user, input, responseContext); } - else - { - GlobalLog.Warn(LogFilter.Command, "User " + user.name + " tried to invoke command that doesn't exist: " + input.key); - } } // Looks up command by name. If it exists, dumps help text, otherwise returns null. diff --git a/src/core/lua/Plugin.java b/src/core/lua/Plugin.java index 9053ef6..b58a87c 100644 --- a/src/core/lua/Plugin.java +++ b/src/core/lua/Plugin.java @@ -6,29 +6,61 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Stream; -//To promote flexibility, plugins are lua file with predefined callbacks. -//They are executed between the initial built-in preprocessing and the command parsing. +import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.lib.jse.JsePlatform; + +// To promote flexibility, plugins are lua file with predefined callbacks. +// They are executed between the initial built-in preprocessing and the command parsing. +// This class wraps the lua layer - provides all the processing and function calls to the lua binding. public class Plugin { public Path filepath; public String contents; + private Globals globals; + private LuaValue func_plugin; public Plugin(Path filepath) { this.filepath = filepath; - StringBuilder contentBuilder = new StringBuilder(); + StringBuilder contentBuilder = new StringBuilder(); + try { Stream stream = Files.lines(filepath, StandardCharsets.UTF_8); stream.forEach(str -> contentBuilder.append(str).append("\n")); stream.close(); contents = contentBuilder.toString(); + + globals = JsePlatform.standardGlobals(); + + globals.load(contents).call(); + func_plugin = globals.get("plugin"); + + String output = null; } catch (IOException e) { PluginLog.Error(e.getMessage()); } } + + public String Run(String args) + { + try + { + LuaValue res = func_plugin.call(LuaValue.valueOf(args)); + + if(!res.isnil()) + return res.toString(); + } + catch(Exception e) + { + PluginLog.Error("Failed to run plugin from file " + filepath); + } + + return null; + } } diff --git a/src/core/lua/PluginLoader.java b/src/core/lua/PluginLoader.java deleted file mode 100644 index 35db1a0..0000000 --- a/src/core/lua/PluginLoader.java +++ /dev/null @@ -1,42 +0,0 @@ -package core.lua; - -import org.luaj.vm2.Globals; -import org.luaj.vm2.LuaValue; -import org.luaj.vm2.lib.jse.JsePlatform; - -// This class wraps the lua layer - provides all the processing and function -// calls to the lua binding. -public class PluginLoader -{ - private Globals globals; - - public PluginLoader() - { - globals = JsePlatform.standardGlobals(); - PluginLog.Log("Created new PluginLoader lua environment"); - } - - public String Process(Plugin toProcess, String args) - { - globals.load(toProcess.contents).call(); - LuaValue pluginFunc = globals.get("plugin"); - - String output = null; - - try - { - LuaValue res = pluginFunc.call(LuaValue.valueOf(args)); - - if(res.isnil()) - output = null; - else - output = res.toString(); - } - catch(Exception e) - { - output = null; - } - - return output; - } -} diff --git a/src/core/lua/PluginManager.java b/src/core/lua/PluginManager.java index c4e1fa9..90593c3 100644 --- a/src/core/lua/PluginManager.java +++ b/src/core/lua/PluginManager.java @@ -9,7 +9,6 @@ import java.util.stream.Stream; // Reads in, handles, and manipulates plugins. Plugins are loaded in the order they appear in the folder. public class PluginManager { - public PluginLoader pluginLoader; public final String pluginFolder; public ArrayList plugins; @@ -22,8 +21,7 @@ public class PluginManager { this.pluginFolder = folder; plugins = new ArrayList(); - this.pluginLoader = new PluginLoader(); - + try { try (Stream paths = Files.walk(Paths.get(this.pluginFolder))) @@ -37,16 +35,18 @@ public class PluginManager } } - public String CallAll(String input) + // Runs all plugins, returning when it gets a non-nill result. + // Otherwise, returns null. + public String RunAll(String input) { for(int i = 0; i < plugins.size(); ++i) { - Plugin script = plugins.get(i); - String out = pluginLoader.Process(script, input); + Plugin plugin = plugins.get(i); + String out = plugin.Run(input); if(out != null) { - PluginLog.Log("Executed plugin at " + script.filepath); + PluginLog.Log("Executed plugin at " + plugin.filepath); return out; } } diff --git a/src/main/Main.java b/src/main/Main.java index 5d79ca8..37edf6f 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -75,14 +75,18 @@ public class Main extends ListenerAdapter // RP logging system RPManager.instance.addLine(channel, user, input); - // Run plugins right before invoking the commands but after all other setup - String output = pluginManager.CallAll(input.message); + // - // Spin up the command if no plugins ran. Otherwise, send a response. - if(output == null) - commandManager.InvokeOnNewThread(guild, channel, user, input, response); - else - response.Call(output); + + // Attempt to spin up a command. If the command doesn't exist. + // Run plugins right before invoking the commands but after all other setup. + if(commandManager.InvokeOnNewThread(guild, channel, user, input, response) == false) + { + String pluginOutput = pluginManager.RunAll(input.message); + + if(pluginOutput != null) + response.Call(pluginOutput); + } // Run any upkeep we need to PerCommandUpkeep();