From 4a32b8f988370885a5142ec1d4a8cce3c623418f Mon Sep 17 00:00:00 2001 From: anjapede Date: Tue, 14 Apr 2026 12:00:21 +0200 Subject: [PATCH] fix: redirect players if host leaves --- .../android/firebase/FirestoreSessionRepository.java | 5 ++++- .../beatbattle/controller/LeaderboardController.java | 9 +++++++++ .../beatbattle/controller/LobbyController.java | 11 +++++++++++ .../beatbattle/controller/RoundController.java | 10 ++++++++++ .../group07/beatbattle/ecs/systems/AudioSystem.java | 9 +++++++++ .../group07/beatbattle/firebase/FirebaseGateway.java | 4 ++++ .../main/java/group07/beatbattle/view/LobbyView.java | 11 +++++++++++ 7 files changed, 58 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/group07/beatbattle/android/firebase/FirestoreSessionRepository.java b/android/src/main/java/group07/beatbattle/android/firebase/FirestoreSessionRepository.java index 3722644..4568491 100644 --- a/android/src/main/java/group07/beatbattle/android/firebase/FirestoreSessionRepository.java +++ b/android/src/main/java/group07/beatbattle/android/firebase/FirestoreSessionRepository.java @@ -346,7 +346,10 @@ public void listenToSessionState( listener.onFailure(error); return; } - if (snapshot == null || !snapshot.exists()) return; + if (snapshot == null || !snapshot.exists()) { + listener.onSessionDeleted(); + return; + } String state = snapshot.getString("state"); Long roundLong = snapshot.getLong("currentRound"); int currentRound = roundLong != null ? roundLong.intValue() : 0; diff --git a/core/src/main/java/group07/beatbattle/controller/LeaderboardController.java b/core/src/main/java/group07/beatbattle/controller/LeaderboardController.java index 74a3607..3d0bde3 100644 --- a/core/src/main/java/group07/beatbattle/controller/LeaderboardController.java +++ b/core/src/main/java/group07/beatbattle/controller/LeaderboardController.java @@ -90,6 +90,15 @@ private void launchNextRound() { } public void onBackToMenu() { + if (game.isLocalHost()) { + String sessionId = game.getLocalSessionId(); + if (sessionId != null && !sessionId.isBlank()) { + game.getFirebaseGateway().deleteSession(sessionId, new FirebaseGateway.DeleteSessionCallback() { + @Override public void onSuccess() {} + @Override public void onFailure(Exception e) {} + }); + } + } StateManager.getInstance().setState(new StartState(game, new LobbyController(game))); } diff --git a/core/src/main/java/group07/beatbattle/controller/LobbyController.java b/core/src/main/java/group07/beatbattle/controller/LobbyController.java index 6986237..2184807 100644 --- a/core/src/main/java/group07/beatbattle/controller/LobbyController.java +++ b/core/src/main/java/group07/beatbattle/controller/LobbyController.java @@ -7,6 +7,8 @@ import java.util.List; import group07.beatbattle.BeatBattle; +import group07.beatbattle.ecs.Engine; +import group07.beatbattle.ecs.systems.AudioSystem; import group07.beatbattle.firebase.FirebaseGateway; import group07.beatbattle.model.GameMode; import group07.beatbattle.model.GameSession; @@ -289,6 +291,15 @@ public void onStateChanged(String state, int currentRound) { } } + @Override + public void onSessionDeleted() { + Gdx.app.postRunnable(() -> { + AudioSystem.getInstance().stopAll(); + Engine.getInstance().reset(); + StateManager.getInstance().setState(new StartState(game, new LobbyController(game))); + }); + } + @Override public void onFailure(Exception exception) { Gdx.app.error("LobbyController", diff --git a/core/src/main/java/group07/beatbattle/controller/RoundController.java b/core/src/main/java/group07/beatbattle/controller/RoundController.java index 2614fc3..dcddec1 100644 --- a/core/src/main/java/group07/beatbattle/controller/RoundController.java +++ b/core/src/main/java/group07/beatbattle/controller/RoundController.java @@ -89,6 +89,16 @@ public void onRoundExpired() { public void onLeaveSession() { AudioSystem.getInstance().stop(roundEntity); Engine.getInstance().removeEntity(roundEntity); + if (game.isLocalHost()) { + String sessionId = game.getLocalSessionId(); + if (sessionId != null && !sessionId.isBlank()) { + game.getFirebaseGateway().deleteSession(sessionId, new FirebaseGateway.DeleteSessionCallback() { + @Override public void onSuccess() {} + @Override public void onFailure(Exception e) {} + }); + } + } + StateManager.getInstance().setState(new StartState(game, new LobbyController(game))); } diff --git a/core/src/main/java/group07/beatbattle/ecs/systems/AudioSystem.java b/core/src/main/java/group07/beatbattle/ecs/systems/AudioSystem.java index bd837b0..5cbe3e5 100644 --- a/core/src/main/java/group07/beatbattle/ecs/systems/AudioSystem.java +++ b/core/src/main/java/group07/beatbattle/ecs/systems/AudioSystem.java @@ -51,6 +51,15 @@ public boolean isMuted() { return muted; } + /** + * Stops any currently playing audio without needing a specific entity reference. + * Used when a joiner is redirected to the start screen mid-round because the + * host left + */ + public void stopAll() { + if (audioPlayer != null) audioPlayer.stop(); + } + public void dispose() { if (audioPlayer != null) audioPlayer.dispose(); } diff --git a/core/src/main/java/group07/beatbattle/firebase/FirebaseGateway.java b/core/src/main/java/group07/beatbattle/firebase/FirebaseGateway.java index d539696..acb10ee 100644 --- a/core/src/main/java/group07/beatbattle/firebase/FirebaseGateway.java +++ b/core/src/main/java/group07/beatbattle/firebase/FirebaseGateway.java @@ -132,6 +132,10 @@ interface SessionStateListener { * @param currentRound current round index stored in Firebase */ void onStateChanged(String state, int currentRound); void onFailure(Exception exception); + /** + * Called when the session document is deleted from Firestore. If host leaves. + */ + default void onSessionDeleted() {} } interface AnswerCountCallback { diff --git a/core/src/main/java/group07/beatbattle/view/LobbyView.java b/core/src/main/java/group07/beatbattle/view/LobbyView.java index d00b23b..0efb5a0 100644 --- a/core/src/main/java/group07/beatbattle/view/LobbyView.java +++ b/core/src/main/java/group07/beatbattle/view/LobbyView.java @@ -26,6 +26,8 @@ import group07.beatbattle.model.GameMode; import group07.beatbattle.model.Player; import group07.beatbattle.model.services.LobbyService; +import group07.beatbattle.states.StartState; +import group07.beatbattle.states.StateManager; import group07.beatbattle.ui.components.BackButton; import group07.beatbattle.ui.components.RoundSelector; import group07.beatbattle.ui.components.SettingsButton; @@ -165,6 +167,15 @@ public void onFailure(Exception exception) { ); } } + + @Override + public void onSessionDeleted() { + Gdx.app.postRunnable(() -> { + if (!leavingLobby && !gameStarted) { + StateManager.getInstance().setState(new StartState(game, new LobbyController(game))); + } + }); + } @Override public void onFailure(Exception exception) {