Modding improvements
This commit is contained in:
@@ -13,6 +13,7 @@ import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
@@ -24,6 +25,10 @@ public class ContentParser{
|
||||
put(BulletType.class, (type, data) -> field(Bullets.class, data));
|
||||
put(Effect.class, (type, data) -> field(Fx.class, data));
|
||||
}};
|
||||
/** Stores things that need to be parsed fully, e.g. reading fields of content.
|
||||
* This is done to accomodate binding of content names first.*/
|
||||
private Array<Runnable> reads = new Array<>();
|
||||
private LoadedMod currentMod;
|
||||
|
||||
private Json parser = new Json(){
|
||||
public <T> T readValue(Class<T> type, Class elementType, JsonValue jsonData){
|
||||
@@ -33,7 +38,11 @@ public class ContentParser{
|
||||
}
|
||||
|
||||
if(Content.class.isAssignableFrom(type)){
|
||||
return (T)Vars.content.getByName(contentTypes.getThrow(type, () -> new IllegalArgumentException("No content type for class: " + type.getSimpleName())), jsonData.asString());
|
||||
ContentType ctype = contentTypes.getThrow(type, () -> new IllegalArgumentException("No content type for class: " + type.getSimpleName()));
|
||||
String prefix = currentMod != null ? currentMod.name + "-" : "";
|
||||
T one = (T)Vars.content.getByName(ctype, prefix + jsonData.asString());
|
||||
if(one != null) return one;
|
||||
return (T)Vars.content.getByName(ctype, jsonData.asString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,21 +52,37 @@ public class ContentParser{
|
||||
|
||||
private ObjectMap<ContentType, TypeParser<?>> parsers = ObjectMap.of(
|
||||
ContentType.block, (TypeParser<Block>)(mod, name, value) -> {
|
||||
Class<Block> type = resolve(value.getString("type"), "io.anuke.mindustry.world", "io.anuke.mindustry.world.blocks", "io.anuke.mindustry.world.blocks.defense");
|
||||
Block block = type.getDeclaredConstructor(String.class).newInstance(mod + "-" + name);
|
||||
readFields(block, value, true);
|
||||
//TODO generate dynamically instead of doing.. this
|
||||
Class<? extends Block> type = resolve(value.getString("type"),
|
||||
"io.anuke.mindustry.world",
|
||||
"io.anuke.mindustry.world.blocks",
|
||||
"io.anuke.mindustry.world.blocks.defense",
|
||||
"io.anuke.mindustry.world.blocks.defense.turrets",
|
||||
"io.anuke.mindustry.world.blocks.distribution",
|
||||
"io.anuke.mindustry.world.blocks.logic",
|
||||
"io.anuke.mindustry.world.blocks.power",
|
||||
"io.anuke.mindustry.world.blocks.production",
|
||||
"io.anuke.mindustry.world.blocks.sandbox",
|
||||
"io.anuke.mindustry.world.blocks.storage",
|
||||
"io.anuke.mindustry.world.blocks.units"
|
||||
);
|
||||
|
||||
//make block visible
|
||||
if(block.buildRequirements != null){
|
||||
block.buildVisibility = () -> true;
|
||||
}
|
||||
Block block = type.getDeclaredConstructor(String.class).newInstance(mod + "-" + name);
|
||||
read(() -> {
|
||||
readFields(block, value, true);
|
||||
|
||||
//make block visible
|
||||
if(block.requirements != null){
|
||||
block.buildVisibility = () -> true;
|
||||
}
|
||||
});
|
||||
|
||||
return block;
|
||||
},
|
||||
ContentType.unit, (TypeParser<UnitType>)(mod, name, value) -> {
|
||||
Class<BaseUnit> type = resolve(value.getString("type"), "io.anuke.mindustry.entities.type.base");
|
||||
UnitType unit = new UnitType(mod + "-" + name, supply(type));
|
||||
readFields(unit, value, true);
|
||||
read(() -> readFields(unit, value, true));
|
||||
|
||||
return unit;
|
||||
},
|
||||
@@ -75,11 +100,19 @@ public class ContentParser{
|
||||
}else{
|
||||
item = constructor.get(mod + "-" + name);
|
||||
}
|
||||
readFields(item, value);
|
||||
read(() -> readFields(item, value));
|
||||
return item;
|
||||
};
|
||||
}
|
||||
|
||||
private void read(Runnable run){
|
||||
LoadedMod mod = currentMod;
|
||||
reads.add(() -> {
|
||||
this.currentMod = mod;
|
||||
run.run();
|
||||
});
|
||||
}
|
||||
|
||||
private void init(){
|
||||
for(ContentType type : ContentType.all){
|
||||
Array<Content> arr = Vars.content.getBy(type);
|
||||
@@ -95,6 +128,11 @@ public class ContentParser{
|
||||
}
|
||||
}
|
||||
|
||||
public void finishParsing(){
|
||||
reads.each(Runnable::run);
|
||||
reads.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses content from a json file.
|
||||
* @param name the name of the file without its extension
|
||||
@@ -102,7 +140,7 @@ public class ContentParser{
|
||||
* @param type the type of content this is
|
||||
* @return the content that was parsed
|
||||
*/
|
||||
public Content parse(String mod, String name, String json, ContentType type) throws Exception{
|
||||
public Content parse(LoadedMod mod, String name, String json, ContentType type) throws Exception{
|
||||
if(contentTypes.isEmpty()){
|
||||
init();
|
||||
}
|
||||
@@ -112,7 +150,9 @@ public class ContentParser{
|
||||
throw new SerializationException("No parsers for content type '" + type + "'");
|
||||
}
|
||||
|
||||
Content c = parsers.get(type).parse(mod, name, value);
|
||||
currentMod = mod;
|
||||
Content c = parsers.get(type).parse(mod.name, name, value);
|
||||
c.mod = mod;
|
||||
checkNulls(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,7 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
/** @return the loaded mod found by class, or null if not found. */
|
||||
public @Nullable
|
||||
LoadedMod getMod(Class<? extends Mod> type){
|
||||
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
||||
return loaded.find(l -> l.mod.getClass() == type);
|
||||
}
|
||||
|
||||
@@ -76,26 +75,29 @@ public class Mods implements Loadable{
|
||||
|
||||
packer = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true);
|
||||
for(LoadedMod mod : loaded){
|
||||
try{
|
||||
int packed = 0;
|
||||
for(FileHandle file : mod.root.child("sprites").list()){
|
||||
if(file.extension().equals("png")){
|
||||
try(InputStream stream = file.read()){
|
||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||
packer.pack(mod.name + "-" + file.nameWithoutExtension(), pixmap);
|
||||
pixmap.dispose();
|
||||
packed ++;
|
||||
totalSprites ++;
|
||||
}
|
||||
int[] packed = {0};
|
||||
boolean[] failed = {false};
|
||||
mod.root.child("sprites").walk(file -> {
|
||||
if(failed[0]) return;
|
||||
if(file.extension().equals("png")){
|
||||
try(InputStream stream = file.read()){
|
||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||
packer.pack(mod.name + "-" + file.nameWithoutExtension(), pixmap);
|
||||
pixmap.dispose();
|
||||
packed[0] ++;
|
||||
totalSprites ++;
|
||||
}catch(IOException e){
|
||||
failed[0] = true;
|
||||
Core.app.post(() -> {
|
||||
Log.err("Error packing images for mod: {0}", mod.meta.name);
|
||||
e.printStackTrace();
|
||||
if(!headless) ui.showException(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
Log.info("Packed {0} images for mod '{1}'.", packed, mod.meta.name);
|
||||
}catch(IOException e){
|
||||
Log.err("Error packing images for mod: {0}", mod.meta.name);
|
||||
e.printStackTrace();
|
||||
if(!headless) ui.showException(e);
|
||||
}
|
||||
});
|
||||
Log.info("Packed {0} images for mod '{1}'.", packed[0], mod.meta.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +199,7 @@ public class Mods implements Loadable{
|
||||
for(FileHandle file : folder.list()){
|
||||
if(file.extension().equals("json")){
|
||||
try{
|
||||
Content loaded = parser.parse(mod.name, file.nameWithoutExtension(), file.readString(), type);
|
||||
Content loaded = parser.parse(mod, file.nameWithoutExtension(), file.readString(), type);
|
||||
Log.info("[{0}] Loaded '{1}'.", mod.meta.name, loaded);
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException("Failed to parse content file '" + file + "' for mod '" + mod.meta.name + "'.", e);
|
||||
@@ -209,6 +211,8 @@ public class Mods implements Loadable{
|
||||
}
|
||||
}
|
||||
|
||||
parser.finishParsing();
|
||||
|
||||
each(Mod::loadContent);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user