//-----------------------------------------------------------------------------
// StorageManager
//
// The static class that manages storage for saving game data.
/**
* The static class that manages storage for saving game data.
*
* @namespace
*/
function StorageManager() {
throw new Error("This is a static class");
}
StorageManager._forageKeys = [];
StorageManager._forageKeysUpdated = false;
/**
* Check if the game is running locally (Nwjs)
*
* @static
* @return {boolean} If game is running locally (mostly means not mobile/web)
*/
StorageManager.isLocalMode = function() {
return Utils.isNwjs();
};
/**
* Save an object
*
* @static
* @param {string} saveName - Name of the save file
* @param {Object} object - The object to save
*/
StorageManager.saveObject = function(saveName, object) {
return this.objectToJson(object)
.then(json => this.jsonToZip(json))
.then(zip => this.saveZip(saveName, zip));
};
/**
* Load a saved object
*
* @static
* @param {string} saveName - Name of the save file to load
*/
StorageManager.loadObject = function(saveName) {
return this.loadZip(saveName)
.then(zip => this.zipToJson(zip))
.then(json => this.jsonToObject(json));
};
/**
* Converts given object to JSON via stringify
*
* @static
* @param {Object} object - Object to convert to JSON string
* @return {Promise} Promise object of the converted JSON
*/
StorageManager.objectToJson = function(object) {
return new Promise((resolve, reject) => {
try {
const json = JsonEx.stringify(object);
resolve(json);
} catch (e) {
reject(e);
}
});
};
/**
* Converts given JSON to object via parsing
*
* @static
* @param {string} json - JSON string to convert to object
* @return {Promise} Promise object of the converted object
*/
StorageManager.jsonToObject = function(json) {
return new Promise((resolve, reject) => {
try {
const object = JsonEx.parse(json);
resolve(object);
} catch (e) {
reject(e);
}
});
};
/**
* Converts given JSON to zip
*
* @static
* @param {string} json - JSON string to convert
* @return {Promise} Promise object of the converted zip
*/
StorageManager.jsonToZip = function(json) {
return new Promise((resolve, reject) => {
try {
const zip = pako.deflate(json, { to: "string", level: 1 });
if (zip.length >= 50000) {
console.warn("Save data is too big.");
}
resolve(zip);
} catch (e) {
reject(e);
}
});
};
/**
* Converts given zip to JSON
*
* @static
* @param {string} zip - ZIP string to convert
* @return {Promise} Promise object of the converted JSON
*/
StorageManager.zipToJson = function(zip) {
return new Promise((resolve, reject) => {
try {
if (zip) {
const json = pako.inflate(zip, { to: "string" });
resolve(json);
} else {
resolve("null");
}
} catch (e) {
reject(e);
}
});
};
/**
* Saves a zip formatted string
*
* @static
* @param {string} saveName - Name of the save file
* @param {string} zip - ZIP string to save
* @return {Promise} Promise object for saving data
*/
StorageManager.saveZip = function(saveName, zip) {
if (this.isLocalMode()) {
return this.saveToLocalFile(saveName, zip);
} else {
return this.saveToForage(saveName, zip);
}
};
/**
* Loads a zip formatted string
*
* @static
* @param {string} saveName - Name of the save file
* @return {Promise} Promise object for loading data
*/
StorageManager.loadZip = function(saveName) {
if (this.isLocalMode()) {
return this.loadFromLocalFile(saveName);
} else {
return this.loadFromForage(saveName);
}
};
/**
* Checks if a save file of the given name exists
*
* @static
* @param {string} saveName - Name of the save file
* @return {boolean} True if file exists, otherwise false
*/
StorageManager.exists = function(saveName) {
if (this.isLocalMode()) {
return this.localFileExists(saveName);
} else {
return this.forageExists(saveName);
}
};
/**
* Removes a given save file
*
* @static
* @param {string} saveName - Name of the save file
* @return {Promise} Promise object for removing a save file
*/
StorageManager.remove = function(saveName) {
if (this.isLocalMode()) {
return this.removeLocalFile(saveName);
} else {
return this.removeForage(saveName);
}
};
/**
* Saves a file to the local environment
*
* @static
* @param {string} saveName - Name of the save file
* @param {string} zip - Zip string to save
* @return {Promise} Promise object for saving the file
*/
StorageManager.saveToLocalFile = function(saveName, zip) {
const dirPath = this.fileDirectoryPath();
const filePath = this.filePath(saveName);
const backupFilePath = filePath + "_";
return new Promise((resolve, reject) => {
this.fsMkdir(dirPath);
this.fsUnlink(backupFilePath);
this.fsRename(filePath, backupFilePath);
try {
this.fsWriteFile(filePath, zip);
this.fsUnlink(backupFilePath);
resolve();
} catch (e) {
try {
this.fsUnlink(filePath);
this.fsRename(backupFilePath, filePath);
} catch (e2) {
//
}
reject(e);
}
});
};
/**
* Loads a file from the local environment
*
* @static
* @param {string} saveName - Name of the save file
* @return {Promise} Promise object for the data in the file
*/
StorageManager.loadFromLocalFile = function(saveName) {
const filePath = this.filePath(saveName);
return new Promise((resolve, reject) => {
const data = this.fsReadFile(filePath);
if (data) {
resolve(data);
} else {
reject(new Error("Savefile not found"));
}
});
};
/**
* Checks if a save file of the given name exists locally
*
* @static
* @param {string} saveName - Name of the save file
* @return {boolean} True if file exists, otherwise false
*/
StorageManager.localFileExists = function(saveName) {
const fs = require("fs");
return fs.existsSync(this.filePath(saveName));
};
/**
* Removes a local save file
*
* @static
* @param {string} saveName - Name of the save file
*/
StorageManager.removeLocalFile = function(saveName) {
this.fsUnlink(this.filePath(saveName));
};
/**
* Saves data to browser storage
*
* @static
* @param {string} saveName - Name of the save key
* @param {string} zip - Zip string to save
* @return {Promise} Promise object for saving
*/
StorageManager.saveToForage = function(saveName, zip) {
const key = this.forageKey(saveName);
const testKey = this.forageTestKey();
setTimeout(() => localforage.removeItem(testKey));
return localforage
.setItem(testKey, zip)
.then(() => localforage.setItem(key, zip))
.then(() => this.updateForageKeys());
};
/**
* Loads data from browser storage
*
* @static
* @param {string} saveName - Name of the save key
* @return {Promise} Promise object for loading data
*/
StorageManager.loadFromForage = function(saveName) {
const key = this.forageKey(saveName);
return localforage.getItem(key);
};
/**
* Checks if a save key exists in browser storage
*
* @static
* @param {string} saveName - Name of the save key
* @return {boolean} True if key exists, else false
*/
StorageManager.forageExists = function(saveName) {
const key = this.forageKey(saveName);
return this._forageKeys.includes(key);
};
/**
* Removes save data from browser storage
*
* @static
* @param {string} saveName - Name of the save key
*/
StorageManager.removeForage = function(saveName) {
const key = this.forageKey(saveName);
return localforage.removeItem(key).then(() => this.updateForageKeys());
};
/**
* Update localforage save keys for browser storage
*
* @static
*/
StorageManager.updateForageKeys = function() {
this._forageKeysUpdated = false;
return localforage.keys().then(keys => {
this._forageKeys = keys;
this._forageKeysUpdated = true;
return 0;
});
};
/**
* Checks if localforage keys have been updated
*
* @static
* @return {boolean} True if keys are updated
*/
StorageManager.forageKeysUpdated = function() {
return this._forageKeysUpdated;
};
/**
* Makes a directory (synchronously)
*
* @static
* @param {string} path - The path to make the directory
*/
StorageManager.fsMkdir = function(path) {
const fs = require("fs");
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
};
/**
* Renames a file (synchronously)
*
* @static
* @param {string} oldPath - The old path where the file existed
* @param {string} newPath - The new path to change the file to
*/
StorageManager.fsRename = function(oldPath, newPath) {
const fs = require("fs");
if (fs.existsSync(oldPath)) {
fs.renameSync(oldPath, newPath);
}
};
/**
* Deletes a file (synchronously)
*
* @static
* @param {string} path - The path to the file
*/
StorageManager.fsUnlink = function(path) {
const fs = require("fs");
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
};
/**
* Reads a file (synchronously)
*
* @static
* @param {string} path - The path to the file
* @return {string} The contents of the file
*/
StorageManager.fsReadFile = function(path) {
const fs = require("fs");
if (fs.existsSync(path)) {
return fs.readFileSync(path, { encoding: "utf8" });
} else {
return null;
}
};
/**
* Writes a file (synchronously)
*
* @static
* @param {string} path - The path to the file
* @param {string} data - The data to write
*/
StorageManager.fsWriteFile = function(path, data) {
const fs = require("fs");
fs.writeFileSync(path, data);
};
/**
* Gets the path to the save file directory
*
* @static
* @return {string} The path to the save file directory
*/
StorageManager.fileDirectoryPath = function() {
const path = require("path");
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
};
/**
* Gets the path to the save file of the given name
*
* @static
* @param {string} saveName - The name of the save file
* @return {string} The path to the save file
*/
StorageManager.filePath = function(saveName) {
const dir = this.fileDirectoryPath();
return dir + saveName + ".rmmzsave";
};
/**
* Gets the path to the save data of the given name
*
* @static
* @param {string} saveName - The name of the save key
* @return {string} The forage key for the given save name
*/
StorageManager.forageKey = function(saveName) {
const gameId = $dataSystem.advanced.gameId;
return "rmmzsave." + gameId + "." + saveName;
};
/**
* A test key for localforage
*
* @static
* @return {string} The forage key for the test data
*/
StorageManager.forageTestKey = function() {
return "rmmzsave.test";
};