Add full multi-step decision workflow for SINGLE_UNCAPPED and DOUBLE_UNCAPPED outcomes, replacing the previous stub that fell through to basic single/double advancement. The decision tree follows the same interactive pattern as X-Check resolution with 5 phases: lead runner advance, defensive throw, trail runner advance, throw target selection, and safe/out speed check. - game_models.py: PendingUncappedHit model, 5 new decision phases - game_engine.py: initiate_uncapped_hit(), 5 submit methods, 3 result builders - handlers.py: 5 new WebSocket event handlers - ai_opponent.py: 5 AI decision stubs (conservative defaults) - play_resolver.py: Updated TODO comments for fallback paths - 80 new backend tests (2481 total): workflow (49), handlers (23), truth tables (8) - Fix GameplayPanel.spec.ts: add missing Pinia setup, fix component references Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
127 lines
3.2 KiB
Markdown
127 lines
3.2 KiB
Markdown
# WebSocket Module - Real-Time Game Communication
|
|
|
|
## Purpose
|
|
|
|
Real-time bidirectional communication using Socket.io. Primary interface between players and game engine - all game actions flow through WebSocket events.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Client (Browser)
|
|
↓ Socket.io
|
|
ConnectionManager
|
|
↓
|
|
Event Handlers
|
|
↓
|
|
Game Engine → StateManager → Database
|
|
↓
|
|
Broadcast to All Players
|
|
```
|
|
|
|
## Structure
|
|
|
|
```
|
|
app/websocket/
|
|
├── connection_manager.py # Connection lifecycle & broadcasting
|
|
└── handlers.py # Event handler registration (20 handlers)
|
|
```
|
|
|
|
## ConnectionManager
|
|
|
|
Manages connections, rooms, and broadcasting.
|
|
|
|
**State**:
|
|
- `user_sessions: Dict[str, str]` - sid → user_id
|
|
- `game_rooms: Dict[str, Set[str]]` - game_id → sids
|
|
|
|
**Key Methods**:
|
|
```python
|
|
await manager.connect(sid, user_id)
|
|
await manager.disconnect(sid)
|
|
await manager.join_game(sid, game_id, role)
|
|
await manager.broadcast_to_game(game_id, event, data)
|
|
await manager.emit_to_user(sid, event, data)
|
|
```
|
|
|
|
## Event Handlers (20 Total)
|
|
|
|
### Connection Events
|
|
- `connect` - JWT authentication
|
|
- `disconnect` - Cleanup sessions
|
|
|
|
### Game Flow
|
|
- `join_game` - Join game room
|
|
- `start_game` - Initialize game state
|
|
- `get_game_state` - Request current state
|
|
- `get_box_score` - Get statistics
|
|
|
|
### Decision Submission
|
|
- `submit_defensive_decision` - Defense strategy
|
|
- `submit_offensive_decision` - Offense strategy
|
|
|
|
### Manual Outcome Flow
|
|
- `roll_dice` - Roll dice for play
|
|
- `submit_manual_outcome` - Submit card result
|
|
|
|
### Substitutions
|
|
- `submit_pinch_hitter` - Batting substitution
|
|
- `submit_pitching_change` - Pitcher substitution
|
|
- `submit_defensive_replacement` - Field substitution
|
|
|
|
### Uncapped Hit Decisions
|
|
- `submit_uncapped_lead_advance` - Lead runner advance choice (offensive)
|
|
- `submit_uncapped_defensive_throw` - Throw to base choice (defensive)
|
|
- `submit_uncapped_trail_advance` - Trail runner advance choice (offensive)
|
|
- `submit_uncapped_throw_target` - Throw at lead or trail (defensive)
|
|
- `submit_uncapped_safe_out` - Declare safe or out from card (offensive)
|
|
|
|
### Lineup
|
|
- `get_lineup` - Get team lineup
|
|
|
|
## Event Pattern
|
|
|
|
```python
|
|
@sio.event
|
|
async def event_name(sid, data):
|
|
try:
|
|
# 1. Validate input
|
|
# 2. Get game state
|
|
# 3. Process action
|
|
# 4. Broadcast result
|
|
except Exception as e:
|
|
await emit_error(sid, str(e))
|
|
```
|
|
|
|
## Key Events Emitted
|
|
|
|
| Event | Recipient | Purpose |
|
|
|-------|-----------|---------|
|
|
| `game_state_update` | Room | State changed |
|
|
| `play_resolved` | Room | Play completed |
|
|
| `decision_required` | User | Need input |
|
|
| `error` | User | Error occurred |
|
|
| `dice_rolled` | Room | Dice result |
|
|
|
|
## Common Tasks
|
|
|
|
### Broadcasting State Update
|
|
```python
|
|
state_dict = state.model_dump()
|
|
await manager.broadcast_to_game(game_id, "game_state_update", state_dict)
|
|
```
|
|
|
|
### Error Handling
|
|
```python
|
|
await manager.emit_to_user(sid, "error", {"message": str(e)})
|
|
```
|
|
|
|
## References
|
|
|
|
- **Protocol Spec**: `../../.claude/implementation/websocket-protocol.md`
|
|
- **Game Engine**: See `../core/CLAUDE.md`
|
|
- **Frontend Integration**: See `frontend-sba/composables/CLAUDE.md`
|
|
|
|
---
|
|
|
|
**Handlers**: 20/20 implemented | **Updated**: 2026-02-11
|