Fixed compile errors / New non-crappy undo system

This commit is contained in:
Anuken
2019-03-11 23:06:41 -04:00
parent 6c3ccb259f
commit 0fd0abc6c0
18 changed files with 392 additions and 316 deletions

View File

@ -197,8 +197,8 @@ editor.description = Description:
editor.name = Name:
editor.teams = Teams
editor.elevation = Elevation
editor.errorimageload = Error loading file:\n[accent]{0}
editor.errorimagesave = Error saving file:\n[accent]{0}
editor.errorload = Error loading file:\n[accent]{0}
editor.errorsave = Error saving file:\n[accent]{0}
editor.generate = Generate
editor.resize = Resize
editor.loadmap = Load Map

View File

@ -30,13 +30,15 @@ public class DrawOperation{
class TileOpStruct{
short x;
short y;
/**
* 0: floor
* 1: block
* 2: rotation
*/
byte type;
byte from;
byte to;
}
public enum OpType{
floor,
block,
rotation,
team
}
}

View File

@ -0,0 +1,53 @@
package io.anuke.mindustry.editor;
import io.anuke.mindustry.editor.DrawOperation.OpType;
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;
import static io.anuke.mindustry.Vars.ui;
public class EditorTile extends Tile{
public EditorTile(int x, int y, byte floor, byte wall){
super(x, y, floor, wall);
}
@Override
public void setFloor(Floor type){
Block previous = floor();
if(previous == type) return;
super.setFloor(type);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous.id, type.id));
}
@Override
public void setBlock(Block type){
Block previous = block();
if(previous == type) return;
super.setBlock(type);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous.id, type.id));
}
@Override
public void setTeam(Team team){
byte previous = getTeamID();
if(previous == team.ordinal()) return;
super.setTeam(team);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous, (byte)team.ordinal()));
}
@Override
public void setRotation(byte rotation){
byte previous = getRotation();
if(previous == rotation) return;
super.setRotation(rotation);
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous, rotation));
}
private static void op(long op){
ui.editor.editor.addTileOp(op);
}
}

View File

@ -8,29 +8,32 @@ import io.anuke.arc.util.Pack;
import io.anuke.arc.util.Structs;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.ui;
import static io.anuke.mindustry.Vars.world;
public enum EditorTool{
pick{
public void touched(MapEditor editor, int x, int y){
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
byte bf = editor.getMap().read(x, y, DataPosition.floor);
byte bw = editor.getMap().read(x, y, DataPosition.wall);
byte link = editor.getMap().read(x, y, DataPosition.link);
Tile tile = editor.tile(x, y);
Block floor = tile.floor(), block = tile.block();
byte link = tile.getLinkByte();
if(link != 0){
x -= (Pack.leftByte(link) - 8);
y -= (Pack.rightByte(link) - 8);
bf = editor.getMap().read(x, y, DataPosition.floor);
bw = editor.getMap().read(x, y, DataPosition.wall);
tile = editor.tile(x, y);
block = tile.block();
}
Block block = content.block(bw == 0 ? bf : bw);
editor.setDrawBlock(block);
editor.drawBlock = block == Blocks.air ? floor : block;
ui.editor.updateSelectedBlock();
}
},
@ -64,7 +67,7 @@ public enum EditorTool{
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint(), editor.getDrawBlock(), 0.012);
editor.draw(x, y, isPaint(), editor.drawBlock, 0.012);
}
},
line{
@ -78,56 +81,57 @@ public enum EditorTool{
}
IntArray stack = new IntArray();
int width;
byte be, dest;
boolean floor;
MapTileData data;
Block dest;
boolean isfloor;
MapEditor data;
public void touched(MapEditor editor, int x, int y){
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
Tile tile = editor.tile(x, y);
if(editor.getDrawBlock().isMultiblock()){
if(editor.drawBlock.isMultiblock()){
//don't fill multiblocks, thanks
pencil.touched(editor, x, y);
return;
}
data = editor.getMap();
data = editor;
isfloor = editor.drawBlock instanceof Floor;
floor = editor.getDrawBlock() instanceof Floor;
Block floor = tile.floor();
Block block = tile.block();
boolean synth = editor.drawBlock.synthetic();
byte bf = data.read(x, y, DataPosition.floor);
byte bw = data.read(x, y, DataPosition.wall);
boolean synth = editor.getDrawBlock().synthetic();
byte brt = Pack.byteByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal());
dest = isfloor ? floor : block;
Block draw = editor.drawBlock;
dest = floor ? bf : bw;
byte draw = editor.getDrawBlock().id;
if(dest == draw || content.block(bw) instanceof BlockPart || content.block(bw).isMultiblock()){
if(dest == draw || block == Blocks.part || block.isMultiblock()){
return;
}
width = world.width();
int width = world.width();
int height = world.height();
IntPositionConsumer writer = (px, py) -> {
TileDataMarker prev = editor.getPrev(px, py, false);
Tile write = editor.tile(px, py);
if(floor){
data.write(px, py, DataPosition.floor, draw);
if(isfloor){
write.setFloor((Floor)draw);
}else{
data.write(px, py, DataPosition.wall, draw);
write.setBlock(draw);
}
if(synth){
data.write(px, py, DataPosition.rotationTeam, brt);
write.setTeam(editor.drawTeam);
}
editor.onWrite(px, py, prev);
if(draw.rotate){
write.setRotation((byte)editor.rotation);
}
};
if(isAlt()){
//fill all of the same type regardless of borders
for(int cx = 0; cx < width; cx++){
for(int cy = 0; cy < height; cy++){
if(eq(cx, cy)){
@ -136,28 +140,28 @@ public enum EditorTool{
}
}
}else if(isAlt2()){
//fill all teams.
for(int cx = 0; cx < width; cx++){
for(int cy = 0; cy < height; cy++){
byte w = data.read(cx, cy, DataPosition.wall);
if(content.block(w).synthetic()){
TileDataMarker prev = editor.getPrev(cx, cy, false);
data.write(cx, cy, DataPosition.rotationTeam, (byte)editor.getDrawTeam().ordinal());
editor.onWrite(cx, cy, prev);
Tile write = editor.tile(cx, cy);
if(write.block().synthetic()){
write.setTeam(editor.drawTeam);
}
}
}
}else{
//normal fill
int x1;
boolean spanAbove, spanBelow;
stack.clear();
stack.add(asi(x, y));
stack.add(Pos.get(x, y));
while(stack.size > 0){
int popped = stack.pop();
x = popped % width;
y = popped / width;
x = Pos.x(popped);
y = Pos.y(popped);
x1 = x;
while(x1 >= 0 && eq(x1, y)) x1--;
@ -167,14 +171,14 @@ public enum EditorTool{
writer.accept(x1, y);
if(!spanAbove && y > 0 && eq(x1, y - 1)){
stack.add(asi(x1, y - 1));
stack.add(Pos.get(x1, y - 1));
spanAbove = true;
}else if(spanAbove && y > 0 && eq(x1, y - 1)){
}else if(spanAbove && eq(x1, y - 1)){
spanAbove = false;
}
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
stack.add(asi(x1, y + 1));
stack.add(Pos.get(x1, y + 1));
spanBelow = true;
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
spanBelow = false;
@ -186,15 +190,9 @@ public enum EditorTool{
}
boolean eq(int px, int py){
byte nbf = data.read(px, py, DataPosition.floor);
byte nbw = data.read(px, py, DataPosition.wall);
byte nbe = data.read(px, py, DataPosition.elevation);
Tile tile = data.tile(px, py);
return (floor ? nbf : nbw) == dest && nbe == be;
}
int asi(int x, int y){
return x + y * width;
return (isfloor ? tile.floor() : tile.block()) == dest;
}
},
zoom;

View File

@ -1,19 +1,21 @@
package io.anuke.mindustry.editor;
import io.anuke.arc.collection.GridBits;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.math.Mathf;
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.game.Team;
import io.anuke.mindustry.gen.TileOp;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import static io.anuke.mindustry.Vars.content;
import java.io.IOException;
import static io.anuke.mindustry.Vars.world;
public class MapEditor{
@ -24,8 +26,8 @@ public class MapEditor{
private Tile[][] tiles;
private OperationStack stack = new OperationStack();
private DrawOperation op;
private GridBits used;
private DrawOperation currentOp;
private boolean loading;
public int brushSize = 1;
public int rotation;
@ -36,27 +38,70 @@ public class MapEditor{
return tags;
}
public void beginEdit(Tile[][] map, ObjectMap<String, String> tags, boolean clear){
public void beginEdit(int width, int height){
reset();
this.brushSize = 1;
this.tags = tags;
loading = true;
tiles = createTiles(width, height);
renderer.resize(width(), height());
loading = false;
}
if(clear){
for(int x = 0; x < map.length; x++){
for(int y = 0; y < map[0].length; y++){
map[x][y].setFloor((Floor)Blocks.stone);
}
public void beginEdit(Map map) throws IOException{
reset();
loading = true;
tiles = createTiles(map.width, map.height);
tags.putAll(map.tags);
MapIO.readTiles(map, tiles);
renderer.resize(width(), height());
loading = false;
}
public void beginEdit(Tile[][] tiles) throws IOException{
reset();
this.tiles = tiles;
renderer.resize(width(), height());
}
public void load(Runnable r){
loading = true;
r.run();
loading = false;
}
/**Creates a 2-D array of EditorTiles with stone as the floor block.*/
public Tile[][] createTiles(int width, int height){
tiles = new Tile[width][height];
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
}
}
return tiles;
}
public Map createMap(FileHandle file){
return new Map(file, width(), height(), new ObjectMap<>(tags), true);
}
private void reset(){
clearOp();
brushSize = 1;
drawBlock = Blocks.stone;
renderer.resize(map.length, map[0].length);
tags = new ObjectMap<>();
}
public Tile[][] tiles(){
return tiles;
}
public Tile tile(int x, int y){
return tiles[x][y];
}
public int width(){
return tiles.length;
}
@ -74,9 +119,7 @@ public class MapEditor{
}
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
byte writeID = drawBlock.id;
byte partID = Blocks.part.id;
byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
//byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
@ -94,52 +137,44 @@ public class MapEditor{
int worldy = dy + offsety + y;
if(Structs.inBounds(worldx, worldy, world.width(), world.height())){
TileDataMarker prev = getPrev(worldx, worldy, false);
Tile tile = tiles[worldx][worldy];
if(i == 1){
map.write(worldx, worldy, DataPosition.wall, partID);
map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam);
map.write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
tile.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
}else{
byte link = map.read(worldx, worldy, DataPosition.link);
byte block = map.read(worldx, worldy, DataPosition.wall);
byte link = tile.getLinkByte();
Block block = tile.block();
if(link != 0){
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
}else if(content.block(block).isMultiblock()){
}else if(block.isMultiblock()){
removeLinked(worldx, worldy);
}
}
onWrite(worldx, worldy, prev);
}
}
}
}
TileDataMarker prev = getPrev(x, y, false);
map.write(x, y, DataPosition.wall, writeID);
map.write(x, y, DataPosition.link, (byte) 0);
map.write(x, y, DataPosition.rotationTeam, rotationTeam);
onWrite(x, y, prev);
Tile tile = tiles[x][y];
tile.setBlock(drawBlock);
tile.setTeam(drawTeam);
}else{
for(int rx = -brushSize; rx <= brushSize; rx++){
for(int ry = -brushSize; ry <= brushSize; ry++){
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
int wx = x + rx, wy = y + ry;
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height() || (paint && !isfloor && content.block(map.read(wx, wy, DataPosition.wall)) == Blocks.air)){
if(wx < 0 || wy < 0 || wx >= width() || wy >= height() || (paint && !isfloor && tiles[wx][wy].block() == Blocks.air)){
continue;
}
TileDataMarker prev = getPrev(wx, wy, true);
Tile tile = tiles[wx][wy];
if(!isfloor){
byte link = map.read(wx, wy, DataPosition.link);
byte link = tile.getLinkByte();
if(content.block(map.read(wx, wy, DataPosition.wall)).isMultiblock()){
if(tile.block().isMultiblock()){
removeLinked(wx, wy);
}else if(link != 0){
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
@ -147,14 +182,13 @@ public class MapEditor{
}
if(isfloor){
map.write(wx, wy, DataPosition.floor, writeID);
tile.setFloor((Floor)drawBlock);
}else{
map.write(wx, wy, DataPosition.wall, writeID);
map.write(wx, wy, DataPosition.link, (byte) 0);
map.write(wx, wy, DataPosition.rotationTeam, rotationTeam);
tile.setBlock(drawBlock);
if(drawBlock.synthetic()){
tile.setTeam(drawTeam);
}
}
onWrite(x + rx, y + ry, prev);
}
}
}
@ -162,62 +196,31 @@ public class MapEditor{
}
private void removeLinked(int x, int y){
Block block = content.block(map.read(x, y, DataPosition.wall));
Block block = tiles[x][y].block();
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
if(Structs.inBounds(worldx, worldy, map.width(), map.height())){
TileDataMarker prev = getPrev(worldx, worldy, false);
map.write(worldx, worldy, DataPosition.link, (byte) 0);
map.write(worldx, worldy, DataPosition.rotationTeam, (byte) 0);
map.write(worldx, worldy, DataPosition.wall, (byte) 0);
onWrite(worldx, worldy, prev);
if(Structs.inBounds(worldx, worldy, width(), height())){
tiles[worldx][worldy].setTeam(Team.none);
tiles[worldx][worldy].setBlock(Blocks.air);
}
}
}
}
boolean checkDupes(int x, int y){
return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y);
}
void onWrite(int x, int y, TileDataMarker previous){
if(previous == null){
renderer.updatePoint(x, y);
return;
}
TileDataMarker current = map.new TileDataMarker();
map.position(x, y);
map.read(current);
Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current));
renderer.updatePoint(x, y);
}
TileDataMarker getPrev(int x, int y, boolean checkDupes){
if(checkDupes && checkDupes(x, y)){
return null;
}else{
TileDataMarker marker = map.newDataMarker();
map.position(x, y);
map.read(marker);
return marker;
}
}
public MapRenderer renderer(){
return renderer;
}
public void resize(int width, int height){
clearOp();
Tile[][] previous = tiles;
int offsetX = -(width - width())/2, offsetY = -(height - height())/2;
loading = true;
tiles = new Tile[width][height];
for(int x = 0; x < width; x++){
@ -228,17 +231,17 @@ public class MapEditor{
tiles[x][y].x = (short)x;
tiles[x][y].y = (short)y;
}else{
tiles[x][y] = new Tile(x, y, Blocks.stone.id, (byte)0);
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
}
}
}
renderer.resize(width, height);
loading = false;
}
public void changeFloor(int x, int y, Block to){
Block from = tiles[x][y].floor();
tiles[x][y].setFloor((Floor)to);
addTileOp(TileOp.get((short)x, (short)y, (byte)0, from.id, to.id));
public void clearOp(){
stack.clear();
}
public void undo(){
@ -253,16 +256,26 @@ public class MapEditor{
}
}
public void addTileOp(long data){
used.set(TileOp.x(data), TileOp.y(data));
op.addOperation(data);
public boolean canUndo(){
return stack.canUndo();
}
public boolean checkUsed(short x, short y){
if(used == null || used.width() != width() || used.height() != height()){
used = new GridBits(world.width(), world.height());
}
public boolean canRedo(){
return stack.canRedo();
}
return used.get(x, y);
public void flushOp(){
if(currentOp == null || currentOp.isEmpty()) return;
stack.add(currentOp);
currentOp = null;
}
public void addTileOp(long data){
if(loading) return;
if(currentOp == null) currentOp = new DrawOperation();
currentOp.addOperation(data);
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
}
}

View File

@ -2,7 +2,6 @@ package io.anuke.mindustry.editor;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.graphics.Color;
@ -26,16 +25,14 @@ import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Block.Icon;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.OreBlock;
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
import java.io.DataInputStream;
import java.io.InputStream;
import static io.anuke.mindustry.Vars.*;
public class MapEditorDialog extends Dialog implements Disposable{
private MapEditor editor;
public final MapEditor editor;
private MapView view;
private MapInfoDialog infoDialog;
private MapLoadDialog loadDialog;
@ -87,17 +84,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
createDialog("$editor.import",
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable) loadDialog::show,
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable) () ->
Platform.instance.showFileChooser("$loadimage", "Map Files", file -> ui.loadAnd(() -> {
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
try{
DataInputStream stream = new DataInputStream(file.read());
MapMeta meta = MapIO.readMapMeta(stream);
MapTileData data = MapIO.readTileData(stream, meta, false);
editor.beginEdit(data, meta.tags, false);
view.clearStack();
//TODO what if it's an image? users should be warned for their stupidity
editor.beginEdit(MapIO.readMap(file, true));
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}), true, mapExtension),
@ -106,39 +98,32 @@ public class MapEditorDialog extends Dialog implements Disposable{
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
ui.loadAnd(() -> {
try{
MapTileData data = MapIO.readLegacyPixmap(new Pixmap(file));
editor.beginEdit(data, editor.getTags(), false);
view.clearStack();
Pixmap pixmap = new Pixmap(file);
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
editor.beginEdit(tiles);
}catch (Exception e){
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}), true, "png")
));
}), true, "png")));
t.addImageTextButton("$editor.export", "icon-save-map", isize, () -> createDialog("$editor.export",
"$editor.exportfile", "$editor.exportfile.description", "icon-file", (Runnable) () ->
Platform.instance.showFileChooser("$saveimage", "Map Files", file -> {
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
Platform.instance.showFileChooser("$editor.savemap", "Map Files", file -> {
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
FileHandle result = file;
ui.loadAnd(() -> {
try{
if(!editor.getTags().containsKey("name")){
editor.getTags().put("name", result.nameWithoutExtension());
}
MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap());
MapIO.writeMap(result, editor.createMap(result), editor.tiles());
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorimagesave", Strings.parseException(e, false)));
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
Log.err(e);
}
});
}, false, mapExtension)));
t.row();
t.row();
}, false, mapExtension));
});
menu.cont.row();
@ -149,24 +134,19 @@ public class MapEditorDialog extends Dialog implements Disposable{
}).padTop(-5).size(swidth * 2f + 10, 60f);
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
if(!(world.width() == x && world.height() == y)){
if(!(editor.width() == x && editor.height() == y)){
ui.loadAnd(() -> {
editor.resize(x, y);
view.clearStack();
});
}
});
loadDialog = new MapLoadDialog(map ->
ui.loadAnd(() -> {
try(DataInputStream stream = new DataInputStream(map.stream.get())){
MapMeta meta = MapIO.readMapMeta(stream);
MapTileData data = MapIO.readTileData(stream, meta, false);
editor.beginEdit(data, meta.tags, false);
view.clearStack();
try{
editor.beginEdit(map);
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}));
@ -198,10 +178,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
shown(() -> {
saved = true;
Platform.instance.beginForceLandscape();
view.clearStack();
editor.clearOp();
Core.scene.setScrollFocus(view);
if(!shownWithMap){
editor.beginEdit(new MapTileData(200, 200), new ObjectMap<>(), true);
editor.beginEdit(200, 200);
}
shownWithMap = false;
@ -209,6 +189,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
});
hidden(() -> {
editor.clearOp();
Platform.instance.updateRPC();
Platform.instance.endForceLandscape();
});
@ -223,13 +204,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
String name = editor.getTags().get("name", "");
if(name.isEmpty()){
ui.showError("$editor.save.noname");
infoDialog.show();
Core.app.post(() -> ui.showError("$editor.save.noname"));
}else{
Map map = world.maps.getByName(name);
Map map = world.maps.all().find(m -> m.name().equals(name));
if(map != null && !map.custom){
ui.showError("$editor.save.overwrite");
}else{
world.maps.saveMap(name, editor.getMap(), editor.getTags());
world.maps.saveMap(editor.getTags(), editor.tiles());
ui.showInfoFade("$editor.saved");
}
}
@ -294,12 +276,13 @@ public class MapEditorDialog extends Dialog implements Disposable{
public void beginEditMap(FileHandle file){
ui.loadAnd(() -> {
try{
Map map = MapIO.readMap(file, true);
shownWithMap = true;
editor.beginEdit(MapIO.readTiles(file));
editor.beginEdit(map);
show();
}catch(Exception e){
Log.err(e);
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
}
});
}
@ -364,15 +347,15 @@ public class MapEditorDialog extends Dialog implements Disposable{
tools.row();
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, () -> view.undo()).get();
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, () -> view.redo()).get();
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, editor::undo).get();
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, editor::redo).get();
addTool.accept(EditorTool.pick);
tools.row();
undo.setDisabled(() -> !view.getStack().canUndo());
redo.setDisabled(() -> !view.getStack().canRedo());
undo.setDisabled(() -> !editor.canUndo());
redo.setDisabled(() -> !editor.canRedo());
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE));
@ -387,9 +370,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
addTool.accept(EditorTool.fill);
addTool.accept(EditorTool.spray);
ImageButton rotate = tools.addImageButton("icon-arrow-16", "clear", 16 * 2f, () -> editor.setDrawRotation((editor.getDrawRotation() + 1) % 4)).get();
ImageButton rotate = tools.addImageButton("icon-arrow-16", "clear", 16 * 2f, () -> editor.rotation = (editor.rotation + 1) % 4).get();
rotate.getImage().update(() -> {
rotate.getImage().setRotation(editor.getDrawRotation() * 90);
rotate.getImage().setRotation(editor.rotation * 90);
rotate.getImage().setOrigin(Align.center);
});
@ -409,8 +392,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
button.margin(4f);
button.getImageCell().grow();
button.getStyle().imageUpColor = team.color;
button.clicked(() -> editor.setDrawTeam(team));
button.update(() -> button.setChecked(editor.getDrawTeam() == team));
button.clicked(() -> editor.drawTeam = team);
button.update(() -> button.setChecked(editor.drawTeam == team));
teamgroup.add(button);
tools.add(button);
@ -423,7 +406,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
mid.table("underline", t -> {
Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false);
slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int) (float) f]));
slider.moved(f -> editor.brushSize = MapEditor.brushSizes[(int) (float) f]);
t.top();
t.add("$editor.brush");
@ -451,21 +434,21 @@ public class MapEditorDialog extends Dialog implements Disposable{
}
if(Core.input.keyTap(KeyCode.R)){
editor.setDrawRotation((editor.getDrawRotation() + 1) % 4);
editor.rotation = Mathf.mod(editor.rotation + 1, 4);
}
if(Core.input.keyTap(KeyCode.E)){
editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4));
editor.rotation = Mathf.mod(editor.rotation - 1, 4);
}
//ctrl keys (undo, redo, save)
if(UIUtils.ctrl()){
if(Core.input.keyTap(KeyCode.Z)){
view.undo();
editor.undo();
}
if(Core.input.keyTap(KeyCode.Y)){
view.redo();
editor.redo();
}
if(Core.input.keyTap(KeyCode.S)){
@ -515,9 +498,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
ImageButton button = new ImageButton("white", "clear-toggle");
button.getStyle().imageUp = new TextureRegionDrawable(region);
button.clicked(() -> editor.setDrawBlock(block));
button.clicked(() -> editor.drawBlock = block);
button.resizeImage(8 * 4f);
button.update(() -> button.setChecked(editor.getDrawBlock() == block));
button.update(() -> button.setChecked(editor.drawBlock == block));
group.add(button);
content.add(button).size(50f);
@ -528,7 +511,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
group.getButtons().get(2).setChecked(true);
table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().localizedName).width(200f).center()).growX();
table.table("underline", extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX();
table.row();
table.add(pane).growY().fillX();
}

View File

@ -9,13 +9,12 @@ import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Disposable;
import io.anuke.arc.util.Pack;
import io.anuke.mindustry.content.Blocks;
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 static io.anuke.mindustry.Vars.content;
import static io.anuke.mindustry.Vars.tilesize;
public class MapRenderer implements Disposable{
@ -101,27 +100,24 @@ public class MapRenderer implements Disposable{
private void render(int wx, int wy){
int x = wx / chunksize, y = wy / chunksize;
IndexedRenderer mesh = chunks[x][y];
byte bf = editor.getMap().read(wx, wy, DataPosition.floor);
byte bw = editor.getMap().read(wx, wy, DataPosition.wall);
byte btr = editor.getMap().read(wx, wy, DataPosition.rotationTeam);
byte rotation = Pack.leftByte(btr);
Team team = Team.all[Pack.rightByte(btr)];
Tile tile = editor.tiles()[wx][wy];
Block floor = content.block(bf);
Block wall = content.block(bw);
Team team = tile.getTeam();
Block floor = tile.floor();
Block wall = tile.block();
TextureRegion region;
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
if(bw != 0 && (wall.synthetic() || wall == Blocks.part)){
if(wall != Blocks.air && (wall.synthetic() || wall == Blocks.part)){
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
if(wall.rotate){
mesh.draw(idxWall, region,
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, rotation * 90 - 90);
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.getRotation() * 90 - 90);
}else{
mesh.draw(idxWall, region,
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
@ -139,7 +135,7 @@ public class MapRenderer implements Disposable{
if(wall.update || wall.destructible){
mesh.setColor(team.color);
region = Core.atlas.find("block-border-editor");
}else if(!wall.synthetic() && bw != 0){
}else if(!wall.synthetic() && wall != Blocks.air){
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
offsetX = tilesize/2f - region.getWidth()/2f * Draw.scl;
offsetY = tilesize/2f - region.getHeight()/2f * Draw.scl;

View File

@ -24,7 +24,7 @@ public class MapSaveDialog extends FloatingDialog{
shown(() -> {
cont.clear();
cont.label(() -> {
Map map = world.maps.getByName(field.getText());
Map map = world.maps.byName(field.getText());
if(map != null){
if(map.custom){
return "$editor.overwrite";
@ -69,7 +69,7 @@ public class MapSaveDialog extends FloatingDialog{
if(field.getText().isEmpty()){
return true;
}
Map map = world.maps.getByName(field.getText());
Map map = world.maps.byName(field.getText());
return map != null && !map.custom;
}
}

View File

@ -2,7 +2,6 @@ package io.anuke.mindustry.editor;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.GridBits;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.Lines;
@ -22,16 +21,16 @@ 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;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.mobile;
import static io.anuke.mindustry.Vars.ui;
public class MapView extends Element implements GestureListener{
private MapEditor editor;
private EditorTool tool = EditorTool.pencil;
//private OperationStack stack = new OperationStack();
//private DrawOperation op;
private GridBits used;
//private GridBits used;
private Bresenham2 br = new Bresenham2();
private boolean updated = false;
private float offsetx, offsety;
@ -88,13 +87,6 @@ public class MapView extends Element implements GestureListener{
mousex = x;
mousey = y;
op = new DrawOperation();
if(used == null || used.width() != world.width() || used.height() != world.height()){
used = new GridBits(world.width(), world.height());
}else{
used.clear();
}
updated = false;
Point2 p = project(x, y);
@ -141,12 +133,7 @@ public class MapView extends Element implements GestureListener{
updated = true;
}
if(op != null && updated){
if(!op.isEmpty()){
stack.add(op);
}
op = null;
}
editor.flushOp();
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
tool = lastTool;
@ -196,14 +183,6 @@ public class MapView extends Element implements GestureListener{
this.tool = tool;
}
public void clearStack(){
stack.clear();
}
public OperationStack getStack(){
return stack;
}
public boolean isGrid(){
return grid;
}
@ -212,27 +191,6 @@ public class MapView extends Element implements GestureListener{
this.grid = grid;
}
public void undo(){
if(stack.canUndo()){
stack.undo(editor);
}
}
public void redo(){
if(stack.canRedo()){
stack.redo(editor);
}
}
public void addTileOp(int xy, byte type, byte from, byte to){
used.set(Pos.x(xy), Pos.y(xy));
op.addOperation(xy, type, from, to);
}
public boolean checkForDuplicates(short x, short y){
return used.get(x, y);
}
@Override
public void act(float delta){
super.act(delta);
@ -266,14 +224,14 @@ public class MapView extends Element implements GestureListener{
}
private Point2 project(float x, float y){
float ratio = 1f / ((float) world.width() / world.height());
float ratio = 1f / ((float) editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * world.width();
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * world.height();
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.width();
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.height();
if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){
if(editor.drawBlock.size % 2 == 0 && tool != EditorTool.eraser){
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
}else{
return Tmp.g1.set((int) x, (int) y);
@ -281,26 +239,26 @@ public class MapView extends Element implements GestureListener{
}
private Vector2 unproject(int x, int y){
float ratio = 1f / ((float) world.width() / world.height());
float ratio = 1f / ((float) editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
float px = ((float) x / world.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
float py = ((float) (y) / world.height()) * sclheight
float px = ((float) x / editor.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
float py = ((float) (y) / editor.height()) * sclheight
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
return vec.set(px, py);
}
@Override
public void draw(){
float ratio = 1f / ((float) world.width() / world.height());
float ratio = 1f / ((float) editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
float centerx = x + width / 2 + offsetx * zoom;
float centery = y + height / 2 + offsety * zoom;
image.setImageSize(world.width(), world.height());
image.setImageSize(editor.width(), editor.height());
if(!ScissorStack.pushScissors(rect.set(x, y, width, height))){
return;
@ -325,18 +283,18 @@ public class MapView extends Element implements GestureListener{
int index = 0;
for(int i = 0; i < MapEditor.brushSizes.length; i++){
if(editor.getBrushSize() == MapEditor.brushSizes[i]){
if(editor.brushSize == MapEditor.brushSizes[i]){
index = i;
break;
}
}
float scaling = zoom * Math.min(width, height) / world.width();
float scaling = zoom * Math.min(width, height) / editor.width();
Draw.color(Pal.accent);
Lines.stroke(Unit.dp.scl(2f));
if((!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
if((!editor.drawBlock.isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
if(tool == EditorTool.line && drawing){
Vector2 v1 = unproject(startx, starty).add(x, y);
float sx = v1.x, sy = v1.y;
@ -355,11 +313,11 @@ public class MapView extends Element implements GestureListener{
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
Point2 p = project(mousex, mousey);
Vector2 v = unproject(p.x, p.y).add(x, y);
float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling / 2f : 0f);
float offset = (editor.drawBlock.size % 2 == 0 ? scaling / 2f : 0f);
Lines.square(
v.x + scaling / 2f + offset,
v.y + scaling / 2f + offset,
scaling * editor.getDrawBlock().size / 2f);
scaling * editor.drawBlock.size / 2f);
}
}

View File

@ -7,12 +7,15 @@ 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.arc.util.Structs;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.game.MappableContent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.world.Block;
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;
@ -57,16 +60,46 @@ public class MapIO{
return pixmap;
}
//TODO implement
/**Reads a pixmap in the 3.5 pixmap format.*/
public static Tile[][] unfinished_readLegacyPixmap(Pixmap pixmap){
return null;
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);
//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(Blocks.part);
write.setTeam(Team.blue);
write.setLinkByte(Pack.byteByte((byte) (dx - 1 + 8), (byte) (dy - 1 + 8)));
}
}
}
//actual core parts
tile.setBlock(Blocks.coreShard);
tile.setTeam(Team.blue);
}
}
}
}
//TODO implement
/**Reads a pixmap in the old 4.0 .mmap format.*/
private static Tile[][] unfinished_readLegacyMmap(InputStream stream) throws IOException{
return null;
private static void readLegacyMmap(FileHandle file, Tile[][] tiles) throws IOException{
}
public static int colorFor(Block floor, Block wall, Team team){
@ -76,7 +109,9 @@ public class MapIO{
return Color.rgba8888(wall.solid ? wall.color : floor.color);
}
public static void writeMap(OutputStream output, Map map, Tile[][] tiles) throws IOException{
public static void writeMap(FileHandle file, Map map, Tile[][] tiles) throws IOException{
OutputStream output = file.write(false);
try(DataOutputStream stream = new DataOutputStream(output)){
stream.writeInt(version);
stream.writeInt(Version.build);

View File

@ -19,7 +19,7 @@ public class SaveMeta{
this.build = build;
this.timestamp = timestamp;
this.timePlayed = timePlayed;
this.map = world.maps.getByName(map);
this.map = world.maps.all().find(m -> m.fileName().equals(map));
this.wave = wave;
this.rules = rules;
}

View File

@ -1,6 +1,6 @@
package io.anuke.mindustry.io.versions;
import io.anuke.arc.util.Strings;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.gen.Serialization;
@ -34,8 +34,8 @@ public class Save16 extends SaveFileVersion{
state.rules.spawns = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get().spawns;
}
String mapname = stream.readUTF();
Map map = world.maps.getByName(mapname);
if(map == null) map = new Map(Strings.capitalize(mapname), 1, 1);
Map map = world.maps.all().find(m -> m.fileName().equals(mapname));
if(map == null) map = new Map(customMapDirectory.child(mapname), 1, 1, new ObjectMap<>(), true);
world.setMap(map);
int wave = stream.readInt();
@ -62,7 +62,7 @@ public class Save16 extends SaveFileVersion{
//--GENERAL STATE--
Serialization.writeRules(stream, state.rules);
stream.writeUTF(world.getMap().name); //map name
stream.writeUTF(world.getMap().fileName()); //map name
stream.writeInt(state.wave); //wave
stream.writeFloat(state.wavetime); //wave countdown

View File

@ -2,6 +2,7 @@ package io.anuke.mindustry.maps;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Texture;
import io.anuke.arc.util.Disposable;
@ -34,6 +35,10 @@ public class Maps implements Disposable{
return maps.select(m -> !m.custom);
}
public Map byName(String name){
return maps.find(m -> m.name().equals(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.
@ -62,10 +67,32 @@ public class Maps implements Disposable{
loadCustomMaps();
}
/** Save a map. This updates all values and stored data necessary. */
public void saveMap(Map map, Tile[][] data){
/** Save a custom map to the directory. This updates all values and stored data necessary.
* The tags are copied to prevent mutation later.*/
public void saveMap(ObjectMap<String, String> baseTags, Tile[][] data){
try{
MapIO.writeMap(map.file.write(false), map, data);
ObjectMap<String, String> tags = new ObjectMap<>(baseTags);
String name = tags.get("name");
if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?");
FileHandle file = customMapDirectory.child(name + "." + mapExtension);
//find map with the same exact display name
Map other = maps.find(m -> m.getDisplayName().equals(name));
if(other != null){
//dispose of map if it's already there
if(other.texture != null){
other.texture.dispose();
other.texture = null;
}
maps.remove(other);
}
//create map, write it, etc etc etc
Map map = new Map(file, data.length, data[0].length, tags, true);
MapIO.writeMap(file, map, data);
if(!headless){
map.texture = new Texture(MapIO.generatePreview(data));
}

View File

@ -27,10 +27,10 @@ public class NetworkIO{
try(DataOutputStream stream = new DataOutputStream(os)){
//--GENERAL STATE--
Serialization.writeRules(stream, state.rules);
stream.writeUTF(world.getMap().name); //map name
stream.writeUTF(world.getMap().name()); //map name
//write tags
ObjectMap<String, String> tags = world.getMap().meta.tags;
ObjectMap<String, String> tags = world.getMap().tags;
stream.writeByte(tags.size);
for(Entry<String, String> entry : tags.entries()){
stream.writeUTF(entry.key);
@ -105,7 +105,7 @@ public class NetworkIO{
//map
world.spawner.read(stream);
SaveIO.getSaveWriter().readMap(stream);
world.setMap(new Map(map, 0, 0));
world.setMap(new Map(customMapDirectory.child(map), 0, 0, new ObjectMap<>(), true));
state.teams = new Teams();
@ -141,7 +141,7 @@ public class NetworkIO{
int maxlen = 32;
String host = (headless ? "Server" : players[0].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));
map = map.substring(0, Math.min(map.length(), maxlen));

View File

@ -106,7 +106,7 @@ public class CustomGameDialog extends FloatingDialog{
image.row();
image.add("[accent]" + map.getDisplayName()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
image.row();
image.label((() -> Core.bundle.format("level.highscore", Core.settings.getInt("hiscore" + map.name, 0)))).pad(3f);
image.label((() -> Core.bundle.format("level.highscore", Core.settings.getInt("hiscore" + map.fileName(), 0)))).pad(3f);
BorderImage border = new BorderImage(map.texture, 3f);
border.setScaling(Scaling.fit);

View File

@ -29,12 +29,15 @@ public class MapsDialog extends FloatingDialog{
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
try{
Map map = MapIO.readMap(file.read(), file.name(), true, file::read);
Map map = MapIO.readMap(file, true);
String name = map.tags.get("name", file.nameWithoutExtension());
if(world.maps.getByName(name) != null && !world.maps.getByName(name).custom){
//TODO filename conflict, erasure
Map conflict = world.maps.byName(name);
if(conflict != null && !conflict.custom){
ui.showError(Core.bundle.format("editor.import.exists", name));
}else if(world.maps.getByName(name) != null){
}else if(conflict != null){
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
world.maps.importMap(file, map);
setup();
@ -138,7 +141,7 @@ public class MapsDialog extends FloatingDialog{
table.addImageTextButton("$editor.openin", "icon-load-map", 16 * 2, () -> {
try{
Vars.ui.editor.beginEditMap(map.stream.get());
Vars.ui.editor.beginEditMap(map.file);
dialog.hide();
hide();
}catch(Exception e){
@ -148,7 +151,7 @@ public class MapsDialog extends FloatingDialog{
}).fillX().height(54f).marginLeft(10);
table.addImageTextButton("$delete", "icon-trash-16", 16 * 2, () -> {
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name), () -> {
ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> {
world.maps.removeMap(map);
dialog.hide();
setup();

View File

@ -215,6 +215,14 @@ public class Tile implements Position, TargetTrait{
return link != 0;
}
public byte getLinkByte(){
return link;
}
public void setLinkByte(byte b){
this.link = 0;
}
/** Sets this to a linked tile, which sets the block to a part. dx and dy can only be -8-7. */
public void setLinked(byte dx, byte dy){
setBlock(Blocks.part);

View File

@ -54,9 +54,9 @@ public class DesktopPlatform extends Platform{
if(world.getMap() == null){
presence.details = "Unknown Map";
}else if(!state.rules.waves){
presence.details = Strings.capitalize(world.getMap().name);
presence.details = Strings.capitalize(world.getMap().getDisplayName());
}else{
presence.details = Strings.capitalize(world.getMap().name) + " | Wave " + state.wave;
presence.details = Strings.capitalize(world.getMap().getDisplayName()) + " | Wave " + state.wave;
presence.largeImageText = "Wave " + state.wave;
}