165 lines
4.2 KiB
Markdown
165 lines
4.2 KiB
Markdown
# Lua State Persistence / Spielstand-Speicherung
|
|
|
|
## Übersicht
|
|
|
|
Der Wherigo Player kann den Lua-State speichern und wiederherstellen, um Spielfortschritte zu sichern.
|
|
|
|
## Funktionsweise
|
|
|
|
### Automatisches Speichern
|
|
|
|
Der Spielstand wird automatisch gespeichert unter:
|
|
- **macOS**: `~/Library/Application Support/wxWherigo/<CartridgeName>.save`
|
|
- **Windows**: `%APPDATA%\wxWherigo\<CartridgeName>.save`
|
|
- **Linux**: `~/.wxWherigo/<CartridgeName>.save`
|
|
|
|
### Was wird gespeichert?
|
|
|
|
Die Persistierung speichert:
|
|
- ✅ **Alle Wherigo-Objekte**: ZCartridge, Zone, ZItem, ZCharacter, ZTask, ZTimer, ZInput, ZMedia
|
|
- ✅ **Objekt-Properties**: Name, Description, Active, Visible, Container, etc.
|
|
- ✅ **Globale Variablen**: Alle einfachen Variablen (Strings, Numbers, Booleans)
|
|
- ✅ **Player-Objekt**: Position, Inventar, etc.
|
|
- ✅ **Verschachtelte Tabellen**: Rekursive Serialisierung (bis Tiefe 10)
|
|
|
|
### Was wird NICHT gespeichert?
|
|
|
|
- ❌ **Funktionen**: Lua-Funktionen können nicht serialisiert werden
|
|
- ❌ **Userdata**: C-Objekte bleiben im Originalzustand
|
|
- ❌ **Threads/Coroutines**: Werden als `nil` gespeichert
|
|
- ❌ **Metatables**: Werden nicht persistent gespeichert
|
|
|
|
## Verwendung im Code
|
|
|
|
### Spielstand speichern
|
|
|
|
```cpp
|
|
// Automatischer Pfad (empfohlen)
|
|
wxGetApp().saveGameState("");
|
|
|
|
// Eigener Pfad
|
|
wxGetApp().saveGameState("/path/to/save.lua");
|
|
```
|
|
|
|
### Spielstand laden
|
|
|
|
```cpp
|
|
// Automatischer Pfad
|
|
wxGetApp().loadGameState("");
|
|
|
|
// Eigener Pfad
|
|
wxGetApp().loadGameState("/path/to/save.lua");
|
|
```
|
|
|
|
### Im Spiel
|
|
|
|
- **Menü → Spielstand speichern** (Strg+S)
|
|
- **Menü → Spielstand laden** (Strg+L)
|
|
|
|
## Save-Datei-Format
|
|
|
|
Die Save-Datei ist eine lesbare Lua-Datei:
|
|
|
|
```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>
|
|
},
|
|
-- ... weitere Objekte
|
|
}
|
|
```
|
|
|
|
## Technische Details
|
|
|
|
### Serialisierung
|
|
|
|
Die Implementierung verwendet:
|
|
1. **Rekursives Traversieren** der Lua-Tabellen
|
|
2. **Type-Detection** für verschiedene Lua-Typen
|
|
3. **Escaping** von Sonderzeichen in Strings
|
|
4. **Referenz-Handling** durch Lua selbst beim Laden
|
|
|
|
### Deserialisierung
|
|
|
|
1. Save-Datei wird als Lua-Code geladen (`luaL_loadstring`)
|
|
2. Ausführung gibt eine Tabelle zurück (`lua_pcall`)
|
|
3. Tabellen-Einträge werden als Globals wiederhergestellt
|
|
4. UI wird über `notifyStateChanged()` aktualisiert
|
|
|
|
## Performance
|
|
|
|
- **Speichern**: ~10-100ms für typische Cartridges
|
|
- **Laden**: ~20-200ms (inkl. Lua-Parsing)
|
|
- **Dateigröße**: ~10-500KB (abhängig von Cartridge-Komplexität)
|
|
|
|
## Erweiterungen
|
|
|
|
### Eigene Filter
|
|
|
|
```cpp
|
|
// Nur bestimmte Globals speichern
|
|
std::vector<std::string> myGlobals = {"Player", "zitemKey", "ztaskMain"};
|
|
wherigo::LuaPersistence::saveGlobals(L, "custom.save", myGlobals);
|
|
```
|
|
|
|
### Auto-Save beim Beenden
|
|
|
|
```cpp
|
|
// In cGame::OnClose()
|
|
wxGetApp().saveGameState(""); // Auto-Save
|
|
```
|
|
|
|
### Mehrere Save-Slots
|
|
|
|
```cpp
|
|
std::string slot1 = wxGetApp().getAutoSavePath() + ".slot1";
|
|
std::string slot2 = wxGetApp().getAutoSavePath() + ".slot2";
|
|
std::string slot3 = wxGetApp().getAutoSavePath() + ".slot3";
|
|
```
|
|
|
|
## Bekannte Limitierungen
|
|
|
|
1. **Funktions-Callbacks** werden nicht gespeichert (OnClick, OnEnter, etc.)
|
|
- Diese bleiben im Cartridge-Code definiert
|
|
|
|
2. **Zirkuläre Referenzen** werden bei der Rekursion abgebrochen
|
|
- Max. Tiefe: 10 Ebenen
|
|
|
|
3. **Metatables** gehen verloren
|
|
- Nach dem Laden müssen ggf. Metatables neu gesetzt werden
|
|
|
|
4. **Timer-Status** wird gespeichert, aber `Remaining` muss ggf. neu berechnet werden
|
|
|
|
## Debugging
|
|
|
|
Aktiviere Logging um Save/Load zu tracken:
|
|
|
|
```cpp
|
|
wxLogDebug("Saved %zu globals to %s", globals.size(), filePath);
|
|
wxLogDebug("Restored %d globals from %s", count, filePath);
|
|
```
|
|
|
|
## Zukünftige Erweiterungen
|
|
|
|
Mögliche Verbesserungen:
|
|
- [ ] Kompression der Save-Dateien (zlib)
|
|
- [ ] Verschlüsselung (verhindert Cheating)
|
|
- [ ] Delta-Saves (nur Änderungen speichern)
|
|
- [ ] Cloud-Sync Integration
|
|
- [ ] Automatisches Backup (3 neueste Saves)
|
|
|