|
|
@@ -33,6 +33,15 @@ Alle Spieler simulieren die Welt selbst und tauschen nur Befehle aus (Gleichschr
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Gemeinsame Welt im Netz
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Ein Spieler ist Host, die anderen sind Gäste. Der Host (`core/src/host.rs`) legt fest, welche Befehle in welchem Takt laufen, und schickt jeden Takt an seine Gäste. Jeder Gast (`core/src/guest.rs`) rechnet jeden Takt selbst nach. Allein spielen heißt: Host ohne Gäste.
|
|
|
|
|
|
|
|
- Ein Gast bekommt beim Beitritt die Welt des Hosts als Snapshot. Einmal pro Sekunde liegt einem Takt die Prüfsumme des Hosts bei. Weicht die Welt des Gastes ab, holt er sich die Welt des Hosts neu und hebt die Aufzeichnung der abgewichenen Welt auf.
|
|
|
|
|
|
|
|
- Die Nachrichten stehen in `core/src/protocol.rs`. Wer eine Nachricht ändert, erhöht `PROTOCOL_VERSION`.
|
|
|
|
|
|
|
|
- Die Regel-Kennung (`core/src/rules.rs`) leitet sich aus den Endzuständen eingefrorener Skripte ab. Rechner mit verschiedener Regel-Kennung spielen nicht zusammen, und Aufzeichnungen anderer Regeln werden abgelehnt. Eine neue Regel braucht deshalb ein neues Skript in `SCRIPTS`, das sie benutzt; bestehende Skripte ändert niemand.
|
|
|
|
|
|
|
|
- Gäste schicken nur Aktionen, ohne Spielernummer. Der Host macht daraus Befehle für den Spieler der Verbindung und nimmt höchstens `MAX_ACTIONS_PER_TICK` pro Spieler und Takt an.
|
|
|
|
|
|
|
|
- Die Reichweite der Spitzhacke prüft nur die Hülle des eigenen Spielers. Figuren laufen außerhalb des Gleichschritts, also kennt der Kern ihre Position nicht. Ein veränderter Client könnte deshalb aus der Ferne graben. Für ein Koop-Spiel unter Freunden nehmen wir das hin.
|
|
|
|
|
|
|
|
|
|
|
|
## Regeln für Brücke und Hülle
|
|
|
|
## 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/`.
|
|
|
|
- Die Brücke übersetzt nur. Neue Spielregeln gehören in den Kern, nie in `bridge/` oder `game/`.
|
|
|
@@ -41,6 +50,9 @@ Drei Wächter prüfen das. `core/clippy.toml` sperrt Pfade wie `std::collections
|
|
|
|
- Alle Texte, die Spieler sehen, stehen in `game/i18n/texts.csv` (Deutsch und Englisch) und werden über `tr()` geholt.
|
|
|
|
- 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.
|
|
|
|
- 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.
|
|
|
|
- Godot erzeugt beim Import zu jedem Skript eine `.uid`-Datei. Sie gehört ins Archiv. Der Ordner `game/.godot/` gehört nicht hinein.
|
|
|
|
|
|
|
|
- Das Netzwerk liegt in `game/scripts/net_link.gd` (ENet, Port 24680) und `game/scripts/session_link.gd`. Nachrichten des Kerns gehen zuverlässig und in Reihenfolge über Kanal 0, Positionen der Figuren unzuverlässig über Kanal 1. Eine Verbindung schließt `NetLink.close_peer` mit `peer_disconnect_later`, damit wartende Nachrichten wie eine Ablehnung noch ankommen.
|
|
|
|
|
|
|
|
- Nur der Host speichert. Pausieren gibt es nur ohne Gäste, Laden mit F9 nur beim Spielen allein.
|
|
|
|
|
|
|
|
- Tests mit Netzwerk lauschen nur auf `127.0.0.1` und lassen das System den Port wählen (Port 0), damit sie nie an einem belegten Port scheitern.
|
|
|
|
|
|
|
|
|
|
|
|
## Prüfen
|
|
|
|
## Prüfen
|
|
|
|
|
|
|
|
|
|
|
@@ -57,6 +69,8 @@ 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.
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Der Test `game/tests/test_two_instances.gd` startet einen zweiten Godot-Prozess als Gast (`game/tools/guest_bot.gd`) und prüft, dass beide Welten gleich bleiben. Er braucht deshalb die gebaute Brücke und den Import wie alle anderen Tests der Hülle.
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
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:
|
|
|
|
Für Änderungen am Aussehen gibt es ein Werkzeug, das kurz ein Fenster öffnet und ein Bildschirmfoto speichert:
|
|
|
@@ -69,6 +83,18 @@ godot --path game -s res://tools/screenshot.gd -- <Pfad der PNG-Datei>
|
|
|
|
|
|
|
|
|
|
|
|
`play.bat` im Hauptordner baut die Brücke und startet das Spiel. Spielstand, Spielerschlüssel und Aufzeichnungen liegen unter `%APPDATA%\Godot\app_userdata\Grovewright`.
|
|
|
|
`play.bat` im Hauptordner baut die Brücke und startet das Spiel. Spielstand, Spielerschlüssel und Aufzeichnungen liegen unter `%APPDATA%\Godot\app_userdata\Grovewright`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Argumente hinter `play.bat` gehen an das Spiel:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Argument | Wirkung |
|
|
|
|
|
|
|
|
|---|---|
|
|
|
|
|
|
|
|
| `--profile=NAME` | Eigener Ordner unter `profiles\NAME` für Schlüssel, Spielstand und Aufzeichnungen. Zwei Fenster auf einem Rechner brauchen zwei Profile, sonst sind sie derselbe Spieler. |
|
|
|
|
|
|
|
|
| `--name=NAME` | Name des Spielers |
|
|
|
|
|
|
|
|
| `--solo`, `--host` | Startet ohne Menü allein beziehungsweise mit offener Welt |
|
|
|
|
|
|
|
|
| `--port=PORT` | Port einer offenen Welt |
|
|
|
|
|
|
|
|
| `--join=ADRESSE` | Tritt ohne Menü einem Host bei; die Adresse darf auf `:PORT` enden |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`play-zweites-fenster.bat` startet ein zweites Fenster mit dem Profil `zweites-fenster`.
|
|
|
|
|
|
|
|
|
|
|
|
## Sprache
|
|
|
|
## Sprache
|
|
|
|
|
|
|
|
|
|
|
|
- Code, Bezeichner und Kommentare im Code: Englisch.
|
|
|
|
- Code, Bezeichner und Kommentare im Code: Englisch.
|
|
|
|