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

4.2 KiB

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

// Automatischer Pfad (empfohlen)
wxGetApp().saveGameState("");

// Eigener Pfad
wxGetApp().saveGameState("/path/to/save.lua");

Spielstand laden

// 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:

-- 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

// Nur bestimmte Globals speichern
std::vector<std::string> myGlobals = {"Player", "zitemKey", "ztaskMain"};
wherigo::LuaPersistence::saveGlobals(L, "custom.save", myGlobals);

Auto-Save beim Beenden

// In cGame::OnClose()
wxGetApp().saveGameState("");  // Auto-Save

Mehrere Save-Slots

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:

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)