diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 9ec221e850..b0ce757754 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -20,8 +20,6 @@ import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.maps.Maps; import io.anuke.mindustry.maps.generators.Generator; import io.anuke.mindustry.type.ItemStack; diff --git a/core/src/io/anuke/mindustry/editor/DrawOperation.java b/core/src/io/anuke/mindustry/editor/DrawOperation.java index b6b7d13f76..03ca6be4a1 100755 --- a/core/src/io/anuke/mindustry/editor/DrawOperation.java +++ b/core/src/io/anuke/mindustry/editor/DrawOperation.java @@ -3,8 +3,6 @@ package io.anuke.mindustry.editor; import io.anuke.arc.collection.Array; import io.anuke.arc.collection.IntSet; import io.anuke.arc.util.Pack; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; public class DrawOperation{ /** diff --git a/core/src/io/anuke/mindustry/editor/EditorTool.java b/core/src/io/anuke/mindustry/editor/EditorTool.java index 981fa88057..c773aba50e 100644 --- a/core/src/io/anuke/mindustry/editor/EditorTool.java +++ b/core/src/io/anuke/mindustry/editor/EditorTool.java @@ -5,9 +5,6 @@ import io.anuke.arc.function.IntPositionConsumer; import io.anuke.arc.util.Pack; import io.anuke.arc.util.Structs; import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.DataPosition; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.Floor; diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index e7fee69dbd..9ec4881e6f 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -8,9 +8,6 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.editor.DrawOperation.TileOperation; import io.anuke.mindustry.game.Team; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.DataPosition; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.Floor; diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index fa534655b8..841213d8e2 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -23,8 +23,6 @@ import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapMeta; -import io.anuke.mindustry.maps.MapTileData; import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.mindustry.world.Block; diff --git a/core/src/io/anuke/mindustry/editor/MapRenderer.java b/core/src/io/anuke/mindustry/editor/MapRenderer.java index fac6adf728..439cd97bec 100644 --- a/core/src/io/anuke/mindustry/editor/MapRenderer.java +++ b/core/src/io/anuke/mindustry/editor/MapRenderer.java @@ -10,7 +10,6 @@ import io.anuke.arc.util.Disposable; import io.anuke.arc.util.Pack; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.graphics.IndexedRenderer; -import io.anuke.mindustry.maps.MapTileData.DataPosition; import io.anuke.mindustry.world.Block; import static io.anuke.mindustry.Vars.content; diff --git a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java index 95a6bb8b21..9aa263b42a 100644 --- a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java @@ -1,6 +1,5 @@ package io.anuke.mindustry.editor; -import io.anuke.mindustry.maps.MapTileData; import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.arc.function.BiConsumer; import io.anuke.arc.scene.ui.ButtonGroup; diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index c92269ef64..da11e47183 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -11,22 +11,20 @@ import io.anuke.arc.util.Structs; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapMeta; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.DataPosition; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.ColorMapper; import io.anuke.mindustry.world.LegacyColorMapper; import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock; +import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.blocks.BlockPart; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; -import static io.anuke.mindustry.Vars.content; +import static io.anuke.mindustry.Vars.*; /** * Reads and writes map files. @@ -148,12 +146,59 @@ public class MapIO{ } } - public static MapMeta readMapMeta(DataInputStream stream) throws IOException{ + public static void writeMap(Map map, Tile[][] tiles, DataOutputStream stream) throws IOException{ + stream.writeInt(version); + stream.writeByte((byte) map.tags.size); + + for(Entry entry : map.tags.entries()){ + stream.writeUTF(entry.key); + stream.writeUTF(entry.value); + } + + stream.writeShort(content.blocks().size); + for(Block block : content.blocks()){ + stream.writeShort(block.id); + stream.writeUTF(block.name); + } + + stream.writeShort(tiles.length); + stream.writeShort(tiles[0].length); + + for(int i = 0; i < tiles.length * tiles[0].length; i++){ + Tile tile = world.tile(i % world.width(), i / world.width()); + + stream.writeByte(tile.getFloorID()); + stream.writeByte(tile.getBlockID()); + + if(tile.block() instanceof BlockPart){ + stream.writeByte(tile.link); + }else if(tile.entity != null){ + stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.getRotation())); //team + rotation + stream.writeShort((short) tile.entity.health); //health + }else if(tile.block() == Blocks.air){ + 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.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air){ + break; + } + + consecutives++; + } + + stream.writeByte(consecutives); + i += consecutives; + } + } + } + + public static Map readMap(DataInputStream stream) throws IOException{ ObjectMap tags = new ObjectMap<>(); IntIntMap map = new IntIntMap(); int version = stream.readInt(); - byte tagAmount = stream.readByte(); for(int i = 0; i < tagAmount; i++){ @@ -168,7 +213,6 @@ public class MapIO{ String name = stream.readUTF(); Block block = content.getByName(ContentType.block, name); if(block == null){ - //Log.info("Map load info: No block with name {0} found.", name); block = Blocks.air; } map.put(id, block.id); @@ -177,7 +221,55 @@ public class MapIO{ int width = stream.readShort(); int height = stream.readShort(); - return new MapMeta(version, tags, width, height, map); + Tile[][] tiles = new Tile[width][height]; + + for(int i = 0; i < width * height; i++){ + int x = i % width, y = i / width; + byte floorid = stream.readByte(); + byte wallid = stream.readByte(); + + Tile tile = new Tile(x, y, floorid, wallid); + + if(wallid == Blocks.blockpart.id){ + tile.link = stream.readByte(); + }else if(tile.entity != null){ + byte tr = stream.readByte(); + short health = stream.readShort(); + + byte team = Pack.leftByte(tr); + byte rotation = Pack.rightByte(tr); + + Team t = Team.all[team]; + + tile.setTeam(Team.all[team]); + tile.entity.health = health; + tile.setRotation(rotation); + + if(tile.entity.items != null) tile.entity.items.read(stream); + if(tile.entity.power != null) tile.entity.power.read(stream); + if(tile.entity.liquids != null) tile.entity.liquids.read(stream); + if(tile.entity.cons != null) tile.entity.cons.read(stream); + + tile.entity.readConfig(stream); + tile.entity.read(stream); + + if(tile.block() == Blocks.core){ + state.teams.get(t).cores.add(tile); + } + }else if(wallid == 0){ + int consecutives = stream.readUnsignedByte(); + + for(int j = i + 1; j < i + 1 + consecutives; j++){ + int newx = j % width, newy = j / width; + Tile newTile = new Tile(newx, newy, floorid, wallid); + tiles[newx][newy] = newTile; + } + + i += consecutives; + } + + tiles[x][y] = tile; + } } public static void writeMapMeta(DataOutputStream stream, MapMeta meta) throws IOException{ diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index 2481d42344..bc61e67049 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -1,8 +1,9 @@ package io.anuke.mindustry.maps; -import io.anuke.arc.graphics.Texture; +import io.anuke.arc.Core; import io.anuke.arc.collection.ObjectMap; import io.anuke.arc.function.Supplier; +import io.anuke.arc.graphics.Texture; import java.io.InputStream; @@ -12,25 +13,45 @@ public class Map{ /** Whether this is a custom map.*/ public final boolean custom; /** Metadata. Author description, display name, etc.*/ - public final MapMeta meta; + public final ObjectMap tags; /** Supplies a new input stream with the data of this map.*/ public final Supplier stream; /** Preview texture.*/ public Texture texture; - public Map(String name, MapMeta meta, boolean custom, Supplier streamSupplier){ + public Map(String name, ObjectMap tags, boolean custom, Supplier streamSupplier){ this.name = name; this.custom = custom; - this.meta = meta; + this.tags = tags; this.stream = streamSupplier; } - public Map(String unknownName, int width, int height){ - this(unknownName, new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null); + public Map(String name){ + this(name, new ObjectMap<>(), true, () -> null); } public String getDisplayName(){ - return meta.tags.get("name", name); + return tags.get("name", name); + } + + public String author(){ + return tag("author"); + } + + public String description(){ + return tag("description"); + } + + public String name(){ + return tag("name"); + } + + public String tag(String name){ + return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Core.bundle.get("unknown"); + } + + public boolean hasOreGen(){ + return !tags.get("oregen", "0").equals("0"); } @Override @@ -38,7 +59,7 @@ public class Map{ return "Map{" + "name='" + name + '\'' + ", custom=" + custom + - ", meta=" + meta + + ", tags=" + tags + '}'; } } diff --git a/core/src/io/anuke/mindustry/maps/MapMeta.java b/core/src/io/anuke/mindustry/maps/MapMeta.java deleted file mode 100644 index 74228aa5b4..0000000000 --- a/core/src/io/anuke/mindustry/maps/MapMeta.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.anuke.mindustry.maps; - -import io.anuke.arc.Core; -import io.anuke.arc.collection.IntIntMap; -import io.anuke.arc.collection.ObjectMap; - -//todo: specify preferred game rules here; can be overriden -public class MapMeta{ - public final int version; - public final ObjectMap tags; - public final int width, height; - public final IntIntMap blockMap; - - public MapMeta(int version, ObjectMap tags, int width, int height, IntIntMap blockMap){ - this.version = version; - this.tags = tags; - this.width = width; - this.height = height; - this.blockMap = blockMap; - } - - public String author(){ - return tag("author"); - } - - public String description(){ - return tag("description"); - } - - public String name(){ - return tag("name"); - } - - public String tag(String name){ - return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Core.bundle.get("unknown"); - } - - public boolean hasOreGen(){ - return !tags.get("oregen", "0").equals("0"); - } - - @Override - public String toString(){ - return "MapMeta{" + - "tags=" + tags + - ", width=" + width + - ", height=" + height + - '}'; - } -} diff --git a/core/src/io/anuke/mindustry/maps/MapTileData.java b/core/src/io/anuke/mindustry/maps/MapTileData.java deleted file mode 100644 index 2948522b95..0000000000 --- a/core/src/io/anuke/mindustry/maps/MapTileData.java +++ /dev/null @@ -1,175 +0,0 @@ -package io.anuke.mindustry.maps; - -import io.anuke.arc.collection.IntIntMap; -import io.anuke.arc.util.Pack; -import io.anuke.arc.util.Structs; -import io.anuke.mindustry.Vars; -import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.world.Block; - -import java.nio.ByteBuffer; - -public class MapTileData{ - /** - * Tile size: 4 bytes.
- * 0: ground tile
- * 1: wall tile
- * 2: rotation + team
- * 3: link (x/y)
- * 4: elevation
- */ - private final static int TILE_SIZE = 5; - - private final ByteBuffer buffer; - private final int width, height; - private final boolean readOnly; - - private IntIntMap map; - - public MapTileData(int width, int height){ - this.width = width; - this.height = height; - this.map = null; - this.readOnly = false; - buffer = ByteBuffer.allocate(width * height * TILE_SIZE); - } - - public MapTileData(byte[] bytes, int width, int height, IntIntMap mapping, boolean readOnly){ - buffer = ByteBuffer.wrap(bytes); - this.width = width; - this.height = height; - this.map = mapping; - this.readOnly = readOnly; - - if(mapping != null && !readOnly){ - buffer.position(0); - TileDataMarker marker = new TileDataMarker(); - for(int i = 0; i < width * height; i++){ - read(marker); - - //strip blockparts from map data, as they can be invalid - if(marker.wall == Blocks.blockpart.id){ - marker.wall = Blocks.air.id; - } - - buffer.position(i * TILE_SIZE); - - //write mapped marker - write(marker); - } - - buffer.position(0); - for(int x = 0; x < width; x ++){ - for(int y = 0; y < height; y ++){ - //add missing blockparts - Block drawBlock = Vars.content.block(read(x, y, DataPosition.wall)); - if(drawBlock.isMultiblock()){ - int offsetx = -(drawBlock.size - 1) / 2; - int offsety = -(drawBlock.size - 1) / 2; - for(int dx = 0; dx < drawBlock.size; dx++){ - for(int dy = 0; dy < drawBlock.size; dy++){ - int worldx = dx + offsetx + x; - int worldy = dy + offsety + y; - - if(Structs.inBounds(worldx, worldy, width, height) && !(dx + offsetx == 0 && dy + offsety == 0)){ - write(worldx, worldy, DataPosition.wall, Blocks.blockpart.id); - write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8))); - } - } - } - } - } - } - buffer.position(0); - this.map = null; - } - } - - public byte[] toArray(){ - return buffer.array(); - } - - public int width(){ - return width; - } - - public int height(){ - return height; - } - - /** - * Write a byte to a specific position. - */ - public void write(int x, int y, DataPosition position, byte data){ - buffer.put((x + width * y) * TILE_SIZE + position.ordinal(), data); - } - - /** - * Gets a byte at a specific position. - */ - public byte read(int x, int y, DataPosition position){ - return buffer.get((x + width * y) * TILE_SIZE + position.ordinal()); - } - - /** - * Reads and returns the next tile data. - */ - public TileDataMarker read(TileDataMarker marker){ - marker.read(buffer); - return marker; - } - - /** - * Writes this tile data marker. - */ - public void write(TileDataMarker marker){ - marker.write(buffer); - } - - /** - * Sets read position to the specified coordinates - */ - public void position(int x, int y){ - buffer.position((x + width * y) * TILE_SIZE); - } - - public TileDataMarker newDataMarker(){ - return new TileDataMarker(); - } - - public enum DataPosition{ - floor, wall, link, rotationTeam, elevation - } - - public class TileDataMarker{ - public byte floor, wall; - public byte link; - public byte rotation; - public byte team; - public byte elevation; - - public void read(ByteBuffer buffer){ - floor = buffer.get(); - wall = buffer.get(); - link = buffer.get(); - byte rt = buffer.get(); - elevation = buffer.get(); - rotation = Pack.leftByte(rt); - team = Pack.rightByte(rt); - - if(map != null){ - floor = (byte) map.get(floor, Blocks.stone.id); - wall = (byte) map.get(wall, 0); - } - } - - public void write(ByteBuffer buffer){ - if(readOnly) throw new IllegalArgumentException("This data is read-only."); - buffer.put(floor); - buffer.put(wall); - buffer.put(link); - buffer.put(Pack.byteByte(rotation, team)); - buffer.put(elevation); - } - } -} diff --git a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java index 92c5def5f9..0c9274c0b1 100644 --- a/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generators/MapGenerator.java @@ -3,8 +3,6 @@ package io.anuke.mindustry.maps.generators; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapTileData; -import io.anuke.mindustry.maps.MapTileData.TileDataMarker; import io.anuke.mindustry.world.Tile; import static io.anuke.mindustry.Vars.world; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 55a1ecb84d..1e31d68f21 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -15,8 +15,6 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.Platform; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.maps.MapMeta; -import io.anuke.mindustry.maps.MapTileData; import io.anuke.mindustry.ui.BorderImage; import java.io.DataInputStream;