Added new screen for managing and viewing maps, many editor fixes
This commit is contained in:
@@ -9,7 +9,6 @@ import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.editor.MapEditorDialog;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
import io.anuke.ucore.core.Core;
|
||||
@@ -42,6 +41,7 @@ public class UI extends SceneModule{
|
||||
public AboutDialog about;
|
||||
public RestartDialog restart;
|
||||
public LevelDialog levels;
|
||||
public MapsDialog maps;
|
||||
public LoadDialog load;
|
||||
public DiscordDialog discord;
|
||||
public JoinDialog join;
|
||||
@@ -172,6 +172,7 @@ public class UI extends SceneModule{
|
||||
bans = new BansDialog();
|
||||
admins = new AdminsDialog();
|
||||
traces = new TraceDialog();
|
||||
maps = new MapsDialog();
|
||||
localplayers = new LocalPlayerDialog();
|
||||
|
||||
build.begin(scene);
|
||||
@@ -251,21 +252,22 @@ public class UI extends SceneModule{
|
||||
|
||||
public void showInfo(String info){
|
||||
new Dialog("$text.info.title", "dialog"){{
|
||||
content().margin(15).add(info).width(600f).get().setWrap(true);
|
||||
getCell(content()).growX();
|
||||
content().margin(15).add(info).width(400f).wrap();
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showError(String text){
|
||||
new Dialog("$text.error.title", "dialog"){{
|
||||
content().margin(15).add(text);
|
||||
content().margin(15).add(text).width(400f).wrap();
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showConfirm(String title, String text, Listenable confirmed){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.content().add(text).pad(4f);
|
||||
dialog.content().add(text).width(400f).wrap().pad(4f);
|
||||
dialog.buttons().defaults().size(200f, 54f).pad(2f);
|
||||
dialog.buttons().addButton("$text.cancel", dialog::hide);
|
||||
dialog.buttons().addButton("$text.ok", () -> {
|
||||
|
||||
@@ -39,6 +39,7 @@ import io.anuke.ucore.util.Strings;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -47,19 +48,17 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
private MapView view;
|
||||
private MapInfoDialog infoDialog;
|
||||
private MapLoadDialog loadDialog;
|
||||
private MapSaveDialog saveDialog;
|
||||
private MapResizeDialog resizeDialog;
|
||||
private ScrollPane pane;
|
||||
private FloatingDialog menu;
|
||||
private FileChooser openFile, saveFile, openImage, saveImage;
|
||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
||||
private boolean saved = false;
|
||||
private boolean shownWithMap = false;
|
||||
|
||||
private ButtonGroup<ImageButton> blockgroup;
|
||||
|
||||
public MapEditorDialog(){
|
||||
super("$text.mapeditor", "dialog");
|
||||
if(gwt) return;
|
||||
|
||||
editor = new MapEditor();
|
||||
view = new MapView(editor);
|
||||
@@ -73,7 +72,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
try{
|
||||
if(!editor.getTags().containsKey("name")){
|
||||
tags.put("name", result.nameWithoutExtension());
|
||||
editor.getTags().put("name", result.nameWithoutExtension());
|
||||
}
|
||||
MapIO.writeMap(result.write(false), editor.getTags(), editor.getMap());
|
||||
}catch (Exception e){
|
||||
@@ -118,7 +117,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
try{
|
||||
MapTileData data = MapIO.readPixmap(new Pixmap(file));
|
||||
|
||||
editor.beginEdit(data, new ObjectMap<>());
|
||||
editor.beginEdit(data, editor.getTags());
|
||||
view.clearStack();
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
|
||||
@@ -136,23 +135,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
menu.content().table(t -> {
|
||||
t.defaults().size(swidth, 60f).padBottom(5).padRight(5).padLeft(5);
|
||||
|
||||
t.addImageTextButton("$text.editor.savemap", "icon-floppy-16", isize, () -> {
|
||||
String name = editor.getTags().get("name", "");
|
||||
|
||||
if(name.isEmpty()){
|
||||
ui.showError("$text.editor.save.noname");
|
||||
}else{
|
||||
Map map = world.maps().getByName(name);
|
||||
if(map != null && !map.custom){
|
||||
ui.showError("$text.editor.save.overwrite");
|
||||
}else{
|
||||
world.maps().saveAndReload(name, editor.getMap(), editor.getTags());
|
||||
ui.showInfoFade("$text.editor.saved");
|
||||
}
|
||||
}
|
||||
|
||||
menu.hide();
|
||||
}).size(swidth*2f + 10, 60f).colspan(2);
|
||||
t.addImageTextButton("$text.editor.savemap", "icon-floppy-16", isize, this::save).size(swidth*2f + 10, 60f).colspan(2);
|
||||
|
||||
t.row();
|
||||
|
||||
@@ -172,11 +155,23 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
createDialog("$text.editor.import",
|
||||
"$text.editor.importmap", "$text.editor.importmap.description", "icon-load-map", (Listenable)loadDialog::show,
|
||||
"$text.editor.importfile", "$text.editor.importfile.description", "icon-file", (Listenable)openFile::show,
|
||||
"$text.editor.importimage", "$text.editor.importimage.description", "icon-file-image", (Listenable)openImage::show));
|
||||
"$text.editor.importimage", "$text.editor.importimage.description", "icon-file-image", (Listenable)() -> {
|
||||
if(gwt){
|
||||
ui.showError("text.web.unsupported");
|
||||
}else {
|
||||
openImage.show();
|
||||
}
|
||||
}));
|
||||
|
||||
t.addImageTextButton("$text.editor.export", "icon-save-map", isize, () -> createDialog("$text.editor.export",
|
||||
"$text.editor.exportfile", "$text.editor.exportfile.description", "icon-file", (Listenable)saveFile::show,
|
||||
"$text.editor.exportimage", "$text.editor.exportimage.description", "icon-file-image", (Listenable)saveImage::show));
|
||||
"$text.editor.exportimage", "$text.editor.exportimage.description", "icon-file-image", (Listenable)() -> {
|
||||
if(gwt){
|
||||
ui.showError("text.web.unsupported");
|
||||
}else {
|
||||
saveImage.show();
|
||||
}
|
||||
}));
|
||||
|
||||
t.row();
|
||||
|
||||
@@ -204,7 +199,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
});
|
||||
|
||||
loadDialog = new MapLoadDialog(map -> {
|
||||
saveDialog.setFieldText(map.name);
|
||||
|
||||
ui.loadAnd(() -> {
|
||||
try (DataInputStream stream = new DataInputStream(map.stream.get())){
|
||||
@@ -219,15 +213,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
saveDialog = new MapSaveDialog(name -> {
|
||||
ui.loadAnd(() -> {
|
||||
saved = true;
|
||||
world.maps().saveAndReload(editor.getTags().get("name", name), editor.getMap(), editor.getTags());
|
||||
loadDialog.rebuild();
|
||||
});
|
||||
});
|
||||
|
||||
setFillParent(true);
|
||||
|
||||
@@ -250,10 +235,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
shown(() -> {
|
||||
saved = true;
|
||||
editor.beginEdit(new MapTileData(256, 256), new ObjectMap<>());
|
||||
blockgroup.getButtons().get(2).setChecked(true);
|
||||
Core.scene.setScrollFocus(view);
|
||||
view.clearStack();
|
||||
Core.scene.setScrollFocus(view);
|
||||
if(!shownWithMap){
|
||||
editor.beginEdit(new MapTileData(256, 256), new ObjectMap<>());
|
||||
}
|
||||
shownWithMap = false;
|
||||
|
||||
Timers.runTask(10f, Platform.instance::updateRPC);
|
||||
});
|
||||
@@ -261,12 +248,30 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
hidden(() -> Platform.instance.updateRPC());
|
||||
}
|
||||
|
||||
private void save(){
|
||||
String name = editor.getTags().get("name", "");
|
||||
|
||||
if(name.isEmpty()){
|
||||
ui.showError("$text.editor.save.noname");
|
||||
}else{
|
||||
Map map = world.maps().getByName(name);
|
||||
if(map != null && !map.custom){
|
||||
ui.showError("$text.editor.save.overwrite");
|
||||
}else{
|
||||
world.maps().saveMap(name, editor.getMap(), editor.getTags());
|
||||
ui.showInfoFade("$text.editor.saved");
|
||||
}
|
||||
}
|
||||
|
||||
menu.hide();
|
||||
saved = true;
|
||||
}
|
||||
|
||||
/**Argument format:
|
||||
* 0) button name
|
||||
* 1) description
|
||||
* 2) icon name
|
||||
* 3) listener
|
||||
*/
|
||||
* 3) listener */
|
||||
private FloatingDialog createDialog(String title, Object... arguments){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
|
||||
@@ -318,6 +323,22 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
editor.renderer().dispose();
|
||||
}
|
||||
|
||||
public void beginEditMap(InputStream is){
|
||||
ui.loadAnd(() -> {
|
||||
try {
|
||||
shownWithMap = true;
|
||||
DataInputStream stream = new DataInputStream(is);
|
||||
MapMeta meta = MapIO.readMapMeta(stream);
|
||||
editor.beginEdit(MapIO.readTileData(stream, meta, false), meta.tags);
|
||||
is.close();
|
||||
show();
|
||||
}catch (Exception e){
|
||||
Log.err(e);
|
||||
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MapView getView() {
|
||||
return view;
|
||||
}
|
||||
@@ -482,7 +503,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Input.S)){
|
||||
saveDialog.save();
|
||||
save();
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Input.G)){
|
||||
|
||||
@@ -67,6 +67,10 @@ public class MapInfoDialog extends FloatingDialog{
|
||||
tags.put("oregen", enabled ? "1" : "0");
|
||||
}).left();
|
||||
|
||||
name.change();
|
||||
description.change();
|
||||
author.change();
|
||||
|
||||
Platform.instance.addDialog(name, 50);
|
||||
Platform.instance.addDialog(author, 50);
|
||||
Platform.instance.addDialog(description, 1000);
|
||||
|
||||
@@ -36,6 +36,7 @@ public class MapLoadDialog extends FloatingDialog{
|
||||
|
||||
public void rebuild(){
|
||||
content().clear();
|
||||
selected = world.maps().all().first();
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
|
||||
@@ -52,7 +53,7 @@ public class MapLoadDialog extends FloatingDialog{
|
||||
|
||||
for (Map map : world.maps().all()) {
|
||||
|
||||
TextButton button = new TextButton(map.meta.name(), "toggle");
|
||||
TextButton button = new TextButton(map.getDisplayName(), "toggle");
|
||||
button.add(new BorderImage(map.texture, 2f)).size(16 * 4f);
|
||||
button.getCells().reverse();
|
||||
button.clicked(() -> selected = map);
|
||||
|
||||
@@ -198,6 +198,9 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if(chunks == null){
|
||||
return;
|
||||
}
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
if(chunks[x][y] != null){
|
||||
|
||||
@@ -23,4 +23,8 @@ public class Map {
|
||||
this.meta = meta;
|
||||
this.stream = streamSupplier;
|
||||
}
|
||||
|
||||
public String getDisplayName(){
|
||||
return meta.tags.get("name", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,8 @@ public class Maps implements Disposable{
|
||||
loadCustomMaps();
|
||||
}
|
||||
|
||||
public void saveAndReload(String name, MapTileData data, ObjectMap<String, String> tags){
|
||||
/**Save a map. This updates all values and stored data necessary.*/
|
||||
public void saveMap(String name, MapTileData data, ObjectMap<String, String> tags){
|
||||
try {
|
||||
if (!gwt) {
|
||||
FileHandle file = customMapDirectory.child(name + "." + mapExtension);
|
||||
@@ -92,18 +93,43 @@ public class Maps implements Disposable{
|
||||
}
|
||||
|
||||
if(maps.containsKey(name)){
|
||||
maps.get(name).texture.dispose();
|
||||
if(maps.get(name).texture != null) {
|
||||
maps.get(name).texture.dispose();
|
||||
maps.get(name).texture = null;
|
||||
}
|
||||
allMaps.removeValue(maps.get(name), true);
|
||||
}
|
||||
|
||||
Map map = new Map(name, new MapMeta(version, tags, data.width(), data.height(), null), true, getStreamFor(name));
|
||||
if (!headless){
|
||||
map.texture = new Texture(MapIO.generatePixmap(data));
|
||||
}
|
||||
allMaps.add(map);
|
||||
|
||||
maps.put(name, map);
|
||||
}catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//todo implement
|
||||
}
|
||||
|
||||
/**Removes a map completely.*/
|
||||
public void removeMap(Map map){
|
||||
if(map.texture != null){
|
||||
map.texture.dispose();
|
||||
map.texture = null;
|
||||
}
|
||||
|
||||
maps.remove(map.name);
|
||||
allMaps.removeValue(map, true);
|
||||
|
||||
if (!gwt) {
|
||||
customMapDirectory.child(map.name + "." + mapExtension).delete();
|
||||
} else {
|
||||
customMapNames.removeValue(map.name, false);
|
||||
Settings.putString("map-data-" + map.name, "");
|
||||
Settings.putString("custom-maps", json.toJson(customMapNames));
|
||||
Settings.save();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMap(String name, Supplier<InputStream> supplier, boolean custom) throws IOException{
|
||||
|
||||
@@ -19,9 +19,11 @@ import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.gwt;
|
||||
|
||||
public class FileChooser extends FloatingDialog {
|
||||
private Table files;
|
||||
private FileHandle homeDirectory = Gdx.files.absolute(Gdx.files.getExternalStoragePath());
|
||||
private FileHandle homeDirectory = gwt ? Gdx.files.internal("") : Gdx.files.absolute(Gdx.files.getExternalStoragePath());
|
||||
private FileHandle directory = homeDirectory;
|
||||
private ScrollPane pane;
|
||||
private TextField navigation, filefield;
|
||||
|
||||
@@ -17,12 +17,9 @@ import io.anuke.ucore.util.Mathf;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LevelDialog extends FloatingDialog{
|
||||
private ScrollPane pane;
|
||||
|
||||
public LevelDialog(){
|
||||
super("$text.level.select");
|
||||
getTitleTable().getCell(title()).growX().center();
|
||||
getTitleTable().center();
|
||||
addCloseButton();
|
||||
shown(this::setup);
|
||||
}
|
||||
@@ -31,7 +28,7 @@ public class LevelDialog extends FloatingDialog{
|
||||
content().clear();
|
||||
|
||||
Table maps = new Table();
|
||||
pane = new ScrollPane(maps);
|
||||
ScrollPane pane = new ScrollPane(maps);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
int maxwidth = 4;
|
||||
|
||||
116
core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java
Normal file
116
core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java
Normal file
@@ -0,0 +1,116 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Scaling;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.Image;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapsDialog extends FloatingDialog {
|
||||
|
||||
public MapsDialog() {
|
||||
super("$text.maps");
|
||||
addCloseButton();
|
||||
shown(this::setup);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
content().clear();
|
||||
|
||||
Table maps = new Table();
|
||||
maps.marginRight(24);
|
||||
|
||||
ScrollPane pane = new ScrollPane(maps, "clear-black");
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
int maxwidth = 4;
|
||||
float mapsize = 200f;
|
||||
|
||||
int i = 0;
|
||||
for(Map map : world.maps().all()){
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
maps.row();
|
||||
}
|
||||
|
||||
TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
||||
button.clearChildren();
|
||||
button.margin(6);
|
||||
button.add(map.meta.tags.get("name", map.name)).growX().center().get().setEllipsis(true);
|
||||
button.row();
|
||||
button.addImage("white").growX().pad(4).color(Color.GRAY);
|
||||
button.row();
|
||||
((Image)button.stack(new Image(map.texture), new BorderImage(map.texture)).size(mapsize-20f).get().getChildren().first()).setScaling(Scaling.fit);
|
||||
button.row();
|
||||
button.add(map.custom ? "$text.custom" : "$text.builtin").color(Color.GRAY).padTop(3);
|
||||
|
||||
i ++;
|
||||
}
|
||||
|
||||
content().add(pane).uniformX();
|
||||
}
|
||||
|
||||
void showMapInfo(Map map){
|
||||
FloatingDialog dialog = new FloatingDialog("$text.editor.mapinfo");
|
||||
dialog.addCloseButton();
|
||||
|
||||
float mapsize = 300f;
|
||||
Table table = dialog.content();
|
||||
|
||||
((Image) table.stack(new Image(map.texture), new BorderImage(map.texture)).size(mapsize).get().getChildren().first()).setScaling(Scaling.fit);
|
||||
|
||||
table.table("clear", desc -> {
|
||||
desc.top();
|
||||
Table t = new Table();
|
||||
|
||||
ScrollPane pane = new ScrollPane(t, "clear-black");
|
||||
desc.add(pane).grow();
|
||||
|
||||
t.top();
|
||||
t.defaults().padTop(10).left();
|
||||
|
||||
t.add("$text.editor.name").padRight(10).color(Color.GRAY).padTop(0);
|
||||
t.row();
|
||||
t.add(map.meta.tags.get("name", map.name)).growX().wrap().padTop(2);
|
||||
t.row();
|
||||
t.add("$text.editor.author").padRight(10).color(Color.GRAY);
|
||||
t.row();
|
||||
t.add(map.meta.author()).growX().wrap().padTop(2);
|
||||
t.row();
|
||||
t.add("$text.editor.description").padRight(10).color(Color.GRAY).top();
|
||||
t.row();
|
||||
t.add(map.meta.description()).growX().wrap().padTop(2);
|
||||
t.row();
|
||||
t.add("$text.editor.oregen.info").padRight(10).color(Color.GRAY);
|
||||
t.row();
|
||||
t.add(map.meta.hasOreGen() ? "$text.on" : "$text.off").padTop(2);
|
||||
}).height(mapsize).width(mapsize).margin(6);
|
||||
|
||||
table.row();
|
||||
|
||||
table.addImageTextButton("$text.editor.openin", "icon-load-map", "clear", 16*2, () -> {
|
||||
Vars.ui.editor.beginEditMap(map.stream.get());
|
||||
dialog.hide();
|
||||
hide();
|
||||
}).fillX().height(50f).marginLeft(6);
|
||||
|
||||
table.addImageTextButton("$text.delete", "icon-trash-16", "clear", 16*2, () -> {
|
||||
ui.showConfirm("$text.confirm", Bundles.format("text.map.delete", map.name), () -> {
|
||||
world.maps().removeMap(map);
|
||||
dialog.hide();
|
||||
setup();
|
||||
});
|
||||
}).fillX().height(50f).marginLeft(6).disabled(!map.custom).touchable(map.custom ? Touchable.enabled : Touchable.disabled);
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
@@ -31,21 +31,15 @@ public class MenuFragment implements Fragment{
|
||||
|
||||
row();
|
||||
|
||||
add(new MenuButton("icon-editor", "$text.editor", () -> {
|
||||
if(gwt){
|
||||
ui.showInfo("$text.editor.web");
|
||||
}else{
|
||||
ui.editor.show();
|
||||
}
|
||||
}));
|
||||
|
||||
add(new MenuButton("icon-tools", "$text.settings", ui.settings::show));
|
||||
add(new MenuButton("icon-editor", "$text.editor", ui.editor::show));
|
||||
|
||||
add(new MenuButton("icon-menu", "$text.maps", ui.maps::show));
|
||||
|
||||
row();
|
||||
|
||||
add(new MenuButton("icon-info", "$text.about.button", ui.about::show));
|
||||
|
||||
add(new MenuButton("icon-menu", "$text.changelog.title", ui.changelog::show));
|
||||
add(new MenuButton("icon-tools", "$text.settings", ui.settings::show));
|
||||
|
||||
row();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user