From 7a073b6fffa57f51144c8d548ddfc3f581075cd1 Mon Sep 17 00:00:00 2001 From: Jonas <77726472+kobolol@users.noreply.github.com> Date: Thu, 12 Mar 2026 23:18:58 +0100 Subject: [PATCH] Handle disconnects, add restart flow and UI fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Server: Make DisconnectedPlayer async, await hub notifications, add logging, and delay scheduled deletion (2s). Harden ScheduleGameDeletion with try/catch and only destroy/send GameDestroyed when game is not running or has no players. Client: Add restart-game flow — expose restartGame on OnlineGame, propagate event from GameEndedMenu (adds local restarted state and disables button), and hook restart handling + player disconnect on unmount in OnlineMode. Also conditionally show bot switch in GameCreationMenu and include replayGameCode in GameEnded interface. Remove automatic reconnect on SignalR connection. Overall: Improves robustness around player disconnects and adds a UI/logic path for restarting games. --- API/Services/GameManager/GameManager.cs | 38 ++++++++++++------- GUI/src/components/GameCreationMenu.vue | 1 + GUI/src/components/GameEndedMenu.vue | 16 ++++++-- GUI/src/routes/OnlineMode.vue | 12 +++++- .../scripts/logic/onlineMode/OnlineGame.ts | 10 +++++ .../scripts/logic/signalR/GameConnection.ts | 2 +- 6 files changed, 61 insertions(+), 18 deletions(-) diff --git a/API/Services/GameManager/GameManager.cs b/API/Services/GameManager/GameManager.cs index f6f7ad6..6efa140 100644 --- a/API/Services/GameManager/GameManager.cs +++ b/API/Services/GameManager/GameManager.cs @@ -131,27 +131,28 @@ public class GameManager(IGameRepository gameRepository, IHubContext { - await Task.Delay(delay); - - var g = gameRepository.GetOne(gameId); - if (g != null && g.State != GameState.Running) + try { - gameRepository.Destroy(gameId); + await Task.Delay(delay); - await hubContext.Clients.Group(gameId).SendAsync("GameDestroyed"); + var g = gameRepository.GetOne(gameId); + if (g == null) + return; + + if (g.State != GameState.Running || g.Players.Count == 0) + { + gameRepository.Destroy(gameId); + await hubContext.Clients.Group(gameId).SendAsync("GameDestroyed"); + } + + Console.WriteLine($"Scheduled deletion of game {gameId} executed. {gameRepository.GetAll().Count}"); + } + catch (Exception ex) + { + Console.WriteLine($"Error deleting game {gameId}: {ex}"); } }); } diff --git a/GUI/src/components/GameCreationMenu.vue b/GUI/src/components/GameCreationMenu.vue index f047dda..c5fc0e6 100644 --- a/GUI/src/components/GameCreationMenu.vue +++ b/GUI/src/components/GameCreationMenu.vue @@ -34,6 +34,7 @@ function gameFieldPreset(x: number, y: number) { required > -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import type { GameEnded } from '@/scripts/logic/signalR/GameConnection'; -defineEmits(['restartGame']); +const emit = defineEmits(['restartGame']); const props = defineProps<{ gameEndedInformation: GameEnded | null }>(); +const restarted = ref(false); const message = computed(() => { + if(restarted.value) { + return 'Das Spiel wird neugestartet...'; + } switch (props.gameEndedInformation?.method) { case 'PlayerDisconnected': return `Bei dem Spieler ${props.gameEndedInformation.player?.name} ist die Verbindung abgebrochen :(`; @@ -18,6 +22,12 @@ const message = computed(() => { return ''; } }); + +function restartClicked() { + emit('restartGame'); + + restarted.value = true; +}