Support for zones

This commit is contained in:
Anuken
2019-10-03 18:53:43 -04:00
parent 35ede418eb
commit bc02d178ce
6 changed files with 50 additions and 7 deletions

View File

@@ -78,6 +78,7 @@ mod.enable = Enable
mod.requiresrestart = The game will now close to apply the mod changes. mod.requiresrestart = The game will now close to apply the mod changes.
mod.reloadrequired = [scarlet]Reload Required mod.reloadrequired = [scarlet]Reload Required
mod.import = Import Mod mod.import = Import Mod
mod.import.github = Import Github Mod
mod.remove.confirm = This mod will be deleted. mod.remove.confirm = This mod will be deleted.
mod.author = [LIGHT_GRAY]Author:[] {0} mod.author = [LIGHT_GRAY]Author:[] {0}
mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0} mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0}

View File

@@ -284,7 +284,7 @@ public class UI implements ApplicationListener, Loadable{
new Dialog(titleText){{ new Dialog(titleText){{
cont.margin(30).add(dtext).padRight(6f); cont.margin(30).add(dtext).padRight(6f);
TextFieldFilter filter = inumeric ? TextFieldFilter.digitsOnly : (f, c) -> true; TextFieldFilter filter = inumeric ? TextFieldFilter.digitsOnly : (f, c) -> true;
TextField field = cont.addField(def, t -> {}).size(170f, 50f).get(); TextField field = cont.addField(def, t -> {}).size(330f, 50f).get();
field.setFilter((f, c) -> field.getText().length() < textLength && filter.acceptChar(f, c)); field.setFilter((f, c) -> field.getText().length() < textLength && filter.acceptChar(f, c));
buttons.defaults().size(120, 54).pad(4); buttons.defaults().size(120, 54).pad(4);
buttons.addButton("$ok", () -> { buttons.addButton("$ok", () -> {

View File

@@ -2,11 +2,13 @@ package io.anuke.mindustry.mod;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.audio.*; import io.anuke.arc.audio.*;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.reflect.Field;
import io.anuke.arc.util.reflect.*; import io.anuke.arc.util.reflect.*;
import io.anuke.arc.util.serialization.*; import io.anuke.arc.util.serialization.*;
import io.anuke.arc.util.serialization.Json.*; import io.anuke.arc.util.serialization.Json.*;
@@ -21,6 +23,8 @@ import io.anuke.mindustry.mod.Mods.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import java.lang.reflect.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ContentParser{ public class ContentParser{
private static final boolean ignoreUnknownFields = true; private static final boolean ignoreUnknownFields = true;
@@ -29,6 +33,7 @@ public class ContentParser{
put(BulletType.class, (type, data) -> field(Bullets.class, data)); put(BulletType.class, (type, data) -> field(Bullets.class, data));
put(Effect.class, (type, data) -> field(Fx.class, data)); put(Effect.class, (type, data) -> field(Fx.class, data));
put(StatusEffect.class, (type, data) -> field(StatusEffects.class, data)); put(StatusEffect.class, (type, data) -> field(StatusEffects.class, data));
put(Loadout.class, (type, data) -> field(Loadouts.class, data));
put(Color.class, (type, data) -> Color.valueOf(data.asString())); put(Color.class, (type, data) -> Color.valueOf(data.asString()));
put(Music.class, (type, data) -> { put(Music.class, (type, data) -> {
if(fieldOpt(Musics.class, data) != null) return fieldOpt(Musics.class, data); if(fieldOpt(Musics.class, data) != null) return fieldOpt(Musics.class, data);
@@ -173,7 +178,7 @@ public class ContentParser{
if(!arr.isEmpty()){ if(!arr.isEmpty()){
Class<?> c = arr.first().getClass(); Class<?> c = arr.first().getClass();
//get base content class, skipping intermediates //get base content class, skipping intermediates
while(!(c.getSuperclass() == Content.class || c.getSuperclass() == UnlockableContent.class || c.getSuperclass() == UnlockableContent.class)){ while(!(c.getSuperclass() == Content.class || c.getSuperclass() == UnlockableContent.class || Modifier.isAbstract(c.getSuperclass().getModifiers()))){
c = c.getSuperclass(); c = c.getSuperclass();
} }
@@ -260,13 +265,13 @@ public class ContentParser{
private void checkNulls(Object object, ObjectSet<Object> checked){ private void checkNulls(Object object, ObjectSet<Object> checked){
checked.add(object); checked.add(object);
parser.getFields(object.getClass()).each((name, field) -> { parser.getFields(object.getClass()).values().toArray().each(field -> {
try{ try{
if(field.field.getType().isPrimitive()) return; if(field.field.getType().isPrimitive()) return;
Object obj = field.field.get(object); Object obj = field.field.get(object);
if(field.field.isAnnotationPresent(NonNull.class) && field.field.get(object) == null){ if(field.field.isAnnotationPresent(NonNull.class) && field.field.get(object) == null){
throw new RuntimeException("Field '" + name + "' in " + object.getClass().getSimpleName() + " is missing!"); throw new RuntimeException("Field '" + field.field.getName() + "' in " + object.getClass().getSimpleName() + " is missing!");
} }
if(obj != null && !checked.contains(obj)){ if(obj != null && !checked.contains(obj)){

View File

@@ -331,6 +331,9 @@ public class Mods implements Loadable{
* Note that directories can be loaded as mods.*/ * Note that directories can be loaded as mods.*/
private LoadedMod loadMod(FileHandle sourceFile) throws Exception{ private LoadedMod loadMod(FileHandle sourceFile) throws Exception{
FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile); FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile);
if(zip.list().length == 1 && zip.list()[0].isDirectory()){
zip = zip.list()[0];
}
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("plugin.json"); FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("plugin.json");
if(!metaf.exists()){ if(!metaf.exists()){
@@ -341,6 +344,12 @@ public class Mods implements Loadable{
ModMeta meta = json.fromJson(ModMeta.class, metaf.readString()); ModMeta meta = json.fromJson(ModMeta.class, metaf.readString());
String camelized = meta.name.replace(" ", ""); String camelized = meta.name.replace(" ", "");
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main; String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
String baseName = meta.name.toLowerCase().replace(" ", "-");
if(loaded.contains(m -> m.name.equals(baseName)) || disabled.contains(m -> m.name.equals(baseName))){
throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported.");
}
Mod mainMod; Mod mainMod;
FileHandle mainFile = zip; FileHandle mainFile = zip;

View File

@@ -47,7 +47,7 @@ public class Zone extends UnlockableContent{
@Override @Override
public void load(){ public void load(){
preview = Core.atlas.find("zone-" + name); preview = Core.atlas.find("zone-" + name, Core.atlas.find(name + "-zone"));
} }
public Rules getRules(){ public Rules getRules(){
@@ -209,14 +209,18 @@ public class Zone extends UnlockableContent{
} }
public static class ZoneRequirement{ public static class ZoneRequirement{
public final Zone zone; public @NonNull Zone zone;
public final int wave; public @NonNull int wave;
public ZoneRequirement(Zone zone, int wave){ public ZoneRequirement(Zone zone, int wave){
this.zone = zone; this.zone = zone;
this.wave = wave; this.wave = wave;
} }
protected ZoneRequirement(){
}
public static ZoneRequirement[] with(Object... objects){ public static ZoneRequirement[] with(Object... objects){
ZoneRequirement[] out = new ZoneRequirement[objects.length / 2]; ZoneRequirement[] out = new ZoneRequirement[objects.length / 2];
for(int i = 0; i < objects.length; i += 2){ for(int i = 0; i < objects.length; i += 2){

View File

@@ -3,6 +3,8 @@ package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.io.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.mod.Mods.*;
@@ -107,5 +109,27 @@ public class ModsDialog extends FloatingDialog{
} }
}); });
}).margin(12f).width(500f); }).margin(12f).width(500f);
//not well tested currently
if(Version.build == -1){
cont.row();
cont.addImageTextButton("$mod.import.github", Icon.github, () -> {
ui.showTextInput("$mod.import.github", "", "Anuken/ExampleMod", text -> {
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
Core.net.httpGet(loc.getHeader("Location"), result -> {
try{
Streams.copyStream(result.getResultAsStream(), modDirectory.child(text.replace("/", "") + ".zip").write(false));
ui.loadAnd(() -> {
mods.reloadContent();
});
}catch(Exception e){
ui.showException(e);
}
}, ui::showException);
}, ui::showException);
});
}).margin(12f).width(500f);
}
} }
} }