Mods branch

This commit is contained in:
Anuken
2019-09-27 19:51:46 -04:00
parent f925ec8cbe
commit 70ab102d8c
6 changed files with 155 additions and 51 deletions

View File

@@ -18,8 +18,8 @@ import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.mod.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.plugin.*;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.*;
import java.nio.charset.*;
@@ -120,8 +120,8 @@ public class Vars implements Loadable{
public static FileHandle tmpDirectory;
/** data subdirectory used for saves */
public static FileHandle saveDirectory;
/** data subdirectory used for plugins */
public static FileHandle pluginDirectory;
/** data subdirectory used for mods */
public static FileHandle modDirectory;
/** map file extension */
public static final String mapExtension = "msav";
/** save file extension */
@@ -138,7 +138,7 @@ public class Vars implements Loadable{
public static DefaultWaves defaultWaves;
public static LoopControl loops;
public static Platform platform = new Platform(){};
public static Plugins plugins;
public static Mods mods;
public static World world;
public static Maps maps;
@@ -193,6 +193,7 @@ public class Vars implements Loadable{
Version.init();
mods = new Mods();
content = new ContentLoader();
loops = new LoopControl();
defaultWaves = new DefaultWaves();
@@ -240,7 +241,9 @@ public class Vars implements Loadable{
mapPreviewDirectory = dataDirectory.child("previews/");
saveDirectory = dataDirectory.child("saves/");
tmpDirectory = dataDirectory.child("tmp/");
pluginDirectory = dataDirectory.child("plugins/");
modDirectory = dataDirectory.child("mods/");
modDirectory.mkdirs();
maps.load();
}

View 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){
}
}

View 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;
}
}

View File

@@ -1,28 +1,7 @@
package io.anuke.mindustry.plugin;
import io.anuke.arc.files.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.mod.*;
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){
}
}

View File

@@ -4,6 +4,7 @@ import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*;