Files
wx_wherigo/LUA_PERSISTENCE.md
2026-02-14 09:47:27 +01:00

165 lines
3.8 KiB
Markdown

# Lua State Persistence / Save Game System
## Overview
The Wherigo Player can save and restore the Lua state to preserve game progress.
## How It Works
### Automatic Save Locations
Game saves are automatically stored at:
- **macOS**: `~/Library/Application Support/wxWherigo/<CartridgeName>.save`
- **Windows**: `%APPDATA%\wxWherigo\<CartridgeName>.save`
- **Linux**: `~/.wxWherigo/<CartridgeName>.save`
### What is Saved?
Persistence saves:
-**All Wherigo Objects**: ZCartridge, Zone, ZItem, ZCharacter, ZTask, ZTimer, ZInput, ZMedia
-**Object Properties**: Name, Description, Active, Visible, Container, etc.
-**Global Variables**: All simple variables (Strings, Numbers, Booleans)
-**Player Object**: Position, inventory, etc.
-**Nested Tables**: Recursive serialization (up to depth 10)
### What is NOT Saved?
-**Functions**: Lua functions cannot be serialized
-**Userdata**: C objects remain in original state
-**Threads/Coroutines**: Saved as `nil`
-**Metatables**: Not persisted
## Usage in Code
### Save Game State
```cpp
// Automatic path (recommended)
wxGetApp().saveGameState("");
// Custom path
wxGetApp().saveGameState("/path/to/save.lua");
```
### Load Game State
```cpp
// Automatic path
wxGetApp().loadGameState("");
// Custom path
wxGetApp().loadGameState("/path/to/save.lua");
```
### In-Game
- **Menu → Save Game** (Ctrl+S)
- **Menu → Load Game** (Ctrl+L)
## Save File Format
The save file is a readable Lua file:
```lua
-- Wherigo Save State
return {
["Player"] = {
["ClassName"] = "Player",
["Name"] = "Player",
["ObjectLocation"] = {
["latitude"] = 51.5074,
["longitude"] = -0.1278,
["altitude"] = 0
}
},
["zitemLetter"] = {
["ClassName"] = "ZItem",
["Name"] = "Letter from Professor",
["Active"] = true,
["Visible"] = true,
["Container"] = <reference to Player>
},
-- ... more objects
}
```
## Technical Details
### Serialization
The implementation uses:
1. **Recursive traversal** of Lua tables
2. **Type detection** for different Lua types
3. **Escaping** of special characters in strings
4. **Reference handling** by Lua itself when loading
### Deserialization
1. Save file is loaded as Lua code (`luaL_loadstring`)
2. Execution returns a table (`lua_pcall`)
3. Table entries are restored as globals
4. UI is updated via `notifyStateChanged()`
## Performance
- **Saving**: ~10-100ms for typical cartridges
- **Loading**: ~20-200ms (including Lua parsing)
- **File size**: ~10-500KB (depends on cartridge complexity)
## Extensions
### Custom Filters
```cpp
// Save only specific globals
std::vector<std::string> myGlobals = {"Player", "zitemKey", "ztaskMain"};
wherigo::LuaPersistence::saveGlobals(L, "custom.save", myGlobals);
```
### Auto-Save on Exit
```cpp
// In cGame::OnClose()
wxGetApp().saveGameState(""); // Auto-save
```
### Multiple Save Slots
```cpp
std::string slot1 = wxGetApp().getAutoSavePath() + ".slot1";
std::string slot2 = wxGetApp().getAutoSavePath() + ".slot2";
std::string slot3 = wxGetApp().getAutoSavePath() + ".slot3";
```
## Known Limitations
1. **Function Callbacks** are not saved (OnClick, OnEnter, etc.)
- These remain defined in cartridge code
2. **Circular References** are cut off during recursion
- Max depth: 10 levels
3. **Metatables** are lost
- May need to be reset after loading
4. **Timer Status** is saved, but `Remaining` may need recalculation
## Debugging
Enable logging to trace save/load:
```cpp
wxLogDebug("Saved %zu globals to %s", globals.size(), filePath);
wxLogDebug("Restored %d globals from %s", count, filePath);
```
## Future Enhancements
Possible improvements:
- [ ] Compression of save files (zlib)
- [ ] Encryption (prevent cheating)
- [ ] Delta saves (only save changes)
- [ ] Cloud sync integration
- [ ] Automatic backups (keep 3 most recent saves)