Mods branch
This commit is contained in:
@@ -18,8 +18,8 @@ import io.anuke.mindustry.game.*;
|
|||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.input.*;
|
import io.anuke.mindustry.input.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.*;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.plugin.*;
|
|
||||||
import io.anuke.mindustry.world.blocks.defense.ForceProjector.*;
|
import io.anuke.mindustry.world.blocks.defense.ForceProjector.*;
|
||||||
|
|
||||||
import java.nio.charset.*;
|
import java.nio.charset.*;
|
||||||
@@ -120,8 +120,8 @@ public class Vars implements Loadable{
|
|||||||
public static FileHandle tmpDirectory;
|
public static FileHandle tmpDirectory;
|
||||||
/** data subdirectory used for saves */
|
/** data subdirectory used for saves */
|
||||||
public static FileHandle saveDirectory;
|
public static FileHandle saveDirectory;
|
||||||
/** data subdirectory used for plugins */
|
/** data subdirectory used for mods */
|
||||||
public static FileHandle pluginDirectory;
|
public static FileHandle modDirectory;
|
||||||
/** map file extension */
|
/** map file extension */
|
||||||
public static final String mapExtension = "msav";
|
public static final String mapExtension = "msav";
|
||||||
/** save file extension */
|
/** save file extension */
|
||||||
@@ -138,7 +138,7 @@ public class Vars implements Loadable{
|
|||||||
public static DefaultWaves defaultWaves;
|
public static DefaultWaves defaultWaves;
|
||||||
public static LoopControl loops;
|
public static LoopControl loops;
|
||||||
public static Platform platform = new Platform(){};
|
public static Platform platform = new Platform(){};
|
||||||
public static Plugins plugins;
|
public static Mods mods;
|
||||||
|
|
||||||
public static World world;
|
public static World world;
|
||||||
public static Maps maps;
|
public static Maps maps;
|
||||||
@@ -193,6 +193,7 @@ public class Vars implements Loadable{
|
|||||||
|
|
||||||
Version.init();
|
Version.init();
|
||||||
|
|
||||||
|
mods = new Mods();
|
||||||
content = new ContentLoader();
|
content = new ContentLoader();
|
||||||
loops = new LoopControl();
|
loops = new LoopControl();
|
||||||
defaultWaves = new DefaultWaves();
|
defaultWaves = new DefaultWaves();
|
||||||
@@ -240,7 +241,9 @@ public class Vars implements Loadable{
|
|||||||
mapPreviewDirectory = dataDirectory.child("previews/");
|
mapPreviewDirectory = dataDirectory.child("previews/");
|
||||||
saveDirectory = dataDirectory.child("saves/");
|
saveDirectory = dataDirectory.child("saves/");
|
||||||
tmpDirectory = dataDirectory.child("tmp/");
|
tmpDirectory = dataDirectory.child("tmp/");
|
||||||
pluginDirectory = dataDirectory.child("plugins/");
|
modDirectory = dataDirectory.child("mods/");
|
||||||
|
|
||||||
|
modDirectory.mkdirs();
|
||||||
|
|
||||||
maps.load();
|
maps.load();
|
||||||
}
|
}
|
||||||
|
|||||||
27
core/src/io/anuke/mindustry/mod/Mod.java
Normal file
27
core/src/io/anuke/mindustry/mod/Mod.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package io.anuke.mindustry.mod;
|
||||||
|
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.mindustry.*;
|
||||||
|
|
||||||
|
public class Mod{
|
||||||
|
/** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/
|
||||||
|
public FileHandle getConfig(){
|
||||||
|
return Vars.mods.getConfig(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
94
core/src/io/anuke/mindustry/mod/Mods.java
Normal file
94
core/src/io/anuke/mindustry/mod/Mods.java
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package io.anuke.mindustry.mod;
|
||||||
|
|
||||||
|
import io.anuke.annotations.Annotations.*;
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.*;
|
||||||
|
import io.anuke.arc.function.*;
|
||||||
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.mindustry.io.*;
|
||||||
|
import io.anuke.mindustry.plugin.*;
|
||||||
|
import io.anuke.mindustry.plugin.Plugins.*;
|
||||||
|
|
||||||
|
import java.net.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class Mods{
|
||||||
|
private Array<LoadedMod> loaded = new Array<>();
|
||||||
|
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
|
||||||
|
|
||||||
|
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
||||||
|
* Call this in init(). */
|
||||||
|
public FileHandle getConfig(Mod mod){
|
||||||
|
ModMeta load = metas.get(mod.getClass());
|
||||||
|
if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!");
|
||||||
|
return modDirectory.child(load.name).child("config.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return the loaded plugin found by class, or null if not found. */
|
||||||
|
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
||||||
|
return loaded.find(l -> l.mod.getClass() == type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Loads all plugins from the folder, but does call any methods on them.*/
|
||||||
|
public void load(){
|
||||||
|
for(FileHandle file : modDirectory.list()){
|
||||||
|
if(!file.extension().equals("jar") || !file.extension().equals("zi[")) continue;
|
||||||
|
|
||||||
|
try{
|
||||||
|
loaded.add(loadmod(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<LoadedMod> all(){
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates through each plugin.*/
|
||||||
|
public void each(Consumer<Mod> cons){
|
||||||
|
loaded.each(p -> cons.accept(p.mod));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadedMod loadmod(FileHandle jar) throws Exception{
|
||||||
|
FileHandle zip = new ZipFileHandle(jar);
|
||||||
|
|
||||||
|
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("plugin.json");
|
||||||
|
if(!metaf.exists()){
|
||||||
|
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json' file, skipping.", jar);
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModMeta meta = JsonIO.read(ModMeta.class, metaf.readString());
|
||||||
|
|
||||||
|
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||||
|
Class<?> main = classLoader.loadClass(meta.main);
|
||||||
|
metas.put(main, meta);
|
||||||
|
return new LoadedMod(jar, zip, (Mod)main.getDeclaredConstructor().newInstance(), meta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Represents a plugin that has been loaded from a jar file.*/
|
||||||
|
public static class LoadedMod{
|
||||||
|
public final FileHandle jarFile;
|
||||||
|
public final FileHandle zipRoot;
|
||||||
|
public final @Nullable Mod mod;
|
||||||
|
public final ModMeta meta;
|
||||||
|
|
||||||
|
public LoadedMod(FileHandle jarFile, FileHandle zipRoot, Mod mod, ModMeta meta){
|
||||||
|
this.zipRoot = zipRoot;
|
||||||
|
this.jarFile = jarFile;
|
||||||
|
this.mod = mod;
|
||||||
|
this.meta = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Plugin metadata information.*/
|
||||||
|
public static class ModMeta{
|
||||||
|
public String name, author, description, version, main;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,7 @@
|
|||||||
package io.anuke.mindustry.plugin;
|
package io.anuke.mindustry.plugin;
|
||||||
|
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.mindustry.mod.*;
|
||||||
import io.anuke.arc.util.*;
|
|
||||||
import io.anuke.mindustry.*;
|
|
||||||
|
|
||||||
public abstract class Plugin{
|
public abstract class Plugin extends Mod{
|
||||||
|
|
||||||
/** @return the config file for this plugin, as the file 'plugins/[plugin-name]/config.json'.*/
|
|
||||||
public FileHandle getConfig(){
|
|
||||||
return Vars.plugins.getConfig(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.*;
|
|||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
|
import io.anuke.arc.input.*;
|
||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.arc.math.geom.*;
|
import io.anuke.arc.math.geom.*;
|
||||||
import io.anuke.arc.scene.*;
|
import io.anuke.arc.scene.*;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import io.anuke.mindustry.gen.*;
|
|||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
import io.anuke.mindustry.net.Administration.*;
|
import io.anuke.mindustry.net.Administration.*;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
import io.anuke.mindustry.plugin.*;
|
import io.anuke.mindustry.plugin.*;
|
||||||
@@ -51,7 +52,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
private PrintWriter socketOutput;
|
private PrintWriter socketOutput;
|
||||||
|
|
||||||
public ServerControl(String[] args){
|
public ServerControl(String[] args){
|
||||||
plugins = new Plugins();
|
|
||||||
|
|
||||||
Core.settings.defaults(
|
Core.settings.defaults(
|
||||||
"shufflemode", "normal",
|
"shufflemode", "normal",
|
||||||
@@ -134,7 +134,6 @@ public class ServerControl implements ApplicationListener{
|
|||||||
});
|
});
|
||||||
|
|
||||||
customMapDirectory.mkdirs();
|
customMapDirectory.mkdirs();
|
||||||
pluginDirectory.mkdirs();
|
|
||||||
|
|
||||||
Thread thread = new Thread(this::readCommands, "Server Controls");
|
Thread thread = new Thread(this::readCommands, "Server Controls");
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
@@ -178,10 +177,10 @@ public class ServerControl implements ApplicationListener{
|
|||||||
});
|
});
|
||||||
|
|
||||||
//initialize plugins
|
//initialize plugins
|
||||||
plugins.each(io.anuke.mindustry.plugin.Plugin::init);
|
plugins.each(Plugin::init);
|
||||||
|
|
||||||
if(!plugins.all().isEmpty()){
|
if(!mods.all().isEmpty()){
|
||||||
info("&lc{0} plugins loaded.", plugins.all().size);
|
info("&lc{0} plugins loaded.", mods.all().size);
|
||||||
}
|
}
|
||||||
|
|
||||||
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
||||||
@@ -324,28 +323,28 @@ public class ServerControl implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.register("plugins", "Display all loaded plugins.", arg -> {
|
handler.register("mods", "Display all loaded mods.", arg -> {
|
||||||
if(!plugins.all().isEmpty()){
|
if(!mods.all().isEmpty()){
|
||||||
info("Plugins:");
|
info("Mods:");
|
||||||
for(LoadedPlugin plugin : plugins.all()){
|
for(LoadedMod mod : mods.all()){
|
||||||
info(" &ly{0} &lcv{1}", plugin.meta.name, plugin.meta.version);
|
info(" &ly{0} &lcv{1}", mod.meta.name, mod.meta.version);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
info("No plugins found.");
|
info("No mods found.");
|
||||||
}
|
}
|
||||||
info("&lyPlugin directory: &lb&fi{0}", pluginDirectory.file().getAbsoluteFile().toString());
|
info("&lyMod directory: &lb&fi{0}", modDirectory.file().getAbsoluteFile().toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.register("plugin", "<name...>", "Display information about a loaded plugin.", arg -> {
|
handler.register("mod", "<name...>", "Display information about a loaded plugin.", arg -> {
|
||||||
LoadedPlugin plugin = plugins.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
|
LoadedMod mod = mods.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
|
||||||
if(plugin != null){
|
if(mod != null){
|
||||||
info("Name: &ly{0}", plugin.meta.name);
|
info("Name: &ly{0}", mod.meta.name);
|
||||||
info("Version: &ly{0}", plugin.meta.version);
|
info("Version: &ly{0}", mod.meta.version);
|
||||||
info("Author: &ly{0}", plugin.meta.author);
|
info("Author: &ly{0}", mod.meta.author);
|
||||||
info("Path: &ly{0}", plugin.jarFile.path());
|
info("Path: &ly{0}", mod.jarFile.path());
|
||||||
info("Description: &ly{0}", plugin.meta.description);
|
info("Description: &ly{0}", mod.meta.description);
|
||||||
}else{
|
}else{
|
||||||
info("No plugin with name &ly'{0}'&lg found.");
|
info("No mod with name &ly'{0}'&lg found.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -757,8 +756,9 @@ public class ServerControl implements ApplicationListener{
|
|||||||
info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post);
|
info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post);
|
||||||
});
|
});
|
||||||
|
|
||||||
plugins.each(p -> p.registerServerCommands(handler));
|
mods.each(p -> p.registerServerCommands(handler));
|
||||||
plugins.each(p -> p.registerClientCommands(netServer.clientCommands));
|
//TODO
|
||||||
|
//plugins.each(p -> p.registerClientCommands(netServer.clientCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readCommands(){
|
private void readCommands(){
|
||||||
|
|||||||
Reference in New Issue
Block a user