mirror of
https://github.com/Anuken/Mindustry.git
synced 2024-11-13 07:15:28 +03:00
even less broken
This commit is contained in:
parent
bf073a84c8
commit
20fbe2fbbe
@ -143,6 +143,19 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
||||
.addStatement("bjson.writeObjectEnd()")
|
||||
.addStatement("stream.writeUTF(output.toString())");
|
||||
|
||||
MethodSpec.Builder binaryJsonWriteStringMethod = MethodSpec.methodBuilder("write" + simpleTypeName + "StringJson")
|
||||
.returns(String.class)
|
||||
.addParameter(DataOutput.class, "stream")
|
||||
.addParameter(type, "object")
|
||||
.addException(IOException.class)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addStatement("java.io.StringWriter output = new java.io.StringWriter()")
|
||||
.addStatement("bjson.setWriter(output)")
|
||||
.addStatement("bjson.writeObjectStart(" + type + ".class, " + type + ".class)")
|
||||
.addStatement("write" + simpleTypeName + "Json(bjson, object)")
|
||||
.addStatement("bjson.writeObjectEnd()")
|
||||
.addStatement("return output.toString()");
|
||||
|
||||
MethodSpec.Builder binaryJsonReadMethod = MethodSpec.methodBuilder("read" + simpleTypeName + "StreamJson")
|
||||
.returns(type)
|
||||
.addParameter(DataInput.class, "stream")
|
||||
@ -151,6 +164,7 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
||||
.addStatement("return read" + simpleTypeName + "Json(bjson.fromJson(null, stream.readUTF()))");
|
||||
|
||||
classBuilder.addMethod(binaryJsonWriteMethod.build());
|
||||
classBuilder.addMethod(binaryJsonWriteStringMethod.build());
|
||||
classBuilder.addMethod(binaryJsonReadMethod.build());
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,10 @@ package io.anuke.mindustry.ai;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
@ -14,48 +14,25 @@ import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class WaveSpawner{
|
||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||
private IntArray loadedSpawns = new IntArray();
|
||||
private boolean spawning = false;
|
||||
|
||||
public WaveSpawner(){
|
||||
Events.on(WorldLoadEvent.class, e -> reset());
|
||||
}
|
||||
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeInt(groundSpawns.size);
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
stream.writeInt(Pos.get(spawn.x, spawn.y));
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInput stream) throws IOException{
|
||||
flySpawns.clear();
|
||||
groundSpawns.clear();
|
||||
loadedSpawns.clear();
|
||||
|
||||
int amount = stream.readInt();
|
||||
|
||||
for(int i = 0; i < amount; i++){
|
||||
loadedSpawns.add(stream.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
public int countSpawns(){
|
||||
return groundSpawns.size;
|
||||
}
|
||||
|
||||
/** @return true if the player is near a ground spawn point. */
|
||||
public boolean playerNear(){
|
||||
return groundSpawns.count(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius) > 0;
|
||||
return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius);
|
||||
}
|
||||
|
||||
public void spawnEnemies(){
|
||||
@ -117,21 +94,11 @@ public class WaveSpawner{
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
|
||||
if(world.tile(x, y).block() == Blocks.spawn){
|
||||
if(world.tile(x, y).overlay() == Blocks.spawn){
|
||||
addSpawns(x, y);
|
||||
|
||||
//hide spawnpoints, they have served their purpose
|
||||
world.tile(x, y).setBlock(Blocks.air);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < loadedSpawns.size; i++){
|
||||
int pos = loadedSpawns.get(i);
|
||||
addSpawns(Pos.x(pos), Pos.y(pos));
|
||||
}
|
||||
|
||||
loadedSpawns.clear();
|
||||
}
|
||||
|
||||
private void addSpawns(int x, int y){
|
||||
|
@ -88,15 +88,9 @@ public class Blocks implements ContentList{
|
||||
hasShadow = false;
|
||||
}
|
||||
|
||||
public void draw(Tile tile){
|
||||
}
|
||||
|
||||
public void load(){
|
||||
}
|
||||
|
||||
public void init(){
|
||||
}
|
||||
|
||||
public void draw(Tile tile){}
|
||||
public void load(){}
|
||||
public void init(){}
|
||||
public boolean isHidden(){
|
||||
return true;
|
||||
}
|
||||
@ -119,7 +113,9 @@ public class Blocks implements ContentList{
|
||||
}
|
||||
}
|
||||
|
||||
spawn = new Block("spawn");
|
||||
spawn = new OverlayFloor("spawn"){
|
||||
public void draw(Tile tile){}
|
||||
};
|
||||
|
||||
//Registers build blocks
|
||||
//no reference is needed here since they can be looked up by name later
|
||||
|
@ -14,6 +14,7 @@ import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
@ -110,7 +111,7 @@ public class MapRenderer implements Disposable{
|
||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||
|
||||
if(wall != Blocks.air && (wall.synthetic() || wall == Blocks.part)){
|
||||
if(wall != Blocks.air && (wall.synthetic() || wall instanceof BlockPart)){
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
|
||||
if(wall.rotate){
|
||||
|
248
core/src/io/anuke/mindustry/io/BaseSaveVersion.java
Normal file
248
core/src/io/anuke/mindustry/io/BaseSaveVersion.java
Normal file
@ -0,0 +1,248 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.StringMap;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.io.CounterInputStream;
|
||||
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.type.ContentType;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public abstract class BaseSaveVersion extends SaveFileVersion{
|
||||
|
||||
public BaseSaveVersion(int version){
|
||||
super(version);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream stream) throws IOException{
|
||||
region("meta", stream, this::writeMeta);
|
||||
region("content", stream, this::writeContentHeader);
|
||||
region("map", stream, this::writeMap);
|
||||
region("entities", stream, this::writeEntities);
|
||||
}
|
||||
|
||||
public void read(DataInputStream stream, CounterInputStream counter) throws IOException{
|
||||
region("meta", stream, counter, this::readMeta);
|
||||
region("content", stream, counter, this::readContentHeader);
|
||||
region("map", stream, counter, this::readMap);
|
||||
region("entities", stream, counter, this::readEntities);
|
||||
}
|
||||
|
||||
public void writeMap(DataOutput stream) throws IOException{
|
||||
//write world size
|
||||
stream.writeShort(world.width());
|
||||
stream.writeShort(world.height());
|
||||
|
||||
//floor + overlay
|
||||
for(int i = 0; i < world.width() * world.height(); i++){
|
||||
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||
stream.writeShort(tile.floorID());
|
||||
stream.writeShort(tile.overlayID());
|
||||
int consecutives = 0;
|
||||
|
||||
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
||||
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
||||
|
||||
if(nextTile.floorID() != tile.floorID() || nextTile.overlayID() != tile.overlayID()){
|
||||
break;
|
||||
}
|
||||
|
||||
consecutives++;
|
||||
}
|
||||
|
||||
stream.writeByte(consecutives);
|
||||
i += consecutives;
|
||||
}
|
||||
|
||||
//blocks
|
||||
for(int i = 0; i < world.width() * world.height(); i++){
|
||||
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||
stream.writeShort(tile.blockID());
|
||||
|
||||
if(tile.entity != null){
|
||||
//TODO chunks, backward compat
|
||||
tile.entity.write(stream);
|
||||
}else{
|
||||
//write consecutive non-entity blocks
|
||||
int consecutives = 0;
|
||||
|
||||
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
||||
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
||||
|
||||
if(nextTile.blockID() != tile.blockID()){
|
||||
break;
|
||||
}
|
||||
|
||||
consecutives++;
|
||||
}
|
||||
|
||||
stream.writeByte(consecutives);
|
||||
i += consecutives;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readMap(DataInput stream) throws IOException{
|
||||
short width = stream.readShort();
|
||||
short height = stream.readShort();
|
||||
|
||||
world.beginMapLoad();
|
||||
|
||||
Tile[][] tiles = world.createTiles(width, height);
|
||||
|
||||
//read floor and create tiles first
|
||||
for(int i = 0; i < width * height; i++){
|
||||
int x = i % width, y = i / width;
|
||||
short floorid = stream.readShort();
|
||||
short oreid = stream.readShort();
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
|
||||
tiles[x][y] = new Tile(x, y, floorid, oreid, (short)0);
|
||||
|
||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||
int newx = j % width, newy = j / width;
|
||||
tiles[newx][newy] = new Tile(newx, newy, floorid, oreid, (short)0);
|
||||
}
|
||||
|
||||
i += consecutives;
|
||||
}
|
||||
|
||||
//read blocks
|
||||
for(int i = 0; i < width * height; i++){
|
||||
int x = i % width, y = i / width;
|
||||
Block block = content.block(stream.readShort());
|
||||
Tile tile = tiles[x][y];
|
||||
tile.setBlock(block);
|
||||
|
||||
if(tile.entity != null){
|
||||
//TODO chunks, backward compat
|
||||
tile.entity.read(stream);
|
||||
}else{
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
|
||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||
int newx = j % width, newy = j / width;
|
||||
tiles[newx][newy].setBlock(block);
|
||||
}
|
||||
|
||||
i += consecutives;
|
||||
}
|
||||
}
|
||||
|
||||
content.setTemporaryMapper(null);
|
||||
world.endMapLoad();
|
||||
}
|
||||
|
||||
public void writeEntities(DataOutput stream) throws IOException{
|
||||
//write entity chunk
|
||||
int groups = 0;
|
||||
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||
groups++;
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeByte(groups);
|
||||
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||
stream.writeInt(group.size());
|
||||
for(Entity entity : group.all()){
|
||||
//TODO chunks, backward compat
|
||||
//each entity is a separate chunk.
|
||||
writeChunk(stream, true, out -> {
|
||||
stream.writeByte(((SaveTrait)entity).getTypeID());
|
||||
((SaveTrait)entity).writeSave(out);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readEntities(DataInput stream) throws IOException{
|
||||
byte groups = stream.readByte();
|
||||
|
||||
for(int i = 0; i < groups; i++){
|
||||
int amount = stream.readInt();
|
||||
for(int j = 0; j < amount; j++){
|
||||
//TODO chunks, backwards compat
|
||||
byte typeid = stream.readByte();
|
||||
SaveTrait trait = (SaveTrait)TypeTrait.getTypeByID(typeid).get();
|
||||
trait.readSave(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readContentHeader(DataInput stream) throws IOException{
|
||||
|
||||
byte mapped = stream.readByte();
|
||||
|
||||
MappableContent[][] map = new MappableContent[ContentType.values().length][0];
|
||||
|
||||
for(int i = 0; i < mapped; i++){
|
||||
ContentType type = ContentType.values()[stream.readByte()];
|
||||
short total = stream.readShort();
|
||||
map[type.ordinal()] = new MappableContent[total];
|
||||
|
||||
for(int j = 0; j < total; j++){
|
||||
String name = stream.readUTF();
|
||||
map[type.ordinal()][j] = content.getByName(type, fallback.get(name, name));
|
||||
}
|
||||
}
|
||||
|
||||
content.setTemporaryMapper(map);
|
||||
}
|
||||
|
||||
public void writeContentHeader(DataOutput stream) throws IOException{
|
||||
Array<Content>[] map = content.getContentMap();
|
||||
|
||||
int mappable = 0;
|
||||
for(Array<Content> arr : map){
|
||||
if(arr.size > 0 && arr.first() instanceof MappableContent){
|
||||
mappable++;
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeByte(mappable);
|
||||
for(Array<Content> arr : map){
|
||||
if(arr.size > 0 && arr.first() instanceof MappableContent){
|
||||
stream.writeByte(arr.first().getContentType().ordinal());
|
||||
stream.writeShort(arr.size);
|
||||
for(Content c : arr){
|
||||
stream.writeUTF(((MappableContent)c).name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,40 +1,50 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.ObjectMap.Entry;
|
||||
import io.anuke.arc.collection.StringMap;
|
||||
import io.anuke.arc.util.io.CounterInputStream;
|
||||
import io.anuke.arc.util.io.ReusableByteOutStream;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.MappableContent;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
/**
|
||||
* Format:
|
||||
* 1. version of format / int
|
||||
* - version of format: int
|
||||
* (begin deflating)
|
||||
* 2. regions
|
||||
* - regions begin
|
||||
* 1. meta tags (short length, key-val UTF pairs)
|
||||
* 2. map data
|
||||
*/
|
||||
public abstract class SaveFileVersion{
|
||||
public final int version;
|
||||
|
||||
private final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
|
||||
private final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
|
||||
private final Region[] regions;
|
||||
private final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||
protected final ReusableByteOutStream byteOutput = new ReusableByteOutStream();
|
||||
protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput);
|
||||
protected final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||
|
||||
public SaveFileVersion(int version, Region... regions){
|
||||
public SaveFileVersion(int version){
|
||||
this.version = version;
|
||||
this.regions = regions;
|
||||
}
|
||||
|
||||
protected void region(String name, DataInput stream, CounterInputStream counter, IORunner<DataInput> cons) throws IOException{
|
||||
int length;
|
||||
try{
|
||||
length = readChunk(stream, cons);
|
||||
}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));
|
||||
}
|
||||
}
|
||||
|
||||
protected void region(String name, DataOutput stream, IORunner<DataOutput> cons) throws IOException{
|
||||
try{
|
||||
writeChunk(stream, cons);
|
||||
}catch(Throwable e){
|
||||
throw new IOException("Error writing region \"" + name + "\".", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeChunk(DataOutput output, IORunner<DataOutput> runner) throws IOException{
|
||||
@ -67,7 +77,6 @@ public abstract class SaveFileVersion{
|
||||
/** 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{
|
||||
int length = isByte ? input.readUnsignedByte() : input.readInt();
|
||||
//TODO descriptive error with chunk name
|
||||
runner.accept(input);
|
||||
return length;
|
||||
}
|
||||
@ -81,7 +90,7 @@ public abstract class SaveFileVersion{
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMeta(DataOutput stream, ObjectMap<String, String> map) throws IOException{
|
||||
public void writeStringMap(DataOutput stream, ObjectMap<String, String> map) throws IOException{
|
||||
stream.writeShort(map.size);
|
||||
for(Entry<String, String> entry : map.entries()){
|
||||
stream.writeUTF(entry.key);
|
||||
@ -89,7 +98,7 @@ public abstract class SaveFileVersion{
|
||||
}
|
||||
}
|
||||
|
||||
public StringMap readMeta(DataInput stream) throws IOException{
|
||||
public StringMap readStringMap(DataInput stream) throws IOException{
|
||||
StringMap map = new StringMap();
|
||||
short size = stream.readShort();
|
||||
for(int i = 0; i < size; i++){
|
||||
@ -98,227 +107,9 @@ public abstract class SaveFileVersion{
|
||||
return map;
|
||||
}
|
||||
|
||||
public void writeMap(DataOutput stream) throws IOException{
|
||||
//write world size
|
||||
stream.writeShort(world.width());
|
||||
stream.writeShort(world.height());
|
||||
public abstract void read(DataInputStream stream, CounterInputStream counter) throws IOException;
|
||||
|
||||
//floor + overlay
|
||||
for(int i = 0; i < world.width() * world.height(); i++){
|
||||
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||
stream.writeShort(tile.floorID());
|
||||
stream.writeShort(tile.overlayID());
|
||||
int consecutives = 0;
|
||||
|
||||
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
||||
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
||||
|
||||
if(nextTile.floorID() != tile.floorID() || nextTile.overlayID() != tile.overlayID()){
|
||||
break;
|
||||
}
|
||||
|
||||
consecutives++;
|
||||
}
|
||||
|
||||
stream.writeByte(consecutives);
|
||||
i += consecutives;
|
||||
}
|
||||
|
||||
//blocks
|
||||
for(int i = 0; i < world.width() * world.height(); i++){
|
||||
Tile tile = world.tile(i % world.width(), i / world.width());
|
||||
stream.writeShort(tile.blockID());
|
||||
|
||||
if(tile.entity != null){
|
||||
tile.entity.write(stream);
|
||||
}else{
|
||||
//write consecutive non-entity blocks
|
||||
int consecutives = 0;
|
||||
|
||||
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
|
||||
Tile nextTile = world.tile(j % world.width(), j / world.width());
|
||||
|
||||
if(nextTile.blockID() != tile.blockID()){
|
||||
break;
|
||||
}
|
||||
|
||||
consecutives++;
|
||||
}
|
||||
|
||||
stream.writeByte(consecutives);
|
||||
i += consecutives;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readMap(DataInputStream stream) throws IOException{
|
||||
short width = stream.readShort();
|
||||
short height = stream.readShort();
|
||||
|
||||
world.beginMapLoad();
|
||||
|
||||
Tile[][] tiles = world.createTiles(width, height);
|
||||
|
||||
//read floor and create tiles first
|
||||
for(int i = 0; i < width * height; i++){
|
||||
int x = i % width, y = i / width;
|
||||
short floorid = stream.readShort();
|
||||
short oreid = stream.readShort();
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
|
||||
tiles[x][y] = new Tile(false, x, y, floorid, oreid);
|
||||
|
||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||
int newx = j % width, newy = j / width;
|
||||
tiles[newx][newy] = new Tile(false, newx, newy, floorid, 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.readShort());
|
||||
Tile tile = tiles[x][y];
|
||||
tile.setBlock(block);
|
||||
|
||||
if(tile.entity != null){
|
||||
tile.entity.read(stream);
|
||||
}else{
|
||||
int consecutives = stream.readUnsignedByte();
|
||||
|
||||
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||
int newx = j % width, newy = j / width;
|
||||
tiles[newx][newy].setBlock(block);
|
||||
}
|
||||
|
||||
i += consecutives;
|
||||
}
|
||||
}
|
||||
|
||||
content.setTemporaryMapper(null);
|
||||
world.endMapLoad();
|
||||
}
|
||||
|
||||
public void writeEntities(DataOutputStream stream) throws IOException{
|
||||
//write entity chunk
|
||||
int groups = 0;
|
||||
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||
groups++;
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeByte(groups);
|
||||
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){
|
||||
stream.writeInt(group.size());
|
||||
for(Entity entity : group.all()){
|
||||
//each entity is a separate chunk.
|
||||
writeChunk(stream, true, out -> {
|
||||
stream.writeByte(((SaveTrait)entity).getTypeID());
|
||||
((SaveTrait)entity).writeSave(out);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readEntities(DataInputStream stream) throws IOException{
|
||||
byte groups = stream.readByte();
|
||||
|
||||
for(int i = 0; i < groups; i++){
|
||||
int amount = stream.readInt();
|
||||
for(int j = 0; j < amount; j++){
|
||||
byte typeid = stream.readByte();
|
||||
SaveTrait trait = (SaveTrait)TypeTrait.getTypeByID(typeid).get();
|
||||
trait.readSave(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MappableContent[][] readContentHeader(DataInputStream stream) throws IOException{
|
||||
|
||||
byte mapped = stream.readByte();
|
||||
|
||||
MappableContent[][] map = new MappableContent[ContentType.values().length][0];
|
||||
|
||||
for(int i = 0; i < mapped; i++){
|
||||
ContentType type = ContentType.values()[stream.readByte()];
|
||||
short total = stream.readShort();
|
||||
map[type.ordinal()] = new MappableContent[total];
|
||||
|
||||
for(int j = 0; j < total; j++){
|
||||
String name = stream.readUTF();
|
||||
map[type.ordinal()][j] = content.getByName(type, fallback.get(name, name));
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public void writeContentHeader(DataOutputStream stream) throws IOException{
|
||||
Array<Content>[] map = content.getContentMap();
|
||||
|
||||
int mappable = 0;
|
||||
for(Array<Content> arr : map){
|
||||
if(arr.size > 0 && arr.first() instanceof MappableContent){
|
||||
mappable++;
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeByte(mappable);
|
||||
for(Array<Content> arr : map){
|
||||
if(arr.size > 0 && arr.first() instanceof MappableContent){
|
||||
stream.writeByte(arr.first().getContentType().ordinal());
|
||||
stream.writeShort(arr.size);
|
||||
for(Content c : arr){
|
||||
stream.writeUTF(((MappableContent)c).name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void read(DataInputStream stream, CounterInputStream counter) throws IOException{
|
||||
for(Region region : regions){
|
||||
counter.resetCount();
|
||||
try{
|
||||
int length = readChunk(stream, region.reader);
|
||||
if(length != counter.count() + 4){
|
||||
throw new IOException("Error reading region \"" + region.name + "\": read length mismatch. Expected: " + length + "; Actual: " + (counter.count() + 4));
|
||||
}
|
||||
}catch(Throwable e){
|
||||
throw new IOException("Error reading region \"" + region.name + "\".", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final void write(DataOutputStream stream) throws IOException{
|
||||
for(Region region : regions){
|
||||
try{
|
||||
writeChunk(stream, region.writer);
|
||||
}catch(Throwable e){
|
||||
throw new IOException("Error writing region \"" + region.name + "\".", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A region of a save file that holds a specific category of information.
|
||||
* Uses: simplify code reuse, provide better error messages, skip unnecessary data.*/
|
||||
protected final class Region{
|
||||
final IORunner<DataOutput> writer;
|
||||
final IORunner<DataInput> reader;
|
||||
final String name;
|
||||
|
||||
public Region(IORunner<DataOutput> writer, IORunner<DataInput> reader, String name){
|
||||
this.writer = writer;
|
||||
this.reader = reader;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
public abstract void write(DataOutputStream stream) throws IOException;
|
||||
|
||||
protected interface IORunner<T>{
|
||||
void accept(T stream) throws IOException;
|
||||
|
@ -1,12 +1,14 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.util.io.CounterInputStream;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.io.versions.Save1;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
@ -110,6 +112,8 @@ public class SaveIO{
|
||||
|
||||
try{
|
||||
stream = new DataOutputStream(os);
|
||||
stream.write(header);
|
||||
stream.writeInt(getVersion().version);
|
||||
getVersion().write(stream);
|
||||
stream.close();
|
||||
}catch(Exception e){
|
||||
@ -135,6 +139,7 @@ public class SaveIO{
|
||||
public static void load(InputStream is) throws SaveException{
|
||||
try(CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){
|
||||
logic.reset();
|
||||
readHeader(stream);
|
||||
int version = stream.readInt();
|
||||
SaveFileVersion ver = versions.get(version);
|
||||
|
||||
@ -150,6 +155,14 @@ public class SaveIO{
|
||||
return versionArray.peek();
|
||||
}
|
||||
|
||||
public static void readHeader(DataInput input) throws IOException{
|
||||
byte[] bytes = new byte[header.length];
|
||||
input.readFully(bytes);
|
||||
if(!Arrays.equals(bytes, header)){
|
||||
throw new IOException("Incorrect header! Expecting: " + Arrays.toString(header) + "; Actual: " + Arrays.toString(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
public static class SaveException extends RuntimeException{
|
||||
public SaveException(Throwable throwable){
|
||||
super(throwable);
|
||||
|
@ -69,6 +69,7 @@ public class Save1 extends SaveFileVersion{
|
||||
stream.writeFloat(state.wavetime); //wave countdown
|
||||
|
||||
Serialization.writeStats(stream, state.stats);
|
||||
|
||||
world.spawner.write(stream);
|
||||
|
||||
writeContentHeader(stream);
|
||||
|
@ -156,8 +156,7 @@ public abstract class BasicGenerator extends RandomGenerator{
|
||||
block = tiles[x][y].block();
|
||||
ore = tiles[x][y].overlay();
|
||||
r.accept(x, y);
|
||||
tiles[x][y] = new Tile(x, y, floor.id, block.id);
|
||||
tiles[x][y].setOverlay(ore);
|
||||
tiles[x][y] = new Tile(x, y, floor.id, ore.id, block.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,7 @@ import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Loadout;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
import io.anuke.mindustry.world.blocks.StaticWall;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
import io.anuke.mindustry.world.blocks.storage.StorageBlock;
|
||||
|
||||
@ -88,12 +87,12 @@ public class MapGenerator extends Generator{
|
||||
tiles[x][y].setBlock(Blocks.air);
|
||||
}
|
||||
|
||||
if(tiles[x][y].block() == Blocks.spawn && enemySpawns != -1){
|
||||
if(tiles[x][y].overlay() == Blocks.spawn && enemySpawns != -1){
|
||||
enemies.add(new Point2(x, y));
|
||||
tiles[x][y].setBlock(Blocks.air);
|
||||
tiles[x][y].setOverlay(Blocks.air);
|
||||
}
|
||||
|
||||
if(tiles[x][y].block() == Blocks.part){
|
||||
if(tiles[x][y].block() instanceof BlockPart){
|
||||
tiles[x][y].setBlock(Blocks.air);
|
||||
}
|
||||
}
|
||||
@ -111,13 +110,15 @@ public class MapGenerator extends Generator{
|
||||
if(((tile.block() instanceof StaticWall
|
||||
&& tiles[newX][newY].block() instanceof StaticWall)
|
||||
|| (tile.block() == Blocks.air && !tiles[newX][newY].block().synthetic())
|
||||
|| (tiles[newX][newY].block() == Blocks.air && tile.block() instanceof StaticWall)) && tiles[newX][newY].block() != Blocks.spawn && tile.block() != Blocks.spawn){
|
||||
|| (tiles[newX][newY].block() == Blocks.air && tile.block() instanceof StaticWall))){
|
||||
tile.setBlock(tiles[newX][newY].block());
|
||||
}
|
||||
|
||||
if(distortFloor){
|
||||
tile.setFloor(tiles[newX][newY].floor());
|
||||
tile.setOverlay(tiles[newX][newY].overlay());
|
||||
if(tiles[newX][newY].overlay() != Blocks.spawn && tile.overlay() != Blocks.spawn){
|
||||
tile.setOverlay(tiles[newX][newY].overlay());
|
||||
}
|
||||
}
|
||||
|
||||
for(Decoration decor : decorations){
|
||||
@ -150,7 +151,7 @@ public class MapGenerator extends Generator{
|
||||
enemies.shuffle();
|
||||
for(int i = 0; i < enemySpawns; i++){
|
||||
Point2 point = enemies.get(i);
|
||||
tiles[point.x][point.y].setBlock(Blocks.spawn);
|
||||
tiles[point.x][point.y].setOverlay(Blocks.spawn);
|
||||
|
||||
int rad = 10, frad = 12;
|
||||
|
||||
@ -160,7 +161,9 @@ public class MapGenerator extends Generator{
|
||||
double dst = Mathf.dst(x, y);
|
||||
if(dst < frad && Structs.inBounds(wx, wy, tiles) && (dst <= rad || Mathf.chance(0.5))){
|
||||
Tile tile = tiles[wx][wy];
|
||||
tile.clearOverlay();
|
||||
if(tile.overlay() != Blocks.spawn){
|
||||
tile.clearOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,7 @@ public abstract class RandomGenerator extends Generator{
|
||||
block = Blocks.air;
|
||||
ore = Blocks.air;
|
||||
generate(x, y);
|
||||
tiles[x][y] = new Tile(x, y, floor.id, block.id);
|
||||
tiles[x][y].setOverlay(ore);
|
||||
tiles[x][y] = new Tile(x, y, floor.id, ore.id, block.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class DesertWastesGenerator extends BasicGenerator{
|
||||
overlay(tiles, Blocks.sand, Blocks.pebbles, 0.15f, 5, 0.8f, 30f, 0.62f);
|
||||
//scatter(tiles, Blocks.sandRocks, Blocks.creeptree, 1f);
|
||||
|
||||
tiles[endX][endY].setBlock(Blocks.spawn);
|
||||
tiles[endX][endY].setOverlay(Blocks.spawn);
|
||||
loadout.setup(spawnX, spawnY);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public class OvergrowthGenerator extends BasicGenerator{
|
||||
noise(tiles, Blocks.darksandTaintedWater, Blocks.duneRocks, 4, 0.7f, 120f, 0.64f);
|
||||
//scatter(tiles, Blocks.sporePine, Blocks.whiteTreeDead, 1f);
|
||||
|
||||
tiles[endX][endY].setBlock(Blocks.spawn);
|
||||
tiles[endX][endY].setOverlay(Blocks.spawn);
|
||||
loadout.setup(spawnX, spawnY);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ public class NetworkIO{
|
||||
stream.writeInt(player.id);
|
||||
player.write(stream);
|
||||
|
||||
world.spawner.write(stream);
|
||||
SaveIO.getSaveWriter().writeMap(stream);
|
||||
|
||||
stream.write(Team.all.length);
|
||||
@ -98,7 +97,6 @@ public class NetworkIO{
|
||||
player.add();
|
||||
|
||||
//map
|
||||
world.spawner.read(stream);
|
||||
SaveIO.getSaveWriter().readMap(stream);
|
||||
world.setMap(new Map(customMapDirectory.child(map), 0, 0, new ObjectMap<>(), true));
|
||||
|
||||
|
@ -18,7 +18,7 @@ public class LegacyColorMapper implements ContentList{
|
||||
public void load(){
|
||||
defaultValue = new LegacyBlock(Blocks.stone, Blocks.air);
|
||||
|
||||
map("ff0000", Blocks.stone, Blocks.spawn);
|
||||
map("ff0000", Blocks.stone, Blocks.air, Blocks.spawn);
|
||||
map("00ff00", Blocks.stone);
|
||||
map("323232", Blocks.stone);
|
||||
map("646464", Blocks.stone, Blocks.rocks);
|
||||
@ -60,9 +60,7 @@ public class LegacyColorMapper implements ContentList{
|
||||
public final Block ore;
|
||||
|
||||
public LegacyBlock(Block floor, Block wall){
|
||||
this.floor = (Floor)floor;
|
||||
this.wall = wall;
|
||||
this.ore = null;
|
||||
this(floor, wall, Blocks.air);
|
||||
}
|
||||
|
||||
public LegacyBlock(Block floor, Block wall, Block ore){
|
||||
|
@ -36,10 +36,11 @@ public class Tile implements Position, TargetTrait{
|
||||
block = floor = (Floor)Blocks.air;
|
||||
}
|
||||
|
||||
public Tile(boolean __removeThisLater, int x, int y, short floor, short overlay){
|
||||
public Tile(int x, int y, short floor, short overlay, short wall){
|
||||
this.x = (short)x;
|
||||
this.y = (short)y;
|
||||
this.floor = (Floor)content.block(floor);
|
||||
this.block = content.block(wall);
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user