Files
basic1/SAVE_SYSTEM_PLAN.md
T
Adolfo Reyna e6e4eca188 Add Lua 5.4 scripting integration for dynamic game loading
- Integrated Lua 5.4 engine (32-bit mode for embedded ARM)
- Created LuaGame wrapper class implementing Game interface
- Added C++ bindings exposing renderer, game state, and input to Lua
- Implemented SD card loader for automatic .lua game discovery
- Updated GameLauncher to support std::function for lambda captures
- Made Game class members public for Lua bindings access
- Added example Lua games: counter, snake, bouncing ball
- Included comprehensive API documentation

Games can now be written as .lua text files on SD card and loaded
without recompilation. Build size: 747KB UF2, Lua VM uses ~50-80KB RAM.
2026-02-07 11:56:03 -05:00

72 lines
3.3 KiB
Markdown

# Game Save System Implementation Plan (RP2350/RP2040)
This document outlines the strategy for implementing non-volatile game save states using the onboard Flash memory.
## 1. Objectives
* **Persistence:** Save game state so progress is kept after power-off.
* **Multi-game Support:** Allow multiple games to have independent saves without overwriting each other.
* **Safety:** Ensure flash writes don't interfere with program execution or interrupt handlers.
* **Wear Leveling:** Minimize unnecessary writes to prolong flash lifespan.
## 2. Flash Memory Mapping
The RP2350 on this board has 8MB of Flash memory mapped starting at `XIP_BASE` (`0x10000000`). We will reserve the top section for data.
| Memory Range | Purpose | Size |
| :--- | :--- | :--- |
| `0x10000000 - 0x106FFFFF` | Program Code, Fonts, Assets | 7MB |
| `0x10700000 - 0x107EFFFF` | Reserved/Future | 960KB |
| `0x107F0000 - 0x107F0FFF` | **Save Registry** | 4KB (1 Sector) |
| `0x107F1000 - 0x107FFFFF` | **Game Save Slots** | 60KB (15 Slots) |
## 3. Architecture Components
### A. `PersistentStorage` Manager (`lib/persistent_storage.h`)
A singleton or static helper class that handles raw flash operations.
* `bool save_exists(const char* game_id)`
* `bool save_data(const char* game_id, void* data, size_t size)`
* `bool load_data(const char* game_id, void* buffer, size_t size)`
### B. Updated `Game` Interface (`lib/game.h`)
Add methods to the base class to standardize how state is handled.
```cpp
virtual const char* get_game_id() const = 0;
virtual size_t get_save_data(void* buffer, size_t max_size) = 0;
virtual void load_save_data(const void* buffer, size_t size) = 0;
```
### C. Save Registry
To avoid collisions, the first sector (`0x107F0000`) will store a lookup table:
```cpp
struct RegistryEntry {
char game_id[16];
uint32_t sector_index;
uint32_t data_size;
uint32_t checksum;
};
```
## 4. Implementation Steps
1. **Create `PersistentStorage`:**
* Implement flash sector erasing and programming using `pico/flash.h`.
* Include interrupt protection using `save_and_disable_interrupts()`.
2. **Update `Game` Base Class:**
* Modify `lib/game.h` to include the virtual persistence methods.
3. **Implement in Monopoly:**
* Create a `MonopolySaveState` struct (POD - Plain Old Data).
* Populate it from game variables in `get_save_data`.
4. **Integrate with Launcher:**
* Modify `GameLauncher` to check for existing saves when a game is selected.
* Modify the main loop to trigger `save_data` at logical points (e.g., end of turn/exit).
## 5. Collision Avoidance Logic
* When a game requests a save for the first time, the `PersistentStorage` manager scans the Registry.
* If the `game_id` isn't found, it allocates the next available 4KB sector.
* It writes the specific `game_id` and its assigned `sector_index` back to the Registry sector.
* Sequential saves for that ID will always use that specific sector.
## 6. Important Notes
* **Flash Wear:** Each sector supports ~100k erase cycles. Total lifespan depends on frequency of saves.
* **Alignment:** Data must be programmed in multiples of `FLASH_PAGE_SIZE` (256 bytes).
* **Recursion:** Never call flash functions from within an interrupt or callback that might be triggered during a write.