Zusammenfassung der Änderungen:
1. GameState.cs - Neue Properties hinzugefügt:
- IsGameOver - zeigt an, dass das Spiel beendet ist
- WinnerId - ID des Gewinners
2. GameReducers.cs:
- OnProcessThrowResult setzt jetzt IsGameOver und WinnerId
- OnExecuteGameActionSuccess setzt jetzt IsGameOver und WinnerId
- OnStartGameSuccess setzt IsGameOver=false
- OnEndGameSuccess setzt IsGameOver=false
3. GameEffects.cs:
- HandleRecordThrow blockiert Eingaben wenn IsGameOver=true
- HandleExecuteGameAction blockiert Eingaben wenn IsGameOver=true
- EndGameAction wird nicht automatisch dispatcht - der Benutzer muss das Spiel explizit über die UI beenden
Verhalten jetzt:
- Wenn ProcessThrow oder ExecuteAction IsGameOver=true zurückgibt, wird der State auf IsGameOver=true gesetzt
- Die Tafel bleibt sichtbar mit dem Endergebnis
- Weitere Würfe/Actions werden blockiert
- Der Benutzer muss EndGameAction explizit über einen Button in der UI auslösen
Die UI muss jetzt GameState.IsGameOver und GameState.WinnerId nutzen, um:
1. Eingaben zu deaktivieren
2. Eine "Spiel beenden"-Schaltfläche anzuzeigen
Zusammenfassung der Fixes:
1. Fix 1 (HandlePinClick und HandleNumberClick): _hasModifiedPins = true wird jetzt VOR dem Dispatch gesetzt, um zu verhindern, dass OnGameStateChanged den Before-State während der Pin-Modifikation überschreibt.
2. Fix 2 (ConfirmThrow): Nach dem Dispatch wird explizit CaptureBeforeThrowState() aufgerufen. Das ist der wichtigste Fix:
- Nach RecordThrowAction Dispatch sind alle Reducer/Effects durchgelaufen
- Der State ist bereits mit den neuen Pin-Zuständen aktualisiert
- _beforeThrowState wird mit dem NEUEN Zustand für den nächsten Wurf erfasst
Vorher wurde _beforeThrowState nie nach einem Wurf aktualisiert (weil _hasModifiedPins zum falschen Zeitpunkt gesetzt war), sodass beim zweiten Wurf der stale Before-State verwendet wurde.
- IGameHubClient: client interface for SignalR messages
- GameHub: SignalR hub with group management for games/days
- GameHubService: scoped service wrapper with auto-reconnect
- GameEffects: broadcasts game start/end/state via SignalR
- EndGameAction: extended with winner info and final scores
- Program.cs: AddSignalR + MapHub configuration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extend Game entity with GameType, Status, StartedAt, CompletedAt, RowVersion
- Add GameConfiguration with RowVersion for optimistic concurrency
- Create IGamePersistenceService interface
- Implement GamePersistenceService with CRUD operations
- Create GameStateSerializationDto for JSON serialization
- Extend GameEffects with full persistence lifecycle:
- HandleStartGame: Creates game in DB
- HandleEndGame: Updates status to Completed/Aborted
- HandleLoadActiveGame: Recovery from page reload
- HandleRecordThrow: Debounced save (500ms)
- HandleSaveGameState: Explicit save with concurrency check
- Add migration ExtendGameEntity
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add UndoButton.razor as reusable component
- Refactor GameInputPanel to use UndoButton component
- Enhance GameEffects with proper UndoThrowAction handler
- IState injection for state access in effects
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Scoped services can't be resolved from singleton (GameDefinitionRegistry).
Logic services are stateless, so transient is appropriate.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>