Saving

NihiloCore provides a debounced saving base built on top of the engine's USaveGame system. Rather than writing to disk on every change, saves are deferred and coalesced — only committing once activity has settled, with a hard deadline to guarantee the write eventually happens regardless of how frequently data changes.

How It Works

UNihiloDebouncedSavingTask wraps a Debounce Task internally. When Save is called, the provided USaveGame object is stored as pending and the debounce is triggered. If Save is called again before the delay elapses, the pending data is replaced and the delay resets. The actual disk write only happens once the delay completes uninterrupted.
The timeout acts as a guarantee. If saves keep arriving faster than the delay window — for example, during a long sequence of rapid stat updates — the timeout ensures the write happens anyway after a maximum wait, using whatever the most recent pending data was at that moment. Both the delay and the timeout call the same internal ExecuteSave path, so the behavior is identical either way.
On completion, OnSaveCompleted is broadcast with a success flag and an optional error message string. Bind to this to update UI, retry logic, or telemetry.

Setup

The task is configured via FNihiloScheduledSavingProviderSettings, which carries the slot name, delay time, timeout time, user index, and a debug logging flag. Use the static CreateDefault factory for quick construction with sensible defaults, or build the struct manually for full control.
Pass the settings to Initialize before calling anything else. The debounce task is created internally at this point — calls to Save before initialization are rejected with an error broadcast on OnSaveCompleted. Call Deinitialize when the task is no longer needed to cleanly tear down the internal debounce and clear pending data.
Setting Default Description
Slot Name SlotName The save slot identifier passed to SaveGameToSlot and LoadGameFromSlot.
Delay Time 0.5s How long to wait after the last Save call before writing to disk.
Max Save Delay Time 5.0s Hard deadline from the first Save call in a burst. The write is forced after this regardless of ongoing activity.
User Index 0 Platform user index forwarded to the engine save system. Relevant for split-screen or multi-user platforms.
Enable Debug Logging false Emits log entries for save and load operations, including slot name and success state.

Extending the Task

UNihiloDebouncedSavingTask is designed to be subclassed. Three virtual hooks let derived classes participate in the save lifecycle without overriding the core saving logic:
  • GetSaveGameClass — return the USaveGame subclass your project uses. The base returns the plain USaveGame class, which is only useful as a placeholder.
  • OnSaveDataLoaded — called after a successful load, with the deserialized save object. Use this to distribute loaded data to the rest of your systems.
  • OnSaveDataCreated — called when no save file exists and a fresh one is created by Load. Use this to populate default values before the new file is written to disk.
A typical subclass overrides GetSaveGameClass to return its own save type, and implements OnSaveDataLoaded to push the loaded data into whatever provider or component owns it. Gateway's saving provider follows exactly this pattern.

Loading

Load is synchronous and returns the USaveGame object directly. If a save file exists in the slot it is loaded and returned after calling OnSaveDataLoaded. If no file exists yet, CreateSaveFile is called — which creates a default save object via CreateDefaultSaveData, calls OnSaveDataCreated, writes it to disk immediately, and returns it. This means a first-time load always results in a valid object with no extra handling needed at the call site.
SaveImmediate bypasses the debounce entirely by calling Force on the internal debounce task, flushing any pending write to disk right away. Use this for cases where a guaranteed synchronous commit is required — application shutdown, returning to the main menu, or explicit user-triggered saves.