Merged save previews

This commit is contained in:
Anuken 2019-08-30 20:13:03 -04:00
commit b39464a7d1
11 changed files with 1110 additions and 988 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 KiB

After

Width:  |  Height:  |  Size: 579 KiB

View File

@ -18,7 +18,7 @@ import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.dialogs.*;
@ -26,8 +26,8 @@ import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.storage.*;
import java.io.*;
import java.time.*;
import java.time.format.*;
import java.text.*;
import java.util.*;
import static io.anuke.arc.Core.*;
import static io.anuke.mindustry.Vars.*;
@ -233,7 +233,7 @@ public class Control implements ApplicationListener, Loadable{
state.rules = rules;
logic.play();
if(settings.getBool("savecreate")){
control.saves.addSave(map.name() + "-" + DateTimeFormatter.ofPattern("MMM dd h:mm").format(LocalDateTime.now()));
control.saves.addSave(map.name() + " " + new SimpleDateFormat("MMM dd h:mm", Locale.getDefault()).format(new Date()));
}
});
}
@ -387,6 +387,8 @@ public class Control implements ApplicationListener, Loadable{
@Override
public void update(){
saves.update();
//update and load any requested assets
assets.update();
input.updateController();

View File

@ -87,6 +87,7 @@ public class UI implements ApplicationListener, Loadable{
skin.addRegions(Core.atlas);
loadExtraStyle(skin);
skin.add("outline", Core.assets.get("outline"));
skin.getFont("outline").getData().markupEnabled = true;
skin.getFont("default").getData().markupEnabled = true;
skin.getFont("default").setOwnsTexture(false);
skin.load(Core.files.internal("sprites/uiskin.json"));

View File

@ -1,30 +1,31 @@
package io.anuke.mindustry.game;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.*;
import io.anuke.arc.assets.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.files.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.io.SaveIO.SaveException;
import io.anuke.mindustry.io.SaveMeta;
import io.anuke.arc.util.async.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.io.SaveIO.*;
import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.type.Zone;
import io.anuke.mindustry.type.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.io.*;
import java.text.*;
import java.util.*;
import static io.anuke.mindustry.Vars.saveExtension;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.*;
public class Saves{
private int nextSlot;
private Array<SaveSlot> saves = new Array<>();
private IntMap<SaveSlot> saveMap = new IntMap<>();
private SaveSlot current;
private AsyncExecutor previewExecutor = new AsyncExecutor(2);
private boolean saving;
private float time;
@ -32,6 +33,8 @@ public class Saves{
private long lastTimestamp;
public Saves(){
Core.assets.setLoader(Texture.class, ".spreview", new SavePreviewLoader());
Events.on(StateChangeEvent.class, event -> {
if(event.to == State.menu){
totalPlaytime = 0;
@ -162,6 +165,7 @@ public class Saves{
public class SaveSlot{
public final int index;
boolean requestedPreview;
SaveMeta meta;
public SaveSlot(int index){
@ -174,6 +178,7 @@ public class Saves{
meta = SaveIO.getMeta(index);
current = this;
totalPlaytime = meta.timePlayed;
savePreview();
}catch(Exception e){
throw new SaveException(e);
}
@ -191,6 +196,41 @@ public class Saves{
}
totalPlaytime = prev;
savePreview();
}
private void savePreview(){
if(Core.assets.isLoaded(loadPreviewFile().path())){
Core.assets.unload(loadPreviewFile().path());
}
previewExecutor.submit(() -> {
try{
previewFile().writePNG(renderer.minimap.getPixmap());
requestedPreview = false;
}catch(Throwable t){
t.printStackTrace();
}
});
}
public Texture previewTexture(){
if(!previewFile().exists()){
return null;
}else if(Core.assets.isLoaded(loadPreviewFile().path())){
return Core.assets.get(loadPreviewFile().path());
}else if(!requestedPreview){
Core.assets.load(new AssetDescriptor<>(loadPreviewFile(), Texture.class));
requestedPreview = true;
}
return null;
}
private FileHandle previewFile(){
return mapPreviewDirectory.child("save_slot_" + index + ".png");
}
private FileHandle loadPreviewFile(){
return previewFile().sibling(previewFile().name() + ".spreview");
}
public boolean isHidden(){
@ -214,7 +254,7 @@ public class Saves{
}
public String getName(){
return Core.settings.getString("save-" + index + "-name", "untittled");
return Core.settings.getString("save-" + index + "-name", "untitled");
}
public void setName(String name){
@ -270,6 +310,10 @@ public class Saves{
current = null;
}
if(Core.assets.isLoaded(loadPreviewFile().path())){
Core.assets.unload(loadPreviewFile().path());
}
saveSlots();
}
}

View File

@ -36,6 +36,10 @@ public class MinimapRenderer implements Disposable{
Events.on(TileChangeEvent.class, event -> Core.app.post(() -> update(event.tile)));
}
public Pixmap getPixmap(){
return pixmap;
}
public Texture getTexture(){
return texture;
}

View File

@ -0,0 +1,23 @@
package io.anuke.mindustry.io;
import io.anuke.arc.assets.*;
import io.anuke.arc.assets.loaders.*;
import io.anuke.arc.assets.loaders.resolvers.*;
import io.anuke.arc.files.*;
public class SavePreviewLoader extends TextureLoader{
public SavePreviewLoader(){
super(new AbsoluteFileHandleResolver());
}
@Override
public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
try{
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
}catch(Exception e){
e.printStackTrace();
file.sibling(file.nameWithoutExtension()).delete();
}
}
}

View File

@ -1,13 +1,14 @@
package io.anuke.mindustry.ui;
import io.anuke.arc.graphics.Texture;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.scene.ui.Image;
import io.anuke.arc.scene.ui.layout.UnitScl;
import io.anuke.mindustry.graphics.Pal;
public class BorderImage extends Image{
private float thickness = 4f;
public float thickness = 4f;
public Color borderColor = Pal.gray;
public BorderImage(){
@ -27,6 +28,11 @@ public class BorderImage extends Image{
thickness = thick;
}
public BorderImage border(Color color){
this.borderColor = color;
return this;
}
@Override
public void draw(){
super.draw();
@ -34,7 +40,7 @@ public class BorderImage extends Image{
float scaleX = getScaleX();
float scaleY = getScaleY();
Draw.color(Pal.gray);
Draw.color(borderColor);
Draw.alpha(parentAlpha);
Lines.stroke(UnitScl.dp.scl(thickness));
Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY);

View File

@ -9,6 +9,7 @@ import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*;
import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.scene.utils.*;
@ -77,20 +78,30 @@ public class DeployDialog extends FloatingDialog{
}}.setScaling(Scaling.fit));
if(control.saves.getZoneSlot() != null){
float size = 230f;
float size = 250f;
stack.add(new Table(t -> {
SaveSlot slot = control.saves.getZoneSlot();
Stack sub = new Stack();
if(control.saves.getZoneSlot().getZone() != null){
if(slot.getZone() != null){
sub.add(new Table(f -> f.margin(4f).add(new Image("whiteui")).color(Color.fromGray(0.1f)).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image(control.saves.getZoneSlot().getZone().preview).setScaling(Scaling.fit)).color(Color.DARK_GRAY).grow()));
sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> {
TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable();
if(draw.getRegion().getTexture().isDisposed()){
draw.setRegion(slot.getZone().preview);
}
Texture text = slot.previewTexture();
if(draw.getRegion() == slot.getZone().preview && text != null){
draw.setRegion(new TextureRegion(text));
}
}).color(Color.DARK_GRAY).grow()));
}
TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName()), "square", () -> {
hide();
ui.loadAnd(() -> {
logic.reset();
@ -127,7 +138,7 @@ public class DeployDialog extends FloatingDialog{
slot.delete();
setup();
});
}).width(230f).height(50f).padTop(3);
}).width(size).height(50f).padTop(3);
}));
}else{
stack.add(new View());

View File

@ -3,6 +3,9 @@ package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*;
@ -12,6 +15,7 @@ import io.anuke.mindustry.game.Saves.*;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.io.SaveIO.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.*;
import java.io.*;
@ -55,33 +59,35 @@ public class LoadDialog extends FloatingDialog{
for(SaveSlot slot : array){
if(slot.isHidden()) continue;
TextButton button = new TextButton("[accent]" + slot.getName(), "clear");
button.getLabelCell().growX().left();
button.getLabelCell().padBottom(8f);
button.getLabelCell().top().left().growX();
TextButton button = new TextButton("", "clear");
button.getLabel().remove();
button.clearChildren();
button.defaults().left();
button.table(t -> {
t.right();
button.table(title -> {
title.add("[accent]" + slot.getName()).left().growX().width(230f).wrap();
t.addImageButton("icon-floppy", "emptytoggle", iconsize, () -> {
slot.setAutosave(!slot.isAutosave());
}).checked(slot.isAutosave()).right();
title.table(t -> {
t.right();
t.addImageButton("icon-trash", "empty", iconsize, () -> {
ui.showConfirm("$confirm", "$save.delete.confirm", () -> {
slot.delete();
setup();
});
}).size(iconsize).right();
t.addImageButton("icon-floppy", "emptytoggle", iconsize, () -> {
slot.setAutosave(!slot.isAutosave());
}).checked(slot.isAutosave()).right();
t.addImageButton("icon-pencil", "empty", iconsize, () -> {
ui.showTextInput("$save.rename", "$save.rename.text", slot.getName(), text -> {
slot.setName(text);
setup();
});
}).size(iconsize).right();
t.addImageButton("icon-trash", "empty", iconsize, () -> {
ui.showConfirm("$confirm", "$save.delete.confirm", () -> {
slot.delete();
setup();
});
}).size(iconsize).right();
t.addImageButton("icon-pencil", "empty", iconsize, () -> {
ui.showTextInput("$save.rename", "$save.rename.text", slot.getName(), text -> {
slot.setName(text);
setup();
});
}).size(iconsize).right();
t.addImageButton("icon-save", "empty", iconsize, () -> {
if(!ios){
@ -105,26 +111,44 @@ public class LoadDialog extends FloatingDialog{
}).size(iconsize).right();
}).padRight(-10).growX();
}).padRight(-10).growX();
}).growX().colspan(2);
button.row();
String color = "[lightgray]";
TextureRegion def = Core.atlas.find("nomap");
button.left().add(new BorderImage(def, 4f)).update(i -> {
TextureRegionDrawable draw = (TextureRegionDrawable)i.getDrawable();
if(draw.getRegion().getTexture().isDisposed()){
draw.setRegion(def);
}
Texture text = slot.previewTexture();
if(draw.getRegion() == def && text != null){
draw.setRegion(new TextureRegion(text));
}
}).left().size(160f).padRight(5);
button.table(meta -> {
meta.left().top();
meta.defaults().padBottom(-2).left().width(250f);
meta.row();
meta.labelWrap(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
meta.row();
meta.labelWrap(Core.bundle.format("save.wave", color + slot.getWave()));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
meta.row();
meta.labelWrap(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
meta.row();
meta.labelWrap(Core.bundle.format("save.date", color + slot.getDate()));
meta.row();
}).left().growX().width(250f);
button.defaults().padBottom(3);
button.row();
button.add(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
button.row();
button.add(Core.bundle.format("save.wave", color + slot.getWave()));
button.row();
button.label(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
button.row();
button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
button.row();
button.add(Core.bundle.format("save.date", color + slot.getDate())).colspan(2).padTop(5).right();
button.row();
modifyButton(button, slot);
slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).marginLeft(20f).marginRight(20f);
slots.row();
slots.add(button).uniformX().fillX().pad(4).padRight(-4).margin(10f).row();
}
cont.add(pane);