Fragebogen und Regeln an das Spiel angeglichen
Der Fragebogen nennt die Statuszeile oben rechts. Er sagt wieder, wann eine Aufzeichnung entsteht, dass eine angehaltene Sitzung keine hinterlässt und wo die Logs liegen, und er gibt bessere Hinweise für Verbindungen übers Internet. CLAUDE.md beschreibt jetzt auch: - die Übernahme der Host-Welt durch Gäste, - den festen Anfang von Gruß und Ablehnung, - die Pausenregel und das Anhalten bei einem Kernfehler, - die erlaubten Profilnamen, - die gesperrte Brücken-DLL bei laufendem Spiel. play-zweites-fenster.bat gibt weitere Argumente an das Spiel weiter. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@ Alle Spieler simulieren die Welt selbst und tauschen nur Befehle aus (Gleichschr
|
||||
- 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.
|
||||
- Die Welt ändert sich nur durch einen `Command` in `World::step`. Ausnahmen sind das Laden eines Speicherstands mit `World::load`, das alle Spieler abmeldet, und die Übernahme der Welt des Hosts mit `World::from_snapshot`, die ein Gast beim Beitritt und nach einer Abweichung macht.
|
||||
- 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`.
|
||||
@@ -36,8 +36,8 @@ Drei Wächter prüfen das. `core/clippy.toml` sperrt Pfade wie `std::collections
|
||||
## 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`.
|
||||
- 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 die Hülle speichert die Aufzeichnung der abgewichenen Welt.
|
||||
- Die Nachrichten stehen in `core/src/protocol.rs`. Wer eine Nachricht ändert, erhöht `PROTOCOL_VERSION`. Der Anfang des Grußes und die ganze Ablehnung ändern sich dabei nie, damit Spiele jeder Version einander noch sagen können, dass sie nicht zusammenpassen; `core/tests/golden.rs` hält beides fest.
|
||||
- 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.
|
||||
@@ -50,8 +50,10 @@ 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.
|
||||
- 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.
|
||||
- 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.
|
||||
- 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. `NetLink.close_peer` schließt eine Verbindung mit `peer_disconnect_later`, damit wartende Nachrichten wie eine Ablehnung noch ankommen.
|
||||
- Nur der Host speichert. Laden mit F9 geht nur ohne geöffnete Welt („Allein spielen“).
|
||||
- Eine Pause beginnt nur ohne Gäste und lässt sich immer beenden. Nimmt der Host einen Gast an, endet sie; eine bloße Verbindung ohne Gruß beendet sie nicht.
|
||||
- Hält der Kern mit einem internen Fehler an, schließt ein Host seine Welt für Gäste, und ein Gast kehrt ins Menü zurück. Eine angehaltene Sitzung hinterlässt keine Aufzeichnung.
|
||||
- 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
|
||||
@@ -71,7 +73,7 @@ Der erste Import in einem frischen Checkout stürzt mit Godot 4.7.2 und der Rust
|
||||
|
||||
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, Aufzeichnungen oder Nachrichten betroffen, erhöhst du die Versionskonstante, die die Fehlermeldung nennt (`SNAPSHOT_VERSION`, `RECORDING_VERSION` oder `PROTOCOL_VERSION`). 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:
|
||||
|
||||
@@ -83,17 +85,19 @@ 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`.
|
||||
|
||||
Ein laufendes Spiel hält `target\debug\grovewright_bridge.dll` offen. Ändern sich danach Brücke oder Kern, scheitert `cargo build` mit „Zugriff verweigert (os error 5)“, bis alle Spielfenster geschlossen sind.
|
||||
|
||||
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. |
|
||||
| `--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. Erlaubt sind bis zu 32 Zeichen aus A bis Z, a bis z, Ziffern, `-` und `_`; einen anderen Namen übergeht das Spiel mit einer Warnung im Log und nimmt das Standardprofil. |
|
||||
| `--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`.
|
||||
`play-zweites-fenster.bat` startet ein zweites Fenster mit dem Profil `zweites-fenster`. Weitere Argumente gibt es ebenfalls an das Spiel weiter, etwa `--name=Zweiter`.
|
||||
|
||||
## Sprache
|
||||
|
||||
|
||||
+13
-10
@@ -6,10 +6,13 @@ Mit M1c teilen sich bis zu vier Spieler eine Welt. Jeder Rechner rechnet die gan
|
||||
|
||||
1. Doppelklick auf `play.bat`. Im Menü trägst du deinen Namen ein.
|
||||
2. **Allein:** „Allein spielen“ setzt deinen gespeicherten Stand fort.
|
||||
3. **Als Host:** „Welt öffnen“ setzt deinen Stand fort und lässt Gäste zu. Oben links steht der Port, normalerweise 24680. Beim ersten Mal fragt Windows, ob Godot im Netzwerk erreichbar sein darf. Erlaube es für private Netzwerke.
|
||||
4. **Als Gast:** Trag die Adresse des Hosts ein und klick auf „Beitreten“. Im selben Heimnetz ist das die IPv4-Adresse des Host-Rechners, etwa `192.168.178.20`; der Host findet sie mit dem Befehl `ipconfig`. Übers Internet braucht der Host eine Portfreigabe für UDP-Port 24680 in seinem Router oder ein virtuelles Netz wie Tailscale oder ZeroTier; dann gilt die Adresse aus diesem Netz.
|
||||
5. **Zwei Fenster auf einem Rechner:** Starte mit `play.bat` und klick auf „Welt öffnen“. Dann Doppelklick auf `play-zweites-fenster.bat`, Adresse `127.0.0.1`, „Beitreten“. Das zweite Fenster hat ein eigenes Profil und ist deshalb ein zweiter Spieler.
|
||||
6. Steuerung wie in M1b: WASD laufen, linke Maustaste Stein schlagen. Nur der Host speichert (F5 und automatisch). Esc pausiert nur, solange keine Gäste da sind; F9 lädt nur beim Spielen allein.
|
||||
3. **Als Host:** „Welt öffnen“ setzt deinen Stand fort und lässt Gäste zu. Oben rechts steht dann die Statuszeile mit dem Port, etwa „Welt offen auf Port 24680 · Spieler: 1“. Beim ersten Mal fragt Windows, ob Godot im Netzwerk erreichbar sein darf. Erlaube es für private Netzwerke.
|
||||
4. **Als Gast:** Trag die Adresse des Hosts ein und klick auf „Beitreten“. Alle brauchen denselben Stand des Spiels, sonst lehnt der Host den Gast ab.
|
||||
- Im selben Heimnetz ist die Adresse die IPv4-Adresse des Host-Rechners, etwa `192.168.178.20`; der Host findet sie mit dem Befehl `ipconfig`.
|
||||
- Übers Internet geht es am einfachsten mit einem virtuellen Netz wie Tailscale oder ZeroTier; dann gilt die Adresse des Hosts aus diesem Netz. Windows stuft solche Netze oft als öffentlich ein. Kommt keine Verbindung zustande, erlaube Godot in der Windows-Firewall auch für öffentliche Netzwerke.
|
||||
- Ohne virtuelles Netz braucht der Host eine Portfreigabe für UDP-Port 24680 in seinem Router, und der Gast trägt die öffentliche IP-Adresse des Hosts ein. Bei Anschlüssen ohne eigene öffentliche IPv4-Adresse, etwa mit DS-Lite, geht das nicht.
|
||||
5. **Zwei Fenster auf einem Rechner:** Starte mit `play.bat` und klick auf „Welt öffnen“. Dann Doppelklick auf `play-zweites-fenster.bat`, einen anderen Namen eintragen, Adresse `127.0.0.1`, „Beitreten“. Das zweite Fenster hat ein eigenes Profil und ist deshalb ein zweiter Spieler. Holst du zwischendurch eine neue Version des Spiels, schließ vorher alle Fenster, sonst scheitert der Start mit „Zugriff verweigert“.
|
||||
6. Steuerung wie in M1b: WASD laufen, linke Maustaste Stein schlagen. Nur der Host speichert (F5 und automatisch). Esc pausiert nur, solange keine Gäste da sind; kommt ein Gast, endet die Pause. F9 lädt nur nach „Allein spielen“.
|
||||
|
||||
## Fragen
|
||||
|
||||
@@ -17,12 +20,12 @@ Mit M1c teilen sich bis zu vier Spieler eine Welt. Jeder Rechner rechnet die gan
|
||||
2. Wirken deine Schläge als Gast spürbar später als beim Host? Stört das?
|
||||
3. Bewegen sich die Figuren der anderen gleichmäßig, oder ruckeln und springen sie?
|
||||
4. Erkennst du an den Namen über den Figuren, wer wer ist?
|
||||
5. Erschien irgendwann die Meldung „Welt mit dem Host abgeglichen“? Wenn ja: Was habt ihr kurz davor getan? Diese Meldung bedeutet, dass zwei Welten auseinandergelaufen sind. Das ist ein Fehler, den ich finden muss.
|
||||
5. Erschien bei einem Gast irgendwann die Meldung „Welt mit dem Host abgeglichen“? Nur Gäste sehen sie. Wenn ja: Was habt ihr kurz davor getan? Diese Meldung bedeutet, dass zwei Welten auseinandergelaufen sind. Das ist ein Fehler, den ich finden muss.
|
||||
6. Wenn ein Gast die Welt verlässt und später wiederkommt: Hat er seine Steine noch?
|
||||
7. Ist dir etwas Merkwürdiges passiert? Schick mir dann die neuesten Dateien aus dem Ordner `recordings`:
|
||||
- Beim Host liegt er unter `%APPDATA%\Godot\app_userdata\Grovewright\recordings`.
|
||||
- Beim zweiten Fenster liegt er unter `profiles\zweites-fenster\recordings` im selben Ordner.
|
||||
- Nach einer Abgleich-Meldung hebt der Gast dort die Aufzeichnung der abgewichenen Welt auf.
|
||||
- Nach einem Absturz schick stattdessen den Ordner `logs` daneben, und zwar bevor du das Spiel erneut startest.
|
||||
7. Ist dir etwas Merkwürdiges passiert? Dann schick mir die neuesten Dateien aus dem Ordner `recordings`; mit ihnen spiele ich die Sitzung exakt nach.
|
||||
- Für ein Fenster aus `play.bat` liegt er unter `%APPDATA%\Godot\app_userdata\Grovewright\recordings`, für das zweite Fenster unter `%APPDATA%\Godot\app_userdata\Grovewright\profiles\zweites-fenster\recordings`.
|
||||
- Eine Aufzeichnung entsteht erst, wenn du das Fenster schließt oder mit F9 einen Stand lädst, beim Gast auch, wenn seine Sitzung endet, etwa weil der Host die Welt schließt. Schließ das Fenster also, bevor du die Datei suchst.
|
||||
- Nach der Meldung „Welt mit dem Host abgeglichen“ legt der Gast dort zusätzlich die Aufzeichnung der abgewichenen Welt ab.
|
||||
- Nach einem Absturz oder nach der Meldung „Die Simulation wurde angehalten“ gibt es von dieser Sitzung keine Aufzeichnung. Schick mir dann den Ordner `%APPDATA%\Godot\app_userdata\Grovewright\logs`, und zwar sofort, bevor du das Spiel erneut startest, denn jeder Start verdrängt ältere Logdateien. Alle Fenster eines Rechners schreiben in diesen einen Ordner.
|
||||
|
||||
Antworte formlos im Chat oder als Kommentar in Gitea.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@echo off
|
||||
rem Starts a second window with a profile of its own, so that it plays as a
|
||||
rem second player on this machine, for example as a guest of the first one.
|
||||
call "%~dp0play.bat" --profile=zweites-fenster
|
||||
rem Further arguments go to the game as well, for example --name=Zweiter.
|
||||
call "%~dp0play.bat" --profile=zweites-fenster %*
|
||||
|
||||
Reference in New Issue
Block a user