diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/context/WorldContext.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/context/WorldContext.java index 4ebeb5714..ed83d2abe 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/context/WorldContext.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/context/WorldContext.java @@ -70,6 +70,6 @@ public final class WorldContext { ChecksumBuilder checksumBuilder = new ChecksumBuilder(); model.addToChecksum(checksumBuilder); maps.addToChecksum(checksumBuilder, this); - return checksumBuilder.build(); + return checksumBuilder.build(); } } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/model/ChecksumBuilder.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/model/ChecksumBuilder.java index fb430fa8f..570fd1965 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/model/ChecksumBuilder.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/model/ChecksumBuilder.java @@ -13,103 +13,103 @@ import java.security.NoSuchAlgorithmException; public class ChecksumBuilder { - public static final int CHECKSUM_LENGTH = 32;// 256 bits (depends on the hash algorithm) - public static final String CHECKSUM_ALGORITHM = "SHA-256"; //Should be available in all Android versions - private ByteBuffer buffer; - private final MessageDigest digest; + public static final int CHECKSUM_LENGTH = 32;// 256 bits (depends on the hash algorithm) + public static final String CHECKSUM_ALGORITHM = "SHA-256"; //Should be available in all Android versions + private ByteBuffer buffer; + private final MessageDigest digest; - private ChecksumBuilder(int initialCapacity, ByteOrder byteOrder) { - buffer = ByteBuffer.allocate(initialCapacity); - buffer.order(byteOrder); - try { - digest = MessageDigest.getInstance(CHECKSUM_ALGORITHM); // Or SHA-512 for even stronger hash - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Hash algorithm not found", e); - } - } + private ChecksumBuilder(int initialCapacity, ByteOrder byteOrder) { + buffer = ByteBuffer.allocate(initialCapacity); + buffer.order(byteOrder); + try { + digest = MessageDigest.getInstance(CHECKSUM_ALGORITHM); // Or SHA-512 for even stronger hash + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Hash algorithm not found", e); + } + } - private ChecksumBuilder(int initialCapacity) { - this(initialCapacity, ByteOrder.BIG_ENDIAN); // Default to big-endian - } + private ChecksumBuilder(int initialCapacity) { + this(initialCapacity, ByteOrder.BIG_ENDIAN); // Default to big-endian + } - public ChecksumBuilder() { - this(1024*10); // A reasonable default initial capacity - } + public ChecksumBuilder() { + this(1024*10); // A reasonable default initial capacity + } - // --- Methods for adding different data types --- + // --- Methods for adding different data types --- - public ChecksumBuilder add(String value) { - if (value != null) { - byte[] bytes; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - bytes = value.getBytes(StandardCharsets.UTF_8); - } else { - bytes = value.getBytes(); - } - add(bytes); - } else { - add(-1); // Use -1 to represent a null string - } - return this; - } + public ChecksumBuilder add(String value) { + if (value != null) { + byte[] bytes; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + bytes = value.getBytes(StandardCharsets.UTF_8); + } else { + bytes = value.getBytes(); + } + add(bytes); + } else { + add(-1); // Use -1 to represent a null string + } + return this; + } - public ChecksumBuilder add(byte[] bytes) { - add(bytes.length); // Add length prefix - ensureCapacity(bytes.length + 4); // +4 for length prefix (int) - buffer.put(bytes); - return this; - } + public ChecksumBuilder add(byte[] bytes) { + add(bytes.length); // Add length prefix + ensureCapacity(bytes.length + 4); // +4 for length prefix (int) + buffer.put(bytes); + return this; + } - public ChecksumBuilder add(boolean value) { - ensureCapacity(1); - buffer.put(value ? (byte) 1 : (byte) 0); - return this; - } + public ChecksumBuilder add(boolean value) { + ensureCapacity(1); + buffer.put(value ? (byte) 1 : (byte) 0); + return this; + } - public ChecksumBuilder add(long value) { - ensureCapacity(8); - buffer.putLong(value); - return this; - } + public ChecksumBuilder add(long value) { + ensureCapacity(8); + buffer.putLong(value); + return this; + } - public ChecksumBuilder add(int value) { - ensureCapacity(4); - buffer.putInt(value); - return this; - } + public ChecksumBuilder add(int value) { + ensureCapacity(4); + buffer.putInt(value); + return this; + } - public ChecksumBuilder add(float value) { - ensureCapacity(8); - buffer.putFloat(value); - return this; - } + public ChecksumBuilder add(float value) { + ensureCapacity(8); + buffer.putFloat(value); + return this; + } - public ChecksumBuilder add(double value) { - ensureCapacity(4); - buffer.putDouble(value); - return this; - } + public ChecksumBuilder add(double value) { + ensureCapacity(4); + buffer.putDouble(value); + return this; + } - // --- Method to finalize and get the checksum --- + // --- Method to finalize and get the checksum --- - public byte[] build() throws DigestException { - buffer.flip(); // Prepare for reading - digest.update(buffer);// Only use the actually used part of the buffer - buffer.flip(); // Prepare for further writing - return digest.digest(); - } + public byte[] build() throws DigestException { + buffer.flip(); // Prepare for reading + digest.update(buffer);// Only use the actually used part of the buffer + buffer.flip(); // Prepare for further writing + return digest.digest(); + } - // --- Utility method to ensure sufficient capacity --- - private void ensureCapacity(int required) { - if (buffer.remaining() < required) { - int newCapacity = Math.max(buffer.capacity() * 2, buffer.capacity() + required); - ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); - newBuffer.order(buffer.order()); - buffer.flip(); // Prepare for reading - newBuffer.put(buffer); // Copy existing data - buffer = newBuffer; // Assign the new buffer to the field - } - } + // --- Utility method to ensure sufficient capacity --- + private void ensureCapacity(int required) { + if (buffer.remaining() < required) { + int newCapacity = Math.max(buffer.capacity() * 2, buffer.capacity() + required); + ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); + newBuffer.order(buffer.order()); + buffer.flip(); // Prepare for reading + newBuffer.put(buffer); // Copy existing data + buffer = newBuffer; // Assign the new buffer to the field + } + } } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/savegames/Savegames.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/savegames/Savegames.java index b4e34d94a..3f93d88ea 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/savegames/Savegames.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/savegames/Savegames.java @@ -84,11 +84,11 @@ public final class Savegames { L.log("Error saving world: " + e.toString()); return false; } - } + } private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException { File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER); - ensureDirExists(cheatDetectionFolder); + ensureDirExists(cheatDetectionFolder); File backupFile = new File(cheatDetectionFolder, playerId + "X"); FileOutputStream fileOutputStream = new FileOutputStream(backupFile); fileOutputStream.write(savegame); @@ -109,8 +109,8 @@ public final class Savegames { LoadSavegameResult result = loadWorld(androidContext.getResources(), world, controllers, androidContext, fos, fh); fos.close(); if (result == LoadSavegameResult.success && slot != SLOT_QUICKSAVE && !world.model.statistics.hasUnlimitedSaves()) { - // save to the quicksave slot before deleting the file - if (!saveWorld(world, androidContext, SLOT_QUICKSAVE)) { + // save to the quicksave slot before deleting the file + if (!saveWorld(world, androidContext, SLOT_QUICKSAVE)) { return LoadSavegameResult.unknownError; } getSlotFile(slot, androidContext).delete(); @@ -127,35 +127,35 @@ public final class Savegames { } return LoadSavegameResult.unknownError; } - } + } - private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException { - long savedVersionToCheck = 0; - File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER); - ensureDirExists(cheatDetectionFolder); - File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId); - if (cheatDetectionFile.exists()) { - FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile); - DataInputStream dataInputStream = new DataInputStream(fileInputStream); - final CheatDetection cheatDetection = new CheatDetection(dataInputStream); - savedVersionToCheck = cheatDetection.savedVersion; - dataInputStream.close(); - fileInputStream.close(); - } + private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException { + long savedVersionToCheck = 0; + File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER); + ensureDirExists(cheatDetectionFolder); + File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId); + if (cheatDetectionFile.exists()) { + FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile); + DataInputStream dataInputStream = new DataInputStream(fileInputStream); + final CheatDetection cheatDetection = new CheatDetection(dataInputStream); + savedVersionToCheck = cheatDetection.savedVersion; + dataInputStream.close(); + fileInputStream.close(); + } if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) { return true; } - if (androidContext.getFileStreamPath(fh.playerId).exists()) { - FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId); - DataInputStream dataInputStream = new DataInputStream(fileInputStream); - final CheatDetection cheatDetection = new CheatDetection(dataInputStream); - if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) { - savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED; - } else if (cheatDetection.savedVersion > savedVersionToCheck) { - savedVersionToCheck = cheatDetection.savedVersion; - } + if (androidContext.getFileStreamPath(fh.playerId).exists()) { + FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId); + DataInputStream dataInputStream = new DataInputStream(fileInputStream); + final CheatDetection cheatDetection = new CheatDetection(dataInputStream); + if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) { + savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED; + } else if (cheatDetection.savedVersion > savedVersionToCheck) { + savedVersionToCheck = cheatDetection.savedVersion; + } if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) { L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion); @@ -168,48 +168,48 @@ public final class Savegames { return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck); } - private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException { - if (slot == SLOT_QUICKSAVE) { - return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE); - } else { - ensureSavegameDirectoryExists(androidContext); - return new FileOutputStream(getSlotFile(slot, androidContext)); - } - } + private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException { + if (slot == SLOT_QUICKSAVE) { + return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE); + } else { + ensureSavegameDirectoryExists(androidContext); + return new FileOutputStream(getSlotFile(slot, androidContext)); + } + } - private static void ensureSavegameDirectoryExists(Context context) { - File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY); - ensureDirExists(dir); - } + private static void ensureSavegameDirectoryExists(Context context) { + File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY); + ensureDirExists(dir); + } - public static boolean ensureDirExists(File dir) { - if (!dir.exists()) { - boolean worked = dir.mkdir(); - return worked; - } - return true; - } + public static boolean ensureDirExists(File dir) { + if (!dir.exists()) { + boolean worked = dir.mkdir(); + return worked; + } + return true; + } - private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException { - if (slot == SLOT_QUICKSAVE) { - return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE); - } else { - return new FileInputStream(getSlotFile(slot, androidContext)); - } - } + private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException { + if (slot == SLOT_QUICKSAVE) { + return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE); + } else { + return new FileInputStream(getSlotFile(slot, androidContext)); + } + } - public static File getSlotFile(int slot, Context context) { - File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY); - return getSlotFile(slot, root); - } + public static File getSlotFile(int slot, Context context) { + File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY); + return getSlotFile(slot, root); + } - public static File getSlotFile(int slot, File directory) { - return new File(directory, getSlotFileName(slot)); - } + public static File getSlotFile(int slot, File directory) { + return new File(directory, getSlotFileName(slot)); + } - public static String getSlotFileName(int slot) { - return Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot; - } + public static String getSlotFileName(int slot) { + return Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot; + } public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException, DigestException { @@ -230,11 +230,11 @@ public final class Savegames { dest.close(); } - public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, Context androidContext, InputStream inState, FileHeader fh) throws IOException, DigestException { - DataInputStream src = new DataInputStream(inState); - final FileHeader header = new FileHeader(src, fh.skipIcon); - if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION) - return LoadSavegameResult.savegameIsFromAFutureVersion; + public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, Context androidContext, InputStream inState, FileHeader fh) throws IOException, DigestException { + DataInputStream src = new DataInputStream(inState); + final FileHeader header = new FileHeader(src, fh.skipIcon); + if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION) + return LoadSavegameResult.savegameIsFromAFutureVersion; world.maps.readFromParcel(src, world, controllers, header.fileversion); world.model = new ModelContainer(src, world, controllers, header.fileversion); @@ -247,7 +247,7 @@ public final class Savegames { if (header.fileversion < 45) { LegacySavegamesContentAdaptations.adaptToNewContentForVersion45(world, controllers, res); } - + onWorldLoaded(res, world, controllers); return LoadSavegameResult.success; @@ -284,15 +284,15 @@ public final class Savegames { } } - private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException { - File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER); - ensureDirExists(cheatDetectionFolder); - File cheatDetectionFile = new File(cheatDetectionFolder, playerId); - FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile); - DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); - CheatDetection.writeToParcel(dataOutputStream, savedVersion); - dataOutputStream.close(); - fileOutputStream.close(); + private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException { + File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER); + ensureDirExists(cheatDetectionFolder); + File cheatDetectionFile = new File(cheatDetectionFolder, playerId); + FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile); + DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream); + CheatDetection.writeToParcel(dataOutputStream, savedVersion); + dataOutputStream.close(); + fileOutputStream.close(); fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE); dataOutputStream = new DataOutputStream(fileOutputStream); @@ -303,26 +303,26 @@ public final class Savegames { private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)"); - public static List getUsedSavegameSlots(Context context) { - try { - final List result = new ArrayList(); - AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() { - @Override - public boolean accept(File f, String filename) { - Matcher m = savegameFilenamePattern.matcher(filename); - if (m != null && m.matches()) { - result.add(Integer.parseInt(m.group(1))); - return true; - } - return false; - } - }); - Collections.sort(result); - return result; - } catch (Exception e) { - return new ArrayList(); - } - } + public static List getUsedSavegameSlots(Context context) { + try { + final List result = new ArrayList(); + AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() { + @Override + public boolean accept(File f, String filename) { + Matcher m = savegameFilenamePattern.matcher(filename); + if (m != null && m.matches()) { + result.add(Integer.parseInt(m.group(1))); + return true; + } + return false; + } + }); + Collections.sort(result); + return result; + } catch (Exception e) { + return new ArrayList(); + } + } private static final class CheatDetection { public final int fileversion; @@ -342,17 +342,17 @@ public final class Savegames { } - public static final class FileHeader { - public final int fileversion; - public final String playerName; - public final String displayInfo; - public final int iconID; + public static final class FileHeader { + public final int fileversion; + public final String playerName; + public final String displayInfo; + public final int iconID; public final boolean isAlteredSavegame; public boolean skipIcon = false; - public final boolean isDead; - public final boolean hasUnlimitedSaves; - public final String playerId; - public final long savedVersion; + public final boolean isDead; + public final boolean hasUnlimitedSaves; + public final String playerId; + public final long savedVersion; public String describe() { return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo; @@ -361,18 +361,18 @@ public final class Savegames { // ====== PARCELABLE =================================================================== - public FileHeader(DataInputStream src, boolean skipIcon) throws IOException { - int fileversion = src.readInt(); - if (fileversion == 11) - fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11. - this.fileversion = fileversion; - if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header. - this.playerName = src.readUTF(); - this.displayInfo = src.readUTF(); - } else { - this.playerName = null; - this.displayInfo = null; - } + public FileHeader(DataInputStream src, boolean skipIcon) throws IOException { + int fileversion = src.readInt(); + if (fileversion == 11) + fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11. + this.fileversion = fileversion; + if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header. + this.playerName = src.readUTF(); + this.displayInfo = src.readUTF(); + } else { + this.playerName = null; + this.displayInfo = null; + } if (fileversion >= 43) { int id = src.readInt();