Desktop/mobile descriptive tool modes

This commit is contained in:
Anuken
2019-06-11 23:31:57 -04:00
parent 16190aa878
commit df78412896
12 changed files with 407 additions and 176 deletions

View File

@@ -1,13 +1,14 @@
package io.anuke.mindustry.editor;
import io.anuke.arc.Core;
import io.anuke.arc.collection.IntArray;
import io.anuke.arc.function.IntPositionConsumer;
import io.anuke.arc.input.KeyCode;
import io.anuke.arc.util.*;
import io.anuke.arc.function.*;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Bresenham2;
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.world.*;
import io.anuke.mindustry.world.blocks.*;
public enum EditorTool{
zoom,
@@ -16,12 +17,34 @@ public enum EditorTool{
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
Tile tile = editor.tile(x, y).link();
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
}
},
line,
pencil{
line("replace", "straight"){
@Override
public void touchedLine(MapEditor editor, int x1, int y1, int x2, int y2){
//straight
if(mode == 1){
if(Math.abs(x2 - x1) > Math.abs(y2 - y1)){
y2 = y1;
}else{
x2 = x1;
}
}
Bresenham2.line(x1, y1, x2, y2, (x, y) -> {
if(mode == 0){
//replace
editor.drawBlocksReplace(x, y);
}else{
//normal
editor.drawBlocks(x, y);
}
});
}
},
pencil("replace", "square"){
{
edit = true;
draggable = true;
@@ -29,10 +52,20 @@ public enum EditorTool{
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint());
if(mode == -1){
//normal mode
editor.drawBlocks(x, y);
}else if(mode == 0){
//replace mode
editor.drawBlocksReplace(x, y);
}else if(mode == 1){
//square mode
editor.drawBlocks(x, y, true, tile -> true);
}
}
},
eraser{
eraser("eraseores"){
{
edit = true;
draggable = true;
@@ -40,19 +73,25 @@ public enum EditorTool{
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint(), Blocks.air);
editor.drawCircle(x, y, tile -> {
if(mode == -1){
//erase block
Vars.world.removeBlock(tile);
}else if(mode == 0){
//erase ore
tile.clearOverlay();
}
});
}
},
fill{
fill("replaceall", "fillteams"){
{
edit = true;
}
IntArray stack = new IntArray();
Block dest;
boolean isFloor;
MapEditor data;
@Override
public void touched(MapEditor editor, int x, int y){
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
Tile tile = editor.tile(x, y);
@@ -63,74 +102,57 @@ public enum EditorTool{
return;
}
data = editor;
isFloor = editor.drawBlock instanceof Floor;
//mode 0 or 1, fill everything with the floor/tile or replace it
if(mode == 0 || mode == -1){
Predicate<Tile> tester;
Consumer<Tile> setter;
Block floor = tile.floor();
Block block = tile.block();
boolean synth = editor.drawBlock.synthetic();
Block draw = editor.drawBlock;
dest = draw instanceof OverlayFloor ? tile.overlay() : isFloor ? floor : block;
if(dest == draw || block instanceof BlockPart || block.isMultiblock()){
return;
}
boolean alt = isAlt();
int width = editor.width();
int height = editor.height();
IntPositionConsumer writer = (px, py) -> {
Tile write = editor.tile(px, py);
if(isFloor){
if(alt && !(draw instanceof OverlayFloor)){
Block ore = write.overlay();
write.setFloor((Floor)draw);
write.setOverlay(ore);
}else{
write.setFloor((Floor)draw);
}
if(editor.drawBlock.isOverlay()){
Block dest = tile.overlay();
tester = t -> t.overlay() == dest;
setter = t -> t.setOverlay(editor.drawBlock);
}else if(editor.drawBlock.isFloor()){
Block dest = tile.floor();
tester = t -> t.floor() == dest;
setter = t -> t.setFloorUnder(editor.drawBlock.asFloor());
}else{
write.setBlock(draw);
Block dest = tile.block();
tester = t -> t.block() == dest;
setter = t -> t.setBlock(editor.drawBlock);
}
if(synth){
write.setTeam(editor.drawTeam);
}
//replace only when the mode is 0 using the specified functions
fill(editor, x, y, mode == 0, tester, setter);
}else if(mode == 1){ //mode 1 is team fill
if(draw.rotate){
write.rotation((byte)editor.rotation);
}
};
//only fill synthetic blocks, it's meaningless otherwise
if(tile.link().synthetic()){
if(isAlt()){
//fill all of the same type regardless of borders
Team dest = tile.getTeam();
fill(editor, x, y, false, t -> t.getTeam() == dest, t -> t.setTeam(editor.drawTeam));
}
}
}
void fill(MapEditor editor, int x, int y, boolean replace, Predicate<Tile> tester, Consumer<Tile> filler){
int width = editor.width(), height = editor.height();
if(replace){
//just do it on everything
for(int cx = 0; cx < width; cx++){
for(int cy = 0; cy < height; cy++){
if(eq(cx, cy)){
writer.accept(cx, cy);
}
}
}
}else if(isAlt2()){
//fill all teams.
for(int cx = 0; cx < width; cx++){
for(int cy = 0; cy < height; cy++){
Tile write = editor.tile(cx, cy);
if(write.block().synthetic()){
write.setTeam(editor.drawTeam);
Tile tile = editor.tile(cx, cy);
if(tester.test(tile)){
filler.accept(tile);
}
}
}
}else{
//normal fill
//perform flood fill
int x1;
stack.clear();
stack.add(Pos.get(x, y));
while(stack.size > 0){
@@ -139,23 +161,23 @@ public enum EditorTool{
y = Pos.y(popped);
x1 = x;
while(x1 >= 0 && eq(x1, y)) x1--;
while(x1 >= 0 && tester.test(editor.tile(x1, y))) x1--;
x1++;
boolean spanAbove = false, spanBelow = false;
while(x1 < width && eq(x1, y)){
writer.accept(x1, y);
while(x1 < width && tester.test(editor.tile(x1, y))){
filler.accept(editor.tile(x1, y));
if(!spanAbove && y > 0 && eq(x1, y - 1)){
if(!spanAbove && y > 0 && tester.test(editor.tile(x1, y - 1))){
stack.add(Pos.get(x1, y - 1));
spanAbove = true;
}else if(spanAbove && !eq(x1, y - 1)){
}else if(spanAbove && !tester.test(editor.tile(x1, y - 1))){
spanAbove = false;
}
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
if(!spanBelow && y < height - 1 && tester.test(editor.tile(x1, y + 1))){
stack.add(Pos.get(x1, y + 1));
spanBelow = true;
}else if(spanBelow && y < height - 1 && !eq(x1, y + 1)){
}else if(spanBelow && y < height - 1 && !tester.test(editor.tile(x1, y + 1))){
spanBelow = false;
}
x1++;
@@ -163,14 +185,10 @@ public enum EditorTool{
}
}
}
boolean eq(int px, int py){
Tile tile = data.tile(px, py);
return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isFloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid);
}
},
spray{
spray("replace"){
final double chance = 0.012;
{
edit = true;
draggable = true;
@@ -178,25 +196,40 @@ public enum EditorTool{
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint(), editor.drawBlock, 0.012);
//floor spray
if(editor.drawBlock.isFloor()){
editor.drawCircle(x, y, tile -> {
if(Mathf.chance(chance)){
tile.setFloor(editor.drawBlock.asFloor());
}
});
}else if(mode == 0){ //replace-only mode, doesn't affect air
editor.drawBlocks(x, y, tile -> Mathf.chance(chance) && tile.block() != Blocks.air);
}else{
editor.drawBlocks(x, y, tile -> Mathf.chance(chance));
}
}
};
boolean edit, draggable;
/** All the internal alternate placement modes of this tool. */
public final String[] altModes;
/** The current alternate placement mode. -1 is the standard mode, no changes.*/
public int mode = -1;
/** Whether this tool causes canvas changes when touched.*/
public boolean edit;
/** Whether this tool should be dragged across the canvas when the mouse moves.*/
public boolean draggable;
public static boolean isPaint(){
return Core.input.keyDown(KeyCode.CONTROL_LEFT);
EditorTool(){
this(new String[]{});
}
public static boolean isAlt(){
return Core.input.keyDown(KeyCode.TAB);
EditorTool(String... altModes){
this.altModes = altModes;
}
public static boolean isAlt2(){
return Core.input.keyDown(KeyCode.GRAVE);
}
public void touched(MapEditor editor, int x, int y){}
public void touched(MapEditor editor, int x, int y){
}
public void touchedLine(MapEditor editor, int x1, int y1, int x2, int y2){}
}

View File

@@ -2,6 +2,8 @@ package io.anuke.mindustry.editor;
import io.anuke.arc.collection.StringMap;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.graphics.Pixmap;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Structs;
@@ -132,15 +134,111 @@ public class MapEditor{
return world.height();
}
public void draw(int x, int y, boolean paint){
draw(x, y, paint, drawBlock);
public void drawBlocksReplace(int x, int y){
drawBlocks(x, y, tile -> tile.block() != Blocks.air || drawBlock.isFloor());
}
public void draw(int x, int y, boolean paint, Block drawBlock){
draw(x, y, paint, drawBlock, 1.0);
public void drawBlocks(int x, int y){
drawBlocks(x, y, false, tile -> true);
}
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
public void drawBlocks(int x, int y, Predicate<Tile> tester){
drawBlocks(x, y, false, tester);
}
public void drawBlocks(int x, int y, boolean square, Predicate<Tile> tester){
if(drawBlock.isMultiblock()){
x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1);
y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1);
int offsetx = -(drawBlock.size - 1) / 2;
int offsety = -(drawBlock.size - 1) / 2;
for(int dx = 0; dx < drawBlock.size; dx++){
for(int dy = 0; dy < drawBlock.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(Structs.inBounds(worldx, worldy, width(), height())){
Tile tile = tile(worldx, worldy);
Block block = tile.block();
//bail out if there's anything blocking the way
if(block.isMultiblock() || block instanceof BlockPart){
return;
}
renderer.updatePoint(worldx, worldy);
}
}
}
world.setBlock(tile(x, y), drawBlock, drawTeam);
}else{
boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air;
Consumer<Tile> drawer = tile -> {
if(!tester.test(tile)) return;
//remove linked tiles blocking the way
if(!isFloor && (tile.isLinked() || tile.block().isMultiblock())){
world.removeBlock(tile.link());
}
if(isFloor){
tile.setFloor(drawBlock.asFloor());
}else{
tile.setBlock(drawBlock);
if(drawBlock.synthetic()){
tile.setTeam(drawTeam);
}
if(drawBlock.rotate){
tile.rotation((byte)rotation);
}
}
};
if(square){
drawSquare(x, y, drawer);
}else{
drawCircle(x, y, drawer);
}
}
}
public void drawCircle(int x, int y, Consumer<Tile> drawer){
for(int rx = -brushSize; rx <= brushSize; rx++){
for(int ry = -brushSize; ry <= brushSize; ry++){
if(Mathf.dst2(rx, ry) <= (brushSize - 0.5f) * (brushSize - 0.5f)){
int wx = x + rx, wy = y + ry;
if(wx < 0 || wy < 0 || wx >= width() || wy >= height()){
continue;
}
drawer.accept(tile(wx, wy));
}
}
}
}
public void drawSquare(int x, int y, Consumer<Tile> drawer){
for(int rx = -brushSize; rx <= brushSize; rx++){
for(int ry = -brushSize; ry <= brushSize; ry++){
int wx = x + rx, wy = y + ry;
if(wx < 0 || wy < 0 || wx >= width() || wy >= height()){
continue;
}
drawer.accept(tile(wx, wy));
}
}
}
public void draw_DEPRECATED(int x, int y, boolean paint, Block drawBlock, double chance){
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
Tile[][] tiles = world.getTiles();

View File

@@ -12,8 +12,10 @@ import io.anuke.arc.input.KeyCode;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.scene.actions.Actions;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.style.TextureRegionDrawable;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.TextButton.TextButtonStyle;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.scene.ui.layout.Unit;
import io.anuke.arc.util.*;
@@ -21,6 +23,7 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.io.JsonIO;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.maps.Map;
@@ -380,15 +383,77 @@ public class MapEditorDialog extends Dialog implements Disposable{
ButtonGroup<ImageButton> group = new ButtonGroup<>();
Consumer<EditorTool> addTool = tool -> {
Table[] lastTable = {null};
ImageButton button = new ImageButton("icon-" + tool.name(), "clear-toggle");
button.clicked(() -> view.setTool(tool));
button.clicked(() -> {
view.setTool(tool);
if(lastTable[0] != null){
lastTable[0].remove();
}
});
button.resizeImage(16 * 2f);
button.update(() -> button.setChecked(view.getTool() == tool));
group.add(button);
if(tool == EditorTool.pencil)
button.setChecked(true);
tools.add(button);
if(tool.altModes.length > 0){
button.clicked(l -> {
if(!mobile){
//desktop: rightclick
l.setButton(KeyCode.MOUSE_RIGHT);
}
}, e -> {
//need to double tap
if(mobile && e.getTapCount() < 2){
return;
}
if(lastTable[0] != null){
lastTable[0].remove();
}
Table table = new Table("dialogDim");
table.defaults().size(280f, 70f);
for(int i = 0; i < tool.altModes.length; i++){
int mode = i;
String name = tool.altModes[i];
table.addButton(b -> {
b.left();
b.marginLeft(6);
b.setStyle(Core.scene.skin.get("clear-toggle", TextButtonStyle.class));
b.add(Core.bundle.get("toolmode." + name)).left();
b.row();
b.add(Core.bundle.get("toolmode." + name + ".description")).color(Color.LIGHT_GRAY).left();
}, () -> {
tool.mode = (tool.mode == mode ? -1 : mode);
table.remove();
}).update(b -> b.setChecked(tool.mode == mode));
table.row();
}
table.update(() -> {
Vector2 v = button.localToStageCoordinates(Tmp.v1.setZero());
table.setPosition(v.x, v.y, Align.topLeft);
});
table.pack();
table.act(Core.graphics.getDeltaTime());
Core.scene.add(table);
lastTable[0] = table;
});
}
Label mode = new Label("");
mode.setColor(Pal.remove);
mode.update(() -> mode.setText(tool.mode == -1 ? "" : "M" + (tool.mode + 1) + " "));
mode.setAlignment(Align.bottomRight, Align.bottomRight);
mode.touchable(Touchable.disabled);
tools.stack(button, mode);
};
tools.defaults().size(size, size);
@@ -479,14 +544,26 @@ public class MapEditorDialog extends Dialog implements Disposable{
}
private void doInput(){
//tool select
for(int i = 0; i < EditorTool.values().length; i++){
if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){
view.setTool(EditorTool.values()[i]);
break;
if(Core.input.ctrl()){
//alt mode select
//TODO these keycode are unusable, tweak later
for(int i = 0; i < view.getTool().altModes.length + 1; i++){
if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){
view.getTool().mode = i - 1;
}
}
}else{
//tool select
for(int i = 0; i < EditorTool.values().length; i++){
if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){
view.setTool(EditorTool.values()[i]);
break;
}
}
}
if(Core.input.keyTap(KeyCode.ESCAPE)){
if(!menu.isShown()){
menu.show();

View File

@@ -29,47 +29,49 @@ public class MapInfoDialog extends FloatingDialog{
cont.clear();
ObjectMap<String, String> tags = editor.getTags();
cont.pane(t -> {
t.add("$editor.name").padRight(8).left();
t.defaults().padTop(15);
cont.add("$editor.name").padRight(8).left();
TextField name = t.addField(tags.get("name", ""), text -> {
tags.put("name", text);
}).size(400, 55f).get();
name.setMessageText("$unknown");
cont.defaults().padTop(15);
t.row();
t.add("$editor.description").padRight(8).left();
TextField name = cont.addField(tags.get("name", ""), text -> {
tags.put("name", text);
}).size(400, 55f).get();
name.setMessageText("$unknown");
TextArea description = t.addArea(tags.get("description", ""), "textarea", text -> {
tags.put("description", text);
}).size(400f, 140f).get();
cont.row();
cont.add("$editor.description").padRight(8).left();
t.row();
t.add("$editor.author").padRight(8).left();
TextArea description = cont.addArea(tags.get("description", ""), "textarea", text -> {
tags.put("description", text);
}).size(400f, 140f).get();
TextField author = t.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> {
tags.put("author", text);
Core.settings.put("mapAuthor", text);
Core.settings.save();
}).size(400, 55f).get();
author.setMessageText("$unknown");
cont.row();
cont.add("$editor.author").padRight(8).left();
t.row();
t.add("$editor.rules").padRight(8).left();
t.addButton("$edit", () -> ruleInfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f);
TextField author = cont.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> {
tags.put("author", text);
Core.settings.put("mapAuthor", text);
Core.settings.save();
}).size(400, 55f).get();
author.setMessageText("$unknown");
t.row();
t.add("$editor.waves").padRight(8).left();
t.addButton("$edit", waveInfo::show).left().width(200f);
cont.row();
cont.add("$editor.rules").padRight(8).left();
cont.addButton("$edit", () -> ruleInfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f);
name.change();
description.change();
author.change();
cont.row();
cont.add("$editor.waves").padRight(8).left();
cont.addButton("$edit", waveInfo::show).left().width(200f);
name.change();
description.change();
author.change();
Platform.instance.addDialog(name, 50);
Platform.instance.addDialog(author, 50);
Platform.instance.addDialog(description, 1000);
Platform.instance.addDialog(name, 50);
Platform.instance.addDialog(author, 50);
Platform.instance.addDialog(description, 1000);
t.margin(16f);
});
}
}

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.editor;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.GestureDetector;
@@ -24,7 +23,6 @@ import static io.anuke.mindustry.Vars.ui;
public class MapView extends Element implements GestureListener{
private MapEditor editor;
private EditorTool tool = EditorTool.pencil;
private Bresenham2 br = new Bresenham2();
private float offsetx, offsety;
private float zoom = 1f;
private boolean grid = false;
@@ -107,19 +105,8 @@ public class MapView extends Element implements GestureListener{
Point2 p = project(x, y);
if(tool == EditorTool.line){
if(Core.input.keyDown(KeyCode.TAB)){
if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){
p.y = firstTouch.y;
}else{
p.x = firstTouch.x;
}
}
ui.editor.resetSaved();
Array<Point2> points = br.line(startx, starty, p.x, p.y);
for(Point2 point : points){
editor.draw(point.x, point.y, EditorTool.isPaint());
}
tool.touchedLine(editor, startx, starty, p.x, p.y);
}
editor.flushOp();
@@ -133,7 +120,6 @@ public class MapView extends Element implements GestureListener{
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer){
mousex = x;
mousey = y;
@@ -141,13 +127,10 @@ public class MapView extends Element implements GestureListener{
if(drawing && tool.draggable && !(p.x == lastx && p.y == lasty)){
ui.editor.resetSaved();
Array<Point2> points = br.line(lastx, lasty, p.x, p.y);
for(Point2 point : points){
tool.touched(editor, point.x, point.y);
}
Bresenham2.line(lastx, lasty, p.x, p.y, (cx, cy) -> tool.touched(editor, cx, cy));
}
if(tool == EditorTool.line && Core.input.keyDown(KeyCode.TAB)){
if(tool == EditorTool.line && tool.mode == 1){
if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){
lastx = p.x;
lasty = firstTouch.y;
@@ -296,7 +279,13 @@ public class MapView extends Element implements GestureListener{
if((tool.edit || (tool == EditorTool.line && !drawing)) && (!mobile || drawing)){
Point2 p = project(mousex, mousey);
Vector2 v = unproject(p.x, p.y).add(x, y);
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
//pencil square outline
if(tool == EditorTool.pencil && tool.mode == 1){
Lines.square(v.x + scaling/2f, v.y + scaling/2f, scaling * (editor.brushSize + 0.5f));
}else{
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
}
}
}else{
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){

View File

@@ -27,17 +27,8 @@ public class Net{
private static ObjectMap<Class<?>, BiConsumer<Integer, Object>> serverListeners = new ObjectMap<>();
private static ClientProvider clientProvider;
private static ServerProvider serverProvider;
private static IntMap<StreamBuilder> streams = new IntMap<>();
public static boolean hasClient(){
return clientProvider != null;
}
public static boolean hasServer(){
return serverProvider != null;
}
/** Display a network error. Call on the graphics thread. */
public static void showError(Throwable e){
@@ -50,12 +41,13 @@ public class Net{
String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase();
String type = t.getClass().toString().toLowerCase();
boolean isError = false;
if(e instanceof BufferUnderflowException || e instanceof BufferOverflowException){
error = Core.bundle.get("error.io");
}else if(error.equals("mismatch")){
error = Core.bundle.get("error.mismatch");
}else if(error.contains("port out of range") || error.contains("invalid argument") || (error.contains("invalid") && error.contains("address"))){
}else if(error.contains("port out of range") || error.contains("invalid argument") || (error.contains("invalid") && error.contains("address")) || Strings.parseException(e, true).contains("address associated")){
error = Core.bundle.get("error.invalidaddress");
}else if(error.contains("connection refused") || error.contains("route to host") || type.contains("unknownhost")){
error = Core.bundle.get("error.unreachable");
@@ -65,9 +57,14 @@ public class Net{
error = Core.bundle.get("error.alreadyconnected");
}else if(!error.isEmpty()){
error = Core.bundle.get("error.any") + "\n" + Strings.parseException(e, true);
isError = true;
}
ui.showText("", Core.bundle.format("connectfail", error));
if(isError){
ui.showError(Core.bundle.format("connectfail", error));
}else{
ui.showText("", Core.bundle.format("connectfail", error));
}
ui.loadfrag.hide();
if(Net.client()){

View File

@@ -27,6 +27,8 @@ import io.anuke.mindustry.input.InputHandler.PlaceDraw;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.Bar;
import io.anuke.mindustry.ui.ContentDisplay;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.OverlayFloor;
import io.anuke.mindustry.world.consumers.*;
import io.anuke.mindustry.world.meta.*;
@@ -658,6 +660,18 @@ public class Block extends BlockStorage{
return buildVisibility.get() && !isHidden();
}
public boolean isFloor(){
return this instanceof Floor;
}
public boolean isOverlay(){
return this instanceof OverlayFloor;
}
public Floor asFloor(){
return (Floor)this;
}
@Override
public boolean isHidden(){
return !buildVisibility.get();

View File

@@ -9,8 +9,7 @@ import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.blocks.BlockPart;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.modules.*;
import static io.anuke.mindustry.Vars.*;
@@ -161,6 +160,13 @@ public class Tile implements Position, TargetTrait{
this.overlay = 0;
}
/** Sets the floor, preserving overlay.*/
public void setFloorUnder(Floor floor){
Block overlay = overlay();
setFloor(floor);
setOverlay(overlay);
}
public byte rotation(){
return rotation;
}
@@ -190,7 +196,7 @@ public class Tile implements Position, TargetTrait{
}
public void clearOverlay(){
this.overlay = 0;
setOverlayID((short)0);
}
public boolean passable(){