Removed old maps, re-added map editor, broke compilation again
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 757 B |
Before Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 8.0 KiB |
@ -1,95 +0,0 @@
|
||||
{
|
||||
"maps": [
|
||||
{
|
||||
"id": 0,
|
||||
"name": "maze",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "fortress",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "sinkhole",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "caves",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "volcano",
|
||||
"visible": true,
|
||||
"flipBase": true,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "caldera",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "scorch",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "e5d8bb"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "desert",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "island",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "e5d8bb"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "grassland",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "5ab464"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "tundra",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "spiral",
|
||||
"visible": true,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "f7feff"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "tutorial",
|
||||
"visible": false,
|
||||
"flipBase": false,
|
||||
"backgroundColor": "646464"
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 547 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 7.9 KiB |
@ -1,5 +1,5 @@
|
||||
#Autogenerated file. Do not modify.
|
||||
#Sat Mar 17 21:20:30 EDT 2018
|
||||
#Sat Mar 17 21:49:13 EDT 2018
|
||||
version=release
|
||||
androidBuildCode=538
|
||||
name=Mindustry
|
||||
|
@ -7,6 +7,7 @@ import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.editor.MapEditorDialog;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
@ -43,7 +44,7 @@ public class UI extends SceneModule{
|
||||
public PausedDialog paused;
|
||||
public SettingsMenuDialog settings;
|
||||
public ControlsDialog controls;
|
||||
public FloatingDialog editor; //TODO change back to map editor dialog
|
||||
public MapEditorDialog editor;
|
||||
public LanguageDialog language;
|
||||
public BansDialog bans;
|
||||
public AdminsDialog admins;
|
||||
@ -143,7 +144,7 @@ public class UI extends SceneModule{
|
||||
@Override
|
||||
public void init(){
|
||||
|
||||
(editor = new FloatingDialog("The editor is currently broken.")).addCloseButton();
|
||||
editor = new MapEditorDialog();
|
||||
controls = new ControlsDialog();
|
||||
restart = new RestartDialog();
|
||||
join = new JoinDialog();
|
||||
|
39
core/src/io/anuke/mindustry/editor/DrawOperation.java
Executable file
@ -0,0 +1,39 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import io.anuke.mindustry.io.MapTileData;
|
||||
import io.anuke.mindustry.io.MapTileData.TileDataWriter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class DrawOperation implements Disposable{
|
||||
/**Data to apply operation to.*/
|
||||
MapTileData data;
|
||||
/**Format:
|
||||
* position (int)
|
||||
* packed data FROM (use TileDataWriter's read/write methods)
|
||||
* packed data TO (use TileDataWriter's read/write methods)
|
||||
*/
|
||||
ByteBuffer operation;
|
||||
TileDataWriter writer = new TileDataWriter();
|
||||
|
||||
public DrawOperation(MapTileData data){
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void set(ByteBuffer operation) {
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
//TODO implement
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
//TODO implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {}
|
||||
|
||||
}
|
94
core/src/io/anuke/mindustry/editor/EditorTool.java
Normal file
@ -0,0 +1,94 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import com.badlogic.gdx.utils.IntSet;
|
||||
import io.anuke.mindustry.io.MapTileData.TileDataWriter;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public enum EditorTool{
|
||||
pick{
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
TileDataWriter writer = editor.getMap().readAt(x, y);
|
||||
Block block = Block.getByID(writer.wall == 0 ? writer.floor : writer.wall);
|
||||
editor.setDrawBlock(block);
|
||||
ui.editor.updateSelectedBlock();
|
||||
}
|
||||
},
|
||||
pencil{
|
||||
{
|
||||
edit = true;
|
||||
}
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y);
|
||||
}
|
||||
},
|
||||
line{
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
fill{
|
||||
{
|
||||
edit = true;
|
||||
}
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
//TODO select floor/block properly instead of using this method!
|
||||
boolean floor = editor.getDrawBlock() instanceof Floor;
|
||||
|
||||
TileDataWriter writer = editor.getMap().readAt(x, y);
|
||||
|
||||
byte dest = floor ? writer.floor : writer.wall;
|
||||
|
||||
int width = editor.getMap().width();
|
||||
int height = editor.getMap().height();
|
||||
|
||||
IntSet set = new IntSet();
|
||||
IntArray points = new IntArray();
|
||||
points.add(asInt(x, y, editor.getMap().width()));
|
||||
|
||||
while(points.size != 0){
|
||||
int pos = points.pop();
|
||||
int px = pos % width;
|
||||
int py = pos / width;
|
||||
set.add(pos);
|
||||
|
||||
writer = editor.getMap().readAt(px, py);
|
||||
|
||||
if((floor ? writer.floor : writer.wall) == dest){
|
||||
if(floor)
|
||||
writer.floor = dest;
|
||||
else
|
||||
writer.wall = dest;
|
||||
|
||||
editor.getMap().write(px, py, writer);
|
||||
editor.renderer().updatePoint(px, py);
|
||||
|
||||
if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width));
|
||||
if(py > 0 && !set.contains(asInt(px, py - 1, width))) points.add(asInt(px, py - 1, width));
|
||||
if(px < width - 1 && !set.contains(asInt(px + 1, py, width))) points.add(asInt(px + 1, py, width));
|
||||
if(py < height - 1 && !set.contains(asInt(px, py + 1, width))) points.add(asInt(px, py + 1, width));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int asInt(int x, int y, int width){
|
||||
return x+y*width;
|
||||
}
|
||||
|
||||
boolean colorEquals(int a, int b){
|
||||
return a == b;
|
||||
}
|
||||
},
|
||||
zoom;
|
||||
boolean edit;
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
|
||||
}
|
||||
}
|
81
core/src/io/anuke/mindustry/editor/MapEditor.java
Normal file
@ -0,0 +1,81 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.mindustry.io.MapTileData;
|
||||
import io.anuke.mindustry.io.MapTileData.TileDataWriter;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class MapEditor{
|
||||
public static final int minMapSize = 128, maxMapSize = 512;
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15};
|
||||
|
||||
private MapTileData map;
|
||||
private MapRenderer renderer = new MapRenderer(this);
|
||||
|
||||
private int brushSize = 1;
|
||||
private Block drawBlock = Blocks.stone;
|
||||
|
||||
public MapEditor(){
|
||||
|
||||
}
|
||||
|
||||
public MapTileData getMap(){
|
||||
return map;
|
||||
}
|
||||
|
||||
public void beginEdit(MapTileData map){
|
||||
drawBlock = Blocks.stone;
|
||||
this.map = map;
|
||||
this.brushSize = 1;
|
||||
}
|
||||
|
||||
public Block getDrawBlock(){
|
||||
return drawBlock;
|
||||
}
|
||||
|
||||
public void setDrawBlock(Block block){
|
||||
this.drawBlock = block;
|
||||
}
|
||||
|
||||
public void setBrushSize(int size){
|
||||
this.brushSize = size;
|
||||
}
|
||||
|
||||
public int getBrushSize() {
|
||||
return brushSize;
|
||||
}
|
||||
|
||||
public void draw(int dx, int dy){
|
||||
if(dx < 0 || dy < 0 || dx >= map.width() || dy >= map.height()){
|
||||
return;
|
||||
}
|
||||
|
||||
TileDataWriter writer = map.readAt(dx, dy);
|
||||
if(drawBlock instanceof Floor){
|
||||
writer.floor = (byte)drawBlock.id;
|
||||
}else{
|
||||
writer.wall = (byte)drawBlock.id;
|
||||
}
|
||||
|
||||
for(int rx = -brushSize + 1; rx <= brushSize - 1; rx ++){
|
||||
for(int ry = -brushSize + 1; ry <= brushSize - 1; ry ++){
|
||||
if(Mathf.dst(rx, ry) < brushSize){
|
||||
map.write(dx + rx, dy + ry, writer);
|
||||
renderer.updatePoint(dx + rx, dy + ry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MapRenderer renderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
map = new MapTileData(width, height);
|
||||
renderer.resize(width, height);
|
||||
}
|
||||
}
|
421
core/src/io/anuke/mindustry/editor/MapEditorDialog.java
Normal file
@ -0,0 +1,421 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import io.anuke.mindustry.io.MapTileData;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.core.Inputs;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.builders.build;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
|
||||
import static io.anuke.mindustry.Vars.gwt;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class MapEditorDialog extends Dialog{
|
||||
private MapEditor editor;
|
||||
private MapView view;
|
||||
private MapGenerateDialog dialog;
|
||||
private MapLoadDialog loadDialog;
|
||||
private MapSaveDialog saveDialog;
|
||||
private MapResizeDialog resizeDialog;
|
||||
private ScrollPane pane;
|
||||
//private FileChooser openFile, saveFile;
|
||||
private boolean saved = false;
|
||||
|
||||
private ButtonGroup<ImageButton> blockgroup;
|
||||
|
||||
public MapEditorDialog(){
|
||||
super("$text.mapeditor", "dialog");
|
||||
if(gwt) return;
|
||||
|
||||
editor = new MapEditor();
|
||||
dialog = new MapGenerateDialog(editor);
|
||||
view = new MapView(editor);
|
||||
/*
|
||||
openFile = new FileChooser("$text.loadimage", FileChooser.pngFilter, true, file -> {
|
||||
ui.loadfrag.show();
|
||||
Timers.run(3f, () -> {
|
||||
try{
|
||||
Pixmap pixmap = new Pixmap(file);
|
||||
if(verifySize(pixmap)){
|
||||
editor.setPixmap(pixmap);
|
||||
view.clearStack();
|
||||
}else{
|
||||
ui.showError(Bundles.format("text.editor.badsize", Arrays.toString(MapEditor.validMapSizes)));
|
||||
}
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
});
|
||||
|
||||
saveFile = new FileChooser("$saveimage", false, file -> {
|
||||
if(!file.extension().toLowerCase().equals(".png")){
|
||||
file = file.parent().child(file.nameWithoutExtension() + ".png");
|
||||
}
|
||||
FileHandle result = file;
|
||||
ui.loadfrag.show();
|
||||
Timers.run(3f, () -> {
|
||||
try{
|
||||
Pixmaps.write(editor.pixmap(), result);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
|
||||
if(!android) Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
});*/
|
||||
/*
|
||||
loadDialog = new MapLoadDialog(map -> {
|
||||
saveDialog.setFieldText(map.name);
|
||||
ui.loadfrag.show();
|
||||
|
||||
Timers.run(3f, () -> {
|
||||
Map copy = new Map();
|
||||
copy.name = map.name;
|
||||
copy.id = -1;
|
||||
copy.pixmap = Pixmaps.copy(map.pixmap);
|
||||
copy.texture = new Texture(copy.pixmap);
|
||||
copy.oreGen = map.oreGen;
|
||||
editor.beginEdit(copy);
|
||||
ui.loadfrag.hide();
|
||||
view.clearStack();
|
||||
});
|
||||
});*/
|
||||
|
||||
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
||||
if(!(editor.getMap().width() == x && editor.getMap().height() == y)){
|
||||
ui.loadfrag.show();
|
||||
Timers.run(10f, () -> {
|
||||
editor.resize(x, y);
|
||||
view.clearStack();
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
saveDialog = new MapSaveDialog(name -> {
|
||||
ui.loadfrag.show();
|
||||
if(verifyMap()){
|
||||
saved = true;
|
||||
String before = editor.getMap().name;
|
||||
editor.getMap().name = name;
|
||||
Timers.run(10f, () -> {
|
||||
world.maps().saveAndReload(editor.getMap(), editor.pixmap());
|
||||
loadDialog.rebuild();
|
||||
ui.loadfrag.hide();
|
||||
view.clearStack();
|
||||
|
||||
if(!name.equals(before)) {
|
||||
Map map = new Map();
|
||||
map.name = editor.getMap().name;
|
||||
map.oreGen = editor.getMap().oreGen;
|
||||
map.pixmap = Pixmaps.copy(editor.getMap().pixmap);
|
||||
map.texture = new Texture(map.pixmap);
|
||||
map.custom = true;
|
||||
editor.beginEdit(map);
|
||||
}
|
||||
});
|
||||
|
||||
}else{
|
||||
ui.loadfrag.hide();
|
||||
}
|
||||
});*/
|
||||
|
||||
setFillParent(true);
|
||||
|
||||
clearChildren();
|
||||
margin(0);
|
||||
build.begin(this);
|
||||
build();
|
||||
build.end();
|
||||
|
||||
tapped(() -> {
|
||||
Element e = Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true);
|
||||
if(e == null || !e.isDescendantOf(pane)) Core.scene.setScrollFocus(null);
|
||||
});
|
||||
|
||||
update(() -> {
|
||||
if(Core.scene != null && Core.scene.getKeyboardFocus() == this){
|
||||
doInput();
|
||||
}
|
||||
});
|
||||
|
||||
shown(() -> {
|
||||
saved = true;
|
||||
editor.beginEdit(new MapTileData(256, 256));
|
||||
blockgroup.getButtons().get(2).setChecked(true);
|
||||
Core.scene.setScrollFocus(view);
|
||||
view.clearStack();
|
||||
|
||||
Timers.runTask(10f, Platform.instance::updateRPC);
|
||||
});
|
||||
|
||||
hidden(() -> Platform.instance.updateRPC());
|
||||
}
|
||||
|
||||
public MapView getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public void resetSaved(){
|
||||
saved = false;
|
||||
}
|
||||
|
||||
public void updateSelectedBlock(){
|
||||
Block block = editor.getDrawBlock();
|
||||
int i = 0;
|
||||
for(BlockPair pair : ColorMapper.getPairs()){
|
||||
if(pair.wall == block || (pair.wall == Blocks.air && pair.floor == block)){
|
||||
blockgroup.getButtons().get(i).setChecked(true);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasPane(){
|
||||
return Core.scene.getScrollFocus() == pane;
|
||||
}
|
||||
|
||||
public void build(){
|
||||
|
||||
new table(){{
|
||||
float isize = 16*2f;
|
||||
aleft();
|
||||
|
||||
new table(){{
|
||||
|
||||
defaults().growY().width(130f).padBottom(-6);
|
||||
|
||||
new imagebutton("icon-terrain", isize, () ->
|
||||
dialog.show()
|
||||
).text("$text.editor.generate");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-resize", isize, () ->
|
||||
resizeDialog.show()
|
||||
).text("$text.editor.resize").padTop(4f);
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-load-map", isize, () ->
|
||||
loadDialog.show()
|
||||
).text("$text.editor.loadmap");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-save-map", isize, ()->
|
||||
saveDialog.show()
|
||||
).text("$text.editor.savemap");
|
||||
|
||||
row();
|
||||
/*
|
||||
new imagebutton("icon-load-image", isize, () ->
|
||||
openFile.show()
|
||||
).text("$text.editor.loadimage");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-save-image", isize, () ->
|
||||
saveFile.show()
|
||||
).text("$text.editor.saveimage");*/
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-back", isize, () -> {
|
||||
if(!saved){
|
||||
ui.showConfirm("$text.confirm", "$text.editor.unsaved",
|
||||
MapEditorDialog.this::hide);
|
||||
}else{
|
||||
hide();
|
||||
}
|
||||
}).padBottom(0).text("$text.back");
|
||||
|
||||
}}.left().growY().end();
|
||||
|
||||
new table("button"){{
|
||||
add(view).grow();
|
||||
}}.grow().end();
|
||||
|
||||
new table(){{
|
||||
Table tools = new Table("button");
|
||||
tools.top();
|
||||
tools.marginTop(0).marginBottom(6);
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
int i = 1;
|
||||
|
||||
tools.defaults().size(53f, 58f).padBottom(-6);
|
||||
|
||||
ImageButton undo = tools.addImageButton("icon-undo", 16*2f, () -> view.undo()).get();
|
||||
ImageButton redo = tools.addImageButton("icon-redo", 16*2f, () -> view.redo()).get();
|
||||
ImageButton grid = tools.addImageButton("icon-grid", "toggle", 16*2f, () -> view.setGrid(!view.isGrid())).get();
|
||||
|
||||
undo.setDisabled(() -> !view.getStack().canUndo());
|
||||
redo.setDisabled(() -> !view.getStack().canRedo());
|
||||
|
||||
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
|
||||
redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE));
|
||||
grid.update(() -> grid.setChecked(view.isGrid()));
|
||||
|
||||
for(EditorTool tool : EditorTool.values()){
|
||||
ImageButton button = new ImageButton("icon-" + tool.name(), "toggle");
|
||||
button.clicked(() -> view.setTool(tool));
|
||||
button.resizeImage(16*2f);
|
||||
button.update(() -> button.setChecked(view.getTool() == tool));
|
||||
group.add(button);
|
||||
if (tool == EditorTool.pencil)
|
||||
button.setChecked(true);
|
||||
|
||||
tools.add(button).padBottom(-6f);
|
||||
if(i++ % 4 == 1) tools.row();
|
||||
}
|
||||
|
||||
add(tools).width(53*4).padBottom(-6);
|
||||
|
||||
row();
|
||||
|
||||
new table("button"){{
|
||||
margin(10f);
|
||||
Slider slider = new Slider(0, MapEditor.brushSizes.length-1, 1, false);
|
||||
slider.moved(f -> editor.setBrushSize(MapEditor.brushSizes[(int)(float)f]));
|
||||
new label(() -> Bundles.format("text.editor.brushsize", MapEditor.brushSizes[(int)slider.getValue()])).left();
|
||||
row();
|
||||
add(slider).growX().padTop(4f);
|
||||
}}.growX().padBottom(-6).end();
|
||||
|
||||
row();
|
||||
|
||||
/*
|
||||
new table("button"){{
|
||||
get().addCheck("$text.oregen", b -> editor.getMap().oreGen = b)
|
||||
.update(c -> c.setChecked(editor.getMap().oreGen)).padTop(3).padBottom(3);
|
||||
}}.growX().padBottom(-6).end();*/
|
||||
|
||||
row();
|
||||
|
||||
addBlockSelection(get());
|
||||
|
||||
row();
|
||||
|
||||
}}.right().growY().end();
|
||||
}}.grow().end();
|
||||
}
|
||||
|
||||
private void doInput(){
|
||||
//tool select
|
||||
for(int i = 0; i < EditorTool.values().length; i ++){
|
||||
int code = i == 0 ? 5 : i;
|
||||
if(Inputs.keyTap("weapon_" + code)){
|
||||
view.setTool(EditorTool.values()[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//ctrl keys (undo, redo, save)
|
||||
if(Inputs.keyDown(Keys.CONTROL_LEFT)){
|
||||
if(Inputs.keyTap(Keys.Z)){
|
||||
view.undo();
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Keys.Y)){
|
||||
view.redo();
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Keys.S)){
|
||||
saveDialog.save();
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Keys.G)){
|
||||
view.setGrid(!view.isGrid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean verifyMap(){
|
||||
//TODO make sure both teams have cores or something
|
||||
/*
|
||||
int psc = ColorMapper.getColor(SpecialBlocks.playerSpawn);
|
||||
int esc = ColorMapper.getColor(SpecialBlocks.enemySpawn);
|
||||
|
||||
int playerSpawns = 0;
|
||||
int enemySpawns = 0;
|
||||
Pixmap pix = editor.pixmap();
|
||||
|
||||
for(int x = 0; x < pix.getWidth(); x ++){
|
||||
for(int y = 0; y < pix.getHeight(); y ++){
|
||||
int i = pix.getPixel(x, y);
|
||||
if(i == psc) playerSpawns ++;
|
||||
if(i == esc) enemySpawns ++;
|
||||
}
|
||||
}
|
||||
|
||||
if(playerSpawns == 0){
|
||||
ui.showError("$text.editor.noplayerspawn");
|
||||
return false;
|
||||
}else if(playerSpawns > 1){
|
||||
ui.showError("$text.editor.manyplayerspawns");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(enemySpawns > MapEditor.maxSpawnpoints){
|
||||
ui.showError(Bundles.format("text.editor.manyenemyspawns", MapEditor.maxSpawnpoints));
|
||||
return false;
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addBlockSelection(Table table){
|
||||
Table content = new Table();
|
||||
pane = new ScrollPane(content, "volume");
|
||||
pane.setScrollingDisabled(true, false);
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setOverscroll(true, false);
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
blockgroup = group;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(BlockPair pair : ColorMapper.getPairs()){
|
||||
Block block = pair.wall == Blocks.air ? pair.floor : pair.wall;
|
||||
|
||||
ImageButton button = new ImageButton(Draw.hasRegion(block.name) ? Draw.region(block.name) : Draw.region(block.name + "1"), "toggle");
|
||||
button.clicked(() -> editor.setDrawBlock(block));
|
||||
button.resizeImage(8*4f);
|
||||
group.add(button);
|
||||
content.add(button).pad(4f).size(53f, 58f);
|
||||
|
||||
if(i++ % 2 == 1){
|
||||
content.row();
|
||||
}
|
||||
}
|
||||
|
||||
group.getButtons().get(2).setChecked(true);
|
||||
|
||||
Table extra = new Table("button");
|
||||
extra.labelWrap(() -> editor.getDrawBlock().formalName).width(180f).center();
|
||||
table.add(extra).padBottom(-6).growX();
|
||||
table.row();
|
||||
table.add(pane).growY().fillX();
|
||||
}
|
||||
}
|
244
core/src/io/anuke/mindustry/editor/MapFilter.java
Normal file
@ -0,0 +1,244 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import com.badlogic.gdx.utils.OrderedMap;
|
||||
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
import io.anuke.ucore.noise.RidgedPerlin;
|
||||
import io.anuke.ucore.noise.Simplex;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class MapFilter{
|
||||
private ObjectMap<String, GenPref> prefs = map(
|
||||
pref("replace", "whether to replace blocks"),
|
||||
pref("terrain", "generate new terrain"),
|
||||
pref("circle", "generate terrain in a circle"),
|
||||
pref("distort", "distort the map image"),
|
||||
pref("sand", "add patches of sand"),
|
||||
pref("grass", "add patches of grass"),
|
||||
pref("stone", "add patches of stone"),
|
||||
pref("blackstone", "add patches of black stone"),
|
||||
pref("allgrass", "fill map with grass"),
|
||||
pref("allsnow", "fill map with snow"),
|
||||
pref("allsand", "fill map with sand"),
|
||||
pref("water", "add lakes"),
|
||||
pref("oil", "add oil lakes"),
|
||||
pref("lavariver", "add lava rivers"),
|
||||
pref("slavariver", "ad small lava rivers"),
|
||||
pref("river", "add rivers"),
|
||||
pref("iceriver", "add frozen rivers"),
|
||||
pref("oilriver", "add oil rivers")
|
||||
);
|
||||
|
||||
private Simplex sim = new Simplex();
|
||||
private RidgedPerlin rid = new RidgedPerlin(1, 10, 20f);
|
||||
private RidgedPerlin rid2 = new RidgedPerlin(1, 6, 1f);
|
||||
private RidgedPerlin rid3 = new RidgedPerlin(1, 6, 1f);
|
||||
|
||||
public MapFilter(){
|
||||
prefs.get("replace").enabled = true;
|
||||
prefs.get("terrain").enabled = true;
|
||||
randomize();
|
||||
}
|
||||
|
||||
public void randomize(){
|
||||
sim.setSeed(Mathf.random(999999));
|
||||
rid.setSeed(Mathf.random(999999));
|
||||
rid2.setSeed(Mathf.random(999999));
|
||||
rid3.setSeed(Mathf.random(999999));
|
||||
}
|
||||
|
||||
public ObjectMap<String, GenPref> getPrefs(){
|
||||
return prefs;
|
||||
}
|
||||
|
||||
public Pixmap process(Pixmap pixmap){
|
||||
if(prefs.get("terrain").enabled){
|
||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||
float dist = Vector2.dst((float) x / pixmap.getWidth(), (float) y / pixmap.getHeight(), 0.5f, 0.5f) * 2f;
|
||||
double noise = sim.octaveNoise2D(6, 0.6, 1 / 180.0, x, y + 9999) / (prefs.get("circle").enabled ? 1.7 : 1f) + dist / 10f;
|
||||
|
||||
if(dist > 0.8){
|
||||
noise += 2 * (dist - 0.8);
|
||||
}
|
||||
|
||||
Block block = noise > 0.6 ? Blocks.stoneblock : Blocks.stone;
|
||||
|
||||
pixmap.drawPixel(x, y, ColorMapper.getColor(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pixmap src = Pixmaps.copy(pixmap);
|
||||
|
||||
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||
int dx = 0, dy = 0;
|
||||
|
||||
if(prefs.get("distort").enabled){
|
||||
double intensity = 12;
|
||||
double scale = 80;
|
||||
double octaves = 4;
|
||||
double falloff = 0.6;
|
||||
double nx = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y) - 0.5f) * intensity;
|
||||
double ny = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y + 99999) - 0.5f) * intensity;
|
||||
dx = (int) nx;
|
||||
dy = (int) ny;
|
||||
}
|
||||
|
||||
int pix = src.getPixel(x + dx, y + dy);
|
||||
|
||||
BlockPair pair = ColorMapper.get(pix);
|
||||
Block block = pair == null ? null : pair.wall == Blocks.air ? pair.floor : pair.wall;
|
||||
|
||||
if(block == null)
|
||||
continue;
|
||||
|
||||
boolean floor = block instanceof Floor;
|
||||
|
||||
double noise = sim.octaveNoise2D(4, 0.6, 1 / 170.0, x, y) + sim.octaveNoise2D(1, 1.0, 1 / 5.0, x, y) / 18.0;
|
||||
double nwater = sim.octaveNoise2D(1, 1.0, 1 / 130.0, x, y);
|
||||
noise += nwater / 5.0;
|
||||
|
||||
double noil = sim.octaveNoise2D(1, 1.0, 1 / 150.0, x + 9999, y) + sim.octaveNoise2D(1, 1.0, 1 / 2.0, x, y) / 290.0;
|
||||
|
||||
if(!floor || prefs.get("replace").enabled){
|
||||
|
||||
if(prefs.get("allgrass").enabled){
|
||||
block = floor ? Blocks.grass : Blocks.grassblock;
|
||||
}else if(prefs.get("allsnow").enabled){
|
||||
block = floor ? Blocks.snow : Blocks.snowblock;
|
||||
}else if(prefs.get("allsand").enabled){
|
||||
block = floor ? Blocks.sand : Blocks.sandblock;
|
||||
}else if(prefs.get("replace").enabled){
|
||||
block = floor ? Blocks.stone : Blocks.stoneblock;
|
||||
}
|
||||
|
||||
if(noise > 0.7 && prefs.get("grass").enabled){
|
||||
block = floor ? Blocks.grass : Blocks.grassblock;
|
||||
}
|
||||
if(noise > 0.7 && prefs.get("blackstone").enabled){
|
||||
block = floor ? Blocks.blackstone : Blocks.blackstoneblock;
|
||||
}
|
||||
if(noise > 0.7 && prefs.get("sand").enabled){
|
||||
block = floor ? Blocks.sand : Blocks.sandblock;
|
||||
}
|
||||
if(noise > 0.8 && prefs.get("stone").enabled){
|
||||
block = floor ? Blocks.stone : Blocks.stoneblock;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor){
|
||||
if(nwater > 0.93 && prefs.get("water").enabled){
|
||||
block = Blocks.water;
|
||||
if(nwater > 0.943){
|
||||
block = Blocks.deepwater;
|
||||
}
|
||||
}
|
||||
|
||||
if(noil > 0.95 && prefs.get("oil").enabled){
|
||||
block = Blocks.dirt;
|
||||
if(noil > 0.955){
|
||||
block = Blocks.oil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("lavariver").enabled){
|
||||
double lava = rid.getValue(x, y, 1 / 100f);
|
||||
double t = 0.6;
|
||||
if(lava > t){
|
||||
block = Blocks.lava;
|
||||
}else if(lava > t - 0.2){
|
||||
block = Blocks.blackstone;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("slavariver").enabled){
|
||||
double lava = rid.getValue(x, y, 1 / 40f);
|
||||
double t = 0.7;
|
||||
if(lava > t){
|
||||
block = Blocks.lava;
|
||||
}else if(lava > t - 0.3){
|
||||
block = Blocks.blackstone;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("oilriver").enabled){
|
||||
double lava = rid3.getValue(x, y, 1 / 100f);
|
||||
double t = 0.9;
|
||||
if(lava > t){
|
||||
block = Blocks.oil;
|
||||
}else if(lava > t - 0.2){
|
||||
block = Blocks.dirt;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("river").enabled){
|
||||
double riv = rid2.getValue(x, y, 1 / 140f);
|
||||
double t = 0.4;
|
||||
|
||||
if(riv > t + 0.1){
|
||||
block = Blocks.deepwater;
|
||||
}else if(riv > t){
|
||||
block = Blocks.water;
|
||||
}else if(riv > t - 0.2){
|
||||
block = Blocks.grass;
|
||||
}
|
||||
}
|
||||
|
||||
if(floor && prefs.get("iceriver").enabled){
|
||||
double riv = rid2.getValue(x, y, 1 / 140f);
|
||||
double t = 0.4;
|
||||
|
||||
if(riv > t + 0.1){
|
||||
block = Blocks.ice;
|
||||
}else if(riv > t){
|
||||
block = Blocks.ice;
|
||||
}else if(riv > t - 0.2){
|
||||
block = Blocks.snow;
|
||||
}
|
||||
}
|
||||
|
||||
pixmap.drawPixel(x, y, ColorMapper.getColor(block));
|
||||
}
|
||||
}
|
||||
|
||||
src.dispose();
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
private static OrderedMap<String, GenPref> map(GenPref...objects){
|
||||
OrderedMap<String, GenPref> prefs = new OrderedMap<>();
|
||||
|
||||
for(int i = 0; i < objects.length; i ++){
|
||||
GenPref pref = (GenPref)objects[i];
|
||||
prefs.put(pref.name, pref);
|
||||
}
|
||||
return prefs;
|
||||
}
|
||||
|
||||
private GenPref pref(String name, String desc){
|
||||
return new GenPref(name, desc);
|
||||
}
|
||||
|
||||
class GenPref{
|
||||
public final String name;
|
||||
public final String description;
|
||||
public boolean enabled;
|
||||
|
||||
GenPref(String name, String description){
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
105
core/src/io/anuke/mindustry/editor/MapGenerateDialog.java
Normal file
@ -0,0 +1,105 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Scaling;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import io.anuke.mindustry.editor.MapFilter.GenPref;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
import io.anuke.ucore.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.ucore.scene.ui.CheckBox;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Stack;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
public class MapGenerateDialog extends FloatingDialog{
|
||||
private MapEditor editor;
|
||||
private Image image;
|
||||
private boolean loading;
|
||||
|
||||
public MapGenerateDialog(MapEditor editor) {
|
||||
super("$text.editor.generate");
|
||||
this.editor = editor;
|
||||
|
||||
Stack stack = new Stack();
|
||||
stack.add(image = new BorderImage());
|
||||
|
||||
Image loadImage = new Image("icon-loading");
|
||||
loadImage.setScaling(Scaling.none);
|
||||
loadImage.setScale(3f);
|
||||
loadImage.update(() -> loadImage.setOrigin(Align.center));
|
||||
loadImage.setVisible(() -> loading);
|
||||
Image next = new Image("white");
|
||||
next.setScaling(Scaling.fit);
|
||||
next.setColor(0, 0, 0, 0.6f);
|
||||
next.setVisible(() -> loading);
|
||||
|
||||
stack.add(next);
|
||||
stack.add(loadImage);
|
||||
|
||||
content().add(stack).grow();
|
||||
image.setScaling(Scaling.fit);
|
||||
Table preft = new Table();
|
||||
preft.left();
|
||||
preft.margin(4f).marginRight(25f);
|
||||
|
||||
for(GenPref pref : editor.getFilter().getPrefs().values()){
|
||||
CheckBox box = new CheckBox(pref.name);
|
||||
box.setChecked(pref.enabled);
|
||||
box.changed(() -> pref.enabled = box.isChecked());
|
||||
preft.add(box).pad(4f).left();
|
||||
preft.row();
|
||||
}
|
||||
|
||||
ScrollPane pane = new ScrollPane(preft, "volume");
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setScrollingDisabled(true, false);
|
||||
|
||||
content().add(pane).fillY();
|
||||
|
||||
buttons().defaults().size(170f, 50f).pad(4f);
|
||||
buttons().addButton("$text.back", this::hide);
|
||||
buttons().addButton("$text.randomize", () ->{
|
||||
editor.getFilter().randomize();
|
||||
apply();
|
||||
});
|
||||
buttons().addButton("$text.update", this::apply);
|
||||
buttons().addButton("$text.apply", () ->{
|
||||
ui.loadfrag.show();
|
||||
|
||||
Timers.run(3f, () ->{
|
||||
Pixmap copy = Pixmaps.copy(editor.pixmap());
|
||||
editor.applyFilter();
|
||||
ui.editor.getView().push(copy, Pixmaps.copy(editor.pixmap()));
|
||||
ui.loadfrag.hide();
|
||||
ui.editor.resetSaved();
|
||||
hide();
|
||||
});
|
||||
});
|
||||
|
||||
shown(() ->{
|
||||
loading = true;
|
||||
Timers.run(30f, () -> {
|
||||
editor.applyFilterPreview();
|
||||
image.setDrawable(new TextureRegionDrawable(new TextureRegion(editor.getFilterTexture())));
|
||||
loading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void apply(){
|
||||
loading = true;
|
||||
Timers.run(3f, () -> {
|
||||
editor.applyFilterPreview();
|
||||
loading = false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
73
core/src/io/anuke/mindustry/editor/MapLoadDialog.java
Normal file
@ -0,0 +1,73 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapLoadDialog extends FloatingDialog{
|
||||
private Map selected = world.maps().getMap(0);
|
||||
|
||||
public MapLoadDialog(Consumer<Map> loader) {
|
||||
super("$text.editor.loadmap");
|
||||
|
||||
shown(this::rebuild);
|
||||
rebuild();
|
||||
|
||||
TextButton button = new TextButton("$text.load");
|
||||
button.setDisabled(() -> selected == null);
|
||||
button.clicked(() -> {
|
||||
if (selected != null) {
|
||||
loader.accept(selected);
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().add(button);
|
||||
}
|
||||
|
||||
public void rebuild(){
|
||||
content().clear();
|
||||
|
||||
selected = world.maps().getMap(0);
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
|
||||
int maxcol = 3;
|
||||
|
||||
int i = 0;
|
||||
|
||||
Table table = new Table();
|
||||
table.defaults().size(200f, 90f).pad(4f);
|
||||
table.margin(10f);
|
||||
|
||||
ScrollPane pane = new ScrollPane(table, "horizontal");
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
for (Map map : world.maps().list()) {
|
||||
if (!map.visible) continue;
|
||||
|
||||
TextButton button = new TextButton(map.localized(), "toggle");
|
||||
button.add(new BorderImage(map.texture, 2f)).size(16 * 4f);
|
||||
button.getCells().reverse();
|
||||
button.clicked(() -> selected = map);
|
||||
button.getLabelCell().grow().left().padLeft(5f);
|
||||
group.add(button);
|
||||
table.add(button);
|
||||
if (++i % maxcol == 0) table.row();
|
||||
}
|
||||
|
||||
content().add("$text.editor.loadmap");
|
||||
content().row();
|
||||
content().add(pane);
|
||||
}
|
||||
|
||||
}
|
103
core/src/io/anuke/mindustry/editor/MapRenderer.java
Normal file
@ -0,0 +1,103 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.utils.IntSet;
|
||||
import com.badlogic.gdx.utils.IntSet.IntSetIterator;
|
||||
import io.anuke.mindustry.io.MapTileData.TileDataWriter;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.graphics.CacheBatch;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class MapRenderer {
|
||||
private static final int chunksize = 32;
|
||||
private CacheBatch batch;
|
||||
private int[][] chunks;
|
||||
private IntSet updates = new IntSet();
|
||||
private MapEditor editor;
|
||||
|
||||
public MapRenderer(MapEditor editor){
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
batch = new CacheBatch(width * height * 3);
|
||||
chunks = new int[width / chunksize][height / chunksize];
|
||||
updates.clear();
|
||||
updateAll();
|
||||
}
|
||||
|
||||
public void draw(){
|
||||
Graphics.end();
|
||||
Graphics.useBatch(batch);
|
||||
|
||||
IntSetIterator it = updates.iterator();
|
||||
int i = it.next();
|
||||
for(; it.hasNext; i = it.next()){
|
||||
int x = i % chunks.length;
|
||||
int y = i / chunks.length;
|
||||
render(x, y, chunks[x][y]);
|
||||
}
|
||||
updates.clear();
|
||||
|
||||
Graphics.popBatch();
|
||||
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND);
|
||||
|
||||
batch.beginDraw();
|
||||
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
int id = chunks[x][y];
|
||||
batch.drawCache(id);
|
||||
}
|
||||
}
|
||||
|
||||
batch.endDraw();
|
||||
|
||||
Graphics.begin();
|
||||
}
|
||||
|
||||
public void updatePoint(int x, int y){
|
||||
x /= chunksize;
|
||||
y /= chunksize;
|
||||
updates.add(x + y * chunks.length);
|
||||
}
|
||||
|
||||
public void updateAll(){
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
render(x, y, chunks[x][y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void render(int chunkx, int chunky, int previousID){
|
||||
if(previousID == -1){
|
||||
batch.begin();
|
||||
}else{
|
||||
batch.begin(previousID);
|
||||
}
|
||||
|
||||
for(int x = 0; x < chunkx; x ++){
|
||||
for(int y = 0; y < chunky; y ++){
|
||||
int wx = chunkx*chunksize + x;
|
||||
int wy = chunky*chunksize + y;
|
||||
|
||||
TileDataWriter data = editor.getMap().readAt(wx, wy);
|
||||
Block floor = Block.getByID(data.floor);
|
||||
Block wall = Block.getByID(data.wall);
|
||||
|
||||
if(floor != Blocks.air) Draw.rect(floor.name, wx * tilesize, wy * tilesize);
|
||||
if(floor != Blocks.air) Draw.rect(wall.name, wx * tilesize, wy * tilesize);
|
||||
}
|
||||
}
|
||||
|
||||
batch.end();
|
||||
chunks[chunkx][chunky] = batch.getLastCache();
|
||||
}
|
||||
}
|
67
core/src/io/anuke/mindustry/editor/MapResizeDialog.java
Normal file
@ -0,0 +1,67 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.function.BiConsumer;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
public class MapResizeDialog extends FloatingDialog{
|
||||
int width, height;
|
||||
|
||||
public MapResizeDialog(MapEditor editor, BiConsumer<Integer, Integer> cons){
|
||||
super("$text.editor.resizemap");
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
Pixmap pix = editor.pixmap();
|
||||
width = pix.getWidth();
|
||||
height = pix.getHeight();
|
||||
|
||||
Table table = new Table();
|
||||
|
||||
for(int d = 0; d < 2; d ++){
|
||||
boolean w = d == 0;
|
||||
int curr = d == 0 ? pix.getWidth() : pix.getHeight();
|
||||
int idx = 0;
|
||||
for(int i = 0; i < MapEditor.validMapSizes.length; i ++)
|
||||
if(MapEditor.validMapSizes[i] == curr) idx = i;
|
||||
|
||||
table.add(d == 0 ? "$text.width": "$text.height").padRight(8f);
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
for(int i = 0; i < MapEditor.validMapSizes.length; i ++){
|
||||
int size = MapEditor.validMapSizes[i];
|
||||
TextButton button = new TextButton(size + "", "toggle");
|
||||
button.clicked(() -> {
|
||||
if(w)
|
||||
width = size;
|
||||
else
|
||||
height = size;
|
||||
});
|
||||
group.add(button);
|
||||
if(i == idx) button.setChecked(true);
|
||||
table.add(button).size(100f, 54f).pad(2f);
|
||||
}
|
||||
|
||||
table.row();
|
||||
}
|
||||
|
||||
content().label(() ->
|
||||
width + height > 512 ? "$text.editor.resizebig" : ""
|
||||
).get().setAlignment(Align.center, Align.center);
|
||||
content().row();
|
||||
content().add(table);
|
||||
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().addButton("$text.editor.resize", () -> {
|
||||
cons.accept(width, height);
|
||||
hide();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
75
core/src/io/anuke/mindustry/editor/MapSaveDialog.java
Normal file
@ -0,0 +1,75 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapSaveDialog extends FloatingDialog{
|
||||
private TextField field;
|
||||
private Consumer<String> listener;
|
||||
|
||||
public MapSaveDialog(Consumer<String> cons){
|
||||
super("$text.editor.savemap");
|
||||
field = new TextField();
|
||||
listener = cons;
|
||||
|
||||
Platform.instance.addDialog(field);
|
||||
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
content().label(() ->{
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
if(map != null){
|
||||
if(map.custom){
|
||||
return "$text.editor.overwrite";
|
||||
}else{
|
||||
return "$text.editor.failoverwrite";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}).colspan(2);
|
||||
content().row();
|
||||
content().add("$text.editor.mapname").padRight(14f);
|
||||
content().add(field).size(220f, 48f);
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f).pad(2f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
|
||||
TextButton button = new TextButton("$text.save");
|
||||
button.clicked(() -> {
|
||||
if(!invalid()){
|
||||
cons.accept(field.getText());
|
||||
hide();
|
||||
}
|
||||
});
|
||||
button.setDisabled(this::invalid);
|
||||
buttons().add(button);
|
||||
}
|
||||
|
||||
public void save(){
|
||||
if(!invalid()){
|
||||
listener.accept(field.getText());
|
||||
}else{
|
||||
ui.showError("$text.editor.failoverwrite");
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldText(String text){
|
||||
field.setText(text);
|
||||
}
|
||||
|
||||
private boolean invalid(){
|
||||
if(field.getText().isEmpty()){
|
||||
return true;
|
||||
}
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
return map != null && !map.custom;
|
||||
}
|
||||
}
|
328
core/src/io/anuke/mindustry/editor/MapView.java
Normal file
@ -0,0 +1,328 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.Input.Keys;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.g2d.Batch;
|
||||
import com.badlogic.gdx.input.GestureDetector;
|
||||
import com.badlogic.gdx.input.GestureDetector.GestureListener;
|
||||
import com.badlogic.gdx.math.Bresenham2;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.ui.GridImage;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.core.Inputs;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.graphics.Pixmaps;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
import io.anuke.ucore.scene.event.InputEvent;
|
||||
import io.anuke.ucore.scene.event.InputListener;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Tmp;
|
||||
|
||||
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 Pixmap current;
|
||||
private Bresenham2 br = new Bresenham2();
|
||||
private boolean updated = false;
|
||||
private float offsetx, offsety;
|
||||
private float zoom = 1f;
|
||||
private boolean grid = false;
|
||||
private GridImage image = new GridImage(0, 0);
|
||||
private Vector2 vec = new Vector2();
|
||||
private Rectangle rect = new Rectangle();
|
||||
|
||||
private boolean drawing;
|
||||
private int lastx, lasty;
|
||||
private int startx, starty;
|
||||
|
||||
public void setTool(EditorTool tool){
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
public EditorTool getTool() {
|
||||
return tool;
|
||||
}
|
||||
|
||||
public void clearStack(){
|
||||
stack.clear();
|
||||
current = null;
|
||||
}
|
||||
|
||||
public OperationStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void setGrid(boolean grid) {
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
public boolean isGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public void push(Pixmap previous, Pixmap add){
|
||||
DrawOperation op = new DrawOperation(editor.pixmap());
|
||||
op.add(previous, add);
|
||||
stack.add(op);
|
||||
this.current = add;
|
||||
}
|
||||
|
||||
public void undo(){
|
||||
if(stack.canUndo()){
|
||||
stack.undo();
|
||||
editor.updateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(){
|
||||
if(stack.canRedo()){
|
||||
stack.redo();
|
||||
editor.updateTexture();
|
||||
}
|
||||
}
|
||||
|
||||
public MapView(MapEditor editor){
|
||||
this.editor = editor;
|
||||
|
||||
Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
|
||||
setTouchable(Touchable.enabled);
|
||||
|
||||
addListener(new InputListener(){
|
||||
|
||||
@Override
|
||||
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
|
||||
if(pointer != 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(current == null){
|
||||
current = Pixmaps.copy(editor.pixmap());
|
||||
}
|
||||
updated = false;
|
||||
|
||||
GridPoint2 p = project(x, y);
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
startx = p.x;
|
||||
starty = p.y;
|
||||
tool.touched(editor, p.x, p.y);
|
||||
|
||||
if(tool.edit){
|
||||
updated = true;
|
||||
ui.editor.resetSaved();
|
||||
}
|
||||
|
||||
op = new DrawOperation(editor.pixmap());
|
||||
|
||||
drawing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
|
||||
drawing = false;
|
||||
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
if(tool == EditorTool.line){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(startx, starty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if(updated){
|
||||
if(op == null) op = new DrawOperation(editor.pixmap());
|
||||
Pixmap next = Pixmaps.copy(editor.pixmap());
|
||||
op.add(current, next);
|
||||
current = null;
|
||||
stack.add(op);
|
||||
op = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchDragged (InputEvent event, float x, float y, int pointer) {
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
if(drawing && tool == EditorTool.pencil){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(lastx, lasty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
|
||||
if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) &&
|
||||
!Inputs.keyDown(Keys.CONTROL_LEFT)) {
|
||||
float ax = Inputs.getAxis("move_x");
|
||||
float ay = Inputs.getAxis("move_y");
|
||||
offsetx -= ax * 15f / zoom;
|
||||
offsety -= ay * 15f / zoom;
|
||||
}
|
||||
|
||||
if(ui.editor.hasPane()) return;
|
||||
|
||||
zoom += Inputs.scroll()/10f * zoom;
|
||||
clampZoom();
|
||||
}
|
||||
|
||||
private void clampZoom(){
|
||||
zoom = Mathf.clamp(zoom, 0.2f, 12f);
|
||||
}
|
||||
|
||||
private GridPoint2 project(float x, float y){
|
||||
float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
x = (x - getWidth()/2 + sclwidth/2 - offsetx*zoom) / sclwidth * editor.texture().getWidth();
|
||||
y = (y - getHeight()/2 + sclheight/2 - offsety*zoom) / sclheight * editor.texture().getHeight();
|
||||
return Tmp.g1.set((int)x, editor.texture().getHeight() - 1 - (int)y);
|
||||
}
|
||||
|
||||
private Vector2 unproject(int x, int y){
|
||||
float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float px = ((float)x / editor.texture().getWidth()) * sclwidth + offsetx*zoom - sclwidth/2 + getWidth()/2;
|
||||
float py = (float)((float)(editor.texture().getHeight() - 1 - y) / editor.texture().getHeight()) * sclheight
|
||||
+ offsety*zoom - sclheight/2 + getHeight()/2;
|
||||
return vec.set(px, py);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
|
||||
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(editor.pixmap().getWidth(), editor.pixmap().getHeight());
|
||||
|
||||
batch.flush();
|
||||
boolean pop = ScissorStack.pushScissors(rect.set(x + width/2 - size/2, y + height/2 - size/2, size, size));
|
||||
|
||||
batch.draw(editor.texture(), centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
|
||||
|
||||
if(grid){
|
||||
Draw.color(Color.GRAY);
|
||||
image.setBounds(centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
|
||||
image.draw(batch, alpha);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
if(tool == EditorTool.line && drawing){
|
||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||
float sx = v1.x, sy = v1.y;
|
||||
Vector2 v2 = unproject(lastx, lasty).add(x, y);
|
||||
|
||||
Draw.color(Tmp.c1.set(ColorMapper.getColor(editor.getDrawBlock())));
|
||||
Lines.stroke(Unit.dp.scl(3f * zoom));
|
||||
Lines.line(sx, sy, v2.x, v2.y);
|
||||
|
||||
Lines.poly(sx, sy, 40, editor.getBrushSize() * zoom * 3);
|
||||
|
||||
Lines.poly(v2.x, v2.y, 40, editor.getBrushSize() * zoom * 3);
|
||||
}
|
||||
|
||||
batch.flush();
|
||||
|
||||
if(pop) ScissorStack.popScissors();
|
||||
|
||||
Draw.color(Colors.get("accent"));
|
||||
Lines.stroke(Unit.dp.scl(3f));
|
||||
Lines.rect(x + width/2 - size/2, y + height/2 - size/2, size, size);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
private boolean active(){
|
||||
return Core.scene.getKeyboardFocus() != null
|
||||
&& Core.scene.getKeyboardFocus().isDescendantOf(ui.editor)
|
||||
&& ui.editor.isShown() && tool == EditorTool.zoom &&
|
||||
Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY){
|
||||
if(!active()) return false;
|
||||
offsetx += deltaX / zoom;
|
||||
offsety -= deltaY / zoom;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean panStop(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float initialDistance, float distance){
|
||||
if(!active()) return false;
|
||||
float nzoom = distance - initialDistance;
|
||||
zoom += nzoom / 10000f / Unit.dp.scl(1f) * zoom;
|
||||
clampZoom();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pinchStop(){
|
||||
|
||||
}
|
||||
}
|
54
core/src/io/anuke/mindustry/editor/OperationStack.java
Executable file
@ -0,0 +1,54 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class OperationStack{
|
||||
private final static int maxSize = 10;
|
||||
private Array<DrawOperation> stack = new Array<>();
|
||||
private int index = 0;
|
||||
|
||||
public OperationStack(){
|
||||
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
for(DrawOperation op : stack){
|
||||
op.dispose();
|
||||
}
|
||||
stack.clear();
|
||||
index = 0;
|
||||
}
|
||||
|
||||
public void add(DrawOperation action){
|
||||
stack.truncate(stack.size + index);
|
||||
index = 0;
|
||||
stack.add(action);
|
||||
|
||||
if(stack.size > maxSize){
|
||||
stack.removeIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canUndo(){
|
||||
return !(stack.size - 1 + index < 0);
|
||||
}
|
||||
|
||||
public boolean canRedo(){
|
||||
return !(index > -1 || stack.size + index < 0);
|
||||
}
|
||||
|
||||
public void undo(){
|
||||
if(!canUndo()) return;
|
||||
|
||||
stack.get(stack.size - 1 + index).undo();
|
||||
index --;
|
||||
}
|
||||
|
||||
public void redo(){
|
||||
if(!canRedo()) return;
|
||||
|
||||
index ++;
|
||||
stack.get(stack.size - 1 + index).redo();
|
||||
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ public class MapTileData {
|
||||
private final static int TILE_SIZE = 3;
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
private final TileData tile = new TileData();
|
||||
private final TileDataWriter tile = new TileDataWriter();
|
||||
private final int width, height;
|
||||
|
||||
public MapTileData(int width, int height){
|
||||
@ -36,15 +36,22 @@ public class MapTileData {
|
||||
}
|
||||
|
||||
/**Reads and returns the next tile data.*/
|
||||
public TileData read(){
|
||||
tile.read();
|
||||
public TileDataWriter read(){
|
||||
tile.read(buffer);
|
||||
return tile;
|
||||
}
|
||||
|
||||
/**Writes tile data at a specified position. Uses the tile data returned by read().*/
|
||||
public void write(int x, int y){
|
||||
/**Reads and returns the next tile data.*/
|
||||
public TileDataWriter readAt(int x, int y){
|
||||
position(x, y);
|
||||
tile.write();
|
||||
tile.read(buffer);
|
||||
return tile;
|
||||
}
|
||||
|
||||
/**Writes tile data at a specified position.*/
|
||||
public void write(int x, int y, TileDataWriter writer){
|
||||
position(x, y);
|
||||
writer.write(buffer);
|
||||
}
|
||||
|
||||
/**Sets read position to the specified coordinates*/
|
||||
@ -52,12 +59,12 @@ public class MapTileData {
|
||||
buffer.position((x + width * y) * TILE_SIZE);
|
||||
}
|
||||
|
||||
public class TileData{
|
||||
public static class TileDataWriter {
|
||||
public byte floor, wall;
|
||||
public byte rotation;
|
||||
public byte team;
|
||||
|
||||
private void read(){
|
||||
public void read(ByteBuffer buffer){
|
||||
floor = buffer.get();
|
||||
wall = buffer.get();
|
||||
byte rt = buffer.get();
|
||||
@ -65,7 +72,7 @@ public class MapTileData {
|
||||
team = Bits.getRightByte(rt);
|
||||
}
|
||||
|
||||
private void write(){
|
||||
public void write(ByteBuffer buffer){
|
||||
buffer.put(floor);
|
||||
buffer.put(wall);
|
||||
byte rt = Bits.packByte(rotation, team);
|
||||
|
@ -1,9 +1,11 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
@ -13,30 +15,43 @@ import static io.anuke.mindustry.Vars.customMapDirectory;
|
||||
import static io.anuke.mindustry.Vars.mapExtension;
|
||||
|
||||
public class Maps implements Disposable{
|
||||
/**List of all built-in maps.*/
|
||||
private static final String[] defaultMapNames = {};
|
||||
|
||||
private ObjectMap<String, Map> maps = new ObjectMap<>();
|
||||
private Array<Map> allMaps = new Array<>();
|
||||
private Array<Map> customMaps = new Array<>();
|
||||
private Array<Map> defaultMaps = new Array<>();
|
||||
|
||||
public void load(){
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void save(){
|
||||
//TODO?
|
||||
}
|
||||
private Array<Map> returnArray = new Array<>();
|
||||
|
||||
/**Returns a list of all maps, including custom ones.*/
|
||||
public Array<Map> all(){
|
||||
return allMaps;
|
||||
}
|
||||
|
||||
/**Returns a list of only custo maps.*/
|
||||
public Array<Map> customMaps(){
|
||||
returnArray.clear();
|
||||
for(Map map : allMaps){
|
||||
if(map.custom) returnArray.add(map);
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
/**Returns a list of only default maps.*/
|
||||
public Array<Map> defaultMaps(){
|
||||
returnArray.clear();
|
||||
for(Map map : allMaps){
|
||||
if(!map.custom) returnArray.add(map);
|
||||
}
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
/**Returns map by internal name.*/
|
||||
public Map getByName(String name){
|
||||
return maps.get(name);
|
||||
}
|
||||
|
||||
//TODO GWT support: read from prefs string if custom
|
||||
/**Reads all tile data from a map. Should be used sparingly.*/
|
||||
public MapTileData readTileData(Map map){
|
||||
try {
|
||||
InputStream stream;
|
||||
@ -56,6 +71,35 @@ public class Maps implements Disposable{
|
||||
}
|
||||
}
|
||||
|
||||
/**Load all maps. Should be called at application start.*/
|
||||
public void load(){
|
||||
try {
|
||||
for (String name : defaultMapNames) {
|
||||
loadMap(Gdx.files.internal("maps/" + name + "." + mapExtension), false);
|
||||
}
|
||||
}catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
for(FileHandle file : customMapDirectory.list()){
|
||||
try{
|
||||
loadMap(file, true);
|
||||
}catch (IOException e){
|
||||
Log.err("Failed to load custom map file '{0}'!", file);
|
||||
Log.err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMap(FileHandle file, boolean custom) throws IOException{
|
||||
DataInputStream ds = new DataInputStream(file.read());
|
||||
MapMeta meta = readMapMeta(ds);
|
||||
Map map = new Map(file.nameWithoutExtension(), meta, custom);
|
||||
|
||||
maps.put(map.name, map);
|
||||
allMaps.add(map);
|
||||
}
|
||||
|
||||
private MapTileData readTileData(DataInputStream stream) throws IOException{
|
||||
MapMeta meta = readMapMeta(stream);
|
||||
byte[] bytes = new byte[stream.available()];
|
||||
|
@ -2,7 +2,7 @@ package io.anuke.mindustry.world;
|
||||
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import io.anuke.mindustry.io.MapTileData;
|
||||
import io.anuke.mindustry.io.MapTileData.TileData;
|
||||
import io.anuke.mindustry.io.MapTileData.TileDataWriter;
|
||||
import io.anuke.mindustry.world.blocks.Blocks;
|
||||
import io.anuke.ucore.noise.Noise;
|
||||
|
||||
@ -23,7 +23,7 @@ public class WorldGenerator {
|
||||
|
||||
for(int x = 0; x < data.width(); x ++){
|
||||
for(int y = 0; y < data.height(); y ++){
|
||||
TileData tile = data.read();
|
||||
TileDataWriter tile = data.read();
|
||||
tiles[x][y] = new Tile(x, y, tile.floor, tile.wall, tile.rotation, tile.team);
|
||||
|
||||
//TODO ores, plants, extra decoration?
|
||||
|
@ -8,6 +8,7 @@ import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.EventType.GameOverEvent;
|
||||
import io.anuke.mindustry.game.GameMode;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
@ -17,7 +18,6 @@ import io.anuke.mindustry.net.Packets.ChatPacket;
|
||||
import io.anuke.mindustry.net.Packets.KickReason;
|
||||
import io.anuke.mindustry.net.TraceInfo;
|
||||
import io.anuke.mindustry.ui.fragments.DebugFragment;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.*;
|
||||
import io.anuke.ucore.modules.Module;
|
||||
@ -34,8 +34,6 @@ import java.util.Scanner;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.ucore.util.Log.*;
|
||||
|
||||
;
|
||||
|
||||
public class ServerControl extends Module {
|
||||
private final CommandHandler handler = new CommandHandler("");
|
||||
private ShuffleMode mode;
|
||||
@ -81,12 +79,12 @@ public class ServerControl extends Module {
|
||||
}
|
||||
|
||||
if (mode != ShuffleMode.off) {
|
||||
Array<Map> maps = mode == ShuffleMode.both ? world.maps().getAllMaps() :
|
||||
mode == ShuffleMode.normal ? world.maps().getDefaultMaps() : world.maps().getCustomMaps();
|
||||
Array<Map> maps = mode == ShuffleMode.both ? world.maps().all() :
|
||||
mode == ShuffleMode.normal ? world.maps().defaultMaps() : world.maps().customMaps();
|
||||
|
||||
Map previous = world.getMap();
|
||||
Map map = previous;
|
||||
while (map == previous || !map.visible) map = maps.random();
|
||||
while (map == previous) map = maps.random();
|
||||
|
||||
info("Selected next map to be {0}.", map.name);
|
||||
state.set(State.playing);
|
||||
@ -134,7 +132,7 @@ public class ServerControl extends Module {
|
||||
|
||||
String search = arg[0];
|
||||
Map result = null;
|
||||
for(Map map : world.maps().list()){
|
||||
for(Map map : world.maps().all()){
|
||||
if(map.name.equalsIgnoreCase(search))
|
||||
result = map;
|
||||
}
|
||||
@ -165,8 +163,8 @@ public class ServerControl extends Module {
|
||||
|
||||
handler.register("maps", "Display all available maps.", arg -> {
|
||||
Log.info("Maps:");
|
||||
for(Map map : world.maps().getAllMaps()){
|
||||
Log.info(" &ly{0}: &lb&fi{1} / {2}x{3}", map.name, map.custom ? "Custom" : "Default", map.getWidth(), map.getHeight());
|
||||
for(Map map : world.maps().all()){
|
||||
Log.info(" &ly{0}: &lb&fi{1} / {2}x{3}", map.name, map.custom ? "Custom" : "Default", map.meta.width, map.meta.height);
|
||||
}
|
||||
});
|
||||
|
||||
@ -505,7 +503,8 @@ public class ServerControl extends Module {
|
||||
return;
|
||||
}
|
||||
|
||||
world.removeBlock(world.getCore());
|
||||
Events.fire(GameOverEvent.class);
|
||||
|
||||
info("Core destroyed.");
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.server.mapgen;
|
||||
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.ucore.noise.RidgedPerlin;
|
||||
import io.anuke.ucore.noise.Simplex;
|
||||
|
||||
|