Made save format actually functional, many things still broken
This commit is contained in:
@@ -60,9 +60,10 @@ public class Logic implements ApplicationListener{
|
||||
state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts
|
||||
|
||||
//sometimes a map has no waves defined, they're defined in the zone rules
|
||||
if(world.getMap().getWaves() != DefaultWaves.get() || !world.isZone()){
|
||||
state.rules.spawns = world.getMap().getWaves();
|
||||
}
|
||||
//TODO ???? how does this even work now
|
||||
//if(world.getMap().getWaves() != DefaultWaves.get() || !world.isZone()){
|
||||
// state.rules.spawns = world.getMap().getWaves();
|
||||
//}
|
||||
|
||||
Events.fire(new PlayEvent());
|
||||
}
|
||||
|
||||
@@ -35,7 +35,9 @@ public class World implements ApplicationListener{
|
||||
private boolean generating, invalidMap;
|
||||
|
||||
public World(){
|
||||
//TODO swap
|
||||
Core.app.post(maps::load);
|
||||
//maps.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.anuke.mindustry.type.*;
|
||||
@Serialize
|
||||
public class Stats{
|
||||
/** Items delivered to global resoure counter. Zones only. */
|
||||
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
public transient ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
/** Enemy (red team) units destroyed. */
|
||||
public int enemyUnitsDestroyed;
|
||||
/** Total waves lasted. */
|
||||
|
||||
24
core/src/io/anuke/mindustry/io/JsonIO.java
Normal file
24
core/src/io/anuke/mindustry/io/JsonIO.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.util.serialization.Json;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
|
||||
public class JsonIO{
|
||||
private static Json json = new Json(){{
|
||||
setIgnoreUnknownFields(true);
|
||||
setElementType(Rules.class, "spawns", SpawnGroup.class);
|
||||
}};
|
||||
|
||||
public static String write(Object object){
|
||||
return json.toJson(object);
|
||||
}
|
||||
|
||||
public static <T> T read(Class<T> type, String string){
|
||||
return json.fromJson(type, string);
|
||||
}
|
||||
|
||||
public static String print(String in){
|
||||
return json.prettyPrint(in);
|
||||
}
|
||||
}
|
||||
7
core/src/io/anuke/mindustry/io/JsonTypeReader.java
Normal file
7
core/src/io/anuke/mindustry/io/JsonTypeReader.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.util.serialization.JsonValue;
|
||||
|
||||
public interface JsonTypeReader<T>{
|
||||
T read(JsonValue json, String name);
|
||||
}
|
||||
7
core/src/io/anuke/mindustry/io/JsonTypeWriter.java
Normal file
7
core/src/io/anuke/mindustry/io/JsonTypeWriter.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.util.serialization.Json;
|
||||
|
||||
public interface JsonTypeWriter<T>{
|
||||
void write(Json json, T object, String name);
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.Pixmap;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.serialization.Json;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.io.MapIO.TileProvider;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
@@ -25,16 +27,22 @@ import static io.anuke.mindustry.Vars.*;
|
||||
* Differentiate between legacy maps and new maps by checking the extension (or the header).*/
|
||||
public class LegacyMapIO{
|
||||
private static final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||
private static final Json json = new Json();
|
||||
|
||||
/* Convert a map from the old format to the new format. */
|
||||
public static void convertMap(FileHandle in, FileHandle out) throws IOException{
|
||||
Map map = readMap(in, true);
|
||||
|
||||
String waves = map.tags.get("waves", "[]");
|
||||
Array<SpawnGroup> groups = new Array<>(json.fromJson(SpawnGroup[].class, waves));
|
||||
|
||||
Tile[][] tiles = world.createTiles(map.width, map.height);
|
||||
for(int x = 0; x < map.width; x++){
|
||||
for(int y = 0; y < map.height; y++){
|
||||
tiles[x][y] = new Tile(x, y);
|
||||
tiles[x][y] = new CachedTile();
|
||||
}
|
||||
}
|
||||
state.rules.spawns = groups;
|
||||
readTiles(map, tiles);
|
||||
MapIO.writeMap(out, map);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import java.io.*;
|
||||
public abstract class SaveFileReader{
|
||||
protected final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
|
||||
protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
|
||||
protected final ReusableByteOutStream byteOutputSmall = new ReusableByteOutStream();
|
||||
protected final DataOutputStream dataBytesSmall = new DataOutputStream(byteOutputSmall);
|
||||
protected final ObjectMap<String, String> fallback = ObjectMap.of();
|
||||
|
||||
protected void region(String name, DataInput stream, CounterInputStream counter, IORunner<DataInput> cons) throws IOException{
|
||||
@@ -21,6 +23,7 @@ public abstract class SaveFileReader{
|
||||
}catch(Throwable e){
|
||||
throw new IOException("Error reading region \"" + name + "\".", e);
|
||||
}
|
||||
|
||||
if(length != counter.count() - 4){
|
||||
throw new IOException("Error reading region \"" + name + "\": read length mismatch. Expected: " + length + "; Actual: " + (counter.count() - 4));
|
||||
}
|
||||
@@ -40,11 +43,12 @@ public abstract class SaveFileReader{
|
||||
|
||||
/** Write a chunk of input to the stream. An integer of some length is written first, followed by the data. */
|
||||
public void writeChunk(DataOutput output, boolean isByte, IORunner<DataOutput> runner) throws IOException{
|
||||
ReusableByteOutStream dout = isByte ? byteOutputSmall : byteOutput;
|
||||
//reset output position
|
||||
byteOutput.reset();
|
||||
dout.reset();
|
||||
//write the needed info
|
||||
runner.accept(dataBytes);
|
||||
int length = byteOutput.size();
|
||||
runner.accept(isByte ? dataBytesSmall : dataBytes);
|
||||
int length = dout.size();
|
||||
//write length (either int or byte) followed by the output bytes
|
||||
if(!isByte){
|
||||
output.writeInt(length);
|
||||
@@ -54,7 +58,7 @@ public abstract class SaveFileReader{
|
||||
}
|
||||
output.writeShort(length);
|
||||
}
|
||||
output.write(byteOutput.getBytes(), 0, length);
|
||||
output.write(dout.getBytes(), 0, length);
|
||||
}
|
||||
|
||||
public int readChunk(DataInput input, IORunner<DataInput> runner) throws IOException{
|
||||
|
||||
@@ -90,6 +90,7 @@ public class SaveIO{
|
||||
public static SaveMeta getMeta(DataInputStream stream){
|
||||
|
||||
try{
|
||||
readHeader(stream);
|
||||
int version = stream.readInt();
|
||||
SaveMeta meta = versions.get(version).getMeta(stream);
|
||||
stream.close();
|
||||
@@ -116,10 +117,7 @@ public class SaveIO{
|
||||
}
|
||||
|
||||
public static void write(OutputStream os, StringMap tags){
|
||||
DataOutputStream stream;
|
||||
|
||||
try{
|
||||
stream = new DataOutputStream(os);
|
||||
try(DataOutputStream stream = new DataOutputStream(os)){
|
||||
stream.write(header);
|
||||
stream.writeInt(getVersion().version);
|
||||
if(tags == null){
|
||||
@@ -127,7 +125,6 @@ public class SaveIO{
|
||||
}else{
|
||||
getVersion().write(stream, tags);
|
||||
}
|
||||
stream.close();
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -27,7 +26,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
public SaveMeta getMeta(DataInput stream) throws IOException{
|
||||
stream.readInt(); //length of data, doesn't matter here
|
||||
StringMap map = readStringMap(stream);
|
||||
return new SaveMeta(map.getInt("version"), map.getLong("saved"), map.getLong("playtime"), map.getInt("build"), map.get("mapname"), map.getInt("wave"), Serialization.readRulesStringJson(map.get("rules", "{}")));
|
||||
return new SaveMeta(map.getInt("version"), map.getLong("saved"), map.getLong("playtime"), map.getInt("build"), map.get("mapname"), map.getInt("wave"), JsonIO.read(Rules.class, map.get("rules", "{}")));
|
||||
}
|
||||
|
||||
public final void write(DataOutputStream stream) throws IOException{
|
||||
@@ -56,8 +55,8 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
"mapname", world.getMap() == null ? "unknown" : world.getMap().name(),
|
||||
"wave", state.wave,
|
||||
"wavetime", state.wavetime,
|
||||
"stats", Serialization.writeStatsJson(state.stats),
|
||||
"rules", Serialization.writeRulesJson(state.rules),
|
||||
"stats", JsonIO.write(state.stats),
|
||||
"rules", JsonIO.write(state.rules),
|
||||
"width", world.width(),
|
||||
"height", world.height()
|
||||
).merge(tags));
|
||||
@@ -68,11 +67,12 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
|
||||
state.wave = map.getInt("wave");
|
||||
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
|
||||
state.stats = Serialization.readStatsStringJson(map.get("stats", "{}"));
|
||||
state.rules = Serialization.readRulesStringJson(map.get("rules", "{}"));
|
||||
state.stats = JsonIO.read(Stats.class, map.get("stats", "{}"));
|
||||
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
|
||||
}
|
||||
|
||||
public void writeMap(DataOutput stream) throws IOException{
|
||||
//TODO something here messes up everything
|
||||
//write world size
|
||||
stream.writeShort(world.width());
|
||||
stream.writeShort(world.height());
|
||||
@@ -106,7 +106,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
if(tile.entity != null){
|
||||
writeChunk(stream, true, out -> {
|
||||
out.writeByte(tile.entity.version());
|
||||
tile.entity.write(stream);
|
||||
tile.entity.write(out);
|
||||
});
|
||||
}else{
|
||||
//write consecutive non-entity blocks
|
||||
@@ -129,10 +129,12 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
}
|
||||
|
||||
public void readMap(DataInput stream) throws IOException{
|
||||
short width = stream.readShort();
|
||||
short height = stream.readShort();
|
||||
int width = stream.readUnsignedShort();
|
||||
int height = stream.readUnsignedShort();
|
||||
|
||||
world.beginMapLoad();
|
||||
boolean generating = world.isGenerating();
|
||||
|
||||
if(!generating) world.beginMapLoad();
|
||||
|
||||
Tile[][] tiles = world.createTiles(width, height);
|
||||
|
||||
@@ -163,7 +165,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
if(tile.entity != null){
|
||||
readChunk(stream, true, in -> {
|
||||
byte version = in.readByte();
|
||||
tile.entity.read(stream, version);
|
||||
tile.entity.read(in, version);
|
||||
});
|
||||
}else{
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
@@ -178,7 +180,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
}
|
||||
|
||||
content.setTemporaryMapper(null);
|
||||
world.endMapLoad();
|
||||
if(!generating) world.endMapLoad();
|
||||
}
|
||||
|
||||
public void writeEntities(DataOutput stream) throws IOException{
|
||||
@@ -200,8 +202,8 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
SaveTrait save = (SaveTrait)entity;
|
||||
//each entity is a separate chunk.
|
||||
writeChunk(stream, true, out -> {
|
||||
stream.writeByte(save.getTypeID());
|
||||
stream.writeByte(save.version());
|
||||
out.writeByte(save.getTypeID());
|
||||
out.writeByte(save.version());
|
||||
save.writeSave(out);
|
||||
});
|
||||
}
|
||||
@@ -217,10 +219,10 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
for(int j = 0; j < amount; j++){
|
||||
//TODO throw exception on read fail
|
||||
readChunk(stream, true, in -> {
|
||||
byte typeid = stream.readByte();
|
||||
byte version = stream.readByte();
|
||||
byte typeid = in.readByte();
|
||||
byte version = in.readByte();
|
||||
SaveTrait trait = (SaveTrait)TypeTrait.getTypeByID(typeid).get();
|
||||
trait.readSave(stream, version);
|
||||
trait.readSave(in, version);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package io.anuke.mindustry.maps;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.collection.StringMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.game.DefaultWaves;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Map implements Comparable<Map>{
|
||||
/** Whether this is a custom map. */
|
||||
@@ -49,20 +44,6 @@ public class Map implements Comparable<Map>{
|
||||
this(Vars.customMapDirectory.child(tags.get("name", "unknown")), 0, 0, tags, true);
|
||||
}
|
||||
|
||||
public Array<SpawnGroup> getWaves(){
|
||||
if(tags.containsKey("waves")){
|
||||
try{
|
||||
return world.maps.readWaves(tags.get("waves"));
|
||||
}catch(Exception e){
|
||||
Log.err("Malformed waves: {0}", tags.get("waves"));
|
||||
e.printStackTrace();
|
||||
return DefaultWaves.get();
|
||||
}
|
||||
}else{
|
||||
return DefaultWaves.get();
|
||||
}
|
||||
}
|
||||
|
||||
public int getHightScore(){
|
||||
return Core.settings.getInt("hiscore" + file.nameWithoutExtension(), 0);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import io.anuke.arc.util.Disposable;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.serialization.Json;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.io.LegacyMapIO;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.io.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
@@ -61,6 +60,7 @@ public class Maps implements Disposable{
|
||||
public void load(){
|
||||
try{
|
||||
//TODO remove, this is only for testing
|
||||
|
||||
for(FileHandle in : Core.files.absolute("/home/anuke/Projects/Mindustry/core/assets/maps").list()){
|
||||
if(in.extension().equalsIgnoreCase(oldMapExtension)){
|
||||
Log.info("Converting {0}...", in);
|
||||
|
||||
@@ -60,10 +60,9 @@ public class MapGenerator extends Generator{
|
||||
@Override
|
||||
public void init(Loadout loadout){
|
||||
this.loadout = loadout;
|
||||
//TODO uncomment once conversion works
|
||||
//map = world.maps.loadInternalMap(mapName);
|
||||
//width = map.width;
|
||||
//height = map.height;
|
||||
map = world.maps.loadInternalMap(mapName);
|
||||
width = map.width;
|
||||
height = map.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.anuke.mindustry.game.EventType.ZoneConfigureCompleteEvent;
|
||||
import io.anuke.mindustry.game.EventType.ZoneRequireCompleteEvent;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.maps.generators.Generator;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
@@ -38,6 +39,12 @@ public class Zone extends UnlockableContent{
|
||||
|
||||
private Array<ItemStack> defaultStartingItems = new Array<>();
|
||||
|
||||
static{
|
||||
Serialization.setSerializer(Zone.class,
|
||||
(json, zone, name) -> json.writeValue(name, zone.name),
|
||||
(json, name) -> content.getByName(ContentType.zone, json.getString(name)));
|
||||
}
|
||||
|
||||
public Zone(String name, Generator generator){
|
||||
super(name);
|
||||
this.generator = generator;
|
||||
|
||||
@@ -37,6 +37,7 @@ public class CachedTile extends Tile{
|
||||
if(!entities.containsKey(block.id)){
|
||||
TileEntity n = block.newEntity();
|
||||
n.cons = new ConsumeModule(entity);
|
||||
n.tile = this;
|
||||
if(block.hasItems) n.items = new ItemModule();
|
||||
if(block.hasLiquids) n.liquids = new LiquidModule();
|
||||
if(block.hasPower) n.power = new PowerModule();
|
||||
|
||||
Reference in New Issue
Block a user