Made save format actually functional, many things still broken

This commit is contained in:
Anuken
2019-05-08 23:16:08 -04:00
parent 53167a3b52
commit 8127e5a66f
16 changed files with 146 additions and 60 deletions

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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. */

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

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

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

View File

@@ -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);
}

View File

@@ -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{

View File

@@ -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);
}

View File

@@ -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);
});
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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();