From 6c8d80777c5e096454290ce015fefbe8da7a89ba Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 11 Mar 2019 11:43:23 -0400 Subject: [PATCH] Removed useless name mapping / Cleanup --- .../anuke/mindustry/editor/DrawOperation.java | 15 +- .../io/anuke/mindustry/editor/MapEditor.java | 93 +++++++----- .../mindustry/editor/MapEditorDialog.java | 10 +- .../mindustry/editor/MapResizeDialog.java | 10 +- .../io/anuke/mindustry/editor/MapView.java | 5 +- core/src/io/anuke/mindustry/io/MapIO.java | 67 ++++++--- .../anuke/mindustry/io/SaveFileVersion.java | 60 ++++++-- core/src/io/anuke/mindustry/maps/Map.java | 23 ++- core/src/io/anuke/mindustry/maps/Maps.java | 141 +++++++----------- .../mindustry/ui/dialogs/LoadDialog.java | 2 +- .../mindustry/ui/dialogs/MapsDialog.java | 22 +-- tests/src/test/java/ApplicationTests.java | 4 +- tests/src/test/java/MapTests.java | 11 ++ 13 files changed, 251 insertions(+), 212 deletions(-) create mode 100644 tests/src/test/java/MapTests.java diff --git a/core/src/io/anuke/mindustry/editor/DrawOperation.java b/core/src/io/anuke/mindustry/editor/DrawOperation.java index e1b09d2325..49765644b5 100755 --- a/core/src/io/anuke/mindustry/editor/DrawOperation.java +++ b/core/src/io/anuke/mindustry/editor/DrawOperation.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.editor; +import io.anuke.annotations.Annotations.Struct; import io.anuke.arc.collection.LongArray; -import io.anuke.arc.util.Pack; public class DrawOperation{ private LongArray array = new LongArray(); @@ -10,8 +10,8 @@ public class DrawOperation{ return array.isEmpty(); } - public void addOperation(int xy, byte type, byte from, byte to){ - array.add(Pack.longInt(xy, Pack.intBytes(type, from, to, (byte)0))); + public void addOperation(long op){ + array.add(op); } public void undo(MapEditor editor){ @@ -25,4 +25,13 @@ public class DrawOperation{ long l = array.get(i); } } + + @Struct + class TileOpStruct{ + short x; + short y; + byte type; + byte from; + byte to; + } } diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index bb5f4a24ec..afa19d6f0e 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.editor; +import io.anuke.arc.collection.GridBits; import io.anuke.arc.collection.ObjectMap; import io.anuke.arc.math.Mathf; import io.anuke.arc.util.Pack; @@ -7,6 +8,7 @@ import io.anuke.arc.util.Structs; import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.gen.TileOp; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Floor; @@ -19,11 +21,16 @@ public class MapEditor{ private ObjectMap tags = new ObjectMap<>(); private MapRenderer renderer = new MapRenderer(this); + private Tile[][] tiles; - private int brushSize = 1; - private int rotation; - private Block drawBlock = Blocks.stone; - private Team drawTeam = Team.blue; + private OperationStack stack = new OperationStack(); + private DrawOperation op; + private GridBits used; + + public int brushSize = 1; + public int rotation; + public Block drawBlock = Blocks.stone; + public Team drawTeam = Team.blue; public ObjectMap getTags(){ return tags; @@ -46,36 +53,16 @@ public class MapEditor{ renderer.resize(map.length, map[0].length); } - public int getDrawRotation(){ - return rotation; + public Tile[][] tiles(){ + return tiles; } - public void setDrawRotation(int rotation){ - this.rotation = rotation; + public int width(){ + return tiles.length; } - public Team getDrawTeam(){ - return drawTeam; - } - - public void setDrawTeam(Team team){ - this.drawTeam = team; - } - - public Block getDrawBlock(){ - return drawBlock; - } - - public void setDrawBlock(Block block){ - this.drawBlock = block; - } - - public int getBrushSize(){ - return brushSize; - } - - public void setBrushSize(int size){ - this.brushSize = size; + public int height(){ + return tiles[0].length; } public void draw(int x, int y, boolean paint){ @@ -229,23 +216,47 @@ public class MapEditor{ } public void resize(int width, int height){ - MapTileData previous = map; - int offsetX = -(width - previous.width())/2, offsetY = -(height - previous.height())/2; + Tile[][] previous = tiles; + int offsetX = -(width - width())/2, offsetY = -(height - height())/2; - map = new MapTileData(width, height); - for(int x = 0; x < map.width(); x++){ - for(int y = 0; y < map.height(); y++){ + tiles = new Tile[width][height]; + for(int x = 0; x < width; x++){ + for(int y = 0; y < height; y++){ int px = offsetX + x, py = offsetY + y; - if(Structs.inBounds(px, py, previous.width(), previous.height())){ - map.write(x, y, DataPosition.floor, previous.read(px, py, DataPosition.floor)); - map.write(x, y, DataPosition.wall, previous.read(px, py, DataPosition.wall)); - map.write(x, y, DataPosition.link, previous.read(px, py, DataPosition.link)); - map.write(x, y, DataPosition.rotationTeam, previous.read(px, py, DataPosition.rotationTeam)); + if(Structs.inBounds(px, py, previous.length, previous[0].length)){ + tiles[x][y] = previous[px][py]; + tiles[x][y].x = (short)x; + tiles[x][y].y = (short)y; }else{ - map.write(x, y, DataPosition.floor, Blocks.stone.id); + tiles[x][y] = new Tile(x, y, Blocks.stone.id, (byte)0); } } } renderer.resize(width, height); } + + public void undo(){ + if(stack.canUndo()){ + stack.undo(this); + } + } + + public void redo(){ + if(stack.canRedo()){ + stack.redo(this); + } + } + + public void addTileOp(long data){ + used.set(TileOp.x(data), TileOp.y(data)); + op.addOperation(data); + } + + public boolean checkUsed(short x, short y){ + if(used == null || used.width() != width() || used.height() != height()){ + used = new GridBits(world.width(), world.height()); + } + + return used.get(x, y); + } } diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 42d8103856..6ff2b6cbff 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -291,14 +291,11 @@ public class MapEditorDialog extends Dialog implements Disposable{ editor.renderer().dispose(); } - public void beginEditMap(InputStream is){ + public void beginEditMap(FileHandle file){ ui.loadAnd(() -> { try{ shownWithMap = true; - DataInputStream stream = new DataInputStream(is); - MapMeta meta = MapIO.readMapMeta(stream); - editor.beginEdit(MapIO.readTileData(stream, meta, false), meta.tags, false); - is.close(); + editor.beginEdit(MapIO.readTiles(file)); show(); }catch(Exception e){ Log.err(e); @@ -316,9 +313,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ } public void updateSelectedBlock(){ - Block block = editor.getDrawBlock(); for(int j = 0; j < Vars.content.blocks().size; j++){ - if(block.id == j && j < blockgroup.getButtons().size){ + if(editor.drawBlock.id == j && j < blockgroup.getButtons().size){ blockgroup.getButtons().get(j).setChecked(true); break; } diff --git a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java index b0a9ec2cfb..fb6c4f6adb 100644 --- a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java @@ -1,22 +1,20 @@ package io.anuke.mindustry.editor; -import io.anuke.arc.function.BiConsumer; +import io.anuke.arc.function.IntPositionConsumer; import io.anuke.arc.math.Mathf; import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.mindustry.maps.MapTileData; import io.anuke.mindustry.ui.dialogs.FloatingDialog; public class MapResizeDialog extends FloatingDialog{ private static final int minSize = 50, maxSize = 500, increment = 50; int width, height; - public MapResizeDialog(MapEditor editor, BiConsumer cons){ + public MapResizeDialog(MapEditor editor, IntPositionConsumer cons){ super("$editor.resizemap"); shown(() -> { cont.clear(); - MapTileData data = editor.getMap(); - width = data.width(); - height = data.height(); + width = editor.width(); + height = editor.height(); Table table = new Table(); diff --git a/core/src/io/anuke/mindustry/editor/MapView.java b/core/src/io/anuke/mindustry/editor/MapView.java index 222694d7a5..18fe4b48cf 100644 --- a/core/src/io/anuke/mindustry/editor/MapView.java +++ b/core/src/io/anuke/mindustry/editor/MapView.java @@ -19,6 +19,7 @@ import io.anuke.arc.scene.event.Touchable; import io.anuke.arc.scene.ui.TextField; import io.anuke.arc.scene.ui.layout.Unit; import io.anuke.arc.util.Tmp; +import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.input.Binding; import io.anuke.mindustry.ui.GridImage; import io.anuke.mindustry.world.Pos; @@ -28,8 +29,8 @@ import static io.anuke.mindustry.Vars.*; public class MapView extends Element implements GestureListener{ private MapEditor editor; private EditorTool tool = EditorTool.pencil; - private OperationStack stack = new OperationStack(); - private DrawOperation op; + //private OperationStack stack = new OperationStack(); + //private DrawOperation op; private GridBits used; private Bresenham2 br = new Bresenham2(); private boolean updated = false; diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index d2f8d7a7c9..1fc8901943 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -5,6 +5,7 @@ import io.anuke.arc.collection.ObjectMap.Entry; import io.anuke.arc.files.FileHandle; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Pixmap; +import io.anuke.arc.graphics.Pixmap.Format; import io.anuke.arc.util.Pack; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.game.MappableContent; @@ -41,10 +42,21 @@ public class MapIO{ } //TODO implement - public static Pixmap unfinished_generatePreview(Map map){ + public static Pixmap generatePreview(Map map){ return null; } + public static Pixmap generatePreview(Tile[][] tiles){ + Pixmap pixmap = new Pixmap(tiles.length, tiles[0].length, Format.RGBA8888); + for(int x = 0; x < pixmap.getWidth(); x++){ + for(int y = 0; y < pixmap.getHeight(); y++){ + Tile tile = tiles[x][y]; + pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.getTeam())); + } + } + return pixmap; + } + //TODO implement /**Reads a pixmap in the 3.5 pixmap format.*/ public static Tile[][] unfinished_readLegacyPixmap(Pixmap pixmap){ @@ -64,7 +76,7 @@ public class MapIO{ return Color.rgba8888(wall.solid ? wall.color : floor.color); } - public static void writeMap(Map map, Tile[][] tiles, OutputStream output) throws IOException{ + public static void writeMap(OutputStream output, Map map, Tile[][] tiles) throws IOException{ try(DataOutputStream stream = new DataOutputStream(output)){ stream.writeInt(version); stream.writeInt(Version.build); @@ -103,7 +115,7 @@ public class MapIO{ i += consecutives; } - //blocks + //then blocks for(int i = 0; i < tiles.length * tiles[0].length; i++){ Tile tile = world.tile(i % world.width(), i / world.width()); stream.writeByte(tile.getBlockID()); @@ -135,8 +147,8 @@ public class MapIO{ } } - public static Map readMap(String useName, InputStream input) throws IOException{ - try(DataInputStream stream = new DataInputStream(input)){ + public static Map readMap(FileHandle file, boolean custom) throws IOException{ + try(DataInputStream stream = new DataInputStream(file.read())){ ObjectMap tags = new ObjectMap<>(); //meta is uncompressed @@ -151,34 +163,53 @@ public class MapIO{ tags.put(name, value); } - return new Map(useName, width, height); + return new Map(file, width, height, tags, custom); } } public static Tile[][] readTiles(Map map, Tile[][] tiles) throws IOException{ - return readTiles(map.stream.get(), map.width, map.height, tiles); + return readTiles(map.file, map.width, map.height, tiles); } - public static Tile[][] readTiles(InputStream input, int width, int height, Tile[][] tiles) throws IOException{ - readMap("this map name is utterly irrelevant", input); + public static Tile[][] readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{ + readMap(file, false); - try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){ + try(DataInputStream stream = new DataInputStream(new InflaterInputStream(file.read()))){ MappableContent[][] c = SaveIO.getSaveWriter().readContentHeader(stream); try{ content.setTemporaryMapper(c); - //TODO 2-phase rle + //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 wallid = stream.readByte(); byte oreid = stream.readByte(); + int consecutives = stream.readUnsignedByte(); - Tile tile = new Tile(x, y, floorid, wallid); + tiles[x][y] = new Tile(x, y, floorid, (byte)0); + tiles[x][y].setOre(oreid); - if(wallid == Blocks.part.id){ + for(int j = i + 1; j < i + 1 + consecutives; j++){ + int newx = j % width, newy = j / width; + Tile newTile = new Tile(newx, newy, floorid, (byte)0); + newTile.setOre(oreid); + tiles[newx][newy] = newTile; + } + + 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[x][y]; + tile.setBlock(block); + + if(block == Blocks.part){ tile.link = stream.readByte(); }else if(tile.entity != null){ byte tr = stream.readByte(); @@ -192,20 +223,16 @@ public class MapIO{ tile.setRotation(rotation); tile.entity.readConfig(stream); - }else if(wallid == 0){ + }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; - Tile newTile = new Tile(newx, newy, floorid, wallid); - newTile.setOre(oreid); - tiles[newx][newy] = newTile; + tiles[newx][newy].setBlock(block); } i += consecutives; } - - tiles[x][y] = tile; } return tiles; diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index fe0c646c09..5143c982b9 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -14,6 +14,7 @@ import io.anuke.mindustry.game.Rules; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.gen.Serialization; import io.anuke.mindustry.type.ContentType; +import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.BlockPart; @@ -42,17 +43,36 @@ public abstract class SaveFileVersion{ return new SaveMeta(version, time, playtime, build, map, wave, rules); } - //TODO 2-phase rle public void writeMap(DataOutputStream stream) throws IOException{ //write world size stream.writeShort(world.width()); stream.writeShort(world.height()); + //floor first for(int i = 0; i < world.width() * world.height(); i++){ Tile tile = world.tile(i % world.width(), i / world.width()); - stream.writeByte(tile.getFloorID()); + stream.writeByte(tile.getOre()); + 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 || nextTile.getOre() != tile.getOre()){ + 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.writeByte(tile.getBlockID()); if(tile.block() instanceof BlockPart){ @@ -68,13 +88,14 @@ public abstract class SaveFileVersion{ tile.entity.writeConfig(stream); tile.entity.write(stream); - }else if(tile.block() == Blocks.air){ + }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.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air){ + if(nextTile.block() != tile.block()){ break; } @@ -87,7 +108,6 @@ public abstract class SaveFileVersion{ } } - //TODO 2-phase rle public void readMap(DataInputStream stream) throws IOException{ short width = stream.readShort(); short height = stream.readShort(); @@ -96,14 +116,33 @@ public abstract class SaveFileVersion{ 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; byte floorid = stream.readByte(); - byte wallid = stream.readByte(); + byte oreid = stream.readByte(); + int consecutives = stream.readUnsignedByte(); - Tile tile = new Tile(x, y, floorid, wallid); + tiles[x][y] = new Tile(x, y, floorid, (byte)0); + tiles[x][y].setOre(oreid); - if(wallid == Blocks.part.id){ + for(int j = i + 1; j < i + 1 + consecutives; j++){ + int newx = j % width, newy = j / width; + Tile newTile = new Tile(newx, newy, floorid, (byte)0); + newTile.setOre(oreid); + tiles[newx][newy] = newTile; + } + + 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[x][y]; + + if(block == Blocks.part){ tile.link = stream.readByte(); }else if(tile.entity != null){ byte tr = stream.readByte(); @@ -123,13 +162,12 @@ public abstract class SaveFileVersion{ tile.entity.readConfig(stream); tile.entity.read(stream); - }else if(wallid == 0){ + }else{ 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; + tiles[newx][newy].setBlock(block); } i += consecutives; diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index 46c034ba64..715a21895f 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -2,40 +2,35 @@ package io.anuke.mindustry.maps; import io.anuke.arc.Core; import io.anuke.arc.collection.ObjectMap; -import io.anuke.arc.function.Supplier; +import io.anuke.arc.files.FileHandle; import io.anuke.arc.graphics.Texture; -import java.io.InputStream; - public class Map{ - /** Internal map name. This is the filename, without any extensions.*/ - public final String name; /** Whether this is a custom map.*/ public final boolean custom; /** Metadata. Author description, display name, etc.*/ public final ObjectMap tags; - /** Supplies a new input stream with the data of this map.*/ - public final Supplier stream; + /** Base file of this map.*/ + public final FileHandle file; /**Map width/height, shorts.*/ public int width, height; /** Preview texture.*/ public Texture texture; - public Map(String name, int width, int height, ObjectMap tags, boolean custom, Supplier streamSupplier){ - this.name = name; + public Map(FileHandle file, int width, int height, ObjectMap tags, boolean custom){ this.custom = custom; this.tags = tags; - this.stream = streamSupplier; + this.file = file; this.width = width; this.height = height; } - public Map(String name, int width, int height){ - this(name, width, height, new ObjectMap<>(), true, () -> null); + public String fileName(){ + return file.nameWithoutExtension(); } public String getDisplayName(){ - return tags.get("name", name); + return tags.get("name", fileName()); } public String author(){ @@ -57,7 +52,7 @@ public class Map{ @Override public String toString(){ return "Map{" + - "name='" + name + '\'' + + "file='" + file + '\'' + ", custom=" + custom + ", tags=" + tags + '}'; diff --git a/core/src/io/anuke/mindustry/maps/Maps.java b/core/src/io/anuke/mindustry/maps/Maps.java index 2bd7823ad5..355f151658 100644 --- a/core/src/io/anuke/mindustry/maps/Maps.java +++ b/core/src/io/anuke/mindustry/maps/Maps.java @@ -1,166 +1,125 @@ package io.anuke.mindustry.maps; import io.anuke.arc.Core; +import io.anuke.arc.collection.Array; import io.anuke.arc.files.FileHandle; import io.anuke.arc.graphics.Texture; -import io.anuke.arc.collection.Array; import io.anuke.arc.util.Disposable; -import io.anuke.arc.collection.ObjectMap; -import io.anuke.mindustry.io.MapIO; -import io.anuke.arc.function.Supplier; import io.anuke.arc.util.Log; +import io.anuke.mindustry.io.MapIO; +import io.anuke.mindustry.world.Tile; -import java.io.DataInputStream; import java.io.IOException; -import java.io.InputStream; import static io.anuke.mindustry.Vars.*; public class Maps implements Disposable{ - /**List of all built-in maps.*/ - private static final String[] defaultMapNames = {}; - /**Tile format version.*/ - private static final int version = 0; + /** List of all built-in maps. */ + private static final String[] defaultMapNames = {"impact0079"}; + /** All maps stored in an ordered array. */ + private Array maps = new Array<>(); - /**Maps map names to the real maps.*/ - private ObjectMap maps = new ObjectMap<>(); - /**All maps stored in an ordered array.*/ - private Array allMaps = new Array<>(); - /**Temporary array used for returning things.*/ - private Array returnArray = new Array<>(); - - /**Returns a list of all maps, including custom ones.*/ + /** Returns a list of all maps, including custom ones. */ public Array all(){ - return allMaps; + return maps; } - /**Returns a list of only custom maps.*/ + /** Returns a list of only custom maps. */ public Array customMaps(){ - returnArray.clear(); - for(Map map : allMaps){ - if(map.custom) returnArray.add(map); - } - return returnArray; + return maps.select(m -> m.custom); } - /**Returns a list of only default maps.*/ + /** Returns a list of only default maps. */ public Array defaultMaps(){ - returnArray.clear(); - for(Map map : allMaps){ - if(!map.custom) returnArray.add(map); - } - return returnArray; + return maps.select(m -> !m.custom); } - /**Returns map by internal name.*/ - public Map getByName(String name){ - return maps.get(name); - } - - /**Loads a map from the map folder and returns it. Should only be used for zone maps. - * Does not add this map to the map list.*/ + /** + * Loads a map from the map folder and returns it. Should only be used for zone maps. + * Does not add this map to the map list. + */ public Map loadInternalMap(String name){ FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension); - try(DataInputStream ds = new DataInputStream(file.read())) { - return new Map(name, MapIO.readMapMeta(ds), false, file::read); + try{ + return MapIO.readMap(file, false); }catch(IOException e){ throw new RuntimeException(e); } } - /**Load all maps. Should be called at application start.*/ + /** Load all maps. Should be called at application start. */ public void load(){ try{ - for (String name : defaultMapNames) { + for(String name : defaultMapNames){ FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension); - loadMap(file.nameWithoutExtension(), file::read, false); + loadMap(file, false); } - }catch (IOException e){ + }catch(IOException e){ throw new RuntimeException(e); } loadCustomMaps(); } - /**Save a map. This updates all values and stored data necessary.*/ - public void saveMap(String name, MapTileData data, ObjectMap tags){ + /** Save a map. This updates all values and stored data necessary. */ + public void saveMap(Map map, Tile[][] data){ try{ - //create copy of tags to prevent mutation later - ObjectMap newTags = new ObjectMap<>(); - newTags.putAll(tags); - tags = newTags; - - FileHandle file = customMapDirectory.child(name + "." + mapExtension); - MapIO.writeMap(file.write(false), tags, data); - - if(maps.containsKey(name)){ - if(maps.get(name).texture != null) { - maps.get(name).texture.dispose(); - maps.get(name).texture = null; - } - allMaps.removeValue(maps.get(name), true); - } - - Map map = new Map(name, new MapMeta(version, tags, data.width(), data.height(), null), true, getStreamFor(name)); + MapIO.writeMap(map.file.write(false), map, data); if(!headless){ - map.texture = new Texture(MapIO.generatePixmap(data)); + map.texture = new Texture(MapIO.generatePreview(data)); } - allMaps.add(map); - - maps.put(name, map); - }catch (IOException e){ + maps.add(map); + }catch(IOException e){ throw new RuntimeException(e); } } - /**Removes a map completely.*/ + /** Import a map, then save it. This updates all values and stored data necessary. */ + public void importMap(FileHandle file, Map map){ + file.copyTo(customMapDirectory.child(file.name())); + if(!headless){ + map.texture = new Texture(MapIO.generatePreview(map)); + } + maps.add(map); + } + + /** Removes a map completely. */ public void removeMap(Map map){ if(map.texture != null){ map.texture.dispose(); map.texture = null; } - maps.remove(map.name); - allMaps.removeValue(map, true); - - customMapDirectory.child(map.name + "." + mapExtension).delete(); + maps.remove(map); + map.file.delete(); } - private void loadMap(String name, Supplier supplier, boolean custom) throws IOException{ - try(DataInputStream ds = new DataInputStream(supplier.get())) { - MapMeta meta = MapIO.readMapMeta(ds); - Map map = new Map(name, meta, custom, supplier); + private void loadMap(FileHandle file, boolean custom) throws IOException{ + Map map = MapIO.readMap(file, custom); - if (!headless){ - map.texture = new Texture(MapIO.generatePixmap(MapIO.readTileData(ds, meta, true))); - } - - maps.put(map.name, map); - allMaps.add(map); + if(!headless){ + map.texture = new Texture(MapIO.generatePreview(map)); } + + maps.add(map); } private void loadCustomMaps(){ for(FileHandle file : customMapDirectory.list()){ try{ if(file.extension().equalsIgnoreCase(mapExtension)){ - loadMap(file.nameWithoutExtension(), file::read, true); + loadMap(file, true); } - }catch (Exception e){ + }catch(Exception e){ Log.err("Failed to load custom map file '{0}'!", file); Log.err(e); } } } - /**Returns an input stream supplier for a given map name.*/ - private Supplier getStreamFor(String name){ - return customMapDirectory.child(name + "." + mapExtension)::read; - } - @Override - public void dispose() { + public void dispose(){ } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java index 1bfccbc6df..5a9c007437 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java @@ -113,7 +113,7 @@ public class LoadDialog extends FloatingDialog{ button.defaults().padBottom(3); button.row(); - button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().meta.name()))); + button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().getDisplayName()))); button.row(); button.add(Core.bundle.format("save.wave", color + slot.getWave())); button.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 402004af76..6ce8745e39 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -17,8 +17,6 @@ import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.ui.BorderImage; -import java.io.DataInputStream; - import static io.anuke.mindustry.Vars.*; public class MapsDialog extends FloatingDialog{ @@ -31,22 +29,18 @@ public class MapsDialog extends FloatingDialog{ buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> { Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> { try{ - DataInputStream stream = new DataInputStream(file.read()); - MapMeta meta = MapIO.readMapMeta(stream); - MapTileData data = MapIO.readTileData(stream, meta, true); - stream.close(); - - String name = meta.tags.get("name", file.nameWithoutExtension()); + Map map = MapIO.readMap(file.read(), file.name(), true, file::read); + String name = map.tags.get("name", file.nameWithoutExtension()); if(world.maps.getByName(name) != null && !world.maps.getByName(name).custom){ ui.showError(Core.bundle.format("editor.import.exists", name)); }else if(world.maps.getByName(name) != null){ ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> { - world.maps.saveMap(name, data, meta.tags); + world.maps.importMap(file, map); setup(); }); }else{ - world.maps.saveMap(name, data, meta.tags); + world.maps.importMap(file, map); setup(); } @@ -87,7 +81,7 @@ public class MapsDialog extends FloatingDialog{ TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get(); button.clearChildren(); button.margin(9); - button.add(map.meta.tags.get("name", map.name)).width(mapsize - 18f).center().get().setEllipsis(true); + button.add(map.getDisplayName()).width(mapsize - 18f).center().get().setEllipsis(true); button.row(); button.addImage("white").growX().pad(4).color(Color.GRAY); button.row(); @@ -127,15 +121,15 @@ public class MapsDialog extends FloatingDialog{ t.add("$editor.name").padRight(10).color(Color.GRAY).padTop(0); t.row(); - t.add(map.meta.tags.get("name", map.name)).growX().wrap().padTop(2); + t.add(map.getDisplayName()).growX().wrap().padTop(2); t.row(); t.add("$editor.author").padRight(10).color(Color.GRAY); t.row(); - t.add(map.meta.author()).growX().wrap().padTop(2); + t.add(map.author()).growX().wrap().padTop(2); t.row(); t.add("$editor.description").padRight(10).color(Color.GRAY).top(); t.row(); - t.add(map.meta.description()).growX().wrap().padTop(2); + t.add(map.description()).growX().wrap().padTop(2); t.row(); t.add("$editor.oregen.info").padRight(10).color(Color.GRAY); }).height(mapsize).width(mapsize); diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index f67122d9a7..91958bf7ab 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -194,8 +194,8 @@ public class ApplicationTests{ resetWorld(); SaveIO.loadFromSlot(0); - assertEquals(world.width(), map.meta.width); - assertEquals(world.height(), map.meta.height); + assertEquals(world.width(), map.width); + assertEquals(world.height(), map.height); assertTrue(state.teams.get(defaultTeam).cores.size > 0); } diff --git a/tests/src/test/java/MapTests.java b/tests/src/test/java/MapTests.java new file mode 100644 index 0000000000..689c7f5d22 --- /dev/null +++ b/tests/src/test/java/MapTests.java @@ -0,0 +1,11 @@ +import org.junit.jupiter.api.BeforeAll; + +public class MapTests{ + + @BeforeAll + static void launchApplication(){ + ApplicationTests.launchApplication(); + } + + //TODO +}