165 lines
3.8 KiB
Markdown
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)
|
|
|