Skip to content

Recipe 5: In-Game Save/Load Browser UI ​

This recipe demonstrates how to build a complete, professional Save and Load Game Menu in UMG. It shows how to query save slot metadata in sub-milliseconds without decompressing world data, format timestamps and playtimes, and handle slot creation, loading, and deletion.


1. Fast Slot Metadata Reads ​

A common performance pitfall in Unreal save menus is loading every save file into memory just to display the slot names and timestamps in a UI list. With 20 slots of 10 MB each, this causes a multi-second freeze.

How Aegis Solves This ​

Aegis Save stores all slot metadata in an uncompressed Metadata Section at the very beginning of the .aegis container:

  • Get All Slot Info and Get Slot Info read only the first few hundred bytes of each file.
  • It never decompresses record bundles.
  • A menu with 100 save slots loads in less than 10 milliseconds!

2. Inspecting FAegisSlotInfo ​

When querying slots, Aegis returns an array of FAegisSlotInfo:

FieldTypeDescription
SlotNameFStringInternal disk identifier (e.g. "SaveSlot_01")
DisplayNameFStringPlayer-visible name (e.g. "Chapter 3: The Whispering Woods")
TimestampUtcFDateTimeReal-world date and time when the save was written
PlaytimeSecondsint32Total accumulated game time in seconds
RecordCountint32Total number of persistent entities in the save
GameSchemaVersionint32Developer-defined game patch version
bIsLoadableboolCritical: True if this save can be loaded by the current build

Always Check bIsLoadable

If a player tries to load a save written by a future format version or incompatible schema, bIsLoadable will be false. In your UI, gray out the "Load" button or display a compatibility badge!


3. Blueprint Implementation: Populating the Menu ​

Step 1: Querying All Slots ​

In your Save Menu Widget (WBP_SaveGameMenu), bind to Construct or OnMenuOpened:

text
[Event OnMenuOpened]
       │
       ▼
[Get All Slot Info (Aegis)]
       │
       ▼
[For Each Loop (Array of FAegisSlotInfo)]
       │
       ▼
[Create Widget: WBP_SaveSlotEntry]
  ├── Pass In: FAegisSlotInfo Struct
  └── Add Child to: (ScrollBox_SlotList)

Step 2: Formatting the Entry Widget (WBP_SaveSlotEntry) ​

Inside the slot entry row widget, bind the text elements:

  1. Title: Set to SlotInfo.DisplayName.
  2. Date / Time: Convert SlotInfo.TimestampUtc to local time and format as YYYY-MM-DD HH:MM.
  3. Playtime: Convert SlotInfo.PlaytimeSeconds into hours, minutes, and seconds:
text
PlaytimeHours   = Floor(PlaytimeSeconds / 3600)
PlaytimeMinutes = Floor((PlaytimeSeconds % 3600) / 60)
PlaytimeSecs    = PlaytimeSeconds % 60
FormattedText   = Format: "{0}h {1}m {2}s"
  1. Load Button: Set Button.SetIsEnabled(SlotInfo.bIsLoadable).

4. Save, Load, and Delete Actions ​

Loading a Slot ​

When the player clicks the "Load Game" button on an entry:

text
[OnClicked: Button_Load]
       │
       ▼
[Show Loading Screen / Fade Out (0.5s)]
       │
       ▼
[Load Game from Slot (Aegis)]
  ├── Slot Name: SelectedSlotInfo.SlotName
  ├── OnSuccess ──► [Hide Loading Screen / Resume Game]
  └── OnFailed  ──► [Show Dialog: "Failed to load save! " + Status.Context]

Deleting a Slot ​

When the player clicks the trash icon to delete an old save:

text
[OnClicked: Button_Delete]
       │
       ▼
[Delete Slot (Aegis)]
  ├── Slot Name: SelectedSlotInfo.SlotName
  └── OnSuccess ──► [Remove Entry Widget from ScrollBox]

Clean Backup Cleanup

Calling Delete Slot cleanly deletes both the .aegis container file and its companion .bak backup file from the player's save directory.


5. C++ Implementation: Slot Browser Service ​

For C++ projects, here is a clean helper function to fetch and sort slots:

cpp
#include "Core/AegisSubsystem.h"

void UMySaveService::GetSortedSaveSlots(TArray<FAegisSlotInfo>& OutSortedSlots)
{
    OutSortedSlots.Empty();

    UAegisSubsystem* Aegis = UAegisSubsystem::Get(this);
    if (!Aegis)
    {
        return;
    }

    TArray<FAegisSlotInfo> Slots;
    const FAegisStatus Status = Aegis->GetAllSlotInfo(Slots);

    if (Status.IsSuccess())
    {
        // Sort by most recent save timestamp first
        Slots.Sort([](const FAegisSlotInfo& A, const FAegisSlotInfo& B)
        {
            return A.TimestampUtc > B.TimestampUtc;
        });

        OutSortedSlots = MoveTemp(Slots);
    }
}

Next Steps ​

Aegis Save — Enterprise World Persistence for Unreal Engine 5.