Server plugins + clientside commands
This commit is contained in:
@@ -22,11 +22,10 @@ public class MindustryServer implements ApplicationListener{
|
||||
Vars.loadSettings();
|
||||
Vars.init();
|
||||
content.createContent();
|
||||
content.init();
|
||||
|
||||
Core.app.addListener(logic = new Logic());
|
||||
Core.app.addListener(netServer = new NetServer());
|
||||
Core.app.addListener(new ServerControl(args));
|
||||
|
||||
content.init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ import io.anuke.mindustry.maps.*;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.server.plugin.*;
|
||||
import io.anuke.mindustry.server.plugin.Plugins.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -40,6 +42,7 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
private final CommandHandler handler = new CommandHandler("");
|
||||
private final FileHandle logFolder = Core.files.local("logs/");
|
||||
private final Plugins plugins = new Plugins();
|
||||
|
||||
private FileHandle currentLogFile;
|
||||
private boolean inExtraRound;
|
||||
@@ -107,6 +110,9 @@ public class ServerControl implements ApplicationListener{
|
||||
Effects.setScreenShakeProvider((a, b) -> {});
|
||||
Effects.setEffectProvider((a, b, c, d, e, f) -> {});
|
||||
|
||||
//load plugins
|
||||
plugins.load();
|
||||
|
||||
registerCommands();
|
||||
|
||||
Core.app.post(() -> {
|
||||
@@ -118,7 +124,7 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
|
||||
for(String s : commands){
|
||||
Response response = handler.handleMessage(s);
|
||||
CommandResponse response = handler.handleMessage(s);
|
||||
if(response.type != ResponseType.valid){
|
||||
err("Invalid command argument sent: '{0}': {1}", s, response.type.name());
|
||||
err("Argument usage: &lc<command-1> <command1-args...>,<command-2> <command-2-args2...>");
|
||||
@@ -128,6 +134,7 @@ public class ServerControl implements ApplicationListener{
|
||||
});
|
||||
|
||||
customMapDirectory.mkdirs();
|
||||
pluginDirectory.mkdirs();
|
||||
|
||||
Thread thread = new Thread(this::readCommands, "Server Controls");
|
||||
thread.setDaemon(true);
|
||||
@@ -166,6 +173,13 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
//initialize plugins
|
||||
plugins.each(Plugin::init);
|
||||
|
||||
if(!plugins.all().isEmpty()){
|
||||
info("&lc{0} plugins loaded.", plugins.all().size);
|
||||
}
|
||||
|
||||
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
||||
System.out.print("> ");
|
||||
|
||||
@@ -306,6 +320,31 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
handler.register("plugins", "Display all loaded plugins.", arg -> {
|
||||
if(!plugins.all().isEmpty()){
|
||||
info("Maps:");
|
||||
for(LoadedPlugin plugin : plugins.all()){
|
||||
info(" &ly{0} &lcv{1}", plugin.meta.name, plugin.meta.version);
|
||||
}
|
||||
}else{
|
||||
info("No plugins found.");
|
||||
}
|
||||
info("&lyPlugin directory: &lb&fi{0}", pluginDirectory.file().getAbsoluteFile().toString());
|
||||
});
|
||||
|
||||
handler.register("plugin", "<name...>", "Display information about a loaded plugin.", arg -> {
|
||||
LoadedPlugin plugin = plugins.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
|
||||
if(plugin != null){
|
||||
info("Name: &ly{0}", plugin.meta.name);
|
||||
info("Version: &ly{0}", plugin.meta.version);
|
||||
info("Author: &ly{0}", plugin.meta.author);
|
||||
info("Path: &ly{0}", plugin.jarFile.path());
|
||||
info("Description: &ly{0}", plugin.meta.description);
|
||||
}else{
|
||||
info("No plugin with name &ly'{0}'&lg found.");
|
||||
}
|
||||
});
|
||||
|
||||
handler.register("say", "<message...>", "Send a message to all players.", arg -> {
|
||||
if(!state.is(State.playing)){
|
||||
err("Not hosting. Host a game first.");
|
||||
@@ -644,12 +683,15 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
handler.register("gc", "Trigger a grabage collection. Testing onlu.", arg -> {
|
||||
handler.register("gc", "Trigger a grabage collection. Testing only.", arg -> {
|
||||
int pre = (int)(Core.app.getJavaHeap() / 1024 / 1024);
|
||||
System.gc();
|
||||
int post = (int)(Core.app.getJavaHeap() / 1024 / 1024);
|
||||
info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post);
|
||||
});
|
||||
|
||||
plugins.each(p -> p.registerServerCommands(handler));
|
||||
plugins.each(p -> p.registerClientCommands(netServer.clientCommands));
|
||||
}
|
||||
|
||||
private void readCommands(){
|
||||
@@ -662,7 +704,7 @@ public class ServerControl implements ApplicationListener{
|
||||
}
|
||||
|
||||
private void handleCommandString(String line){
|
||||
Response response = handler.handleMessage(line);
|
||||
CommandResponse response = handler.handleMessage(line);
|
||||
|
||||
if(response.type == ResponseType.unknownCommand){
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
package io.anuke.mindustry.server.plugin;
|
||||
|
||||
import io.anuke.arc.util.*;
|
||||
|
||||
public abstract class Plugin{
|
||||
public abstract void init();
|
||||
|
||||
/** Called after all plugins have been created and commands have been registered.*/
|
||||
public void init(){
|
||||
|
||||
}
|
||||
|
||||
/** Register any commands to be used on the server side, e.g. from the console. */
|
||||
public void registerServerCommands(CommandHandler handler){
|
||||
|
||||
}
|
||||
|
||||
/** Register any commands to be used on the client side, e.g. sent from an in-game player.. */
|
||||
public void registerClientCommands(CommandHandler handler){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,82 @@
|
||||
package io.anuke.mindustry.server.plugin;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.pluginDirectory;
|
||||
|
||||
public class Plugins{
|
||||
private Array<Plugin> loaded = new Array<>();
|
||||
private Array<LoadedPlugin> loaded = new Array<>();
|
||||
|
||||
/** Loads all plugins from the folder, but does call any methods on them.*/
|
||||
public void load(){
|
||||
for(FileHandle file : pluginDirectory.list()){
|
||||
if(!file.extension().equals("jar")) continue;
|
||||
|
||||
try{
|
||||
loaded.add(loadPlugin(file));
|
||||
}catch(IllegalArgumentException ignored){
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load plugin file {0}. Skipping.", file);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return all loaded plugins. */
|
||||
public Array<LoadedPlugin> all(){
|
||||
return loaded;
|
||||
}
|
||||
|
||||
/** Iterates through each plugin.*/
|
||||
public void each(Consumer<Plugin> cons){
|
||||
loaded.each(p -> cons.accept(p.plugin));
|
||||
}
|
||||
|
||||
private LoadedPlugin loadPlugin(FileHandle jar) throws Exception{
|
||||
FileHandle zip = new ZipFileHandle(jar);
|
||||
|
||||
FileHandle metaf = zip.child("plugin.json");
|
||||
if(!metaf.exists()){
|
||||
Log.warn("Plugin {0} doesn't have a 'plugin.json' file, skipping.", jar);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
PluginMeta meta = JsonIO.read(PluginMeta.class, metaf.readString());
|
||||
|
||||
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
|
||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(classLoader, jar.file().toURI().toURL());
|
||||
|
||||
Class<?> main = Class.forName(meta.main);
|
||||
return new LoadedPlugin(jar, zip, (Plugin)main.newInstance(), meta);
|
||||
}
|
||||
|
||||
/** Represents a plugin that has been loaded from a jar file.*/
|
||||
public static class LoadedPlugin{
|
||||
public final FileHandle jarFile;
|
||||
public final FileHandle zipRoot;
|
||||
public final Plugin plugin;
|
||||
public final PluginMeta meta;
|
||||
|
||||
public LoadedPlugin(FileHandle jarFile, FileHandle zipRoot, Plugin plugin, PluginMeta meta){
|
||||
this.zipRoot = zipRoot;
|
||||
this.jarFile = jarFile;
|
||||
this.plugin = plugin;
|
||||
this.meta = meta;
|
||||
}
|
||||
}
|
||||
|
||||
/** Plugin metadata information.*/
|
||||
public static class PluginMeta{
|
||||
public String name, author, main, description;
|
||||
public String version;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user