Mindustry/core/src/mindustry/game/Saves.java
2020-02-03 20:30:18 -05:00

324 lines
8.6 KiB
Java

package mindustry.game;
import arc.*;
import arc.assets.*;
import arc.struct.*;
import arc.files.*;
import arc.graphics.*;
import arc.util.*;
import arc.util.async.*;
import mindustry.*;
import mindustry.core.GameState.*;
import mindustry.game.EventType.*;
import mindustry.io.*;
import mindustry.io.SaveIO.*;
import mindustry.maps.Map;
import mindustry.type.*;
import java.io.*;
import java.text.*;
import java.util.*;
import static mindustry.Vars.*;
public class Saves{
private Array<SaveSlot> saves = new Array<>();
private SaveSlot current;
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
private boolean saving;
private float time;
private Fi zoneFile;
private long totalPlaytime;
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;
lastTimestamp = 0;
current = null;
}
});
}
public void load(){
saves.clear();
zoneFile = saveDirectory.child("-1.msav");
for(Fi file : saveDirectory.list()){
if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){
SaveSlot slot = new SaveSlot(file);
saves.add(slot);
slot.meta = SaveIO.getMeta(file);
}
}
}
public SaveSlot getCurrent(){
return current;
}
public void update(){
SaveSlot current = this.current;
if(current != null && !state.is(State.menu)
&& !(state.isPaused() && Core.scene.hasDialog())){
if(lastTimestamp != 0){
totalPlaytime += Time.timeSinceMillis(lastTimestamp);
}
lastTimestamp = Time.millis();
}
if(!state.is(State.menu) && !state.gameOver && current != null && current.isAutosave() && !state.rules.tutorial){
time += Time.delta();
if(time > Core.settings.getInt("saveinterval") * 60){
saving = true;
Time.runTask(2f, () -> {
try{
current.save();
}catch(Exception e){
e.printStackTrace();
}
saving = false;
});
time = 0;
}
}else{
time = 0;
}
}
public long getTotalPlaytime(){
return totalPlaytime;
}
public void resetSave(){
current = null;
}
public boolean isSaving(){
return saving;
}
public void zoneSave(){
SaveSlot slot = new SaveSlot(zoneFile);
slot.setName("zone");
saves.remove(s -> s.file.equals(zoneFile));
saves.add(slot);
slot.save();
}
public SaveSlot addSave(String name){
SaveSlot slot = new SaveSlot(getNextSlotFile());
slot.setName(name);
saves.add(slot);
slot.save();
return slot;
}
public SaveSlot importSave(Fi file) throws IOException{
SaveSlot slot = new SaveSlot(getNextSlotFile());
slot.importFile(file);
slot.setName(file.nameWithoutExtension());
saves.add(slot);
slot.meta = SaveIO.getMeta(slot.file);
current = slot;
return slot;
}
public SaveSlot getZoneSlot(){
SaveSlot slot = getSaveSlots().find(s -> s.file.equals(zoneFile));
return slot == null || slot.getZone() == null ? null : slot;
}
public Fi getNextSlotFile(){
int i = 0;
Fi file;
while((file = saveDirectory.child(i + "." + saveExtension)).exists()){
i ++;
}
return file;
}
public Array<SaveSlot> getSaveSlots(){
return saves;
}
public class SaveSlot{
//public final int index;
public final Fi file;
boolean requestedPreview;
SaveMeta meta;
public SaveSlot(Fi file){
this.file = file;
}
public void load() throws SaveException{
try{
SaveIO.load(file);
meta = SaveIO.getMeta(file);
current = this;
totalPlaytime = meta.timePlayed;
savePreview();
}catch(Exception e){
throw new SaveException(e);
}
}
public void save(){
long time = totalPlaytime;
long prev = totalPlaytime;
totalPlaytime = time;
SaveIO.save(file);
meta = SaveIO.getMeta(file);
if(!state.is(State.menu)){
current = this;
}
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 String index(){
return file.nameWithoutExtension();
}
private Fi previewFile(){
return mapPreviewDirectory.child("save_slot_" + index() + ".png");
}
private Fi loadPreviewFile(){
return previewFile().sibling(previewFile().name() + ".spreview");
}
public boolean isHidden(){
return getZone() != null;
}
public String getPlayTime(){
return Strings.formatMillis(current == this ? totalPlaytime : meta.timePlayed);
}
public long getTimestamp(){
return meta.timestamp;
}
public String getDate(){
return SimpleDateFormat.getDateTimeInstance().format(new Date(meta.timestamp));
}
public Map getMap(){
return meta.map;
}
public void cautiousLoad(Runnable run){
Array<String> mods = Array.with(getMods());
mods.removeAll(Vars.mods.getModStrings());
if(!mods.isEmpty()){
ui.showConfirm("$warning", Core.bundle.format("mod.missing", mods.toString("\n")), run);
}else{
run.run();
}
}
public String getName(){
return Core.settings.getString("save-" + index() + "-name", "untitled");
}
public void setName(String name){
Core.settings.put("save-" + index() + "-name", name);
Core.settings.save();
}
public String[] getMods(){
return meta.mods;
}
public Zone getZone(){
return meta == null || meta.rules == null ? null : meta.rules.zone;
}
public Gamemode mode(){
return Gamemode.bestFit(meta.rules);
}
public int getBuild(){
return meta.build;
}
public int getWave(){
return meta.wave;
}
public boolean isAutosave(){
return Core.settings.getBool("save-" + index() + "-autosave", true);
}
public void setAutosave(boolean save){
Core.settings.put("save-" + index() + "-autosave", save);
Core.settings.save();
}
public void importFile(Fi from) throws IOException{
try{
from.copyTo(file);
}catch(Exception e){
throw new IOException(e);
}
}
public void exportFile(Fi to) throws IOException{
try{
file.copyTo(to);
}catch(Exception e){
throw new IOException(e);
}
}
public void delete(){
file.delete();
saves.remove(this, true);
if(this == current){
current = null;
}
if(Core.assets.isLoaded(loadPreviewFile().path())){
Core.assets.unload(loadPreviewFile().path());
}
}
}
}