game workflow corrected #93

Merged
Donat merged 1 commits from Backend_Fix into main 2025-11-06 19:37:54 +01:00
3 changed files with 63 additions and 1 deletions
+32
View File
@@ -970,6 +970,8 @@ socket.on('game:ended', {
message: string; message: string;
finalPositions: PlayerPosition[]; finalPositions: PlayerPosition[];
timestamp: string; timestamp: string;
reason?: string; // Optional: 'gamemaster_left' if GM disconnected
gamemasterName?: string; // Optional: GM name if GM left
}); });
// Server → All Players: Cleanup complete // Server → All Players: Cleanup complete
@@ -980,6 +982,36 @@ socket.on('game:cleanup-complete', {
}); });
``` ```
**Game End Scenarios**:
1. **Normal Win** (Player reaches position 100):
```typescript
{
winner: "player-uuid",
winnerName: "Alice",
message: "🎉 Alice won the game! Congratulations!",
finalPositions: [...],
timestamp: "2025-11-06T..."
}
```
2. **Gamemaster Disconnect** (Game cancelled):
```typescript
{
reason: "gamemaster_left",
gamemasterName: "Bob",
message: "🎭 Gamemaster Bob left. Game has ended.",
timestamp: "2025-11-06T..."
}
```
**Behavior**:
- Game immediately cancelled when gamemaster disconnects
- All players notified via `game:ended` event
- Database updated: `state = CANCELLED`, `enddate = now`
- All Redis data and socket connections cleaned up
- No winner recorded (game didn't complete normally)
--- ---
#### Error Events #### Error Events
Binary file not shown.
@@ -1139,6 +1139,36 @@ export class GameWebSocketService {
// If the socket was in a game, handle cleanup // If the socket was in a game, handle cleanup
if (socket.gameCode && socket.playerName) { if (socket.gameCode && socket.playerName) {
try { try {
// Check if this player is the gamemaster
const game = await this.gameRepository.findByGameCode(socket.gameCode);
const isGamemaster = game && socket.userId && game.createdby === socket.userId;
// If gamemaster leaves, end the game immediately
if (isGamemaster && game) {
logOther(`Gamemaster ${socket.playerName} left game ${socket.gameCode}, ending game`);
const gameRoomName = `game_${socket.gameCode}`;
// Notify all players
this.io.of('/game').to(gameRoomName).emit('game:ended', {
reason: 'gamemaster_left',
gamemasterName: socket.playerName,
message: `🎭 Gamemaster ${socket.playerName} left. Game has ended.`,
timestamp: new Date().toISOString()
});
// Update database
await this.gameRepository.update(game.id, {
state: GameState.CANCELLED,
enddate: new Date()
});
// Clean up all game data
await this.cleanupGameData(socket.gameCode, game.id);
return; // Exit early, no need for further cleanup
}
// Clean up any pending card answer // Clean up any pending card answer
if (socket.userId) { if (socket.userId) {
const pendingCard = await this.getPendingCard(socket.gameCode, socket.userId); const pendingCard = await this.getPendingCard(socket.gameCode, socket.userId);
@@ -2236,7 +2266,7 @@ export class GameWebSocketService {
if (game) { if (game) {
await this.gameRepository.update(game.id, { await this.gameRepository.update(game.id, {
state: GameState.FINISHED, state: GameState.FINISHED,
winner: winnerId, winnerId: winnerId,
enddate: new Date() enddate: new Date()
}); });
} }