Set the save game class to use your derived class that is extended will all the extra data your game needs to save.Â
1. To save data using the save system, you'll need to make a child class that derives from the KSaveGame class. The base class is already set up to save data for systems within the KGameFramework. In the Content Browser, right click and select "Blueprint Class". Then, for "Pick Parent Class" search "All Classes" for KSaveGame. Select the class to create a new Blueprint.
2a. If you intend to add save and load functionality to a class, you'll need to create a struct to hold data specific to the class. You can create a struct by right clicking in the Content Browser and selecting Blueprint > Struct.
2b. Any variables you add to your save class will be saved when the SaveManagerSubsystem saves the game. If you only need to save one instance of a variable, you can add it straight to the save class. You have successfully extended the save class for simple implementations. To update your new variable you can get the SaveManagerSubsystem, call GetSaveData(), cast to your derived class and set the variable directly. Skip to the last step.
3. Within this new struct, add variables for whatever data you want your class to store.
4. Now return to your KSaveGame Blueprint. Add a map variable to the class where the key type is FGuid and the value type is your new struct. This map will allow any number of instances of your class to save and load unique data for that instance.
5. Finally, assign your new save class to Project Settings > KGameFramework > Save Class so the system will instantiated your class.
You will need a unique SaveAgent for each class you want to add save and load functionality to.
2. Open the SaveAgent Blueprint. To configure the agent to be used with your class you'll be overriding 2 built-in functions: SaveData() and LoadData(). To do this, on the left side of the Blueprint editor locate "Interfaces". Double-clicking either function will relocate it to the "Functions" section and open the function for editing in a tab.
2. Starting with the SaveData() function, drag off the "Save Game" output pin on the purple function node and cast the object reference to your custom KSaveGame class. Connect the execution pin for the cast node as well.
3. Now drag off the blue output pin of the cast node. This is now recognized as a reference to your KSaveGame class and you can access any variables. You can now set all relevant variables for saving your class.
3a. Note that if you are storing your save data for a class in a map on the KSaveGame, you'll need to check if an entry already exists and if not, create a new entry. The code below shows how to set this up.
5. Lastly, right click the purple function node and select "Add Call to Parent Function". Feed the "Save Game" output pin from the first purple function pin you started with into the input pin of this new orange node. The base SaveAgent class has default implementation that we want to always make sure to call. This is also true in any case when you are implementing additional save functionality in a class derived from a parent class that already saves. Your final function will look something like this.
6. For LoadData() you essentially want to do the same steps as you did for SaveData(), put pass the data from the KSaveGame to your GetOwner() class instead.
7. When you have completed setting up the SaveAgent attach it as a component in the class it was made for and it is ready to go.
The save system uses profiles each with their own save slots to store and access saved data. Management of these profiles and slots are handled by the save system and only require UI be developed to interact with it. All functions necessary can be found on the SaveManagerSubsystem. Here is an example of how to setup your UI.
1. On start up, the SaveManagerSubsystem will attempt to load a save file that holds an array of all profiles the game. If no save file is found, the save system will automatically create an empty one. Each profile stores an array of save slot data. When making a UI for the save system, the functions you'll be calling are essentially working with this data.
2. Your save system UI will need to provide a way for users to create new profiles. Call the NewProfile() function to do this. If the profile name already exists, the function will return "false" and not create a new profile.
3. Next, you UI needs to display all profiles. The GetAllProfileNames() function is provided for this purpose. Make sure you refresh the UI when new profiles are added or deleted.
You'll need to store the profile names as well for future reference. When selecting a profile, you'll probably be using buttons, so for simplicity you could assign the profile name to the button text. Each button when clicked should call the GetProfile() function and use the profile name to retreive the profile data. That profile data can then be input into the SetProfile() function, thereby making it the active save profile within the save system.
4. When clicking a profile button, you'll probably want to display all the save slots within the profile. To do this, call GetProfile() and access the "saveSlots" array. For each entry, you can create and display a button. This button when click, should call GetSaveSlot() and feed it into SetSaveSlot() to set the active save slot.
5. At this point, you can call the LoadGame() function to load a KSaveGame to the SaveManagerSubsystem's active save. If SetProfile() or SetSaveSlot() have not been set then the save system will not successfully load a KSaveGame. If they have been correctly set, the save system will load the save file from disk and set it as the active save.
NOTE: The save system does not automatically handle if there is no active profile. However, if there is no active save slot set then upon calling LoadGame() a new empty KSaveGame will be loaded for use.
6. Once an active save is loaded, data can now be updated and read on the KSaveGame at any time. SaveAgents will automatically communicate with the active save and calling GetSaveData() returns this reference. All data at this point is runtime data.
7. In the flow of your game, once a level is loaded, you should make sure to call the LoadSaveAgents() function to synchronously load all SaveAgents within a level.
8. When it comes time to save, simply call the SaveGame() or AutosaveGame() functions which will write the data on your active save to disk.