Der Client steckte die Partie in einen SubViewport. Der rendert mit der
Basisaufloesung 1280x720 und wurde danach hochskaliert - das Bild wurde
matschig und die Kantenglaettung fiel weg. Den eigenen Physikraum braucht
aber nur der Server, weil dort viele Partien nebeneinander laufen. Also
bekommt nur er SubViewports; der Client haengt die Partie direkt in die
Szene. Die Knotennamen bleiben gleich, daran haengt das RPC-Ziel.
Der Healthcheck oeffnete alle 30 Sekunden eine nackte TCP-Verbindung auf
den WebSocket-Port. Der Server lehnte sie ab ("Missing or invalid header
'upgrade'"), und dabei ging reproduzierbar ein Paket an einen echten
Spieler verloren. Traefik braucht den Check nicht, also raus damit.
Blieb ein seltener Verlust des Startpakets: der Spieler sass in der Lobby,
waehrend die anderen spielten. Der Server legt jetzt nach, bis jeder den
Start quittiert hat.
Ein Verbindungsabbruch im Menue lud ausserdem die Szene neu und warf die
Meldung dazu gleich wieder weg.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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 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 mitown_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 perrpc_idan die Peers des eigenen Raums. - Der Server sitzt nicht mit am Tisch:
local_seatbleibt −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://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.