-
Notifications
You must be signed in to change notification settings - Fork 0
SaveManager (en)
SaveManager is a ScriptableObject responsible for providing the Save() and Load() public methods, which save and load data to the SaveContainer.
Before using the system, it's necessary to perform a setup and configure it according to your preferences.
- Save File Name: Defines the name to be used in the save file name. By default, it is "save".
- Save File Extension: Defines the extension to be used in the save file name. By default, it is "sav".
- Hash File Name: Defines the name to be used in the hash file name. By default, it is "hash".
- Hash File Extension: Defines the extension to be used in the save file name. By default, it is "sav".
- Current Slot: Current save slot. By default, the first slot is selected.
- Save Path: Location where the save will be saved, with options including Persistent Data Path and Data Path. By default, Persistent Data Path is selected.
- Protect Save: Enables or disables save protection. By default, it is true.
- Shuffle Seed: Seed to be used in byte shuffling, any 32-bit integer. By default, it is 1.
- Hash Salt: "Salt" to be added to the save hash, can be any text. By default, it is "salt423".
- Save Container: Reference to a Save Container.
SaveManager contains some Action-type events, allowing you to assign methods that will be called when certain events occur.
- OnStartSave: Called when saving starts.
- OnEndSave: Called when saving finishes, whether successful or not.
- OnSaveSuccess: Called when successfully saved.
- OnSaveError<Exception>: Called when an error occurs during the save attempt, passing an Exception as a parameter.
- OnStartLoad: Called when loading the save starts.
- OnEndLoad: Called when loading the save finishes, whether successful or not.
- OnLoadSuccess: Called when successfully loaded.
- OnLoadError<Exception>: Called when an error occurs during the load attempt, passing an Exception as a parameter.
When the Save() method is called from another script, it will begin by invoking the OnStartSave Action, then checking if the file name or extension provided by you is not empty; if they are, it returns an Exception.
After verification, the data contained in the SaveData class within the SaveContainer will be converted into JSON using the ToJson() method of Unity's JsonUtility class. Then, an instance of a FileStream is created using the path chosen by you and using FileMode.Create.
It will create a new instance of a StreamWriter, passing the previously created FileStream as a parameter, then writing the JSON to the file.
It will create a new instance of a StreamWriter, passing the path of the Hash file as a parameter, then writing the hash of the data along with the "salt" generated by the GetStringHash() method of the SaveIntegrityUtility class.
After the hash is generated and saved, the ShuffleBytes() function of the SaveIntegrityUtility class is called, with the UTF-8 converted data as a parameter and another parameter being the seed defined by you.
After shuffling, a for loop is created to separate the bytes by spaces, then a new instance of BinaryWriter is created, passing the FileStream as a parameter, then writing the separated bytes in binary. Finally, the OnSaveSuccess event is called.
If an error occurs, the catch block will call the OnSaveError event passing the Exception as a parameter.
When the Load() method is called from another script, it will begin by invoking the OnStartLoad Action.
It will instantiate a new StreamReader, passing the save path as a parameter, then it reads the file and stores it in a string.
It will create a new instance of a FileStream, passing the save path as a parameter, and the second parameter being FileMode.Open.
Then a new instance of BinaryReader is created, passing the previously instantiated FileStream as a parameter, and reading the save that was previously saved in binary.
After reading, the bytes that are separated go through a foreach loop where the Split() method is used to get the bytes that were divided by spaces, then incrementing into a list of bytes.
After the bytes are passed to a list of bytes, they are unshuffled with the seed you defined.
The data has been loaded, and then it generates a hash of this loaded data and loads the previous hash using a StreamReader.
The two hashes are compared, and if they are the same, the algorithm loads successfully; if they are not the same or there is no hash, the algorithm returns an Exception and does not allow the save to be loaded.
After this whole process, the FromJson() method of JsonUtility is used to convert the data from JSON to the SaveData class, then assigning the values in the SaveContainer and calling the OnLoadSuccess Action.
If an error occurs, the OnLoadError event is called passing the Exception as a parameter.