mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-07-04 15:27:19 +07:00
Fixed compile errors / New non-crappy undo system
This commit is contained in:
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
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.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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user