2Brute2Best
πŸ”₯0
C3

Save Checkpoints & Restore Without Exposing Private State

Pro OnlyMemento
⚑ 60-Second Architecture SummaryC3 · Memento Pattern
Naive Bottleneck→Memento Pattern Cure
The Naive Bottleneck: Complete destruction of encapsulation

Exposing public getters and setters for every private HP, mana, position, and inventory field breaks encapsulation completely. Any external script can tamper with internal health invariants, and whenever new fields (like cooldowns or curses) are added to `Hero`, external save structures break.

To allow external saving, Hero must make its internal fields public or provide public setters. Any external script can tamper with hero.hp = 99999 or bypass health bounds.

The Pattern Cure: Memento Pattern

Capture and externalize an object's internal state without violating encapsulation, so that the object can be restored to this state later.

Hero (the Originator) creates an instance of HeroSnapshot (the Memento). HeroSnapshot keeps its fields and constructor private, declaring friend class Hero; so that only Hero can read and write its contents. CheckpointHistory (the Caretaker) holds snapshots as opaque black boxes, managing undo/restore stacks without ever inspecting or tampering with internal state.

Sprint 3 of 8 Β· Boss-Room Checkpoints & Encapsulated Save States
Story C β€” 2D RPG Game Engine β€” Progressive System Build
1. Where our codebase left off
← C2

In Sprint 2 (C2 Β· Composite), we designed a recursive inventory hierarchy where pouches and bags nest seamlessly to arbitrary depths. Equipped with their stacked buffs and organized inventories, heroes now face deadly dungeon boss chambers where total party wipes are frequent.

2. What we are building now

We need a boss-room checkpoint save-and-restore system. When a player activates a checkpoint shrine before entering a boss room, the engine must capture Hero's current state (HP, mana, position (x, y)) and restore it seamlessly if the party dies during combat.

3. The pain point we hit

Exposing public getters and setters for every private HP, mana, position, and inventory field breaks encapsulation completely. Any external script can tamper with internal health invariants, and whenever new fields (like cooldowns or curses) are added to Hero, external save structures break.

4. What this unlocks next
Next: C4 β†’

The Memento Pattern (HeroSnapshot) captures an opaque state snapshot managed by a SaveManager caretaker (CheckpointHistory), keeping internals strictly private via friendship. Next in Sprint 4 (C4 Β· Prototype), where entering the dungeon requires spawning waves of pre-configured monster variants (Elite Goblin, Enraged Orc) configured at runtime.

01

The product ticket

Ticket Β· C3RPG-103 Β· Save Checkpoints & Restore Without Exposing Private State

Before confronting a deadly dungeon boss, players hit 'Save Checkpoint'. If the party wipes out, the game rolls back to the saved state: restoring HP, mana, and dungeon position (x, y). The save system must support saving multiple checkpoints across an adventure and restoring previous checkpoints in LIFO order.

Requirements
  • β€’

    Capture the internal state of Hero at any given moment into an opaque checkpoint token (HeroSnapshot).

  • β€’

    Restore Hero cleanly from a snapshot, ensuring internal invariants (hp <= maxHp) remain intact.

  • β€’

    Manage a history of saved checkpoints in a caretaker manager (CheckpointHistory) supporting push and pop operations.

  • β€’

    Strictly preserve encapsulation: external classes must not be able to read, mutate, or tamper with the snapshot's internal state.

The next requirement that breaks naive code

Next sprint, developers will add status curses, skill cooldowns, and temporary equipment buffs to Hero. Adding new fields to Hero must not break the checkpoint manager or require exposing new public getters and setters.

02

Step 1 β€” The naive code & why it breaks

The naive SaveSystem accesses public fields of Hero directly (hero.hp_, hero.mana_, hero.x_, hero.y_) or uses broad public setters to copy data into an external struct.

Naive design (what not to ship) Β· naive.cpp
#include <print>
#include <string>

// Naive: Hero exposes all internal fields publicly so SaveSystem can copy them!
class NaiveHero {
public:
    std::string name;
    int hp{100};
    int maxHp{100};
    int mana{50};
    int x{0};
    int y{0};

    void takeDamage(int dmg) {
        hp = std::max(0, hp - dmg);
    }
};

// External save system reaches straight into Hero's guts!
struct NaiveSaveData {
    int hp;
    int mana;
    int x;
    int y;
};

class NaiveSaveSystem {
public:
    NaiveSaveData createSave(const NaiveHero& h) {
        // Exposes every private detail to external code
        return {h.hp, h.mana, h.x, h.y};
    }

    void restore(NaiveHero& h, const NaiveSaveData& data) {
        h.hp = data.hp;
        h.mana = data.mana;
        h.x = data.x;
        h.y = data.y;
    }
};

int main() {
    NaiveHero hero{"Sir Alistair"};
    NaiveSaveSystem saveSys;

    // Save checkpoint before boss fight
    NaiveSaveData checkpoint = saveSys.createSave(hero);
    std::println("[Before Boss] {} HP: {}, Mana: {} at ({}, {})",
                 hero.name, hero.hp, hero.mana, hero.x, hero.y);

    // Boss fight: player takes massive damage
    hero.takeDamage(85);
    std::println("[During Boss] {} HP: {} (Critical!)", hero.name, hero.hp);

    // Flaw: any external code can tamper with the save data!
    checkpoint.hp = 99999; // Corrupted save!

    // Restore corrupted state
    saveSys.restore(hero, checkpoint);
    std::println("[After Restore] {} HP: {} (Invariants destroyed!)", hero.name, hero.hp);
}
Complete destruction of encapsulation

To allow external saving, Hero must make its internal fields public or provide public setters. Any external script can tamper with hero.hp = 99999 or bypass health bounds.

Extreme coupling between Hero and SaveSystem

Whenever Hero adds or renames an internal field (e.g. mana, statusEffects), SaveSystem and its save struct break and must be manually rewritten.

Save data is vulnerable to corruption

Because save data is stored in open structs, external code or rogue systems can mutate fields between save and restore, corrupting game state.

03

Step 2 β€” The fix: Memento Pattern

Core idea in one sentence

Capture and externalize an object's internal state without violating encapsulation, so that the object can be restored to this state later.

Hero (the Originator) creates an instance of HeroSnapshot (the Memento). HeroSnapshot keeps its fields and constructor private, declaring friend class Hero; so that only Hero can read and write its contents. CheckpointHistory (the Caretaker) holds snapshots as opaque black boxes, managing undo/restore stacks without ever inspecting or tampering with internal state.

Pattern roles in our story
Originator

Hero β€” holds state (HP, mana, position) and invariants; creates snapshots and restores its state from them.

Memento

HeroSnapshot β€” holds private state fields; grants access only to Hero via friend class Hero;.

Caretaker

CheckpointHistory β€” manages a stack of snapshots; never inspects or alters the internal data.

Brute2Best Pro Content

Unlock Full UML Diagram & C++23 Solution

The interactive UML architecture diagrams, refactored C++23 code, real-world extensions, and interview Q&A are part of Brute2Best Pro. All 7 foundation chapters are 100% free.

All 440 visual dry runs & algorithms
Interactive step-by-step playback with pointer & array state transitions
52 comprehensive LLD chapters
Interactive UML diagrams, real-world stories (Food Delivery, Trading, RPG), and practice solutions
40 C++ basics labs & hardware memory models
Vtables, byte layouts, assembly insights, and multi-threading race conditions
Production-ready C++23 source code
Modern idioms, clean contracts, time/space complexity derivations, and interview takeaways

First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.

Systems Integration

Related C++ Systems & Algorithmic Foundations

Deep dive into underlying layers