62 lines
7.4 KiB
Markdown
62 lines
7.4 KiB
Markdown
# Projektplan: Audiopoker (Bevy + Wasm)
|
||
|
||
## Zielsetzung
|
||
Ein barrierefreies Multiplayer-Pokergame für blinde Spieler, das primär über Audio (TTS & SFX) bedient wird. Das Spiel wird via Webbrowser aufgerufen und auf WebAssembly kompiliert.
|
||
|
||
## Technologie-Stack
|
||
- **Engine:** Bevy (Rust)
|
||
- **Target:** WebAssembly (Wasm)
|
||
- **Networking:** WebSockets für die Synchronisation des Spielzustands.
|
||
- **Audio-Output:** Web Speech API (via JS-Bindings) für Text-to-Speech, `bevy_audio` für Soundeffekte.
|
||
- **Input:** Tastatur-zentrierte Steuerung (Tab/Space/Enter).
|
||
|
||
## Modul-Struktur
|
||
- `core::logic`: Reine Poker-Logik (Deck, Hand-Evaluation, Betting) ohne grafische Abhängigkeiten.
|
||
- `core::network`: Netzwerkprotokoll und WebSocket-Handhabung für Multiplayer-Synchronisation.
|
||
- `audio::tts`: Interface zur Web Speech API für dynamisches Sprechen von Spielereignissen.
|
||
- `audio::sfx`: Sound-Manager für atmosphärische Effekte (Chips, Karten mischen).
|
||
- `ui_minimal`: Minimalistische Darstellung, optimiert für Barrierefreiheit und geringen Ressourcenverbrauch.
|
||
|
||
## Implementierungsphasen
|
||
|
||
### Phase 1: Fundament & Core Logic (MVP)
|
||
- [x] Projektstruktur aufsetzen (`Cargo.toml`; Modul-Struktur `core`/`audio` bereinigt und verdrahtet).
|
||
- [x] **Poker Engine**: Hand-Rankings (inkl. Wheel-Straight, 7-Karten-Bestbewertung), Deck-Shuffling/Draw und einfache Betting-Logik (Fold/Check/Call/Raise, All-In) implementiert und getestet.
|
||
- [x] **Audio-Grundlagen**: `audio::tts` ruft die Web Speech API korrekt an (`SpeechSynthesisUtterance`); auf nativen Targets Dummy-Ausgabe für Tests.
|
||
- [x] Bevy-`App`-Grundgerüst aufgesetzt: `AudiopokerPlugin` (`src/game_plugin.rs`) verdrahtet `core::game`/`core::logic` und `audio` über Bevy-Messages (`Announce`, `PlaySfx`) mit `Startup`/`Update`-Systemen. API-Stand: Bevy 0.19 (`Message`/`MessageWriter`/`MessageReader`/`add_message`, seit 0.17 getrennt von Observer-`Event`s). **Bitte lokal mit `cargo check`/`cargo run` verifizieren**, da hier kein zu Bevy 0.19 passender Compiler zur Verfügung stand.
|
||
|
||
## Projektstruktur (seit Phase 2: Cargo-Workspace)
|
||
- `core/` (Lib `audiopoker_core`): `logic`, `game`, `network` - unverändert engine-unabhängig, jetzt von Client *und* Server genutzt.
|
||
- `client/` (Bin `audiopoker_client`): Bevy/Wasm, bisheriger Inhalt von `src/`.
|
||
- `server/` (Bin `audiopoker_server`): neuer nativer WebSocket-Server (Tokio + tokio-tungstenite).
|
||
|
||
### Phase 2: Networking & Multiplayer
|
||
- [x] **Server-Architektur**: `server/src/table.rs` (`TableActor`, Actor-Modell: ein Tokio-Task pro Tisch, kein geteilter Mutex für den Spielzustand) + `server/src/lobby.rs` (Tisch-Registry, legt Tische on-demand per Namen an). `server/src/main.rs` nimmt WebSocket-Verbindungen an (`tokio-tungstenite`) und verbindet sie mit dem passenden Tisch.
|
||
- [x] **Netzwerkprotokoll**: `core::network::{ClientMessage, ServerMessage}` neu entworfen, sodass der Server dieselben Announce-/PlaySfx-"Häppchen" verschickt, die der lokale Client schon per TTS/SFX verarbeitet (`GameManager::take_action` liefert sie direkt). Erhöhungsbeträge werden bewusst serverseitig festgelegt (kein clientseitig frei wählbarer Raise-Betrag).
|
||
- [x] **Multiplayer-Lobby/Tischsuche (einfache Variante)**: Tischname im `JoinTable` dient als Suchbegriff; unbekannte Namen legen automatisch einen neuen Tisch an. Kein Auflisten aller offenen Tische (`ListTables`) - falls gewünscht, wäre das die nächste Ausbaustufe.
|
||
- **Getestet**: `cargo test -p audiopoker_core` (10 Tests) und ein Ende-zu-Ende-Smoke-Test mit zwei echten WebSocket-Clients (Python) gegen den laufenden `audiopoker_server` liefen hier erfolgreich durch (kompletter Hand-Durchlauf Pre-Flop bis Showdown, korrekte Sieger-Ermittlung).
|
||
- [x] **Client-Anbindung an den Server**: `client/src/network.rs` verbindet sich per `web_sys::WebSocket` mit `audiopoker_server` (Non-Send-Resource, da die JS-Callbacks nicht `Send` sind). `game_plugin.rs` spielt jetzt nicht mehr lokal/offline, sondern hält nur noch eine schlanke `NetworkGameView` (eigene Hole Cards, sichtbare Community Cards, wer am Zug ist) und schickt Aktionen als `ClientMessage` an den Server; `ServerMessage`s werden zu `Announce`/`PlaySfx` übersetzt (gleicher Audio-Pfad wie zuvor lokal). Server-Bugfix nebenbei gefixt: Aktionen nach `Round::Showdown` wurden bisher nicht abgelehnt - jetzt gibt's dafür einen `Error` plus ein neues `ServerMessage::HandFinished`-Signal, mit dem Clients die Eingabe sperren.
|
||
- Server-/Tisch-/Spielername sind über Browser-URL-Parameter steuerbar (`?server=...&table=...&name=...`), damit sich mehrere Browser-Tabs bequem als unterschiedliche Spieler an denselben Tisch hängen lassen.
|
||
- **Wichtiger Verifikationshinweis**: Der eigentliche `web_sys::WebSocket`-Code (`#[cfg(target_arch = "wasm32")]`) konnte hier nicht kompiliert werden (kein wasm32-Std verfügbar). Ein natives `cargo check -p audiopoker_client` prüft nur den `not(wasm32)`-Dummy-Zweig, NICHT den echten WebSocket-Pfad! Bitte zusätzlich `cargo check --target wasm32-unknown-unknown -p audiopoker_client` (Target ggf. per `rustup target add wasm32-unknown-unknown` installieren) ausführen, um das wirklich zu verifizieren. Der plattformunabhängige Teil (`ClientMessage`/`ServerMessage`-Nutzung, Query-Parameter-Parsing) wurde hier isoliert gegen den nativen Dummy-Zweig getestet und funktioniert.
|
||
- [ ] Tisch-Übersicht/`ListTables` für echte Tischsuche (aktuell nur "Name kennen und beitreten").
|
||
- [ ] Neue Hand nach Showdown starten (serverseitig; der Client sperrt nach `HandFinished` nur die Eingabe).
|
||
|
||
### Phase 3: Audio Experience & UI
|
||
- [x] **TTS-Logik verfeinert**: `GameManager::take_action` erzeugt kontextuelle Ansagen (Aktion des Spielers, Rundenwechsel inkl. aufgedeckter Community Cards, Showdown-Gewinner mit Hand-Kategorie, "wer ist am Zug"). Karten werden über `Card`/`Suit`-`Display` sprachfreundlich ausgegeben ("König Herz").
|
||
- [x] **Soundeffekte eingebunden** (Event-Ebene): `PlaySfx`-Messages für "shuffle", "chip", "fold", "flip" werden an den entsprechenden Stellen ausgelöst und von `audio::sfx` entgegengenommen. Echte Audiodateien/`bevy_audio`-Wiedergabe fehlen noch (keine Assets im Projekt) – aktuell Log-Ausgabe als Platzhalter.
|
||
- [x] **Minimalistische, tastaturzentrierte Steuerung**: `Tab` wählt zwischen Fold/Call-Check/Raise, `Leertaste`/`Enter` bestätigt (siehe `game_plugin::handle_player_input`). Kein grafisches UI nötig, da das Spiel primär auf Audio-Feedback setzt.
|
||
- [ ] Mehrspieler-lokal-Testbarkeit über die Konsole hinaus (aktuell nur 2 fest verdrahtete Spieler; echte Steuerung pro Spieler braucht Networking, siehe Phase 2).
|
||
- [ ] Neue Hand nach Showdown starten (aktuell stoppt die Eingabe-Verarbeitung nach `Round::Showdown`).
|
||
|
||
### Phase 4: Polishing & Testing
|
||
- [ ] Barrierefreiheits-Audit (Tastatur-Flow ohne Maus).
|
||
- [ ] Latenztests im Multiplayer.
|
||
- [ ] WebAssembly Deployment Vorbereitung.
|
||
|
||
## Lokal zu zweit testen (nach Client-Netzwerk-Anbindung)
|
||
1. Server starten: `cargo run -p audiopoker_server` (lauscht standardmäßig auf `ws://0.0.0.0:9001`, überschreibbar über die Umgebungsvariable `AUDIOPOKER_ADDR`).
|
||
2. Client für Wasm bauen/starten (z. B. über `trunk serve` o. ä. - noch nicht Teil dieses Repos, siehe offene Punkte) und zweimal im Browser öffnen:
|
||
- Tab 1: `?server=ws://127.0.0.1:9001&table=tisch1&name=Anna`
|
||
- Tab 2: `?server=ws://127.0.0.1:9001&table=tisch1&name=Ben`
|
||
3. Sobald beide beigetreten sind, startet die Hand automatisch; Steuerung wie gehabt über Tab/Space/Enter.
|