Feat/ms 4 integration #282

Merged
jona.walpert merged 23 commits from feat/ms-4-integration into main 2026-04-13 03:07:52 +02:00
2 changed files with 57 additions and 29 deletions
Showing only changes of commit fb593d48a6 - Show all commits
@@ -13,9 +13,17 @@ import java.util.logging.Logger;
/** /**
* Fetches and parses game state from server. * Fetches and parses game state from server.
* *
* Protocol notes (based on your logs): * Protocol notes (based on your current server implementation):
* - Success replies contain lines like PHASE=..., POT=..., PLAYER ... END ... END * - Success replies contain: PHASE, POT, CURRENT_BET, DEALER, ACTIVE_PLAYER, then blocks:
* - Error replies contain -ERR, CODE=..., MSG=..., END * - CARD ... END (community cards on root level)
* - PLAYER ... (NAME/CHIPS/BET/STATE + optional CARD blocks for requesting player) ... END
* - Error replies contain: -ERR then CODE=..., MSG=..., END
*
* Important:
* - The server does NOT wrap cards in a "CARDS" container.
* - CARD blocks appear either:
* - at root level -> community cards
* - inside PLAYER -> hole cards for that player (usually only for the requesting user)
*/ */
public class GameClient { public class GameClient {
@@ -51,7 +59,7 @@ public class GameClient {
String joined = String.join("\n", lines); String joined = String.join("\n", lines);
if (joined.contains("-ERR")) { if (joined.contains("-ERR") || joined.contains("-ERROR")) {
String code = extractValue(joined, "CODE"); String code = extractValue(joined, "CODE");
String msg = extractValue(joined, "MSG"); String msg = extractValue(joined, "MSG");
LOG.info(() -> "GET_GAME_STATE returned -ERR code=" + code + " msg=" + msg); LOG.info(() -> "GET_GAME_STATE returned -ERR code=" + code + " msg=" + msg);
@@ -100,14 +108,12 @@ public class GameClient {
Player currentPlayer = null; Player currentPlayer = null;
Card currentCard = null; Card currentCard = null;
boolean inPlayerCards = false;
boolean inCommunityCards = false;
for (String raw : input.split("\n")) { for (String raw : input.split("\n")) {
String line = raw.trim(); String line = raw.trim();
if (line.isEmpty()) continue; if (line.isEmpty()) continue;
if (line.startsWith("+OK")) continue; if (line.startsWith("+OK")) continue;
// Global fields
if (line.startsWith("PHASE=")) { if (line.startsWith("PHASE=")) {
s.phase = value(line); s.phase = value(line);
continue; continue;
@@ -136,24 +142,21 @@ public class GameClient {
if (line.equals("PLAYER")) { if (line.equals("PLAYER")) {
currentPlayer = new Player(); currentPlayer = new Player();
s.players.add(currentPlayer); s.players.add(currentPlayer);
inPlayerCards = false;
currentCard = null; currentCard = null;
continue; continue;
} }
if (line.equals("CARDS")) { if (line.equals("CARDS")) {
inPlayerCards = (currentPlayer != null);
inCommunityCards = (currentPlayer == null);
currentCard = null;
continue; continue;
} }
if (line.startsWith("CARD")) { if (line.equals("CARD")) {
currentCard = new Card("", ""); currentCard = new Card("", "");
if (inPlayerCards && currentPlayer != null) {
currentPlayer.addCard(currentCard); if (currentPlayer != null) {
} else if (inCommunityCards) { currentPlayer.addCard(currentCard); // hole card
s.communityCards.add(currentCard); } else {
s.communityCards.add(currentCard); // community card
} }
continue; continue;
} }
@@ -162,7 +165,6 @@ public class GameClient {
currentCard.setValue(value(line)); currentCard.setValue(value(line));
continue; continue;
} }
if (line.startsWith("SUIT=") && currentCard != null) { if (line.startsWith("SUIT=") && currentCard != null) {
currentCard.setSuit(value(line)); currentCard.setSuit(value(line));
continue; continue;
@@ -173,18 +175,12 @@ public class GameClient {
currentCard = null; currentCard = null;
continue; continue;
} }
if (inPlayerCards) {
inPlayerCards = false;
continue;
}
if (inCommunityCards) {
inCommunityCards = false;
continue;
}
if (currentPlayer != null) { if (currentPlayer != null) {
currentPlayer = null; currentPlayer = null;
continue; continue;
} }
continue; continue;
} }
@@ -51,6 +51,9 @@ public class CasinoGameController {
private Image dealerImage; private Image dealerImage;
private javafx.animation.Timeline timeline; private javafx.animation.Timeline timeline;
private boolean gameStarted = false; private boolean gameStarted = false;
private java.util.List<String> lastCommunityKeys = java.util.List.of();
private java.util.List<String> lastMyCardKeys = java.util.List.of();
private int lastPot = Integer.MIN_VALUE;
private static final int TOTAL_SLOTS = 5; private static final int TOTAL_SLOTS = 5;
private static final int PLAYER_SLOTS = 2; private static final int PLAYER_SLOTS = 2;
@@ -126,6 +129,22 @@ public class CasinoGameController {
// default constructor for FXML // default constructor for FXML
} }
private String cardKey(Card c) {
if (c == null) return "null";
String suit = (c.getSuit() == null) ? "" : c.getSuit().toLowerCase();
String value = (c.getValue() == null) ? "" : c.getValue().toLowerCase();
return suit + ":" + value;
}
private java.util.List<String> cardKeys(java.util.List<Card> cards, int slots) {
java.util.List<String> keys = new java.util.ArrayList<>(slots);
for (int i = 0; i < slots; i++) {
Card c = (cards != null && i < cards.size()) ? cards.get(i) : null;
keys.add(cardKey(c));
}
return java.util.List.copyOf(keys);
}
/** /**
* Set the GameService for this controller. This method must be called before starting the UI to * Set the GameService for this controller. This method must be called before starting the UI to
* ensure that the controller has access to the game logic and can update the interface * ensure that the controller has access to the game logic and can update the interface
@@ -356,15 +375,28 @@ public class CasinoGameController {
List<Player> players = (s.players != null) ? s.players : List.of(); List<Player> players = (s.players != null) ? s.players : List.of();
List<Card> community = (s.communityCards != null) ? s.communityCards : List.of(); List<Card> community = (s.communityCards != null) ? s.communityCards : List.of();
List<Card> myCards = getMyCards(players);
renderCommunityCards(community); java.util.List<String> newCommunityKeys = cardKeys(community, TOTAL_SLOTS);
renderPlayerCards(getMyCards(players)); if (!newCommunityKeys.equals(lastCommunityKeys)) {
renderPot(s.pot); lastCommunityKeys = newCommunityKeys;
renderCommunityCards(community);
}
java.util.List<String> newMyCardKeys = cardKeys(myCards, PLAYER_SLOTS);
if (!newMyCardKeys.equals(lastMyCardKeys)) {
lastMyCardKeys = newMyCardKeys;
renderPlayerCards(myCards);
}
if (s.pot != lastPot) {
lastPot = s.pot;
renderPot(s.pot);
}
updatePlayers(players); updatePlayers(players);
updateGameInfo(s); updateGameInfo(s);
highlightDealer(s); highlightDealer(s);
updateTaskbar(s); updateTaskbar(s);
LOGGER.info("myPlayerId=" + myPlayerId); LOGGER.info("myPlayerId=" + myPlayerId);