Überall limit auswahl entfernen

pull/24/head
eric 2025-08-07 15:44:14 +02:00
parent 98ebcad2eb
commit 6635b49770
8 changed files with 37 additions and 53 deletions

View File

@ -36,14 +36,13 @@ package eric.Roullette.controller;
ctx.status(400).result("username fehlt"); ctx.status(400).result("username fehlt");
return; return;
} }
int limit = body.get("limit") != null ? (int) body.get("limit") : 10;
String gameId; String gameId;
do { do {
gameId = String.format("%04d", ThreadLocalRandom.current().nextInt(0, 10000)); gameId = String.format("%04d", ThreadLocalRandom.current().nextInt(0, 10000));
} while (gameService.gameExists(gameId)); } while (gameService.gameExists(gameId));
gameService.createGame(gameId, limit); gameService.createGame(gameId);
gameService.addPlayer(gameId, user, limit); gameService.addPlayer(gameId, user);
gameService.broadcastPlayers(gameId); gameService.broadcastPlayers(gameId);
ctx.json(Map.of("status", "ok", "gameId", gameId)); ctx.json(Map.of("status", "ok", "gameId", gameId));
@ -53,40 +52,35 @@ package eric.Roullette.controller;
Map<String, String> body = ctx.bodyAsClass(Map.class); Map<String, String> body = ctx.bodyAsClass(Map.class);
String user = body.get("username"); String user = body.get("username");
String gameId = body.get("gameId"); String gameId = body.get("gameId");
int limit = body.get("limit") != null ? Integer.parseInt(body.get("limit")) : 10;
if (user == null || gameId == null) { if (user == null || gameId == null) {
ctx.status(400).result("username oder gameId fehlt"); ctx.status(400).result("username oder gameId fehlt");
return; return;
} }
gameService.addPlayer(gameId, user, limit); gameService.addPlayer(gameId, user);
gameService.broadcastPlayers(gameId); gameService.broadcastPlayers(gameId);
ctx.json(Map.of("status", "ok")); ctx.json(Map.of("status", "ok"));
} }
private void getPlayers(Context ctx) { private void getPlayers(Context ctx) {
String gameId = ctx.pathParam("gameId"); String gameId = ctx.pathParam("gameId");
int limit = Integer.parseInt(Objects.requireNonNull(ctx.queryParam("limit"))); var game = gameService.getOrCreateGame(gameId);
var game = gameService.getOrCreateGame(gameId, limit);
ctx.json(Map.of( ctx.json(Map.of(
"players", game.players(), "players", game.players()
"limit", game.limit() // Limit mitgeben!
)); ));
} }
private void startRound(Context ctx) { private void startRound(Context ctx) {
String gameId = ctx.pathParam("gameId"); String gameId = ctx.pathParam("gameId");
int limit = Integer.parseInt(Objects.requireNonNull(ctx.queryParam("limit")));
ctx.json(Map.of("status", "ok")); ctx.json(Map.of("status", "ok"));
webSocketHandler.broadcastRoundStart(gameId, limit); webSocketHandler.broadcastRoundStart(gameId);
} }
private void guess(Context ctx) { private void guess(Context ctx) {
String gameId = ctx.pathParam("gameId"); String gameId = ctx.pathParam("gameId");
int limit = Integer.parseInt(Objects.requireNonNull(ctx.queryParam("limit")));
Map<String, String> body = ctx.bodyAsClass(Map.class); Map<String, String> body = ctx.bodyAsClass(Map.class);
String guess = body.get("guess"); String guess = body.get("guess");
String user = body.get("username"); String user = body.get("username");
GameService.Game game = gameService.getOrCreateGame(gameId, limit); GameService.Game game = gameService.getOrCreateGame(gameId);
String owner = game.currentOwner(); String owner = game.currentOwner();
if (owner == null || guess == null) { if (owner == null || guess == null) {
ctx.status(400).result("ungültig"); ctx.status(400).result("ungültig");

View File

@ -14,19 +14,19 @@ public class GameService {
private final Map<String, Game> games = new ConcurrentHashMap<>(); private final Map<String, Game> games = new ConcurrentHashMap<>();
public record Game(String id, List<String> players, Map<String,Integer> scores,String currentOwner, public record Game(String id, List<String> players, Map<String,Integer> scores,String currentOwner,
String currentSong,List<String> allTracks, int limit) { String currentSong,List<String> allTracks) {
public static Game create(String id, int limit) { public static Game create(String id) {
return new Game(id, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), limit); return new Game(id, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>());
} }
} }
public Game getOrCreateGame(String gameId, int limit) { public Game getOrCreateGame(String gameId) {
return games.computeIfAbsent(gameId, id -> Game.create(id, limit)); return games.computeIfAbsent(gameId, id -> Game.create(id));
} }
public void addPlayer(String gameId, String user, int limit) { public void addPlayer(String gameId, String user) {
Game g = getOrCreateGame(gameId, limit); Game g = getOrCreateGame(gameId);
if (user != null && !g.players().contains(user)) { if (user != null && !g.players().contains(user)) {
g.players().add(user); g.players().add(user);
g.scores().putIfAbsent(user, 0); g.scores().putIfAbsent(user, 0);
@ -53,20 +53,20 @@ public class GameService {
.forEach(ctx -> ctx.send(JsonUtil.toJson(msg))); .forEach(ctx -> ctx.send(JsonUtil.toJson(msg)));
} }
public void createGame(String gameId, int limit) { public void createGame(String gameId) {
Game game = new Game(gameId, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), limit); Game game = new Game(gameId, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>());
games.put(gameId, game); games.put(gameId, game);
} }
public boolean gameExists(String gameId) { public boolean gameExists(String gameId) {
return games.containsKey(gameId); return games.containsKey(gameId);
} }
public Game startRound(String gameId, List<String> uris, int limit) { public Game startRound(String gameId, List<String> uris) {
Game g = getOrCreateGame(gameId, limit); Game g = getOrCreateGame(gameId);
if (g.players().isEmpty()) throw new IllegalStateException("No players"); if (g.players().isEmpty()) throw new IllegalStateException("No players");
String owner = g.players().get(ThreadLocalRandom.current().nextInt(g.players().size())); String owner = g.players().get(ThreadLocalRandom.current().nextInt(g.players().size()));
String song = uris.get(ThreadLocalRandom.current().nextInt(uris.size())); String song = uris.get(ThreadLocalRandom.current().nextInt(uris.size()));
Game updated = new Game(gameId, g.players(), g.scores(), owner, song, uris, limit); Game updated = new Game(gameId, g.players(), g.scores(), owner, song, uris);
games.put(gameId, updated); games.put(gameId, updated);
return updated; return updated;
} }

View File

@ -36,9 +36,8 @@ public class GameWebSocketHandler {
ws.onConnect(ctx -> { ws.onConnect(ctx -> {
String gameId = ctx.pathParam("gameId"); String gameId = ctx.pathParam("gameId");
String username = ctx.queryParam("username"); String username = ctx.queryParam("username");
int limit = Integer.parseInt(Objects.requireNonNull(ctx.queryParam("limit")));
// Spiel- und Session-Registrierung // Spiel- und Session-Registrierung
service.addPlayer(gameId, username, limit); service.addPlayer(gameId, username);
// Alle Clients über neue Spielerliste informieren // Alle Clients über neue Spielerliste informieren
service.registerSession(gameId, ctx); service.registerSession(gameId, ctx);
service.broadcastPlayers(gameId); service.broadcastPlayers(gameId);
@ -53,7 +52,6 @@ public class GameWebSocketHandler {
// Eingehende Nachrichten (Guesses & Player-Requests) // Eingehende Nachrichten (Guesses & Player-Requests)
ws.onMessage(ctx -> { ws.onMessage(ctx -> {
String gameId = ctx.pathParam("gameId"); String gameId = ctx.pathParam("gameId");
int limit = Integer.parseInt(Objects.requireNonNull(ctx.queryParam("limit")));
JsonNode node = JsonUtil.fromJson(ctx.message(), JsonNode.class); JsonNode node = JsonUtil.fromJson(ctx.message(), JsonNode.class);
String type = node.get("type").asText(); String type = node.get("type").asText();
@ -66,15 +64,15 @@ public class GameWebSocketHandler {
.computeIfAbsent(gameId, id -> new ConcurrentHashMap<>()) .computeIfAbsent(gameId, id -> new ConcurrentHashMap<>())
.put(user, guess); .put(user, guess);
// Wenn alle getippt haben, Ergebnis broadcasten // Wenn alle getippt haben, Ergebnis broadcasten
int numPlayers = service.getOrCreateGame(gameId, limit).players().size(); int numPlayers = service.getOrCreateGame(gameId).players().size();
if (currentGuesses.get(gameId).size() == numPlayers) { if (currentGuesses.get(gameId).size() == numPlayers) {
broadcastRoundResult(gameId, limit); broadcastRoundResult(gameId);
} }
} }
case "requestPlayers" -> service.broadcastPlayers(gameId); case "requestPlayers" -> service.broadcastPlayers(gameId);
case "start-round" -> { case "start-round" -> {
var game = service.getOrCreateGame(gameId,limit); var game = service.getOrCreateGame(gameId);
if (game.players().isEmpty()) return; if (game.players().isEmpty()) return;
// Songs von allen Spielern sammeln // Songs von allen Spielern sammeln
@ -88,9 +86,9 @@ public class GameWebSocketHandler {
} }
// Runde im Service starten, um Song und Owner zu setzen // Runde im Service starten, um Song und Owner zu setzen
service.startRound(gameId, allTracks,limit); service.startRound(gameId, allTracks);
// Jetzt Broadcast mit den aktuellen Daten // Jetzt Broadcast mit den aktuellen Daten
broadcastRoundStart(gameId, limit); broadcastRoundStart(gameId);
} }
} }
}); });
@ -99,8 +97,8 @@ public class GameWebSocketHandler {
// ----- Broadcast-Methoden ----- // ----- Broadcast-Methoden -----
/** Broadcastet den Runden-Start (Song + Optionen) an alle Clients. */ /** Broadcastet den Runden-Start (Song + Optionen) an alle Clients. */
public void broadcastRoundStart(String gameId, int limit) { public void broadcastRoundStart(String gameId) {
var game = service.getOrCreateGame(gameId,limit); var game = service.getOrCreateGame(gameId);
List<String> opts = game.players(); List<String> opts = game.players();
String songUri = game.currentSong(); String songUri = game.currentSong();
List<String> allTracks = game.allTracks(); List<String> allTracks = game.allTracks();
@ -115,8 +113,8 @@ public class GameWebSocketHandler {
/** Broadcastet das Rundenergebnis (Scores, wer richtig, wer getippt hat). */ /** Broadcastet das Rundenergebnis (Scores, wer richtig, wer getippt hat). */
// Punkte für alle Guess-Teilnehmer anpassen // Punkte für alle Guess-Teilnehmer anpassen
private void broadcastRoundResult(String gameId, int limit) { private void broadcastRoundResult(String gameId) {
var game = service.getOrCreateGame(gameId, limit); var game = service.getOrCreateGame(gameId);
Map<String,Integer> scores = game.scores(); Map<String,Integer> scores = game.scores();
Map<String,String> guesses = currentGuesses.remove(gameId); Map<String,String> guesses = currentGuesses.remove(gameId);
String owner = game.currentOwner(); String owner = game.currentOwner();
@ -156,7 +154,7 @@ private void broadcastRoundResult(String gameId, int limit) {
// nächste Runde starten // nächste Runde starten
new Thread(() -> { new Thread(() -> {
try { Thread.sleep(4000); } catch (InterruptedException ignored) {} try { Thread.sleep(4000); } catch (InterruptedException ignored) {}
broadcastRoundStart(gameId, limit); broadcastRoundStart(gameId);
}).start(); }).start();
} }
} }

View File

@ -7,7 +7,6 @@
<body> <body>
<h1>Neues Spiel erstellen</h1> <h1>Neues Spiel erstellen</h1>
<button id="createGame">Spiel erstellen</button> <button id="createGame">Spiel erstellen</button>
<script type="module" src="/js/create-game.js"></script> <script type="module" src="/js/create-game.js"></script>
</body> </body>
</html> </html>

View File

@ -10,15 +10,15 @@ if (!username) {
} }
document.getElementById("createGame").addEventListener("click", async () => { document.getElementById("createGame").addEventListener("click", async () => {
const limit = parseInt(document.getElementById("limit").value, 10);
try { try {
const { status, gameId } = await fetchJson("/api/create-game", { const { status, gameId } = await fetchJson("/api/create-game", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username, limit }) body: JSON.stringify({ username })
}); });
if (status === "ok") { if (status === "ok") {
window.location.href = `/game.html?gameId=${gameId}&username=${encodeURIComponent(username)}&limit=${limit}`; } else { window.location.href = `/game.html?gameId=${gameId}&username=${encodeURIComponent(username)}`; } else {
alert("Fehler beim Erstellen des Spiels"); alert("Fehler beim Erstellen des Spiels");
} }
} catch (err) { } catch (err) {

View File

@ -5,12 +5,7 @@ import { setupStartRound } from "./start-round.js";
const gameId = getParam("gameId"); const gameId = getParam("gameId");
const username = getParam("username"); const username = getParam("username");
const limit = getParam("limit");
if (!limit) {
alert("Limit fehlt!");
throw new Error("Missing limit");
}
// 1) Parameter prüfen // 1) Parameter prüfen
if (!gameId || !username) { if (!gameId || !username) {
@ -55,7 +50,7 @@ document.getElementById("gameId").textContent = gameId;
// 5) WebSocket einrichten und Spieler laden // 5) WebSocket einrichten und Spieler laden
const protocol = location.protocol === "https:" ? "wss" : "ws"; const protocol = location.protocol === "https:" ? "wss" : "ws";
const socket = new WebSocket( const socket = new WebSocket(
`${protocol}://${location.host}/ws/${gameId}?username=${encodeURIComponent(username)}&limit=${limit}` `${protocol}://${location.host}/ws/${gameId}?username=${encodeURIComponent(username)}`
); );
socket.addEventListener("open", () => { socket.addEventListener("open", () => {

View File

@ -12,14 +12,12 @@ document.getElementById("joinForm").addEventListener("submit", async e => {
return; return;
} }
try { try {
const res = await fetchJson(`/api/game/${gameId}/players?limit=50`); // Dummy-Limit, Backend ignoriert es beim getOrCreateGame
const limit = res && res.players ? res.limit : 10; // Backend sollte das Limit mitliefern!
await fetchJson("/api/join-game", { await fetchJson("/api/join-game", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ gameId, username }) body: JSON.stringify({ gameId, username })
}); });
window.location.href = `/game.html?gameId=${gameId}&username=${encodeURIComponent(username)}&limit=${limit}`; window.location.href = `/game.html?gameId=${gameId}&username=${encodeURIComponent(username)}`;
} catch (err) { } catch (err) {
alert(`Fehler: ${err.message}`); alert(`Fehler: ${err.message}`);
} }

View File

@ -11,11 +11,11 @@ class GameServiceTest {
void testGetOrCreateGame() { void testGetOrCreateGame() {
GameService service = new GameService(); GameService service = new GameService();
// Erstes Mal anlegen // Erstes Mal anlegen
GameService.Game g1 = service.getOrCreateGame("g1",0); GameService.Game g1 = service.getOrCreateGame("g1");
assertNotNull(g1); assertNotNull(g1);
assertEquals("g1", g1.id()); assertEquals("g1", g1.id());
// Beim zweiten Aufruf dieselbe Instanz // Beim zweiten Aufruf dieselbe Instanz
GameService.Game g2 = service.getOrCreateGame("g1",0); GameService.Game g2 = service.getOrCreateGame("g1");
assertSame(g1, g2); assertSame(g1, g2);
} }