diff --git a/SPD-classes/src/main/java/com/watabou/utils/FileUtils.java b/SPD-classes/src/main/java/com/watabou/utils/FileUtils.java
new file mode 100644
index 000000000..1c767186b
--- /dev/null
+++ b/SPD-classes/src/main/java/com/watabou/utils/FileUtils.java
@@ -0,0 +1,138 @@
+/*
+ * Pixel Dungeon
+ * Copyright (C) 2012-2015 Oleg Dolya
+ *
+ * Shattered Pixel Dungeon
+ * Copyright (C) 2014-2017 Evan Debenham
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+
+package com.watabou.utils;
+
+import com.watabou.noosa.Game;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class FileUtils {
+
+ // Files
+
+ public static boolean fileExists( String name ){
+ File file = new File(Game.instance.getFilesDir(), name);
+ return file.exists() && !file.isDirectory();
+ }
+
+ public static File getFile( String name ){
+ return getFile( Game.instance.getFilesDir(), name);
+ }
+
+ public static File getFile( File base, String name ){
+ File file = new File(base, name);
+ if (!file.exists() || !file.isDirectory()){
+ return file;
+ }
+ return null;
+ }
+
+ public static boolean deleteFile( String name ){
+ return Game.instance.deleteFile( name );
+ }
+
+ public static boolean deleteFile( File file ){
+ return !file.isDirectory() && file.delete();
+ }
+
+
+ // Directories
+
+ public static boolean dirExists( String name ){
+ File dir = new File(Game.instance.getFilesDir(), name);
+ return dir.exists() && dir.isDirectory();
+ }
+
+ //base directory
+ public static File getDir( String name ){
+ return getDir( Game.instance.getFilesDir(), name);
+ }
+
+ public static File getDir( File base, String name ){
+ File dir = new File(base, name);
+ if (!dir.exists() && dir.mkdirs()){
+ return dir;
+ } else if (dir.isDirectory()){
+ return dir;
+ }
+ return null;
+ }
+
+ public static boolean deleteDir( String name ){
+ return deleteDir(getDir(name));
+ }
+
+ public static boolean deleteDir( File dir ){
+ if (dir == null || !dir.isDirectory()){
+ return false;
+ }
+
+ for (File f : dir.listFiles()){
+ if (f.isDirectory()){
+ if (!deleteDir(f)) return false;
+ } else {
+ if (!deleteFile(f)) return false;
+ }
+ }
+
+ return dir.delete();
+ }
+
+ // bundle reading
+
+ //only works for base path
+ public static Bundle bundleFromFile( String fileName ) throws IOException{
+ return bundleFromStream(Game.instance.openFileInput( fileName ));
+ }
+
+ public static Bundle bundleFromFile( File file ) throws IOException{
+ return bundleFromStream(new FileInputStream(file));
+ }
+
+ private static Bundle bundleFromStream( InputStream input ) throws IOException{
+ Bundle bundle = Bundle.read( input );
+ input.close();
+ return bundle;
+ }
+
+ // bundle writing
+
+ //only works for base path
+ public static void bundleToFile( String fileName, Bundle bundle ) throws IOException{
+ bundleToStream( Game.instance.openFileOutput( fileName, Game.MODE_PRIVATE ), bundle);
+ }
+
+ public static void bundleToFile( File file, Bundle bundle ) throws IOException{
+ bundleToStream( new FileOutputStream(file), bundle);
+ }
+
+ private static void bundleToStream( OutputStream output, Bundle bundle ) throws IOException{
+ Bundle.write( bundle, output );
+ output.close();
+ }
+
+}
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java
index 2e8046be0..b91d1ec0a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Badges.java
@@ -37,13 +37,11 @@ import com.shatteredpixel.shatteredpixeldungeon.journal.Catalog;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
-import com.watabou.noosa.Game;
import com.watabou.utils.Bundle;
import com.watabou.utils.Callback;
+import com.watabou.utils.FileUtils;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -222,10 +220,7 @@ public class Badges {
public static void loadGlobal() {
if (global == null) {
try {
- InputStream input = Game.instance.openFileInput( BADGES_FILE );
- Bundle bundle = Bundle.read( input );
- input.close();
-
+ Bundle bundle = FileUtils.bundleFromFile( BADGES_FILE );
global = restore( bundle );
} catch (IOException e) {
@@ -241,9 +236,7 @@ public class Badges {
store( bundle, global );
try {
- OutputStream output = Game.instance.openFileOutput( BADGES_FILE, Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile(BADGES_FILE, bundle);
saveNeeded = false;
} catch (IOException e) {
ShatteredPixelDungeon.reportException(e);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java
index 277ed784a..21582fe03 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Bones.java
@@ -29,11 +29,10 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.Artifact;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
import com.watabou.noosa.Game;
import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
import com.watabou.utils.Random;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
@@ -64,9 +63,7 @@ public class Bones {
bundle.put( ITEM, item );
try {
- OutputStream output = Game.instance.openFileOutput( BONES_FILE, Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile( BONES_FILE, bundle );
} catch (IOException e) {
ShatteredPixelDungeon.reportException(e);
}
@@ -127,9 +124,7 @@ public class Bones {
if (depth == -1) {
try {
- InputStream input = Game.instance.openFileInput( BONES_FILE ) ;
- Bundle bundle = Bundle.read( input );
- input.close();
+ Bundle bundle = FileUtils.bundleFromFile(BONES_FILE);
depth = bundle.getInt( LEVEL );
item = (Item)bundle.get( ITEM );
@@ -143,7 +138,7 @@ public class Bones {
} else {
//heroes who are challenged cannot find bones
if (depth == Dungeon.depth && Dungeon.challenges == 0) {
- Game.instance.deleteFile( BONES_FILE );
+ FileUtils.deleteFile( BONES_FILE );
depth = 0;
//Enforces artifact uniqueness
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
index 587d837a7..06fe509cf 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java
@@ -69,13 +69,13 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndResurrect;
import com.watabou.noosa.Game;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
import com.watabou.utils.SparseArray;
+import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
@@ -431,17 +431,9 @@ public class Dungeon {
return Random.Int(5 - floorThisSet) < asLeftThisSet;
}
- private static final String RG_GAME_FILE = "game.dat";
- private static final String RG_DEPTH_FILE = "depth%d.dat";
-
- private static final String WR_GAME_FILE = "warrior.dat";
- private static final String WR_DEPTH_FILE = "warrior%d.dat";
-
- private static final String MG_GAME_FILE = "mage.dat";
- private static final String MG_DEPTH_FILE = "mage%d.dat";
-
- private static final String RN_GAME_FILE = "ranger.dat";
- private static final String RN_DEPTH_FILE = "ranger%d.dat";
+ private static final String GAME_FOLDER = "game%d";
+ private static final String GAME_FILE = "game.dat";
+ private static final String DEPTH_FILE = "depth%d.dat";
private static final String VERSION = "version";
private static final String SEED = "seed";
@@ -456,33 +448,62 @@ public class Dungeon {
private static final String QUESTS = "quests";
private static final String BADGES = "badges";
- public static String gameFile( HeroClass cl ) {
+ //TODO remove class-based loading
+
+ public static File gameFolder( HeroClass cl ) {
switch (cl) {
- case WARRIOR:
- return WR_GAME_FILE;
- case MAGE:
- return MG_GAME_FILE;
- case HUNTRESS:
- return RN_GAME_FILE;
- default:
- return RG_GAME_FILE;
+ case WARRIOR:
+ return gameFolder(1);
+ case MAGE:
+ return gameFolder(2);
+ case ROGUE: default:
+ return gameFolder(3);
+ case HUNTRESS:
+ return gameFolder(4);
}
}
- private static String depthFile( HeroClass cl ) {
+
+
+ public static File gameFile( HeroClass cl ) {
switch (cl) {
case WARRIOR:
- return WR_DEPTH_FILE;
+ return gameFile(1);
case MAGE:
- return MG_DEPTH_FILE;
+ return gameFile(2);
+ case ROGUE: default:
+ return gameFile(3);
case HUNTRESS:
- return RN_DEPTH_FILE;
- default:
- return RG_DEPTH_FILE;
+ return gameFile(4);
}
}
- public static void saveGame( String fileName ) throws IOException {
+ public static File depthFile( HeroClass cl, int depth ) {
+ switch (cl) {
+ case WARRIOR:
+ return depthFile(1, depth);
+ case MAGE:
+ return depthFile(2, depth);
+ case ROGUE: default:
+ return depthFile(3, depth);
+ case HUNTRESS:
+ return depthFile(4, depth);
+ }
+ }
+
+ public static File gameFolder( int save ){
+ return FileUtils.getDir(Messages.format(GAME_FOLDER, save));
+ }
+
+ public static File gameFile( int save ){
+ return FileUtils.getFile(gameFolder( save ), GAME_FILE);
+ }
+
+ public static File depthFile( int save, int depth ) {
+ return FileUtils.getFile( gameFolder(save), Messages.format(DEPTH_FILE, depth));
+ }
+
+ public static void saveGame( HeroClass cl ) throws IOException {
try {
Bundle bundle = new Bundle();
@@ -535,9 +556,7 @@ public class Dungeon {
Badges.saveLocal( badges );
bundle.put( BADGES, badges );
- OutputStream output = Game.instance.openFileOutput( fileName, Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile( gameFile(cl), bundle);
} catch (IOException e) {
GamesInProgress.setUnknown( hero.heroClass );
@@ -549,17 +568,14 @@ public class Dungeon {
Bundle bundle = new Bundle();
bundle.put( LEVEL, level );
- OutputStream output = Game.instance.openFileOutput(
- Messages.format( depthFile( hero.heroClass ), depth ), Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile(depthFile( hero.heroClass, depth), bundle);
}
public static void saveAll() throws IOException {
if (hero != null && hero.isAlive()) {
Actor.fixTime();
- saveGame( gameFile( hero.heroClass ) );
+ saveGame( hero.heroClass );
saveLevel();
GamesInProgress.set( hero.heroClass, depth, hero.lvl, challenges != 0 );
@@ -573,16 +589,12 @@ public class Dungeon {
}
public static void loadGame( HeroClass cl ) throws IOException {
- loadGame( gameFile( cl ), true );
- }
-
- public static void loadGame( String fileName ) throws IOException {
- loadGame( fileName, false );
+ loadGame( cl, true );
}
- public static void loadGame( String fileName, boolean fullLoad ) throws IOException {
+ public static void loadGame( HeroClass cl, boolean fullLoad ) throws IOException {
- Bundle bundle = gameBundle( fileName );
+ Bundle bundle = FileUtils.bundleFromFile( gameFile( cl ) );
version = bundle.getInt( VERSION );
@@ -674,9 +686,7 @@ public class Dungeon {
Dungeon.level = null;
Actor.clear();
- InputStream input = Game.instance.openFileInput( Messages.format( depthFile( cl ), depth ) ) ;
- Bundle bundle = Bundle.read( input );
- input.close();
+ Bundle bundle = FileUtils.bundleFromFile( depthFile( cl, depth)) ;
Level level = (Level)bundle.get( LEVEL );
@@ -689,27 +699,15 @@ public class Dungeon {
public static void deleteGame( HeroClass cl, boolean deleteLevels ) {
- Game.instance.deleteFile( gameFile( cl ) );
+ FileUtils.deleteFile(gameFile(cl));
if (deleteLevels) {
- int depth = 1;
- while (Game.instance.deleteFile( Messages.format( depthFile( cl ), depth ) )) {
- depth++;
- }
+ FileUtils.deleteDir(gameFolder(cl));
}
GamesInProgress.delete( cl );
}
- public static Bundle gameBundle( String fileName ) throws IOException {
-
- InputStream input = Game.instance.openFileInput( fileName );
- Bundle bundle = Bundle.read( input );
- input.close();
-
- return bundle;
- }
-
public static void preview( GamesInProgress.Info info, Bundle bundle ) {
info.depth = bundle.getInt( DEPTH );
info.version = bundle.getInt( VERSION );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java
index b90577823..d1ca60f90 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/GamesInProgress.java
@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass;
import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
import java.io.IOException;
import java.util.HashMap;
@@ -31,6 +32,7 @@ public class GamesInProgress {
private static HashMap state = new HashMap();
+ //TODO this should check if a game directly exists
public static Info check( HeroClass cl ) {
if (state.containsKey( cl )) {
@@ -42,13 +44,14 @@ public class GamesInProgress {
Info info;
try {
- Bundle bundle = Dungeon.gameBundle( Dungeon.gameFile( cl ) );
+ Bundle bundle = FileUtils.bundleFromFile(Dungeon.gameFile(cl));
info = new Info();
- Dungeon.preview( info, bundle );
+ Dungeon.preview(info, bundle);
//saves from before 0.4.3c are not supported
- if (info.version < ShatteredPixelDungeon.v0_4_3c){
+ if (info.version < ShatteredPixelDungeon.v0_4_3c) {
info = null;
+
}
} catch (IOException e) {
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java
index c2c30e483..a797a82f0 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Rankings.java
@@ -33,13 +33,11 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.Scroll;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton;
-import com.watabou.noosa.Game;
import com.watabou.utils.Bundlable;
import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -194,9 +192,7 @@ public enum Rankings {
bundle.put( WON, wonNumber );
try {
- OutputStream output = Game.instance.openFileOutput( RANKINGS_FILE, Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile( RANKINGS_FILE, bundle);
} catch (IOException e) {
ShatteredPixelDungeon.reportException(e);
}
@@ -212,9 +208,7 @@ public enum Rankings {
records = new ArrayList<>();
try {
- InputStream input = Game.instance.openFileInput( RANKINGS_FILE );
- Bundle bundle = Bundle.read( input );
- input.close();
+ Bundle bundle = FileUtils.bundleFromFile( RANKINGS_FILE );
for (Bundlable record : bundle.getCollection( RECORDS )) {
records.add( (Record)record );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
index 60ff3bfe3..3f4e3337a 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ShatteredPixelDungeon.java
@@ -56,6 +56,8 @@ public class ShatteredPixelDungeon extends Game {
public static final int v0_6_1 = 205;
public static final int v0_6_2 = 222;
+ public static final int v0_6_2e = 229;
+
public ShatteredPixelDungeon() {
super( WelcomeScene.class );
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Journal.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Journal.java
index 77cd05005..0398d0b76 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Journal.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Journal.java
@@ -22,12 +22,10 @@
package com.shatteredpixel.shatteredpixeldungeon.journal;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
-import com.watabou.noosa.Game;
import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
public class Journal {
@@ -42,9 +40,7 @@ public class Journal {
Bundle bundle;
try {
- InputStream input = Game.instance.openFileInput( JOURNAL_FILE );
- bundle = Bundle.read(input);
- input.close();
+ bundle = FileUtils.bundleFromFile( JOURNAL_FILE );
} catch (IOException e){
bundle = new Bundle();
@@ -70,9 +66,7 @@ public class Journal {
Document.store(bundle);
try {
- OutputStream output = Game.instance.openFileOutput( JOURNAL_FILE, Game.MODE_PRIVATE );
- Bundle.write( bundle, output );
- output.close();
+ FileUtils.bundleToFile( JOURNAL_FILE, bundle );
saveNeeded = false;
} catch (IOException e) {
ShatteredPixelDungeon.reportException(e);
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
index 02fb064a5..d41a52017 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/WelcomeScene.java
@@ -23,6 +23,7 @@ package com.shatteredpixel.shatteredpixeldungeon.scenes;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Badges;
+import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.Rankings;
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
import com.shatteredpixel.shatteredpixeldungeon.effects.BannerSprites;
@@ -35,6 +36,8 @@ import com.watabou.noosa.Camera;
import com.watabou.noosa.Game;
import com.watabou.noosa.Image;
import com.watabou.noosa.audio.Sample;
+import com.watabou.utils.Bundle;
+import com.watabou.utils.FileUtils;
public class WelcomeScene extends PixelScene {
@@ -155,7 +158,35 @@ public class WelcomeScene extends PixelScene {
Rankings.INSTANCE.save();
} catch (Exception e) {
//if we encounter a fatal error, then just clear the rankings
- Game.instance.deleteFile( Rankings.RANKINGS_FILE );
+ FileUtils.deleteFile( Rankings.RANKINGS_FILE );
+ }
+ }
+
+ //convert game saves from the old format
+ if (previousVersion <= ShatteredPixelDungeon.v0_6_2e){
+ //old save file names for warrior, mage, rogue, huntress
+ String[] classes = new String[]{"warrior", "mage", "game", "ranger"};
+ for (int i = 1; i <= classes.length; i++){
+ String name = classes[i-1];
+ if (FileUtils.fileExists(name + ".dat")){
+ try {
+ Bundle gamedata = FileUtils.bundleFromFile(name + ".dat");
+ FileUtils.bundleToFile(Dungeon.gameFile(i), gamedata);
+ FileUtils.deleteFile(name + ".dat");
+
+ //rogue's safe files have a different name
+ if (name.equals("game")) name = "depth";
+
+ int depth = 1;
+ while (FileUtils.fileExists(name + depth + ".dat")) {
+ gamedata = FileUtils.bundleFromFile(name + depth + ".dat");
+ FileUtils.bundleToFile(Dungeon.depthFile(i, depth), gamedata);
+ FileUtils.deleteFile(name + depth + ".dat");
+ depth++;
+ }
+ } catch (Exception e){
+ }
+ }
}
}