Global Save System #
Videos #
Here is an very extensive video on every detail about the save system:
This is a quick walkthrough of the Save system, a devllog:
Components: #
We have two components. One for the game mode:
- For server side save logic.
- This is the core component.
- On begin play basically is the on load.
- Save Game is the most crucial function

One for the player controller:
- For client side save logic.
- On die
- On pawn possesed
- Create new game
- Load slot

Saveable Interface #
- We use interfaces to automatically save Actor components or Actors on demand.
- To save any actor component, Assign the: BPI_Saveable_Component
- To save any actor component, Assign the: BPI_Saveable_Component

-
- To save any actor, assign the BPI_Saveable_Actor:
- To save any actor, assign the BPI_Saveable_Actor:

- Important note for Player Saving:
- The BPI_Saveable_Actor should not be assigned to players. Players need to be spawned and assinged via the game mode. This requires different functionality. More on this later.
- How does this interface work?
- The save system automatically saves all actors which have the BPI_Saveable_Actor interface.
- On these actors, all components that have the BPI_Saveable_Component are also saved.
- The save system automatically saves all actors which have the BPI_Saveable_Actor interface.
- Custom load and save functionality
- The interface provides an On Save and On Load event for both actors and components
- In many cases, you would want to execute some custom code when an actor is loaded or saved.
- As an example, look at the Attached actors section.
- The actors interface includes 2 more functions (check next sections for the details),
- Is Streamed From Level
- Is Spawned From Save.
- To get access to the same variables in any actor component, simply get owner and do a check:

Is Spawned From Save. #
- When an actor is spawned from save, there are many use cases that you want to execute custom code, or bypass existing code.
- As an example:
- In the attribute manager, on begin play > we initialze the state to Healthy (in a fresh game). However, if we do load from save, we just want to use the existing state.

- Another example:
- In the inventory system, we spawn an initial inventory. However, we only need to do that when the actor was not spawned from save.

Is Streamed From Level #
- The state: Is streamed from level bascically determines:
- On true: if an actor was already placed in the world (e.g. by a level desinger, placing a lootchest in editor, etc)
- On false: it was placed in the world during gameplay (e.g. dropping a pickip item, placing a buildable, etc)
- We use the Is Streamed from level variable in the BP_Save_Manager_World_Proxy
BP_Save_Manager_World_Proxy #
- The purpose of this actor is to manage destroy events of saveable actors which where placed manually in the world (so not on runtime).
- When such a saveable actor is destroyed, we do not want to spawn it anymore.
- E.g. if we chop down a tree, we want that tree to be gone when we load the game. Therefore we need to know which actors where destroyed in the game so we can destroy them on load.
- When such a saveable actor is destroyed, we do not want to spawn it anymore.
- Some crucial knowledge to understand the purpose of this:
- On begin play, we spawn actors in the world in two different ways:
- Level actors (stored in the map itself, placed in editor)
- The level actors are always spawned since it is stored in the map
- However, we destroyed a couple of actors in the world during gameplay, so want to destroy a couple of those things.
- The level actors are always spawned since it is stored in the map
- Runtime actors (placed during gameplay e.g. a buildable) (stored in our save object, and on load > spawn those actors in the world)
- The runtime actors from our save game object, we always want to spawn.
- If we destroy that actor during gameplay and save the game later, it is not in our save game object anymore so it is cleaned up
- The runtime actors from our save game object, we always want to spawn.
- Level actors (stored in the map itself, placed in editor)
- On begin play, we spawn actors in the world in two different ways:
- So what does the world proxy do?
- when an saveable actor is destroyed, it needs to check if the actor was streamed from level
- On true:
- Add it to the destroyed level actors
- So we can destroy the initial placed (streamed) actors on begin play)
- Add it to the destroyed level actors
- On false:
- Nothing
- On true:
- when an saveable actor is destroyed, it needs to check if the actor was streamed from level
- Auto set Streamed from Level
- On any actor that you want to check if it was streamed from level, we set the following code.
- Our Is Streamed From level function auto determines if it was streamed from level, and we store that variable manually.

-
- We return that variable in the interface call:

- Destroy level actors
- We destroy the level actors on begin play (load) of the save game

Load #
- In the gamemode_savemanager the begin play is basically peforming the “on load’ logic.
- The function try set current save name is key here.
- It gets the game instance, and checks which slot we are currently loading.
- This also means that the game instance is determining what we load. We use the game instance to set the slot and travel between world. E.g. in the main menu we click on load slot with name xyz > it stores xyz in the game instance > opens level > on begin play of level get game instance > which slot? > xyz > load xyz
- It gets the game instance, and checks which slot we are currently loading.
- The function try set current save name is key here.

Attached Actors #
- Attached actors are hard to save. The reason is because in unreal a lot of logic happens with attached actors think of: What kind of attachement type? snap to target? To which actor should this attach to? What if that actor does not exist yet? Etc. etc. It is so complex that for loading and saving attached actors, custom functionality needs to be implemented.
- Lets provide an example on how to save attached actors:
- In the attribute manager, we attach “State Effects” as an object to the character.
- Instead of saving the attached objects via the interface, we manually save them.
- On event save of the attribute manager, we store the state effects
- On event load of the attribute manager, we get these stored state effects and manually spawn them an attach them to the player
- We also do the same for Equipment (those are attached actors to the player)
- In the attribute manager, we attach “State Effects” as an object to the character.

Save Game #
When we want to save the game, we need to call the function: Save Game on the Game Mode Save Manager

- Override save name
- Leave this one empty
- If it is not empty, it will make a new slot.
- This is usefull for when making a manual new save game.
- The save game functions works as follows:
- It stores ALL players
- It gets ALL actors in the world that have BPI_Saveable_Actor
- and executes the custom On Save logic attached to that actor
- On all the actors, get gets all components that have BPI_Saveable_Component
- and executes the custom On Save logic attached to that component
- It stores all the data in a save object (unreal save object)
Flag All Save Game Properties #
- This is a core function to “flag” the save game checkbox for properties.
- This is what we mean with flagging a save game property. The image shows a manual flag of the checkbox:
- This is what we mean with flagging a save game property. The image shows a manual flag of the checkbox:

-
- All properties in blueprints contain a save game flag. To use this flag, a c++ plugin is included with this system that has functions for converting all properties on an object that have the save game flag to a byte array and back. It also provides a function for making sure all properties that are marked as save game, are fully saved, as engine structs like datatable rows arent marked as savegame by default.
- There are two use cases to use this function. To understand these use cases it is critical to know that child properties of a flagged property are not auto flagged. An example:
- If we flag a boolean, it is simply flagged.
- If we flag a boolean, it is simply flagged.

-
- If we flag a struct, all the child properties are nog flagged.:
- If we flag a struct, all the child properties are nog flagged.:

-
- All the child properties need to be manually flagged too. This can be very devious:
- All the child properties need to be manually flagged too. This can be very devious:

-
- And now the critical part: Engine properties are not able to be flagged manually. E.g. if you have a data table row handle in a structure, we are not able to flag that ourselves. This means that the selected row cannot be saved:
- And now the critical part: Engine properties are not able to be flagged manually. E.g. if you have a data table row handle in a structure, we are not able to flag that ourselves. This means that the selected row cannot be saved:

- Because of the above, we have two use cases for this function:
- To flag properties that we are not able to flag ourselves. E.g. Engine properties.
- To auto flag all child properties, e.g. a large structure for items where we do not want to manually flag hundreds of properties
Spawn actor from save logic #
When we spawn an actor from the save, we basically always follows the same order (based on the logic described her https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-actor-lifecycle :
- spawn actor deferred.
- Spawns an actor but is basically a placeholder. No begin play or begin play or construction scripts are being run
- Flag all save game properties
- Unreal Engine does seem to keep save game flags only in memory but not between editor sessions. So we need to reflag all the save game properties so we know what to load.
- Load Object
- This converts the byte array to all property values of that specific object and sets all the properties.
- Finish Spawning actor
- This runs the construction script and begin play of the spawned actor. We can only do this when the data is loaded.

BP_SaveGame #
This is our save game object that we use to store all the data in. It also hold the crucial functions to save and load the actors and players
- Actor Records
- Component Records (Components that are assinged to actors)
- Player records (specific states of players, location, player identifier, etc)
- Destroyed level actors (stored from the BP_Save_Manager_world_Proxy)
- The temp actors are used to temp store data so we know which components are linked

The core functions of the BP_SaveGame are:
- Player
- Spawn And Load Player
- Save Player
- Save
- Save Actor With Components
- Load
- Load All Actors with components
Save Player vs Save Game #
- Save Game saves the whole game. This is expensive.
- Save game also saves ALL players
- However, in some games you want to only save a specific player instead of the whole game. E.g. on a dedicated server.
- So on log-out > Save the player
- This is not implemented. Ideas to implement are:
- If on the on-logout no actor is available, try to implement something like this in a UI. E.g. on quit game > Execute save player
- This is not implemented. Ideas to implement are:
- So on log-out > Save the player
Saving Player and Spawn and load player #
- Saving players and Spawning players need different logic than saving actors.
- The core reason is that players also have player controller components. These need to be initialzed seperately.
- Players also have player identifiers which is unique.
Spawn Player/ On player login #
- On login > call the player login event

- This calls the try spawn saved player

- This spawns the actual player and possesses the pawn

Singleplayer vs Co-Op vs Dedicated server game #
- Save logic differs per type of game
- Singeplayer
- The player acts as the server and is always authoritive to save/load
- Co-op
- This will mean that the server will save all the level and player data and that when a client joins back in, it loads that data. This is meant for games like the forest.
- Clients cannot manually save.
- Dedicated server
- We've also got a dedicated server example. This is inspired by games like Rust. This means that players log on and off and the data for them will be saved. Also players will leave a body that can be killed.
- Clients cannot save themselves. The server is fully auhoritive.
- This can be started with the .bat file that is provided with this example. That is because you want to be able to log in and out.
TransferPlayerToLevel #
When a player is traveling between maps (think of exiting a cave to the main map), we want to:
- Save the player info (e.g. health, ammo, etc)
- Open the map
- Load the player info back (health, ammo etc)
Todo: #
Function library #
We also have a BFL_SaveGame
- Some utility functions like:
- Get Current Save Slot
- Create Save Slot
- Get Last Save
- Get Save Slot
- Get Save Slots
- Remove Missing Slots
- Save Slots
- Get Save Slots From Level
BP_Sleeping_Character #
When you play in a co-op game, and a player disconnects. We do not want them to disappear directly. We have a “sleeping character” as a placeholder with the info of the player while he is not connected.
BP_Overlap_Save_Box #
In singeplayer games, you want to force save the game when the player has reached a certain area. Therefore we made an overlap box which saves the game.
BP_Save_Slots #
This only tracks the save game: e.g. name, which save file etc.
BP_GameInstance_Save #
When loading a level, and we click on: Load slot x, we want to transfer to that level, however, on load of that level, we want to load the actual info again. Therefore we need to know which slot we clicked on load so we can load it back in.
Settings #
We've implemented multiple settings in the gamemode component. These will help you tweak the functionality of the save system.
To test multiple saves out, you can change the 'Single Save Per Map' setting to off. This will create a new save slot each time you play the game. This way you'll see multiple save slots show up.
Functions #
- Load Object
- Save Object
- Load Actor
- Spawn Actor Deferred
- Finish Spawning Actor
- Is Streamed from Level
Saving definitions #
- Save Slots
- A save slot or single group, is basically a single slot, that is linked to a full game. E.g. in Hogwards, when you create a characther, that char can have multiple manual saves/auto saves.
- The save slots, is a reference to all the available slots.
- This characther cannot be used in another save slot.
- The reason for this, is so that when multiple players, or multiple “games” or “characthers” are created on the same pc, the saves (manual and auto) are linked to the specific “group” or “slot”.
- Therefore, A save slot is a collection of a slot name and linked to an array of manual and auto saves.
- This can also be seen as a “save slot” wherein the slot is the player/character/game/session
- Save Slot
- Slot Name
- Manual Save
- This is called a: “save”
- Auto Save
- This is called a: “save”
