mod planning
This commit is contained in:
parent
d2ee1c5193
commit
fab82fcde8
|
|
@ -850,7 +850,8 @@ Spiele laufen im Speicher auf der DayDetails-Seite ohne Browser-Reload.
|
|||
| Spiel-Ende | Auto-Ende + manuelle "Beenden" Option |
|
||||
| Strafen-Schnellwahl | Nur im Details-Tab, nicht in Eingabe/Tafel |
|
||||
| Multi-Game | Sequentiell - mehrere Spiele pro Tag, Liste sichtbar |
|
||||
| Persistenz | JSON in `Game.GameData` nach Spielende speichern |
|
||||
| Persistenz | **Nach jedem Wurf** in DB speichern (Game.GameData) |
|
||||
| Multi-User | Spielfortschritt in anderen Sessions via **SignalR** sichtbar |
|
||||
| Scheiss-Spiel Ende | Erster mit 0 Punkten **gewinnt**, andere bekommen Strafen nach Restpunkten |
|
||||
| Strafen-Berechnung | Fixbetrag pro Restpunkt (z.B. 0.10€ × 30 Punkte = 3.00€) |
|
||||
|
||||
|
|
@ -862,22 +863,55 @@ Spiele laufen im Speicher auf der DayDetails-Seite ohne Browser-Reload.
|
|||
| View-Wechsel | ViewMode-Enum + MudTabs (kein URL-Routing) |
|
||||
| Spieltyp-System | IGameDefinition in Domain, Registry in Application |
|
||||
| Pin-Komponenten | Port aus KoogleApp mit neuem Namespace |
|
||||
| Persistenz | In-Memory während Spiel → DB (Game.GameData) bei Ende |
|
||||
| Persistenz | **Nach jedem Wurf** → DB (Game.GameData JSON) |
|
||||
| Recovery | Bei Page-Load: aktives Spiel aus DB laden |
|
||||
| Multi-User Sync | **SignalR** für Echtzeit-Updates (Live-Tafel) |
|
||||
|
||||
## Existierende Entity
|
||||
## Game Entity (erweitern)
|
||||
|
||||
```csharp
|
||||
// Koogle.Domain/Entities/Game.cs - bereits vorhanden
|
||||
// Koogle.Domain/Entities/Game.cs - erweitern
|
||||
public class Game : BaseEntity
|
||||
{
|
||||
public string GameData { get; set; } = "{}"; // JSON für Spielergebnis
|
||||
public string GameData { get; set; } = "{}"; // JSON für kompletten Spielzustand
|
||||
public Guid DayId { get; set; }
|
||||
public Day Day { get; set; }
|
||||
public ICollection<GamePerson> GamePersons { get; set; }
|
||||
public Guid ClubId { get; set; }
|
||||
public Club Club { get; set; }
|
||||
|
||||
// NEU:
|
||||
public string GameType { get; set; } = ""; // "Training", "Shit"
|
||||
public GameStatus Status { get; set; } // Active, Completed, Aborted
|
||||
public DateTime? StartedAt { get; set; }
|
||||
public DateTime? CompletedAt { get; set; }
|
||||
}
|
||||
|
||||
public enum GameStatus { Active, Completed, Aborted }
|
||||
```
|
||||
|
||||
## GameData JSON Struktur (Beispiel Training)
|
||||
|
||||
```json
|
||||
{
|
||||
"gameType": "Training",
|
||||
"throwPanelState": {
|
||||
"throwsPerRound": 3,
|
||||
"throwMode": "Reposition",
|
||||
"totalThrowCounter": 42
|
||||
},
|
||||
"participants": {
|
||||
"playerIds": ["guid1", "guid2"],
|
||||
"currentPlayerIndex": 1
|
||||
},
|
||||
"gameModel": {
|
||||
"playerStatistics": {
|
||||
"guid1": { "throwCount": 21, "pinCount": 145, "circleCount": 2 },
|
||||
"guid2": { "throwCount": 21, "pinCount": 138, "circleCount": 1 }
|
||||
}
|
||||
},
|
||||
"undoStack": [ ... ]
|
||||
}
|
||||
// → GameType Property hinzufügen (string oder Enum)
|
||||
```
|
||||
|
||||
## Architektur
|
||||
|
|
@ -900,10 +934,11 @@ Web: Store/GameState/, Components/Game/
|
|||
| ☐ | H6 | UI | Game Setup Dialog | 4 |
|
||||
| ☐ | H7 | Integration | DayDetails Integration | 3 |
|
||||
| ☐ | H8 | Features | Undo/Redo | 3 |
|
||||
| ☐ | H9 | Features | Session Persistence | 2 |
|
||||
| ☐ | H9 | Persistenz | DB Persistence & Recovery | 4 |
|
||||
| ☐ | H9b | Sync | SignalR Live-Updates | 4 |
|
||||
| ☐ | H10 | Testing | Game Tests | 3 |
|
||||
|
||||
**Geschätzte Dateien: ~42 neue/modifizierte**
|
||||
**Geschätzte Dateien: ~48 neue/modifizierte**
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1166,16 +1201,66 @@ public record ShitGameModel
|
|||
|
||||
---
|
||||
|
||||
### **Phase H9: Session Persistence**
|
||||
### **Phase H9: DB Persistence & Recovery**
|
||||
|
||||
**Dateien:**
|
||||
1. `src/Koogle.Web/wwwroot/js/gameSession.js`
|
||||
2. `src/Koogle.Web/Store/GameState/GameEffects.cs` (erweitern)
|
||||
1. `src/Koogle.Application/Interfaces/IGamePersistenceService.cs`
|
||||
2. `src/Koogle.Application/Services/GamePersistenceService.cs`
|
||||
3. `src/Koogle.Web/Store/GameState/GameEffects.cs` (erweitern)
|
||||
4. `src/Koogle.Application/DTOs/GameStateDto.cs` (JSON-Serialisierung)
|
||||
|
||||
**Mechanismus:**
|
||||
- Bei State-Änderung: SessionStorage speichern
|
||||
- Bei Page-Load: SessionStorage prüfen
|
||||
- Wenn Session für aktuellen DayId existiert: Restore anbieten
|
||||
**Methoden:**
|
||||
- `SaveGameStateAsync(Guid gameId, GameState state)` - Nach jedem Wurf
|
||||
- `LoadActiveGameAsync(Guid dayId)` - Bei Page-Load
|
||||
- `GetCompletedGamesAsync(Guid dayId)` - Für Spiele-Liste
|
||||
|
||||
**Persistenz-Flow:**
|
||||
```
|
||||
1. Spiel starten → Game Entity mit Status=Active erstellen
|
||||
2. Nach jedem Wurf:
|
||||
- GameState → JSON serialisieren
|
||||
- Game.GameData updaten (Debounced, max 1x/500ms)
|
||||
3. Page Reload / Andere Session:
|
||||
- LoadActiveGameAsync(dayId)
|
||||
- Wenn Active Game existiert → GameState wiederherstellen
|
||||
4. Spiel beenden:
|
||||
- Status = Completed, CompletedAt = now
|
||||
- Finales GameData speichern
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **Phase H9b: SignalR Live-Updates**
|
||||
|
||||
**Dateien:**
|
||||
1. `src/Koogle.Web/Hubs/GameHub.cs`
|
||||
2. `src/Koogle.Web/Hubs/IGameHubClient.cs`
|
||||
3. `src/Koogle.Web/Store/GameState/GameEffects.cs` (erweitern für Broadcast)
|
||||
4. `src/Koogle.Web/Program.cs` (AddSignalR, MapHub)
|
||||
|
||||
**SignalR Hub:**
|
||||
```csharp
|
||||
public class GameHub : Hub<IGameHubClient>
|
||||
{
|
||||
public async Task JoinGame(Guid gameId)
|
||||
=> await Groups.AddToGroupAsync(Context.ConnectionId, gameId.ToString());
|
||||
|
||||
public async Task LeaveGame(Guid gameId)
|
||||
=> await Groups.RemoveFromGroupAsync(Context.ConnectionId, gameId.ToString());
|
||||
}
|
||||
|
||||
public interface IGameHubClient
|
||||
{
|
||||
Task GameStateUpdated(GameStateDto state);
|
||||
Task GameEnded(GameResultDto result);
|
||||
}
|
||||
```
|
||||
|
||||
**Flow:**
|
||||
1. Tafel-View öffnen → `JoinGame(gameId)`
|
||||
2. Nach jedem Wurf: DB Save → `Clients.Group(gameId).GameStateUpdated(state)`
|
||||
3. Andere Sessions empfangen Update → Reducer aktualisiert State
|
||||
4. Tafel-View schließen → `LeaveGame(gameId)`
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -1224,8 +1309,8 @@ public record ShitGameModel
|
|||
## Migration
|
||||
|
||||
```bash
|
||||
# GameType Property zu Game Entity hinzufügen
|
||||
dotnet ef migrations add AddGameType --project src/Koogle.Infrastructure --startup-project src/Koogle.Web --context AppDbContext --output-dir Data/Migrations
|
||||
# Game Entity erweitern: GameType, Status, StartedAt, CompletedAt
|
||||
dotnet ef migrations add ExtendGameEntity --project src/Koogle.Infrastructure --startup-project src/Koogle.Web --context AppDbContext --output-dir Data/Migrations
|
||||
|
||||
dotnet ef database update -p src/Koogle.Infrastructure -s src/Koogle.Web --context AppDbContext
|
||||
```
|
||||
|
|
@ -1242,6 +1327,13 @@ dotnet ef database update -p src/Koogle.Infrastructure -s src/Koogle.Web --conte
|
|||
|
||||
## Zusammenfassung Phase 2
|
||||
|
||||
**10 Phasen (H1-H10)** → **~42 Dateien** → **Detaillierte Spielverwaltung**
|
||||
**11 Phasen (H1-H10 + H9b)** → **~48 Dateien** → **Detaillierte Spielverwaltung**
|
||||
|
||||
**Kernfeatures:**
|
||||
- Spiele mit Wurf-für-Wurf Eingabe
|
||||
- DB-Persistenz nach jedem Wurf
|
||||
- SignalR Live-Updates für Multi-User
|
||||
- Recovery bei Page-Reload
|
||||
- Undo/Redo für Wurf-Korrekturen
|
||||
|
||||
Bereit für Implementierung Phase H1
|
||||
|
|
|
|||
Loading…
Reference in New Issue