Make a handler
- In the Content Browser, Add > Blueprint Class > All Classes > Rolly Save Handler.
- Add a variable for each value to keep, and tick SaveGame on it (its Details, the Variable section’s advanced options).
- Add Event Gather and set the variables from the game, such as Get Actor Of Class (your sky) > its time of day > Set TimeOfDay.
- Add Event Apply and set the game from the variables.
- In Project Settings > Plugins > Rolly Save > Save Handlers, add the class to Global Handlers.
World nodes such as Get Actor Of Class and Get Game Mode work in a handler: they use the world of the game being saved or loaded.
Attach a handler to actors
For state of each actor of a kind, such as a lamp’s flicker phase, attach the handler instead of listing it in Global Handlers:
- In a Save Rule (or an actor’s Rolly Save component), under Handlers, add an entry, click its class button and pick your handler under Your Handlers, whose search box finds it by name.
- Expand the entry and set its settings: the handler’s variables that are editable, such as a Rate. Each rule can attach the class with settings of its own.
- In Event Gather and Event Apply, Get Target Actor gives the actor the handler saves.
Each matched actor gets its own copy of the entry, saved after the actor’s components. A class several rules or the component attach is attached once, with the settings of the source that applies last; Removed Handlers drops a class an earlier source attaches. An actor with an attached handler saves under With Saved State even without SaveGame variables.
Apply Timing works as for Global Handlers, with one more value: When Asked runs Apply once your game calls Apply Saved Values for the actor (see Choose what saves). An attached handler saves with its actor, so its Group is not used. A record of a class no rule attaches any more is kept, not applied, and written back while the actor saves, so attaching the class again brings it back.
Use Rolly Save’s engine state handlers
For dynamic materials, timelines, Level Sequences, montages and sounds, attach Rolly Save’s own handlers instead of making one: Material Parameters, Timelines, Level Sequence, Montages and Audio (see Save materials, timelines, sequences, montages and sounds). For AI, attach Blackboard and StateTree (see Save Blackboards and StateTrees). They attach to actors only, so Global Handlers does not offer them.
When Gather and Apply run
- Gather runs during each save, inside the save call, on the server or in a standalone game. Clients run no handlers.
- Apply runs during each load once every saved object has its values. Apply Timing, in the handler’s Class Defaults, picks when in a load that opens the saved map:
| Apply Timing | Apply runs | Use it when |
|---|---|---|
| Before Begin Play (default) | With the other saved values, before any actor’s Begin Play | The game reads the state in Begin Play, such as a door that opens if a value is set |
| After Begin Play | For an attached handler, once its own actor’s Begin Play ran, also in a level that streams in; for a Global Handler, once every actor’s Begin Play ran, before On Load Finished | The actor you restore sets itself up in its Begin Play and would overwrite what Apply set |
| When Asked | For an attached handler, once your game calls Apply Saved Values for its actor; a Global Handler applies After Begin Play | The actor sets itself up after Begin Play |
A load with Keep Current Map runs every handler’s Apply at once, with any timing.
What a handler keeps
- Group, in the handler’s Class Defaults, puts it in a group that part saves and part loads take, such as
Chapter2(see Save and load parts of the game); empty saves it with the world. - Each save and each load makes a new instance of each handler. Variables without SaveGame start at their defaults every time, so keep nothing in them from one event to the next.
- While an attached handler’s Apply waits, for its Apply Timing, for Apply Saved Values or because it cannot apply yet, saves write its loaded record back, so a save made meanwhile keeps the loaded values.
- Apply runs only when the loaded save holds a record of that handler. A handler added to Global Handlers after a save has none in it, so its Apply does not run for that save; neither does Apply of a load that failed.
- A handler removed from Global Handlers keeps its saved state: the next save writes it back, so adding the handler again finds it. Clear Loaded Game drops it.
- A handler saves under the path of its class. After renaming or moving the Blueprint, add
+ClassRedirectsor+ObjectRedirectswith the old and new path of its class, which ends in_C(see Rename saved data without losing saves); without it, saves made before the rename do not run its Apply.
What the editor tells you
| Message | Where | Fix |
|---|---|---|
| The handler has no variable with SaveGame ticked, so it saves nothing | Compiler Results on Compile, Data Validation, and once in the game | Tick SaveGame on each variable that Gather sets |
| Gather sets a variable that does not have SaveGame ticked | Compiler Results on Compile | Tick SaveGame on it, or stop setting it in Gather. Only Set nodes that Event Gather reaches through exec wires in the same graph are checked, not those in functions it calls |
| Global Handlers lists an entry that is empty, cannot be loaded or is abstract, or one class more than once | Project Settings’ Data Validation, and once as the game starts for entries that do not save | Pick the class again, or remove the entry |
| A Global Handler has Apply Timing When Asked (WhenAskedGlobal) | Project Settings’ Data Validation, and once as the game starts | Attach it in a Save Rule or Rolly Save component, or pick another Apply Timing |
| A rule or component attaches a class twice (DuplicateClass), or a handler whose Group goes unused (GroupIgnored) | Data Validation | Keep one entry; clear Group or list the handler in Global Handlers |
| An attached handler’s save ID would pass 1,024 characters (IdTooLong) | Once in the game, naming the actor | Shorten the handler’s folder path, or the actor’s name or Custom Save ID |
| Global Handlers lists an engine state handler, which saves the actor it is attached to (GlobalNotAllowed) | Project Settings’ Data Validation, and once as the game starts; the handler is skipped | Attach it in a Save Rule or Rolly Save component |
| An engine state handler has Apply Timing Before Begin Play, which it does not offer (TimingNotOffered) | Data Validation of the rule or component; it applies After Begin Play | Pick After Begin Play or When Asked |
| An entry of an engine state handler’s Components is empty, cannot be loaded, is of another kind of component or is listed twice (BadEntry) | Data Validation of the rule or component; the entry is ignored | Pick the class again, or remove the entry |
| An entry of the Blackboard handler’s Keys or Not Saved Keys is empty, is SelfActor, is listed twice, or is in both lists (BadEntry) | Data Validation of the rule or component; the entry is ignored | Remove the entry, or keep it in one of the two lists |
Cooking
Every class in Global Handlers is cooked into every packaged build, also when no map refers to it. A listed class that does not exist gives a cook warning naming it.
From C++
Subclass URollySaveHandler (Handler/RollySaveHandler.h), give it UPROPERTY(SaveGame) members and override Gather_Implementation and Apply_Implementation. List the class in Global Handlers as for a Blueprint, or attach it in a rule’s or component’s Handlers; GetTargetActor() gives an attached instance its actor.
C++ handlers can also override:
CaptureState, called in place of Gather during a save:Write(the default) runs Gather and writes the variables;Nothingwrites no record and drops the loaded one, such as for an actor whose state is at its design;Keepwrites the loaded record back, such as when the state cannot be read now.WouldWrite: whether the handler makes its actor save when nothing else of the actor saves; true by default.CanApplyNow: false keeps the loaded values waiting while what Apply restores is not there yet. CallURollySaveWorldSubsystem::RetryPendingHandlersfor the actor once it is; Apply then runs once. A When Asked handler that could not apply when Apply Saved Values asked applies at that call too.OffersApplyTiming: whether the handler can apply at an Apply Timing; one it does not offer applies After Begin Play, and the rule editor shows it disabled.GetHandlerName: the words messages use for the class.
#include "Handler/RollySaveHandler.h"
UCLASS()
class UMyWeatherHandler : public URollySaveHandler
{
GENERATED_BODY()
public:
UMyWeatherHandler()
{
ApplyTiming = ERollySaveApplyTiming::AfterBeginPlay; // the weather actor resets itself in its Begin Play
}
protected:
virtual void Gather_Implementation() override
{
if (const AMyWeather* Weather = AMyWeather::Find(GetWorld()))
{
Rain = Weather->GetRain();
}
}
virtual void Apply_Implementation() override
{
if (AMyWeather* Weather = AMyWeather::Find(GetWorld()))
{
Weather->SetRain(Rain);
}
}
UPROPERTY(SaveGame)
float Rain = 0.0f;
};