Files
pirate-dice/README.md
2026-09-07 18:07:53 +02:00

86 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Liar's Dice 3D
Würfel-Bluffspiel in Godot 4.7 mit echter 3D-Physik, Mehrspieler über Raum-Codes,
KI-Bots und einem Booster-System aus Buffs und Debuffs.
## Starten
godot --path . # oder das Projekt im Godot-Editor öffnen
Das Startmenü hat drei Punkte:
* **Einzelspieler** – nur die Bot-Anzahl (1–7) einstellen und starten. Es wird
kein Netzwerk geöffnet.
* **Mehrspieler** – nur den Namen eintragen, dann **Hosten** oder
**Beitreten**. Hosten führt direkt in die Lobby; dort steht der Code.
Beitreten fragt zuerst nach dem Code. Niemand braucht eine IP oder eine
Portfreigabe.
* **Lobby** – zeigt den Code, wer schon da ist und die Bot-Anzahl. Nur der
Host stellt die Bots ein und startet, sobald mindestens 2 Teilnehmer
zusammen sind (Menschen und Bots zusammengezählt, maximal 8).
* **Beenden** – schließt das Spiel.
## Mehrspieler: wie es zusammenhängt
Die Partie läuft nicht beim Host, sondern auf `pirate-dice.marha.de`:
Spieler ──wss://443──> ein Serverprozess ──> Raum MQG4 (SubViewport + World3D)
└──> Raum 4YPV (SubViewport + World3D)
* **Ein Prozess, ein Port.** Der Server trägt alle Räume gleichzeitig und
spricht WebSocket. Traefik reicht das auf 443 durch, es muss kein Port
freigegeben werden.
* **Ein Raum** ist ein Knoten unter `/root/Main/Raeume/<CODE>`. Darin ein
SubViewport mit `own_world_3d` – nur so hat jede Partie ihren eigenen
Physikraum, sonst lägen alle Würfel im selben.
* Die Knotennamen sind auf Server und Client gleich. Daran hängt das Ziel
jedes RPC, deshalb dürfen sie nicht auseinanderlaufen.
* Broadcasts (`rpc`) würden alle Räume treffen. Deshalb geht alles gezielt per
`rpc_id` an die Peers des eigenen Raums.
* Der Server sitzt nicht mit am Tisch: `local_seat` bleibt −1, kein HUD.
* Der **Host** ist der erste Spieler im Raum. Geht er, rückt der nächste nach.
Nur er stellt die Bots ein und startet.
* Der letzte macht das Licht aus: verlässt der letzte Spieler den Raum, wird er
samt Code sofort abgeräumt.
Gemessen mit sechs gleichzeitigen Partien zu acht Plätzen: **3,7 MB je Raum**,
im Leerlauf unter 1 % eines Kerns, kurze Spitzen beim Würfelwurf.
## Lokal entwickeln
make server # Spielserver auf :8000, trägt alle Räume
make dev # Spiel, zeigt auf den lokalen Server
Ohne `PIRATE_DICE_SERVER` zeigt das Spiel auf `wss://pirate-dice.marha.de`.
## Auf dem Server
git pull
make prod # baut und startet, holt Godot selbst
make logs
make down
Mehr ist nicht nötig. Der Docker-Build lädt Godot 4.7.2 herunter (Version steht
im `Dockerfile`), importiert das Projekt einmal vor und startet den Server.
`restart: unless-stopped` bringt ihn nach einem Neustart von selbst wieder hoch.
Es muss kein Port freigegeben werden: alles läuft als WebSocket über Traefik
auf 443.
## Aufbau
| Datei | Inhalt |
|---|---|
| `scripts/net.gd` | Autoload: WebSocket-Verbindung, Räume, Lobby, Spielstart |
| `scripts/boosters.gd` | Autoload: Booster-Katalog |
| `scripts/game.gd` | Spiellogik (host-autoritativ), RPCs, Zustandsabgleich |
| `scripts/table.gd` | Aufbau der 3D-Szene: Tisch, Würfelzonen, Becher, Kamera |
| `scripts/die.gd` | Physik-Würfel, Ablesen der Augenzahl aus der Ruhelage |
| `scripts/ai.gd` | Bot-Entscheidungen (Binomialabschätzung für Gebot/Anfechtung) |
| `scripts/hud.gd` | Spiel-UI |
| `scripts/menu.gd` | Startmenü und Lobby |
Die gesamte Spiellogik und die Würfelphysik laufen beim Host. Clients erhalten
nur ihre eigenen Würfel als Transform-Stream, gegnerische Werte erst beim
Aufdecken – Mitlesen fremder Würfel ist damit nicht möglich.