From 9aefcb9b7bdf599735d5bbe5a4ffb8da07fd0e58 Mon Sep 17 00:00:00 2001 From: Bas Antonius de Jong <49651652+BAFGdeJong@users.noreply.github.com> Date: Wed, 7 Jan 2026 23:47:38 +0100 Subject: [PATCH] 289 server demo ready (#306) * Server update with new dev changes (#305) * merge widgets with development * readd previous game thread code * Revert "readd previous game thread code" This reverts commit d24feef73e0ba05357776d24e2a607d8be4aa849. * Revert "Merge remote-tracking branch 'origin/Development' into Development" This reverts commit 59d46cb73c3bf208ee359ce86f3ce4306d4e5964, reversing changes made to 38681c5db03e3e170c90ec3ec6795b6331b157df. * Revert "merge widgets with development" This reverts commit 38681c5db03e3e170c90ec3ec6795b6331b157df. * Merge 292 into development (#293) Applied template method pattern to abstract player * Added documentation to player classes and improved method names (#295) * mcts v1 * bitboard optimization * bitboard fix & mcts v2 & mcts v3. v3 still in progress and v4 coming soon * main * Hotfix for stuff * Logging and fixed user input getting stuck * Fixed merge mistakes --- app/src/main/java/org/toop/app/Server.java | 33 +++++++---------- .../org/toop/app/canvas/BitGameCanvas.java | 4 +-- .../GenericGameController.java | 28 ++++++++++++--- .../TicTacToeBitController.java | 3 +- .../app/widget/view/LocalMultiplayerView.java | 2 +- .../org/toop/framework/game/BitboardGame.java | 8 +++-- .../gameThreads/OnlineThreadBehaviour.java | 36 +++++++++++++++++-- .../framework/game/players/LocalPlayer.java | 17 +++++---- .../connectionHandler/NettyClientSession.java | 6 ---- 9 files changed, 87 insertions(+), 50 deletions(-) diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java index 1042a26..f6bcdec 100644 --- a/app/src/main/java/org/toop/app/Server.java +++ b/app/src/main/java/org/toop/app/Server.java @@ -19,7 +19,7 @@ import org.toop.framework.networking.connection.clients.TournamentNetworkingClie import org.toop.framework.networking.connection.events.NetworkEvents; import org.toop.framework.networking.connection.types.NetworkingConnector; import org.toop.framework.networking.server.gateway.NettyGatewayServer; -import org.toop.game.players.LocalPlayer; +import org.toop.framework.game.players.LocalPlayer; import org.toop.local.AppContext; import java.util.List; @@ -196,30 +196,21 @@ public final class Server { return; } - final int myTurn = response.playerToMove().equalsIgnoreCase(response.opponent()) ? 1 : 0; + final String startingPlayer = response.playerToMove(); + final int userStartingTurn = startingPlayer.equalsIgnoreCase(user) ? 0 : 1; + final int opponentStartingTurn = 1 - userStartingTurn; final GameInformation information = new GameInformation(type); - //information.players[0] = playerInformation; - information.players[0].name = user; - information.players[0].isHuman = true; // Make false and uncomment/comment code at lines HERE To make use of AI. -// information.players[0].computerDifficulty = 5; // HERE -// information.players[0].computerThinkTime = 1; // HERE - information.players[1].name = response.opponent(); + information.players[userStartingTurn].name = user; + information.players[opponentStartingTurn].name = response.opponent(); + + Player[] players = new Player[2]; + players[userStartingTurn] = new LocalPlayer(user); + players[opponentStartingTurn] = new OnlinePlayer(response.opponent()); switch (type) { - case TICTACTOE -> { - Player[] players = new Player[2]; - players[Math.abs(myTurn-1)] = new OnlinePlayer(response.opponent()); - players[myTurn] = new LocalPlayer(user); // HERE -// players[myTurn] = new ArtificialPlayer(new RandomAI(), user); // HERE - gameController = new TicTacToeBitController(players); - } - case REVERSI -> { - Player[] players = new Player[2]; - players[Math.abs(myTurn-1)] = new OnlinePlayer(response.opponent()); - players[myTurn] = new LocalPlayer(user); // HERE -// players[myTurn] = new ArtificialPlayer(new RandomAI(), user); // HERE - gameController = new ReversiBitController(players);} + case TICTACTOE -> gameController = new TicTacToeBitController(players); + case REVERSI -> gameController = new ReversiBitController(players); default -> new ErrorPopup("Unsupported game type."); } diff --git a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java index 2f00e10..b441f44 100644 --- a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java @@ -78,6 +78,7 @@ public abstract class BitGameCanvas implements GameCanvas { } canvas.setOnMouseClicked(event -> { + if (event.getButton() != MouseButton.PRIMARY) { return; } @@ -93,9 +94,6 @@ public abstract class BitGameCanvas implements GameCanvas { } }); - - - render(); } diff --git a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java index c19e6fb..0c68a74 100644 --- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java +++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java @@ -16,7 +16,7 @@ import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehavio import org.toop.framework.gameFramework.model.player.Player; import org.toop.framework.gameFramework.view.GUIEvents; import org.toop.framework.networking.connection.events.NetworkEvents; -import org.toop.game.players.LocalPlayer; +import org.toop.framework.game.players.LocalPlayer; public class GenericGameController implements GameController { protected final EventFlow eventFlow = new EventFlow(); @@ -35,14 +35,16 @@ public class GenericGameController implements GameController { // TODO: Change gameType to automatically happen with either dependency injection or something else. public GenericGameController(GameCanvas canvas, TurnBasedGame game, ThreadBehaviour gameThreadBehaviour, String gameType) { - logger.info("Creating: " + this.getClass()); + logger.info("Creating: {}", this.getClass()); this.canvas = canvas; this.game = game; this.gameThreadBehaviour = gameThreadBehaviour; // Tell thread how to send moves - this.gameThreadBehaviour.setOnSendMove((id, m) -> GlobalEventBus.get().post(new NetworkEvents.SendMove(id, (short)translateMove(m)))); + this.gameThreadBehaviour.setOnSendMove( + (id, m) -> GlobalEventBus.get().post(new NetworkEvents.SendMove(id, (short)translateMove(m))) + ); // Tell thread how to update UI this.gameThreadBehaviour.setOnUpdateUI(() -> Platform.runLater(this::updateUI)); @@ -53,21 +55,37 @@ public class GenericGameController implements GameController { WidgetContainer.getCurrentView().transitionNext(gameView, true); // Listen to updates + logger.info("Game controller started listening"); eventFlow .listen(GUIEvents.GameEnded.class, this::onGameFinish, false) - .listen(GUIEvents.PlayerAttemptedMove.class, event -> {if (getCurrentPlayer() instanceof LocalPlayer lp){lp.setLastMove(event.move());}}, false); + .listen(GUIEvents.PlayerAttemptedMove.class, event -> { + logger.info("User attempting move {}", event.move()); + logger.info("Current player's turn {}", getCurrentPlayer().getName()); + logger.info("First player {}", game.getPlayer(0).getName()); + logger.info("Username {}", getCurrentPlayer().getName()); + logger.info("User is class {}, {}", getCurrentPlayer().getClass(), getCurrentPlayer() instanceof LocalPlayer); + if (getCurrentPlayer() instanceof LocalPlayer lp) { + try { + lp.setLastMove(event.move()); + } catch (Exception e) { + IO.println(e); + } + } + }, false); } public void start(){ logger.info("Starting GameManager"); updateUI(); gameThreadBehaviour.start(); + logger.info("GameManager started"); } public void stop(){ logger.info("Stopping GameManager"); removeListeners(); gameThreadBehaviour.stop(); + logger.info("GameManager stopped"); } public Player getCurrentPlayer(){ @@ -98,7 +116,7 @@ public class GenericGameController implements GameController { } public Player getPlayer(int player){ - if (player < 0 || player >= 2){ // TODO: Make game turn player count + if (player < 0 || player > game.getPlayerCount()-1){ // TODO: Make game turn player count logger.error("Invalid player index"); throw new IllegalArgumentException("player out of range"); } diff --git a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java index 9ef825c..8315249 100644 --- a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java +++ b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java @@ -7,7 +7,6 @@ import org.toop.framework.game.gameThreads.LocalThreadBehaviour; import org.toop.framework.game.gameThreads.OnlineThreadBehaviour; import org.toop.framework.game.games.tictactoe.BitboardTicTacToe; import org.toop.framework.game.players.OnlinePlayer; -import org.toop.framework.networking.server.OnlineGame; import java.util.Arrays; @@ -19,6 +18,6 @@ public class TicTacToeBitController extends GenericGameController { ThreadBehaviour thread = Arrays.stream(players).anyMatch(e -> e instanceof OnlinePlayer) ? new OnlineThreadBehaviour(game) : new LocalThreadBehaviour(game); - super(new TicTacToeBitCanvas(), game, thread , "TicTacToe"); + super(new TicTacToeBitCanvas(), game, thread, "TicTacToe"); } } diff --git a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java index a4fa180..9139720 100644 --- a/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java +++ b/app/src/main/java/org/toop/app/widget/view/LocalMultiplayerView.java @@ -12,7 +12,7 @@ import org.toop.app.widget.complex.PlayerInfoWidget; import org.toop.app.widget.complex.ViewWidget; import org.toop.app.widget.popup.ErrorPopup; import org.toop.app.widget.tutorial.*; -import org.toop.game.players.LocalPlayer; +import org.toop.framework.game.players.LocalPlayer; import org.toop.game.players.ai.MCTSAI; import org.toop.game.players.ai.MCTSAI2; import org.toop.game.players.ai.MCTSAI3; diff --git a/framework/src/main/java/org/toop/framework/game/BitboardGame.java b/framework/src/main/java/org/toop/framework/game/BitboardGame.java index 8562432..76997c5 100644 --- a/framework/src/main/java/org/toop/framework/game/BitboardGame.java +++ b/framework/src/main/java/org/toop/framework/game/BitboardGame.java @@ -47,9 +47,11 @@ public abstract class BitboardGame implements TurnBasedGame { this.playerBitboard = other.playerBitboard.clone(); this.currentTurn = other.currentTurn; - this.players = Arrays.stream(other.players) - .map(Player::deepCopy) - .toArray(Player[]::new); + this.players = other.players; + // TODO: Players are not deep copied, which is bad. I don't know why but deepcopying breaks it. Fix it + //this.players = Arrays.stream(other.players) + // .map(Player::deepCopy) + // .toArray(Player[]::new); } public int getColumnSize() { diff --git a/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java index fde7606..6a7c5d2 100644 --- a/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java +++ b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java @@ -8,6 +8,9 @@ import org.toop.framework.gameFramework.model.game.threadBehaviour.SupportsOnlin import org.toop.framework.gameFramework.model.player.Player; import org.toop.framework.game.players.OnlinePlayer; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + /** * Handles online multiplayer game logic. *

@@ -15,6 +18,9 @@ import org.toop.framework.game.players.OnlinePlayer; * for the local player while receiving moves from other players. */ public class OnlineThreadBehaviour extends AbstractThreadBehaviour implements SupportsOnlinePlay { + + private ExecutorService moveExecutor = Executors.newSingleThreadExecutor(); + /** * Creates behaviour and sets the first local player * (non-online player) from the given array. @@ -51,9 +57,33 @@ public class OnlineThreadBehaviour extends AbstractThreadBehaviour implements Su */ @Override public void onYourTurn(long clientId) { - if (!isRunning.get()) return; - long move = game.getPlayer(game.getCurrentTurn()).getMove(game.deepCopy()); - sendMove(clientId, move); + logger.info("Yourturn"); + if (!isRunning.get()) { + logger.warn("Game is not running!"); + return; + } + + TurnBasedGame gameCopy = game.deepCopy(); + if (gameCopy == null) { + logger.error("Could not deep copy game"); + return; + } + logger.info("Successfully collected game copy"); + + Player player = gameCopy.getPlayer(game.getCurrentTurn()); + if (player == null) { + logger.error("Could not find current turn's player"); + return; + } + logger.info("Successfully collected current turn's player"); + + moveExecutor.submit(() -> { + long move = player.getMove(gameCopy); + logger.info("Move set: {}", move); + logger.info("Completed onYourTurn"); + + sendMove(clientId, move); + }); } /** diff --git a/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java b/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java index 9cab095..f922179 100644 --- a/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java +++ b/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java @@ -1,4 +1,4 @@ -package org.toop.game.players; +package org.toop.framework.game.players; import org.toop.framework.gameFramework.model.game.TurnBasedGame; import org.toop.framework.gameFramework.model.player.AbstractPlayer; @@ -45,11 +45,16 @@ public class LocalPlayer extends AbstractPlayer { long legalMoves = gameCopy.getLegalMoves(); long move; - do { - move = getLastMove(); - } while ((legalMoves & move) == 0); - - return move; + try { + do { + move = getLastMove(); + IO.println("GETTING MOVE"); + } while ((legalMoves & move) == 0); + return move; + } catch (Exception e) { + IO.println(e); + } + return -1; } /** diff --git a/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java b/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java index d9df676..8aaa350 100644 --- a/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java +++ b/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java @@ -11,8 +11,6 @@ import org.toop.framework.networking.server.Server; import org.toop.framework.networking.server.client.Client; import org.toop.framework.networking.server.parsing.Parser; -import java.util.Arrays; - public class NettyClientSession extends SimpleChannelInboundHandler implements ClientSession { private final NettyClient client; @@ -41,13 +39,9 @@ public class NettyClientSession extends SimpleChannelInboundHandler impl @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { - IO.println(msg); - ParsedMessage p = Parser.parse(msg); if (p == null) return; - IO.println(p.command() + " " + Arrays.toString(p.args())); - handler.handle(p); }