diff --git a/core/src/io/anuke/mindustry/editor/DrawOperation.java b/core/src/io/anuke/mindustry/editor/DrawOperation.java index 249a6163ce..a394e063e4 100755 --- a/core/src/io/anuke/mindustry/editor/DrawOperation.java +++ b/core/src/io/anuke/mindustry/editor/DrawOperation.java @@ -1,38 +1,68 @@ package io.anuke.mindustry.editor; +import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; +import com.badlogic.gdx.utils.IntSet; import io.anuke.mindustry.io.MapTileData; - -import java.nio.ByteBuffer; +import io.anuke.mindustry.io.MapTileData.TileDataMarker; +import io.anuke.ucore.util.Bits; public class DrawOperation implements Disposable{ /**Data to apply operation to.*/ - MapTileData data; - /**Format: - * position (int) - * packed data FROM (use TileDataMarker's read/write methods) - * packed data TO (use TileDataMarker's read/write methods) - */ - ByteBuffer operation; - //TileDataMarker writer = new TileDataMarker(); + private MapTileData data; + /**List of per-tile operations that occurred.*/ + private Array operations = new Array<>(); + /**Checks for duplicate operations, useful for brushes.*/ + private IntSet checks = new IntSet(); public DrawOperation(MapTileData data){ this.data = data; } - public void set(ByteBuffer operation) { - this.operation = operation; + public boolean isEmpty(){ + return operations.size == 0; } - public void undo() { - //TODO implement + public boolean checkDuplicate(short x, short y){ + int i = Bits.packInt(x, y); + if(checks.contains(i)) return true; + + checks.add(i); + return false; } - public void redo() { - //TODO implement + public void addOperation(TileOperation op){ + operations.add(op); + } + + public void undo(MapEditor editor) { + for(int i = operations.size - 1; i >= 0; i --){ + TileOperation op = operations.get(i); + data.write(op.x, op.y, op.from); + editor.renderer().updatePoint(op.x, op.y); + } + } + + public void redo(MapEditor editor) { + for(TileOperation op : operations){ + data.write(op.x, op.y, op.to); + editor.renderer().updatePoint(op.x, op.y); + } } @Override public void dispose() {} + public static class TileOperation{ + public short x, y; + public TileDataMarker from; + public TileDataMarker to; + + public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to) { + this.x = x; + this.y = y; + this.from = from; + this.to = to; + } + } } diff --git a/core/src/io/anuke/mindustry/editor/EditorTool.java b/core/src/io/anuke/mindustry/editor/EditorTool.java index e6f860fb08..0e5a85cdb1 100644 --- a/core/src/io/anuke/mindustry/editor/EditorTool.java +++ b/core/src/io/anuke/mindustry/editor/EditorTool.java @@ -67,7 +67,7 @@ public enum EditorTool{ else writer.wall = (byte)editor.getDrawBlock().id; - editor.getMap().write(px, py, writer); + editor.write(px, py, writer, false); editor.renderer().updatePoint(px, py); if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width)); diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index c13fe8c0b1..f65d4abf91 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -1,6 +1,8 @@ package io.anuke.mindustry.editor; +import io.anuke.mindustry.Vars; import io.anuke.mindustry.content.blocks.Blocks; +import io.anuke.mindustry.editor.DrawOperation.TileOperation; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.MapTileData; import io.anuke.mindustry.io.MapTileData.TileDataMarker; @@ -111,7 +113,7 @@ public class MapEditor{ writer.team = (byte)drawTeam.ordinal(); writer.floor = floor; writer.link = Bits.packByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)); - map.write(worldx, worldy, writer); + write(worldx, worldy, writer, false); renderer.updatePoint(worldx, worldy); } @@ -129,7 +131,7 @@ public class MapEditor{ writer.team = (byte)drawTeam.ordinal(); writer.rotation = 0; writer.link = 0; - map.write(x, y, writer); + write(x, y, writer, false); renderer.updatePoint(x, y); }else{ @@ -140,7 +142,7 @@ public class MapEditor{ if (x + rx < 0 || y + ry < 0 || x + rx >= map.width() || y + ry >= map.height()) { continue; } - map.write(x + rx, y + ry, writer); + write(x + rx, y + ry, writer, true); renderer.updatePoint(x + rx, y + ry); } } @@ -163,7 +165,7 @@ public class MapEditor{ marker.wall = 0; marker.rotation = 0; marker.team = 0; - map.write(worldx, worldy, marker); + write(worldx, worldy, marker, false); if(worldx == x && worldy == y){ renderer.updatePoint(worldx, worldy); @@ -173,6 +175,27 @@ public class MapEditor{ } } + public void write(int x, int y, TileDataMarker writer, boolean checkDupes){ + boolean dupe = checkDupes && Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y); + TileDataMarker prev = null; + + if(!dupe) { + prev = map.new TileDataMarker(); + map.position(x, y); + map.read(prev); + } + + map.write(x, y, writer); + + if(!dupe) { + TileDataMarker current = map.new TileDataMarker(); + map.position(x, y); + map.read(current); + + Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, prev, current)); + } + } + public MapRenderer renderer() { return renderer; } diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index b87ddaa37e..f0a4893844 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -420,6 +420,14 @@ public class MapEditorDialog extends Dialog{ } } + if(Inputs.keyTap(Input.R)){ + editor.setDrawRotation((editor.getDrawRotation() + 1)%4); + } + + if(Inputs.keyTap(Input.E)){ + editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4)); + } + //ctrl keys (undo, redo, save) if(UIUtils.ctrl()){ if(Inputs.keyTap(Input.Z)){ @@ -434,14 +442,6 @@ public class MapEditorDialog extends Dialog{ saveDialog.save(); } - if(Inputs.keyTap(Input.R)){ - editor.setDrawRotation((editor.getDrawRotation() + 1)%4); - } - - if(Inputs.keyTap(Input.E)){ - editor.setDrawRotation(Mathf.mod((editor.getDrawRotation() + 1), 4)); - } - if(Inputs.keyTap(Input.G)){ view.setGrid(!view.isGrid()); } diff --git a/core/src/io/anuke/mindustry/editor/MapView.java b/core/src/io/anuke/mindustry/editor/MapView.java index 7fa732dc7d..b95f369a76 100644 --- a/core/src/io/anuke/mindustry/editor/MapView.java +++ b/core/src/io/anuke/mindustry/editor/MapView.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.editor.DrawOperation.TileOperation; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.ui.GridImage; import io.anuke.ucore.core.Core; @@ -77,16 +78,24 @@ public class MapView extends Element implements GestureListener{ public void undo(){ if(stack.canUndo()){ - stack.undo(); + stack.undo(editor); } } public void redo(){ if(stack.canRedo()){ - stack.redo(); + stack.redo(editor); } } + public void addTileOp(TileOperation t){ + op.addOperation(t); + } + + public boolean checkForDuplicates(short x, short y){ + return op.checkDuplicate(x, y); + } + public MapView(MapEditor editor){ this.editor = editor; @@ -114,6 +123,8 @@ public class MapView extends Element implements GestureListener{ return false; } + op = new DrawOperation(editor.getMap()); + updated = false; GridPoint2 p = project(x, y); @@ -146,6 +157,14 @@ public class MapView extends Element implements GestureListener{ } updated = true; } + + if(op != null && updated){ + if(!op.isEmpty()){ + stack.add(op); + } + op = null; + } + } @Override diff --git a/core/src/io/anuke/mindustry/editor/OperationStack.java b/core/src/io/anuke/mindustry/editor/OperationStack.java index b09e4c48d9..5218ce616c 100755 --- a/core/src/io/anuke/mindustry/editor/OperationStack.java +++ b/core/src/io/anuke/mindustry/editor/OperationStack.java @@ -37,18 +37,18 @@ public class OperationStack{ return !(index > -1 || stack.size + index < 0); } - public void undo(){ + public void undo(MapEditor editor){ if(!canUndo()) return; - stack.get(stack.size - 1 + index).undo(); + stack.get(stack.size - 1 + index).undo(editor); index --; } - public void redo(){ + public void redo(MapEditor editor){ if(!canRedo()) return; index ++; - stack.get(stack.size - 1 + index).redo(); + stack.get(stack.size - 1 + index).redo(editor); } } diff --git a/core/src/io/anuke/mindustry/io/MapTileData.java b/core/src/io/anuke/mindustry/io/MapTileData.java index d94306d337..a3fdaea910 100644 --- a/core/src/io/anuke/mindustry/io/MapTileData.java +++ b/core/src/io/anuke/mindustry/io/MapTileData.java @@ -68,6 +68,12 @@ public class MapTileData { return tile; } + /**Reads and returns the next tile data.*/ + public TileDataMarker read(TileDataMarker marker){ + marker.read(buffer); + return marker; + } + /**Reads and returns the next tile data.*/ public TileDataMarker readAt(int x, int y){ position(x, y);