Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File backups in development builds #610

Merged
merged 7 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
allprojects {
apply plugin: "java"

version = "2.2.1-dev1"
version = "2.2.1-dev2"

sourceCompatibility = 8
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
Expand Down
2 changes: 1 addition & 1 deletion src/client/java/minicraft/core/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected Game() {

public static final String NAME = "Minicraft Plus"; // This is the name on the application window.

public static final Version VERSION = new Version("2.2.1-dev1");
public static final Version VERSION = new Version("2.2.1-dev2");

public static InputHandler input; // Input used in Game, Player, and just about all the *Menu classes.
public static Player player;
Expand Down
87 changes: 87 additions & 0 deletions src/client/java/minicraft/saveload/Load.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import minicraft.screen.SignDisplay;
import minicraft.screen.SkinDisplay;
import minicraft.screen.TutorialDisplayHandler;
import minicraft.screen.WorldSelectDisplay;
import minicraft.screen.entry.ListEntry;
import minicraft.screen.entry.StringEntry;
import minicraft.util.AdvancementElement;
Expand Down Expand Up @@ -128,6 +129,87 @@ public Load(String worldname, boolean loadGame) {

if (!loadGame) return;

// Is dev build
if (Game.VERSION.isDev() && worldVer.compareTo(Game.VERSION) < 0) {
Logging.SAVELOAD.info("Old world detected, backup prompting...");
ArrayList<ListEntry> entries = new ArrayList<>();
entries.addAll(Arrays.asList(StringEntry.useLines(Color.WHITE, false,
Localization.getLocalized("minicraft.displays.save.popup_display.world_backup_prompt.msg",
worldVer, Game.VERSION))));
entries.addAll(Arrays.asList(StringEntry.useLines("minicraft.display.popup.escape_cancel")));

AtomicBoolean acted = new AtomicBoolean(false);
AtomicBoolean continues = new AtomicBoolean(false);
AtomicBoolean doBackup = new AtomicBoolean(false);

ArrayList<PopupDisplay.PopupActionCallback> callbacks = new ArrayList<>();
callbacks.add(new PopupDisplay.PopupActionCallback("EXIT", m -> {
Game.exitDisplay();
acted.set(true);
return true;
}));

callbacks.add(new PopupDisplay.PopupActionCallback("ENTER|Y", m -> {
Game.exitDisplay();
continues.set(true);
doBackup.set(true);
acted.set(true);
return true;
}));

callbacks.add(new PopupDisplay.PopupActionCallback("N", m -> {
Game.exitDisplay();
continues.set(true);
acted.set(true);
return true;
}));

Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(
"minicraft.displays.save.popup_display.world_backup_prompt", callbacks, 2),
entries.toArray(new ListEntry[0])));

while (true) {
if (acted.get()) {
if (continues.get()) {
if (doBackup.get()) {
Logging.SAVELOAD.info("Performing world backup...");
int i = 0;
String filename = worldname;
File f = new File(location + "/saves/", filename);
while (f.exists()) { // Increments world name if world exists
i++;
filename = worldname + " (" + i + ")";
f = new File(location + "/saves/", filename);
}
f.mkdirs();
try {
FileHandler.copyFolderContents(Paths.get(location, "saves", worldname),
f.toPath(), FileHandler.SKIP, false);
} catch (IOException e) {
Logging.SAVELOAD.error(e, "Error occurs while performing world backup, loading aborted");
throw new RuntimeException(new InterruptedException("World loading interrupted."));
}

Logging.SAVELOAD.info("World backup \"{}\" is created.", filename);
WorldSelectDisplay.updateWorlds();
} else
Logging.SAVELOAD.warn("World backup is skipped.");
Logging.SAVELOAD.debug("World loading continues...");
} else {
Logging.SAVELOAD.info("User cancelled world loading, loading aborted.");
throw new RuntimeException(new InterruptedException("World loading interrupted."));
}

break;
}

try {
//noinspection BusyWait
Thread.sleep(10);
} catch (InterruptedException ignored) {}
}
}

if (worldVer.compareTo(new Version("1.9.2")) < 0)
new LegacyLoad(worldname);
else {
Expand Down Expand Up @@ -198,6 +280,11 @@ public Load(String worldname, boolean loadGame) {

break;
}

try {
//noinspection BusyWait
Thread.sleep(10);
} catch (InterruptedException ignored) {}
}
}
}
Expand Down
31 changes: 31 additions & 0 deletions src/client/java/minicraft/saveload/Save.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -119,6 +120,36 @@ public Save(String worldname) {
*/
public Save() {
this(new File(Game.gameDir + "/"));

if (Game.VERSION.isDev()) { // Is dev build
Logging.SAVELOAD.debug("In dev build: Searching for old preferences...");
Version prefVer;
File prefFile = new File(location, "Preferences.json"); // Only this is checked when checking existence.
File unlocFile = new File(location, "Unlocks.json");
try {
JSONObject json = new JSONObject(Load.loadFromFile(location + "Preferences.json", false));
prefVer = new Version(json.getString("version"));
} catch (FileNotFoundException e) {
Logging.SAVELOAD.debug("Preferences.json is not found, ignoring...");
prefVer = null;
} catch (IOException e) {
Logging.SAVELOAD.error(e, "Unable to load Preferences.json, saving aborted");
return;
}

if (prefVer != null && prefVer.compareTo(Game.VERSION) < 0) {
Logging.SAVELOAD.info("Old preferences detected, backup performing...");
File prefBackupFile = new File(location + "Preferences.json.bak");
if (prefBackupFile.exists()) Logging.SAVELOAD.info("Overwriting old Preferences.json backup...");
if (prefBackupFile.delete()) Logging.SAVELOAD.trace("Preferences.json.bak is deleted.");
if (prefFile.renameTo(prefBackupFile)) Logging.SAVELOAD.trace("Preferences.json is renamed to Preferences.json.bak");
File unlocBackupFile = new File(location + "Unlocks.json.bak");
if (unlocBackupFile.exists()) Logging.SAVELOAD.info("Overwriting old Unlocks.json backup...");
if (unlocBackupFile.delete()) Logging.SAVELOAD.trace("Unlocks.json.bak is deleted.");
if (unlocFile.renameTo(unlocBackupFile)) Logging.SAVELOAD.trace("Unlocks.json is renamed to Unlocks.json.bak");
}
}

Logging.SAVELOAD.debug("Writing preferences and unlocks...");
writePrefs();
writeUnlocks();
Expand Down
4 changes: 4 additions & 0 deletions src/client/java/minicraft/saveload/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ public int compareTo(@NotNull Version ov, boolean ignoreDev) {
return 0; // The versions are equal.
}

public boolean isDev() {
return dev != 0;
}

@Override
public String toString() {
return make + "." + major + "." + minor + (dev == 0 ? "" : "-dev" + dev);
Expand Down
2 changes: 2 additions & 0 deletions src/client/resources/assets/localization/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@
"minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] to move packs. ",
"minicraft.displays.resource_packs.display.help.select": "%s to examine.",
"minicraft.displays.resource_packs.display.title": "Resource Packs",
"minicraft.displays.save.popup_display.world_backup_prompt": "World Backup Prompt",
"minicraft.displays.save.popup_display.world_backup_prompt.msg": "The world is on version %s while you are on version %s. You are advised to perform a backup in case of irreversible world corruption. Should you like to perform a backup before continuing? (Y|N)",
"minicraft.displays.skin": "Skins",
"minicraft.displays.skin.display.help.move": "Use %s and %s to move.",
"minicraft.displays.skin.display.help.select": "%s to select, and %s to cancel.",
Expand Down
Loading