many things
This commit is contained in:
@@ -143,9 +143,8 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
.addStatement("bjson.writeObjectEnd()")
|
.addStatement("bjson.writeObjectEnd()")
|
||||||
.addStatement("stream.writeUTF(output.toString())");
|
.addStatement("stream.writeUTF(output.toString())");
|
||||||
|
|
||||||
MethodSpec.Builder binaryJsonWriteStringMethod = MethodSpec.methodBuilder("write" + simpleTypeName + "StringJson")
|
MethodSpec.Builder binaryJsonWriteStringMethod = MethodSpec.methodBuilder("write" + simpleTypeName + "Json")
|
||||||
.returns(String.class)
|
.returns(String.class)
|
||||||
.addParameter(DataOutput.class, "stream")
|
|
||||||
.addParameter(type, "object")
|
.addParameter(type, "object")
|
||||||
.addException(IOException.class)
|
.addException(IOException.class)
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||||
@@ -163,9 +162,17 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||||
.addStatement("return read" + simpleTypeName + "Json(bjson.fromJson(null, stream.readUTF()))");
|
.addStatement("return read" + simpleTypeName + "Json(bjson.fromJson(null, stream.readUTF()))");
|
||||||
|
|
||||||
|
MethodSpec.Builder binaryJsonReadStringMethod = MethodSpec.methodBuilder("read" + simpleTypeName + "StringJson")
|
||||||
|
.returns(type)
|
||||||
|
.addParameter(String.class, "str")
|
||||||
|
.addException(IOException.class)
|
||||||
|
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||||
|
.addStatement("return read" + simpleTypeName + "Json(bjson.fromJson(null, str))");
|
||||||
|
|
||||||
classBuilder.addMethod(binaryJsonWriteMethod.build());
|
classBuilder.addMethod(binaryJsonWriteMethod.build());
|
||||||
classBuilder.addMethod(binaryJsonWriteStringMethod.build());
|
classBuilder.addMethod(binaryJsonWriteStringMethod.build());
|
||||||
classBuilder.addMethod(binaryJsonReadMethod.build());
|
classBuilder.addMethod(binaryJsonReadMethod.build());
|
||||||
|
classBuilder.addMethod(binaryJsonReadStringMethod.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
classBuilder.addMethod(method.build());
|
classBuilder.addMethod(method.build());
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//called on all clients
|
//called on all clients
|
||||||
@Remote(called = Loc.server, targets = Loc.server)
|
@Remote(called = Loc.server, targets = Loc.server, variants = Variant.both)
|
||||||
public static void sendMessage(String message, String sender, Player playersender){
|
public static void sendMessage(String message, String sender, Player playersender){
|
||||||
if(Vars.ui != null){
|
if(Vars.ui != null){
|
||||||
Vars.ui.chatfrag.addMessage(message, sender);
|
Vars.ui.chatfrag.addMessage(message, sender);
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ public class World implements ApplicationListener{
|
|||||||
return state.rules.zone;
|
return state.rules.zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO move to Control
|
||||||
public void playZone(Zone zone){
|
public void playZone(Zone zone){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
logic.reset();
|
logic.reset();
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float lifetime(){
|
public float lifetime(){
|
||||||
return lifetime;
|
return lifetime;
|
||||||
@@ -151,7 +156,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
this.loadedPosition = stream.readInt();
|
this.loadedPosition = stream.readInt();
|
||||||
this.lifetime = stream.readFloat();
|
this.lifetime = stream.readFloat();
|
||||||
this.time = stream.readFloat();
|
this.time = stream.readFloat();
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
|||||||
return liquid.flammability * amount;
|
return liquid.flammability * amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hitbox(Rectangle rectangle){
|
public void hitbox(Rectangle rectangle){
|
||||||
rectangle.setCenter(x, y).setSize(tilesize);
|
rectangle.setCenter(x, y).setSize(tilesize);
|
||||||
@@ -245,7 +250,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
this.loadedPosition = stream.readInt();
|
this.loadedPosition = stream.readInt();
|
||||||
this.x = stream.readFloat();
|
this.x = stream.readFloat();
|
||||||
this.y = stream.readFloat();
|
this.y = stream.readFloat();
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ package io.anuke.mindustry.entities.traits;
|
|||||||
* Marks an entity as serializable.
|
* Marks an entity as serializable.
|
||||||
*/
|
*/
|
||||||
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
||||||
|
byte version();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ import java.io.*;
|
|||||||
|
|
||||||
public interface Saveable{
|
public interface Saveable{
|
||||||
void writeSave(DataOutput stream) throws IOException;
|
void writeSave(DataOutput stream) throws IOException;
|
||||||
|
void readSave(DataInput stream, byte version) throws IOException;
|
||||||
void readSave(DataInput stream) throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,15 +41,6 @@ public interface SyncTrait extends Entity, TypeTrait{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this entity is clipped and not synced when out of viewport. */
|
|
||||||
default boolean isClipped(){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default float clipSize(){
|
|
||||||
return (this instanceof DrawTrait ? ((DrawTrait)this).drawSize() : 8f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Read and write sync data, usually position
|
//Read and write sync data, usually position
|
||||||
void write(DataOutput data) throws IOException;
|
void write(DataOutput data) throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ public interface TypeTrait{
|
|||||||
lastRegisteredID[0]++;
|
lastRegisteredID[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**Gets a syncable type by ID.*/
|
||||||
* Registers a syncable type by ID.
|
|
||||||
*/
|
|
||||||
static Supplier<? extends TypeTrait> getTypeByID(int id){
|
static Supplier<? extends TypeTrait> getTypeByID(int id){
|
||||||
if(id == -1){
|
if(id == -1){
|
||||||
throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?");
|
throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?");
|
||||||
|
|||||||
@@ -304,11 +304,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
return type.hitsize * 10;
|
return type.hitsize * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public float clipSize(){
|
|
||||||
return isBoss() ? 10000000000f : super.clipSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(){
|
public void onDeath(){
|
||||||
Call.onUnitDeath(this);
|
Call.onUnitDeath(this);
|
||||||
@@ -336,6 +331,11 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
return unitGroups[team.ordinal()];
|
return unitGroups[team.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSave(DataOutput stream) throws IOException{
|
public void writeSave(DataOutput stream) throws IOException{
|
||||||
super.writeSave(stream);
|
super.writeSave(stream);
|
||||||
@@ -344,8 +344,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
super.readSave(stream);
|
super.readSave(stream, version);
|
||||||
byte type = stream.readByte();
|
byte type = stream.readByte();
|
||||||
this.spawner = stream.readInt();
|
this.spawner = stream.readInt();
|
||||||
|
|
||||||
@@ -363,7 +363,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void read(DataInput data) throws IOException{
|
public void read(DataInput data) throws IOException{
|
||||||
float lastx = x, lasty = y, lastrot = rotation;
|
float lastx = x, lasty = y, lastrot = rotation;
|
||||||
super.readSave(data);
|
|
||||||
|
super.readSave(data, version());
|
||||||
|
|
||||||
this.type = content.getByID(ContentType.unit, data.readByte());
|
this.type = content.getByID(ContentType.unit, data.readByte());
|
||||||
this.spawner = data.readInt();
|
this.spawner = data.readInt();
|
||||||
|
|
||||||
|
|||||||
@@ -817,8 +817,8 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
//region read and write methods
|
//region read and write methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isClipped(){
|
public byte version(){
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -833,7 +833,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
boolean local = stream.readBoolean();
|
boolean local = stream.readBoolean();
|
||||||
|
|
||||||
if(local){
|
if(local){
|
||||||
@@ -844,14 +844,14 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
lastSpawner = (SpawnerTrait)stile.entity;
|
lastSpawner = (SpawnerTrait)stile.entity;
|
||||||
}
|
}
|
||||||
Player player = headless ? this : Vars.player;
|
Player player = headless ? this : Vars.player;
|
||||||
player.readSaveSuper(stream);
|
player.readSaveSuper(stream, version);
|
||||||
player.mech = content.getByID(ContentType.mech, mechid);
|
player.mech = content.getByID(ContentType.mech, mechid);
|
||||||
player.dead = false;
|
player.dead = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readSaveSuper(DataInput stream) throws IOException{
|
private void readSaveSuper(DataInput stream, byte version) throws IOException{
|
||||||
super.readSave(stream);
|
super.readSave(stream, version);
|
||||||
|
|
||||||
add();
|
add();
|
||||||
}
|
}
|
||||||
@@ -873,7 +873,9 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void read(DataInput buffer) throws IOException{
|
public void read(DataInput buffer) throws IOException{
|
||||||
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
||||||
super.readSave(buffer);
|
|
||||||
|
super.readSave(buffer, version());
|
||||||
|
|
||||||
name = TypeIO.readStringData(buffer);
|
name = TypeIO.readStringData(buffer);
|
||||||
byte bools = buffer.readByte();
|
byte bools = buffer.readByte();
|
||||||
isAdmin = (bools & 1) != 0;
|
isAdmin = (bools & 1) != 0;
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
health = stream.readUnsignedShort();
|
health = stream.readUnsignedShort();
|
||||||
byte tr = stream.readByte();
|
byte tr = stream.readByte();
|
||||||
byte team = Pack.leftByte(tr);
|
byte team = Pack.leftByte(tr);
|
||||||
@@ -139,6 +139,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
if(cons != null) cons.read(stream);
|
if(cons != null) cons.read(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the version of this TileEntity IO code.*/
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean collide(Bullet other){
|
public boolean collide(Bullet other){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
byte team = stream.readByte();
|
byte team = stream.readByte();
|
||||||
boolean dead = stream.readBoolean();
|
boolean dead = stream.readBoolean();
|
||||||
float x = stream.readFloat();
|
float x = stream.readFloat();
|
||||||
@@ -150,7 +150,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
byte itemID = stream.readByte();
|
byte itemID = stream.readByte();
|
||||||
short itemAmount = stream.readShort();
|
short itemAmount = stream.readShort();
|
||||||
|
|
||||||
this.status.readSave(stream);
|
this.status.readSave(stream, version);
|
||||||
this.item.amount = itemAmount;
|
this.item.amount = itemAmount;
|
||||||
this.item.item = content.item(itemID);
|
this.item.item = content.item(itemID);
|
||||||
this.dead = dead;
|
this.dead = dead;
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ public class Statuses implements Saveable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
for(StatusEntry effect : statuses){
|
for(StatusEntry effect : statuses){
|
||||||
Pools.free(effect);
|
Pools.free(effect);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class Saves{
|
|||||||
SaveSlot slot = new SaveSlot(index);
|
SaveSlot slot = new SaveSlot(index);
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
saveMap.put(slot.index, slot);
|
||||||
slot.meta = SaveIO.getData(index);
|
slot.meta = SaveIO.getMeta(index);
|
||||||
nextSlot = Math.max(index + 1, nextSlot);
|
nextSlot = Math.max(index + 1, nextSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ public class Saves{
|
|||||||
slot.setName(file.nameWithoutExtension());
|
slot.setName(file.nameWithoutExtension());
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
saveMap.put(slot.index, slot);
|
||||||
slot.meta = SaveIO.getData(slot.index);
|
slot.meta = SaveIO.getMeta(slot.index);
|
||||||
current = slot;
|
current = slot;
|
||||||
saveSlots();
|
saveSlots();
|
||||||
return slot;
|
return slot;
|
||||||
@@ -172,7 +172,7 @@ public class Saves{
|
|||||||
public void load() throws SaveException{
|
public void load() throws SaveException{
|
||||||
try{
|
try{
|
||||||
SaveIO.loadFromSlot(index);
|
SaveIO.loadFromSlot(index);
|
||||||
meta = SaveIO.getData(index);
|
meta = SaveIO.getMeta(index);
|
||||||
current = this;
|
current = this;
|
||||||
totalPlaytime = meta.timePlayed;
|
totalPlaytime = meta.timePlayed;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -186,7 +186,7 @@ public class Saves{
|
|||||||
totalPlaytime = time;
|
totalPlaytime = time;
|
||||||
|
|
||||||
SaveIO.saveToSlot(index);
|
SaveIO.saveToSlot(index);
|
||||||
meta = SaveIO.getData(index);
|
meta = SaveIO.getMeta(index);
|
||||||
if(!state.is(State.menu)){
|
if(!state.is(State.menu)){
|
||||||
current = this;
|
current = this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package io.anuke.mindustry.io;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
|
import io.anuke.arc.files.FileHandle;
|
||||||
|
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.mindustry.content.Blocks;
|
||||||
|
import io.anuke.mindustry.game.Team;
|
||||||
|
import io.anuke.mindustry.io.MapIO.TileProvider;
|
||||||
|
import io.anuke.mindustry.maps.Map;
|
||||||
|
import io.anuke.mindustry.world.*;
|
||||||
|
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
|
||||||
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.bufferSize;
|
||||||
|
import static io.anuke.mindustry.Vars.content;
|
||||||
|
|
||||||
|
/** Map IO for the "old" .mmap format.
|
||||||
|
* Differentiate between legacy maps and new maps by checking the extension (or the header).*/
|
||||||
|
public class LegacyMapIO{
|
||||||
|
|
||||||
|
public static Map readMap(FileHandle file, boolean custom) throws IOException{
|
||||||
|
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
||||||
|
ObjectMap<String, String> tags = new ObjectMap<>();
|
||||||
|
|
||||||
|
//meta is uncompressed
|
||||||
|
int version = stream.readInt();
|
||||||
|
int build = stream.readInt();
|
||||||
|
short width = stream.readShort(), height = stream.readShort();
|
||||||
|
byte tagAmount = stream.readByte();
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
String name = stream.readUTF();
|
||||||
|
String value = stream.readUTF();
|
||||||
|
tags.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Map(file, width, height, tags, custom, version, build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readTiles(Map map, Tile[][] tiles) throws IOException{
|
||||||
|
readTiles(map, (x, y) -> tiles[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readTiles(Map map, TileProvider tiles) throws IOException{
|
||||||
|
readTiles(map.file, map.width, map.height, tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
|
||||||
|
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
|
||||||
|
try(BufferedInputStream input = file.read(bufferSize)){
|
||||||
|
|
||||||
|
//read map
|
||||||
|
{
|
||||||
|
DataInputStream stream = new DataInputStream(input);
|
||||||
|
|
||||||
|
stream.readInt(); //version
|
||||||
|
stream.readInt(); //build
|
||||||
|
stream.readInt(); //width + height
|
||||||
|
byte tagAmount = stream.readByte();
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
stream.readUTF(); //key
|
||||||
|
stream.readUTF(); //val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
|
||||||
|
|
||||||
|
try{
|
||||||
|
SaveIO.getSaveWriter().readContentHeader(stream);
|
||||||
|
|
||||||
|
//read floor and create tiles first
|
||||||
|
for(int i = 0; i < width * height; i++){
|
||||||
|
int x = i % width, y = i / width;
|
||||||
|
byte floorid = stream.readByte();
|
||||||
|
byte oreid = stream.readByte();
|
||||||
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
|
Tile tile = tiles.get(x, y);
|
||||||
|
tile.setFloor((Floor)content.block(floorid));
|
||||||
|
tile.setOverlay(content.block(oreid));
|
||||||
|
|
||||||
|
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||||
|
int newx = j % width, newy = j / width;
|
||||||
|
Tile newTile = tiles.get(newx, newy);
|
||||||
|
newTile.setFloor((Floor)content.block(floorid));
|
||||||
|
newTile.setOverlay(content.block(oreid));
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consecutives;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read blocks
|
||||||
|
for(int i = 0; i < width * height; i++){
|
||||||
|
int x = i % width, y = i / width;
|
||||||
|
Block block = content.block(stream.readByte());
|
||||||
|
|
||||||
|
Tile tile = tiles.get(x, y);
|
||||||
|
tile.setBlock(block);
|
||||||
|
|
||||||
|
if(tile.entity != null){
|
||||||
|
byte tr = stream.readByte();
|
||||||
|
stream.readShort(); //read health (which is actually irrelevant)
|
||||||
|
|
||||||
|
byte team = Pack.leftByte(tr);
|
||||||
|
byte rotation = Pack.rightByte(tr);
|
||||||
|
|
||||||
|
tile.setTeam(Team.all[team]);
|
||||||
|
tile.entity.health = tile.block().health;
|
||||||
|
tile.rotation(rotation);
|
||||||
|
|
||||||
|
if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){
|
||||||
|
stream.readByte(); //these blocks have an extra config byte, read it
|
||||||
|
}
|
||||||
|
}else{ //no entity/part, read consecutives
|
||||||
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
|
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||||
|
int newx = j % width, newy = j / width;
|
||||||
|
tiles.get(newx, newy).setBlock(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consecutives;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}finally{
|
||||||
|
content.setTemporaryMapper(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reads a pixmap in the 3.5 pixmap format. */
|
||||||
|
public static void readLegacyPixmap(Pixmap pixmap, Tile[][] tiles){
|
||||||
|
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||||
|
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||||
|
int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y);
|
||||||
|
LegacyBlock block = LegacyColorMapper.get(color);
|
||||||
|
Tile tile = tiles[x][y];
|
||||||
|
|
||||||
|
tile.setFloor(block.floor);
|
||||||
|
tile.setBlock(block.wall);
|
||||||
|
if(block.ore != null) tile.setOverlay(block.ore);
|
||||||
|
|
||||||
|
//place core
|
||||||
|
if(color == Color.rgba8888(Color.GREEN)){
|
||||||
|
for(int dx = 0; dx < 3; dx++){
|
||||||
|
for(int dy = 0; dy < 3; dy++){
|
||||||
|
int worldx = dx - 1 + x;
|
||||||
|
int worldy = dy - 1 + y;
|
||||||
|
|
||||||
|
//multiblock parts
|
||||||
|
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
|
||||||
|
Tile write = tiles[worldx][worldy];
|
||||||
|
write.setBlock(BlockPart.get(dx - 1, dy - 1));
|
||||||
|
write.setTeam(Team.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//actual core parts
|
||||||
|
tile.setBlock(Blocks.coreShard);
|
||||||
|
tile.setTeam(Team.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,21 @@
|
|||||||
package io.anuke.mindustry.io;
|
package io.anuke.mindustry.io;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
import io.anuke.arc.collection.ObjectMap.Entry;
|
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.arc.graphics.Pixmap;
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
import io.anuke.arc.graphics.Pixmap.Format;
|
import io.anuke.arc.graphics.Pixmap.Format;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.Time;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
|
|
||||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.IOException;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
import java.io.InputStream;
|
||||||
import java.util.zip.InflaterInputStream;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.bufferSize;
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
|
||||||
|
|
||||||
/** Reads and writes map files. */
|
/** Reads and writes map files. */
|
||||||
public class MapIO{
|
public class MapIO{
|
||||||
public static final int version = 1;
|
|
||||||
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
|
|
||||||
public static boolean isImage(FileHandle file){
|
public static boolean isImage(FileHandle file){
|
||||||
@@ -53,9 +44,9 @@ public class MapIO{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOverlayID(byte b){
|
public void setOverlay(Block type){
|
||||||
if(b != 0)
|
if(type != Blocks.air)
|
||||||
floors.drawPixel(x, floors.getHeight() - 1 - y, colorFor(floor(), Blocks.air, content.block(b), getTeam()));
|
floors.drawPixel(x, floors.getHeight() - 1 - y, colorFor(floor(), Blocks.air, type, getTeam()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,13 +59,10 @@ public class MapIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
readTiles(map, (x, y) -> {
|
|
||||||
tile.x = (short)x;
|
|
||||||
tile.y = (short)y;
|
|
||||||
return tile;
|
|
||||||
});
|
|
||||||
floors.drawPixmap(walls, 0, 0);
|
floors.drawPixmap(walls, 0, 0);
|
||||||
walls.dispose();
|
walls.dispose();
|
||||||
|
//TODO actually generate the preview
|
||||||
return floors;
|
return floors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,255 +84,6 @@ public class MapIO{
|
|||||||
return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color);
|
return Color.rgba8888(wall.solid ? wall.color : ore == Blocks.air ? floor.color : ore.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeMap(FileHandle file, Map map, Tile[][] tiles) throws IOException{
|
|
||||||
OutputStream output = file.write(false, bufferSize);
|
|
||||||
|
|
||||||
{
|
|
||||||
DataOutputStream stream = new DataOutputStream(output);
|
|
||||||
stream.writeInt(version);
|
|
||||||
stream.writeInt(Version.build);
|
|
||||||
stream.writeShort(tiles.length);
|
|
||||||
stream.writeShort(tiles[0].length);
|
|
||||||
stream.writeByte((byte)map.tags.size);
|
|
||||||
|
|
||||||
for(Entry<String, String> entry : map.tags.entries()){
|
|
||||||
stream.writeUTF(entry.key);
|
|
||||||
stream.writeUTF(entry.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try(DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(output))){
|
|
||||||
int width = map.width, height = map.height;
|
|
||||||
|
|
||||||
SaveIO.getSaveWriter().writeContentHeader(stream);
|
|
||||||
|
|
||||||
//floor first
|
|
||||||
for(int i = 0; i < tiles.length * tiles[0].length; i++){
|
|
||||||
Tile tile = tiles[i % width][i / width];
|
|
||||||
stream.writeByte(tile.getFloorID());
|
|
||||||
stream.writeByte(tile.overlayID());
|
|
||||||
int consecutives = 0;
|
|
||||||
|
|
||||||
for(int j = i + 1; j < width * height && consecutives < 255; j++){
|
|
||||||
Tile nextTile = tiles[j % width][j / width];
|
|
||||||
|
|
||||||
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.overlayID() != tile.overlayID()){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
consecutives++;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.writeByte(consecutives);
|
|
||||||
i += consecutives;
|
|
||||||
}
|
|
||||||
|
|
||||||
//then blocks
|
|
||||||
for(int i = 0; i < tiles.length * tiles[0].length; i++){
|
|
||||||
Tile tile = tiles[i % width][i / width];
|
|
||||||
stream.writeByte(tile.getBlockID());
|
|
||||||
|
|
||||||
if(tile.block() instanceof BlockPart){
|
|
||||||
stream.writeByte(tile.getLinkByte());
|
|
||||||
}else if(tile.entity != null){
|
|
||||||
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation
|
|
||||||
stream.writeShort(/*(short)tile.entity.health*/tile.block().health); //health
|
|
||||||
if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){
|
|
||||||
stream.writeByte(-1); //write an meaningless byte here, just a fallback thing
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
//write consecutive non-entity blocks
|
|
||||||
int consecutives = 0;
|
|
||||||
|
|
||||||
for(int j = i + 1; j < width * height && consecutives < 255; j++){
|
|
||||||
Tile nextTile = tiles[j % width][j / width];
|
|
||||||
|
|
||||||
if(nextTile.block() != tile.block()){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
consecutives++;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.writeByte(consecutives);
|
|
||||||
i += consecutives;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map readMap(FileHandle file, boolean custom) throws IOException{
|
|
||||||
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
|
||||||
ObjectMap<String, String> tags = new ObjectMap<>();
|
|
||||||
|
|
||||||
//meta is uncompressed
|
|
||||||
int version = stream.readInt();
|
|
||||||
if(version == 0){
|
|
||||||
return readLegacyMap(file, custom);
|
|
||||||
}
|
|
||||||
int build = stream.readInt();
|
|
||||||
short width = stream.readShort(), height = stream.readShort();
|
|
||||||
byte tagAmount = stream.readByte();
|
|
||||||
|
|
||||||
for(int i = 0; i < tagAmount; i++){
|
|
||||||
String name = stream.readUTF();
|
|
||||||
String value = stream.readUTF();
|
|
||||||
tags.put(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Map(file, width, height, tags, custom, version, build);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads tiles from a map, version-agnostic. */
|
|
||||||
public static void readTiles(Map map, Tile[][] tiles) throws IOException{
|
|
||||||
readTiles(map, (x, y) -> tiles[x][y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads tiles from a map, version-agnostic. */
|
|
||||||
public static void readTiles(Map map, TileProvider tiles) throws IOException{
|
|
||||||
if(map.version == 0){
|
|
||||||
readLegacyMmapTiles(map.file, tiles);
|
|
||||||
}else if(map.version == version){
|
|
||||||
readTiles(map.file, map.width, map.height, tiles);
|
|
||||||
}else{
|
|
||||||
throw new IOException("Unknown map version. What?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads tiles from a map in the new build-65 format. */
|
|
||||||
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
|
|
||||||
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reads tiles from a map in the new build-65 format. */
|
|
||||||
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
|
|
||||||
try(BufferedInputStream input = file.read(bufferSize)){
|
|
||||||
|
|
||||||
//read map
|
|
||||||
{
|
|
||||||
DataInputStream stream = new DataInputStream(input);
|
|
||||||
|
|
||||||
stream.readInt(); //version
|
|
||||||
stream.readInt(); //build
|
|
||||||
stream.readInt(); //width + height
|
|
||||||
byte tagAmount = stream.readByte();
|
|
||||||
|
|
||||||
for(int i = 0; i < tagAmount; i++){
|
|
||||||
stream.readUTF(); //key
|
|
||||||
stream.readUTF(); //val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
|
|
||||||
|
|
||||||
MappableContent[][] c = SaveIO.getSaveWriter().readContentHeader(stream);
|
|
||||||
|
|
||||||
try{
|
|
||||||
content.setTemporaryMapper(c);
|
|
||||||
|
|
||||||
//read floor and create tiles first
|
|
||||||
for(int i = 0; i < width * height; i++){
|
|
||||||
int x = i % width, y = i / width;
|
|
||||||
byte floorid = stream.readByte();
|
|
||||||
byte oreid = stream.readByte();
|
|
||||||
int consecutives = stream.readUnsignedByte();
|
|
||||||
|
|
||||||
Tile tile = tiles.get(x, y);
|
|
||||||
tile.setFloor((Floor)content.block(floorid));
|
|
||||||
tile.setOverlay(content.block(oreid));
|
|
||||||
|
|
||||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
|
||||||
int newx = j % width, newy = j / width;
|
|
||||||
Tile newTile = tiles.get(newx, newy);
|
|
||||||
newTile.setFloor((Floor)content.block(floorid));
|
|
||||||
newTile.setOverlay(content.block(oreid));
|
|
||||||
}
|
|
||||||
|
|
||||||
i += consecutives;
|
|
||||||
}
|
|
||||||
|
|
||||||
//read blocks
|
|
||||||
for(int i = 0; i < width * height; i++){
|
|
||||||
int x = i % width, y = i / width;
|
|
||||||
Block block = content.block(stream.readByte());
|
|
||||||
|
|
||||||
Tile tile = tiles.get(x, y);
|
|
||||||
tile.setBlock(block);
|
|
||||||
|
|
||||||
if(tile.entity != null){
|
|
||||||
byte tr = stream.readByte();
|
|
||||||
short health = stream.readShort();
|
|
||||||
|
|
||||||
byte team = Pack.leftByte(tr);
|
|
||||||
byte rotation = Pack.rightByte(tr);
|
|
||||||
|
|
||||||
tile.setTeam(Team.all[team]);
|
|
||||||
tile.entity.health = /*health*/tile.block().health;
|
|
||||||
tile.rotation(rotation);
|
|
||||||
|
|
||||||
if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){
|
|
||||||
stream.readByte(); //these blocks have an extra config byte, read it
|
|
||||||
}
|
|
||||||
}else{ //no entity/part, read consecutives
|
|
||||||
int consecutives = stream.readUnsignedByte();
|
|
||||||
|
|
||||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
|
||||||
int newx = j % width, newy = j / width;
|
|
||||||
tiles.get(newx, newy).setBlock(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
i += consecutives;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}finally{
|
|
||||||
content.setTemporaryMapper(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//region legacy IO
|
|
||||||
|
|
||||||
/** Reads a pixmap in the 3.5 pixmap format. */
|
|
||||||
public static void readLegacyPixmap(Pixmap pixmap, Tile[][] tiles){
|
|
||||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
|
||||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
|
||||||
int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y);
|
|
||||||
LegacyBlock block = LegacyColorMapper.get(color);
|
|
||||||
Tile tile = tiles[x][y];
|
|
||||||
|
|
||||||
tile.setFloor(block.floor);
|
|
||||||
tile.setBlock(block.wall);
|
|
||||||
if(block.ore != null) tile.setOverlay(block.ore);
|
|
||||||
|
|
||||||
//place core
|
|
||||||
if(color == Color.rgba8888(Color.GREEN)){
|
|
||||||
for(int dx = 0; dx < 3; dx++){
|
|
||||||
for(int dy = 0; dy < 3; dy++){
|
|
||||||
int worldx = dx - 1 + x;
|
|
||||||
int worldy = dy - 1 + y;
|
|
||||||
|
|
||||||
//multiblock parts
|
|
||||||
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
|
|
||||||
Tile write = tiles[worldx][worldy];
|
|
||||||
write.setBlock(BlockPart.get(dx - 1, dy - 1));
|
|
||||||
write.setTeam(Team.blue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//actual core parts
|
|
||||||
tile.setBlock(Blocks.coreShard);
|
|
||||||
tile.setTeam(Team.blue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//endregion
|
|
||||||
|
|
||||||
interface TileProvider{
|
interface TileProvider{
|
||||||
Tile get(int x, int y);
|
Tile get(int x, int y);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-19
@@ -8,25 +8,11 @@ import io.anuke.arc.util.io.ReusableByteOutStream;
|
|||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
/**
|
public abstract class SaveFileReader{
|
||||||
* Format:
|
|
||||||
* - version of format: int
|
|
||||||
* (begin deflating)
|
|
||||||
* - regions begin
|
|
||||||
* 1. meta tags (short length, key-val UTF pairs)
|
|
||||||
* 2. map data
|
|
||||||
*/
|
|
||||||
public abstract class SaveFileVersion{
|
|
||||||
public final int version;
|
|
||||||
|
|
||||||
protected final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
|
protected final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
|
||||||
protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
|
protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
|
||||||
protected final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
protected final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||||
|
|
||||||
public SaveFileVersion(int version){
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void region(String name, DataInput stream, CounterInputStream counter, IORunner<DataInput> cons) throws IOException{
|
protected void region(String name, DataInput stream, CounterInputStream counter, IORunner<DataInput> cons) throws IOException{
|
||||||
int length;
|
int length;
|
||||||
try{
|
try{
|
||||||
@@ -62,10 +48,10 @@ public abstract class SaveFileVersion{
|
|||||||
if(!isByte){
|
if(!isByte){
|
||||||
output.writeInt(length);
|
output.writeInt(length);
|
||||||
}else{
|
}else{
|
||||||
if(length > 255){
|
if(length > Short.MAX_VALUE){
|
||||||
throw new IOException("Byte write length exceeded: " + length + " > 255");
|
throw new IOException("Byte write length exceeded: " + length + " > " + Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
output.writeByte(length);
|
output.writeShort(length);
|
||||||
}
|
}
|
||||||
output.write(byteOutput.getBytes(), 0, length);
|
output.write(byteOutput.getBytes(), 0, length);
|
||||||
}
|
}
|
||||||
@@ -76,7 +62,7 @@ public abstract class SaveFileVersion{
|
|||||||
|
|
||||||
/** Reads a chunk of some length. Use the runner for reading to catch more descriptive errors. */
|
/** Reads a chunk of some length. Use the runner for reading to catch more descriptive errors. */
|
||||||
public int readChunk(DataInput input, boolean isByte, IORunner<DataInput> runner) throws IOException{
|
public int readChunk(DataInput input, boolean isByte, IORunner<DataInput> runner) throws IOException{
|
||||||
int length = isByte ? input.readUnsignedByte() : input.readInt();
|
int length = isByte ? input.readUnsignedShort() : input.readInt();
|
||||||
runner.accept(input);
|
runner.accept(input);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@@ -17,16 +17,16 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
public class SaveIO{
|
public class SaveIO{
|
||||||
/** Format header. This is the string 'MSAV' in ASCII. */
|
/** Format header. This is the string 'MSAV' in ASCII. */
|
||||||
public static final byte[] header = {77, 83, 65, 86};
|
public static final byte[] header = {77, 83, 65, 86};
|
||||||
public static final IntMap<SaveFileVersion> versions = new IntMap<>();
|
public static final IntMap<SaveVersion> versions = new IntMap<>();
|
||||||
public static final Array<SaveFileVersion> versionArray = Array.with(new Save1());
|
public static final Array<SaveVersion> versionArray = Array.with(new Save1());
|
||||||
|
|
||||||
static{
|
static{
|
||||||
for(SaveFileVersion version : versionArray){
|
for(SaveVersion version : versionArray){
|
||||||
versions.put(version.version, version);
|
versions.put(version.version, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveFileVersion getSaveWriter(){
|
public static SaveVersion getSaveWriter(){
|
||||||
return versionArray.peek();
|
return versionArray.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ public class SaveIO{
|
|||||||
|
|
||||||
public static boolean isSaveValid(DataInputStream stream){
|
public static boolean isSaveValid(DataInputStream stream){
|
||||||
try{
|
try{
|
||||||
getData(stream);
|
getMeta(stream);
|
||||||
return true;
|
return true;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -72,15 +72,15 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveMeta getData(int slot){
|
public static SaveMeta getMeta(int slot){
|
||||||
return getData(getSlotStream(slot));
|
return getMeta(getSlotStream(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveMeta getData(DataInputStream stream){
|
public static SaveMeta getMeta(DataInputStream stream){
|
||||||
|
|
||||||
try{
|
try{
|
||||||
int version = stream.readInt();
|
int version = stream.readInt();
|
||||||
SaveMeta meta = versions.get(version).getData(stream);
|
SaveMeta meta = versions.get(version).getMeta(stream);
|
||||||
stream.close();
|
stream.close();
|
||||||
return meta;
|
return meta;
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
@@ -141,7 +141,7 @@ public class SaveIO{
|
|||||||
logic.reset();
|
logic.reset();
|
||||||
readHeader(stream);
|
readHeader(stream);
|
||||||
int version = stream.readInt();
|
int version = stream.readInt();
|
||||||
SaveFileVersion ver = versions.get(version);
|
SaveVersion ver = versions.get(version);
|
||||||
|
|
||||||
ver.read(stream, counter);
|
ver.read(stream, counter);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -151,7 +151,7 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveFileVersion getVersion(){
|
public static SaveVersion getVersion(){
|
||||||
return versionArray.peek();
|
return versionArray.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import io.anuke.mindustry.maps.Map;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
|
//TODO consider removing and replacing with a raw StringMap
|
||||||
public class SaveMeta{
|
public class SaveMeta{
|
||||||
public int version;
|
public int version;
|
||||||
public int build;
|
public int build;
|
||||||
|
|||||||
+49
-33
@@ -8,6 +8,7 @@ import io.anuke.mindustry.entities.Entities;
|
|||||||
import io.anuke.mindustry.entities.EntityGroup;
|
import io.anuke.mindustry.entities.EntityGroup;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
|
import io.anuke.mindustry.gen.Serialization;
|
||||||
import io.anuke.mindustry.type.ContentType;
|
import io.anuke.mindustry.type.ContentType;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
@@ -16,10 +17,17 @@ import java.io.*;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public abstract class BaseSaveVersion extends SaveFileVersion{
|
public abstract class SaveVersion extends SaveFileReader{
|
||||||
|
public final int version;
|
||||||
|
|
||||||
public BaseSaveVersion(int version){
|
public SaveVersion(int version){
|
||||||
super(version);
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
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", "{}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(DataOutputStream stream) throws IOException{
|
public void write(DataOutputStream stream) throws IOException{
|
||||||
@@ -36,6 +44,28 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
region("entities", stream, counter, this::readEntities);
|
region("entities", stream, counter, this::readEntities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeMeta(DataOutput stream) throws IOException{
|
||||||
|
writeStringMap(stream, StringMap.of(
|
||||||
|
"saved", Time.millis(),
|
||||||
|
"playtime", headless ? 0 : control.saves.getTotalPlaytime(),
|
||||||
|
"build", Version.build,
|
||||||
|
"mapname", world.getMap().name(),
|
||||||
|
"wave", state.wave,
|
||||||
|
"wavetime", state.wavetime,
|
||||||
|
"stats", Serialization.writeStatsJson(state.stats),
|
||||||
|
"rules", Serialization.writeRulesJson(state.rules)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readMeta(DataInput stream) throws IOException{
|
||||||
|
StringMap map = readStringMap(stream);
|
||||||
|
|
||||||
|
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", "{}"));
|
||||||
|
}
|
||||||
|
|
||||||
public void writeMap(DataOutput stream) throws IOException{
|
public void writeMap(DataOutput stream) throws IOException{
|
||||||
//write world size
|
//write world size
|
||||||
stream.writeShort(world.width());
|
stream.writeShort(world.width());
|
||||||
@@ -68,8 +98,10 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
stream.writeShort(tile.blockID());
|
stream.writeShort(tile.blockID());
|
||||||
|
|
||||||
if(tile.entity != null){
|
if(tile.entity != null){
|
||||||
//TODO chunks, backward compat
|
writeChunk(stream, true, out -> {
|
||||||
|
out.writeByte(tile.entity.version());
|
||||||
tile.entity.write(stream);
|
tile.entity.write(stream);
|
||||||
|
});
|
||||||
}else{
|
}else{
|
||||||
//write consecutive non-entity blocks
|
//write consecutive non-entity blocks
|
||||||
int consecutives = 0;
|
int consecutives = 0;
|
||||||
@@ -123,8 +155,10 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
tile.setBlock(block);
|
tile.setBlock(block);
|
||||||
|
|
||||||
if(tile.entity != null){
|
if(tile.entity != null){
|
||||||
//TODO chunks, backward compat
|
readChunk(stream, true, in -> {
|
||||||
tile.entity.read(stream);
|
byte version = in.readByte();
|
||||||
|
tile.entity.read(stream, version);
|
||||||
|
});
|
||||||
}else{
|
}else{
|
||||||
int consecutives = stream.readUnsignedByte();
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
@@ -157,11 +191,12 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||||
stream.writeInt(group.size());
|
stream.writeInt(group.size());
|
||||||
for(Entity entity : group.all()){
|
for(Entity entity : group.all()){
|
||||||
//TODO chunks, backward compat
|
SaveTrait save = (SaveTrait)entity;
|
||||||
//each entity is a separate chunk.
|
//each entity is a separate chunk.
|
||||||
writeChunk(stream, true, out -> {
|
writeChunk(stream, true, out -> {
|
||||||
stream.writeByte(((SaveTrait)entity).getTypeID());
|
stream.writeByte(save.getTypeID());
|
||||||
((SaveTrait)entity).writeSave(out);
|
stream.writeByte(save.version());
|
||||||
|
save.writeSave(out);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,10 +209,13 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
for(int i = 0; i < groups; i++){
|
for(int i = 0; i < groups; i++){
|
||||||
int amount = stream.readInt();
|
int amount = stream.readInt();
|
||||||
for(int j = 0; j < amount; j++){
|
for(int j = 0; j < amount; j++){
|
||||||
//TODO chunks, backwards compat
|
//TODO throw exception on read fail
|
||||||
|
readChunk(stream, true, in -> {
|
||||||
byte typeid = stream.readByte();
|
byte typeid = stream.readByte();
|
||||||
|
byte version = stream.readByte();
|
||||||
SaveTrait trait = (SaveTrait)TypeTrait.getTypeByID(typeid).get();
|
SaveTrait trait = (SaveTrait)TypeTrait.getTypeByID(typeid).get();
|
||||||
trait.readSave(stream);
|
trait.readSave(stream, version);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,26 +261,4 @@ public abstract class BaseSaveVersion extends SaveFileVersion{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMeta(DataOutput stream) throws IOException{
|
|
||||||
writeStringMap(stream, StringMap.of(
|
|
||||||
"saved", Time.millis(),
|
|
||||||
"playtime", headless ? 0 : control.saves.getTotalPlaytime(),
|
|
||||||
"build", Version.build,
|
|
||||||
"mapname", world.getMap().name(),
|
|
||||||
"wave", state.wave,
|
|
||||||
"wavetime", state.wavetime//,
|
|
||||||
//"stats", Serialization.writeStatsStreamJson(state.stats),
|
|
||||||
//"rules", Serialization.writeRulesStreamJson(state.rules),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readMeta(DataInput stream) throws IOException{
|
|
||||||
StringMap map = readStringMap(stream);
|
|
||||||
|
|
||||||
//TODO read rules, stats
|
|
||||||
|
|
||||||
state.wave = map.getInt("wave");
|
|
||||||
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,83 +1,10 @@
|
|||||||
package io.anuke.mindustry.io.versions;
|
package io.anuke.mindustry.io.versions;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.mindustry.io.SaveVersion;
|
||||||
import io.anuke.arc.util.Time;
|
|
||||||
import io.anuke.mindustry.game.*;
|
|
||||||
import io.anuke.mindustry.gen.Serialization;
|
|
||||||
import io.anuke.mindustry.io.SaveFileVersion;
|
|
||||||
import io.anuke.mindustry.maps.Map;
|
|
||||||
import io.anuke.mindustry.type.ContentType;
|
|
||||||
import io.anuke.mindustry.type.Zone;
|
|
||||||
|
|
||||||
import java.io.*;
|
public class Save1 extends SaveVersion{
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
|
||||||
|
|
||||||
public class Save1 extends SaveFileVersion{
|
|
||||||
|
|
||||||
public Save1(){
|
public Save1(){
|
||||||
super(1);
|
super(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(DataInputStream stream) throws IOException{
|
|
||||||
stream.readLong(); //time
|
|
||||||
stream.readLong(); //total playtime
|
|
||||||
stream.readInt(); //build
|
|
||||||
|
|
||||||
//general state
|
|
||||||
state.rules = Serialization.readRulesStreamJson(stream);
|
|
||||||
String mapname = stream.readUTF();
|
|
||||||
Map map = world.maps.all().find(m -> m.name().equals(mapname));
|
|
||||||
if(map == null) map = new Map(customMapDirectory.child(mapname), 1, 1, new ObjectMap<>(), true);
|
|
||||||
world.setMap(map);
|
|
||||||
state.rules.spawns = map.getWaves();
|
|
||||||
if(content.getByID(ContentType.zone, state.rules.zone) != null){
|
|
||||||
Rules rules = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get();
|
|
||||||
if(rules.spawns != DefaultWaves.get()){
|
|
||||||
state.rules.spawns = rules.spawns;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int wave = stream.readInt();
|
|
||||||
float wavetime = stream.readFloat();
|
|
||||||
|
|
||||||
state.wave = wave;
|
|
||||||
state.wavetime = wavetime;
|
|
||||||
state.stats = Serialization.readStats(stream);
|
|
||||||
world.spawner.read(stream);
|
|
||||||
|
|
||||||
content.setTemporaryMapper(readContentHeader(stream));
|
|
||||||
|
|
||||||
readEntities(stream);
|
|
||||||
readMap(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(DataOutputStream stream) throws IOException{
|
|
||||||
//--META--
|
|
||||||
stream.writeInt(version); //version id
|
|
||||||
stream.writeLong(Time.millis()); //last saved
|
|
||||||
stream.writeLong(headless ? 0 : control.saves.getTotalPlaytime()); //playtime
|
|
||||||
stream.writeInt(Version.build); //build
|
|
||||||
|
|
||||||
//--GENERAL STATE--
|
|
||||||
Serialization.writeRulesStreamJson(stream, state.rules);
|
|
||||||
stream.writeUTF(world.getMap().name()); //map name
|
|
||||||
|
|
||||||
stream.writeInt(state.wave); //wave
|
|
||||||
stream.writeFloat(state.wavetime); //wave countdown
|
|
||||||
|
|
||||||
Serialization.writeStats(stream, state.stats);
|
|
||||||
|
|
||||||
world.spawner.write(stream);
|
|
||||||
|
|
||||||
writeContentHeader(stream);
|
|
||||||
|
|
||||||
//--ENTITIES--
|
|
||||||
|
|
||||||
writeEntities(stream);
|
|
||||||
|
|
||||||
writeMap(stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import io.anuke.arc.util.Log;
|
|||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.game.DefaultWaves;
|
import io.anuke.mindustry.game.DefaultWaves;
|
||||||
import io.anuke.mindustry.game.SpawnGroup;
|
import io.anuke.mindustry.game.SpawnGroup;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
@@ -44,7 +43,11 @@ public class Map implements Comparable<Map>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom){
|
public Map(FileHandle file, int width, int height, ObjectMap<String, String> tags, boolean custom){
|
||||||
this(file, width, height, tags, custom, MapIO.version);
|
this(file, width, height, tags, custom, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map(ObjectMap<String, String> tags){
|
||||||
|
this(Vars.customMapDirectory.child(tags.get("name", "unknown")), 0, 0, tags, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array<SpawnGroup> getWaves(){
|
public Array<SpawnGroup> getWaves(){
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import io.anuke.mindustry.maps.Map;
|
|||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.customMapDirectory;
|
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public abstract class RandomGenerator extends Generator{
|
public abstract class RandomGenerator extends Generator{
|
||||||
@@ -32,7 +31,7 @@ public abstract class RandomGenerator extends Generator{
|
|||||||
|
|
||||||
decorate(tiles);
|
decorate(tiles);
|
||||||
|
|
||||||
world.setMap(new Map(customMapDirectory.child("generated"), 0, 0, new ObjectMap<>(), true));
|
world.setMap(new Map(new ObjectMap<>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void decorate(Tile[][] tiles);
|
public abstract void decorate(Tile[][] tiles);
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ public class Administration{
|
|||||||
|
|
||||||
public Administration(){
|
public Administration(){
|
||||||
Core.settings.defaults(
|
Core.settings.defaults(
|
||||||
"strict", true
|
"strict", true,
|
||||||
|
"servername", "Server"
|
||||||
);
|
);
|
||||||
|
|
||||||
load();
|
load();
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.ObjectMap.Entry;
|
|
||||||
import io.anuke.arc.util.Time;
|
import io.anuke.arc.util.Time;
|
||||||
import io.anuke.mindustry.entities.Entities;
|
import io.anuke.mindustry.entities.Entities;
|
||||||
import io.anuke.mindustry.entities.type.Player;
|
import io.anuke.mindustry.entities.type.Player;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.game.Teams.TeamData;
|
|
||||||
import io.anuke.mindustry.gen.Serialization;
|
import io.anuke.mindustry.gen.Serialization;
|
||||||
import io.anuke.mindustry.io.SaveIO;
|
import io.anuke.mindustry.io.SaveIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.world.Tile;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -22,44 +20,16 @@ public class NetworkIO{
|
|||||||
public static void writeWorld(Player player, OutputStream os){
|
public static void writeWorld(Player player, OutputStream os){
|
||||||
|
|
||||||
try(DataOutputStream stream = new DataOutputStream(os)){
|
try(DataOutputStream stream = new DataOutputStream(os)){
|
||||||
//--GENERAL STATE--
|
|
||||||
Serialization.writeRules(stream, state.rules);
|
Serialization.writeRules(stream, state.rules);
|
||||||
stream.writeUTF(world.getMap().name()); //map name
|
SaveIO.getSaveWriter().writeStringMap(stream, world.getMap().tags);
|
||||||
|
|
||||||
//write tags
|
stream.writeInt(state.wave);
|
||||||
ObjectMap<String, String> tags = world.getMap().tags;
|
stream.writeFloat(state.wavetime);
|
||||||
stream.writeByte(tags.size);
|
|
||||||
for(Entry<String, String> entry : tags.entries()){
|
|
||||||
stream.writeUTF(entry.key);
|
|
||||||
stream.writeUTF(entry.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.writeInt(state.wave); //wave
|
|
||||||
stream.writeFloat(state.wavetime); //wave countdown
|
|
||||||
|
|
||||||
stream.writeInt(player.id);
|
stream.writeInt(player.id);
|
||||||
player.write(stream);
|
player.write(stream);
|
||||||
|
|
||||||
SaveIO.getSaveWriter().writeMap(stream);
|
SaveIO.getSaveWriter().writeMap(stream);
|
||||||
|
|
||||||
stream.write(Team.all.length);
|
|
||||||
|
|
||||||
//write team data
|
|
||||||
for(Team team : Team.all){
|
|
||||||
TeamData data = state.teams.get(team);
|
|
||||||
stream.writeByte(team.ordinal());
|
|
||||||
|
|
||||||
stream.writeByte(data.enemies.size());
|
|
||||||
for(Team enemy : data.enemies){
|
|
||||||
stream.writeByte(enemy.ordinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.writeByte(data.cores.size);
|
|
||||||
for(Tile tile : data.cores){
|
|
||||||
stream.writeInt(tile.pos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -69,25 +39,11 @@ public class NetworkIO{
|
|||||||
|
|
||||||
try(DataInputStream stream = new DataInputStream(is)){
|
try(DataInputStream stream = new DataInputStream(is)){
|
||||||
Time.clear();
|
Time.clear();
|
||||||
|
|
||||||
//general state
|
|
||||||
state.rules = Serialization.readRules(stream);
|
state.rules = Serialization.readRules(stream);
|
||||||
String map = stream.readUTF();
|
world.setMap(new Map(SaveIO.getSaveWriter().readStringMap(stream)));
|
||||||
|
|
||||||
ObjectMap<String, String> tags = new ObjectMap<>();
|
state.wave = stream.readInt();
|
||||||
|
state.wavetime = stream.readFloat();
|
||||||
byte tagSize = stream.readByte();
|
|
||||||
for(int i = 0; i < tagSize; i++){
|
|
||||||
String key = stream.readUTF();
|
|
||||||
String value = stream.readUTF();
|
|
||||||
tags.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
int wave = stream.readInt();
|
|
||||||
float wavetime = stream.readFloat();
|
|
||||||
|
|
||||||
state.wave = wave;
|
|
||||||
state.wavetime = wavetime;
|
|
||||||
|
|
||||||
Entities.clear();
|
Entities.clear();
|
||||||
int id = stream.readInt();
|
int id = stream.readInt();
|
||||||
@@ -96,81 +52,60 @@ public class NetworkIO{
|
|||||||
player.resetID(id);
|
player.resetID(id);
|
||||||
player.add();
|
player.add();
|
||||||
|
|
||||||
//map
|
|
||||||
SaveIO.getSaveWriter().readMap(stream);
|
SaveIO.getSaveWriter().readMap(stream);
|
||||||
world.setMap(new Map(customMapDirectory.child(map), 0, 0, new ObjectMap<>(), true));
|
|
||||||
|
|
||||||
state.teams = new Teams();
|
|
||||||
|
|
||||||
byte teams = stream.readByte();
|
|
||||||
for(int i = 0; i < teams; i++){
|
|
||||||
Team team = Team.all[stream.readByte()];
|
|
||||||
|
|
||||||
byte enemies = stream.readByte();
|
|
||||||
Team[] enemyArr = new Team[enemies];
|
|
||||||
for(int j = 0; j < enemies; j++){
|
|
||||||
enemyArr[j] = Team.all[stream.readByte()];
|
|
||||||
}
|
|
||||||
|
|
||||||
state.teams.add(team, enemyArr);
|
|
||||||
|
|
||||||
byte cores = stream.readByte();
|
|
||||||
|
|
||||||
for(int j = 0; j < cores; j++){
|
|
||||||
state.teams.get(team).cores.add(world.tile(stream.readInt()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer writeServerData(){
|
public static ByteBuffer writeServerData(){
|
||||||
int maxlen = 32;
|
String name = (headless ? Core.settings.getString("servername") : player.name);
|
||||||
|
|
||||||
String host = (headless ? "Server" : player.name);
|
|
||||||
String map = world.getMap() == null ? "None" : world.getMap().name();
|
String map = world.getMap() == null ? "None" : world.getMap().name();
|
||||||
|
|
||||||
host = host.substring(0, Math.min(host.length(), maxlen));
|
ByteBuffer buffer = ByteBuffer.allocate(256);
|
||||||
map = map.substring(0, Math.min(map.length(), maxlen));
|
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(128);
|
writeString(buffer, name, 100);
|
||||||
|
writeString(buffer, map);
|
||||||
buffer.put((byte)host.getBytes(charset).length);
|
|
||||||
buffer.put(host.getBytes(charset));
|
|
||||||
|
|
||||||
buffer.put((byte)map.getBytes(charset).length);
|
|
||||||
buffer.put(map.getBytes(charset));
|
|
||||||
|
|
||||||
buffer.putInt(playerGroup.size());
|
buffer.putInt(playerGroup.size());
|
||||||
buffer.putInt(state.wave);
|
buffer.putInt(state.wave);
|
||||||
buffer.putInt(Version.build);
|
buffer.putInt(Version.build);
|
||||||
buffer.put((byte)Version.type.getBytes(charset).length);
|
writeString(buffer, Version.type);
|
||||||
buffer.put(Version.type.getBytes(charset));
|
//TODO additional information:
|
||||||
|
// - gamemode ID/name (just pick the closest one?)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Host readServerData(String hostAddress, ByteBuffer buffer){
|
public static Host readServerData(String hostAddress, ByteBuffer buffer){
|
||||||
byte hlength = buffer.get();
|
String host = readString(buffer);
|
||||||
byte[] hb = new byte[hlength];
|
String map = readString(buffer);
|
||||||
buffer.get(hb);
|
|
||||||
|
|
||||||
byte mlength = buffer.get();
|
|
||||||
byte[] mb = new byte[mlength];
|
|
||||||
buffer.get(mb);
|
|
||||||
|
|
||||||
String host = new String(hb, charset);
|
|
||||||
String map = new String(mb, charset);
|
|
||||||
|
|
||||||
int players = buffer.getInt();
|
int players = buffer.getInt();
|
||||||
int wave = buffer.getInt();
|
int wave = buffer.getInt();
|
||||||
int version = buffer.getInt();
|
int version = buffer.getInt();
|
||||||
byte tlength = buffer.get();
|
String vertype = readString(buffer);
|
||||||
byte[] tb = new byte[tlength];
|
|
||||||
buffer.get(tb);
|
|
||||||
String vertype = new String(tb, charset);
|
|
||||||
|
|
||||||
return new Host(host, hostAddress, map, wave, players, version, vertype);
|
return new Host(host, hostAddress, map, wave, players, version, vertype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void writeString(ByteBuffer buffer, String string, int maxlen){
|
||||||
|
byte[] bytes = string.getBytes(charset);
|
||||||
|
//truncating this way may lead to wierd encoding errors at the ends of strings...
|
||||||
|
if(bytes.length > maxlen){
|
||||||
|
bytes = Arrays.copyOfRange(bytes, 0, maxlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.put((byte)bytes.length);
|
||||||
|
buffer.put(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeString(ByteBuffer buffer, String string){
|
||||||
|
writeString(buffer, string, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readString(ByteBuffer buffer){
|
||||||
|
short length = (short)(buffer.get() & 0xff);
|
||||||
|
byte[] bytes = new byte[length];
|
||||||
|
buffer.get(bytes);
|
||||||
|
return new String(bytes, charset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,9 +164,9 @@ public class JoinDialog extends FloatingDialog{
|
|||||||
server.content.clear();
|
server.content.clear();
|
||||||
|
|
||||||
server.content.table(t -> {
|
server.content.table(t -> {
|
||||||
t.add(versionString).left();
|
t.add("[lightgray]" + host.name).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||||
t.row();
|
t.row();
|
||||||
t.add("[lightgray]" + Core.bundle.format("server.hostname", host.name)).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
t.add(versionString).left();
|
||||||
t.row();
|
t.row();
|
||||||
t.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players) :
|
t.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players) :
|
||||||
Core.bundle.format("players.single", host.players))).left();
|
Core.bundle.format("players.single", host.players))).left();
|
||||||
|
|||||||
@@ -319,8 +319,8 @@ public class BuildBlock extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
progress = stream.readFloat();
|
progress = stream.readFloat();
|
||||||
short pid = stream.readShort();
|
short pid = stream.readShort();
|
||||||
short rid = stream.readShort();
|
short rid = stream.readShort();
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ public class Door extends Wall{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
open = stream.readBoolean();
|
open = stream.readBoolean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,8 +212,8 @@ public class ForceProjector extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
broken = stream.readBoolean();
|
broken = stream.readBoolean();
|
||||||
buildup = stream.readFloat();
|
buildup = stream.readFloat();
|
||||||
radscl = stream.readFloat();
|
radscl = stream.readFloat();
|
||||||
|
|||||||
@@ -154,8 +154,8 @@ public class MendProjector extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
heat = stream.readFloat();
|
heat = stream.readFloat();
|
||||||
phaseHeat = stream.readFloat();
|
phaseHeat = stream.readFloat();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,8 +153,8 @@ public class OverdriveProjector extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
heat = stream.readFloat();
|
heat = stream.readFloat();
|
||||||
phaseHeat = stream.readFloat();
|
phaseHeat = stream.readFloat();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ public class ItemTurret extends CooledTurret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
byte amount = stream.readByte();
|
byte amount = stream.readByte();
|
||||||
for(int i = 0; i < amount; i++){
|
for(int i = 0; i < amount; i++){
|
||||||
Item item = Vars.content.item(stream.readByte());
|
Item item = Vars.content.item(stream.readByte());
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ public class BufferedItemBridge extends ExtendingItemBridge{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
buffer.read(stream);
|
buffer.read(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,8 +376,8 @@ public class Conveyor extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
convey.clear();
|
convey.clear();
|
||||||
int amount = stream.readInt();
|
int amount = stream.readInt();
|
||||||
convey.ensureCapacity(Math.min(amount, 10));
|
convey.ensureCapacity(Math.min(amount, 10));
|
||||||
|
|||||||
@@ -340,8 +340,8 @@ public class ItemBridge extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
link = stream.readInt();
|
link = stream.readInt();
|
||||||
uptime = stream.readFloat();
|
uptime = stream.readFloat();
|
||||||
byte links = stream.readByte();
|
byte links = stream.readByte();
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ public class Junction extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
for(Buffer b : buffers){
|
for(Buffer b : buffers){
|
||||||
b.read(stream);
|
b.read(stream);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -328,8 +328,8 @@ public class MassDriver extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
link = stream.readInt();
|
link = stream.readInt();
|
||||||
rotation = stream.readFloat();
|
rotation = stream.readFloat();
|
||||||
state = DriverState.values()[stream.readByte()];
|
state = DriverState.values()[stream.readByte()];
|
||||||
|
|||||||
@@ -134,14 +134,13 @@ public class Sorter extends Block{
|
|||||||
@Override
|
@Override
|
||||||
public void write(DataOutput stream) throws IOException{
|
public void write(DataOutput stream) throws IOException{
|
||||||
super.write(stream);
|
super.write(stream);
|
||||||
stream.writeByte(sortItem == null ? -1 : sortItem.id);
|
stream.writeShort(sortItem == null ? -1 : sortItem.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
byte b = stream.readByte();
|
sortItem = content.item(stream.readShort());
|
||||||
sortItem = b == -1 ? null : content.items().get(b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,8 +172,8 @@ public class ImpactReactor extends PowerGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
warmup = stream.readFloat();
|
warmup = stream.readFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,8 +188,8 @@ public class NuclearReactor extends PowerGenerator{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
heat = stream.readFloat();
|
heat = stream.readFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ public class PowerGenerator extends PowerDistributor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
productionEfficiency = stream.readFloat();
|
productionEfficiency = stream.readFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ public class Cultivator extends GenericCrafter{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
warmup = stream.readFloat();
|
warmup = stream.readFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ public class GenericCrafter extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
progress = stream.readFloat();
|
progress = stream.readFloat();
|
||||||
warmup = stream.readFloat();
|
warmup = stream.readFloat();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ public class LiquidSource extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
byte id = stream.readByte();
|
byte id = stream.readByte();
|
||||||
source = id == -1 ? null : content.liquid(id);
|
source = id == -1 ? null : content.liquid(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ public class Unloader extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
byte id = stream.readByte();
|
byte id = stream.readByte();
|
||||||
sortItem = id == -1 ? null : content.items().get(id);
|
sortItem = id == -1 ? null : content.items().get(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,8 +185,8 @@ public class MechPad extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
progress = stream.readFloat();
|
progress = stream.readFloat();
|
||||||
time = stream.readFloat();
|
time = stream.readFloat();
|
||||||
heat = stream.readFloat();
|
heat = stream.readFloat();
|
||||||
|
|||||||
@@ -198,13 +198,12 @@ public class UnitFactory extends Block{
|
|||||||
public void write(DataOutput stream) throws IOException{
|
public void write(DataOutput stream) throws IOException{
|
||||||
super.write(stream);
|
super.write(stream);
|
||||||
stream.writeFloat(buildTime);
|
stream.writeFloat(buildTime);
|
||||||
stream.writeFloat(0f);
|
|
||||||
stream.writeInt(spawned);
|
stream.writeInt(spawned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
super.read(stream);
|
super.read(stream, revision);
|
||||||
buildTime = stream.readFloat();
|
buildTime = stream.readFloat();
|
||||||
spawned = stream.readInt();
|
spawned = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public class ArcNetClient implements ClientProvider{
|
|||||||
handler = new ClientDiscoveryHandler(){
|
handler = new ClientDiscoveryHandler(){
|
||||||
@Override
|
@Override
|
||||||
public DatagramPacket newDatagramPacket(){
|
public DatagramPacket newDatagramPacket(){
|
||||||
return new DatagramPacket(new byte[128], 128);
|
return new DatagramPacket(new byte[256], 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -357,6 +357,16 @@ public class ServerControl implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handler.register("name", "[name...]", "Change the server display name.", arg -> {
|
||||||
|
if(arg.length == 0){
|
||||||
|
info("Server name is currently &lc'{0}'.", Core.settings.getString("servername"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Core.settings.put("servername", arg[0]);
|
||||||
|
Core.settings.save();
|
||||||
|
info("Server name is now &lc'{0}'.", arg[0]);
|
||||||
|
});
|
||||||
|
|
||||||
handler.register("crashreport", "<on/off>", "Disables or enables automatic crash reporting", arg -> {
|
handler.register("crashreport", "<on/off>", "Disables or enables automatic crash reporting", arg -> {
|
||||||
boolean value = arg[0].equalsIgnoreCase("on");
|
boolean value = arg[0].equalsIgnoreCase("on");
|
||||||
Core.settings.put("crashreport", value);
|
Core.settings.put("crashreport", value);
|
||||||
|
|||||||
Reference in New Issue
Block a user