Fixed compile errors / New non-crappy undo system
This commit is contained in:
@@ -197,8 +197,8 @@ editor.description = Description:
|
|||||||
editor.name = Name:
|
editor.name = Name:
|
||||||
editor.teams = Teams
|
editor.teams = Teams
|
||||||
editor.elevation = Elevation
|
editor.elevation = Elevation
|
||||||
editor.errorimageload = Error loading file:\n[accent]{0}
|
editor.errorload = Error loading file:\n[accent]{0}
|
||||||
editor.errorimagesave = Error saving file:\n[accent]{0}
|
editor.errorsave = Error saving file:\n[accent]{0}
|
||||||
editor.generate = Generate
|
editor.generate = Generate
|
||||||
editor.resize = Resize
|
editor.resize = Resize
|
||||||
editor.loadmap = Load Map
|
editor.loadmap = Load Map
|
||||||
|
|||||||
@@ -30,13 +30,15 @@ public class DrawOperation{
|
|||||||
class TileOpStruct{
|
class TileOpStruct{
|
||||||
short x;
|
short x;
|
||||||
short y;
|
short y;
|
||||||
/**
|
|
||||||
* 0: floor
|
|
||||||
* 1: block
|
|
||||||
* 2: rotation
|
|
||||||
*/
|
|
||||||
byte type;
|
byte type;
|
||||||
byte from;
|
byte from;
|
||||||
byte to;
|
byte to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum OpType{
|
||||||
|
floor,
|
||||||
|
block,
|
||||||
|
rotation,
|
||||||
|
team
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
core/src/io/anuke/mindustry/editor/EditorTile.java
Normal file
53
core/src/io/anuke/mindustry/editor/EditorTile.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,29 +8,32 @@ import io.anuke.arc.util.Pack;
|
|||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.world.Block;
|
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 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{
|
public enum EditorTool{
|
||||||
pick{
|
pick{
|
||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
|
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
|
||||||
|
|
||||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
Tile tile = editor.tile(x, y);
|
||||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
|
||||||
byte link = editor.getMap().read(x, y, DataPosition.link);
|
Block floor = tile.floor(), block = tile.block();
|
||||||
|
byte link = tile.getLinkByte();
|
||||||
|
|
||||||
if(link != 0){
|
if(link != 0){
|
||||||
x -= (Pack.leftByte(link) - 8);
|
x -= (Pack.leftByte(link) - 8);
|
||||||
y -= (Pack.rightByte(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.drawBlock = block == Blocks.air ? floor : block;
|
||||||
editor.setDrawBlock(block);
|
|
||||||
ui.editor.updateSelectedBlock();
|
ui.editor.updateSelectedBlock();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -64,7 +67,7 @@ public enum EditorTool{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void touched(MapEditor editor, int x, int y){
|
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{
|
line{
|
||||||
@@ -78,56 +81,57 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
IntArray stack = new IntArray();
|
IntArray stack = new IntArray();
|
||||||
int width;
|
Block dest;
|
||||||
byte be, dest;
|
boolean isfloor;
|
||||||
boolean floor;
|
MapEditor data;
|
||||||
MapTileData data;
|
|
||||||
|
|
||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
if(!Structs.inBounds(x, y, world.width(), world.height())) return;
|
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
|
//don't fill multiblocks, thanks
|
||||||
pencil.touched(editor, x, y);
|
pencil.touched(editor, x, y);
|
||||||
return;
|
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);
|
dest = isfloor ? floor : block;
|
||||||
byte bw = data.read(x, y, DataPosition.wall);
|
Block draw = editor.drawBlock;
|
||||||
boolean synth = editor.getDrawBlock().synthetic();
|
|
||||||
byte brt = Pack.byteByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal());
|
|
||||||
|
|
||||||
dest = floor ? bf : bw;
|
if(dest == draw || block == Blocks.part || block.isMultiblock()){
|
||||||
byte draw = editor.getDrawBlock().id;
|
|
||||||
|
|
||||||
if(dest == draw || content.block(bw) instanceof BlockPart || content.block(bw).isMultiblock()){
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
width = world.width();
|
int width = world.width();
|
||||||
int height = world.height();
|
int height = world.height();
|
||||||
|
|
||||||
IntPositionConsumer writer = (px, py) -> {
|
IntPositionConsumer writer = (px, py) -> {
|
||||||
TileDataMarker prev = editor.getPrev(px, py, false);
|
Tile write = editor.tile(px, py);
|
||||||
|
|
||||||
if(floor){
|
if(isfloor){
|
||||||
data.write(px, py, DataPosition.floor, draw);
|
write.setFloor((Floor)draw);
|
||||||
}else{
|
}else{
|
||||||
data.write(px, py, DataPosition.wall, draw);
|
write.setBlock(draw);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(synth){
|
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()){
|
if(isAlt()){
|
||||||
|
//fill all of the same type regardless of borders
|
||||||
for(int cx = 0; cx < width; cx++){
|
for(int cx = 0; cx < width; cx++){
|
||||||
for(int cy = 0; cy < height; cy++){
|
for(int cy = 0; cy < height; cy++){
|
||||||
if(eq(cx, cy)){
|
if(eq(cx, cy)){
|
||||||
@@ -136,28 +140,28 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if(isAlt2()){
|
}else if(isAlt2()){
|
||||||
|
//fill all teams.
|
||||||
for(int cx = 0; cx < width; cx++){
|
for(int cx = 0; cx < width; cx++){
|
||||||
for(int cy = 0; cy < height; cy++){
|
for(int cy = 0; cy < height; cy++){
|
||||||
byte w = data.read(cx, cy, DataPosition.wall);
|
Tile write = editor.tile(cx, cy);
|
||||||
if(content.block(w).synthetic()){
|
if(write.block().synthetic()){
|
||||||
TileDataMarker prev = editor.getPrev(cx, cy, false);
|
write.setTeam(editor.drawTeam);
|
||||||
data.write(cx, cy, DataPosition.rotationTeam, (byte)editor.getDrawTeam().ordinal());
|
|
||||||
editor.onWrite(cx, cy, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
//normal fill
|
||||||
int x1;
|
int x1;
|
||||||
boolean spanAbove, spanBelow;
|
boolean spanAbove, spanBelow;
|
||||||
|
|
||||||
stack.clear();
|
stack.clear();
|
||||||
|
|
||||||
stack.add(asi(x, y));
|
stack.add(Pos.get(x, y));
|
||||||
|
|
||||||
while(stack.size > 0){
|
while(stack.size > 0){
|
||||||
int popped = stack.pop();
|
int popped = stack.pop();
|
||||||
x = popped % width;
|
x = Pos.x(popped);
|
||||||
y = popped / width;
|
y = Pos.y(popped);
|
||||||
|
|
||||||
x1 = x;
|
x1 = x;
|
||||||
while(x1 >= 0 && eq(x1, y)) x1--;
|
while(x1 >= 0 && eq(x1, y)) x1--;
|
||||||
@@ -167,14 +171,14 @@ public enum EditorTool{
|
|||||||
writer.accept(x1, y);
|
writer.accept(x1, y);
|
||||||
|
|
||||||
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
||||||
stack.add(asi(x1, y - 1));
|
stack.add(Pos.get(x1, y - 1));
|
||||||
spanAbove = true;
|
spanAbove = true;
|
||||||
}else if(spanAbove && y > 0 && eq(x1, y - 1)){
|
}else if(spanAbove && eq(x1, y - 1)){
|
||||||
spanAbove = false;
|
spanAbove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||||
stack.add(asi(x1, y + 1));
|
stack.add(Pos.get(x1, y + 1));
|
||||||
spanBelow = true;
|
spanBelow = true;
|
||||||
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||||
spanBelow = false;
|
spanBelow = false;
|
||||||
@@ -186,15 +190,9 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean eq(int px, int py){
|
boolean eq(int px, int py){
|
||||||
byte nbf = data.read(px, py, DataPosition.floor);
|
Tile tile = data.tile(px, py);
|
||||||
byte nbw = data.read(px, py, DataPosition.wall);
|
|
||||||
byte nbe = data.read(px, py, DataPosition.elevation);
|
|
||||||
|
|
||||||
return (floor ? nbf : nbw) == dest && nbe == be;
|
return (isfloor ? tile.floor() : tile.block()) == dest;
|
||||||
}
|
|
||||||
|
|
||||||
int asi(int x, int y){
|
|
||||||
return x + y * width;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
zoom;
|
zoom;
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.collection.GridBits;
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.gen.TileOp;
|
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.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
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;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class MapEditor{
|
public class MapEditor{
|
||||||
@@ -24,8 +26,8 @@ public class MapEditor{
|
|||||||
private Tile[][] tiles;
|
private Tile[][] tiles;
|
||||||
|
|
||||||
private OperationStack stack = new OperationStack();
|
private OperationStack stack = new OperationStack();
|
||||||
private DrawOperation op;
|
private DrawOperation currentOp;
|
||||||
private GridBits used;
|
private boolean loading;
|
||||||
|
|
||||||
public int brushSize = 1;
|
public int brushSize = 1;
|
||||||
public int rotation;
|
public int rotation;
|
||||||
@@ -36,27 +38,70 @@ public class MapEditor{
|
|||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEdit(Tile[][] map, ObjectMap<String, String> tags, boolean clear){
|
public void beginEdit(int width, int height){
|
||||||
|
reset();
|
||||||
|
|
||||||
this.brushSize = 1;
|
loading = true;
|
||||||
this.tags = tags;
|
tiles = createTiles(width, height);
|
||||||
|
renderer.resize(width(), height());
|
||||||
if(clear){
|
loading = false;
|
||||||
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;
|
drawBlock = Blocks.stone;
|
||||||
renderer.resize(map.length, map[0].length);
|
tags = new ObjectMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tile[][] tiles(){
|
public Tile[][] tiles(){
|
||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Tile tile(int x, int y){
|
||||||
|
return tiles[x][y];
|
||||||
|
}
|
||||||
|
|
||||||
public int width(){
|
public int width(){
|
||||||
return tiles.length;
|
return tiles.length;
|
||||||
}
|
}
|
||||||
@@ -74,9 +119,7 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
||||||
byte writeID = drawBlock.id;
|
//byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
||||||
byte partID = Blocks.part.id;
|
|
||||||
byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
|
||||||
|
|
||||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||||
|
|
||||||
@@ -94,52 +137,44 @@ public class MapEditor{
|
|||||||
int worldy = dy + offsety + y;
|
int worldy = dy + offsety + y;
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, world.width(), world.height())){
|
if(Structs.inBounds(worldx, worldy, world.width(), world.height())){
|
||||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
Tile tile = tiles[worldx][worldy];
|
||||||
|
|
||||||
if(i == 1){
|
if(i == 1){
|
||||||
map.write(worldx, worldy, DataPosition.wall, partID);
|
tile.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
|
||||||
map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam);
|
|
||||||
map.write(worldx, worldy, DataPosition.link, Pack.byteByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
|
||||||
}else{
|
}else{
|
||||||
byte link = map.read(worldx, worldy, DataPosition.link);
|
byte link = tile.getLinkByte();
|
||||||
byte block = map.read(worldx, worldy, DataPosition.wall);
|
Block block = tile.block();
|
||||||
|
|
||||||
if(link != 0){
|
if(link != 0){
|
||||||
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
|
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
|
||||||
}else if(content.block(block).isMultiblock()){
|
}else if(block.isMultiblock()){
|
||||||
removeLinked(worldx, worldy);
|
removeLinked(worldx, worldy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onWrite(worldx, worldy, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TileDataMarker prev = getPrev(x, y, false);
|
Tile tile = tiles[x][y];
|
||||||
|
tile.setBlock(drawBlock);
|
||||||
map.write(x, y, DataPosition.wall, writeID);
|
tile.setTeam(drawTeam);
|
||||||
map.write(x, y, DataPosition.link, (byte) 0);
|
|
||||||
map.write(x, y, DataPosition.rotationTeam, rotationTeam);
|
|
||||||
|
|
||||||
onWrite(x, y, prev);
|
|
||||||
}else{
|
}else{
|
||||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
||||||
int wx = x + rx, wy = y + ry;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileDataMarker prev = getPrev(wx, wy, true);
|
Tile tile = tiles[wx][wy];
|
||||||
|
|
||||||
if(!isfloor){
|
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);
|
removeLinked(wx, wy);
|
||||||
}else if(link != 0){
|
}else if(link != 0){
|
||||||
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
|
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
|
||||||
@@ -147,14 +182,13 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isfloor){
|
if(isfloor){
|
||||||
map.write(wx, wy, DataPosition.floor, writeID);
|
tile.setFloor((Floor)drawBlock);
|
||||||
}else{
|
}else{
|
||||||
map.write(wx, wy, DataPosition.wall, writeID);
|
tile.setBlock(drawBlock);
|
||||||
map.write(wx, wy, DataPosition.link, (byte) 0);
|
if(drawBlock.synthetic()){
|
||||||
map.write(wx, wy, DataPosition.rotationTeam, rotationTeam);
|
tile.setTeam(drawTeam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onWrite(x + rx, y + ry, prev);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,62 +196,31 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeLinked(int x, int y){
|
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 offsetx = -(block.size - 1) / 2;
|
||||||
int offsety = -(block.size - 1) / 2;
|
int offsety = -(block.size - 1) / 2;
|
||||||
for(int dx = 0; dx < block.size; dx++){
|
for(int dx = 0; dx < block.size; dx++){
|
||||||
for(int dy = 0; dy < block.size; dy++){
|
for(int dy = 0; dy < block.size; dy++){
|
||||||
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
||||||
if(Structs.inBounds(worldx, worldy, map.width(), map.height())){
|
if(Structs.inBounds(worldx, worldy, width(), height())){
|
||||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
tiles[worldx][worldy].setTeam(Team.none);
|
||||||
|
tiles[worldx][worldy].setBlock(Blocks.air);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(){
|
public MapRenderer renderer(){
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resize(int width, int height){
|
public void resize(int width, int height){
|
||||||
|
clearOp();
|
||||||
|
|
||||||
Tile[][] previous = tiles;
|
Tile[][] previous = tiles;
|
||||||
int offsetX = -(width - width())/2, offsetY = -(height - height())/2;
|
int offsetX = -(width - width())/2, offsetY = -(height - height())/2;
|
||||||
|
loading = true;
|
||||||
|
|
||||||
tiles = new Tile[width][height];
|
tiles = new Tile[width][height];
|
||||||
for(int x = 0; x < width; x++){
|
for(int x = 0; x < width; x++){
|
||||||
@@ -228,17 +231,17 @@ public class MapEditor{
|
|||||||
tiles[x][y].x = (short)x;
|
tiles[x][y].x = (short)x;
|
||||||
tiles[x][y].y = (short)y;
|
tiles[x][y].y = (short)y;
|
||||||
}else{
|
}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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changeFloor(int x, int y, Block to){
|
renderer.resize(width, height);
|
||||||
Block from = tiles[x][y].floor();
|
loading = false;
|
||||||
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(){
|
public void undo(){
|
||||||
@@ -253,16 +256,26 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canUndo(){
|
||||||
|
return stack.canUndo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canRedo(){
|
||||||
|
return stack.canRedo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flushOp(){
|
||||||
|
if(currentOp == null || currentOp.isEmpty()) return;
|
||||||
|
stack.add(currentOp);
|
||||||
|
currentOp = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void addTileOp(long data){
|
public void addTileOp(long data){
|
||||||
used.set(TileOp.x(data), TileOp.y(data));
|
if(loading) return;
|
||||||
op.addOperation(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkUsed(short x, short y){
|
if(currentOp == null) currentOp = new DrawOperation();
|
||||||
if(used == null || used.width() != width() || used.height() != height()){
|
currentOp.addOperation(data);
|
||||||
used = new GridBits(world.width(), world.height());
|
|
||||||
}
|
|
||||||
|
|
||||||
return used.get(x, y);
|
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.editor;
|
|||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.function.Consumer;
|
import io.anuke.arc.function.Consumer;
|
||||||
import io.anuke.arc.graphics.Color;
|
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.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Block.Icon;
|
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.OreBlock;
|
||||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class MapEditorDialog extends Dialog implements Disposable{
|
public class MapEditorDialog extends Dialog implements Disposable{
|
||||||
private MapEditor editor;
|
public final MapEditor editor;
|
||||||
private MapView view;
|
private MapView view;
|
||||||
private MapInfoDialog infoDialog;
|
private MapInfoDialog infoDialog;
|
||||||
private MapLoadDialog loadDialog;
|
private MapLoadDialog loadDialog;
|
||||||
@@ -87,17 +84,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
createDialog("$editor.import",
|
createDialog("$editor.import",
|
||||||
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable) loadDialog::show,
|
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable) loadDialog::show,
|
||||||
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable) () ->
|
"$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{
|
try{
|
||||||
DataInputStream stream = new DataInputStream(file.read());
|
//TODO what if it's an image? users should be warned for their stupidity
|
||||||
|
editor.beginEdit(MapIO.readMap(file, true));
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
|
||||||
MapTileData data = MapIO.readTileData(stream, meta, false);
|
|
||||||
|
|
||||||
editor.beginEdit(data, meta.tags, false);
|
|
||||||
view.clearStack();
|
|
||||||
}catch(Exception e){
|
}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);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}), true, mapExtension),
|
}), true, mapExtension),
|
||||||
@@ -106,39 +98,32 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
|
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
MapTileData data = MapIO.readLegacyPixmap(new Pixmap(file));
|
Pixmap pixmap = new Pixmap(file);
|
||||||
|
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
|
||||||
editor.beginEdit(data, editor.getTags(), false);
|
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
|
||||||
view.clearStack();
|
editor.beginEdit(tiles);
|
||||||
}catch (Exception e){
|
}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);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}), true, "png")
|
}), true, "png")));
|
||||||
));
|
|
||||||
|
|
||||||
t.addImageTextButton("$editor.export", "icon-save-map", isize, () -> createDialog("$editor.export",
|
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
|
||||||
"$editor.exportfile", "$editor.exportfile.description", "icon-file", (Runnable) () ->
|
Platform.instance.showFileChooser("$editor.savemap", "Map Files", file -> {
|
||||||
Platform.instance.showFileChooser("$saveimage", "Map Files", file -> {
|
|
||||||
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
|
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
|
||||||
FileHandle result = file;
|
FileHandle result = file;
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(!editor.getTags().containsKey("name")){
|
if(!editor.getTags().containsKey("name")){
|
||||||
editor.getTags().put("name", result.nameWithoutExtension());
|
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){
|
}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);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, false, mapExtension)));
|
}, false, mapExtension));
|
||||||
|
|
||||||
t.row();
|
|
||||||
|
|
||||||
t.row();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
menu.cont.row();
|
menu.cont.row();
|
||||||
@@ -149,24 +134,19 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
||||||
|
|
||||||
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
||||||
if(!(world.width() == x && world.height() == y)){
|
if(!(editor.width() == x && editor.height() == y)){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
editor.resize(x, y);
|
editor.resize(x, y);
|
||||||
view.clearStack();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loadDialog = new MapLoadDialog(map ->
|
loadDialog = new MapLoadDialog(map ->
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try(DataInputStream stream = new DataInputStream(map.stream.get())){
|
try{
|
||||||
MapMeta meta = MapIO.readMapMeta(stream);
|
editor.beginEdit(map);
|
||||||
MapTileData data = MapIO.readTileData(stream, meta, false);
|
|
||||||
|
|
||||||
editor.beginEdit(data, meta.tags, false);
|
|
||||||
view.clearStack();
|
|
||||||
}catch(Exception e){
|
}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);
|
Log.err(e);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -198,10 +178,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
shown(() -> {
|
shown(() -> {
|
||||||
saved = true;
|
saved = true;
|
||||||
Platform.instance.beginForceLandscape();
|
Platform.instance.beginForceLandscape();
|
||||||
view.clearStack();
|
editor.clearOp();
|
||||||
Core.scene.setScrollFocus(view);
|
Core.scene.setScrollFocus(view);
|
||||||
if(!shownWithMap){
|
if(!shownWithMap){
|
||||||
editor.beginEdit(new MapTileData(200, 200), new ObjectMap<>(), true);
|
editor.beginEdit(200, 200);
|
||||||
}
|
}
|
||||||
shownWithMap = false;
|
shownWithMap = false;
|
||||||
|
|
||||||
@@ -209,6 +189,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
});
|
});
|
||||||
|
|
||||||
hidden(() -> {
|
hidden(() -> {
|
||||||
|
editor.clearOp();
|
||||||
Platform.instance.updateRPC();
|
Platform.instance.updateRPC();
|
||||||
Platform.instance.endForceLandscape();
|
Platform.instance.endForceLandscape();
|
||||||
});
|
});
|
||||||
@@ -223,13 +204,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
String name = editor.getTags().get("name", "");
|
String name = editor.getTags().get("name", "");
|
||||||
|
|
||||||
if(name.isEmpty()){
|
if(name.isEmpty()){
|
||||||
ui.showError("$editor.save.noname");
|
infoDialog.show();
|
||||||
|
Core.app.post(() -> ui.showError("$editor.save.noname"));
|
||||||
}else{
|
}else{
|
||||||
Map map = world.maps.getByName(name);
|
Map map = world.maps.all().find(m -> m.name().equals(name));
|
||||||
if(map != null && !map.custom){
|
if(map != null && !map.custom){
|
||||||
ui.showError("$editor.save.overwrite");
|
ui.showError("$editor.save.overwrite");
|
||||||
}else{
|
}else{
|
||||||
world.maps.saveMap(name, editor.getMap(), editor.getTags());
|
world.maps.saveMap(editor.getTags(), editor.tiles());
|
||||||
ui.showInfoFade("$editor.saved");
|
ui.showInfoFade("$editor.saved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,12 +276,13 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
public void beginEditMap(FileHandle file){
|
public void beginEditMap(FileHandle file){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
|
Map map = MapIO.readMap(file, true);
|
||||||
shownWithMap = true;
|
shownWithMap = true;
|
||||||
editor.beginEdit(MapIO.readTiles(file));
|
editor.beginEdit(map);
|
||||||
show();
|
show();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(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();
|
tools.row();
|
||||||
|
|
||||||
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, () -> view.undo()).get();
|
ImageButton undo = tools.addImageButton("icon-undo", "clear", 16 * 2f, editor::undo).get();
|
||||||
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, () -> view.redo()).get();
|
ImageButton redo = tools.addImageButton("icon-redo", "clear", 16 * 2f, editor::redo).get();
|
||||||
|
|
||||||
addTool.accept(EditorTool.pick);
|
addTool.accept(EditorTool.pick);
|
||||||
|
|
||||||
tools.row();
|
tools.row();
|
||||||
|
|
||||||
undo.setDisabled(() -> !view.getStack().canUndo());
|
undo.setDisabled(() -> !editor.canUndo());
|
||||||
redo.setDisabled(() -> !view.getStack().canRedo());
|
redo.setDisabled(() -> !editor.canRedo());
|
||||||
|
|
||||||
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
|
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
|
||||||
redo.update(() -> redo.getImage().setColor(redo.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.fill);
|
||||||
addTool.accept(EditorTool.spray);
|
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().update(() -> {
|
||||||
rotate.getImage().setRotation(editor.getDrawRotation() * 90);
|
rotate.getImage().setRotation(editor.rotation * 90);
|
||||||
rotate.getImage().setOrigin(Align.center);
|
rotate.getImage().setOrigin(Align.center);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -409,8 +392,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
button.margin(4f);
|
button.margin(4f);
|
||||||
button.getImageCell().grow();
|
button.getImageCell().grow();
|
||||||
button.getStyle().imageUpColor = team.color;
|
button.getStyle().imageUpColor = team.color;
|
||||||
button.clicked(() -> editor.setDrawTeam(team));
|
button.clicked(() -> editor.drawTeam = team);
|
||||||
button.update(() -> button.setChecked(editor.getDrawTeam() == team));
|
button.update(() -> button.setChecked(editor.drawTeam == team));
|
||||||
teamgroup.add(button);
|
teamgroup.add(button);
|
||||||
tools.add(button);
|
tools.add(button);
|
||||||
|
|
||||||
@@ -423,7 +406,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
mid.table("underline", t -> {
|
mid.table("underline", t -> {
|
||||||
Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false);
|
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.top();
|
||||||
t.add("$editor.brush");
|
t.add("$editor.brush");
|
||||||
@@ -451,21 +434,21 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.R)){
|
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)){
|
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)
|
//ctrl keys (undo, redo, save)
|
||||||
if(UIUtils.ctrl()){
|
if(UIUtils.ctrl()){
|
||||||
if(Core.input.keyTap(KeyCode.Z)){
|
if(Core.input.keyTap(KeyCode.Z)){
|
||||||
view.undo();
|
editor.undo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.Y)){
|
if(Core.input.keyTap(KeyCode.Y)){
|
||||||
view.redo();
|
editor.redo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Core.input.keyTap(KeyCode.S)){
|
if(Core.input.keyTap(KeyCode.S)){
|
||||||
@@ -515,9 +498,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
ImageButton button = new ImageButton("white", "clear-toggle");
|
ImageButton button = new ImageButton("white", "clear-toggle");
|
||||||
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
||||||
button.clicked(() -> editor.setDrawBlock(block));
|
button.clicked(() -> editor.drawBlock = block);
|
||||||
button.resizeImage(8 * 4f);
|
button.resizeImage(8 * 4f);
|
||||||
button.update(() -> button.setChecked(editor.getDrawBlock() == block));
|
button.update(() -> button.setChecked(editor.drawBlock == block));
|
||||||
group.add(button);
|
group.add(button);
|
||||||
content.add(button).size(50f);
|
content.add(button).size(50f);
|
||||||
|
|
||||||
@@ -528,7 +511,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
group.getButtons().get(2).setChecked(true);
|
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.row();
|
||||||
table.add(pane).growY().fillX();
|
table.add(pane).growY().fillX();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,12 @@ import io.anuke.arc.graphics.g2d.Draw;
|
|||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Disposable;
|
import io.anuke.arc.util.Disposable;
|
||||||
import io.anuke.arc.util.Pack;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||||
import io.anuke.mindustry.world.Block;
|
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;
|
import static io.anuke.mindustry.Vars.tilesize;
|
||||||
|
|
||||||
public class MapRenderer implements Disposable{
|
public class MapRenderer implements Disposable{
|
||||||
@@ -101,27 +100,24 @@ public class MapRenderer implements Disposable{
|
|||||||
private void render(int wx, int wy){
|
private void render(int wx, int wy){
|
||||||
int x = wx / chunksize, y = wy / chunksize;
|
int x = wx / chunksize, y = wy / chunksize;
|
||||||
IndexedRenderer mesh = chunks[x][y];
|
IndexedRenderer mesh = chunks[x][y];
|
||||||
byte bf = editor.getMap().read(wx, wy, DataPosition.floor);
|
Tile tile = editor.tiles()[wx][wy];
|
||||||
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)];
|
|
||||||
|
|
||||||
Block floor = content.block(bf);
|
Team team = tile.getTeam();
|
||||||
Block wall = content.block(bw);
|
Block floor = tile.floor();
|
||||||
|
Block wall = tile.block();
|
||||||
|
|
||||||
TextureRegion region;
|
TextureRegion region;
|
||||||
|
|
||||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + 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();
|
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||||
|
|
||||||
if(wall.rotate){
|
if(wall.rotate){
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
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{
|
}else{
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
|
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl)/2f,
|
||||||
@@ -139,7 +135,7 @@ public class MapRenderer implements Disposable{
|
|||||||
if(wall.update || wall.destructible){
|
if(wall.update || wall.destructible){
|
||||||
mesh.setColor(team.color);
|
mesh.setColor(team.color);
|
||||||
region = Core.atlas.find("block-border-editor");
|
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();
|
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||||
offsetX = tilesize/2f - region.getWidth()/2f * Draw.scl;
|
offsetX = tilesize/2f - region.getWidth()/2f * Draw.scl;
|
||||||
offsetY = tilesize/2f - region.getHeight()/2f * Draw.scl;
|
offsetY = tilesize/2f - region.getHeight()/2f * Draw.scl;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class MapSaveDialog extends FloatingDialog{
|
|||||||
shown(() -> {
|
shown(() -> {
|
||||||
cont.clear();
|
cont.clear();
|
||||||
cont.label(() -> {
|
cont.label(() -> {
|
||||||
Map map = world.maps.getByName(field.getText());
|
Map map = world.maps.byName(field.getText());
|
||||||
if(map != null){
|
if(map != null){
|
||||||
if(map.custom){
|
if(map.custom){
|
||||||
return "$editor.overwrite";
|
return "$editor.overwrite";
|
||||||
@@ -69,7 +69,7 @@ public class MapSaveDialog extends FloatingDialog{
|
|||||||
if(field.getText().isEmpty()){
|
if(field.getText().isEmpty()){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Map map = world.maps.getByName(field.getText());
|
Map map = world.maps.byName(field.getText());
|
||||||
return map != null && !map.custom;
|
return map != null && !map.custom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.editor;
|
|||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.GridBits;
|
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
import io.anuke.arc.graphics.g2d.Draw;
|
import io.anuke.arc.graphics.g2d.Draw;
|
||||||
import io.anuke.arc.graphics.g2d.Lines;
|
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.graphics.Pal;
|
||||||
import io.anuke.mindustry.input.Binding;
|
import io.anuke.mindustry.input.Binding;
|
||||||
import io.anuke.mindustry.ui.GridImage;
|
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{
|
public class MapView extends Element implements GestureListener{
|
||||||
private MapEditor editor;
|
private MapEditor editor;
|
||||||
private EditorTool tool = EditorTool.pencil;
|
private EditorTool tool = EditorTool.pencil;
|
||||||
//private OperationStack stack = new OperationStack();
|
//private OperationStack stack = new OperationStack();
|
||||||
//private DrawOperation op;
|
//private DrawOperation op;
|
||||||
private GridBits used;
|
//private GridBits used;
|
||||||
private Bresenham2 br = new Bresenham2();
|
private Bresenham2 br = new Bresenham2();
|
||||||
private boolean updated = false;
|
private boolean updated = false;
|
||||||
private float offsetx, offsety;
|
private float offsetx, offsety;
|
||||||
@@ -88,13 +87,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
mousex = x;
|
mousex = x;
|
||||||
mousey = y;
|
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;
|
updated = false;
|
||||||
|
|
||||||
Point2 p = project(x, y);
|
Point2 p = project(x, y);
|
||||||
@@ -141,12 +133,7 @@ public class MapView extends Element implements GestureListener{
|
|||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(op != null && updated){
|
editor.flushOp();
|
||||||
if(!op.isEmpty()){
|
|
||||||
stack.add(op);
|
|
||||||
}
|
|
||||||
op = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
|
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
|
||||||
tool = lastTool;
|
tool = lastTool;
|
||||||
@@ -196,14 +183,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
this.tool = tool;
|
this.tool = tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearStack(){
|
|
||||||
stack.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OperationStack getStack(){
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGrid(){
|
public boolean isGrid(){
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
@@ -212,27 +191,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
this.grid = grid;
|
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
|
@Override
|
||||||
public void act(float delta){
|
public void act(float delta){
|
||||||
super.act(delta);
|
super.act(delta);
|
||||||
@@ -266,14 +224,14 @@ public class MapView extends Element implements GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Point2 project(float x, float y){
|
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 size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * world.width();
|
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.width();
|
||||||
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * world.height();
|
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));
|
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
|
||||||
}else{
|
}else{
|
||||||
return Tmp.g1.set((int) x, (int) y);
|
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){
|
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 size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
float px = ((float) x / world.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
float px = ((float) x / editor.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
||||||
float py = ((float) (y) / world.height()) * sclheight
|
float py = ((float) (y) / editor.height()) * sclheight
|
||||||
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
||||||
return vec.set(px, py);
|
return vec.set(px, py);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
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 size = Math.min(width, height);
|
||||||
float sclwidth = size * zoom;
|
float sclwidth = size * zoom;
|
||||||
float sclheight = size * zoom * ratio;
|
float sclheight = size * zoom * ratio;
|
||||||
float centerx = x + width / 2 + offsetx * zoom;
|
float centerx = x + width / 2 + offsetx * zoom;
|
||||||
float centery = y + height / 2 + offsety * 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))){
|
if(!ScissorStack.pushScissors(rect.set(x, y, width, height))){
|
||||||
return;
|
return;
|
||||||
@@ -325,18 +283,18 @@ public class MapView extends Element implements GestureListener{
|
|||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
||||||
if(editor.getBrushSize() == MapEditor.brushSizes[i]){
|
if(editor.brushSize == MapEditor.brushSizes[i]){
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float scaling = zoom * Math.min(width, height) / world.width();
|
float scaling = zoom * Math.min(width, height) / editor.width();
|
||||||
|
|
||||||
Draw.color(Pal.accent);
|
Draw.color(Pal.accent);
|
||||||
Lines.stroke(Unit.dp.scl(2f));
|
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){
|
if(tool == EditorTool.line && drawing){
|
||||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||||
float sx = v1.x, sy = v1.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)){
|
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
|
||||||
Point2 p = project(mousex, mousey);
|
Point2 p = project(mousex, mousey);
|
||||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
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(
|
Lines.square(
|
||||||
v.x + scaling / 2f + offset,
|
v.x + scaling / 2f + offset,
|
||||||
v.y + scaling / 2f + offset,
|
v.y + scaling / 2f + offset,
|
||||||
scaling * editor.getDrawBlock().size / 2f);
|
scaling * editor.drawBlock.size / 2f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,15 @@ import io.anuke.arc.graphics.Color;
|
|||||||
import io.anuke.arc.graphics.Pixmap;
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
import io.anuke.arc.graphics.Pixmap.Format;
|
import io.anuke.arc.graphics.Pixmap.Format;
|
||||||
import io.anuke.arc.util.Pack;
|
import io.anuke.arc.util.Pack;
|
||||||
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.MappableContent;
|
import io.anuke.mindustry.game.MappableContent;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.game.Version;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.world.Block;
|
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.Tile;
|
||||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
|
|
||||||
@@ -57,16 +60,46 @@ public class MapIO{
|
|||||||
return pixmap;
|
return pixmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO implement
|
|
||||||
/**Reads a pixmap in the 3.5 pixmap format.*/
|
/**Reads a pixmap in the 3.5 pixmap format.*/
|
||||||
public static Tile[][] unfinished_readLegacyPixmap(Pixmap pixmap){
|
public static void readLegacyPixmap(Pixmap pixmap, Tile[][] tiles){
|
||||||
return null;
|
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
|
//TODO implement
|
||||||
/**Reads a pixmap in the old 4.0 .mmap format.*/
|
/**Reads a pixmap in the old 4.0 .mmap format.*/
|
||||||
private static Tile[][] unfinished_readLegacyMmap(InputStream stream) throws IOException{
|
private static void readLegacyMmap(FileHandle file, Tile[][] tiles) throws IOException{
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int colorFor(Block floor, Block wall, Team team){
|
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);
|
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)){
|
try(DataOutputStream stream = new DataOutputStream(output)){
|
||||||
stream.writeInt(version);
|
stream.writeInt(version);
|
||||||
stream.writeInt(Version.build);
|
stream.writeInt(Version.build);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class SaveMeta{
|
|||||||
this.build = build;
|
this.build = build;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.timePlayed = timePlayed;
|
this.timePlayed = timePlayed;
|
||||||
this.map = world.maps.getByName(map);
|
this.map = world.maps.all().find(m -> m.fileName().equals(map));
|
||||||
this.wave = wave;
|
this.wave = wave;
|
||||||
this.rules = rules;
|
this.rules = rules;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.anuke.mindustry.io.versions;
|
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.arc.util.Time;
|
||||||
import io.anuke.mindustry.game.Version;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.gen.Serialization;
|
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;
|
state.rules.spawns = content.<Zone>getByID(ContentType.zone, state.rules.zone).rules.get().spawns;
|
||||||
}
|
}
|
||||||
String mapname = stream.readUTF();
|
String mapname = stream.readUTF();
|
||||||
Map map = world.maps.getByName(mapname);
|
Map map = world.maps.all().find(m -> m.fileName().equals(mapname));
|
||||||
if(map == null) map = new Map(Strings.capitalize(mapname), 1, 1);
|
if(map == null) map = new Map(customMapDirectory.child(mapname), 1, 1, new ObjectMap<>(), true);
|
||||||
world.setMap(map);
|
world.setMap(map);
|
||||||
|
|
||||||
int wave = stream.readInt();
|
int wave = stream.readInt();
|
||||||
@@ -62,7 +62,7 @@ public class Save16 extends SaveFileVersion{
|
|||||||
|
|
||||||
//--GENERAL STATE--
|
//--GENERAL STATE--
|
||||||
Serialization.writeRules(stream, state.rules);
|
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.writeInt(state.wave); //wave
|
||||||
stream.writeFloat(state.wavetime); //wave countdown
|
stream.writeFloat(state.wavetime); //wave countdown
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.maps;
|
|||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.graphics.Texture;
|
import io.anuke.arc.graphics.Texture;
|
||||||
import io.anuke.arc.util.Disposable;
|
import io.anuke.arc.util.Disposable;
|
||||||
@@ -34,6 +35,10 @@ public class Maps implements Disposable{
|
|||||||
return maps.select(m -> !m.custom);
|
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.
|
* 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.
|
* Does not add this map to the map list.
|
||||||
@@ -62,10 +67,32 @@ public class Maps implements Disposable{
|
|||||||
loadCustomMaps();
|
loadCustomMaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save a map. This updates all values and stored data necessary. */
|
/** Save a custom map to the directory. This updates all values and stored data necessary.
|
||||||
public void saveMap(Map map, Tile[][] data){
|
* The tags are copied to prevent mutation later.*/
|
||||||
|
public void saveMap(ObjectMap<String, String> baseTags, Tile[][] data){
|
||||||
|
|
||||||
try{
|
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){
|
if(!headless){
|
||||||
map.texture = new Texture(MapIO.generatePreview(data));
|
map.texture = new Texture(MapIO.generatePreview(data));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ public class NetworkIO{
|
|||||||
try(DataOutputStream stream = new DataOutputStream(os)){
|
try(DataOutputStream stream = new DataOutputStream(os)){
|
||||||
//--GENERAL STATE--
|
//--GENERAL STATE--
|
||||||
Serialization.writeRules(stream, state.rules);
|
Serialization.writeRules(stream, state.rules);
|
||||||
stream.writeUTF(world.getMap().name); //map name
|
stream.writeUTF(world.getMap().name()); //map name
|
||||||
|
|
||||||
//write tags
|
//write tags
|
||||||
ObjectMap<String, String> tags = world.getMap().meta.tags;
|
ObjectMap<String, String> tags = world.getMap().tags;
|
||||||
stream.writeByte(tags.size);
|
stream.writeByte(tags.size);
|
||||||
for(Entry<String, String> entry : tags.entries()){
|
for(Entry<String, String> entry : tags.entries()){
|
||||||
stream.writeUTF(entry.key);
|
stream.writeUTF(entry.key);
|
||||||
@@ -105,7 +105,7 @@ public class NetworkIO{
|
|||||||
//map
|
//map
|
||||||
world.spawner.read(stream);
|
world.spawner.read(stream);
|
||||||
SaveIO.getSaveWriter().readMap(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();
|
state.teams = new Teams();
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ public class NetworkIO{
|
|||||||
int maxlen = 32;
|
int maxlen = 32;
|
||||||
|
|
||||||
String host = (headless ? "Server" : players[0].name);
|
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));
|
host = host.substring(0, Math.min(host.length(), maxlen));
|
||||||
map = map.substring(0, Math.min(map.length(), maxlen));
|
map = map.substring(0, Math.min(map.length(), maxlen));
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class CustomGameDialog extends FloatingDialog{
|
|||||||
image.row();
|
image.row();
|
||||||
image.add("[accent]" + map.getDisplayName()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
|
image.add("[accent]" + map.getDisplayName()).pad(3f).growX().wrap().get().setAlignment(Align.center, Align.center);
|
||||||
image.row();
|
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);
|
BorderImage border = new BorderImage(map.texture, 3f);
|
||||||
border.setScaling(Scaling.fit);
|
border.setScaling(Scaling.fit);
|
||||||
|
|||||||
@@ -29,12 +29,15 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
|
buttons.addImageTextButton("$editor.importmap", "icon-add", 14 * 2, () -> {
|
||||||
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
Platform.instance.showFileChooser("$editor.importmap", "Map File", file -> {
|
||||||
try{
|
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());
|
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));
|
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", () -> {
|
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||||
world.maps.importMap(file, map);
|
world.maps.importMap(file, map);
|
||||||
setup();
|
setup();
|
||||||
@@ -138,7 +141,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
|
|
||||||
table.addImageTextButton("$editor.openin", "icon-load-map", 16 * 2, () -> {
|
table.addImageTextButton("$editor.openin", "icon-load-map", 16 * 2, () -> {
|
||||||
try{
|
try{
|
||||||
Vars.ui.editor.beginEditMap(map.stream.get());
|
Vars.ui.editor.beginEditMap(map.file);
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
hide();
|
hide();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -148,7 +151,7 @@ public class MapsDialog extends FloatingDialog{
|
|||||||
}).fillX().height(54f).marginLeft(10);
|
}).fillX().height(54f).marginLeft(10);
|
||||||
|
|
||||||
table.addImageTextButton("$delete", "icon-trash-16", 16 * 2, () -> {
|
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);
|
world.maps.removeMap(map);
|
||||||
dialog.hide();
|
dialog.hide();
|
||||||
setup();
|
setup();
|
||||||
|
|||||||
@@ -215,6 +215,14 @@ public class Tile implements Position, TargetTrait{
|
|||||||
return link != 0;
|
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. */
|
/** 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){
|
public void setLinked(byte dx, byte dy){
|
||||||
setBlock(Blocks.part);
|
setBlock(Blocks.part);
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ public class DesktopPlatform extends Platform{
|
|||||||
if(world.getMap() == null){
|
if(world.getMap() == null){
|
||||||
presence.details = "Unknown Map";
|
presence.details = "Unknown Map";
|
||||||
}else if(!state.rules.waves){
|
}else if(!state.rules.waves){
|
||||||
presence.details = Strings.capitalize(world.getMap().name);
|
presence.details = Strings.capitalize(world.getMap().getDisplayName());
|
||||||
}else{
|
}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;
|
presence.largeImageText = "Wave " + state.wave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user