|
|
|
@@ -9,48 +9,75 @@ Das verbindliche Konzept steht in [docs/KONZEPT.md](docs/KONZEPT.md). Lies es, b
|
|
|
|
|
| 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 |
|
|
|
|
|
|
|
|
|
|
Die Brücke zu Godot (`bridge/`), das Godot-Projekt (`game/`) und die Inhaltsdateien (`content/`) kommen mit späteren Plänen dazu.
|
|
|
|
|
|
|
|
|
|
Faustregel: Was im Speicherstand steht oder alle Spieler betrifft, gehört in den Kern.
|
|
|
|
|
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 gilt für den Quelltext des Kerns in `core/src/`. Die Tests in `core/tests/` dürfen zum Beispiel Dateien lesen.
|
|
|
|
|
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.
|
|
|
|
|
- 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 `World::set_all_offline`: Es darf nur direkt nach dem Laden eines Speicherstands aufgerufen werden, bevor jemand beigetreten ist.
|
|
|
|
|
- Alles, was zum Zustand der Welt gehört, steht im Snapshot. Wer ein Feld ergänzt, ergänzt es in `snapshot.rs` und erhöht `SNAPSHOT_VERSION`.
|
|
|
|
|
- Wo eine Rechnung im Spiel überlaufen kann, steht eine ausdrückliche Wahl: `saturating_`, `wrapping_` oder `checked_`. Taktzähler (`u64` bei 20 Takten pro Sekunde) laufen praktisch nie über und werden normal addiert. Werte aus geladenen Dateien müssen deshalb beim Laden geprüft werden.
|
|
|
|
|
- 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 in `snapshot.rs`, prüft es 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.
|
|
|
|
|
|
|
|
|
|
Der Test `core/tests/forbidden_apis.rs` durchsucht den Quelltext des Kerns nach verbotenen Begriffen. Sie dürfen dort auch in Kommentaren nicht vorkommen.
|
|
|
|
|
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. `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()`, nie den echten Benutzerordner.
|
|
|
|
|
- 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 drei Befehle fehlerfrei laufen:
|
|
|
|
|
Vor jedem Commit müssen alle Befehle fehlerfrei laufen:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Schlägt `core/tests/golden.rs` fehl, haben sich Regeln oder ein Format geändert. Die Fehlermeldung nennt die Versionskonstante, die dann erhöht werden muss. Erst danach wird der festgeschriebene Wert bewusst angepasst.
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
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 Übersetzungsdateien.
|
|
|
|
|
- Texte im Spiel: Deutsch und Englisch über `game/i18n/texts.csv`.
|
|
|
|
|
|
|
|
|
|
## Git
|
|
|
|
|
|
|
|
|
|
- Archiv: `https://git.race-cave.cloud/steven/Grovewright.git` (Gitea).
|
|
|
|
|
- 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.
|
|
|
|
|