Files
Grovewright/CLAUDE.md
T
Steven Wroblewski 5b76f828e0 CLAUDE.md: neue Zustandsfelder an allen Kodier-Stellen ergänzen
Die Regel sagte, wer ein Feld ergänze, tue das in snapshot.rs und prüfe
es in check_restorable. Das gilt nur für Felder von World. Spielerfelder
kodiert und dekodiert core/src/player.rs, das Inventar inventory.rs, die
Karte map.rs; deren Prüfungen stehen im jeweiligen Dekodierer, nicht in
check_restorable. M2 ergänzt Welt-, Feld- und Spielerzustand und folgt
diesem Satz.

Die Regel nennt jetzt alle vier Stellen und sagt, dass ein neues Feld
beim Dekodieren oder in check_restorable geprüft wird. Die Namen wurden
gegen den Code geprüft: encode_state und from_snapshot, Player::encode
und Player::decode, Inventory::encode und Inventory::decode sowie
Map::encode und Map::decode.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 13:25:26 +02:00

5.7 KiB
Raw Blame History

Grovewright

Aufbauspiel für ein bis vier Spieler, in dem die Fabrik lebt. Gebaut wird zuerst eine Vertical Slice mit 2–3 Stunden Spielzeit.

Das verbindliche Konzept steht in docs/KONZEPT.md. Lies es, bevor du Spielregeln, Architektur oder Umfang änderst. Was dort nicht steht, ist nicht beschlossen.

Aufbau

Ordner Inhalt
core/ Rust-Kern: die gesamte gemeinsame Welt. Ohne Zugriff auf die Engine, ohne fremde Crates.
bridge/ Rust-Brücke (GDExtension): macht den Kern für Godot aufrufbar und enthält keine Spielregeln.
game/ Godot-Projekt mit der GDScript-Hülle: Darstellung, Eingabe, Oberfläche, Dateien.
docs/KONZEPT.md Spielkonzept und Entscheidungen
docs/superpowers/plans/ Umsetzungspläne
docs/playtests/ Fragebögen für Playtests

Faustregel: Was im Speicherstand steht oder alle Spieler betrifft, gehört in den Kern. Die Hülle darf Gleitkommazahlen nutzen, weil sie nichts an der gemeinsamen Welt ändert; sie schickt nur Befehle.

Regeln für den Kern

Alle Spieler simulieren die Welt selbst und tauschen nur Befehle aus (Gleichschritt). Das funktioniert nur, wenn der Kern auf jedem Rechner exakt gleich rechnet. Deshalb gelten für den Quelltext des Kerns in core/src/ diese Regeln (die Tests in core/tests/ dürfen zum Beispiel Dateien lesen):

  • Nur ganze Zahlen, keine Gleitkommazahlen.
  • Keine Uhr, keine Dateien, kein Netzwerk, keine Threads, keine Umgebungsvariablen, kein globaler veränderlicher Zustand.
  • Zufall nur über rng::Rng mit fester Startzahl.
  • Keine Sammlung mit wechselnder Reihenfolge. Statt einer Hash-Tabelle nimmst du Vec, BTreeMap oder BTreeSet.
  • Die Welt ändert sich nur durch einen Command in World::step. Einzige Ausnahme ist das Laden eines Speicherstands mit World::load, das alle Spieler abmeldet.
  • Wer eine Sitzung aufzeichnet, ruft Recording::step statt World::step auf. So enthält die Aufzeichnung genau die ausgeführten Befehle.
  • Alles, was zum Zustand der Welt gehört, steht im Snapshot. Wer ein Feld ergänzt, ergänzt es im Kodierer und im Dekodierer seiner Struktur (snapshot.rs für die Welt, player.rs für Spieler, inventory.rs für das Inventar, map.rs für die Karte), prüft es beim Dekodieren oder in check_restorable und erhöht SNAPSHOT_VERSION.
  • Wo eine Rechnung im Spiel überlaufen kann, steht eine ausdrückliche Wahl: saturating_, wrapping_ oder checked_. Taktzähler laufen praktisch nie über und werden normal addiert: Die Welt zählt in u64, eine Aufzeichnung in u32, was bei 20 Takten pro Sekunde für über sechs Jahre reicht. Takte aus geladenen Dateien begrenzt MAX_RESTORABLE_TICK.
  • Keine fremden Crates im Kern.

Drei Wächter prüfen das. core/clippy.toml sperrt Pfade wie std::collections::HashMap oder std::fs::read, auch über Aliase und gruppierte Importe. Der Test core/tests/forbidden_apis.rs durchsucht zusätzlich den Text nach verbotenen Begriffen; sie dürfen dort auch in Kommentaren nicht vorkommen. Gruppierte Importe aus std (use std::{…}) sind verboten, weil sie dem Text die Modulnamen verbergen: Jeder Pfad steht in einer eigenen use-Zeile. core/tests/no_dependencies.rs hält die Abhängigkeiten leer.

Regeln für Brücke und Hülle

  • Die Brücke übersetzt nur. Neue Spielregeln gehören in den Kern, nie in bridge/ oder game/.
  • GDScript mit Typangaben schreiben (var x := …, Rückgabetypen an jeder Funktion).
  • Eingabeaktionen legt game/scripts/input_setup.gd an, nicht project.godot.
  • Alle Texte, die Spieler sehen, stehen in game/i18n/texts.csv (Deutsch und Englisch) und werden über tr() geholt.
  • Tests, die Dateien schreiben, nutzen TestFiles.temporary_dir() (Ordner unter user://tests), nie die echten Dateien des Spielers.
  • Godot erzeugt beim Import zu jedem Skript eine .uid-Datei. Sie gehört ins Archiv. Der Ordner game/.godot/ gehört nicht hinein.

Prüfen

Vor jedem Commit müssen alle Befehle fehlerfrei laufen:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build -p grovewright-bridge
godot --headless --path game --import
godot --headless --path game -s res://tests/run_tests.gd

Der erste Import in einem frischen Checkout stürzt mit Godot 4.7.2 und der Rust-Erweiterung beim Beenden ab (Exit-Code 139 in der Bash). Der Import ist dann trotzdem erfolgt; ein zweiter Aufruf läuft fehlerfrei durch. play.bat wiederholt den Import deshalb einmal.

Schlägt core/tests/golden.rs fehl, haben sich Regeln oder ein Format geändert. Sind Speicherstände oder Aufzeichnungen betroffen, erhöhst du die Versionskonstante, die die Fehlermeldung nennt. Erst danach passt du den festgeschriebenen Wert bewusst an.

Für Änderungen am Aussehen gibt es ein Werkzeug, das kurz ein Fenster öffnet und ein Bildschirmfoto speichert:

godot --path game -s res://tools/screenshot.gd -- <Pfad der PNG-Datei>

Spielen

play.bat im Hauptordner baut die Brücke und startet das Spiel. Spielstand, Spielerschlüssel und Aufzeichnungen liegen unter %APPDATA%\Godot\app_userdata\Grovewright.

Sprache

  • Code, Bezeichner und Kommentare im Code: Englisch.
  • Dokumente, Pläne, Commit-Nachrichten, Issues und Pull Requests: Deutsch.
  • Texte im Spiel: Deutsch und Englisch über game/i18n/texts.csv.

Git

  • Archiv: https://git.race-cave.cloud/steven/Grovewright.git (Gitea). Issues und Pull Requests sind freigegeben.
  • Gearbeitet wird auf einem Branch pro Plan, nicht direkt auf main.
  • Nach jedem abgeschlossenen Arbeitsschritt wird committet und hochgeladen. Das ist freigegeben.
  • Commit-Nachrichten enden mit einer Zeile Co-Authored-By: Claude <Modell> <noreply@anthropic.com>, die das Claude-Modell nennt, das den Commit erstellt hat.