Memorycard.js
Save user progress in javascript-based games with slots and objects.
Install / Use
/learn @diablordz99/Memorycard.jsREADME
Content Table
- Installation
- Advantages of Usage
- Available Platforms
- Examples
- Documentation
- Write vs. Save
- Automatic vs. Manual
- Security Practices
- How to Set Up a Cloud-Save System
- Support
Installation
Node.js (Electron/Backend-Servers)
npm i memorycard.js --save
Browser CDN
https://cdn.jsdelivr.net/npm/memorycard.js/dist/memorycard.min.js
Self-Host / Download
Go to dist folder, download one of the javascript files and save it in your project folder then just import it via html: <script src="./memorycard.min.js"></script> or node.js: require( './memorycard.js' )
Advantages
You can save time in your game development by installing this package in your current game. Don't worry about platforms compatibility or organization, With this tool you can easily access to a safe user-progress data storage. Finally, you will get an object with different slots for those games that enable multiple progress save per user (But you can also use this package to save one slot only). <br/><br/>
Available Platforms
This tool was designed to be compatible with all useful javascript frameworks such as Electron and Cordova. Basically, the package encrypts the data and then saves depending on the platform where the game or application is currently running.
| Electron/Node.js | Browsers | Cordova | Cloud/Server | | :--------------: | :----------: | :----------: | :------------: | | OS Drive | LocalStorage | LocalStorage | Encrypted Data |
If you want to save the data in a cloud storage, you can easily request the encrypted data instead of save it by installing memorycard.js in you server (safer) or in the client-side. Also you can use Strict Mode and Card Keys to improve the security.
Electron Tip: Don't forget to enable nodeIntegration or you will get a error saying something like: "require" is not a function. <br/>
Examples
As programmer, I prefer to look at examples to understand how a package works. So I make a few examples with comments in the examples folder. <br/>
Documentation
Reference Object
Depending on the current platform, you can access to the package by importing the module or calling the default object created by the script.
Note: In Electron you can access to the MemoryCard with both options, but I recommend to access via Global Object if you are developing a cross-platform game.
Node.js (Backend Servers/Electron)
const MemoryCard = require( 'memorycard.js' ) ;
Global Object (Cordova/Browsers/Electron)
var mcard = window.MemoryCard ;
var mcard = window.MCARD ;
// or use one of it directly
MemoryCard.write( ) ;
MCARD.load( ) ;
<br/>
Configuration
The configuration is optional, but helps you to have more control about your MemoryCard use flow. Once you have the reference of the MemoryCard Object, just call the config( ) method to set your preferences. You will not able to change the configuration once the selected MemoryCard is loaded or created, so if you create a MemoryCard with 4 slots and a Card Key, you can't change that properties, just edit slots information to save user-progress.
MemoryCard.config( config_object ) ;
Parameters
config_objectObjectfileString - Default:{EXECUTABLE_PATH}/memorycard.data| Set the file where the slots and its data will be writed and saved.slotsNumber - Default: 4 | Number of slots that will be available in the MemoryCard.keyString - Default: null | Increase security by setting up a unique key for every new card created. See Card Keys for mor information.strict_modeBoolean - Default: false | Set strict mode enabled. See Strict Mode section for more information.templateObject - Default: null | Set a template for every new slot writed in the MemoryCard. When strict_mode is disabled all missing properties in the new slot will be replaced with the template properties as default. But if strict_mode is enabled all new slots must match with the template even the properties types to allow the save action.tempBoolean - Default: false | Recommended for cloud-based storage. This option allows to create temporary MemoryCard files that will be deleted automatically by the OS or Browser by setting/tmp/random-filename.datain Node.js and switching LocalStorage to SessionStorage in Browsers.
Why set a slots limit?
It just helps to organize the data and avoids a huge disk usage (Web-LocalStorage only support 5MB per website). Also, a small number of slots can help to create a nice "save screen" for your game, just like many retro games.
Card Keys
Every time you create a MemoryCard (Automatically created when the package doesn't find the specified file or a record in the LocalStorage), the package will set the pre-configured key as MemoryCard encryption-key and will be locked (not-changable).
Tip: Create a unique key based on the user-id (recommended) or also by requesting a unique device-id (not recommended for cloud-save-systems) with tools like machine-id npm package.
How it works?:
Create New MemoryCard -> Set the Pre-Configured Key -> Check if the Pre-configured key matchs with the MemoryCard file every game init -> Allow write/read if key matches correctly.
This feature have two objectives:
- Increase write secutiry by requesting the card key every time the game starts and load the MemoryCard to get user-progress.
- Avoid a progress-hack by replacing the actual MemoryCard file with someone downloaded in a forum. Go to examples section to get a example about Cards Keys implementation.
Strict Mode
The strict mode helps you to keep your saved slots as clean as possible, so it will add missing properties, delete extra-defined properties and fixing the types. This mode can be useful to avoid corrupted data slots, but also could be dangerous, so just try to be careful.
Here an example of strict_mode data output:
// TEMPLATE-SLOT
var $template = {
username : "Diablo Luna" ,
rupees : 8 ,
trophies : "9,2,5,6" ,
tips : true ,
medallions : [ 2, 3 ] ,
inventory : {
nuts : 4
} ,
}
// THE DATA ALREADY SAVED IN THE SLOT
var $slot = {
username : "Diablo Luna" ,
rupees : 0 ,
difficult : "cow"
}
// NEW DATA TO SAVE
var $new = {
username : "Diablo Luna" ,
rupees : "8" ,
trophies : [ 4, 5, 7 ] ,
tips : false ,
wooops : true ,
medallions : 4 ,
inventory : {
nuts : "8"
}
}
// ==== STEPS ================================================ [v]
// $new will be compared with the already saved $slot (if exists)
// and all missed properties will be added to the $new.
// [then]
// $new will be compared with the $template and will be fixed
// by adding missing properties, removing extra-properties in $new
// and fixing types in the properties of $new.
// [then]
// $new will be saved, replacing the $slot in the next save.
// ===============================================================
// DATA SAVED [OUTPUT]
{
username : "Diablo Luna" ,
rupees : 8 ,
trophies : "4,5,7" ,
tips : false ,
medallions : [ 4 ] ,
inventory : null
}
/*
* RUPEES has set to 8 number because the origin
