Darkmode beta
parent
6a067d0c1e
commit
e9ea337ef9
|
|
@ -23,12 +23,13 @@ public class App {
|
||||||
if (cfg.spotifyClientId == null || cfg.spotifyClientSecret == null || cfg.spotifyRedirectUri == null) {
|
if (cfg.spotifyClientId == null || cfg.spotifyClientSecret == null || cfg.spotifyRedirectUri == null) {
|
||||||
throw new IllegalStateException("Spotify-Konfiguration fehlt: Bitte stelle sicher, dass ClientId, ClientSecret und RedirectUri gesetzt sind.");
|
throw new IllegalStateException("Spotify-Konfiguration fehlt: Bitte stelle sicher, dass ClientId, ClientSecret und RedirectUri gesetzt sind.");
|
||||||
}
|
}
|
||||||
GameService gs = new GameService();
|
|
||||||
SpotifyAuthService sas = new SpotifyAuthService(
|
SpotifyAuthService sas = new SpotifyAuthService(
|
||||||
cfg.spotifyClientId,
|
cfg.spotifyClientId,
|
||||||
cfg.spotifyClientSecret,
|
cfg.spotifyClientSecret,
|
||||||
cfg.spotifyRedirectUri
|
cfg.spotifyRedirectUri
|
||||||
);
|
);
|
||||||
|
GameService gs = new GameService(sas);
|
||||||
|
|
||||||
Javalin app = Javalin.create(config -> {
|
Javalin app = Javalin.create(config -> {
|
||||||
config.showJavalinBanner = false;
|
config.showJavalinBanner = false;
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,28 @@
|
||||||
package eric.Roullette.service;
|
package eric.Roullette.service;
|
||||||
|
|
||||||
import eric.Roullette.dto.PlayersMessage;
|
import eric.Roullette.dto.PlayersMessage;
|
||||||
import eric.Roullette.util.JsonUtil;
|
import eric.Roullette.util.JsonUtil;
|
||||||
import io.javalin.websocket.WsContext;
|
import io.javalin.websocket.WsContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
public class GameService {
|
public class GameService {
|
||||||
private static final Logger log = LoggerFactory.getLogger(GameService.class);
|
private static final Logger log = LoggerFactory.getLogger(GameService.class);
|
||||||
|
private final SpotifyAuthService authService;
|
||||||
private final Map<String, Set<WsContext>> sessions = new ConcurrentHashMap<>();
|
private final Map<String, Set<WsContext>> sessions = new ConcurrentHashMap<>();
|
||||||
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 GameService(SpotifyAuthService authService) { // <-- Konstruktor
|
||||||
String currentSong,List<String> allTracks) {
|
this.authService = authService;
|
||||||
public static Game create(String id) {
|
|
||||||
return new Game(id, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public record Game(String id, List<String> players, Map<String,Integer> scores, String currentOwner,
|
||||||
|
String currentSong, List<String> allTracks, Map<String, List<String>> playerTracks) {
|
||||||
|
public static Game create(String id) {
|
||||||
|
return new Game(id, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), new ConcurrentHashMap<>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Game getOrCreateGame(String gameId) {
|
public Game getOrCreateGame(String gameId) {
|
||||||
|
|
@ -30,6 +34,9 @@ public class GameService {
|
||||||
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);
|
||||||
|
// Songs einmalig laden und speichern
|
||||||
|
List<String> tracks = authService.getRecentTracks(user);
|
||||||
|
g.playerTracks().put(user, tracks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,25 +61,25 @@ public class GameService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createGame(String gameId) {
|
public void createGame(String gameId) {
|
||||||
Game game = new Game(gameId, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>());
|
Game game = new Game(gameId, new CopyOnWriteArrayList<>(), new ConcurrentHashMap<>(), null, null, new ArrayList<>(), new ConcurrentHashMap<>());
|
||||||
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) {
|
public Game startRound(String gameId, List<String> uris) {
|
||||||
Game g = getOrCreateGame(gameId);
|
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);
|
Game updated = new Game(gameId, g.players(), g.scores(), owner, song, uris, g.playerTracks());
|
||||||
games.put(gameId, updated);
|
games.put(gameId, updated);
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
// In GameService.java
|
|
||||||
public Set<WsContext> getSessions(String gameId) {
|
public Set<WsContext> getSessions(String gameId) {
|
||||||
return sessions.getOrDefault(gameId, Collections.emptySet());
|
return sessions.getOrDefault(gameId, Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
@ -78,7 +78,7 @@ public class GameWebSocketHandler {
|
||||||
// Songs von allen Spielern sammeln
|
// Songs von allen Spielern sammeln
|
||||||
List<String> allTracks = new ArrayList<>();
|
List<String> allTracks = new ArrayList<>();
|
||||||
for (String player : game.players()) {
|
for (String player : game.players()) {
|
||||||
allTracks.addAll(authService.getRecentTracks(player));
|
allTracks.addAll(game.playerTracks().getOrDefault(player, List.of()));
|
||||||
}
|
}
|
||||||
if (allTracks.isEmpty()) {
|
if (allTracks.isEmpty()) {
|
||||||
// TODO: Fehler an Client senden, dass keine Songs da sind
|
// TODO: Fehler an Client senden, dass keine Songs da sind
|
||||||
|
|
@ -90,6 +90,17 @@ public class GameWebSocketHandler {
|
||||||
// Jetzt Broadcast mit den aktuellen Daten
|
// Jetzt Broadcast mit den aktuellen Daten
|
||||||
broadcastRoundStart(gameId);
|
broadcastRoundStart(gameId);
|
||||||
}
|
}
|
||||||
|
case "next-round" -> {
|
||||||
|
var currentGame = service.getOrCreateGame(gameId);
|
||||||
|
List<String> allTracks = new ArrayList<>();
|
||||||
|
for (String player : currentGame.players()) {
|
||||||
|
allTracks.addAll(authService.getRecentTracks(player));
|
||||||
|
}
|
||||||
|
if (!allTracks.isEmpty()) {
|
||||||
|
service.startRound(gameId, allTracks);
|
||||||
|
}
|
||||||
|
broadcastRoundStart(gameId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,13 @@
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #1DB954;
|
--primary-color: #1DB954;
|
||||||
--bg-light: #f2f2f2;
|
--bg-light: #121212; /* vorher: #f2f2f2 */
|
||||||
--bg-dark: #121212;
|
--bg-dark: #000000; /* vorher: #121212 */
|
||||||
--text-light: #ffffff;
|
--text-light: #eaeaea; /* vorher: #ffffff */
|
||||||
--text-dark: #333333;
|
--text-dark: #eaeaea; /* vorher: #333333 */
|
||||||
--accent: #191414;
|
--accent: #191414;
|
||||||
--option-circle-size: 250px;
|
--option-circle-size: 80%;
|
||||||
|
--option-max-size: 400px;
|
||||||
--option-radius: 120px;
|
--option-radius: 120px;
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
@ -79,7 +80,8 @@
|
||||||
/* Rundenbereich */
|
/* Rundenbereich */
|
||||||
#roundArea {
|
#roundArea {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
background: var(--text-light);
|
background: var(--bg-dark);
|
||||||
|
color: var(--text-light);
|
||||||
padding: 0.7rem 1rem;
|
padding: 0.7rem 1rem;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
|
@ -139,6 +141,7 @@
|
||||||
<!-- Buttons zu Auswahl verteilen: JS erzeugt <button class="player-option">Name</button> -->
|
<!-- Buttons zu Auswahl verteilen: JS erzeugt <button class="player-option">Name</button> -->
|
||||||
</div>
|
</div>
|
||||||
<div id="result"></div>
|
<div id="result"></div>
|
||||||
|
<button id="nextRound" hidden>Weiter</button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<div class="section-title">Scoreboard</div>
|
<div class="section-title">Scoreboard</div>
|
||||||
|
|
|
||||||
|
|
@ -188,12 +188,18 @@ function handleRoundResult({ scores, guesses, owner }) {
|
||||||
resultP.appendChild(p);
|
resultP.appendChild(p);
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
const nextBtn = document.getElementById("nextRound");
|
||||||
|
nextBtn.hidden = false;
|
||||||
|
nextBtn.disabled = false;
|
||||||
|
nextBtn.onclick = () => {
|
||||||
|
socket.send(JSON.stringify({ type: "next-round" }));
|
||||||
|
nextBtn.hidden = true;
|
||||||
|
nextBtn.disabled = true;
|
||||||
resultP.textContent = "";
|
resultP.textContent = "";
|
||||||
startBtn.hidden = true;
|
startBtn.hidden = true;
|
||||||
startBtn.disabled = true;
|
startBtn.disabled = true;
|
||||||
roundArea.hidden = true;
|
roundArea.hidden = true;
|
||||||
}, 3000);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGameEnd({winner}) {
|
function handleGameEnd({winner}) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// src/test/java/eric/roulette/service/GameServiceTest.java
|
// src/test/java/eric/Roullette/service/GameServiceTest.java
|
||||||
package eric.Roullette.service;
|
package eric.Roullette.service;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
@ -9,7 +9,9 @@ class GameServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testGetOrCreateGame() {
|
void testGetOrCreateGame() {
|
||||||
GameService service = new GameService();
|
// Dummy-Parameter für SpotifyAuthService
|
||||||
|
SpotifyAuthService sas = new SpotifyAuthService("dummy", "dummy", "http://localhost");
|
||||||
|
GameService service = new GameService(sas);
|
||||||
// Erstes Mal anlegen
|
// Erstes Mal anlegen
|
||||||
GameService.Game g1 = service.getOrCreateGame("g1");
|
GameService.Game g1 = service.getOrCreateGame("g1");
|
||||||
assertNotNull(g1);
|
assertNotNull(g1);
|
||||||
|
|
@ -18,18 +20,4 @@ class GameServiceTest {
|
||||||
GameService.Game g2 = service.getOrCreateGame("g1");
|
GameService.Game g2 = service.getOrCreateGame("g1");
|
||||||
assertSame(g1, g2);
|
assertSame(g1, g2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
|
||||||
// void testAddPlayerAndScores() {
|
|
||||||
// GameService service = new GameService();
|
|
||||||
// service.getOrCreateGame("g2"); // Spiel anlegen
|
|
||||||
// service.addPlayer("g2", "Alice"); // Spieler hinzufügen
|
|
||||||
// GameService.Game game = service.getOrCreateGame("g2");
|
|
||||||
// // Spieler-Liste korrekt
|
|
||||||
// assertTrue(game.players().contains("Alice"));
|
|
||||||
// assertEquals(1, game.players().size());
|
|
||||||
// // Score für neuen Spieler initial 0
|
|
||||||
// assertEquals(0, game.scores().get("Alice").intValue());
|
|
||||||
// // Duplikate vermeiden
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue