diff --git a/jme3-core/src/tools/java/jme3tools/savegame/SaveGame.java b/jme3-core/src/tools/java/jme3tools/savegame/SaveGame.java index f01b3e9c1c..13ed2d8c4d 100644 --- a/jme3-core/src/tools/java/jme3tools/savegame/SaveGame.java +++ b/jme3-core/src/tools/java/jme3tools/savegame/SaveGame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,14 +36,16 @@ import com.jme3.export.binary.BinaryExporter; import com.jme3.export.binary.BinaryImporter; import com.jme3.system.JmeSystem; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.GZIPInputStream; @@ -51,10 +53,16 @@ /** * Tool for saving Savables as SaveGame entries in a system-dependent way. + * * @author normenhansen */ public class SaveGame { + /** + * The logger instance for this class. Used to log messages, warnings, and errors. + */ + private static final Logger logger = Logger.getLogger(SaveGame.class.getName()); + /** * A private constructor to inhibit instantiation of this class. */ @@ -80,47 +88,33 @@ public static void saveGame(String gamePath, String dataName, Savable data) { */ public static void saveGame(String gamePath, String dataName, Savable data, JmeSystem.StorageFolderType storageType) { if (storageType == null) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Base Storage Folder Type is null, using External!"); + logger.log(Level.WARNING, "Storage folder type is null. Using {0} as default.", JmeSystem.StorageFolderType.External); storageType = JmeSystem.StorageFolderType.External; } - BinaryExporter ex = BinaryExporter.getInstance(); - OutputStream os = null; try { File baseFolder = JmeSystem.getStorageFolder(storageType); if (baseFolder == null) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error creating save file!"); - throw new IllegalStateException("SaveGame dataset cannot be created"); + throw new IllegalStateException("Failed to get base storage folder for type: " + storageType); } - File daveFolder = new File(baseFolder.getAbsolutePath() + File.separator + gamePath.replace('/', File.separatorChar)); - if (!daveFolder.exists() && !daveFolder.mkdirs()) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error creating save file!"); - throw new IllegalStateException("SaveGame dataset cannot be created"); - } - File saveFile = new File(daveFolder.getAbsolutePath() + File.separator + dataName); - if (!saveFile.exists()) { - if (!saveFile.createNewFile()) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error creating save file!"); - throw new IllegalStateException("SaveGame dataset cannot be created"); - } - } - os = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(saveFile))); - ex.save(data, os); - Logger.getLogger(SaveGame.class.getName()).log(Level.FINE, "Saving data to: {0}", saveFile.getAbsolutePath()); - } catch (IOException ex1) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error saving data: {0}", ex1); - ex1.printStackTrace(); - throw new IllegalStateException("SaveGame dataset cannot be saved"); - } finally { - try { - if (os != null) { - os.close(); - } - } catch (IOException ex1) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error saving data: {0}", ex1); - ex1.printStackTrace(); - throw new IllegalStateException("SaveGame dataset cannot be saved"); + + Path saveFolderPath = Paths.get(baseFolder.getAbsolutePath(), gamePath.replace('/', File.separatorChar)); + Path saveFilePath = saveFolderPath.resolve(dataName); + + // Ensure directories exist + Files.createDirectories(saveFolderPath); + + try (OutputStream os = Files.newOutputStream(saveFilePath); + GZIPOutputStream gzip = new GZIPOutputStream(new BufferedOutputStream(os))) { + + BinaryExporter exporter = BinaryExporter.getInstance(); + exporter.save(data, gzip); + logger.log(Level.INFO, "Successfully saved data to: {0}", saveFilePath.toAbsolutePath()); } + } catch (IOException | IllegalStateException ex) { + logger.log(Level.SEVERE, "Error saving data for gamePath: {0}, dataName: {1}. Exception: {2}", + new Object[]{gamePath, dataName, ex.getMessage()}); + throw new IllegalStateException("SaveGame dataset cannot be saved.", ex); } } @@ -160,48 +154,45 @@ public static Savable loadGame(String gamePath, String dataName, AssetManager ma * Loads a savable that has been saved on this system with saveGame() before. * @param gamePath A unique path for this game, e.g. com/mycompany/mygame * @param dataName A unique name for this SaveGame, e.g. "save_001" - * @param manager Link to an AssetManager if required for loading the data (e.g. models with textures) + * @param assetManager Link to an AssetManager if required for loading the data (e.g. models with textures) * @param storageType The specific type of folder to use to save the data * @return The savable that was saved or null if none was found */ - public static Savable loadGame(String gamePath, String dataName, AssetManager manager, JmeSystem.StorageFolderType storageType) { + public static Savable loadGame(String gamePath, String dataName, AssetManager assetManager, JmeSystem.StorageFolderType storageType) { if (storageType == null) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Base Storage Folder Type is null, using External!"); + logger.log(Level.WARNING, "Storage folder type is null. Using {0} as default.", JmeSystem.StorageFolderType.External); storageType = JmeSystem.StorageFolderType.External; } - InputStream is = null; - Savable sav = null; try { File baseFolder = JmeSystem.getStorageFolder(storageType); if (baseFolder == null) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error reading base storage folder!"); + logger.log(Level.SEVERE, "Error reading base storage folder for type: {0}", storageType); return null; } - File file = new File(baseFolder.getAbsolutePath() + File.separator + gamePath.replace('/', File.separatorChar) + File.separator + dataName); - if(!file.exists()){ + Path loadFilePath = Paths.get(baseFolder.getAbsolutePath(), gamePath.replace('/', File.separatorChar), dataName); + + // Check if the file exists before attempting to load + if (!Files.exists(loadFilePath)) { + logger.log(Level.INFO, "Save game file not found: {0}", loadFilePath.toAbsolutePath()); return null; } - is = new GZIPInputStream(new BufferedInputStream(new FileInputStream(file))); - BinaryImporter imp = BinaryImporter.getInstance(); - if (manager != null) { - imp.setAssetManager(manager); - } - sav = imp.load(is); - Logger.getLogger(SaveGame.class.getName()).log(Level.FINE, "Loading data from: {0}", file.getAbsolutePath()); - } catch (IOException ex) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error loading data: {0}", ex); - ex.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ex) { - Logger.getLogger(SaveGame.class.getName()).log(Level.SEVERE, "Error loading data: {0}", ex); - ex.printStackTrace(); + + try (InputStream is = Files.newInputStream(loadFilePath); + GZIPInputStream gzip = new GZIPInputStream(new BufferedInputStream(is))) { + + BinaryImporter importer = BinaryImporter.getInstance(); + if (assetManager != null) { + importer.setAssetManager(assetManager); } + Savable savable = importer.load(gzip); + logger.log(Level.INFO, "Successfully loaded data from: {0}", loadFilePath.toAbsolutePath()); + return savable; } + } catch (IOException ex) { + logger.log(Level.SEVERE, "Error loading data from gamePath: {0}, dataName: {1}. Exception: {2}", + new Object[]{gamePath, dataName, ex.getMessage()}); + return null; } - return sav; } }