Repository navigation
The persistent saving framework
- Overview
- Purpose
- Architecture
- Core Components
- Data Structure
- Save Flows
- Load Flows
- Tutorial Completion Tracking
- Event Flow Reference
- File Storage and Slots
- Error Handling
- Testing
- Design Notes
- Appendix: Mermaid Diagrams
The Persistent Saving Framework is responsible for serialising and restoring the player's game state between sessions. It supports:
- Checkpoint-based autosaves: Triggered automatically when the player activates a checkpoint.
-
Slot-based saves: Up to
SLOT_COUNTindependent save files persisted to disk. -
Save completion tracking: Marks saves as
Completedwhen the player finishes the game through the WIN path or Calypso boss defeat. - Tutorial progression tracking: Persists which tutorial steps have been completed across sessions.
- Deferred world/player restoration: Pending save state is staged and applied at the appropriate time after level/area loading to avoid race conditions.
- Event-driven architecture: Decouples save triggers, such as checkpoints and game end, from persistence logic through the game's event handlers.
This framework exists to allow players to:
- Return to their progress at the last activated checkpoint through autosaving.
- Manage multiple save slots from the Load/Save screen.
- See completion status (
Completed) on finished runs in the save selection UI. - Resume tutorial progress correctly across sessions, deaths, and reloads.
- Restore player stats, inventory-related state, and world state relevant to the active level.
The saving system is divided into data, persistence, orchestration, events, UI, and trigger components. Communication is primarily event-driven through ServiceLocator event handlers, with GdxGame acting as the central coordinator.
CheckpointComponent (trigger)
└── GameArea / Events
└── GameSaveEventHandler ("autosave")
└── LevelsGameScreen
└── GdxGame.autosave(level, area)
└── SaveManager.save(slot, SaveFile)
└── Disk (serialised SaveFile)
Game End (WIN / Boss Defeat)
└── GameEndEventHandler("gameEnd", WIN)
OR direct call on boss defeat
└── LevelsGameScreen / GdxGame.markSaveCompleted()
└── SaveManager.save(activeSlot, completed SaveFile)
LoadSaveDisplay ("Load", slot)
└── GdxGame.loadGame(slot)
└── SaveManager.get(slot)
└── SaveFile stored as pending state
└── Applied later through:
├── applyPendingSavePlayer()
└── applyPendingSaveWorld()
com.csse3200.game.files.SaveFile is the serialisable data container representing a single save slot's state.
Responsibilities:
- Hold player state.
- Store current level and area context.
- Track completion flags.
- Store completed tutorial identifiers.
- Hold entity state snapshots.
- Store metadata, including the last-modified timestamp.
Usage:
A SaveFile is constructed at save time, written by SaveManager, then read back and held as pending state by GdxGame when loading a save.
Key characteristics:
-
currentLevel: Current level identifier, such aslevel1,level2,level3, orboss. -
lastModifiedEpochMs: Timestamp used by the UI. -
completed: Whether the game has been completed successfully. -
tutorialCompleted: Collection or set of completed tutorial IDs/keys. -
player: Nested object containing health, maximum health, gold, and other player state. -
entities: List or map representing world entity state needed for restoration.
com.csse3200.game.files.SaveManager handles disk I/O and save-slot management.
Responsibilities:
-
listAll(): Enumerate available saves for the Load/Save UI. -
get(slot): Read a specific save slot. -
save(slot, saveFile): Persist aSaveFileto a slot. -
delete(slot): Delete a save slot. -
SLOT_COUNT: Define the number of available save slots.
Behaviour:
- Slots are indexed from
0toSLOT_COUNT - 1. - When a save is written,
lastModifiedEpochMsis typically refreshed to the current time. -
listAll()returns an array ofSaveFileobjects, withnullentries representing empty slots. - The UI treats
nullentries as empty slots. - Storage is filesystem-based under the game's save directory, managed by the game's file service.
- File paths are scoped to individual save slots.
com.csse3200.game.GdxGame is the application entry point and central coordinator for the save/load lifecycle.
Key methods:
- Captures the current state of the active game area and player.
- Builds or updates a
SaveFile. - Determines or uses the active save slot.
- Writes the save through
SaveManager.save(). - Called when a checkpoint is activated.
- Loads the active save or uses the current in-memory context.
- Sets
completed = true. - Persists the updated save.
- Called when the generic WIN event occurs or when Calypso is defeated.
- Reads the selected save through
SaveManager.get(slot). - Stores the save as pending state, including
pendingPlayerState,pendingSaveFile, and pending world/level context. - Does not immediately mutate the world.
- Defers application until the appropriate gameplay screen and entities have been initialised.
Applies pending player state to the supplied player entity. This restores health, maximum health, gold, and other player fields captured in the save.
Called after the player entity exists.
Applies pending world/entity state to the specified game area and level.
The pending save must match the target level before world state is restored.
Restores or initialises player state from baseline or in-memory session state, complementing pending save restoration.
getActiveSaveSlot() and related tracking identify the active save slot, generally the last slot loaded or saved to. markSaveCompleted() uses the active slot when marking the current run as finished.
Design note: Deferring state application through pending fields avoids race conditions when the target game area, player entity, or assets have not yet been initialised after a screen or level transition.
The save event handler is registered through ServiceLocator.registerGameSaveEventHandler(...).
Events:
-
autosave: Fired by areas or checkpoints to request an autosave.
The event does not carry heavy state arguments in the current wiring. Instead, LevelsGameScreen listens for the event and calls game.autosave(level, currentGameArea) using its current level and game-area context.
This keeps the event lightweight and avoids serialising game state through the event system.
Registration:
LevelsGameScreen registers a new event handler instance for saves, scoped to that screen's context. Checkpoints and areas forward autosave requests through this dispatcher.
Entities and Components
Input Handling
Arrow Selection Wheel Arrow Selection Wheel — Sprint 3
Game Screens and Areas
Enemies
-
Individual Enemy Pages:
-
Misc Enemy Pages: