Skip to content

Add backend for joining existing sessions #33

Merged
merged 1 commit into from
Apr 10, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,24 @@ public void addHostToPlayers(
) {
sessionRepository.addHostToPlayers(sessionId, hostId, hostName, callback);
}

@Override
public void findSessionIdByGamePin(String gamePin, FindSessionCallback callback) {
sessionRepository.findSessionIdByGamePin(gamePin, callback);
}

@Override
public void addPlayerToSession(
String sessionId,
String playerId,
String playerName,
AddPlayerCallback callback
) {
sessionRepository.addPlayerToSession(sessionId, playerId, playerName, callback);
}

@Override
public void listenToPlayers(String sessionId, PlayersListenerCallback callback) {
sessionRepository.listenToPlayers(sessionId, callback);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

import com.google.firebase.Timestamp;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.QuerySnapshot;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import group07.beatbattle.firebase.FirebaseGateway;
import group07.beatbattle.model.Player;

public class FirestoreSessionRepository {

Expand Down Expand Up @@ -70,4 +75,89 @@ public void addHostToPlayers(
.addOnSuccessListener(unused -> callback.onSuccess())
.addOnFailureListener(callback::onFailure);
}

public void findSessionIdByGamePin(
String gamePin,
FirebaseGateway.FindSessionCallback callback
) {
firestore.collection(SESSIONS)
.whereEqualTo("gamePin", gamePin)
.limit(1)
.get()
.addOnSuccessListener(snapshot -> handleSessionLookup(snapshot, callback))
.addOnFailureListener(callback::onFailure);
}

private void handleSessionLookup(
QuerySnapshot snapshot,
FirebaseGateway.FindSessionCallback callback
) {
if (snapshot.isEmpty()) {
callback.onFailure(new IllegalArgumentException("Invalid game pin"));
return;
}
String sessionId = snapshot.getDocuments().get(0).getId();
callback.onSuccess(sessionId);
}

public void addPlayerToSession(
String sessionId,
String playerId,
String playerName,
FirebaseGateway.AddPlayerCallback callback
) {
Map<String, Object> player = new HashMap<>();
player.put("name", playerName);
player.put("score", 0);
player.put("isHost", false);

firestore.collection(SESSIONS)
.document(sessionId)
.collection(PLAYERS)
.document(playerId)
.set(player)
.addOnSuccessListener(unused -> callback.onSuccess())
.addOnFailureListener(callback::onFailure);
}

public ListenerRegistration listenToPlayers(
String sessionId,
FirebaseGateway.PlayersListenerCallback callback
) {
return firestore.collection(SESSIONS)
.document(sessionId)
.collection(PLAYERS)
.addSnapshotListener((snapshot, error) -> {
if (error != null) {
callback.onFailure(error);
return;
}

if (snapshot == null) {
callback.onPlayersChanged(new ArrayList<>());
return;
}

List<Player> players = new ArrayList<>();

snapshot.getDocuments().forEach(document -> {
String playerId = document.getId();
String name = document.getString("name");
if (name == null) {
name = "Unknown";
}

Player player = new Player(playerId, name);

Long scoreValue = document.getLong("score");
if (scoreValue != null) {
player.setScore(scoreValue.intValue());
}

players.add(player);
});

callback.onPlayersChanged(players);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import group07.beatbattle.model.Player;
import group07.beatbattle.model.Question;
import group07.beatbattle.model.SessionCreationResult;
import group07.beatbattle.model.SessionJoinResult;
import group07.beatbattle.model.Song;
import group07.beatbattle.model.services.LobbyService;
import group07.beatbattle.states.InRoundState;
Expand Down Expand Up @@ -42,23 +43,60 @@ public void onReady(
int totalRounds,
JoinCreateView view
) {
if (mode != GameMode.CREATE) {
StateManager.getInstance().setState(new LobbyState(game, mode, this));
return;
}

view.setLoadingState(true);
view.setStatusMessage("Creating session...");

LobbyService lobbyService = new LobbyService(game.getFirebaseGateway());

lobbyService.createSession(
if (mode == GameMode.CREATE) {
view.setStatusMessage("Creating session...");

lobbyService.createSession(
playerName,
gamePin,
totalRounds,
new LobbyService.CreateSessionCallback() {
@Override
public void onSuccess(SessionCreationResult result) {
Gdx.app.postRunnable(() -> {
view.setLoadingState(false);
view.setStatusMessage("");
StateManager.getInstance().setState(
new LobbyState(
game,
mode,
result.getSessionId(),
result.getGamePin(),
result.getHostName(),
LobbyController.this
)
);
});
}

@Override
public void onFailure(Exception exception) {
Gdx.app.postRunnable(() -> {
view.setLoadingState(false);
view.setStatusMessage(
exception.getMessage() != null
? exception.getMessage()
: "Failed to create session"
);
});
}
}
);
return;
}

view.setStatusMessage("Joining session...");

lobbyService.joinSession(
playerName,
gamePin,
totalRounds,
new LobbyService.CreateSessionCallback() {
new LobbyService.JoinSessionCallback() {
@Override
public void onSuccess(SessionCreationResult result) {
public void onSuccess(SessionJoinResult result) {
Gdx.app.postRunnable(() -> {
view.setLoadingState(false);
view.setStatusMessage("");
Expand All @@ -68,7 +106,7 @@ public void onSuccess(SessionCreationResult result) {
mode,
result.getSessionId(),
result.getGamePin(),
result.getHostName(),
result.getPlayerName(),
LobbyController.this
)
);
Expand All @@ -82,7 +120,7 @@ public void onFailure(Exception exception) {
view.setStatusMessage(
exception.getMessage() != null
? exception.getMessage()
: "Failed to create session"
: "Failed to join session"
);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package group07.beatbattle.firebase;

import java.util.List;

import group07.beatbattle.model.Player;

public interface FirebaseGateway {

void gamePinExists(String gamePin, GamePinExistsCallback callback);
Expand All @@ -20,6 +24,20 @@ void addHostToPlayers(
AddHostCallback callback
);

void findSessionIdByGamePin(String gamePin, FindSessionCallback callback);

void addPlayerToSession(
String sessionId,
String playerId,
String playerName,
AddPlayerCallback callback
);

void listenToPlayers(
String sessionId,
PlayersListenerCallback callback
);

interface GamePinExistsCallback {
void onResult(boolean exists);
void onFailure(Exception exception);
Expand All @@ -34,4 +52,19 @@ interface AddHostCallback {
void onSuccess();
void onFailure(Exception exception);
}

interface FindSessionCallback {
void onSuccess(String sessionId);
void onFailure(Exception exception);
}

interface AddPlayerCallback {
void onSuccess();
void onFailure(Exception exception);
}

interface PlayersListenerCallback {
void onPlayersChanged(List<Player> players);
void onFailure(Exception exception);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public class NoOpFirebaseGateway implements FirebaseGateway {

@Override
public void gamePinExists(String gamePin, GamePinExistsCallback callback) {
callback.onResult(false);
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}

@Override
Expand All @@ -16,7 +16,7 @@ public void createSession(
int totalRounds,
CreateSessionCallback callback
) {
callback.onSuccess("desktop-session");
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}

@Override
Expand All @@ -26,6 +26,29 @@ public void addHostToPlayers(
String hostName,
AddHostCallback callback
) {
callback.onSuccess();
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}

@Override
public void findSessionIdByGamePin(
String gamePin,
FindSessionCallback callback
) {
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}

@Override
public void addPlayerToSession(
String sessionId,
String playerId,
String playerName,
AddPlayerCallback callback
) {
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}

@Override
public void listenToPlayers(String sessionId, PlayersListenerCallback callback) {
callback.onFailure(new UnsupportedOperationException("Firebase is not available on this platform"));
}
}
4 changes: 4 additions & 0 deletions core/src/main/java/group07/beatbattle/model/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ public void addScore(int points) {
this.lastRoundScore = points;
this.score += points;
}

public void setScore(int score) {
this.score = score;
}
}
31 changes: 31 additions & 0 deletions core/src/main/java/group07/beatbattle/model/SessionJoinResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package group07.beatbattle.model;

public class SessionJoinResult {
private final String sessionId;
private final String gamePin;
private final String playerId;
private final String playerName;

public SessionJoinResult(String sessionId, String gamePin, String playerId, String playerName) {
this.sessionId = sessionId;
this.gamePin = gamePin;
this.playerId = playerId;
this.playerName = playerName;
}

public String getSessionId() {
return sessionId;
}

public String getGamePin() {
return gamePin;
}

public String getPlayerId() {
return playerId;
}

public String getPlayerName() {
return playerName;
}
}
Loading
Loading