From 66cb000fad3f480582ba8c24eff1acab228379d6 Mon Sep 17 00:00:00 2001
From: Bas de Jong
Date: Fri, 12 Dec 2025 15:15:55 +0100
Subject: [PATCH 01/35] Init server code
---
app/src/main/java/org/toop/app/Server.java | 16 +--
.../org/toop/app/canvas/ReversiBitCanvas.java | 5 +-
.../toop/app/canvas/TicTacToeBitCanvas.java | 5 +-
.../GenericGameController.java | 4 +-
.../gameControllers/ReversiBitController.java | 8 +-
.../TicTacToeBitController.java | 9 +-
.../app/widget/view/LocalMultiplayerView.java | 18 +--
framework/pom.xml | 1 -
.../java/org/toop/framework}/game/Move.java | 2 +-
.../LocalFixedRateThreadBehaviour.java | 2 +-
.../gameThreads/LocalThreadBehaviour.java | 2 +-
.../gameThreads/OnlineThreadBehaviour.java | 4 +-
.../OnlineWithSleepThreadBehaviour.java | 3 +-
.../framework}/game/players/LocalPlayer.java | 3 +-
.../framework}/game/players/MiniMaxAI.java | 2 +-
.../framework}/game/players/OnlinePlayer.java | 2 +-
.../framework}/game/players/RandomAI.java | 2 +-
.../controller/GameController.java | 3 +-
.../model/game/SupportsOnlinePlay.java | 2 -
.../NetworkingClientEventListener.java | 8 +-
.../NetworkingClientManager.java | 14 +--
.../clients/TournamentNetworkingClient.java | 8 +-
.../events/NetworkEvents.java | 6 +-
.../exceptions/ClientNotFoundException.java | 2 +-
.../exceptions/CouldNotConnectException.java | 2 +-
.../NetworkingInitializationException.java | 2 +-
.../handlers/NetworkingGameClientHandler.java | 4 +-
.../interfaces/NetworkingClient.java | 4 +-
.../interfaces/NetworkingClientManager.java | 8 +-
.../types/NetworkingConnector.java | 2 +-
.../{ => connection}/types/ServerCommand.java | 2 +-
.../connection/types/ServerMessage.java | 3 +
.../framework/networking/server/Game.java | 30 +++++
.../networking/server/GameDefinition.java | 26 ++++
.../networking/server/GameServer.java | 8 ++
.../networking/server/MasterServer.java | 68 ++++++++++
.../networking/server/MessageStore.java | 7 ++
.../networking/server/OnlineGame.java | 7 ++
.../networking/server/ParsedMessage.java | 4 +
.../framework/networking/server/Parser.java | 4 +
.../networking/server/ServableGame.java | 4 +
.../framework/networking/server/Server.java | 51 ++++++++
.../networking/server/ServerHandler.java | 117 ++++++++++++++++++
.../networking/server/ServerMessageStore.java | 27 ++++
.../networking/server/ServerUser.java | 9 ++
.../framework/networking/server/User.java | 40 ++++++
.../networking/types/ServerMessage.java | 3 -
.../NetworkingClientManagerTest.java | 2 +-
.../events/NetworkEventsTest.java | 2 +-
49 files changed, 475 insertions(+), 92 deletions(-)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/Move.java (77%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/LocalFixedRateThreadBehaviour.java (98%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/LocalThreadBehaviour.java (98%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/OnlineThreadBehaviour.java (96%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/gameThreads/OnlineWithSleepThreadBehaviour.java (91%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/LocalPlayer.java (96%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/MiniMaxAI.java (99%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/OnlinePlayer.java (96%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/RandomAI.java (95%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/NetworkingClientEventListener.java (96%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/NetworkingClientManager.java (90%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/clients/TournamentNetworkingClient.java (92%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/events/NetworkEvents.java (97%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/ClientNotFoundException.java (91%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/CouldNotConnectException.java (89%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/exceptions/NetworkingInitializationException.java (76%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/handlers/NetworkingGameClientHandler.java (98%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/interfaces/NetworkingClient.java (66%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/interfaces/NetworkingClientManager.java (57%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/types/NetworkingConnector.java (73%)
rename framework/src/main/java/org/toop/framework/networking/{ => connection}/types/ServerCommand.java (52%)
create mode 100644 framework/src/main/java/org/toop/framework/networking/connection/types/ServerMessage.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/Game.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameServer.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/Parser.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/Server.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/User.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/types/ServerMessage.java
rename framework/src/test/java/org/toop/framework/networking/{ => connection}/events/NetworkEventsTest.java (99%)
diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java
index ef691b4..90040ef 100644
--- a/app/src/main/java/org/toop/app/Server.java
+++ b/app/src/main/java/org/toop/app/Server.java
@@ -14,14 +14,14 @@ import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.gameFramework.controller.GameController;
import org.toop.framework.eventbus.GlobalEventBus;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.framework.networking.clients.TournamentNetworkingClient;
-import org.toop.framework.networking.events.NetworkEvents;
-import org.toop.framework.networking.types.NetworkingConnector;
-import org.toop.game.games.reversi.BitboardReversi;
-import org.toop.game.games.tictactoe.BitboardTicTacToe;
-import org.toop.game.players.ArtificialPlayer;
-import org.toop.game.players.OnlinePlayer;
-import org.toop.game.players.RandomAI;
+import org.toop.framework.networking.connection.clients.TournamentNetworkingClient;
+import org.toop.framework.networking.connection.events.NetworkEvents;
+import org.toop.framework.networking.connection.types.NetworkingConnector;
+import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
+import org.toop.framework.game.players.ArtificialPlayer;
+import org.toop.framework.game.players.OnlinePlayer;
+import org.toop.framework.game.players.RandomAI;
import org.toop.local.AppContext;
import java.util.List;
diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
index 7c2bde0..99b4589 100644
--- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
@@ -2,10 +2,7 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
-import org.toop.game.games.reversi.BitboardReversi;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
+import org.toop.framework.game.games.reversi.BitboardReversi;
public class ReversiBitCanvas extends BitGameCanvas {
public ReversiBitCanvas() {
diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
index 443adbd..6c723cb 100644
--- a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
@@ -2,10 +2,7 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
-import org.toop.game.games.tictactoe.BitboardTicTacToe;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
+import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
public class TicTacToeBitCanvas extends BitGameCanvas{
public TicTacToeBitCanvas() {
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 2c3ad49..80e998f 100644
--- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
@@ -15,8 +15,8 @@ import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour;
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.framework.gameFramework.view.GUIEvents;
-import org.toop.framework.networking.events.NetworkEvents;
-import org.toop.game.players.LocalPlayer;
+import org.toop.framework.networking.connection.events.NetworkEvents;
+import org.toop.framework.game.players.LocalPlayer;
public class GenericGameController> implements GameController {
protected final EventFlow eventFlow = new EventFlow();
diff --git a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
index 40784b0..2f1f3c2 100644
--- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
@@ -3,10 +3,10 @@ package org.toop.app.gameControllers;
import org.toop.app.canvas.ReversiBitCanvas;
import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.gameThreads.LocalThreadBehaviour;
-import org.toop.game.gameThreads.OnlineThreadBehaviour;
-import org.toop.game.games.reversi.BitboardReversi;
-import org.toop.game.players.OnlinePlayer;
+import org.toop.framework.game.gameThreads.LocalThreadBehaviour;
+import org.toop.framework.game.gameThreads.OnlineThreadBehaviour;
+import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.game.players.OnlinePlayer;
public class ReversiBitController extends GenericGameController {
public ReversiBitController(Player[] players) {
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 6307894..b874382 100644
--- a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
@@ -3,11 +3,10 @@ package org.toop.app.gameControllers;
import org.toop.app.canvas.TicTacToeBitCanvas;
import org.toop.framework.gameFramework.model.game.threadBehaviour.ThreadBehaviour;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.gameThreads.LocalFixedRateThreadBehaviour;
-import org.toop.game.gameThreads.LocalThreadBehaviour;
-import org.toop.game.gameThreads.OnlineThreadBehaviour;
-import org.toop.game.games.tictactoe.BitboardTicTacToe;
-import org.toop.game.players.OnlinePlayer;
+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;
public class TicTacToeBitController extends GenericGameController {
public TicTacToeBitController(Player[] players) {
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 9b9bed2..d84b074 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
@@ -2,24 +2,21 @@ package org.toop.app.widget.view;
import javafx.application.Platform;
import org.toop.app.GameInformation;
-import org.toop.app.canvas.ReversiBitCanvas;
-import org.toop.app.canvas.TicTacToeBitCanvas;
-import org.toop.app.gameControllers.GenericGameController;
import org.toop.app.gameControllers.ReversiBitController;
import org.toop.app.gameControllers.TicTacToeBitController;
import org.toop.framework.gameFramework.controller.GameController;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.games.reversi.BitboardReversi;
-import org.toop.game.games.tictactoe.BitboardTicTacToe;
-import org.toop.game.players.ArtificialPlayer;
-import org.toop.game.players.LocalPlayer;
+import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
+import org.toop.framework.game.players.ArtificialPlayer;
+import org.toop.framework.game.players.LocalPlayer;
import org.toop.app.widget.Primitive;
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.MiniMaxAI;
-import org.toop.game.players.RandomAI;
+import org.toop.framework.game.players.MiniMaxAI;
+import org.toop.framework.game.players.RandomAI;
import org.toop.local.AppContext;
import javafx.geometry.Pos;
@@ -27,9 +24,6 @@ import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import org.toop.local.AppSettings;
-import java.util.Arrays;
-import java.util.Random;
-
public class LocalMultiplayerView extends ViewWidget {
private final GameInformation information;
diff --git a/framework/pom.xml b/framework/pom.xml
index b5796c5..9d2055f 100644
--- a/framework/pom.xml
+++ b/framework/pom.xml
@@ -147,7 +147,6 @@
2.42.0
-
diff --git a/game/src/main/java/org/toop/game/Move.java b/framework/src/main/java/org/toop/framework/game/Move.java
similarity index 77%
rename from game/src/main/java/org/toop/game/Move.java
rename to framework/src/main/java/org/toop/framework/game/Move.java
index 62a2b1a..cd1401b 100644
--- a/game/src/main/java/org/toop/game/Move.java
+++ b/framework/src/main/java/org/toop/framework/game/Move.java
@@ -1,3 +1,3 @@
-package org.toop.game;
+package org.toop.framework.game;
// TODO: Remove this, only used in ReversiCanvas. Needs to not
public record Move(int position, char value) {}
diff --git a/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/LocalFixedRateThreadBehaviour.java
similarity index 98%
rename from game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java
rename to framework/src/main/java/org/toop/framework/game/gameThreads/LocalFixedRateThreadBehaviour.java
index 0a9da7f..1104511 100644
--- a/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/LocalFixedRateThreadBehaviour.java
@@ -1,4 +1,4 @@
-package org.toop.game.gameThreads;
+package org.toop.framework.game.gameThreads;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.gameFramework.GameState;
diff --git a/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/LocalThreadBehaviour.java
similarity index 98%
rename from game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java
rename to framework/src/main/java/org/toop/framework/game/gameThreads/LocalThreadBehaviour.java
index 79c57f9..dc5d400 100644
--- a/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/LocalThreadBehaviour.java
@@ -1,4 +1,4 @@
-package org.toop.game.gameThreads;
+package org.toop.framework.game.gameThreads;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour;
diff --git a/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java
similarity index 96%
rename from game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java
rename to framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java
index ae9aa88..5c53bd9 100644
--- a/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineThreadBehaviour.java
@@ -1,4 +1,4 @@
-package org.toop.game.gameThreads;
+package org.toop.framework.game.gameThreads;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour;
@@ -6,7 +6,7 @@ import org.toop.framework.gameFramework.view.GUIEvents;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.game.SupportsOnlinePlay;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.players.OnlinePlayer;
+import org.toop.framework.game.players.OnlinePlayer;
/**
* Handles online multiplayer game logic.
diff --git a/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineWithSleepThreadBehaviour.java
similarity index 91%
rename from game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java
rename to framework/src/main/java/org/toop/framework/game/gameThreads/OnlineWithSleepThreadBehaviour.java
index a666f8d..6ba3351 100644
--- a/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/OnlineWithSleepThreadBehaviour.java
@@ -1,7 +1,6 @@
-package org.toop.game.gameThreads;
+package org.toop.framework.game.gameThreads;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.framework.networking.events.NetworkEvents;
/**
* Online thread behaviour that adds a fixed delay before processing
diff --git a/game/src/main/java/org/toop/game/players/LocalPlayer.java b/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java
similarity index 96%
rename from game/src/main/java/org/toop/game/players/LocalPlayer.java
rename to framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java
index 8f3b94d..3bbfe97 100644
--- a/game/src/main/java/org/toop/game/players/LocalPlayer.java
+++ b/framework/src/main/java/org/toop/framework/game/players/LocalPlayer.java
@@ -1,8 +1,7 @@
-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;
-import org.toop.framework.gameFramework.model.player.Player;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
diff --git a/game/src/main/java/org/toop/game/players/MiniMaxAI.java b/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
similarity index 99%
rename from game/src/main/java/org/toop/game/players/MiniMaxAI.java
rename to framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
index 440bb50..de67068 100644
--- a/game/src/main/java/org/toop/game/players/MiniMaxAI.java
+++ b/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
@@ -1,4 +1,4 @@
-package org.toop.game.players;
+package org.toop.framework.game.players;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.PlayResult;
diff --git a/game/src/main/java/org/toop/game/players/OnlinePlayer.java b/framework/src/main/java/org/toop/framework/game/players/OnlinePlayer.java
similarity index 96%
rename from game/src/main/java/org/toop/game/players/OnlinePlayer.java
rename to framework/src/main/java/org/toop/framework/game/players/OnlinePlayer.java
index 9f011c0..60a45da 100644
--- a/game/src/main/java/org/toop/game/players/OnlinePlayer.java
+++ b/framework/src/main/java/org/toop/framework/game/players/OnlinePlayer.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;
diff --git a/game/src/main/java/org/toop/game/players/RandomAI.java b/framework/src/main/java/org/toop/framework/game/players/RandomAI.java
similarity index 95%
rename from game/src/main/java/org/toop/game/players/RandomAI.java
rename to framework/src/main/java/org/toop/framework/game/players/RandomAI.java
index 2d0fe02..f7006fb 100644
--- a/game/src/main/java/org/toop/game/players/RandomAI.java
+++ b/framework/src/main/java/org/toop/framework/game/players/RandomAI.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.AbstractAI;
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/controller/GameController.java b/framework/src/main/java/org/toop/framework/gameFramework/controller/GameController.java
index f355dc5..5591d25 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/controller/GameController.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/controller/GameController.java
@@ -1,8 +1,7 @@
package org.toop.framework.gameFramework.controller;
-import org.toop.framework.gameFramework.model.game.SupportsOnlinePlay;
import org.toop.framework.gameFramework.model.game.threadBehaviour.Controllable;
-import org.toop.framework.networking.events.NetworkEvents;
+import org.toop.framework.networking.connection.events.NetworkEvents;
public interface GameController extends Controllable, UpdatesGameUI {
/** Called when it is this player's turn to make a move. */
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/game/SupportsOnlinePlay.java b/framework/src/main/java/org/toop/framework/gameFramework/model/game/SupportsOnlinePlay.java
index 1cc1641..965056e 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/game/SupportsOnlinePlay.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/game/SupportsOnlinePlay.java
@@ -1,7 +1,5 @@
package org.toop.framework.gameFramework.model.game;
-import org.toop.framework.networking.events.NetworkEvents;
-
/**
* Interface for games that support online multiplayer play.
*
diff --git a/framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java b/framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientEventListener.java
similarity index 96%
rename from framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java
rename to framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientEventListener.java
index 5a9a08d..05e9bc8 100644
--- a/framework/src/main/java/org/toop/framework/networking/NetworkingClientEventListener.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientEventListener.java
@@ -1,13 +1,13 @@
-package org.toop.framework.networking;
+package org.toop.framework.networking.connection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.bus.EventBus;
-import org.toop.framework.networking.events.NetworkEvents;
-import org.toop.framework.networking.exceptions.ClientNotFoundException;
-import org.toop.framework.networking.interfaces.NetworkingClientManager;
+import org.toop.framework.networking.connection.events.NetworkEvents;
+import org.toop.framework.networking.connection.exceptions.ClientNotFoundException;
+import org.toop.framework.networking.connection.interfaces.NetworkingClientManager;
public class NetworkingClientEventListener {
private static final Logger logger = LogManager.getLogger(NetworkingClientEventListener.class);
diff --git a/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java b/framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientManager.java
similarity index 90%
rename from framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java
rename to framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientManager.java
index 4f1d2ac..1bd0643 100644
--- a/framework/src/main/java/org/toop/framework/networking/NetworkingClientManager.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/NetworkingClientManager.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking;
+package org.toop.framework.networking.connection;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -10,13 +10,13 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.bus.EventBus;
-import org.toop.framework.networking.events.NetworkEvents;
-import org.toop.framework.networking.exceptions.ClientNotFoundException;
-import org.toop.framework.networking.exceptions.CouldNotConnectException;
-import org.toop.framework.networking.interfaces.NetworkingClient;
-import org.toop.framework.networking.types.NetworkingConnector;
+import org.toop.framework.networking.connection.events.NetworkEvents;
+import org.toop.framework.networking.connection.exceptions.ClientNotFoundException;
+import org.toop.framework.networking.connection.exceptions.CouldNotConnectException;
+import org.toop.framework.networking.connection.interfaces.NetworkingClient;
+import org.toop.framework.networking.connection.types.NetworkingConnector;
-public class NetworkingClientManager implements org.toop.framework.networking.interfaces.NetworkingClientManager {
+public class NetworkingClientManager implements org.toop.framework.networking.connection.interfaces.NetworkingClientManager {
private static final Logger logger = LogManager.getLogger(NetworkingClientManager.class);
private final EventBus eventBus;
diff --git a/framework/src/main/java/org/toop/framework/networking/clients/TournamentNetworkingClient.java b/framework/src/main/java/org/toop/framework/networking/connection/clients/TournamentNetworkingClient.java
similarity index 92%
rename from framework/src/main/java/org/toop/framework/networking/clients/TournamentNetworkingClient.java
rename to framework/src/main/java/org/toop/framework/networking/connection/clients/TournamentNetworkingClient.java
index 47adef9..1976e91 100644
--- a/framework/src/main/java/org/toop/framework/networking/clients/TournamentNetworkingClient.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/clients/TournamentNetworkingClient.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.clients;
+package org.toop.framework.networking.connection.clients;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
@@ -12,9 +12,9 @@ import io.netty.util.CharsetUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.bus.EventBus;
-import org.toop.framework.networking.exceptions.CouldNotConnectException;
-import org.toop.framework.networking.handlers.NetworkingGameClientHandler;
-import org.toop.framework.networking.interfaces.NetworkingClient;
+import org.toop.framework.networking.connection.exceptions.CouldNotConnectException;
+import org.toop.framework.networking.connection.handlers.NetworkingGameClientHandler;
+import org.toop.framework.networking.connection.interfaces.NetworkingClient;
import java.net.InetSocketAddress;
diff --git a/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
similarity index 97%
rename from framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java
rename to framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
index 891fb39..d6c0140 100644
--- a/framework/src/main/java/org/toop/framework/networking/events/NetworkEvents.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.events;
+package org.toop.framework.networking.connection.events;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -6,8 +6,8 @@ import java.util.concurrent.CompletableFuture;
import org.toop.annotations.AutoResponseResult;
import org.toop.framework.eventbus.GlobalEventBus;
import org.toop.framework.eventbus.events.*;
-import org.toop.framework.networking.interfaces.NetworkingClient;
-import org.toop.framework.networking.types.NetworkingConnector;
+import org.toop.framework.networking.connection.interfaces.NetworkingClient;
+import org.toop.framework.networking.connection.types.NetworkingConnector;
/**
* Defines all event types related to the networking subsystem.
diff --git a/framework/src/main/java/org/toop/framework/networking/exceptions/ClientNotFoundException.java b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/ClientNotFoundException.java
similarity index 91%
rename from framework/src/main/java/org/toop/framework/networking/exceptions/ClientNotFoundException.java
rename to framework/src/main/java/org/toop/framework/networking/connection/exceptions/ClientNotFoundException.java
index 2506b26..7d8594a 100644
--- a/framework/src/main/java/org/toop/framework/networking/exceptions/ClientNotFoundException.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/ClientNotFoundException.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.exceptions;
+package org.toop.framework.networking.connection.exceptions;
/**
* Thrown when an operation is attempted on a networking client
diff --git a/framework/src/main/java/org/toop/framework/networking/exceptions/CouldNotConnectException.java b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/CouldNotConnectException.java
similarity index 89%
rename from framework/src/main/java/org/toop/framework/networking/exceptions/CouldNotConnectException.java
rename to framework/src/main/java/org/toop/framework/networking/connection/exceptions/CouldNotConnectException.java
index 839fb0b..a364c9c 100644
--- a/framework/src/main/java/org/toop/framework/networking/exceptions/CouldNotConnectException.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/CouldNotConnectException.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.exceptions;
+package org.toop.framework.networking.connection.exceptions;
public class CouldNotConnectException extends RuntimeException {
diff --git a/framework/src/main/java/org/toop/framework/networking/exceptions/NetworkingInitializationException.java b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/NetworkingInitializationException.java
similarity index 76%
rename from framework/src/main/java/org/toop/framework/networking/exceptions/NetworkingInitializationException.java
rename to framework/src/main/java/org/toop/framework/networking/connection/exceptions/NetworkingInitializationException.java
index 0ff430a..3b2582f 100644
--- a/framework/src/main/java/org/toop/framework/networking/exceptions/NetworkingInitializationException.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/exceptions/NetworkingInitializationException.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.exceptions;
+package org.toop.framework.networking.connection.exceptions;
public class NetworkingInitializationException extends RuntimeException {
public NetworkingInitializationException(String message, Throwable cause) {
diff --git a/framework/src/main/java/org/toop/framework/networking/handlers/NetworkingGameClientHandler.java b/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java
similarity index 98%
rename from framework/src/main/java/org/toop/framework/networking/handlers/NetworkingGameClientHandler.java
rename to framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java
index 7b4bf69..a313d97 100644
--- a/framework/src/main/java/org/toop/framework/networking/handlers/NetworkingGameClientHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/handlers/NetworkingGameClientHandler.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.handlers;
+package org.toop.framework.networking.connection.handlers;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -9,7 +9,7 @@ import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.toop.framework.eventbus.bus.EventBus;
-import org.toop.framework.networking.events.NetworkEvents;
+import org.toop.framework.networking.connection.events.NetworkEvents;
public class NetworkingGameClientHandler extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger(NetworkingGameClientHandler.class);
diff --git a/framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClient.java b/framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClient.java
similarity index 66%
rename from framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClient.java
rename to framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClient.java
index 09b215c..31731d3 100644
--- a/framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClient.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClient.java
@@ -1,6 +1,6 @@
-package org.toop.framework.networking.interfaces;
+package org.toop.framework.networking.connection.interfaces;
-import org.toop.framework.networking.exceptions.CouldNotConnectException;
+import org.toop.framework.networking.connection.exceptions.CouldNotConnectException;
import java.net.InetSocketAddress;
diff --git a/framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClientManager.java b/framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClientManager.java
similarity index 57%
rename from framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClientManager.java
rename to framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClientManager.java
index c236080..31fcaa2 100644
--- a/framework/src/main/java/org/toop/framework/networking/interfaces/NetworkingClientManager.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/interfaces/NetworkingClientManager.java
@@ -1,8 +1,8 @@
-package org.toop.framework.networking.interfaces;
+package org.toop.framework.networking.connection.interfaces;
-import org.toop.framework.networking.exceptions.ClientNotFoundException;
-import org.toop.framework.networking.exceptions.CouldNotConnectException;
-import org.toop.framework.networking.types.NetworkingConnector;
+import org.toop.framework.networking.connection.exceptions.ClientNotFoundException;
+import org.toop.framework.networking.connection.exceptions.CouldNotConnectException;
+import org.toop.framework.networking.connection.types.NetworkingConnector;
public interface NetworkingClientManager {
void startClient(
diff --git a/framework/src/main/java/org/toop/framework/networking/types/NetworkingConnector.java b/framework/src/main/java/org/toop/framework/networking/connection/types/NetworkingConnector.java
similarity index 73%
rename from framework/src/main/java/org/toop/framework/networking/types/NetworkingConnector.java
rename to framework/src/main/java/org/toop/framework/networking/connection/types/NetworkingConnector.java
index ee6ed44..ca8fc40 100644
--- a/framework/src/main/java/org/toop/framework/networking/types/NetworkingConnector.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/types/NetworkingConnector.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.types;
+package org.toop.framework.networking.connection.types;
import java.util.concurrent.TimeUnit;
diff --git a/framework/src/main/java/org/toop/framework/networking/types/ServerCommand.java b/framework/src/main/java/org/toop/framework/networking/connection/types/ServerCommand.java
similarity index 52%
rename from framework/src/main/java/org/toop/framework/networking/types/ServerCommand.java
rename to framework/src/main/java/org/toop/framework/networking/connection/types/ServerCommand.java
index e11bb61..9472810 100644
--- a/framework/src/main/java/org/toop/framework/networking/types/ServerCommand.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/types/ServerCommand.java
@@ -1,3 +1,3 @@
-package org.toop.framework.networking.types;
+package org.toop.framework.networking.connection.types;
public record ServerCommand(long clientId, String command) {}
diff --git a/framework/src/main/java/org/toop/framework/networking/connection/types/ServerMessage.java b/framework/src/main/java/org/toop/framework/networking/connection/types/ServerMessage.java
new file mode 100644
index 0000000..3ca1158
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/connection/types/ServerMessage.java
@@ -0,0 +1,3 @@
+package org.toop.framework.networking.connection.types;
+
+public record ServerMessage(String message) {}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
new file mode 100644
index 0000000..057e37c
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -0,0 +1,30 @@
+package org.toop.framework.networking.server;
+
+import org.toop.framework.game.BitboardGame;
+
+public class Game implements OnlineGame {
+
+ private long id;
+ private User[] users;
+ private GameDefinition> game;
+
+ public Game(GameDefinition game, User... users) {
+ this.game = game;
+ this.users = users;
+ }
+
+ @Override
+ public long id() {
+ return id;
+ }
+
+ @Override
+ public GameDefinition game() {
+ return game;
+ }
+
+ @Override
+ public User[] users() {
+ return users;
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java b/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
new file mode 100644
index 0000000..629bc24
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
@@ -0,0 +1,26 @@
+package org.toop.framework.networking.server;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class GameDefinition {
+ private final String name;
+ private final Class game;
+
+ public GameDefinition(String name, Class game) {
+ this.name = name;
+ this.game = game;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public T create(String... users) {
+ try {
+ return game.getDeclaredConstructor().newInstance(users);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameServer.java b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
new file mode 100644
index 0000000..39a03f7
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
@@ -0,0 +1,8 @@
+package org.toop.framework.networking.server;
+
+public interface GameServer {
+// List> gameTypes();
+// List> ongoingGames();
+// void startGame(String gameType, User... users);
+// String[] onlineUsers();
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
new file mode 100644
index 0000000..634ae6f
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
@@ -0,0 +1,68 @@
+package org.toop.framework.networking.server;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.nio.NioIoHandler;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import org.toop.framework.SnowflakeGenerator;
+import org.toop.framework.game.BitboardGame;
+
+import java.util.Map;
+
+public class MasterServer {
+ private final int port;
+ public final Server gs;
+
+ public MasterServer(int port, Map>> gameTypes) {
+ this.port = port;
+ this.gs = new Server(gameTypes);
+ }
+
+ public void start() throws InterruptedException {
+
+ EventLoopGroup bossGroup = new NioEventLoopGroup(1);
+ EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
+
+ try {
+
+ ServerBootstrap bootstrap = new ServerBootstrap();
+ bootstrap.group(workerGroup);
+ bootstrap.channel(NioServerSocketChannel.class);
+ bootstrap.option(ChannelOption.SO_BACKLOG, 128);
+ bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
+ bootstrap.handler(new LoggingHandler(LogLevel.INFO));
+ bootstrap.childHandler(
+ new ChannelInitializer() {
+ @Override
+ protected void initChannel(NioSocketChannel ch) {
+
+ ChannelPipeline pipeline = ch.pipeline();
+
+ pipeline.addLast(new LineBasedFrameDecoder(8192));
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new StringEncoder());
+
+ long userid = SnowflakeGenerator.nextId();
+ User user = new User(userid, ""+userid);
+ pipeline.addLast(new ServerHandler(user, gs));
+ }
+ }
+ );
+
+ ChannelFuture future = bootstrap.bind(port).sync();
+ System.out.println("MasterServer listening on port " + port);
+
+ future.channel().closeFuture().sync();
+ } finally {
+ bossGroup.shutdownGracefully();
+ workerGroup.shutdownGracefully();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java b/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
new file mode 100644
index 0000000..6fbba3b
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server;
+
+public interface MessageStore {
+ void add(String message);
+ String get();
+ void reset();
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
new file mode 100644
index 0000000..59b3399
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server;
+
+public interface OnlineGame {
+ long id();
+ GameDefinition game();
+ User[] users();
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java b/framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java
new file mode 100644
index 0000000..5f8e550
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java
@@ -0,0 +1,4 @@
+package org.toop.framework.networking.server;
+
+public record ParsedMessage(String command, String... args) {}
+
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Parser.java b/framework/src/main/java/org/toop/framework/networking/server/Parser.java
new file mode 100644
index 0000000..016f797
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/Parser.java
@@ -0,0 +1,4 @@
+package org.toop.framework.networking.server;
+
+public class Parser {
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java b/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
new file mode 100644
index 0000000..17dd3a9
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
@@ -0,0 +1,4 @@
+package org.toop.framework.networking.server;
+
+public interface ServableGame {
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
new file mode 100644
index 0000000..757c490
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -0,0 +1,51 @@
+package org.toop.framework.networking.server;
+
+import org.toop.framework.game.BitboardGame;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class Server implements GameServer {
+
+ final private Map>> gameTypes;
+ public List games = new ArrayList<>();
+ final private Map users = new ConcurrentHashMap<>();
+
+ public Server(Map>> gameTypes) {
+ this.gameTypes = gameTypes;
+ }
+
+ public void addUser(ServerUser user) {
+ users.putIfAbsent(user.id(), user);
+ }
+
+ public void removeUser(ServerUser user) {
+ users.remove(user.id());
+ }
+
+ public String[] gameTypes() {
+ return gameTypes.keySet().toArray(new String[0]);
+ }
+
+// public List>> ongoingGames() {
+// return List.of();
+// }
+
+ public void startGame(String gameType, User... users) {
+ if (!gameTypes.containsKey(gameType)) return;
+
+ try {
+ var game = new Game(gameTypes.get(gameType).create(), users);
+ games.addLast(new Game(game, users));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ public String[] onlineUsers() {
+ return users.values().stream().map(ServerUser::name).toArray(String[]::new);
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
new file mode 100644
index 0000000..f5da259
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -0,0 +1,117 @@
+package org.toop.framework.networking.server;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class ServerHandler extends SimpleChannelInboundHandler {
+
+ private final User user;
+ private final Server server;
+
+ public ServerHandler(User user, Server server) {
+ this.user = user;
+ this.server = server;
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ ctx.writeAndFlush("WELCOME " + user.id() + "\n");
+
+ user.setCtx(ctx);
+ server.addUser(user); // TODO set correct name on login
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, String msg) {
+ ParsedMessage p = parse(msg);
+ if (p == null) return;
+
+ IO.println(p.command() + " " + Arrays.toString(p.args()));
+
+ switch (p.command()) {
+ case "ping" -> ctx.writeAndFlush("PONG\n");
+ case "login" -> handleLogin(p);
+ case "get" -> handleGet(p);
+ case "subscribe" -> handleSubscribe(p);
+ case "move" -> handleMove(p);
+ case "challenge" -> handleChallenge(p);
+ case "message" -> handleMessage(p);
+ case "help" -> handleHelp(p);
+ default -> ctx.writeAndFlush("ERROR Unknown command\n");
+ }
+ }
+
+ private boolean allowedArgs(String... args) {
+ if (args.length < 1) return false;
+ return true;
+ }
+
+ private void handleLogin(ParsedMessage p) {
+
+ if (!allowedArgs(p.args())) return;
+
+ user.setName(p.args()[0]);
+ }
+
+ private void handleGet(ParsedMessage p) {
+ if (!allowedArgs(p.args())) return;
+
+ switch (p.args()[0]) {
+ case "playerlist" -> user.ctx().writeAndFlush(Arrays.toString(server.onlineUsers()));
+ case "gamelist" -> user.ctx().writeAndFlush(Arrays.toString(server.gameTypes()));
+ }
+ }
+
+ private void handleSubscribe(ParsedMessage p) {
+ // TODO
+ }
+
+ private void handleHelp(ParsedMessage p) {
+ // TODO
+ }
+
+ private void handleMessage(ParsedMessage p) {
+ // TODO
+ }
+
+ private void handleChallenge(ParsedMessage p) {
+ // TODO
+ }
+
+ private void handleMove(ParsedMessage p) {
+ // TODO
+ }
+
+ private ParsedMessage parse(String msg) {
+ // TODO, what if empty string.
+
+ if (msg.isEmpty()) return null;
+
+ msg = msg.trim().toLowerCase();
+
+ List parts = new LinkedList<>(List.of(msg.split(" ")));
+
+ if (parts.size() > 1) {
+ String command = parts.removeFirst();
+ return new ParsedMessage(command, parts.toArray(String[]::new));
+ }
+ else {
+ return new ParsedMessage(msg);
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+ ctx.close();
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ server.removeUser(user);
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java b/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
new file mode 100644
index 0000000..22af1d7
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
@@ -0,0 +1,27 @@
+package org.toop.framework.networking.server;
+
+import java.util.Queue;
+
+public class ServerMessageStore implements MessageStore {
+
+ Queue messageQueue;
+
+ public ServerMessageStore(Queue messageQueue) {
+ this.messageQueue = messageQueue;
+ }
+
+ @Override
+ public void add(String message) {
+ messageQueue.offer(message);
+ }
+
+ @Override
+ public String get() {
+ return messageQueue.poll();
+ }
+
+ @Override
+ public void reset() {
+ messageQueue.clear();
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
new file mode 100644
index 0000000..8e6e7a5
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
@@ -0,0 +1,9 @@
+package org.toop.framework.networking.server;
+
+import java.net.InetSocketAddress;
+
+public interface ServerUser {
+ long id();
+ String name();
+ void setName(String name);
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
new file mode 100644
index 0000000..8ae5026
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -0,0 +1,40 @@
+package org.toop.framework.networking.server;
+
+import io.netty.channel.ChannelHandlerContext;
+
+import java.net.InetSocketAddress;
+
+public class User implements ServerUser {
+ final private long id;
+ private String name;
+ private ChannelHandlerContext connectionContext;
+
+ public User(long userId, String name) {
+ this.id = userId;
+ this.name = name;
+ }
+
+ @Override
+ public long id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public ChannelHandlerContext ctx() {
+ return connectionContext;
+ }
+
+ public void setCtx(ChannelHandlerContext ctx) {
+ this.connectionContext = ctx;
+ }
+
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/types/ServerMessage.java b/framework/src/main/java/org/toop/framework/networking/types/ServerMessage.java
deleted file mode 100644
index 606607d..0000000
--- a/framework/src/main/java/org/toop/framework/networking/types/ServerMessage.java
+++ /dev/null
@@ -1,3 +0,0 @@
-package org.toop.framework.networking.types;
-
-public record ServerMessage(String message) {}
diff --git a/framework/src/test/java/org/toop/framework/networking/NetworkingClientManagerTest.java b/framework/src/test/java/org/toop/framework/networking/NetworkingClientManagerTest.java
index e626683..4ce747b 100644
--- a/framework/src/test/java/org/toop/framework/networking/NetworkingClientManagerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/NetworkingClientManagerTest.java
@@ -9,7 +9,7 @@
//import org.mockito.*;
//import org.toop.framework.SnowflakeGenerator;
//import org.toop.framework.eventbus.EventFlow;
-//import org.toop.framework.networking.events.NetworkEvents;
+//import org.toop.framework.networking.connection.events.NetworkEvents;
//
//class NetworkingClientManagerTest {
//
diff --git a/framework/src/test/java/org/toop/framework/networking/events/NetworkEventsTest.java b/framework/src/test/java/org/toop/framework/networking/connection/events/NetworkEventsTest.java
similarity index 99%
rename from framework/src/test/java/org/toop/framework/networking/events/NetworkEventsTest.java
rename to framework/src/test/java/org/toop/framework/networking/connection/events/NetworkEventsTest.java
index 5170381..635772d 100644
--- a/framework/src/test/java/org/toop/framework/networking/events/NetworkEventsTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/connection/events/NetworkEventsTest.java
@@ -1,4 +1,4 @@
-//package org.toop.framework.networking.events;
+//package org.toop.framework.networking.connection.events;
//
//import static org.junit.jupiter.api.Assertions.*;
//
From 84e411fa38ec08ac5c192f9e875e3cce1a34a10e Mon Sep 17 00:00:00 2001
From: Bas de Jong
Date: Fri, 12 Dec 2025 15:17:12 +0100
Subject: [PATCH 02/35] Moves
---
.../main/java/org/toop/framework}/game/BitboardGame.java | 3 +--
.../framework}/game/games/reversi/BitboardReversi.java | 7 ++++---
.../framework}/game/games/tictactoe/BitboardTicTacToe.java | 7 ++++---
.../org/toop/framework}/game/players/ArtificialPlayer.java | 2 +-
4 files changed, 10 insertions(+), 9 deletions(-)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/BitboardGame.java (96%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/games/reversi/BitboardReversi.java (96%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/games/tictactoe/BitboardTicTacToe.java (93%)
rename {game/src/main/java/org/toop => framework/src/main/java/org/toop/framework}/game/players/ArtificialPlayer.java (97%)
diff --git a/game/src/main/java/org/toop/game/BitboardGame.java b/framework/src/main/java/org/toop/framework/game/BitboardGame.java
similarity index 96%
rename from game/src/main/java/org/toop/game/BitboardGame.java
rename to framework/src/main/java/org/toop/framework/game/BitboardGame.java
index 4ebdb95..2090e95 100644
--- a/game/src/main/java/org/toop/game/BitboardGame.java
+++ b/framework/src/main/java/org/toop/framework/game/BitboardGame.java
@@ -1,10 +1,9 @@
-package org.toop.game;
+package org.toop.framework.game;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.Player;
import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
// There is AI performance to be gained by getting rid of non-primitives and thus speeding up deepCopy
public abstract class BitboardGame> implements TurnBasedGame {
diff --git a/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
similarity index 96%
rename from game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java
rename to framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
index f380bef..0ea4346 100644
--- a/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java
+++ b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
@@ -1,11 +1,12 @@
-package org.toop.game.games.reversi;
+package org.toop.framework.game.games.reversi;
+import org.toop.framework.game.BitboardGame;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.BitboardGame;
+import org.toop.framework.networking.server.ServableGame;
-public class BitboardReversi extends BitboardGame {
+public class BitboardReversi extends BitboardGame implements ServableGame {
public record Score(int black, int white) {}
diff --git a/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
similarity index 93%
rename from game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java
rename to framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
index 0927431..2d77a9f 100644
--- a/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java
+++ b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
@@ -1,11 +1,12 @@
-package org.toop.game.games.tictactoe;
+package org.toop.framework.game.games.tictactoe;
+import org.toop.framework.game.BitboardGame;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.BitboardGame;
+import org.toop.framework.networking.server.ServableGame;
-public class BitboardTicTacToe extends BitboardGame {
+public class BitboardTicTacToe extends BitboardGame implements ServableGame {
private final long[] winningLines = {
0b111000000L, // top row
0b000111000L, // middle row
diff --git a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java b/framework/src/main/java/org/toop/framework/game/players/ArtificialPlayer.java
similarity index 97%
rename from game/src/main/java/org/toop/game/players/ArtificialPlayer.java
rename to framework/src/main/java/org/toop/framework/game/players/ArtificialPlayer.java
index 418cbed..75e4078 100644
--- a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java
+++ b/framework/src/main/java/org/toop/framework/game/players/ArtificialPlayer.java
@@ -1,4 +1,4 @@
-package org.toop.game.players;
+package org.toop.framework.game.players;
import org.toop.framework.gameFramework.model.player.*;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
From 2599f9fa409ce0a473b8c5edea034e26e760c7d9 Mon Sep 17 00:00:00 2001
From: Bas de Jong
Date: Fri, 12 Dec 2025 15:17:29 +0100
Subject: [PATCH 03/35] Testing code
---
app/src/main/java/org/toop/app/App.java | 35 +++++++++++++++++--------
1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index 5d99acd..b9e0d8d 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -1,10 +1,14 @@
package org.toop.app;
+import javafx.application.Application;
import javafx.application.Platform;
+import javafx.geometry.Pos;
+import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyEvent;
-
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
import org.toop.app.widget.Primitive;
import org.toop.app.widget.WidgetContainer;
import org.toop.app.widget.complex.LoadingWidget;
@@ -16,8 +20,12 @@ import org.toop.framework.audio.*;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.GlobalEventBus;
-import org.toop.framework.networking.NetworkingClientEventListener;
-import org.toop.framework.networking.NetworkingClientManager;
+import org.toop.framework.game.BitboardGame;
+import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.networking.connection.NetworkingClientEventListener;
+import org.toop.framework.networking.connection.NetworkingClientManager;
+import org.toop.framework.networking.server.GameDefinition;
+import org.toop.framework.networking.server.MasterServer;
import org.toop.framework.resource.ResourceLoader;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.events.AssetLoaderEvents;
@@ -27,13 +35,8 @@ import org.toop.framework.resource.resources.SoundEffectAsset;
import org.toop.local.AppContext;
import org.toop.local.AppSettings;
-import javafx.application.Application;
-import javafx.geometry.Pos;
-import javafx.scene.Scene;
-import javafx.scene.layout.StackPane;
-import javafx.stage.Stage;
-
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -86,7 +89,7 @@ public final class App extends Application {
AppSettings.applySettings();
- setKeybinds(root);
+ setKeybinds(root);
LoadingWidget loading = new LoadingWidget(Primitive.text(
"Loading...", false), 0, 0, Integer.MAX_VALUE, false, false // Just set a high default
@@ -138,7 +141,17 @@ public final class App extends Application {
stage.show();
- }
+ var games = new ConcurrentHashMap>>();
+ games.put("tictactoe", new GameDefinition<>("tictactoe", BitboardReversi.class));
+ games.put("reversi", new GameDefinition<>("reversi", BitboardReversi.class));
+ var s = new MasterServer(6666, games);
+ try {
+ s.start();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
private void setKeybinds(StackPane root) {
root.addEventHandler(KeyEvent.KEY_PRESSED,event -> {
From fa9c2ce32b0c20308875bfab6a6bee4518cd2cbd Mon Sep 17 00:00:00 2001
From: Stef
Date: Fri, 12 Dec 2025 15:53:24 +0100
Subject: [PATCH 04/35] Removed Generics, pray nothing breaks.
---
app/src/main/java/org/toop/app/Server.java | 12 ++++++------
.../org/toop/app/canvas/BitGameCanvas.java | 2 +-
.../java/org/toop/app/canvas/GameCanvas.java | 3 +--
.../java/org/toop/app/canvas/GameDrawer.java | 4 ++--
.../org/toop/app/canvas/ReversiBitCanvas.java | 9 +++++----
.../toop/app/canvas/TicTacToeBitCanvas.java | 9 +++++----
.../gameControllers/GenericGameController.java | 16 +++++++++-------
.../gameControllers/ReversiBitController.java | 12 ++++++------
.../TicTacToeBitController.java | 12 ++++++------
.../app/widget/view/LocalMultiplayerView.java | 16 ++++++++--------
.../model/game/PlayerProvider.java | 4 ++--
.../model/game/TurnBasedGame.java | 2 +-
.../AbstractThreadBehaviour.java | 6 +++---
.../gameFramework/model/player/AI.java | 2 +-
.../gameFramework/model/player/AbstractAI.java | 2 +-
.../model/player/AbstractPlayer.java | 6 +++---
.../model/player/MoveProvider.java | 4 ++--
.../gameFramework/model/player/Player.java | 2 +-
.../main/java/org/toop/game/BitboardGame.java | 14 +++++++-------
.../LocalFixedRateThreadBehaviour.java | 6 +++---
.../game/gameThreads/LocalThreadBehaviour.java | 6 +++---
.../gameThreads/OnlineThreadBehaviour.java | 6 +++---
.../OnlineWithSleepThreadBehaviour.java | 4 ++--
.../game/games/reversi/BitboardReversi.java | 4 ++--
.../games/tictactoe/BitboardTicTacToe.java | 4 ++--
.../toop/game/players/ArtificialPlayer.java | 14 +++++++-------
.../org/toop/game/players/LocalPlayer.java | 14 +++++++-------
.../java/org/toop/game/players/MiniMaxAI.java | 18 +++++++++---------
.../org/toop/game/players/OnlinePlayer.java | 8 ++++----
.../java/org/toop/game/players/RandomAI.java | 8 ++++----
30 files changed, 116 insertions(+), 113 deletions(-)
diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java
index ef691b4..a781a70 100644
--- a/app/src/main/java/org/toop/app/Server.java
+++ b/app/src/main/java/org/toop/app/Server.java
@@ -214,15 +214,15 @@ public final class Server {
switch (type) {
case TICTACTOE ->{
- Player[] players = new Player[2];
- players[(myTurn + 1) % 2] = new OnlinePlayer<>(response.opponent());
- players[myTurn] = new ArtificialPlayer<>(new RandomAI(), user);
+ Player[] players = new Player[2];
+ players[(myTurn + 1) % 2] = new OnlinePlayer(response.opponent());
+ players[myTurn] = new ArtificialPlayer(new RandomAI(), user);
gameController = new TicTacToeBitController(players);
}
case REVERSI -> {
- Player[] players = new Player[2];
- players[(myTurn + 1) % 2] = new OnlinePlayer<>(response.opponent());
- players[myTurn] = new ArtificialPlayer<>(new RandomAI(), user);
+ Player[] players = new Player[2];
+ players[(myTurn + 1) % 2] = new OnlinePlayer(response.opponent());
+ players[myTurn] = new ArtificialPlayer(new RandomAI(), user);
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 85c6f7d..5beb7af 100644
--- a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java
@@ -14,7 +14,7 @@ import org.toop.framework.gameFramework.view.GUIEvents;
import java.util.function.Consumer;
-public abstract class BitGameCanvas> implements GameCanvas {
+public abstract class BitGameCanvas implements GameCanvas {
protected record Cell(float x, float y, float width, float height) {
public boolean isInside(double x, double y) {
return x >= this.x && x <= this.x + width &&
diff --git a/app/src/main/java/org/toop/app/canvas/GameCanvas.java b/app/src/main/java/org/toop/app/canvas/GameCanvas.java
index d1361c5..1739d66 100644
--- a/app/src/main/java/org/toop/app/canvas/GameCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/GameCanvas.java
@@ -1,8 +1,7 @@
package org.toop.app.canvas;
import javafx.scene.canvas.Canvas;
-import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface GameCanvas> extends GameDrawer{
+public interface GameCanvas extends GameDrawer{
Canvas getCanvas();
}
diff --git a/app/src/main/java/org/toop/app/canvas/GameDrawer.java b/app/src/main/java/org/toop/app/canvas/GameDrawer.java
index 261334c..2adb6b0 100644
--- a/app/src/main/java/org/toop/app/canvas/GameDrawer.java
+++ b/app/src/main/java/org/toop/app/canvas/GameDrawer.java
@@ -2,6 +2,6 @@ package org.toop.app.canvas;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface GameDrawer> {
- void redraw(T gameCopy);
+public interface GameDrawer {
+ void redraw(TurnBasedGame gameCopy);
}
diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
index 7c2bde0..016d6b3 100644
--- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
@@ -2,12 +2,13 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.game.games.reversi.BitboardReversi;
import java.util.Arrays;
import java.util.function.Consumer;
-public class ReversiBitCanvas extends BitGameCanvas {
+public class ReversiBitCanvas extends BitGameCanvas {
public ReversiBitCanvas() {
super(Color.GRAY, new Color(0f, 0.4f, 0.2f, 1f), (App.getHeight() / 4) * 3, (App.getHeight() / 4) * 3, 8, 8, 5, true);
canvas.setOnMouseMoved(event -> {
@@ -33,10 +34,10 @@ public class ReversiBitCanvas extends BitGameCanvas {
}
@Override
- public void redraw(BitboardReversi gameCopy) {
+ public void redraw(TurnBasedGame gameCopy) {
clearAll();
long[] board = gameCopy.getBoard();
- loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, i));
- loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, i));
+ loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, (int)i));
+ loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, (int)i));
}
}
diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
index 443adbd..3520417 100644
--- a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
@@ -2,12 +2,13 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.game.games.tictactoe.BitboardTicTacToe;
import java.util.Arrays;
import java.util.function.Consumer;
-public class TicTacToeBitCanvas extends BitGameCanvas{
+public class TicTacToeBitCanvas extends BitGameCanvas{
public TicTacToeBitCanvas() {
super(
Color.GRAY,
@@ -22,14 +23,14 @@ public class TicTacToeBitCanvas extends BitGameCanvas{
}
@Override
- public void redraw(BitboardTicTacToe gameCopy) {
+ public void redraw(TurnBasedGame gameCopy) {
clearAll();
drawMoves(gameCopy.getBoard());
}
private void drawMoves(long[] gameBoard){
- loopOverBoard(gameBoard[0], (i) -> drawX(Color.RED, i));
- loopOverBoard(gameBoard[1], (i) -> drawO(Color.BLUE, i));
+ loopOverBoard(gameBoard[0], (i) -> drawX(Color.RED, (int)i));
+ loopOverBoard(gameBoard[1], (i) -> drawO(Color.BLUE, (Integer) i));
}
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 2c3ad49..4de41f6 100644
--- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
@@ -18,7 +18,7 @@ import org.toop.framework.gameFramework.view.GUIEvents;
import org.toop.framework.networking.events.NetworkEvents;
import org.toop.game.players.LocalPlayer;
-public class GenericGameController> implements GameController {
+public class GenericGameController implements GameController {
protected final EventFlow eventFlow = new EventFlow();
// Logger for logging
@@ -28,13 +28,13 @@ public class GenericGameController> implements GameCo
protected final GameView gameView;
// Reference to game canvas
- protected final GameCanvas canvas;
+ protected final GameCanvas canvas;
- protected final TurnBasedGame game; // Reference to game instance
+ protected final TurnBasedGame game; // Reference to game instance
private final ThreadBehaviour gameThreadBehaviour;
// TODO: Change gameType to automatically happen with either dependency injection or something else.
- public GenericGameController(GameCanvas canvas, T game, ThreadBehaviour gameThreadBehaviour, String gameType) {
+ public GenericGameController(GameCanvas canvas, TurnBasedGame game, ThreadBehaviour gameThreadBehaviour, String gameType) {
logger.info("Creating: " + this.getClass());
this.canvas = canvas;
@@ -55,7 +55,9 @@ public class GenericGameController> implements GameCo
// Listen to updates
eventFlow
.listen(GUIEvents.GameEnded.class, this::onGameFinish, false)
- .listen(GUIEvents.PlayerAttemptedMove.class, event -> {if (getCurrentPlayer() instanceof LocalPlayer lp){lp.setMove(event.move());}}, false);
+ .listen(GUIEvents.PlayerAttemptedMove.class, event -> {
+ if (getCurrentPlayer() instanceof LocalPlayer lp){lp.setMove(event.move());}
+ }, false);
}
public void start(){
@@ -70,7 +72,7 @@ public class GenericGameController> implements GameCo
gameThreadBehaviour.stop();
}
- public Player getCurrentPlayer(){
+ public Player getCurrentPlayer(){
return game.getPlayer(getCurrentPlayerIndex());
}
@@ -97,7 +99,7 @@ public class GenericGameController> implements GameCo
stop();
}
- public Player getPlayer(int player){
+ public Player getPlayer(int player){
if (player < 0 || player >= 2){ // 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/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
index 40784b0..c698eeb 100644
--- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
@@ -8,13 +8,13 @@ import org.toop.game.gameThreads.OnlineThreadBehaviour;
import org.toop.game.games.reversi.BitboardReversi;
import org.toop.game.players.OnlinePlayer;
-public class ReversiBitController extends GenericGameController {
- public ReversiBitController(Player[] players) {
+public class ReversiBitController extends GenericGameController {
+ public ReversiBitController(Player[] players) {
BitboardReversi game = new BitboardReversi(players);
- ThreadBehaviour thread = new LocalThreadBehaviour<>(game);
- for (Player player : players) {
- if (player instanceof OnlinePlayer){
- thread = new OnlineThreadBehaviour<>(game);
+ ThreadBehaviour thread = new LocalThreadBehaviour(game);
+ for (Player player : players) {
+ if (player instanceof OnlinePlayer){
+ thread = new OnlineThreadBehaviour(game);
}
}
super(new ReversiBitCanvas(), game, thread, "Reversi");
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 6307894..495f6f9 100644
--- a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
@@ -9,13 +9,13 @@ import org.toop.game.gameThreads.OnlineThreadBehaviour;
import org.toop.game.games.tictactoe.BitboardTicTacToe;
import org.toop.game.players.OnlinePlayer;
-public class TicTacToeBitController extends GenericGameController {
- public TicTacToeBitController(Player[] players) {
+public class TicTacToeBitController extends GenericGameController {
+ public TicTacToeBitController(Player[] players) {
BitboardTicTacToe game = new BitboardTicTacToe(players);
- ThreadBehaviour thread = new LocalThreadBehaviour<>(game);
- for (Player player : players) {
- if (player instanceof OnlinePlayer){
- thread = new OnlineThreadBehaviour<>(game);
+ ThreadBehaviour thread = new LocalThreadBehaviour(game);
+ for (Player player : players) {
+ if (player instanceof OnlinePlayer){
+ thread = new OnlineThreadBehaviour(game);
}
}
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 9b9bed2..1176c37 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
@@ -58,14 +58,14 @@ public class LocalMultiplayerView extends ViewWidget {
switch (information.type) {
case TICTACTOE:
if (information.players[0].isHuman) {
- players[0] = new LocalPlayer<>(information.players[0].name);
+ players[0] = new LocalPlayer(information.players[0].name);
} else {
- players[0] = new ArtificialPlayer<>(new RandomAI(), "Random AI");
+ players[0] = new ArtificialPlayer(new RandomAI(), "Random AI");
}
if (information.players[1].isHuman) {
- players[1] = new LocalPlayer<>(information.players[1].name);
+ players[1] = new LocalPlayer(information.players[1].name);
} else {
- players[1] = new ArtificialPlayer<>(new MiniMaxAI(9), "MiniMax AI");
+ players[1] = new ArtificialPlayer(new MiniMaxAI(9), "MiniMax AI");
}
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstTTT()) {
new ShowEnableTutorialWidget(
@@ -86,14 +86,14 @@ public class LocalMultiplayerView extends ViewWidget {
break;
case REVERSI:
if (information.players[0].isHuman) {
- players[0] = new LocalPlayer<>(information.players[0].name);
+ players[0] = new LocalPlayer(information.players[0].name);
} else {
- players[0] = new ArtificialPlayer<>(new RandomAI(), "Random AI");
+ players[0] = new ArtificialPlayer(new RandomAI(), "Random AI");
}
if (information.players[1].isHuman) {
- players[1] = new LocalPlayer<>(information.players[1].name);
+ players[1] = new LocalPlayer(information.players[1].name);
} else {
- players[1] = new ArtificialPlayer<>(new MiniMaxAI(6), "MiniMax");
+ players[1] = new ArtificialPlayer(new MiniMaxAI(6), "MiniMax");
}
if (AppSettings.getSettings().getTutorialFlag() && AppSettings.getSettings().getFirstReversi()) {
new ShowEnableTutorialWidget(
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/game/PlayerProvider.java b/framework/src/main/java/org/toop/framework/gameFramework/model/game/PlayerProvider.java
index 8db47a3..181edaa 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/game/PlayerProvider.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/game/PlayerProvider.java
@@ -2,6 +2,6 @@ package org.toop.framework.gameFramework.model.game;
import org.toop.framework.gameFramework.model.player.Player;
-public interface PlayerProvider> {
- Player getPlayer(int index);
+public interface PlayerProvider {
+ Player getPlayer(int index);
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java b/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
index d4cb4df..dae192d 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
@@ -1,6 +1,6 @@
package org.toop.framework.gameFramework.model.game;
-public interface TurnBasedGame> extends Playable, DeepCopyable, PlayerProvider, BoardProvider {
+public interface TurnBasedGame extends Playable, PlayerProvider, BoardProvider, DeepCopyable {
int getCurrentTurn();
int getPlayerCount();
int getWinner();
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/game/threadBehaviour/AbstractThreadBehaviour.java b/framework/src/main/java/org/toop/framework/gameFramework/model/game/threadBehaviour/AbstractThreadBehaviour.java
index da6647a..9dd6af7 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/game/threadBehaviour/AbstractThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/game/threadBehaviour/AbstractThreadBehaviour.java
@@ -16,14 +16,14 @@ import java.util.function.Consumer;
* a running flag, a game reference, and a logger.
* Subclasses implement the actual game-loop logic.
*/
-public abstract class AbstractThreadBehaviour> implements ThreadBehaviour {
+public abstract class AbstractThreadBehaviour implements ThreadBehaviour {
private LongPairConsumer onSendMove;
private Runnable onUpdateUI;
/** Indicates whether the game loop or event processing is active. */
protected final AtomicBoolean isRunning = new AtomicBoolean();
/** The game instance controlled by this behaviour. */
- protected final T game;
+ protected final TurnBasedGame game;
/** Logger for the subclass to report errors or debug info. */
protected final Logger logger = LogManager.getLogger(this.getClass());
@@ -33,7 +33,7 @@ public abstract class AbstractThreadBehaviour> implem
*
* @param game the turn-based game to control
*/
- public AbstractThreadBehaviour(T game) {
+ public AbstractThreadBehaviour(TurnBasedGame game) {
this.game = game;
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AI.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AI.java
index 8377166..afacfbf 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AI.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AI.java
@@ -3,5 +3,5 @@ package org.toop.framework.gameFramework.model.player;
import org.toop.framework.gameFramework.model.game.DeepCopyable;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface AI> extends MoveProvider, DeepCopyable> {
+public interface AI extends MoveProvider, DeepCopyable {
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractAI.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractAI.java
index 328132d..bdca918 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractAI.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractAI.java
@@ -12,6 +12,6 @@ import org.toop.framework.gameFramework.model.game.TurnBasedGame;
*
* @param the specific type of game this AI can play, extending {@link GameR}
*/
-public abstract class AbstractAI> implements AI {
+public abstract class AbstractAI implements AI {
// Concrete AI implementations should override findBestMove(T game, int depth)
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
index 57e2f18..f643574 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
@@ -15,7 +15,7 @@ import org.toop.framework.gameFramework.model.game.TurnBasedGame;
* specific move logic.
*
*/
-public abstract class AbstractPlayer> implements Player {
+public abstract class AbstractPlayer implements Player {
private final Logger logger = LogManager.getLogger(this.getClass());
private final String name;
@@ -24,7 +24,7 @@ public abstract class AbstractPlayer> implements Play
this.name = name;
}
- protected AbstractPlayer(AbstractPlayer other) {
+ protected AbstractPlayer(AbstractPlayer other) {
this.name = other.name;
}
/**
@@ -39,7 +39,7 @@ public abstract class AbstractPlayer> implements Play
* @return an integer representing the chosen move
* @throws UnsupportedOperationException if the method is not overridden
*/
- public long getMove(T gameCopy) {
+ public long getMove(TurnBasedGame gameCopy) {
logger.error("Method getMove not implemented.");
throw new UnsupportedOperationException("Not supported yet.");
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/MoveProvider.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/MoveProvider.java
index b9ab448..159addd 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/MoveProvider.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/MoveProvider.java
@@ -2,6 +2,6 @@ package org.toop.framework.gameFramework.model.player;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface MoveProvider> {
- long getMove(T game);
+public interface MoveProvider {
+ long getMove(TurnBasedGame game);
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
index e2ff1a8..a3f1b32 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
@@ -3,5 +3,5 @@ package org.toop.framework.gameFramework.model.player;
import org.toop.framework.gameFramework.model.game.DeepCopyable;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface Player> extends NameProvider, MoveProvider, DeepCopyable> {
+public interface Player extends NameProvider, MoveProvider, DeepCopyable {
}
diff --git a/game/src/main/java/org/toop/game/BitboardGame.java b/game/src/main/java/org/toop/game/BitboardGame.java
index 4ebdb95..b4244af 100644
--- a/game/src/main/java/org/toop/game/BitboardGame.java
+++ b/game/src/main/java/org/toop/game/BitboardGame.java
@@ -7,17 +7,17 @@ import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
// There is AI performance to be gained by getting rid of non-primitives and thus speeding up deepCopy
-public abstract class BitboardGame> implements TurnBasedGame {
+public abstract class BitboardGame implements TurnBasedGame {
private final int columnSize;
private final int rowSize;
- private Player[] players;
+ private Player[] players;
// long is 64 bits. Every game has a limit of 64 cells maximum.
private final long[] playerBitboard;
private int currentTurn = 0;
- public BitboardGame(int columnSize, int rowSize, int playerCount, Player[] players) {
+ public BitboardGame(int columnSize, int rowSize, int playerCount, Player[] players) {
this.columnSize = columnSize;
this.rowSize = rowSize;
this.players = players;
@@ -26,14 +26,14 @@ public abstract class BitboardGame> implements TurnBas
Arrays.fill(playerBitboard, 0L);
}
- public BitboardGame(BitboardGame other) {
+ public BitboardGame(BitboardGame other) {
this.columnSize = other.columnSize;
this.rowSize = other.rowSize;
this.playerBitboard = other.playerBitboard.clone();
this.currentTurn = other.currentTurn;
this.players = Arrays.stream(other.players)
- .map(Player::deepCopy)
+ .map(Player::deepCopy)
.toArray(Player[]::new);
}
@@ -61,7 +61,7 @@ public abstract class BitboardGame> implements TurnBas
return getCurrentPlayerIndex();
}
- public Player getPlayer(int index) {return players[index];}
+ public Player getPlayer(int index) {return players[index];}
public int getCurrentPlayerIndex() {
return currentTurn % playerBitboard.length;
@@ -71,7 +71,7 @@ public abstract class BitboardGame> implements TurnBas
return (currentTurn + 1) % playerBitboard.length;
}
- public Player getCurrentPlayer(){
+ public Player getCurrentPlayer(){
return players[getCurrentPlayerIndex()];
}
diff --git a/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java b/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java
index 0a9da7f..670cb2a 100644
--- a/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java
+++ b/game/src/main/java/org/toop/game/gameThreads/LocalFixedRateThreadBehaviour.java
@@ -16,7 +16,7 @@ import java.util.function.Consumer;
* Runs a separate thread that executes game turns at a fixed frequency (default 60 updates/sec),
* applying player moves, updating the game state, and dispatching UI events.
*/
-public class LocalFixedRateThreadBehaviour> extends AbstractThreadBehaviour implements Runnable {
+public class LocalFixedRateThreadBehaviour extends AbstractThreadBehaviour implements Runnable {
/**
@@ -24,7 +24,7 @@ public class LocalFixedRateThreadBehaviour> extends A
*
* @param game the game instance
*/
- public LocalFixedRateThreadBehaviour(T game) {
+ public LocalFixedRateThreadBehaviour(TurnBasedGame game) {
super(game);
}
@@ -59,7 +59,7 @@ public class LocalFixedRateThreadBehaviour> extends A
if (now >= nextUpdate) {
nextUpdate += UPDATE_INTERVAL;
- Player currentPlayer = game.getPlayer(game.getCurrentTurn());
+ Player currentPlayer = game.getPlayer(game.getCurrentTurn());
long move = currentPlayer.getMove(game.deepCopy());
PlayResult result = game.play(move);
diff --git a/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java b/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java
index 79c57f9..fab1b96 100644
--- a/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java
+++ b/game/src/main/java/org/toop/game/gameThreads/LocalThreadBehaviour.java
@@ -16,14 +16,14 @@ import java.util.function.Consumer;
* Repeatedly gets the current player's move, applies it to the game,
* updates the UI, and stops when the game ends or {@link #stop()} is called.
*/
-public class LocalThreadBehaviour> extends AbstractThreadBehaviour implements Runnable {
+public class LocalThreadBehaviour extends AbstractThreadBehaviour implements Runnable {
/**
* Creates a new behaviour for a local turn-based game.
*
* @param game the game instance
*/
- public LocalThreadBehaviour(T game) {
+ public LocalThreadBehaviour(TurnBasedGame game) {
super(game);
}
@@ -48,7 +48,7 @@ public class LocalThreadBehaviour> extends AbstractTh
@Override
public void run() {
while (isRunning.get()) {
- Player currentPlayer = game.getPlayer(game.getCurrentTurn());
+ Player currentPlayer = game.getPlayer(game.getCurrentTurn());
long move = currentPlayer.getMove(game.deepCopy());
PlayResult result = game.play(move);
diff --git a/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java b/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java
index ae9aa88..97c339a 100644
--- a/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java
+++ b/game/src/main/java/org/toop/game/gameThreads/OnlineThreadBehaviour.java
@@ -14,17 +14,17 @@ import org.toop.game.players.OnlinePlayer;
* Reacts to server events, sending moves and updating the game state
* for the local player while receiving moves from other players.
*/
-public class OnlineThreadBehaviour> extends AbstractThreadBehaviour implements SupportsOnlinePlay {
+public class OnlineThreadBehaviour extends AbstractThreadBehaviour implements SupportsOnlinePlay {
/**
* Creates behaviour and sets the first local player
* (non-online player) from the given array.
*/
- public OnlineThreadBehaviour(T game) {
+ public OnlineThreadBehaviour(TurnBasedGame game) {
super(game);
}
/** Finds the first non-online player in the array. */
- private int getFirstNotOnlinePlayer(Player[] players) {
+ private int getFirstNotOnlinePlayer(Player[] players) {
for (int i = 0; i < players.length; i++) {
if (!(players[i] instanceof OnlinePlayer)) {
return i;
diff --git a/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java b/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java
index a666f8d..ad20969 100644
--- a/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java
+++ b/game/src/main/java/org/toop/game/gameThreads/OnlineWithSleepThreadBehaviour.java
@@ -10,14 +10,14 @@ import org.toop.framework.networking.events.NetworkEvents;
* This is identical to {@link OnlineThreadBehaviour}, but inserts a
* short sleep before delegating to the base implementation.
*/
-public class OnlineWithSleepThreadBehaviour> extends OnlineThreadBehaviour {
+public class OnlineWithSleepThreadBehaviour extends OnlineThreadBehaviour {
/**
* Creates the behaviour and forwards the players to the base class.
*
* @param game the online-capable turn-based game
*/
- public OnlineWithSleepThreadBehaviour(T game) {
+ public OnlineWithSleepThreadBehaviour(TurnBasedGame game) {
super(game);
}
diff --git a/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java b/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java
index f380bef..867322f 100644
--- a/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java
+++ b/game/src/main/java/org/toop/game/games/reversi/BitboardReversi.java
@@ -5,14 +5,14 @@ import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.game.BitboardGame;
-public class BitboardReversi extends BitboardGame {
+public class BitboardReversi extends BitboardGame {
public record Score(int black, int white) {}
private final long notAFile = 0xfefefefefefefefeL;
private final long notHFile = 0x7f7f7f7f7f7f7f7fL;
- public BitboardReversi(Player[] players) {
+ public BitboardReversi(Player[] players) {
super(8, 8, 2, players);
// Black (player 0)
diff --git a/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java b/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java
index 0927431..c467e97 100644
--- a/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java
+++ b/game/src/main/java/org/toop/game/games/tictactoe/BitboardTicTacToe.java
@@ -5,7 +5,7 @@ import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.game.BitboardGame;
-public class BitboardTicTacToe extends BitboardGame {
+public class BitboardTicTacToe extends BitboardGame {
private final long[] winningLines = {
0b111000000L, // top row
0b000111000L, // middle row
@@ -17,7 +17,7 @@ public class BitboardTicTacToe extends BitboardGame {
0b001010100L // anti-diagonal
};
- public BitboardTicTacToe(Player[] players) {
+ public BitboardTicTacToe(Player[] players) {
super(3, 3, 2, players);
}
public BitboardTicTacToe(BitboardTicTacToe other) {
diff --git a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java b/game/src/main/java/org/toop/game/players/ArtificialPlayer.java
index 418cbed..5cfecff 100644
--- a/game/src/main/java/org/toop/game/players/ArtificialPlayer.java
+++ b/game/src/main/java/org/toop/game/players/ArtificialPlayer.java
@@ -12,22 +12,22 @@ import org.toop.framework.gameFramework.model.game.TurnBasedGame;
*
* @param the specific type of game this AI player can play
*/
-public class ArtificialPlayer> extends AbstractPlayer {
+public class ArtificialPlayer extends AbstractPlayer {
/** The AI instance used to calculate moves. */
- private final AI ai;
+ private final AI ai;
/**
* Constructs a new ArtificialPlayer using the specified AI.
*
* @param ai the AI instance that determines moves for this player
*/
- public ArtificialPlayer(AI ai, String name) {
+ public ArtificialPlayer(AI ai, String name) {
super(name);
this.ai = ai;
}
- public ArtificialPlayer(ArtificialPlayer other) {
+ public ArtificialPlayer(ArtificialPlayer other) {
super(other);
this.ai = other.ai.deepCopy();
}
@@ -44,12 +44,12 @@ public class ArtificialPlayer> extends AbstractPlayer
* @return the integer representing the chosen move
* @throws ClassCastException if {@code gameCopy} is not of type {@code T}
*/
- public long getMove(T gameCopy) {
+ public long getMove(TurnBasedGame gameCopy) {
return ai.getMove(gameCopy);
}
@Override
- public ArtificialPlayer deepCopy() {
- return new ArtificialPlayer(this);
+ public ArtificialPlayer deepCopy() {
+ return new ArtificialPlayer(this);
}
}
diff --git a/game/src/main/java/org/toop/game/players/LocalPlayer.java b/game/src/main/java/org/toop/game/players/LocalPlayer.java
index 8f3b94d..47ed5db 100644
--- a/game/src/main/java/org/toop/game/players/LocalPlayer.java
+++ b/game/src/main/java/org/toop/game/players/LocalPlayer.java
@@ -7,7 +7,7 @@ import org.toop.framework.gameFramework.model.player.Player;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
-public class LocalPlayer> extends AbstractPlayer {
+public class LocalPlayer extends AbstractPlayer {
// Future can be used with event system, IF unsubscribeAfterSuccess works...
// private CompletableFuture LastMove = new CompletableFuture<>();
@@ -17,12 +17,12 @@ public class LocalPlayer> extends AbstractPlayer {
super(name);
}
- public LocalPlayer(LocalPlayer other) {
+ public LocalPlayer(LocalPlayer other) {
super(other);
}
@Override
- public long getMove(T gameCopy) {
+ public long getMove(TurnBasedGame gameCopy) {
return getValidMove(gameCopy);
}
@@ -36,7 +36,7 @@ public class LocalPlayer> extends AbstractPlayer {
return false;
}
- private long getMove2(T gameCopy) {
+ private long getMove2(TurnBasedGame gameCopy) {
LastMove = new CompletableFuture<>();
long move = 0;
try {
@@ -49,7 +49,7 @@ public class LocalPlayer> extends AbstractPlayer {
return move;
}
- protected long getValidMove(T gameCopy){
+ protected long getValidMove(TurnBasedGame gameCopy){
// Get this player's valid moves
long validMoves = gameCopy.getLegalMoves();
// Make sure provided move is valid
@@ -64,8 +64,8 @@ public class LocalPlayer> extends AbstractPlayer {
}
@Override
- public LocalPlayer deepCopy() {
- return new LocalPlayer(this.getName());
+ public LocalPlayer deepCopy() {
+ return new LocalPlayer(this.getName());
}
/*public void register() {
diff --git a/game/src/main/java/org/toop/game/players/MiniMaxAI.java b/game/src/main/java/org/toop/game/players/MiniMaxAI.java
index 440bb50..39e254d 100644
--- a/game/src/main/java/org/toop/game/players/MiniMaxAI.java
+++ b/game/src/main/java/org/toop/game/players/MiniMaxAI.java
@@ -9,7 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
-public class MiniMaxAI> extends AbstractAI {
+public class MiniMaxAI extends AbstractAI {
private final int maxDepth;
private final Random random = new Random();
@@ -18,17 +18,17 @@ public class MiniMaxAI> extends AbstractAI {
this.maxDepth = depth;
}
- public MiniMaxAI(MiniMaxAI other) {
+ public MiniMaxAI(MiniMaxAI other) {
this.maxDepth = other.maxDepth;
}
@Override
- public MiniMaxAI deepCopy() {
- return new MiniMaxAI<>(this);
+ public MiniMaxAI deepCopy() {
+ return new MiniMaxAI(this);
}
@Override
- public long getMove(T game) {
+ public long getMove(TurnBasedGame game) {
long legalMoves = game.getLegalMoves();
if (legalMoves == 0) return 0;
@@ -39,7 +39,7 @@ public class MiniMaxAI> extends AbstractAI {
long movesLoop = legalMoves;
while (movesLoop != 0) {
long move = 1L << Long.numberOfTrailingZeros(movesLoop);
- T copy = game.deepCopy();
+ TurnBasedGame copy = game.deepCopy();
PlayResult result = copy.play(move);
int score;
@@ -75,7 +75,7 @@ public class MiniMaxAI> extends AbstractAI {
* @param beta Beta value
* @return score of the position
*/
- private int getMoveScore(T game, int depth, boolean maximizing, int aiPlayer, int alpha, int beta) {
+ private int getMoveScore(TurnBasedGame game, int depth, boolean maximizing, int aiPlayer, int alpha, int beta) {
long legalMoves = game.getLegalMoves();
// Terminal state
@@ -95,7 +95,7 @@ public class MiniMaxAI> extends AbstractAI {
while (movesLoop != 0) {
long move = 1L << Long.numberOfTrailingZeros(movesLoop);
- T copy = game.deepCopy();
+ TurnBasedGame copy = game.deepCopy();
PlayResult result = copy.play(move);
int score;
@@ -130,7 +130,7 @@ public class MiniMaxAI> extends AbstractAI {
* @param aiPlayer AI's player index
* @return heuristic score
*/
- private int evaluateBoard(T game, int aiPlayer) {
+ private int evaluateBoard(TurnBasedGame game, int aiPlayer) {
long[] board = game.getBoard();
int aiCount = 0;
int opponentCount = 0;
diff --git a/game/src/main/java/org/toop/game/players/OnlinePlayer.java b/game/src/main/java/org/toop/game/players/OnlinePlayer.java
index 9f011c0..96cc7a1 100644
--- a/game/src/main/java/org/toop/game/players/OnlinePlayer.java
+++ b/game/src/main/java/org/toop/game/players/OnlinePlayer.java
@@ -12,7 +12,7 @@ import org.toop.framework.gameFramework.model.player.Player;
* Currently, this class is a placeholder and does not implement move logic.
*
*/
-public class OnlinePlayer> extends AbstractPlayer {
+public class OnlinePlayer extends AbstractPlayer {
/**
* Constructs a new OnlinePlayer.
@@ -25,12 +25,12 @@ public class OnlinePlayer> extends AbstractPlayer
super(name);
}
- public OnlinePlayer(OnlinePlayer other) {
+ public OnlinePlayer(OnlinePlayer other) {
super(other);
}
@Override
- public Player deepCopy() {
- return new OnlinePlayer<>(this);
+ public Player deepCopy() {
+ return new OnlinePlayer(this);
}
}
diff --git a/game/src/main/java/org/toop/game/players/RandomAI.java b/game/src/main/java/org/toop/game/players/RandomAI.java
index 2d0fe02..9a867a7 100644
--- a/game/src/main/java/org/toop/game/players/RandomAI.java
+++ b/game/src/main/java/org/toop/game/players/RandomAI.java
@@ -6,19 +6,19 @@ import org.toop.framework.gameFramework.model.player.AbstractAI;
import java.util.Random;
-public class RandomAI> extends AbstractAI {
+public class RandomAI extends AbstractAI {
public RandomAI() {
super();
}
@Override
- public RandomAI deepCopy() {
- return new RandomAI();
+ public RandomAI deepCopy() {
+ return new RandomAI();
}
@Override
- public long getMove(T game) {
+ public long getMove(TurnBasedGame game) {
long legalMoves = game.getLegalMoves();
int move = new Random().nextInt(Long.bitCount(legalMoves));
return nthBitIndex(legalMoves, move);
From c30c118c0430ca6e196e081f0c2a5712c14fd2f7 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Fri, 12 Dec 2025 16:04:12 +0100
Subject: [PATCH 05/35] Code cleanup
---
app/src/main/java/org/toop/app/App.java | 9 +++++----
.../main/java/org/toop/app/canvas/BitGameCanvas.java | 2 +-
.../java/org/toop/app/canvas/ReversiBitCanvas.java | 8 ++------
.../java/org/toop/app/canvas/TicTacToeBitCanvas.java | 8 ++------
.../framework/game/games/reversi/BitboardReversi.java | 5 +++--
.../game/games/tictactoe/BitboardTicTacToe.java | 4 ++--
.../org/toop/framework/networking/server/Game.java | 10 +++++-----
.../framework/networking/server/GameDefinition.java | 2 ++
.../framework/networking/server/MasterServer.java | 3 ++-
.../toop/framework/networking/server/OnlineGame.java | 4 ++--
.../org/toop/framework/networking/server/Server.java | 11 ++++++-----
.../toop/framework/networking/server/ServerTest.java | 11 +++++++++++
12 files changed, 43 insertions(+), 34 deletions(-)
create mode 100644 framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index b9e0d8d..2bce12a 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -22,6 +22,7 @@ import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.GlobalEventBus;
import org.toop.framework.game.BitboardGame;
import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.networking.connection.NetworkingClientEventListener;
import org.toop.framework.networking.connection.NetworkingClientManager;
import org.toop.framework.networking.server.GameDefinition;
@@ -141,9 +142,9 @@ public final class App extends Application {
stage.show();
- var games = new ConcurrentHashMap>>();
- games.put("tictactoe", new GameDefinition<>("tictactoe", BitboardReversi.class));
- games.put("reversi", new GameDefinition<>("reversi", BitboardReversi.class));
+ var games = new ConcurrentHashMap>();
+ games.put("tictactoe", BitboardReversi.class);
+ games.put("reversi", BitboardReversi.class);
var s = new MasterServer(6666, games);
try {
s.start();
@@ -156,7 +157,7 @@ public final class App extends Application {
private void setKeybinds(StackPane root) {
root.addEventHandler(KeyEvent.KEY_PRESSED,event -> {
if (event.getCode() == KeyCode.ESCAPE) {
- escapePopup();
+ escapePopup();
}
});
stage.setFullScreenExitKeyCombination(
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 5beb7af..2f00e10 100644
--- a/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/BitGameCanvas.java
@@ -14,7 +14,7 @@ import org.toop.framework.gameFramework.view.GUIEvents;
import java.util.function.Consumer;
-public abstract class BitGameCanvas implements GameCanvas {
+public abstract class BitGameCanvas implements GameCanvas {
protected record Cell(float x, float y, float width, float height) {
public boolean isInside(double x, double y) {
return x >= this.x && x <= this.x + width &&
diff --git a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
index 016d6b3..685a985 100644
--- a/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/ReversiBitCanvas.java
@@ -3,10 +3,6 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.game.games.reversi.BitboardReversi;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
public class ReversiBitCanvas extends BitGameCanvas {
public ReversiBitCanvas() {
@@ -37,7 +33,7 @@ public class ReversiBitCanvas extends BitGameCanvas {
public void redraw(TurnBasedGame gameCopy) {
clearAll();
long[] board = gameCopy.getBoard();
- loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, (int)i));
- loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, (int)i));
+ loopOverBoard(board[0], (i) -> drawDot(Color.WHITE, i));
+ loopOverBoard(board[1], (i) -> drawDot(Color.BLACK, i));
}
}
diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
index 3520417..7c9b5b4 100644
--- a/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
+++ b/app/src/main/java/org/toop/app/canvas/TicTacToeBitCanvas.java
@@ -3,10 +3,6 @@ package org.toop.app.canvas;
import javafx.scene.paint.Color;
import org.toop.app.App;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.game.games.tictactoe.BitboardTicTacToe;
-
-import java.util.Arrays;
-import java.util.function.Consumer;
public class TicTacToeBitCanvas extends BitGameCanvas{
public TicTacToeBitCanvas() {
@@ -29,8 +25,8 @@ public class TicTacToeBitCanvas extends BitGameCanvas{
}
private void drawMoves(long[] gameBoard){
- loopOverBoard(gameBoard[0], (i) -> drawX(Color.RED, (int)i));
- loopOverBoard(gameBoard[1], (i) -> drawO(Color.BLUE, (Integer) i));
+ loopOverBoard(gameBoard[0], (i) -> drawX(Color.RED, i));
+ loopOverBoard(gameBoard[1], (i) -> drawO(Color.BLUE, i));
}
diff --git a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
index 867322f..d3661ac 100644
--- a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
+++ b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
@@ -1,9 +1,10 @@
-package org.toop.game.games.reversi;
+package org.toop.framework.game.games.reversi;
+import org.toop.framework.game.BitboardGame;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.BitboardGame;
+import org.toop.framework.game.BitboardGame;
public class BitboardReversi extends BitboardGame {
diff --git a/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
index c467e97..378db7d 100644
--- a/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
+++ b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
@@ -1,9 +1,9 @@
-package org.toop.game.games.tictactoe;
+package org.toop.framework.game.games.tictactoe;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.game.BitboardGame;
+import org.toop.framework.game.BitboardGame;
public class BitboardTicTacToe extends BitboardGame {
private final long[] winningLines = {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index 057e37c..48f5036 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -1,14 +1,14 @@
package org.toop.framework.networking.server;
-import org.toop.framework.game.BitboardGame;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public class Game implements OnlineGame {
+public class Game implements OnlineGame {
private long id;
private User[] users;
- private GameDefinition> game;
+ private TurnBasedGame game;
- public Game(GameDefinition game, User... users) {
+ public Game(TurnBasedGame game, User... users) {
this.game = game;
this.users = users;
}
@@ -19,7 +19,7 @@ public class Game implements OnlineGame {
}
@Override
- public GameDefinition game() {
+ public TurnBasedGame game() {
return game;
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java b/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
index 629bc24..bd8252d 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
@@ -1,5 +1,7 @@
package org.toop.framework.networking.server;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+
import java.lang.reflect.InvocationTargetException;
public class GameDefinition {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
index 634ae6f..3f607b4 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
@@ -13,6 +13,7 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.game.BitboardGame;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import java.util.Map;
@@ -20,7 +21,7 @@ public class MasterServer {
private final int port;
public final Server gs;
- public MasterServer(int port, Map>> gameTypes) {
+ public MasterServer(int port, Map> gameTypes) {
this.port = port;
this.gs = new Server(gameTypes);
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
index 59b3399..1b072a9 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
@@ -1,7 +1,7 @@
package org.toop.framework.networking.server;
-public interface OnlineGame {
+public interface OnlineGame {
long id();
- GameDefinition game();
+ T game();
User[] users();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index 757c490..d2cc414 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -1,6 +1,7 @@
package org.toop.framework.networking.server;
import org.toop.framework.game.BitboardGame;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import java.util.ArrayList;
import java.util.List;
@@ -9,11 +10,11 @@ import java.util.concurrent.ConcurrentHashMap;
public class Server implements GameServer {
- final private Map>> gameTypes;
- public List games = new ArrayList<>();
+ final private Map> gameTypes;
+ public List> games = new ArrayList<>();
final private Map users = new ConcurrentHashMap<>();
- public Server(Map>> gameTypes) {
+ public Server(Map> gameTypes) {
this.gameTypes = gameTypes;
}
@@ -37,8 +38,8 @@ public class Server implements GameServer {
if (!gameTypes.containsKey(gameType)) return;
try {
- var game = new Game(gameTypes.get(gameType).create(), users);
- games.addLast(new Game(game, users));
+ var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
+ games.addLast(game);
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
new file mode 100644
index 0000000..0f473f4
--- /dev/null
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -0,0 +1,11 @@
+package org.toop.framework.networking.server;
+
+import org.junit.jupiter.api.BeforeEach;
+
+public class ServerTest {
+
+ @BeforeEach
+ public void setup() {
+ new Server();
+ }
+}
From a60c702306a41733c410d6a2a7d576f515582b1f Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Fri, 12 Dec 2025 16:47:17 +0100
Subject: [PATCH 06/35] Tests and better instantiation
---
app/src/main/java/org/toop/app/App.java | 11 ---
.../gameControllers/ReversiBitController.java | 3 +-
.../TicTacToeBitController.java | 3 +-
.../org/toop/framework/game/BitboardGame.java | 12 ++-
.../game/games/reversi/BitboardReversi.java | 9 +-
.../games/tictactoe/BitboardTicTacToe.java | 10 ++-
.../model/game/TurnBasedGame.java | 3 +
.../gameFramework/model/player/Player.java | 4 +-
.../framework/networking/server/Server.java | 25 ++++--
.../networking/server/ServerTest.java | 90 ++++++++++++++++++-
10 files changed, 136 insertions(+), 34 deletions(-)
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index 2bce12a..aa2e704 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -141,17 +141,6 @@ public final class App extends Application {
}
stage.show();
-
- var games = new ConcurrentHashMap>();
- games.put("tictactoe", BitboardReversi.class);
- games.put("reversi", BitboardReversi.class);
- var s = new MasterServer(6666, games);
- try {
- s.start();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
-
}
private void setKeybinds(StackPane root) {
diff --git a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
index 1ef96dc..9cd62f3 100644
--- a/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/ReversiBitController.java
@@ -10,7 +10,8 @@ import org.toop.framework.game.players.OnlinePlayer;
public class ReversiBitController extends GenericGameController {
public ReversiBitController(Player[] players) {
- BitboardReversi game = new BitboardReversi(players);
+ BitboardReversi game = new BitboardReversi();
+ game.init(players);
ThreadBehaviour thread = new LocalThreadBehaviour(game);
for (Player player : players) {
if (player instanceof OnlinePlayer){
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 1c431b1..18acdfc 100644
--- a/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/TicTacToeBitController.java
@@ -10,7 +10,8 @@ import org.toop.framework.game.players.OnlinePlayer;
public class TicTacToeBitController extends GenericGameController {
public TicTacToeBitController(Player[] players) {
- BitboardTicTacToe game = new BitboardTicTacToe(players);
+ BitboardTicTacToe game = new BitboardTicTacToe();
+ game.init(players);
ThreadBehaviour thread = new LocalThreadBehaviour(game);
for (Player player : players) {
if (player instanceof OnlinePlayer){
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 4cd92a4..f2781cd 100644
--- a/framework/src/main/java/org/toop/framework/game/BitboardGame.java
+++ b/framework/src/main/java/org/toop/framework/game/BitboardGame.java
@@ -13,13 +13,19 @@ public abstract class BitboardGame implements TurnBasedGame {
private Player[] players;
// long is 64 bits. Every game has a limit of 64 cells maximum.
- private final long[] playerBitboard;
+ private long[] playerBitboard;
private int currentTurn = 0;
+ private int playerCount;
- public BitboardGame(int columnSize, int rowSize, int playerCount, Player[] players) {
+ public BitboardGame(int columnSize, int rowSize, int playerCount) {
this.columnSize = columnSize;
this.rowSize = rowSize;
- this.players = players;
+ this.playerCount = playerCount;
+ }
+
+ @Override
+ public void init(Player[] players) {
+ this.players = players;
this.playerBitboard = new long[playerCount];
Arrays.fill(playerBitboard, 0L);
diff --git a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
index d3661ac..c36f236 100644
--- a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
+++ b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
@@ -13,8 +13,8 @@ public class BitboardReversi extends BitboardGame {
private final long notAFile = 0xfefefefefefefefeL;
private final long notHFile = 0x7f7f7f7f7f7f7f7fL;
- public BitboardReversi(Player[] players) {
- super(8, 8, 2, players);
+ public BitboardReversi() {
+ super(8, 8, 2);
// Black (player 0)
setPlayerBitboard(0, (1L << (3 + 4 * 8)) | (1L << (4 + 3 * 8)));
@@ -23,6 +23,11 @@ public class BitboardReversi extends BitboardGame {
setPlayerBitboard(1, (1L << (3 + 3 * 8)) | (1L << (4 + 4 * 8)));
}
+ @Override
+ public void init(Player[] players) {
+ super.init(players);
+ }
+
public BitboardReversi(BitboardReversi other) {
super(other);
}
diff --git a/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
index 378db7d..7115ccc 100644
--- a/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
+++ b/framework/src/main/java/org/toop/framework/game/games/tictactoe/BitboardTicTacToe.java
@@ -17,9 +17,15 @@ public class BitboardTicTacToe extends BitboardGame {
0b001010100L // anti-diagonal
};
- public BitboardTicTacToe(Player[] players) {
- super(3, 3, 2, players);
+ public BitboardTicTacToe() {
+ super(3, 3, 2);
}
+
+ @Override
+ public void init(Player[] players) {
+ super.init(players);
+ }
+
public BitboardTicTacToe(BitboardTicTacToe other) {
super(other);
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java b/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
index dae192d..1e6642d 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/game/TurnBasedGame.java
@@ -1,6 +1,9 @@
package org.toop.framework.gameFramework.model.game;
+import org.toop.framework.gameFramework.model.player.Player;
+
public interface TurnBasedGame extends Playable, PlayerProvider, BoardProvider, DeepCopyable {
+ void init(Player[] players);
int getCurrentTurn();
int getPlayerCount();
int getWinner();
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
index a3f1b32..35ea2b2 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/Player.java
@@ -1,7 +1,5 @@
package org.toop.framework.gameFramework.model.player;
import org.toop.framework.gameFramework.model.game.DeepCopyable;
-import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-public interface Player extends NameProvider, MoveProvider, DeepCopyable {
-}
+public interface Player extends NameProvider, MoveProvider, DeepCopyable {}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index d2cc414..deb3d99 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -1,7 +1,9 @@
package org.toop.framework.networking.server;
import org.toop.framework.game.BitboardGame;
+import org.toop.framework.game.players.LocalPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.gameFramework.model.player.Player;
import java.util.ArrayList;
import java.util.List;
@@ -11,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class Server implements GameServer {
final private Map> gameTypes;
- public List> games = new ArrayList<>();
+ final private List> games = new ArrayList<>();
final private Map users = new ConcurrentHashMap<>();
public Server(Map> gameTypes) {
@@ -30,20 +32,25 @@ public class Server implements GameServer {
return gameTypes.keySet().toArray(new String[0]);
}
-// public List>> ongoingGames() {
-// return List.of();
-// }
+ public List> ongoingGames() {
+ return games;
+ }
public void startGame(String gameType, User... users) {
if (!gameTypes.containsKey(gameType)) return;
try {
- var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
- games.addLast(game);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ Player[] players = new Player[users.length];
+ for (int i = 0; i < users.length; i++) {
+ players[i] = new LocalPlayer(users[i].name());
+ }
+
+ var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
+ game.game().init(players);
+ games.addLast(game);
+
+ } catch (Exception ignored) {}
}
public String[] onlineUsers() {
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
index 0f473f4..c85674c 100644
--- a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -1,11 +1,97 @@
package org.toop.framework.networking.server;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.toop.framework.gameFramework.model.game.PlayResult;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.gameFramework.model.player.Player;
+
+import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
public class ServerTest {
+ static class TurnBasedGameMock implements TurnBasedGame {
+ private Player[] players;
+
+ public TurnBasedGameMock() {}
+
+ @Override
+ public void init(Player[] players) {
+ this.players = players;
+ }
+
+ @Override
+ public int getCurrentTurn() {
+ return 0;
+ }
+
+ @Override
+ public int getPlayerCount() {
+ return 0;
+ }
+
+ @Override
+ public int getWinner() {
+ return 0;
+ }
+
+ @Override
+ public long[] getBoard() {
+ return new long[0];
+ }
+
+ @Override
+ public TurnBasedGame deepCopy() {
+ return null;
+ }
+
+ @Override
+ public long getLegalMoves() {
+ return 0;
+ }
+
+ @Override
+ public PlayResult play(long move) {
+ return null;
+ }
+
+ @Override
+ public Player getPlayer(int index) {
+ return null;
+ }
+
+ }
+
+ private Server server;
+
@BeforeEach
- public void setup() {
- new Server();
+ void setup() {
+
+ var games = new ConcurrentHashMap>();
+ games.put("tictactoe", TurnBasedGameMock.class);
+ games.put("reversi", TurnBasedGameMock.class);
+
+ server = new Server(games);
+ }
+
+ @Test
+ void testGameTypes() {
+ String[] expected = {"tictactoe", "reversi"};
+ String[] actual = server.gameTypes();
+
+ Arrays.sort(expected);
+ Arrays.sort(actual);
+
+ Assertions.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ void testStartGame() {
+ server.startGame("tictactoe", new User(0, "A"), new User(1, "B"));
+ Assertions.assertEquals(1, server.ongoingGames().size());
}
}
From fc47d81b8eac90c45e353dbba3e77acf09d8a2e3 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Fri, 12 Dec 2025 19:47:51 +0100
Subject: [PATCH 07/35] Init challenges
---
.../networking/server/GameChallenge.java | 24 ++++++++
.../networking/server/GameChallengeTimer.java | 33 +++++++++++
.../networking/server/MasterServer.java | 5 +-
.../framework/networking/server/Server.java | 59 +++++++++++++++++--
.../networking/server/SimpleTimer.java | 7 +++
.../networking/server/ServerTest.java | 54 ++++++++++++++++-
6 files changed, 174 insertions(+), 8 deletions(-)
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
new file mode 100644
index 0000000..ba71f89
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
@@ -0,0 +1,24 @@
+package org.toop.framework.networking.server;
+
+public class GameChallenge {
+ private final ServerUser from;
+ private final ServerUser to;
+ private final SimpleTimer timer;
+
+ private boolean isChallengeAccepted = false;
+
+ public GameChallenge(ServerUser from, ServerUser to, SimpleTimer timer) {
+ this.from = from;
+ this.to = to;
+ this.timer = timer;
+ }
+
+ public void acceptChallenge() {
+ isChallengeAccepted = true;
+ timer.forceExpire();
+ }
+
+ public boolean isExpired() {
+ return timer.isExpired();
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java b/framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java
new file mode 100644
index 0000000..1406648
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java
@@ -0,0 +1,33 @@
+package org.toop.framework.networking.server;
+
+import java.time.Instant;
+import java.time.Duration;
+
+public class GameChallengeTimer implements SimpleTimer {
+
+ private final Instant createdAt;
+ private final Duration timeout;
+
+ private boolean isExpired = false;
+
+ public GameChallengeTimer(Duration duration) {
+ this.createdAt = Instant.now();
+ this.timeout = duration;
+ }
+
+ @Override
+ public void forceExpire() {
+ this.isExpired = true;
+ }
+
+ @Override
+ public boolean isExpired() {
+ if (this.isExpired) return true;
+ return Instant.now().isAfter(createdAt.plus(timeout));
+ }
+
+ @Override
+ public long secondsRemaining() {
+ return Duration.between(Instant.now(), createdAt.plus(timeout)).toSeconds();
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
index 3f607b4..587a569 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
@@ -15,15 +15,16 @@ import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.game.BitboardGame;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import java.time.Duration;
import java.util.Map;
public class MasterServer {
private final int port;
public final Server gs;
- public MasterServer(int port, Map> gameTypes) {
+ public MasterServer(int port, Map> gameTypes, Duration challengeDuration) {
this.port = port;
- this.gs = new Server(gameTypes);
+ this.gs = new Server(gameTypes, challengeDuration);
}
public void start() throws InterruptedException {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index deb3d99..be209ca 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -1,23 +1,34 @@
package org.toop.framework.networking.server;
-import org.toop.framework.game.BitboardGame;
import org.toop.framework.game.players.LocalPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.Player;
-import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.*;
+import java.time.Duration;
public class Server implements GameServer {
final private Map> gameTypes;
- final private List> games = new ArrayList<>();
final private Map users = new ConcurrentHashMap<>();
+ final private List gameChallenges = new CopyOnWriteArrayList<>();
+ final private List> games = new CopyOnWriteArrayList<>();
- public Server(Map> gameTypes) {
+ final private Duration challengeDuration;
+ final private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+
+ public Server(Map> gameTypes, Duration challengeDuration) {
this.gameTypes = gameTypes;
+ this.challengeDuration = challengeDuration;
+
+ scheduler.schedule(this::serverTask, 0, TimeUnit.MILLISECONDS);
+ }
+
+ private void serverTask() {
+ checkChallenges();
+ scheduler.schedule(this::serverTask, 500, TimeUnit.MILLISECONDS);
}
public void addUser(ServerUser user) {
@@ -36,6 +47,37 @@ public class Server implements GameServer {
return games;
}
+ public ServerUser getUser(String username) {
+ return users.values().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().get();
+ }
+
+ public ServerUser getUser(long id) {
+ return users.get(id);
+ }
+
+ public void challengeUser(String fromUser, String toUser) {
+ ServerUser from = getUser(fromUser);
+ if (from == null) {
+ return;
+ }
+ ServerUser to = getUser(toUser);
+ if (to == null) {
+ return;
+ }
+
+ gameChallenges.addLast(new GameChallenge(from, to, new GameChallengeTimer(challengeDuration)));
+ }
+
+ public void checkChallenges() {
+ for (int i = gameChallenges.size() - 1; i >= 0; i--) {
+ if (gameChallenges.get(i).isExpired()) gameChallenges.remove(i);
+ }
+ }
+
+ public List gameChallenges() {
+ return gameChallenges;
+ }
+
public void startGame(String gameType, User... users) {
if (!gameTypes.containsKey(gameType)) return;
@@ -53,6 +95,13 @@ public class Server implements GameServer {
} catch (Exception ignored) {}
}
+// public void checkGames() {
+// for (int i = games.size() - 1; i >= 0; i--) {
+// var game = games.get(i);
+// if (game.game().getWinner() >= 0) games.remove(i);
+// }
+// }
+
public String[] onlineUsers() {
return users.values().stream().map(ServerUser::name).toArray(String[]::new);
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java b/framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java
new file mode 100644
index 0000000..c9c25aa
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server;
+
+public interface SimpleTimer {
+ void forceExpire();
+ boolean isExpired();
+ long secondsRemaining();
+}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
index c85674c..6f663bb 100644
--- a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -7,6 +7,7 @@ import org.toop.framework.gameFramework.model.game.PlayResult;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.Player;
+import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
@@ -66,7 +67,35 @@ public class ServerTest {
}
+ static class TestUser implements ServerUser {
+
+ final private long id;
+
+ private String name;
+
+ public TestUser(long id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ @Override
+ public long id() {
+ return id;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
private Server server;
+ private Duration waitTime = Duration.ofSeconds(2);
@BeforeEach
void setup() {
@@ -75,7 +104,7 @@ public class ServerTest {
games.put("tictactoe", TurnBasedGameMock.class);
games.put("reversi", TurnBasedGameMock.class);
- server = new Server(games);
+ server = new Server(games, waitTime);
}
@Test
@@ -89,9 +118,32 @@ public class ServerTest {
Assertions.assertArrayEquals(expected, actual);
}
+ @Test
+ void testChallenge() {
+ server.addUser(new TestUser(1, "test1"));
+ server.addUser(new TestUser(2, "test2"));
+ server.challengeUser("test1", "test2");
+
+ IO.println(server.gameChallenges());
+
+ Assertions.assertEquals(1, server.gameChallenges().size());
+
+ try {
+ Thread.sleep(waitTime);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ Assertions.assertEquals(0, server.gameChallenges().size());
+ }
+
@Test
void testStartGame() {
server.startGame("tictactoe", new User(0, "A"), new User(1, "B"));
Assertions.assertEquals(1, server.ongoingGames().size());
+ server.startGame("reversi", new User(0, "A"), new User(1, "B"));
+ Assertions.assertEquals(2, server.ongoingGames().size());
}
+
+
}
From 4d31a8ed4488690cf5ca4fe1c64422c226ca27c3 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Fri, 12 Dec 2025 21:48:57 +0100
Subject: [PATCH 08/35] Working challenges
---
app/src/main/java/org/toop/app/App.java | 16 +++-
.../networking/server/GameChallenge.java | 23 +++++-
.../framework/networking/server/Server.java | 80 +++++++++++++++++--
.../networking/server/ServerHandler.java | 23 +++++-
.../networking/server/ServerUser.java | 6 +-
.../framework/networking/server/User.java | 28 ++++++-
.../networking/server/ServerTest.java | 26 +++++-
.../networking/server/servertests.ps1 | 17 ++++
8 files changed, 202 insertions(+), 17 deletions(-)
create mode 100644 framework/src/test/java/org/toop/framework/networking/server/servertests.ps1
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index aa2e704..9245318 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -22,11 +22,13 @@ import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.GlobalEventBus;
import org.toop.framework.game.BitboardGame;
import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.networking.connection.NetworkingClientEventListener;
import org.toop.framework.networking.connection.NetworkingClientManager;
import org.toop.framework.networking.server.GameDefinition;
import org.toop.framework.networking.server.MasterServer;
+import org.toop.framework.networking.server.Server;
import org.toop.framework.resource.ResourceLoader;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.events.AssetLoaderEvents;
@@ -36,6 +38,7 @@ import org.toop.framework.resource.resources.SoundEffectAsset;
import org.toop.local.AppContext;
import org.toop.local.AppSettings;
+import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
@@ -98,7 +101,18 @@ public final class App extends Application {
WidgetContainer.setCurrentView(loading);
- setOnLoadingSuccess(loading);
+ var games = new ConcurrentHashMap>();
+ games.put("tictactoe", BitboardTicTacToe.class);
+ games.put("reversi", BitboardReversi.class);
+
+ var a = new MasterServer(6666, games, Duration.ofSeconds(5));
+ try {
+ a.start();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ setOnLoadingSuccess(loading);
EventFlow loadingFlow = new EventFlow();
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
index ba71f89..0c936a5 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
@@ -1,21 +1,40 @@
package org.toop.framework.networking.server;
+import org.toop.framework.SnowflakeGenerator;
+
public class GameChallenge {
+ private final long id = SnowflakeGenerator.nextId(); // I don't need this, but the tournament server uses it...
+
private final ServerUser from;
private final ServerUser to;
+ private final String gameType;
private final SimpleTimer timer;
private boolean isChallengeAccepted = false;
- public GameChallenge(ServerUser from, ServerUser to, SimpleTimer timer) {
+ public GameChallenge(ServerUser from, ServerUser to, String gameType, SimpleTimer timer) {
this.from = from;
this.to = to;
+ this.gameType = gameType;
this.timer = timer;
}
- public void acceptChallenge() {
+ public long id() {
+ return id;
+ }
+
+ public ServerUser[] getUsers() {
+ return new ServerUser[]{from, to};
+ }
+
+ public void forceExpire() {
+ timer.forceExpire();
+ }
+
+ public String acceptChallenge() {
isChallengeAccepted = true;
timer.forceExpire();
+ return gameType;
}
public boolean isExpired() {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index be209ca..80e7792 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -4,6 +4,7 @@ import org.toop.framework.game.players.LocalPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.Player;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
@@ -48,29 +49,88 @@ public class Server implements GameServer {
}
public ServerUser getUser(String username) {
- return users.values().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().get();
+ return users.values().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
}
public ServerUser getUser(long id) {
return users.get(id);
}
- public void challengeUser(String fromUser, String toUser) {
+ public void challengeUser(String fromUser, String toUser, String gameType) {
+
ServerUser from = getUser(fromUser);
if (from == null) {
return;
}
- ServerUser to = getUser(toUser);
- if (to == null) {
+
+ if (!gameTypes.containsKey(gameType)) {
+ from.sendMessage("ERR gametype not found");
return;
}
- gameChallenges.addLast(new GameChallenge(from, to, new GameChallengeTimer(challengeDuration)));
+ ServerUser to = getUser(toUser);
+ if (to == null) {
+ from.sendMessage("ERR user not found");
+ return;
+ }
+
+ var ch = new GameChallenge(from, to, gameType, new GameChallengeTimer(challengeDuration));
+
+ to.sendMessage(
+ "\"SVR GAME CHALLENGE {CHALLENGER: \"%s\", GAMETYPE: \"%s\", CHALLENGENUMBER: \"%s\"}"
+ .formatted(from.name(), gameType, ch.id())
+ );
+
+ if (!isValidChallenge(ch)) {
+ warnUserExpiredChallenge(from, ch.id());
+ ch.forceExpire();
+ return;
+ }
+
+ gameChallenges.addLast(ch);
+ }
+
+ private void warnUserExpiredChallenge(ServerUser user, long challengeId) {
+ user.sendMessage("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}");
+ }
+
+ private boolean isValidChallenge(GameChallenge gameChallenge) {
+ for (var user : gameChallenge.getUsers()) {
+ if (users.get(user.id()) == null) {
+ return false;
+ }
+
+ if (user.games().length > 0) {
+ return false;
+ }
+
+ if (gameChallenge.isExpired()) {
+ return false;
+ }
+ }
+
+ return true;
}
public void checkChallenges() {
for (int i = gameChallenges.size() - 1; i >= 0; i--) {
- if (gameChallenges.get(i).isExpired()) gameChallenges.remove(i);
+ var challenge = gameChallenges.get(i);
+
+ if (isValidChallenge(challenge)) continue;
+
+ if (challenge.isExpired()) {
+ Arrays.stream(challenge.getUsers()).forEach(user -> warnUserExpiredChallenge(user, challenge.id()));
+ gameChallenges.remove(i);
+ }
+ }
+ }
+
+ public void acceptChallenge(long challengeId) {
+ for (var challenge : gameChallenges) {
+ if (challenge.id() == challengeId) {
+ startGame(challenge.acceptChallenge(), (User[]) challenge.getUsers());
+ break;
+ }
}
}
@@ -105,4 +165,12 @@ public class Server implements GameServer {
public String[] onlineUsers() {
return users.values().stream().map(ServerUser::name).toArray(String[]::new);
}
+
+ public void closeServer() {
+ scheduler.shutdown();
+ gameChallenges.clear();
+ games.clear();
+ users.clear();
+ gameTypes.clear();
+ }
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
index f5da259..8357abb 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -79,7 +79,28 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleChallenge(ParsedMessage p) {
- // TODO
+ if(!allowedArgs(p.args())) return;
+ if (p.args().length < 2) return;
+
+ if (p.args()[0].equalsIgnoreCase("accept")) {
+ try {
+ long id = Long.parseLong(p.args()[1]);
+
+ if (id <= 0) {
+ user.sendMessage("ERR id must be a positive number");
+ return;
+ }
+
+ server.acceptChallenge(id);
+
+ } catch (NumberFormatException e) {
+ user.sendMessage("ERR id is not a valid number or too big");
+ return;
+ }
+ return;
+ }
+
+ server.challengeUser(user.name(), p.args()[0], p.args()[1]);
}
private void handleMove(ParsedMessage p) {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
index 8e6e7a5..474c26d 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
@@ -1,9 +1,11 @@
package org.toop.framework.networking.server;
-import java.net.InetSocketAddress;
-
public interface ServerUser {
long id();
String name();
+ Game[] games();
+ void addGame(Game game);
+ void removeGame(Game game);
void setName(String name);
+ void sendMessage(String message);
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
index 8ae5026..9863b12 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -2,11 +2,13 @@ package org.toop.framework.networking.server;
import io.netty.channel.ChannelHandlerContext;
-import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
public class User implements ServerUser {
final private long id;
private String name;
+ private final List games = new ArrayList<>();
private ChannelHandlerContext connectionContext;
public User(long userId, String name) {
@@ -24,11 +26,34 @@ public class User implements ServerUser {
return name;
}
+
+
+ @Override
+ public void addGame(Game game) {
+ games.add(game);
+ }
+
+ @Override
+ public void removeGame(Game game) {
+ games.remove(game);
+ }
+
+ @Override
+ public Game[] games() {
+ return games.toArray(new Game[0]);
+ }
+
@Override
public void setName(String name) {
this.name = name;
}
+ @Override
+ public void sendMessage(String message) {
+ IO.println(message);
+ ctx().channel().writeAndFlush(message);
+ }
+
public ChannelHandlerContext ctx() {
return connectionContext;
}
@@ -37,4 +62,5 @@ public class User implements ServerUser {
this.connectionContext = ctx;
}
+
}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
index 6f663bb..e5dcd09 100644
--- a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -11,8 +11,6 @@ import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
public class ServerTest {
static class TurnBasedGameMock implements TurnBasedGame {
@@ -88,10 +86,30 @@ public class ServerTest {
return name;
}
+ @Override
+ public Game[] games() {
+ return new Game[0];
+ }
+
+ @Override
+ public void addGame(Game game) {
+
+ }
+
+ @Override
+ public void removeGame(Game game) {
+
+ }
+
@Override
public void setName(String name) {
this.name = name;
}
+
+ @Override
+ public void sendMessage(String message) {
+
+ }
}
private Server server;
@@ -122,14 +140,14 @@ public class ServerTest {
void testChallenge() {
server.addUser(new TestUser(1, "test1"));
server.addUser(new TestUser(2, "test2"));
- server.challengeUser("test1", "test2");
+ server.challengeUser("test1", "test2", "tictactoe");
IO.println(server.gameChallenges());
Assertions.assertEquals(1, server.gameChallenges().size());
try {
- Thread.sleep(waitTime);
+ Thread.sleep(waitTime.plusMillis(100));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/servertests.ps1 b/framework/src/test/java/org/toop/framework/networking/server/servertests.ps1
new file mode 100644
index 0000000..9edf089
--- /dev/null
+++ b/framework/src/test/java/org/toop/framework/networking/server/servertests.ps1
@@ -0,0 +1,17 @@
+$client = New-Object System.Net.Sockets.TcpClient("localhost", 6666)
+$stream = $client.GetStream()
+$writer = New-Object System.IO.StreamWriter($stream)
+$reader = New-Object System.IO.StreamReader($stream)
+
+$client2 = New-Object System.Net.Sockets.TcpClient("localhost", 6666)
+$stream2 = $client2.GetStream()
+$writer2 = New-Object System.IO.StreamWriter($stream2)
+$reader2 = New-Object System.IO.StreamReader($stream2)
+
+$writer.WriteLine("login john")
+$writer.Flush()
+$reader.ReadLine()
+
+$writer2.WriteLine("login hendrik")
+$writer2.Flush()
+$reader2.ReadLine()
\ No newline at end of file
From 9c20fcbc39b990a4638cbbf0e1a5a522887256b6 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 15:01:28 +0100
Subject: [PATCH 09/35] Fixed bugs, easy to use host button
---
app/src/main/java/org/toop/app/App.java | 20 ----------
app/src/main/java/org/toop/app/Server.java | 2 +-
.../org/toop/app/widget/view/OnlineView.java | 33 ++++++++++++++-
.../connection/events/NetworkEvents.java | 2 +-
.../networking/server/GameChallenge.java | 14 ++++---
.../framework/networking/server/Server.java | 40 ++++++++++---------
.../networking/server/ServerHandler.java | 23 +++++++++--
7 files changed, 83 insertions(+), 51 deletions(-)
diff --git a/app/src/main/java/org/toop/app/App.java b/app/src/main/java/org/toop/app/App.java
index 9245318..9645cd5 100644
--- a/app/src/main/java/org/toop/app/App.java
+++ b/app/src/main/java/org/toop/app/App.java
@@ -20,15 +20,8 @@ import org.toop.framework.audio.*;
import org.toop.framework.audio.events.AudioEvents;
import org.toop.framework.eventbus.EventFlow;
import org.toop.framework.eventbus.GlobalEventBus;
-import org.toop.framework.game.BitboardGame;
-import org.toop.framework.game.games.reversi.BitboardReversi;
-import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
-import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.networking.connection.NetworkingClientEventListener;
import org.toop.framework.networking.connection.NetworkingClientManager;
-import org.toop.framework.networking.server.GameDefinition;
-import org.toop.framework.networking.server.MasterServer;
-import org.toop.framework.networking.server.Server;
import org.toop.framework.resource.ResourceLoader;
import org.toop.framework.resource.ResourceManager;
import org.toop.framework.resource.events.AssetLoaderEvents;
@@ -38,9 +31,7 @@ import org.toop.framework.resource.resources.SoundEffectAsset;
import org.toop.local.AppContext;
import org.toop.local.AppSettings;
-import java.time.Duration;
import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -101,17 +92,6 @@ public final class App extends Application {
WidgetContainer.setCurrentView(loading);
- var games = new ConcurrentHashMap>();
- games.put("tictactoe", BitboardTicTacToe.class);
- games.put("reversi", BitboardReversi.class);
-
- var a = new MasterServer(6666, games, Duration.ofSeconds(5));
- try {
- a.start();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
-
setOnLoadingSuccess(loading);
EventFlow loadingFlow = new EventFlow();
diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java
index 6c73aa1..d1eb6bb 100644
--- a/app/src/main/java/org/toop/app/Server.java
+++ b/app/src/main/java/org/toop/app/Server.java
@@ -263,7 +263,7 @@ public final class Server {
String gameType = extractQuotedValue(response.gameType());
final String finalGameType = gameType;
var a = new ChallengePopup(challengerName, gameType, (playerInformation) -> {
- final int challengeId = Integer.parseInt(response.challengeId().replaceAll("\\D", ""));
+ final long challengeId = Long.parseLong(response.challengeId().replaceAll("\\D", ""));
new EventFlow().addPostEvent(new NetworkEvents.SendAcceptChallenge(clientId, challengeId)).postEvent();
isSingleGame.set(true);
});
diff --git a/app/src/main/java/org/toop/app/widget/view/OnlineView.java b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
index 16ed1df..2dc51a8 100644
--- a/app/src/main/java/org/toop/app/widget/view/OnlineView.java
+++ b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
@@ -6,6 +6,13 @@ import org.toop.app.widget.complex.LabeledInputWidget;
import org.toop.app.widget.complex.ViewWidget;
import javafx.geometry.Pos;
+import org.toop.framework.game.games.reversi.BitboardReversi;
+import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.networking.server.MasterServer;
+
+import java.time.Duration;
+import java.util.concurrent.ConcurrentHashMap;
public class OnlineView extends ViewWidget {
public OnlineView() {
@@ -23,6 +30,28 @@ public class OnlineView extends ViewWidget {
);
});
+ var localHostButton = Primitive.button("host!", () -> {
+ var games = new ConcurrentHashMap>();
+ games.put("tictactoe", BitboardTicTacToe.class);
+ games.put("reversi", BitboardReversi.class);
+
+ var a = new MasterServer(6666, games, Duration.ofSeconds(10));
+
+ new Thread(() -> {
+ try {
+ a.start();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }).start();
+
+ new Server(
+ "127.0.0.1",
+ "6666",
+ "host"
+ );
+ }, false);
+
add(Pos.CENTER, Primitive.vbox(
serverInformationHeader,
Primitive.separator(),
@@ -32,7 +61,9 @@ public class OnlineView extends ViewWidget {
playerNameInput.getNode(),
Primitive.separator(),
- connectButton
+ connectButton,
+ Primitive.separator(),
+ localHostButton
));
}
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
index d6c0140..22f9588 100644
--- a/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
+++ b/framework/src/main/java/org/toop/framework/networking/connection/events/NetworkEvents.java
@@ -102,7 +102,7 @@ public class NetworkEvents extends EventsBase {
implements GenericEvent {}
/** Requests to accept an existing challenge. */
- public record SendAcceptChallenge(long clientId, int challengeId)
+ public record SendAcceptChallenge(long clientId, long challengeId)
implements GenericEvent {}
/** Requests to forfeit the current game. */
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
index 0c936a5..50a5c2b 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
@@ -5,14 +5,14 @@ import org.toop.framework.SnowflakeGenerator;
public class GameChallenge {
private final long id = SnowflakeGenerator.nextId(); // I don't need this, but the tournament server uses it...
- private final ServerUser from;
- private final ServerUser to;
+ private final User from;
+ private final User to;
private final String gameType;
private final SimpleTimer timer;
private boolean isChallengeAccepted = false;
- public GameChallenge(ServerUser from, ServerUser to, String gameType, SimpleTimer timer) {
+ public GameChallenge(User from, User to, String gameType, SimpleTimer timer) {
this.from = from;
this.to = to;
this.gameType = gameType;
@@ -23,8 +23,8 @@ public class GameChallenge {
return id;
}
- public ServerUser[] getUsers() {
- return new ServerUser[]{from, to};
+ public User[] getUsers() {
+ return new User[]{from, to};
}
public void forceExpire() {
@@ -37,6 +37,10 @@ public class GameChallenge {
return gameType;
}
+ public boolean isChallengeAccepted() {
+ return isChallengeAccepted;
+ }
+
public boolean isExpired() {
return timer.isExpired();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index 80e7792..dc35906 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -13,7 +13,7 @@ import java.time.Duration;
public class Server implements GameServer {
final private Map> gameTypes;
- final private Map users = new ConcurrentHashMap<>();
+ final private Map users = new ConcurrentHashMap<>();
final private List gameChallenges = new CopyOnWriteArrayList<>();
final private List> games = new CopyOnWriteArrayList<>();
@@ -32,53 +32,53 @@ public class Server implements GameServer {
scheduler.schedule(this::serverTask, 500, TimeUnit.MILLISECONDS);
}
- public void addUser(ServerUser user) {
+ public void addUser(User user) {
users.putIfAbsent(user.id(), user);
}
- public void removeUser(ServerUser user) {
+ public void removeUser(User user) {
users.remove(user.id());
}
- public String[] gameTypes() {
- return gameTypes.keySet().toArray(new String[0]);
+ public List gameTypes() {
+ return gameTypes.keySet().stream().toList();
}
public List> ongoingGames() {
return games;
}
- public ServerUser getUser(String username) {
+ public User getUser(String username) {
return users.values().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
}
- public ServerUser getUser(long id) {
+ public User getUser(long id) {
return users.get(id);
}
public void challengeUser(String fromUser, String toUser, String gameType) {
- ServerUser from = getUser(fromUser);
+ User from = getUser(fromUser);
if (from == null) {
return;
}
if (!gameTypes.containsKey(gameType)) {
- from.sendMessage("ERR gametype not found");
+ from.sendMessage("ERR gametype not found \n");
return;
}
- ServerUser to = getUser(toUser);
+ User to = getUser(toUser);
if (to == null) {
- from.sendMessage("ERR user not found");
+ from.sendMessage("ERR user not found \n");
return;
}
var ch = new GameChallenge(from, to, gameType, new GameChallengeTimer(challengeDuration));
to.sendMessage(
- "\"SVR GAME CHALLENGE {CHALLENGER: \"%s\", GAMETYPE: \"%s\", CHALLENGENUMBER: \"%s\"}"
- .formatted(from.name(), gameType, ch.id())
+ "SVR GAME CHALLENGE {CHALLENGER: \"%s\", CHALLENGENUMBER: \"%s\", GAMETYPE: \"%s\"} \n"
+ .formatted(from.name(), ch.id(), gameType)
);
if (!isValidChallenge(ch)) {
@@ -90,8 +90,8 @@ public class Server implements GameServer {
gameChallenges.addLast(ch);
}
- private void warnUserExpiredChallenge(ServerUser user, long challengeId) {
- user.sendMessage("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}");
+ private void warnUserExpiredChallenge(User user, long challengeId) {
+ user.sendMessage("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}" + "\n");
}
private boolean isValidChallenge(GameChallenge gameChallenge) {
@@ -119,7 +119,9 @@ public class Server implements GameServer {
if (isValidChallenge(challenge)) continue;
if (challenge.isExpired()) {
- Arrays.stream(challenge.getUsers()).forEach(user -> warnUserExpiredChallenge(user, challenge.id()));
+ if (!challenge.isChallengeAccepted()) Arrays.stream(challenge.getUsers())
+ .forEach(user -> warnUserExpiredChallenge(user, challenge.id()));
+
gameChallenges.remove(i);
}
}
@@ -128,7 +130,7 @@ public class Server implements GameServer {
public void acceptChallenge(long challengeId) {
for (var challenge : gameChallenges) {
if (challenge.id() == challengeId) {
- startGame(challenge.acceptChallenge(), (User[]) challenge.getUsers());
+ startGame(challenge.acceptChallenge(), challenge.getUsers());
break;
}
}
@@ -162,8 +164,8 @@ public class Server implements GameServer {
// }
// }
- public String[] onlineUsers() {
- return users.values().stream().map(ServerUser::name).toArray(String[]::new);
+ public List onlineUsers() {
+ return users.values().stream().toList();
}
public void closeServer() {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
index 8357abb..f31912f 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -2,8 +2,10 @@ package org.toop.framework.networking.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
+import org.apache.maven.surefire.shared.utils.StringUtils;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -17,6 +19,10 @@ public class ServerHandler extends SimpleChannelInboundHandler {
this.server = server;
}
+ private String returnQuotedString(Iterator strings) { // TODO more places this could be useful
+ return "\"" + StringUtils.join(strings, "\",\"") + "\"";
+ }
+
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush("WELCOME " + user.id() + "\n");
@@ -27,6 +33,9 @@ public class ServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
+
+ IO.println(msg);
+
ParsedMessage p = parse(msg);
if (p == null) return;
@@ -61,8 +70,14 @@ public class ServerHandler extends SimpleChannelInboundHandler {
if (!allowedArgs(p.args())) return;
switch (p.args()[0]) {
- case "playerlist" -> user.ctx().writeAndFlush(Arrays.toString(server.onlineUsers()));
- case "gamelist" -> user.ctx().writeAndFlush(Arrays.toString(server.gameTypes()));
+ case "playerlist" -> {
+ var names = server.onlineUsers().stream().map(ServerUser::name).iterator();
+ user.ctx().writeAndFlush("SVR PLAYERLIST " + returnQuotedString(names) + "\n");
+ }
+ case "gamelist" -> {
+ var names = server.gameTypes().stream().iterator();
+ user.ctx().writeAndFlush("SVR GAMELIST " + returnQuotedString(names) + "\n");
+ }
}
}
@@ -87,14 +102,14 @@ public class ServerHandler extends SimpleChannelInboundHandler {
long id = Long.parseLong(p.args()[1]);
if (id <= 0) {
- user.sendMessage("ERR id must be a positive number");
+ user.sendMessage("ERR id must be a positive number \n");
return;
}
server.acceptChallenge(id);
} catch (NumberFormatException e) {
- user.sendMessage("ERR id is not a valid number or too big");
+ user.sendMessage("ERR id is not a valid number or too big \n");
return;
}
return;
From 150fb2986fb087d16788ce81ea7e693ebb902dc5 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 15:17:16 +0100
Subject: [PATCH 10/35] Fixed tic tac toe naming
---
app/src/main/java/org/toop/app/widget/view/OnlineView.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/src/main/java/org/toop/app/widget/view/OnlineView.java b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
index 2dc51a8..c3b4e39 100644
--- a/app/src/main/java/org/toop/app/widget/view/OnlineView.java
+++ b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
@@ -32,7 +32,7 @@ public class OnlineView extends ViewWidget {
var localHostButton = Primitive.button("host!", () -> {
var games = new ConcurrentHashMap>();
- games.put("tictactoe", BitboardTicTacToe.class);
+ games.put("tic-tac-toe", BitboardTicTacToe.class);
games.put("reversi", BitboardReversi.class);
var a = new MasterServer(6666, games, Duration.ofSeconds(10));
From 8b85915c741dd3f5bbdf62a853bb478b091ef3f4 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:08:10 +0100
Subject: [PATCH 11/35] Fixes
---
.../framework/networking/server/Server.java | 2 +-
.../networking/server/ServerHandler.java | 3 ++-
.../framework/networking/server/ServerUser.java | 4 ++--
.../toop/framework/networking/server/User.java | 17 ++++++++---------
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index dc35906..4db663c 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -100,7 +100,7 @@ public class Server implements GameServer {
return false;
}
- if (user.games().length > 0) {
+ if (user.game() != null) {
return false;
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
index f31912f..9cfb9d7 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -119,7 +119,8 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleMove(ParsedMessage p) {
- // TODO
+ if(!allowedArgs(p.args())) return;
+
}
private ParsedMessage parse(String msg) {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
index 474c26d..e2aa97a 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
@@ -3,9 +3,9 @@ package org.toop.framework.networking.server;
public interface ServerUser {
long id();
String name();
- Game[] games();
+ Game game();
void addGame(Game game);
- void removeGame(Game game);
+ void removeGame();
void setName(String name);
void sendMessage(String message);
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
index 9863b12..9a52587 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -2,13 +2,10 @@ package org.toop.framework.networking.server;
import io.netty.channel.ChannelHandlerContext;
-import java.util.ArrayList;
-import java.util.List;
-
public class User implements ServerUser {
final private long id;
private String name;
- private final List games = new ArrayList<>();
+ private Game game;
private ChannelHandlerContext connectionContext;
public User(long userId, String name) {
@@ -30,17 +27,19 @@ public class User implements ServerUser {
@Override
public void addGame(Game game) {
- games.add(game);
+ if (this.game == null) {
+ this.game = game;
+ }
}
@Override
- public void removeGame(Game game) {
- games.remove(game);
+ public void removeGame() {
+ this.game = null;
}
@Override
- public Game[] games() {
- return games.toArray(new Game[0]);
+ public Game game() {
+ return this.game;
}
@Override
From c929abc4b86bab6539c01cf879220a8c1e1c38a4 Mon Sep 17 00:00:00 2001
From: Stef
Date: Sat, 13 Dec 2025 17:08:34 +0100
Subject: [PATCH 12/35] Removed Generics, pray nothing breaks.
---
.../org/toop/framework/game/BitboardGame.java | 8 +--
.../gameThreads/ServerThreadBehaviour.java | 68 +++++++++++++++++++
.../game/games/reversi/BitboardReversi.java | 11 ++-
.../framework/game/players/ServerPlayer.java | 46 +++++++++++++
.../framework/networking/server/Game.java | 10 +++
.../networking/server/OnlineGame.java | 1 +
.../framework/networking/server/Server.java | 18 +++--
7 files changed, 148 insertions(+), 14 deletions(-)
create mode 100644 framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
create mode 100644 framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
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 f2781cd..3e26d40 100644
--- a/framework/src/main/java/org/toop/framework/game/BitboardGame.java
+++ b/framework/src/main/java/org/toop/framework/game/BitboardGame.java
@@ -13,20 +13,20 @@ public abstract class BitboardGame implements TurnBasedGame {
private Player[] players;
// long is 64 bits. Every game has a limit of 64 cells maximum.
- private long[] playerBitboard;
+ private final long[] playerBitboard;
private int currentTurn = 0;
- private int playerCount;
+ private final int playerCount;
public BitboardGame(int columnSize, int rowSize, int playerCount) {
this.columnSize = columnSize;
this.rowSize = rowSize;
this.playerCount = playerCount;
+ this.playerBitboard = new long[playerCount];
}
@Override
public void init(Player[] players) {
this.players = players;
- this.playerBitboard = new long[playerCount];
Arrays.fill(playerBitboard, 0L);
}
@@ -34,7 +34,7 @@ public abstract class BitboardGame implements TurnBasedGame {
public BitboardGame(BitboardGame other) {
this.columnSize = other.columnSize;
this.rowSize = other.rowSize;
-
+ this.playerCount = other.playerCount;
this.playerBitboard = other.playerBitboard.clone();
this.currentTurn = other.currentTurn;
this.players = Arrays.stream(other.players)
diff --git a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
new file mode 100644
index 0000000..8789e41
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
@@ -0,0 +1,68 @@
+package org.toop.framework.game.gameThreads;
+
+import org.toop.framework.eventbus.EventFlow;
+import org.toop.framework.gameFramework.GameState;
+import org.toop.framework.gameFramework.model.game.PlayResult;
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour;
+import org.toop.framework.gameFramework.model.player.Player;
+import org.toop.framework.gameFramework.view.GUIEvents;
+
+import java.util.function.Consumer;
+
+public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Runnable {
+ private Consumer onPlayerMove;
+ /**
+ * Creates a new base behaviour for the specified game.
+ *
+ * @param game the turn-based game to control
+ */
+ public ServerThreadBehaviour(TurnBasedGame game, Consumer onPlayerMove) {
+ super(game);
+ }
+
+ private void notifyPlayerMove(int player) {
+ onPlayerMove.accept(player);
+ }
+
+ /** Starts the game loop in a new thread. */
+ @Override
+ public void start() {
+ if (isRunning.compareAndSet(false, true)) {
+ new Thread(this).start();
+ }
+ }
+
+ /** Stops the game loop after the current iteration. */
+ @Override
+ public void stop() {
+ isRunning.set(false);
+ }
+
+ @Override
+ public void run() {
+ while (isRunning.get()) {
+ Player currentPlayer = game.getPlayer(game.getCurrentTurn());
+ long move = currentPlayer.getMove(game.deepCopy());
+ PlayResult result = game.play(move);
+
+ GameState state = result.state();
+ switch (state) {
+ case WIN, DRAW -> {
+ isRunning.set(false);
+ new EventFlow().addPostEvent(
+ GUIEvents.GameEnded.class,
+ state == GameState.WIN,
+ result.player()
+ ).postEvent();
+ }
+ case NORMAL, TURN_SKIPPED -> { /* continue normally */ }
+ default -> {
+ logger.error("Unexpected state {}", state);
+ isRunning.set(false);
+ throw new RuntimeException("Unknown state: " + state);
+ }
+ }
+ }
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
index c36f236..e116c9a 100644
--- a/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
+++ b/framework/src/main/java/org/toop/framework/game/games/reversi/BitboardReversi.java
@@ -15,17 +15,16 @@ public class BitboardReversi extends BitboardGame {
public BitboardReversi() {
super(8, 8, 2);
-
- // Black (player 0)
- setPlayerBitboard(0, (1L << (3 + 4 * 8)) | (1L << (4 + 3 * 8)));
-
- // White (player 1)
- setPlayerBitboard(1, (1L << (3 + 3 * 8)) | (1L << (4 + 4 * 8)));
}
@Override
public void init(Player[] players) {
super.init(players);
+ // Black (player 0)
+ setPlayerBitboard(0, (1L << (3 + 4 * 8)) | (1L << (4 + 3 * 8)));
+
+ // White (player 1)
+ setPlayerBitboard(1, (1L << (3 + 3 * 8)) | (1L << (4 + 4 * 8)));
}
public BitboardReversi(BitboardReversi other) {
diff --git a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
new file mode 100644
index 0000000..535a033
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
@@ -0,0 +1,46 @@
+package org.toop.framework.game.players;
+
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.gameFramework.model.player.AbstractPlayer;
+import org.toop.framework.gameFramework.model.player.Player;
+import org.toop.framework.networking.server.User;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public class ServerPlayer extends AbstractPlayer {
+ private User user;
+ private CompletableFuture lastMove;
+
+ public ServerPlayer(User user) {
+ super(user.name());
+ this.user = user;
+ }
+
+ public void setMove(long move) {
+ lastMove.complete(move);
+ }
+
+ @Override
+ public Player deepCopy() {
+ return null;
+ }
+
+ @Override
+ public long getMove(TurnBasedGame game) {
+ lastMove = new CompletableFuture<>();
+ System.out.println("Sending yourturn");
+ user.sendMessage("SVR GAME YOURTURN {TURNMESSAGE: \"\"}\n");
+ try {
+ return lastMove.get();
+ } catch (InterruptedException | ExecutionException e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "";
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index 48f5036..87e24f7 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -1,5 +1,8 @@
package org.toop.framework.networking.server;
+import org.toop.framework.game.gameThreads.LocalThreadBehaviour;
+import org.toop.framework.game.gameThreads.OnlineThreadBehaviour;
+import org.toop.framework.game.gameThreads.ServerThreadBehaviour;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
public class Game implements OnlineGame {
@@ -7,9 +10,11 @@ public class Game implements OnlineGame {
private long id;
private User[] users;
private TurnBasedGame game;
+ private ServerThreadBehaviour gameThread;
public Game(TurnBasedGame game, User... users) {
this.game = game;
+ this.gameThread = new ServerThreadBehaviour(game, null);
this.users = users;
}
@@ -27,4 +32,9 @@ public class Game implements OnlineGame {
public User[] users() {
return users;
}
+
+ @Override
+ public void start(){
+ this.gameThread.start();
+ }
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
index 1b072a9..b82b4b1 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
@@ -4,4 +4,5 @@ public interface OnlineGame {
long id();
T game();
User[] users();
+ void start();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index 4db663c..7f0f71c 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -1,6 +1,9 @@
package org.toop.framework.networking.server;
+import org.toop.framework.game.gameThreads.OnlineThreadBehaviour;
import org.toop.framework.game.players.LocalPlayer;
+import org.toop.framework.game.players.OnlinePlayer;
+import org.toop.framework.game.players.ServerPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.Player;
@@ -144,16 +147,23 @@ public class Server implements GameServer {
if (!gameTypes.containsKey(gameType)) return;
try {
-
Player[] players = new Player[users.length];
for (int i = 0; i < users.length; i++) {
- players[i] = new LocalPlayer(users[i].name());
+ players[i] = new ServerPlayer(users[i]);
}
-
+ System.out.println("Starting Game");
var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
game.game().init(players);
games.addLast(game);
-
+ users[0].sendMessage(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
+ users[0].name(),
+ gameType,
+ users[1].name()));
+ users[1].sendMessage(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
+ users[0].name(),
+ gameType,
+ users[0].name()));
+ game.start();
} catch (Exception ignored) {}
}
From edd2c24b651f1835a475a8cbc1c0b57fc72d4c14 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:22:56 +0100
Subject: [PATCH 13/35] Added ability to take ServerPlayer from user
---
.../framework/networking/server/Game.java | 2 --
.../networking/server/ServerHandler.java | 15 +++++++------
.../networking/server/ServerUser.java | 7 +++++-
.../framework/networking/server/User.java | 22 ++++++++++++-------
4 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index 87e24f7..eeb75a3 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -1,7 +1,5 @@
package org.toop.framework.networking.server;
-import org.toop.framework.game.gameThreads.LocalThreadBehaviour;
-import org.toop.framework.game.gameThreads.OnlineThreadBehaviour;
import org.toop.framework.game.gameThreads.ServerThreadBehaviour;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
index 9cfb9d7..de33c62 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -54,20 +54,19 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
}
- private boolean allowedArgs(String... args) {
- if (args.length < 1) return false;
- return true;
+ private boolean hasArgs(String... args) {
+ return (args.length >= 1);
}
private void handleLogin(ParsedMessage p) {
- if (!allowedArgs(p.args())) return;
+ if (hasArgs(p.args())) return;
user.setName(p.args()[0]);
}
private void handleGet(ParsedMessage p) {
- if (!allowedArgs(p.args())) return;
+ if (hasArgs(p.args())) return;
switch (p.args()[0]) {
case "playerlist" -> {
@@ -94,7 +93,7 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleChallenge(ParsedMessage p) {
- if(!allowedArgs(p.args())) return;
+ if(hasArgs(p.args())) return;
if (p.args().length < 2) return;
if (p.args()[0].equalsIgnoreCase("accept")) {
@@ -119,8 +118,10 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleMove(ParsedMessage p) {
- if(!allowedArgs(p.args())) return;
+ if(hasArgs(p.args())) return;
+ // TODO check if not number
+ user.serverPlayer().setMove(Integer.parseInt(p.args()[0]));
}
private ParsedMessage parse(String msg) {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
index e2aa97a..7fffb4e 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
@@ -1,10 +1,15 @@
package org.toop.framework.networking.server;
+import org.toop.framework.game.players.ServerPlayer;
+
+import java.util.Map;
+
public interface ServerUser {
long id();
String name();
Game game();
- void addGame(Game game);
+ ServerPlayer serverPlayer();
+ void addGame(Game game, ServerPlayer player);
void removeGame();
void setName(String name);
void sendMessage(String message);
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
index 9a52587..2eebcba 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -1,11 +1,15 @@
package org.toop.framework.networking.server;
import io.netty.channel.ChannelHandlerContext;
+import org.toop.framework.game.players.ServerPlayer;
+
+import java.util.HashMap;
+import java.util.Map;
public class User implements ServerUser {
final private long id;
private String name;
- private Game game;
+ private final Map game = new HashMap<>();
private ChannelHandlerContext connectionContext;
public User(long userId, String name) {
@@ -23,23 +27,25 @@ public class User implements ServerUser {
return name;
}
-
-
@Override
- public void addGame(Game game) {
- if (this.game == null) {
- this.game = game;
+ public void addGame(Game game, ServerPlayer player) {
+ if (this.game.isEmpty()) {
+ this.game.put(game, player);
}
}
@Override
public void removeGame() {
- this.game = null;
+ this.game.clear();
}
@Override
public Game game() {
- return this.game;
+ return this.game.keySet().iterator().next();
+ }
+
+ public ServerPlayer serverPlayer() {
+ return this.game.values().iterator().next();
}
@Override
From 22270e58dc2f61bffde4203b1f977e8d5c1ce587 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:33:14 +0100
Subject: [PATCH 14/35] Added pairs
---
.../networking/server/ServerUser.java | 5 +-
.../framework/networking/server/User.java | 18 +-
.../toop/framework/utils/ImmutablePair.java | 21 ++
.../org/toop/framework/utils/MutablePair.java | 29 ++
.../java/org/toop/framework/utils/Pair.java | 6 +
.../networking/server/ServerTest.java | 334 +++++++++---------
6 files changed, 233 insertions(+), 180 deletions(-)
create mode 100644 framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
create mode 100644 framework/src/main/java/org/toop/framework/utils/MutablePair.java
create mode 100644 framework/src/main/java/org/toop/framework/utils/Pair.java
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
index 7fffb4e..e06098c 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
@@ -1,15 +1,14 @@
package org.toop.framework.networking.server;
import org.toop.framework.game.players.ServerPlayer;
-
-import java.util.Map;
+import org.toop.framework.utils.Pair;
public interface ServerUser {
long id();
String name();
Game game();
ServerPlayer serverPlayer();
- void addGame(Game game, ServerPlayer player);
+ void addGame(Pair gamePair);
void removeGame();
void setName(String name);
void sendMessage(String message);
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
index 2eebcba..3078ca5 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -2,14 +2,12 @@ package org.toop.framework.networking.server;
import io.netty.channel.ChannelHandlerContext;
import org.toop.framework.game.players.ServerPlayer;
-
-import java.util.HashMap;
-import java.util.Map;
+import org.toop.framework.utils.Pair;
public class User implements ServerUser {
final private long id;
private String name;
- private final Map game = new HashMap<>();
+ private Pair gamePair;
private ChannelHandlerContext connectionContext;
public User(long userId, String name) {
@@ -28,24 +26,24 @@ public class User implements ServerUser {
}
@Override
- public void addGame(Game game, ServerPlayer player) {
- if (this.game.isEmpty()) {
- this.game.put(game, player);
+ public void addGame(Pair gamePair) {
+ if (this.gamePair == null) {
+ this.gamePair = gamePair;
}
}
@Override
public void removeGame() {
- this.game.clear();
+ this.gamePair = null;
}
@Override
public Game game() {
- return this.game.keySet().iterator().next();
+ return this.gamePair.getLeft();
}
public ServerPlayer serverPlayer() {
- return this.game.values().iterator().next();
+ return this.gamePair.getRight();
}
@Override
diff --git a/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java b/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
new file mode 100644
index 0000000..da8fe91
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
@@ -0,0 +1,21 @@
+package org.toop.framework.utils;
+
+public class ImmutablePair implements Pair {
+ final T left;
+ final K right;
+
+ public ImmutablePair(T left, K right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public T getLeft() {
+ return left;
+ }
+
+ @Override
+ public K getRight() {
+ return right;
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/utils/MutablePair.java b/framework/src/main/java/org/toop/framework/utils/MutablePair.java
new file mode 100644
index 0000000..90c9f91
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/utils/MutablePair.java
@@ -0,0 +1,29 @@
+package org.toop.framework.utils;
+
+public class MutablePair implements Pair {
+ T left;
+ K right;
+
+ public MutablePair(T left, K right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public T getLeft() {
+ return left;
+ }
+
+ public void setLeft(T left) {
+ this.left = left;
+ }
+
+ @Override
+ public K getRight() {
+ return right;
+ }
+
+ public void setRight(K right) {
+ this.right = right;
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/utils/Pair.java b/framework/src/main/java/org/toop/framework/utils/Pair.java
new file mode 100644
index 0000000..26b74ab
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/utils/Pair.java
@@ -0,0 +1,6 @@
+package org.toop.framework.utils;
+
+public interface Pair {
+ T getLeft();
+ K getRight();
+}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
index e5dcd09..789d732 100644
--- a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -1,167 +1,167 @@
-package org.toop.framework.networking.server;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.toop.framework.gameFramework.model.game.PlayResult;
-import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.framework.gameFramework.model.player.Player;
-
-import java.time.Duration;
-import java.util.Arrays;
-import java.util.concurrent.ConcurrentHashMap;
-
-public class ServerTest {
-
- static class TurnBasedGameMock implements TurnBasedGame {
- private Player[] players;
-
- public TurnBasedGameMock() {}
-
- @Override
- public void init(Player[] players) {
- this.players = players;
- }
-
- @Override
- public int getCurrentTurn() {
- return 0;
- }
-
- @Override
- public int getPlayerCount() {
- return 0;
- }
-
- @Override
- public int getWinner() {
- return 0;
- }
-
- @Override
- public long[] getBoard() {
- return new long[0];
- }
-
- @Override
- public TurnBasedGame deepCopy() {
- return null;
- }
-
- @Override
- public long getLegalMoves() {
- return 0;
- }
-
- @Override
- public PlayResult play(long move) {
- return null;
- }
-
- @Override
- public Player getPlayer(int index) {
- return null;
- }
-
- }
-
- static class TestUser implements ServerUser {
-
- final private long id;
-
- private String name;
-
- public TestUser(long id, String name) {
- this.id = id;
- this.name = name;
- }
-
- @Override
- public long id() {
- return id;
- }
-
- @Override
- public String name() {
- return name;
- }
-
- @Override
- public Game[] games() {
- return new Game[0];
- }
-
- @Override
- public void addGame(Game game) {
-
- }
-
- @Override
- public void removeGame(Game game) {
-
- }
-
- @Override
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- public void sendMessage(String message) {
-
- }
- }
-
- private Server server;
- private Duration waitTime = Duration.ofSeconds(2);
-
- @BeforeEach
- void setup() {
-
- var games = new ConcurrentHashMap>();
- games.put("tictactoe", TurnBasedGameMock.class);
- games.put("reversi", TurnBasedGameMock.class);
-
- server = new Server(games, waitTime);
- }
-
- @Test
- void testGameTypes() {
- String[] expected = {"tictactoe", "reversi"};
- String[] actual = server.gameTypes();
-
- Arrays.sort(expected);
- Arrays.sort(actual);
-
- Assertions.assertArrayEquals(expected, actual);
- }
-
- @Test
- void testChallenge() {
- server.addUser(new TestUser(1, "test1"));
- server.addUser(new TestUser(2, "test2"));
- server.challengeUser("test1", "test2", "tictactoe");
-
- IO.println(server.gameChallenges());
-
- Assertions.assertEquals(1, server.gameChallenges().size());
-
- try {
- Thread.sleep(waitTime.plusMillis(100));
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
-
- Assertions.assertEquals(0, server.gameChallenges().size());
- }
-
- @Test
- void testStartGame() {
- server.startGame("tictactoe", new User(0, "A"), new User(1, "B"));
- Assertions.assertEquals(1, server.ongoingGames().size());
- server.startGame("reversi", new User(0, "A"), new User(1, "B"));
- Assertions.assertEquals(2, server.ongoingGames().size());
- }
-
-
-}
+//package org.toop.framework.networking.server;
+//
+//import org.junit.jupiter.api.Assertions;
+//import org.junit.jupiter.api.BeforeEach;
+//import org.junit.jupiter.api.Test;
+//import org.toop.framework.gameFramework.model.game.PlayResult;
+//import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+//import org.toop.framework.gameFramework.model.player.Player;
+//
+//import java.time.Duration;
+//import java.util.Arrays;
+//import java.util.concurrent.ConcurrentHashMap;
+//
+//public class ServerTest {
+//
+// static class TurnBasedGameMock implements TurnBasedGame {
+// private Player[] players;
+//
+// public TurnBasedGameMock() {}
+//
+// @Override
+// public void init(Player[] players) {
+// this.players = players;
+// }
+//
+// @Override
+// public int getCurrentTurn() {
+// return 0;
+// }
+//
+// @Override
+// public int getPlayerCount() {
+// return 0;
+// }
+//
+// @Override
+// public int getWinner() {
+// return 0;
+// }
+//
+// @Override
+// public long[] getBoard() {
+// return new long[0];
+// }
+//
+// @Override
+// public TurnBasedGame deepCopy() {
+// return null;
+// }
+//
+// @Override
+// public long getLegalMoves() {
+// return 0;
+// }
+//
+// @Override
+// public PlayResult play(long move) {
+// return null;
+// }
+//
+// @Override
+// public Player getPlayer(int index) {
+// return null;
+// }
+//
+// }
+//
+// static class TestUser implements ServerUser {
+//
+// final private long id;
+//
+// private String name;
+//
+// public TestUser(long id, String name) {
+// this.id = id;
+// this.name = name;
+// }
+//
+// @Override
+// public long id() {
+// return id;
+// }
+//
+// @Override
+// public String name() {
+// return name;
+// }
+//
+// @Override
+// public Game[] games() {
+// return new Game[0];
+// }
+//
+// @Override
+// public void addGame(Game game) {
+//
+// }
+//
+// @Override
+// public void removeGame(Game game) {
+//
+// }
+//
+// @Override
+// public void setName(String name) {
+// this.name = name;
+// }
+//
+// @Override
+// public void sendMessage(String message) {
+//
+// }
+// }
+//
+// private Server server;
+// private Duration waitTime = Duration.ofSeconds(2);
+//
+// @BeforeEach
+// void setup() {
+//
+// var games = new ConcurrentHashMap>();
+// games.put("tictactoe", TurnBasedGameMock.class);
+// games.put("reversi", TurnBasedGameMock.class);
+//
+// server = new Server(games, waitTime);
+// }
+//
+// @Test
+// void testGameTypes() {
+// String[] expected = {"tictactoe", "reversi"};
+// String[] actual = server.gameTypes();
+//
+// Arrays.sort(expected);
+// Arrays.sort(actual);
+//
+// Assertions.assertArrayEquals(expected, actual);
+// }
+//
+// @Test
+// void testChallenge() {
+// server.addUser(new TestUser(1, "test1"));
+// server.addUser(new TestUser(2, "test2"));
+// server.challengeUser("test1", "test2", "tictactoe");
+//
+// IO.println(server.gameChallenges());
+//
+// Assertions.assertEquals(1, server.gameChallenges().size());
+//
+// try {
+// Thread.sleep(waitTime.plusMillis(100));
+// } catch (InterruptedException e) {
+// throw new RuntimeException(e);
+// }
+//
+// Assertions.assertEquals(0, server.gameChallenges().size());
+// }
+//
+// @Test
+// void testStartGame() {
+// server.startGame("tictactoe", new User(0, "A"), new User(1, "B"));
+// Assertions.assertEquals(1, server.ongoingGames().size());
+// server.startGame("reversi", new User(0, "A"), new User(1, "B"));
+// Assertions.assertEquals(2, server.ongoingGames().size());
+// }
+//
+//
+//}
From 89a9cb1e559ab98a184ae224d93d3c102e4cb0a2 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:37:34 +0100
Subject: [PATCH 15/35] Using pairs now in server.java
---
.../toop/framework/networking/server/Server.java | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index 7f0f71c..bc8742a 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -1,11 +1,8 @@
package org.toop.framework.networking.server;
-import org.toop.framework.game.gameThreads.OnlineThreadBehaviour;
-import org.toop.framework.game.players.LocalPlayer;
-import org.toop.framework.game.players.OnlinePlayer;
import org.toop.framework.game.players.ServerPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.framework.gameFramework.model.player.Player;
+import org.toop.framework.utils.ImmutablePair;
import java.util.Arrays;
import java.util.List;
@@ -147,14 +144,18 @@ public class Server implements GameServer {
if (!gameTypes.containsKey(gameType)) return;
try {
- Player[] players = new Player[users.length];
+ ServerPlayer[] players = new ServerPlayer[users.length];
+ var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
+
for (int i = 0; i < users.length; i++) {
players[i] = new ServerPlayer(users[i]);
+ users[i].addGame(new ImmutablePair<>(game, players[i]));
}
System.out.println("Starting Game");
- var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
+
game.game().init(players);
games.addLast(game);
+
users[0].sendMessage(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
users[0].name(),
gameType,
From cd5736afc80160af690d45c86a054ea50a7b8e5d Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:38:36 +0100
Subject: [PATCH 16/35] Removed space in naming
---
.../src/main/java/org/toop/framework/utils/ImmutablePair.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java b/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
index da8fe91..52abab3 100644
--- a/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
+++ b/framework/src/main/java/org/toop/framework/utils/ImmutablePair.java
@@ -1,6 +1,6 @@
package org.toop.framework.utils;
-public class ImmutablePair implements Pair {
+public class ImmutablePair implements Pair {
final T left;
final K right;
From c015100ebf45278c96b2a99552fd0280a038bde2 Mon Sep 17 00:00:00 2001
From: Stef
Date: Sat, 13 Dec 2025 17:49:54 +0100
Subject: [PATCH 17/35] Werkt nog niet
---
.../gameThreads/ServerThreadBehaviour.java | 22 +++++++++++--------
.../framework/networking/server/Game.java | 7 +++++-
.../networking/server/ServerHandler.java | 2 +-
3 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
index 8789e41..91f9186 100644
--- a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
@@ -7,22 +7,26 @@ import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThreadBehaviour;
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.framework.gameFramework.view.GUIEvents;
+import org.toop.framework.utils.ImmutablePair;
import java.util.function.Consumer;
+import static org.toop.framework.gameFramework.GameState.TURN_SKIPPED;
+import static org.toop.framework.gameFramework.GameState.WIN;
+
public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Runnable {
- private Consumer onPlayerMove;
+ private Consumer> onPlayerMove;
/**
* Creates a new base behaviour for the specified game.
*
* @param game the turn-based game to control
*/
- public ServerThreadBehaviour(TurnBasedGame game, Consumer onPlayerMove) {
+ public ServerThreadBehaviour(TurnBasedGame game, Consumer> onPlayerMove) {
super(game);
}
- private void notifyPlayerMove(int player) {
- onPlayerMove.accept(player);
+ private void notifyPlayerMove(ImmutablePair pair) {
+ onPlayerMove.accept(pair);
}
/** Starts the game loop in a new thread. */
@@ -47,14 +51,14 @@ public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Ru
PlayResult result = game.play(move);
GameState state = result.state();
+
+ if (state != TURN_SKIPPED){
+ notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(move)));
+ }
+
switch (state) {
case WIN, DRAW -> {
isRunning.set(false);
- new EventFlow().addPostEvent(
- GUIEvents.GameEnded.class,
- state == GameState.WIN,
- result.player()
- ).postEvent();
}
case NORMAL, TURN_SKIPPED -> { /* continue normally */ }
default -> {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index eeb75a3..2c9a803 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -12,10 +12,15 @@ public class Game implements OnlineGame {
public Game(TurnBasedGame game, User... users) {
this.game = game;
- this.gameThread = new ServerThreadBehaviour(game, null);
+ this.gameThread = new ServerThreadBehaviour(game, (pair) -> notifyMoveMade(pair.getLeft(), pair.getRight()));
this.users = users;
}
+ private void notifyMoveMade(String speler, int move){
+ users[0].sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", DETAILS: \"\", MOVE: \"%s\"}", speler, move));
+ users[1].sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", DETAILS: \"\", MOVE: \"%s\"}", speler, move));
+ }
+
@Override
public long id() {
return id;
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
index de33c62..48bc77e 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
@@ -121,7 +121,7 @@ public class ServerHandler extends SimpleChannelInboundHandler {
if(hasArgs(p.args())) return;
// TODO check if not number
- user.serverPlayer().setMove(Integer.parseInt(p.args()[0]));
+ user.serverPlayer().setMove(1L << Integer.parseInt(p.args()[0]));
}
private ParsedMessage parse(String msg) {
From afcd9be71ebbada6fc37684c9a5188ad1bfde353 Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 17:53:31 +0100
Subject: [PATCH 18/35] Fixed hasArgs
---
.../{ServerHandler.java => ConnectionHandler.java} | 14 +++++++-------
.../framework/networking/server/MasterServer.java | 3 +--
.../toop/framework/networking/server/Server.java | 7 -------
3 files changed, 8 insertions(+), 16 deletions(-)
rename framework/src/main/java/org/toop/framework/networking/server/{ServerHandler.java => ConnectionHandler.java} (92%)
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
similarity index 92%
rename from framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
rename to framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
index 48bc77e..8c20f32 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerHandler.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
@@ -9,12 +9,12 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-public class ServerHandler extends SimpleChannelInboundHandler {
+public class ConnectionHandler extends SimpleChannelInboundHandler {
private final User user;
private final Server server;
- public ServerHandler(User user, Server server) {
+ public ConnectionHandler(User user, Server server) {
this.user = user;
this.server = server;
}
@@ -54,19 +54,19 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
}
+ // DO NOT INVERT
private boolean hasArgs(String... args) {
return (args.length >= 1);
}
private void handleLogin(ParsedMessage p) {
-
- if (hasArgs(p.args())) return;
+ if (!hasArgs(p.args())) return;
user.setName(p.args()[0]);
}
private void handleGet(ParsedMessage p) {
- if (hasArgs(p.args())) return;
+ if (!hasArgs(p.args())) return;
switch (p.args()[0]) {
case "playerlist" -> {
@@ -93,7 +93,7 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleChallenge(ParsedMessage p) {
- if(hasArgs(p.args())) return;
+ if (!hasArgs(p.args())) return;
if (p.args().length < 2) return;
if (p.args()[0].equalsIgnoreCase("accept")) {
@@ -118,7 +118,7 @@ public class ServerHandler extends SimpleChannelInboundHandler {
}
private void handleMove(ParsedMessage p) {
- if(hasArgs(p.args())) return;
+ if(!hasArgs(p.args())) return;
// TODO check if not number
user.serverPlayer().setMove(1L << Integer.parseInt(p.args()[0]));
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
index 587a569..4259fcd 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
@@ -12,7 +12,6 @@ import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.toop.framework.SnowflakeGenerator;
-import org.toop.framework.game.BitboardGame;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import java.time.Duration;
@@ -53,7 +52,7 @@ public class MasterServer {
long userid = SnowflakeGenerator.nextId();
User user = new User(userid, ""+userid);
- pipeline.addLast(new ServerHandler(user, gs));
+ pipeline.addLast(new ConnectionHandler(user, gs));
}
}
);
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index bc8742a..4da5c4c 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -168,13 +168,6 @@ public class Server implements GameServer {
} catch (Exception ignored) {}
}
-// public void checkGames() {
-// for (int i = games.size() - 1; i >= 0; i--) {
-// var game = games.get(i);
-// if (game.game().getWinner() >= 0) games.remove(i);
-// }
-// }
-
public List onlineUsers() {
return users.values().stream().toList();
}
From cbcce297802ad23a18973ac0f8a5e973e7f5de5b Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 18:38:31 +0100
Subject: [PATCH 19/35] Closable server
---
app/src/main/java/org/toop/app/Server.java | 15 ++++++++--
.../org/toop/app/widget/view/OnlineView.java | 3 +-
.../networking/server/MasterServer.java | 28 +++++++++++++++----
3 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java
index d1eb6bb..cdea35a 100644
--- a/app/src/main/java/org/toop/app/Server.java
+++ b/app/src/main/java/org/toop/app/Server.java
@@ -22,6 +22,7 @@ import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
import org.toop.framework.game.players.ArtificialPlayer;
import org.toop.framework.game.players.OnlinePlayer;
import org.toop.framework.game.players.RandomAI;
+import org.toop.framework.networking.server.MasterServer;
import org.toop.local.AppContext;
import java.util.List;
@@ -32,7 +33,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public final class Server {
- // TODO: Keep track of listeners. Remove them on Server connection close so reference is deleted.
+ private MasterServer masterServer;
+
private String user = "";
private long clientId = -1;
@@ -60,10 +62,13 @@ public final class Server {
return null;
}
+ public Server(String ip, String port, String user) {
+ this(ip, port, user, null);
+ }
// Server has to deal with ALL network related listen events. This "server" can then interact with the manager to make stuff happen.
// This prevents data races where events get sent to the game manager but the manager isn't ready yet.
- public Server(String ip, String port, String user) {
+ public Server(String ip, String port, String user, MasterServer masterServer) {
if (ip.split("\\.").length < 4) {
new ErrorPopup("\"" + ip + "\" " + AppContext.getString("is-not-a-valid-ip-address"));
return;
@@ -83,6 +88,8 @@ public final class Server {
return;
}
+ this.masterServer = masterServer;
+
final int reconnectAttempts = 10;
LoadingWidget loading = new LoadingWidget(
@@ -281,6 +288,10 @@ public final class Server {
stopScheduler();
connectFlow.unsubscribeAll();
+ if (masterServer != null) {
+ masterServer.stop();
+ }
+
WidgetContainer.getCurrentView().transitionPrevious();
}
diff --git a/app/src/main/java/org/toop/app/widget/view/OnlineView.java b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
index c3b4e39..95d7603 100644
--- a/app/src/main/java/org/toop/app/widget/view/OnlineView.java
+++ b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
@@ -48,7 +48,8 @@ public class OnlineView extends ViewWidget {
new Server(
"127.0.0.1",
"6666",
- "host"
+ "host",
+ a
);
}, false);
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
index 4259fcd..b13dc58 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
@@ -19,7 +19,11 @@ import java.util.Map;
public class MasterServer {
private final int port;
- public final Server gs;
+ private final Server gs;
+
+ ChannelFuture future;
+ EventLoopGroup bossGroup;
+ EventLoopGroup workerGroup;
public MasterServer(int port, Map> gameTypes, Duration challengeDuration) {
this.port = port;
@@ -28,11 +32,10 @@ public class MasterServer {
public void start() throws InterruptedException {
- EventLoopGroup bossGroup = new NioEventLoopGroup(1);
- EventLoopGroup workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
+ bossGroup = new NioEventLoopGroup(1);
+ workerGroup = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
try {
-
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
@@ -57,8 +60,7 @@ public class MasterServer {
}
);
- ChannelFuture future = bootstrap.bind(port).sync();
- System.out.println("MasterServer listening on port " + port);
+ future = bootstrap.bind(port).sync();
future.channel().closeFuture().sync();
} finally {
@@ -66,4 +68,18 @@ public class MasterServer {
workerGroup.shutdownGracefully();
}
}
+
+ public void stop() {
+ if (future == null) {
+ return;
+ }
+
+ future.channel().close();
+ bossGroup.shutdownGracefully();
+ workerGroup.shutdownGracefully();
+
+ future = null;
+ bossGroup = null;
+ workerGroup = null;
+ }
}
From 73d71f2a2d2f304c750ce6b207d469fb1cc07797 Mon Sep 17 00:00:00 2001
From: Stef
Date: Sat, 13 Dec 2025 18:53:10 +0100
Subject: [PATCH 20/35] Making moves works. Game notifies when game has ended.
---
.../gameThreads/ServerThreadBehaviour.java | 24 ++++++++++++------
.../framework/game/players/ServerPlayer.java | 5 ----
.../model/player/AbstractPlayer.java | 3 ++-
.../framework/networking/server/Game.java | 25 ++++++++++++++++---
.../framework/networking/server/User.java | 3 +++
5 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
index 91f9186..a4c5ac5 100644
--- a/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
+++ b/framework/src/main/java/org/toop/framework/game/gameThreads/ServerThreadBehaviour.java
@@ -8,6 +8,7 @@ import org.toop.framework.gameFramework.model.game.threadBehaviour.AbstractThrea
import org.toop.framework.gameFramework.model.player.Player;
import org.toop.framework.gameFramework.view.GUIEvents;
import org.toop.framework.utils.ImmutablePair;
+import org.toop.framework.utils.Pair;
import java.util.function.Consumer;
@@ -15,18 +16,29 @@ import static org.toop.framework.gameFramework.GameState.TURN_SKIPPED;
import static org.toop.framework.gameFramework.GameState.WIN;
public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Runnable {
- private Consumer> onPlayerMove;
+ private final Consumer> onPlayerMove;
+ private final Consumer> onGameEnd;
/**
* Creates a new base behaviour for the specified game.
*
* @param game the turn-based game to control
*/
- public ServerThreadBehaviour(TurnBasedGame game, Consumer> onPlayerMove) {
+ public ServerThreadBehaviour(TurnBasedGame game, Consumer> onPlayerMove, Consumer> onGameEnd) {
+ this.onPlayerMove = onPlayerMove;
+ this.onGameEnd = onGameEnd;
super(game);
}
private void notifyPlayerMove(ImmutablePair pair) {
- onPlayerMove.accept(pair);
+ if (onPlayerMove != null) {
+ onPlayerMove.accept(pair);
+ }
+ }
+
+ private void notifyGameEnd(ImmutablePair pair) {
+ if (onGameEnd != null) {
+ onGameEnd.accept(pair);
+ }
}
/** Starts the game loop in a new thread. */
@@ -51,14 +63,12 @@ public class ServerThreadBehaviour extends AbstractThreadBehaviour implements Ru
PlayResult result = game.play(move);
GameState state = result.state();
-
- if (state != TURN_SKIPPED){
- notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(move)));
- }
+ notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(move)));
switch (state) {
case WIN, DRAW -> {
isRunning.set(false);
+ notifyGameEnd(new ImmutablePair<>(state, game.getWinner()));
}
case NORMAL, TURN_SKIPPED -> { /* continue normally */ }
default -> {
diff --git a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
index 535a033..519f857 100644
--- a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
+++ b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
@@ -38,9 +38,4 @@ public class ServerPlayer extends AbstractPlayer {
return 0;
}
}
-
- @Override
- public String getName() {
- return "";
- }
}
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
index f643574..8a294e8 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/model/player/AbstractPlayer.java
@@ -21,6 +21,7 @@ public abstract class AbstractPlayer implements Player {
private final String name;
protected AbstractPlayer(String name) {
+ System.out.println("Player " + name + " has been created");
this.name = name;
}
@@ -44,7 +45,7 @@ public abstract class AbstractPlayer implements Player {
throw new UnsupportedOperationException("Not supported yet.");
}
- public String getName(){
+ public final String getName(){
return this.name;
}
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index 2c9a803..6903120 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -1,6 +1,7 @@
package org.toop.framework.networking.server;
import org.toop.framework.game.gameThreads.ServerThreadBehaviour;
+import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
public class Game implements OnlineGame {
@@ -12,13 +13,31 @@ public class Game implements OnlineGame {
public Game(TurnBasedGame game, User... users) {
this.game = game;
- this.gameThread = new ServerThreadBehaviour(game, (pair) -> notifyMoveMade(pair.getLeft(), pair.getRight()));
+ this.gameThread = new ServerThreadBehaviour(
+ game,
+ (pair) -> notifyMoveMade(pair.getLeft(), pair.getRight()),
+ (pair) -> notifyGameEnd(pair.getLeft(), pair.getRight())
+ );
this.users = users;
}
private void notifyMoveMade(String speler, int move){
- users[0].sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", DETAILS: \"\", MOVE: \"%s\"}", speler, move));
- users[1].sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", DETAILS: \"\", MOVE: \"%s\"}", speler, move));
+ for (User user : users) {
+ user.sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", MOVE: \"%s\", DETAILS: \"\"}\n", speler, move));
+ }
+ }
+
+ private void notifyGameEnd(GameState state, int winner){
+ if (state == GameState.DRAW){
+ for (User user : users) {
+ user.sendMessage(String.format("SVR GAME DRAW {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
+ }
+ }
+ else{
+ users[winner].sendMessage(String.format("SVR GAME WIN {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
+ users[(winner + 1)%2].sendMessage(String.format("SVR GAME LOSS {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
+ }
+
}
@Override
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/User.java
index 3078ca5..34c1211 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/User.java
@@ -39,6 +39,9 @@ public class User implements ServerUser {
@Override
public Game game() {
+ if (this.gamePair == null) {
+ return null;
+ }
return this.gamePair.getLeft();
}
From 0956286616b3046f811e0ecdc5aeababc46cc4cb Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 21:11:26 +0100
Subject: [PATCH 21/35] Partial server refactor
---
app/src/main/java/org/toop/app/Server.java | 14 +-
.../org/toop/app/widget/view/OnlineView.java | 12 +-
.../framework/game/players/ServerPlayer.java | 12 +-
.../networking/server/ConnectionHandler.java | 155 ------------------
.../framework/networking/server/Game.java | 23 +--
.../networking/server/GameDefinition.java | 28 ----
.../networking/server/GameServer.java | 2 +-
.../networking/server/MessageStore.java | 7 -
.../networking/server/OnlineGame.java | 4 +-
.../framework/networking/server/Parser.java | 4 -
.../networking/server/ServableGame.java | 4 -
.../framework/networking/server/Server.java | 99 ++++++-----
.../networking/server/ServerMessageStore.java | 27 ---
.../networking/server/ServerUser.java | 15 --
.../gamechallenge}/GameChallenge.java | 14 +-
.../gamechallenge}/GameChallengeTimer.java | 4 +-
.../networking/server/client/Client.java | 19 +++
.../{User.java => client/NettyClient.java} | 26 ++-
.../connectionHandler/ClientSession.java | 7 +
.../connectionHandler/NettyClientSession.java | 64 ++++++++
.../server/gateway/GatewayServer.java | 7 +
.../NettyGatewayServer.java} | 37 ++++-
.../networking/server/handlers/Handler.java | 5 +
.../server/handlers/MessageHandler.java | 104 ++++++++++++
.../server/{ => parsing}/ParsedMessage.java | 2 +-
.../networking/server/parsing/Parser.java | 24 +++
.../networking/server/stores/ClientStore.java | 7 +
.../networking/server/stores/GameStore.java | 3 +
.../server/stores/NettyClientStore.java | 34 ++++
.../networking/server/stores/Store.java | 10 ++
.../server/stores/TurnBasedGameStore.java | 36 ++++
.../server/stores/TurnBasedGameTypeStore.java | 32 ++++
.../server => utils}/SimpleTimer.java | 2 +-
.../java/org/toop/framework/utils/Utils.java | 11 ++
.../networking/server/ServerTest.java | 6 +-
35 files changed, 511 insertions(+), 349 deletions(-)
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/Parser.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
delete mode 100644 framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
rename framework/src/main/java/org/toop/framework/networking/server/{ => challenges/gamechallenge}/GameChallenge.java (66%)
rename framework/src/main/java/org/toop/framework/networking/server/{ => challenges/gamechallenge}/GameChallengeTimer.java (86%)
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/client/Client.java
rename framework/src/main/java/org/toop/framework/networking/server/{User.java => client/NettyClient.java} (69%)
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/connectionHandler/ClientSession.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/gateway/GatewayServer.java
rename framework/src/main/java/org/toop/framework/networking/server/{MasterServer.java => gateway/NettyGatewayServer.java} (64%)
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/handlers/Handler.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java
rename framework/src/main/java/org/toop/framework/networking/server/{ => parsing}/ParsedMessage.java (54%)
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/parsing/Parser.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/ClientStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/GameStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/NettyClientStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/Store.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameStore.java
create mode 100644 framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameTypeStore.java
rename framework/src/main/java/org/toop/framework/{networking/server => utils}/SimpleTimer.java (70%)
create mode 100644 framework/src/main/java/org/toop/framework/utils/Utils.java
diff --git a/app/src/main/java/org/toop/app/Server.java b/app/src/main/java/org/toop/app/Server.java
index cdea35a..0b10983 100644
--- a/app/src/main/java/org/toop/app/Server.java
+++ b/app/src/main/java/org/toop/app/Server.java
@@ -17,12 +17,10 @@ import org.toop.framework.gameFramework.model.player.Player;
import org.toop.framework.networking.connection.clients.TournamentNetworkingClient;
import org.toop.framework.networking.connection.events.NetworkEvents;
import org.toop.framework.networking.connection.types.NetworkingConnector;
-import org.toop.framework.game.games.reversi.BitboardReversi;
-import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
import org.toop.framework.game.players.ArtificialPlayer;
import org.toop.framework.game.players.OnlinePlayer;
import org.toop.framework.game.players.RandomAI;
-import org.toop.framework.networking.server.MasterServer;
+import org.toop.framework.networking.server.gateway.NettyGatewayServer;
import org.toop.local.AppContext;
import java.util.List;
@@ -33,7 +31,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public final class Server {
- private MasterServer masterServer;
+ private NettyGatewayServer nettyGatewayServer;
private String user = "";
private long clientId = -1;
@@ -68,7 +66,7 @@ public final class Server {
// Server has to deal with ALL network related listen events. This "server" can then interact with the manager to make stuff happen.
// This prevents data races where events get sent to the game manager but the manager isn't ready yet.
- public Server(String ip, String port, String user, MasterServer masterServer) {
+ public Server(String ip, String port, String user, NettyGatewayServer nettyGatewayServer) {
if (ip.split("\\.").length < 4) {
new ErrorPopup("\"" + ip + "\" " + AppContext.getString("is-not-a-valid-ip-address"));
return;
@@ -88,7 +86,7 @@ public final class Server {
return;
}
- this.masterServer = masterServer;
+ this.nettyGatewayServer = nettyGatewayServer;
final int reconnectAttempts = 10;
@@ -288,8 +286,8 @@ public final class Server {
stopScheduler();
connectFlow.unsubscribeAll();
- if (masterServer != null) {
- masterServer.stop();
+ if (nettyGatewayServer != null) {
+ nettyGatewayServer.stop();
}
WidgetContainer.getCurrentView().transitionPrevious();
diff --git a/app/src/main/java/org/toop/app/widget/view/OnlineView.java b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
index 95d7603..4ae8692 100644
--- a/app/src/main/java/org/toop/app/widget/view/OnlineView.java
+++ b/app/src/main/java/org/toop/app/widget/view/OnlineView.java
@@ -9,7 +9,8 @@ import javafx.geometry.Pos;
import org.toop.framework.game.games.reversi.BitboardReversi;
import org.toop.framework.game.games.tictactoe.BitboardTicTacToe;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-import org.toop.framework.networking.server.MasterServer;
+import org.toop.framework.networking.server.gateway.NettyGatewayServer;
+import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore;
import java.time.Duration;
import java.util.concurrent.ConcurrentHashMap;
@@ -31,11 +32,12 @@ public class OnlineView extends ViewWidget {
});
var localHostButton = Primitive.button("host!", () -> {
- var games = new ConcurrentHashMap>();
- games.put("tic-tac-toe", BitboardTicTacToe.class);
- games.put("reversi", BitboardReversi.class);
- var a = new MasterServer(6666, games, Duration.ofSeconds(10));
+ var tps = new TurnBasedGameTypeStore();
+ tps.register("tic-tac-toe", BitboardTicTacToe::new);
+ tps.register("reversi", BitboardReversi::new);
+
+ var a = new NettyGatewayServer(6666, tps, Duration.ofSeconds(10));
new Thread(() -> {
try {
diff --git a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
index 519f857..f4a7ed0 100644
--- a/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
+++ b/framework/src/main/java/org/toop/framework/game/players/ServerPlayer.java
@@ -3,18 +3,18 @@ package org.toop.framework.game.players;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.gameFramework.model.player.AbstractPlayer;
import org.toop.framework.gameFramework.model.player.Player;
-import org.toop.framework.networking.server.User;
+import org.toop.framework.networking.server.client.NettyClient;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class ServerPlayer extends AbstractPlayer {
- private User user;
+ private NettyClient client;
private CompletableFuture lastMove;
- public ServerPlayer(User user) {
- super(user.name());
- this.user = user;
+ public ServerPlayer(NettyClient client) {
+ super(client.name());
+ this.client = client;
}
public void setMove(long move) {
@@ -30,7 +30,7 @@ public class ServerPlayer extends AbstractPlayer {
public long getMove(TurnBasedGame game) {
lastMove = new CompletableFuture<>();
System.out.println("Sending yourturn");
- user.sendMessage("SVR GAME YOURTURN {TURNMESSAGE: \"\"}\n");
+ client.send("SVR GAME YOURTURN {TURNMESSAGE: \"\"}\n");
try {
return lastMove.get();
} catch (InterruptedException | ExecutionException e) {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java b/framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
deleted file mode 100644
index 8c20f32..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/ConnectionHandler.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package org.toop.framework.networking.server;
-
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.SimpleChannelInboundHandler;
-import org.apache.maven.surefire.shared.utils.StringUtils;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
-public class ConnectionHandler extends SimpleChannelInboundHandler {
-
- private final User user;
- private final Server server;
-
- public ConnectionHandler(User user, Server server) {
- this.user = user;
- this.server = server;
- }
-
- private String returnQuotedString(Iterator strings) { // TODO more places this could be useful
- return "\"" + StringUtils.join(strings, "\",\"") + "\"";
- }
-
- @Override
- public void channelActive(ChannelHandlerContext ctx) {
- ctx.writeAndFlush("WELCOME " + user.id() + "\n");
-
- user.setCtx(ctx);
- server.addUser(user); // TODO set correct name on login
- }
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, String msg) {
-
- IO.println(msg);
-
- ParsedMessage p = parse(msg);
- if (p == null) return;
-
- IO.println(p.command() + " " + Arrays.toString(p.args()));
-
- switch (p.command()) {
- case "ping" -> ctx.writeAndFlush("PONG\n");
- case "login" -> handleLogin(p);
- case "get" -> handleGet(p);
- case "subscribe" -> handleSubscribe(p);
- case "move" -> handleMove(p);
- case "challenge" -> handleChallenge(p);
- case "message" -> handleMessage(p);
- case "help" -> handleHelp(p);
- default -> ctx.writeAndFlush("ERROR Unknown command\n");
- }
- }
-
- // DO NOT INVERT
- private boolean hasArgs(String... args) {
- return (args.length >= 1);
- }
-
- private void handleLogin(ParsedMessage p) {
- if (!hasArgs(p.args())) return;
-
- user.setName(p.args()[0]);
- }
-
- private void handleGet(ParsedMessage p) {
- if (!hasArgs(p.args())) return;
-
- switch (p.args()[0]) {
- case "playerlist" -> {
- var names = server.onlineUsers().stream().map(ServerUser::name).iterator();
- user.ctx().writeAndFlush("SVR PLAYERLIST " + returnQuotedString(names) + "\n");
- }
- case "gamelist" -> {
- var names = server.gameTypes().stream().iterator();
- user.ctx().writeAndFlush("SVR GAMELIST " + returnQuotedString(names) + "\n");
- }
- }
- }
-
- private void handleSubscribe(ParsedMessage p) {
- // TODO
- }
-
- private void handleHelp(ParsedMessage p) {
- // TODO
- }
-
- private void handleMessage(ParsedMessage p) {
- // TODO
- }
-
- private void handleChallenge(ParsedMessage p) {
- if (!hasArgs(p.args())) return;
- if (p.args().length < 2) return;
-
- if (p.args()[0].equalsIgnoreCase("accept")) {
- try {
- long id = Long.parseLong(p.args()[1]);
-
- if (id <= 0) {
- user.sendMessage("ERR id must be a positive number \n");
- return;
- }
-
- server.acceptChallenge(id);
-
- } catch (NumberFormatException e) {
- user.sendMessage("ERR id is not a valid number or too big \n");
- return;
- }
- return;
- }
-
- server.challengeUser(user.name(), p.args()[0], p.args()[1]);
- }
-
- private void handleMove(ParsedMessage p) {
- if(!hasArgs(p.args())) return;
-
- // TODO check if not number
- user.serverPlayer().setMove(1L << Integer.parseInt(p.args()[0]));
- }
-
- private ParsedMessage parse(String msg) {
- // TODO, what if empty string.
-
- if (msg.isEmpty()) return null;
-
- msg = msg.trim().toLowerCase();
-
- List parts = new LinkedList<>(List.of(msg.split(" ")));
-
- if (parts.size() > 1) {
- String command = parts.removeFirst();
- return new ParsedMessage(command, parts.toArray(String[]::new));
- }
- else {
- return new ParsedMessage(msg);
- }
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
- cause.printStackTrace();
- ctx.close();
- }
-
- @Override
- public void channelInactive(ChannelHandlerContext ctx) {
- server.removeUser(user);
- }
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/Game.java
index 6903120..3ac78b8 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Game.java
@@ -3,39 +3,40 @@ package org.toop.framework.networking.server;
import org.toop.framework.game.gameThreads.ServerThreadBehaviour;
import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.networking.server.client.NettyClient;
public class Game implements OnlineGame {
private long id;
- private User[] users;
+ private NettyClient[] clients;
private TurnBasedGame game;
private ServerThreadBehaviour gameThread;
- public Game(TurnBasedGame game, User... users) {
+ public Game(TurnBasedGame game, NettyClient... clients) {
this.game = game;
this.gameThread = new ServerThreadBehaviour(
game,
(pair) -> notifyMoveMade(pair.getLeft(), pair.getRight()),
(pair) -> notifyGameEnd(pair.getLeft(), pair.getRight())
);
- this.users = users;
+ this.clients = clients;
}
private void notifyMoveMade(String speler, int move){
- for (User user : users) {
- user.sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", MOVE: \"%s\", DETAILS: \"\"}\n", speler, move));
+ for (NettyClient client : clients) {
+ client.send(String.format("SVR GAME MOVE {PLAYER: \"%s\", MOVE: \"%s\", DETAILS: \"\"}\n", speler, move));
}
}
private void notifyGameEnd(GameState state, int winner){
if (state == GameState.DRAW){
- for (User user : users) {
- user.sendMessage(String.format("SVR GAME DRAW {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
+ for (NettyClient client : clients) {
+ client.send(String.format("SVR GAME DRAW {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"NettyClient disconnected\"}\n"));
}
}
else{
- users[winner].sendMessage(String.format("SVR GAME WIN {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
- users[(winner + 1)%2].sendMessage(String.format("SVR GAME LOSS {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"Client disconnected\"}\n"));
+ clients[winner].send(String.format("SVR GAME WIN {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"NettyClient disconnected\"}\n"));
+ clients[(winner + 1)%2].send(String.format("SVR GAME LOSS {PLAYERONESCORE: \"\", PLAYERTWOSCORE: \"\", COMMENT: \"NettyClient disconnected\"}\n"));
}
}
@@ -51,8 +52,8 @@ public class Game implements OnlineGame {
}
@Override
- public User[] users() {
- return users;
+ public NettyClient[] users() {
+ return clients;
}
@Override
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java b/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
deleted file mode 100644
index bd8252d..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/GameDefinition.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.toop.framework.networking.server;
-
-import org.toop.framework.gameFramework.model.game.TurnBasedGame;
-
-import java.lang.reflect.InvocationTargetException;
-
-public class GameDefinition {
- private final String name;
- private final Class game;
-
- public GameDefinition(String name, Class game) {
- this.name = name;
- this.game = game;
- }
-
- public String name() {
- return name;
- }
-
- public T create(String... users) {
- try {
- return game.getDeclaredConstructor().newInstance(users);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameServer.java b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
index 39a03f7..00993a0 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
@@ -3,6 +3,6 @@ package org.toop.framework.networking.server;
public interface GameServer {
// List> gameTypes();
// List> ongoingGames();
-// void startGame(String gameType, User... users);
+// void startGame(String gameType, NettyClient... users);
// String[] onlineUsers();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java b/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
deleted file mode 100644
index 6fbba3b..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/MessageStore.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.toop.framework.networking.server;
-
-public interface MessageStore {
- void add(String message);
- String get();
- void reset();
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
index b82b4b1..39739e6 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineGame.java
@@ -1,8 +1,10 @@
package org.toop.framework.networking.server;
+import org.toop.framework.networking.server.client.NettyClient;
+
public interface OnlineGame {
long id();
T game();
- User[] users();
+ NettyClient[] users();
void start();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Parser.java b/framework/src/main/java/org/toop/framework/networking/server/Parser.java
deleted file mode 100644
index 016f797..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/Parser.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package org.toop.framework.networking.server;
-
-public class Parser {
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java b/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
deleted file mode 100644
index 17dd3a9..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/ServableGame.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package org.toop.framework.networking.server;
-
-public interface ServableGame {
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index 4da5c4c..cb4f543 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -2,27 +2,41 @@ package org.toop.framework.networking.server;
import org.toop.framework.game.players.ServerPlayer;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.networking.server.challenges.gamechallenge.GameChallenge;
+import org.toop.framework.networking.server.challenges.gamechallenge.GameChallengeTimer;
+import org.toop.framework.networking.server.client.NettyClient;
+import org.toop.framework.networking.server.stores.ClientStore;
+import org.toop.framework.networking.server.stores.TurnBasedGameStore;
+import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore;
import org.toop.framework.utils.ImmutablePair;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.*;
import java.time.Duration;
public class Server implements GameServer {
- final private Map> gameTypes;
- final private Map users = new ConcurrentHashMap<>();
+ final private TurnBasedGameTypeStore gameTypesStore;
+ final private ClientStore clientStore;
final private List gameChallenges = new CopyOnWriteArrayList<>();
- final private List> games = new CopyOnWriteArrayList<>();
+ final private TurnBasedGameStore gameStore;
final private Duration challengeDuration;
final private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
- public Server(Map> gameTypes, Duration challengeDuration) {
- this.gameTypes = gameTypes;
+ public Server(
+ Duration challengeDuration,
+ TurnBasedGameTypeStore turnBasedGameTypeStore,
+ ClientStore clientStore,
+ TurnBasedGameStore gameStore
+
+ ) {
+ this.gameTypesStore = turnBasedGameTypeStore;
this.challengeDuration = challengeDuration;
+ this.clientStore = clientStore;
+ this.gameStore = gameStore;
scheduler.schedule(this::serverTask, 0, TimeUnit.MILLISECONDS);
}
@@ -32,51 +46,51 @@ public class Server implements GameServer {
scheduler.schedule(this::serverTask, 500, TimeUnit.MILLISECONDS);
}
- public void addUser(User user) {
- users.putIfAbsent(user.id(), user);
+ public void addUser(NettyClient client) {
+ clientStore.add(client);
}
- public void removeUser(User user) {
- users.remove(user.id());
+ public void removeUser(NettyClient client) {
+ clientStore.remove(client.id());
}
public List gameTypes() {
- return gameTypes.keySet().stream().toList();
+ return new ArrayList<>(gameTypesStore.all().keySet());
}
public List> ongoingGames() {
- return games;
+ return gameStore.all().stream().toList();
}
- public User getUser(String username) {
- return users.values().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
+ public NettyClient getUser(String username) {
+ return clientStore.all().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
}
- public User getUser(long id) {
- return users.get(id);
+ public NettyClient getUser(long id) {
+ return clientStore.get(id);
}
public void challengeUser(String fromUser, String toUser, String gameType) {
- User from = getUser(fromUser);
+ NettyClient from = getUser(fromUser);
if (from == null) {
return;
}
- if (!gameTypes.containsKey(gameType)) {
- from.sendMessage("ERR gametype not found \n");
+ if (!gameTypesStore.all().containsKey(gameType)) {
+ from.send("ERR gametype not found \n");
return;
}
- User to = getUser(toUser);
+ NettyClient to = getUser(toUser);
if (to == null) {
- from.sendMessage("ERR user not found \n");
+ from.send("ERR user not found \n");
return;
}
var ch = new GameChallenge(from, to, gameType, new GameChallengeTimer(challengeDuration));
- to.sendMessage(
+ to.send(
"SVR GAME CHALLENGE {CHALLENGER: \"%s\", CHALLENGENUMBER: \"%s\", GAMETYPE: \"%s\"} \n"
.formatted(from.name(), ch.id(), gameType)
);
@@ -90,13 +104,13 @@ public class Server implements GameServer {
gameChallenges.addLast(ch);
}
- private void warnUserExpiredChallenge(User user, long challengeId) {
- user.sendMessage("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}" + "\n");
+ private void warnUserExpiredChallenge(NettyClient client, long challengeId) {
+ client.send("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}" + "\n");
}
private boolean isValidChallenge(GameChallenge gameChallenge) {
for (var user : gameChallenge.getUsers()) {
- if (users.get(user.id()) == null) {
+ if (clientStore.get(user.id()) == null) {
return false;
}
@@ -140,43 +154,40 @@ public class Server implements GameServer {
return gameChallenges;
}
- public void startGame(String gameType, User... users) {
- if (!gameTypes.containsKey(gameType)) return;
+ public void startGame(String gameType, NettyClient... clients) {
+ if (!gameTypesStore.all().containsKey(gameType)) return;
try {
- ServerPlayer[] players = new ServerPlayer[users.length];
- var game = new Game(gameTypes.get(gameType).getDeclaredConstructor().newInstance(), users);
+ ServerPlayer[] players = new ServerPlayer[clients.length];
+ var game = new Game(gameTypesStore.create(gameType), clients);
- for (int i = 0; i < users.length; i++) {
- players[i] = new ServerPlayer(users[i]);
- users[i].addGame(new ImmutablePair<>(game, players[i]));
+ for (int i = 0; i < clients.length; i++) {
+ players[i] = new ServerPlayer(clients[i]);
+ clients[i].addGame(new ImmutablePair<>(game, players[i]));
}
System.out.println("Starting Game");
game.game().init(players);
- games.addLast(game);
+ gameStore.add(game);
- users[0].sendMessage(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
- users[0].name(),
+ clients[0].send(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
+ clients[0].name(),
gameType,
- users[1].name()));
- users[1].sendMessage(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
- users[0].name(),
+ clients[1].name()));
+ clients[1].send(String.format("SVR GAME MATCH {PLAYERTOMOVE: \"%s\", GAMETYPE: \"%s\", OPPONENT: \"%s\"}\n",
+ clients[0].name(),
gameType,
- users[0].name()));
+ clients[0].name()));
game.start();
} catch (Exception ignored) {}
}
- public List onlineUsers() {
- return users.values().stream().toList();
+ public List onlineUsers() {
+ return clientStore.all().stream().toList();
}
public void closeServer() {
scheduler.shutdown();
gameChallenges.clear();
- games.clear();
- users.clear();
- gameTypes.clear();
}
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java b/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
deleted file mode 100644
index 22af1d7..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerMessageStore.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.toop.framework.networking.server;
-
-import java.util.Queue;
-
-public class ServerMessageStore implements MessageStore {
-
- Queue messageQueue;
-
- public ServerMessageStore(Queue messageQueue) {
- this.messageQueue = messageQueue;
- }
-
- @Override
- public void add(String message) {
- messageQueue.offer(message);
- }
-
- @Override
- public String get() {
- return messageQueue.poll();
- }
-
- @Override
- public void reset() {
- messageQueue.clear();
- }
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java b/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
deleted file mode 100644
index e06098c..0000000
--- a/framework/src/main/java/org/toop/framework/networking/server/ServerUser.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.toop.framework.networking.server;
-
-import org.toop.framework.game.players.ServerPlayer;
-import org.toop.framework.utils.Pair;
-
-public interface ServerUser {
- long id();
- String name();
- Game game();
- ServerPlayer serverPlayer();
- void addGame(Pair gamePair);
- void removeGame();
- void setName(String name);
- void sendMessage(String message);
-}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java b/framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallenge.java
similarity index 66%
rename from framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
rename to framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallenge.java
index 50a5c2b..c9fefa7 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameChallenge.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallenge.java
@@ -1,18 +1,20 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.networking.server.challenges.gamechallenge;
import org.toop.framework.SnowflakeGenerator;
+import org.toop.framework.networking.server.client.NettyClient;
+import org.toop.framework.utils.SimpleTimer;
public class GameChallenge {
private final long id = SnowflakeGenerator.nextId(); // I don't need this, but the tournament server uses it...
- private final User from;
- private final User to;
+ private final NettyClient from;
+ private final NettyClient to;
private final String gameType;
private final SimpleTimer timer;
private boolean isChallengeAccepted = false;
- public GameChallenge(User from, User to, String gameType, SimpleTimer timer) {
+ public GameChallenge(NettyClient from, NettyClient to, String gameType, SimpleTimer timer) {
this.from = from;
this.to = to;
this.gameType = gameType;
@@ -23,8 +25,8 @@ public class GameChallenge {
return id;
}
- public User[] getUsers() {
- return new User[]{from, to};
+ public NettyClient[] getUsers() {
+ return new NettyClient[]{from, to};
}
public void forceExpire() {
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java b/framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallengeTimer.java
similarity index 86%
rename from framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java
rename to framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallengeTimer.java
index 1406648..bf277b7 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameChallengeTimer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/challenges/gamechallenge/GameChallengeTimer.java
@@ -1,4 +1,6 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.networking.server.challenges.gamechallenge;
+
+import org.toop.framework.utils.SimpleTimer;
import java.time.Instant;
import java.time.Duration;
diff --git a/framework/src/main/java/org/toop/framework/networking/server/client/Client.java b/framework/src/main/java/org/toop/framework/networking/server/client/Client.java
new file mode 100644
index 0000000..96ea515
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/client/Client.java
@@ -0,0 +1,19 @@
+package org.toop.framework.networking.server.client;
+
+import org.toop.framework.networking.server.Game;
+import org.toop.framework.utils.Pair;
+
+public interface Client {
+ long id();
+
+ String name();
+ void setName(String name);
+
+ Game game();
+ P player();
+
+ void addGame(Pair gamePair);
+ void clearGame();
+
+ void send(String message);
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/User.java b/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
similarity index 69%
rename from framework/src/main/java/org/toop/framework/networking/server/User.java
rename to framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
index 34c1211..37eeb4b 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/User.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
@@ -1,16 +1,17 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.networking.server.client;
import io.netty.channel.ChannelHandlerContext;
import org.toop.framework.game.players.ServerPlayer;
+import org.toop.framework.networking.server.Game;
import org.toop.framework.utils.Pair;
-public class User implements ServerUser {
+public class NettyClient implements Client {
final private long id;
+ private ChannelHandlerContext ctx;
private String name;
private Pair gamePair;
- private ChannelHandlerContext connectionContext;
- public User(long userId, String name) {
+ public NettyClient(long userId, String name) {
this.id = userId;
this.name = name;
}
@@ -33,7 +34,7 @@ public class User implements ServerUser {
}
@Override
- public void removeGame() {
+ public void clearGame() {
this.gamePair = null;
}
@@ -45,7 +46,8 @@ public class User implements ServerUser {
return this.gamePair.getLeft();
}
- public ServerPlayer serverPlayer() {
+ @Override
+ public ServerPlayer player() {
return this.gamePair.getRight();
}
@@ -55,18 +57,12 @@ public class User implements ServerUser {
}
@Override
- public void sendMessage(String message) {
+ public void send(String message) {
IO.println(message);
- ctx().channel().writeAndFlush(message);
- }
-
- public ChannelHandlerContext ctx() {
- return connectionContext;
+ ctx.channel().writeAndFlush(message + "\r\n");
}
public void setCtx(ChannelHandlerContext ctx) {
- this.connectionContext = ctx;
+ this.ctx = ctx;
}
-
-
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/ClientSession.java b/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/ClientSession.java
new file mode 100644
index 0000000..06c9a65
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/ClientSession.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server.connectionHandler;
+
+import org.toop.framework.networking.server.client.Client;
+
+public interface ClientSession {
+ Client client();
+}
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
new file mode 100644
index 0000000..ae1f071
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/connectionHandler/NettyClientSession.java
@@ -0,0 +1,64 @@
+package org.toop.framework.networking.server.connectionHandler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import org.toop.framework.game.players.ServerPlayer;
+import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.client.NettyClient;
+import org.toop.framework.networking.server.handlers.Handler;
+import org.toop.framework.networking.server.parsing.ParsedMessage;
+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;
+ private final Server server;
+ private final Handler handler;
+
+ public NettyClientSession(NettyClient client, Server server, Handler handler) {
+ this.client = client;
+ this.server = server;
+ this.handler = handler;
+ }
+
+ @Override
+ public Client client() {
+ return client;
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ ctx.writeAndFlush("Welcome " + client.id() + " please login" + "\n");
+
+ client.setCtx(ctx);
+ server.addUser(client); // TODO set correct name on login
+ }
+
+ @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);
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+ ctx.close();
+ }
+
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ server.removeUser(client);
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/gateway/GatewayServer.java b/framework/src/main/java/org/toop/framework/networking/server/gateway/GatewayServer.java
new file mode 100644
index 0000000..9aef1d6
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/gateway/GatewayServer.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server.gateway;
+
+public interface GatewayServer {
+ void start() throws Exception;
+ void stop();
+ int port();
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java b/framework/src/main/java/org/toop/framework/networking/server/gateway/NettyGatewayServer.java
similarity index 64%
rename from framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
rename to framework/src/main/java/org/toop/framework/networking/server/gateway/NettyGatewayServer.java
index b13dc58..9a4a73f 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/MasterServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/gateway/NettyGatewayServer.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.networking.server.gateway;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
@@ -13,11 +13,20 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.toop.framework.SnowflakeGenerator;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.networking.server.client.NettyClient;
+import org.toop.framework.networking.server.connectionHandler.NettyClientSession;
+import org.toop.framework.networking.server.Server;
+import org.toop.framework.networking.server.handlers.MessageHandler;
+import org.toop.framework.networking.server.stores.NettyClientStore;
+import org.toop.framework.networking.server.stores.TurnBasedGameStore;
+import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore;
import java.time.Duration;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
-public class MasterServer {
+public class NettyGatewayServer implements GatewayServer {
private final int port;
private final Server gs;
@@ -25,11 +34,21 @@ public class MasterServer {
EventLoopGroup bossGroup;
EventLoopGroup workerGroup;
- public MasterServer(int port, Map> gameTypes, Duration challengeDuration) {
+ public NettyGatewayServer(
+ int port,
+ TurnBasedGameTypeStore turnBasedGameTypeStore,
+ Duration challengeDuration
+ ) {
this.port = port;
- this.gs = new Server(gameTypes, challengeDuration);
+ this.gs = new Server(
+ challengeDuration,
+ turnBasedGameTypeStore,
+ new NettyClientStore(new ConcurrentHashMap<>()),
+ new TurnBasedGameStore(new CopyOnWriteArrayList<>())
+ );
}
+ @Override
public void start() throws InterruptedException {
bossGroup = new NioEventLoopGroup(1);
@@ -54,8 +73,8 @@ public class MasterServer {
pipeline.addLast(new StringEncoder());
long userid = SnowflakeGenerator.nextId();
- User user = new User(userid, ""+userid);
- pipeline.addLast(new ConnectionHandler(user, gs));
+ NettyClient client = new NettyClient(userid, ""+userid);
+ pipeline.addLast(new NettyClientSession(client, gs, new MessageHandler(gs, client)));
}
}
);
@@ -69,6 +88,7 @@ public class MasterServer {
}
}
+ @Override
public void stop() {
if (future == null) {
return;
@@ -82,4 +102,9 @@ public class MasterServer {
bossGroup = null;
workerGroup = null;
}
+
+ @Override
+ public int port() {
+ return port;
+ }
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/handlers/Handler.java b/framework/src/main/java/org/toop/framework/networking/server/handlers/Handler.java
new file mode 100644
index 0000000..70b4ed6
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/handlers/Handler.java
@@ -0,0 +1,5 @@
+package org.toop.framework.networking.server.handlers;
+
+public interface Handler {
+ void handle(T message);
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java b/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java
new file mode 100644
index 0000000..28bc24a
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/handlers/MessageHandler.java
@@ -0,0 +1,104 @@
+package org.toop.framework.networking.server.handlers;
+
+import org.toop.framework.game.players.ServerPlayer;
+import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.Server;
+import org.toop.framework.networking.server.client.Client;
+import org.toop.framework.networking.server.parsing.ParsedMessage;
+import org.toop.framework.utils.Utils;
+
+public class MessageHandler implements Handler {
+
+ private final Server server;
+ private final Client client;
+
+ public MessageHandler(Server server, Client client) {
+ this.server = server;
+ this.client = client;
+ }
+
+ @Override
+ public void handle(ParsedMessage message) {
+ switch (message.command()) {
+ case "ping" -> client.send("PONG");
+ case "login" -> handleLogin(message, client);
+ case "get" -> handleGet(message, client);
+ case "subscribe" -> handleSubscribe(message, client);
+ case "move" -> handleMove(message, client);
+ case "challenge" -> handleChallenge(message, client);
+ case "message" -> handleMessage(message, client);
+ case "help" -> handleHelp(message, client);
+ default -> client.send("ERROR Unknown command");
+ }
+ }
+
+ // DO NOT INVERT
+ private boolean hasArgs(String... args) {
+ return (args.length >= 1);
+ }
+
+ private void handleLogin(ParsedMessage p, Client client) {
+ if (!hasArgs(p.args())) return;
+
+ client.setName(p.args()[0]);
+ }
+
+ private void handleSubscribe(ParsedMessage p, Client client) {
+ // TODO
+ }
+
+ private void handleHelp(ParsedMessage p, Client client) {
+ // TODO
+ }
+
+ private void handleMessage(ParsedMessage p, Client client) {
+ // TODO
+ }
+
+ private void handleGet(ParsedMessage p, Client client) {
+ if (!hasArgs(p.args())) return;
+
+ switch (p.args()[0]) {
+ case "playerlist" -> {
+ var names = server.onlineUsers().stream().map(Client::name).iterator();
+ client.send("SVR PLAYERLIST " + Utils.returnQuotedString(names));
+ }
+ case "gamelist" -> {
+ var names = server.gameTypes().stream().iterator();
+ client.send("SVR GAMELIST " + Utils.returnQuotedString(names));
+ }
+ }
+ }
+
+ private void handleChallenge(ParsedMessage p, Client client) {
+ if (!hasArgs(p.args())) return;
+ if (p.args().length < 2) return;
+
+ if (p.args()[0].equalsIgnoreCase("accept")) {
+ try {
+ long id = Long.parseLong(p.args()[1]);
+
+ if (id <= 0) {
+ client.send("ERR id must be a positive number");
+ return;
+ }
+
+ server.acceptChallenge(id);
+
+ } catch (NumberFormatException e) {
+ client.send("ERR id is not a valid number or too big");
+ return;
+ }
+ return;
+ }
+
+ server.challengeUser(client.name(), p.args()[0], p.args()[1]);
+ }
+
+ private void handleMove(ParsedMessage p, Client client) {
+ if(!hasArgs(p.args())) return;
+
+ // TODO check if not number
+ client.player().setMove(1L << Integer.parseInt(p.args()[0]));
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java b/framework/src/main/java/org/toop/framework/networking/server/parsing/ParsedMessage.java
similarity index 54%
rename from framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java
rename to framework/src/main/java/org/toop/framework/networking/server/parsing/ParsedMessage.java
index 5f8e550..e788ae3 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/ParsedMessage.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/parsing/ParsedMessage.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.networking.server.parsing;
public record ParsedMessage(String command, String... args) {}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/parsing/Parser.java b/framework/src/main/java/org/toop/framework/networking/server/parsing/Parser.java
new file mode 100644
index 0000000..cb5cb97
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/parsing/Parser.java
@@ -0,0 +1,24 @@
+package org.toop.framework.networking.server.parsing;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class Parser {
+ public static ParsedMessage parse(String msg) {
+ // TODO, what if empty string.
+
+ if (msg.isEmpty()) return null;
+
+ msg = msg.trim().toLowerCase();
+
+ List parts = new LinkedList<>(List.of(msg.split(" ")));
+
+ if (parts.size() > 1) {
+ String command = parts.removeFirst();
+ return new ParsedMessage(command, parts.toArray(String[]::new));
+ }
+ else {
+ return new ParsedMessage(msg);
+ }
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/ClientStore.java b/framework/src/main/java/org/toop/framework/networking/server/stores/ClientStore.java
new file mode 100644
index 0000000..9d13127
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/ClientStore.java
@@ -0,0 +1,7 @@
+package org.toop.framework.networking.server.stores;
+
+import org.toop.framework.game.players.ServerPlayer;
+import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.client.Client;
+
+public interface ClientStore> extends Store {}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/GameStore.java b/framework/src/main/java/org/toop/framework/networking/server/stores/GameStore.java
new file mode 100644
index 0000000..656df1d
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/GameStore.java
@@ -0,0 +1,3 @@
+package org.toop.framework.networking.server.stores;
+
+public interface GameStore extends Store {}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/NettyClientStore.java b/framework/src/main/java/org/toop/framework/networking/server/stores/NettyClientStore.java
new file mode 100644
index 0000000..f2b42cb
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/NettyClientStore.java
@@ -0,0 +1,34 @@
+package org.toop.framework.networking.server.stores;
+
+import org.toop.framework.networking.server.client.NettyClient;
+
+import java.util.Collection;
+import java.util.Map;
+
+public class NettyClientStore implements ClientStore {
+ final private Map users;
+
+ public NettyClientStore(Map usersMap) {
+ this.users = usersMap;
+ }
+
+ @Override
+ public void add(NettyClient adding) {
+ users.putIfAbsent(adding.id(), adding);
+ }
+
+ @Override
+ public void remove(Long remover) {
+ users.remove(remover);
+ }
+
+ @Override
+ public NettyClient get(Long getter) {
+ return users.get(getter);
+ }
+
+ @Override
+ public Collection all() {
+ return users.values();
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/Store.java b/framework/src/main/java/org/toop/framework/networking/server/stores/Store.java
new file mode 100644
index 0000000..cec7311
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/Store.java
@@ -0,0 +1,10 @@
+package org.toop.framework.networking.server.stores;
+
+import java.util.Collection;
+
+public interface Store {
+ void add(STORED adding);
+ void remove(IDENTIFIER remover);
+ STORED get(IDENTIFIER getter);
+ Collection all();
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameStore.java b/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameStore.java
new file mode 100644
index 0000000..d8c47f2
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameStore.java
@@ -0,0 +1,36 @@
+package org.toop.framework.networking.server.stores;
+
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+import org.toop.framework.networking.server.OnlineGame;
+
+import java.util.Collection;
+import java.util.List;
+
+public class TurnBasedGameStore implements GameStore, OnlineGame> {
+
+ private List> gameList;
+
+ public TurnBasedGameStore(List> initGameList) {
+ this.gameList = initGameList;
+ }
+
+ @Override
+ public void add(OnlineGame adding) {
+ gameList.addLast(adding);
+ }
+
+ @Override
+ public void remove(OnlineGame remover) {
+ gameList.remove(remover);
+ }
+
+ @Override
+ public OnlineGame get(OnlineGame getter) {
+ return gameList.stream().filter(game->game.equals(getter)).findFirst().orElse(null);
+ }
+
+ @Override
+ public Collection> all() {
+ return gameList;
+ }
+}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameTypeStore.java b/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameTypeStore.java
new file mode 100644
index 0000000..0a564b9
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/networking/server/stores/TurnBasedGameTypeStore.java
@@ -0,0 +1,32 @@
+package org.toop.framework.networking.server.stores;
+
+import org.toop.framework.gameFramework.model.game.TurnBasedGame;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+public class TurnBasedGameTypeStore {
+
+ private final Map> gameFactories = new ConcurrentHashMap<>();
+
+ public TurnBasedGameTypeStore() {}
+
+ public void register(String key, Supplier extends TurnBasedGame> factory) {
+ gameFactories.put(key, factory);
+ }
+
+ public void unregister(String key) {
+ gameFactories.remove(key);
+ }
+
+ public TurnBasedGame create(String key) {
+ Supplier extends TurnBasedGame> factory = gameFactories.get(key);
+ if (factory == null) throw new IllegalArgumentException("Unknown game type: " + key);
+ return factory.get();
+ }
+
+ public Map> all() {
+ return Map.copyOf(gameFactories);
+ }
+}
\ No newline at end of file
diff --git a/framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java b/framework/src/main/java/org/toop/framework/utils/SimpleTimer.java
similarity index 70%
rename from framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java
rename to framework/src/main/java/org/toop/framework/utils/SimpleTimer.java
index c9c25aa..bf70f5c 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/SimpleTimer.java
+++ b/framework/src/main/java/org/toop/framework/utils/SimpleTimer.java
@@ -1,4 +1,4 @@
-package org.toop.framework.networking.server;
+package org.toop.framework.utils;
public interface SimpleTimer {
void forceExpire();
diff --git a/framework/src/main/java/org/toop/framework/utils/Utils.java b/framework/src/main/java/org/toop/framework/utils/Utils.java
new file mode 100644
index 0000000..0bc4856
--- /dev/null
+++ b/framework/src/main/java/org/toop/framework/utils/Utils.java
@@ -0,0 +1,11 @@
+package org.toop.framework.utils;
+
+import org.apache.maven.surefire.shared.utils.StringUtils;
+
+import java.util.Iterator;
+
+public class Utils {
+ public static String returnQuotedString(Iterator strings) { // TODO more places this could be useful
+ return "\"" + StringUtils.join(strings, "\",\"") + "\"";
+ }
+}
diff --git a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
index 789d732..6529fd3 100644
--- a/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
+++ b/framework/src/test/java/org/toop/framework/networking/server/ServerTest.java
@@ -65,7 +65,7 @@
//
// }
//
-// static class TestUser implements ServerUser {
+// static class TestUser implements Client {
//
// final private long id;
//
@@ -157,9 +157,9 @@
//
// @Test
// void testStartGame() {
-// server.startGame("tictactoe", new User(0, "A"), new User(1, "B"));
+// server.startGame("tictactoe", new NettyClient(0, "A"), new NettyClient(1, "B"));
// Assertions.assertEquals(1, server.ongoingGames().size());
-// server.startGame("reversi", new User(0, "A"), new User(1, "B"));
+// server.startGame("reversi", new NettyClient(0, "A"), new NettyClient(1, "B"));
// Assertions.assertEquals(2, server.ongoingGames().size());
// }
//
From c2f1df7143def5232ef0990147ca9b60fe47337b Mon Sep 17 00:00:00 2001
From: lieght <49651652+BAFGdeJong@users.noreply.github.com>
Date: Sat, 13 Dec 2025 22:44:13 +0100
Subject: [PATCH 22/35] Refactor done, added ability to subscribe
---
.../GenericGameController.java | 2 +-
.../framework/game/players/MiniMaxAI.java | 2 +-
.../framework/gameFramework/GameState.java | 6 +-
.../networking/server/GameServer.java | 24 ++-
.../{Game.java => OnlineTurnBasedGame.java} | 6 +-
.../framework/networking/server/Server.java | 176 +++++++++++-------
.../networking/server/client/Client.java | 4 +-
.../networking/server/client/NettyClient.java | 10 +-
.../connectionHandler/NettyClientSession.java | 10 +-
.../server/handlers/MessageHandler.java | 30 +--
.../networking/server/stores/ClientStore.java | 4 +-
.../networking/server/ServerTest.java | 16 +-
12 files changed, 178 insertions(+), 112 deletions(-)
rename framework/src/main/java/org/toop/framework/networking/server/{Game.java => OnlineTurnBasedGame.java} (89%)
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 37429a0..1b20204 100644
--- a/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
+++ b/app/src/main/java/org/toop/app/gameControllers/GenericGameController.java
@@ -93,7 +93,7 @@ public class GenericGameController implements GameController {
}
private void onGameFinish(GUIEvents.GameEnded event){
- logger.info("Game Finished");
+ logger.info("OnlineTurnBasedGame Finished");
String name = event.winner() == -1 ? null : getPlayer(event.winner()).getName();
gameView.gameOver(event.winOrTie(), name);
stop();
diff --git a/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java b/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
index 972ddea..666d432 100644
--- a/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
+++ b/framework/src/main/java/org/toop/framework/game/players/MiniMaxAI.java
@@ -126,7 +126,7 @@ public class MiniMaxAI extends AbstractAI {
* Simple heuristic evaluation for Reversi-like games.
* Positive = good for AI, Negative = good for opponent.
*
- * @param game Game state
+ * @param game OnlineTurnBasedGame state
* @param aiPlayer AI's player index
* @return heuristic score
*/
diff --git a/framework/src/main/java/org/toop/framework/gameFramework/GameState.java b/framework/src/main/java/org/toop/framework/gameFramework/GameState.java
index bc5a2bf..df802fe 100644
--- a/framework/src/main/java/org/toop/framework/gameFramework/GameState.java
+++ b/framework/src/main/java/org/toop/framework/gameFramework/GameState.java
@@ -4,13 +4,13 @@ package org.toop.framework.gameFramework;
* Represents the current state of a turn-based game.
*/
public enum GameState {
- /** Game is ongoing and no special condition applies. */
+ /** OnlineTurnBasedGame is ongoing and no special condition applies. */
NORMAL,
- /** Game ended in a draw. */
+ /** OnlineTurnBasedGame ended in a draw. */
DRAW,
- /** Game ended with a win for a player. */
+ /** OnlineTurnBasedGame ended with a win for a player. */
WIN,
/** Next player's turn was skipped. */
diff --git a/framework/src/main/java/org/toop/framework/networking/server/GameServer.java b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
index 00993a0..37a4905 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/GameServer.java
@@ -1,8 +1,22 @@
package org.toop.framework.networking.server;
-public interface GameServer {
-// List> gameTypes();
-// List> ongoingGames();
-// void startGame(String gameType, NettyClient... users);
-// String[] onlineUsers();
+import java.util.List;
+
+public interface GameServer {
+ void startGame(String gameType, CLIENT... clients);
+
+ void addClient(CLIENT client);
+ void removeClient(CLIENT client);
+
+ void challengeClient(String fromClientName, String toClientName, String gameTypeKey);
+ void acceptChallenge(CHALLENGEIDTYPE challengeId);
+
+ void subscribeClient(String clientName, String gameTypeKey);
+ void unsubscribeClient(String clientName);
+
+ List gameTypes();
+ List> ongoingGames();
+
+ List onlineUsers();
+ void shutdown();
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Game.java b/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java
similarity index 89%
rename from framework/src/main/java/org/toop/framework/networking/server/Game.java
rename to framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java
index 3ac78b8..3248922 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Game.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/OnlineTurnBasedGame.java
@@ -5,14 +5,14 @@ import org.toop.framework.gameFramework.GameState;
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
import org.toop.framework.networking.server.client.NettyClient;
-public class Game implements OnlineGame {
+public class OnlineTurnBasedGame implements OnlineGame {
private long id;
private NettyClient[] clients;
private TurnBasedGame game;
private ServerThreadBehaviour gameThread;
- public Game(TurnBasedGame game, NettyClient... clients) {
+ public OnlineTurnBasedGame(TurnBasedGame game, NettyClient... clients) {
this.game = game;
this.gameThread = new ServerThreadBehaviour(
game,
@@ -47,7 +47,7 @@ public class Game implements OnlineGame {
}
@Override
- public TurnBasedGame game() {
+ public org.toop.framework.gameFramework.model.game.TurnBasedGame game() {
return game;
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/Server.java b/framework/src/main/java/org/toop/framework/networking/server/Server.java
index cb4f543..6b82050 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/Server.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/Server.java
@@ -10,19 +10,19 @@ import org.toop.framework.networking.server.stores.TurnBasedGameStore;
import org.toop.framework.networking.server.stores.TurnBasedGameTypeStore;
import org.toop.framework.utils.ImmutablePair;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
import java.util.concurrent.*;
import java.time.Duration;
-public class Server implements GameServer {
+public class Server implements GameServer {
final private TurnBasedGameTypeStore gameTypesStore;
final private ClientStore clientStore;
final private List gameChallenges = new CopyOnWriteArrayList<>();
final private TurnBasedGameStore gameStore;
+ final private ConcurrentHashMap> subscriptions; // TODO move to own store / manager
+
final private Duration challengeDuration;
final private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
@@ -37,40 +37,33 @@ public class Server implements GameServer {
this.challengeDuration = challengeDuration;
this.clientStore = clientStore;
this.gameStore = gameStore;
+ this.subscriptions = new ConcurrentHashMap<>();
scheduler.schedule(this::serverTask, 0, TimeUnit.MILLISECONDS);
}
- private void serverTask() {
- checkChallenges();
- scheduler.schedule(this::serverTask, 500, TimeUnit.MILLISECONDS);
- }
-
- public void addUser(NettyClient client) {
+ @Override
+ public void addClient(NettyClient client) {
clientStore.add(client);
}
- public void removeUser(NettyClient client) {
+ @Override
+ public void removeClient(NettyClient client) {
clientStore.remove(client.id());
}
+ @Override
public List gameTypes() {
return new ArrayList<>(gameTypesStore.all().keySet());
}
+ @Override
public List> ongoingGames() {
return gameStore.all().stream().toList();
}
- public NettyClient getUser(String username) {
- return clientStore.all().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
- }
-
- public NettyClient getUser(long id) {
- return clientStore.get(id);
- }
-
- public void challengeUser(String fromUser, String toUser, String gameType) {
+ @Override
+ public void challengeClient(String fromUser, String toUser, String gameType) {
NettyClient from = getUser(fromUser);
if (from == null) {
@@ -104,44 +97,8 @@ public class Server implements GameServer {
gameChallenges.addLast(ch);
}
- private void warnUserExpiredChallenge(NettyClient client, long challengeId) {
- client.send("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}" + "\n");
- }
-
- private boolean isValidChallenge(GameChallenge gameChallenge) {
- for (var user : gameChallenge.getUsers()) {
- if (clientStore.get(user.id()) == null) {
- return false;
- }
-
- if (user.game() != null) {
- return false;
- }
-
- if (gameChallenge.isExpired()) {
- return false;
- }
- }
-
- return true;
- }
-
- public void checkChallenges() {
- for (int i = gameChallenges.size() - 1; i >= 0; i--) {
- var challenge = gameChallenges.get(i);
-
- if (isValidChallenge(challenge)) continue;
-
- if (challenge.isExpired()) {
- if (!challenge.isChallengeAccepted()) Arrays.stream(challenge.getUsers())
- .forEach(user -> warnUserExpiredChallenge(user, challenge.id()));
-
- gameChallenges.remove(i);
- }
- }
- }
-
- public void acceptChallenge(long challengeId) {
+ @Override
+ public void acceptChallenge(Long challengeId) {
for (var challenge : gameChallenges) {
if (challenge.id() == challengeId) {
startGame(challenge.acceptChallenge(), challenge.getUsers());
@@ -150,22 +107,36 @@ public class Server implements GameServer {
}
}
- public List gameChallenges() {
- return gameChallenges;
+ @Override
+ public void subscribeClient(String clientName, String gameTypeKey) {
+
+ if (!gameTypesStore.all().containsKey(gameTypeKey)) return;
+
+ subscriptions.forEach((_, clientNames) -> clientNames.remove(clientName));
+ subscriptions.computeIfAbsent(
+ gameTypeKey,
+ _ -> new ArrayList<>())
+ .add(clientName);
}
+ @Override
+ public void unsubscribeClient(String clientName) {
+ subscriptions.forEach((_, clientNames) -> clientNames.remove(clientName));
+ }
+
+ @Override
public void startGame(String gameType, NettyClient... clients) {
if (!gameTypesStore.all().containsKey(gameType)) return;
try {
ServerPlayer[] players = new ServerPlayer[clients.length];
- var game = new Game(gameTypesStore.create(gameType), clients);
+ var game = new OnlineTurnBasedGame(gameTypesStore.create(gameType), clients);
for (int i = 0; i < clients.length; i++) {
players[i] = new ServerPlayer(clients[i]);
clients[i].addGame(new ImmutablePair<>(game, players[i]));
}
- System.out.println("Starting Game");
+ System.out.println("Starting OnlineTurnBasedGame");
game.game().init(players);
gameStore.add(game);
@@ -182,12 +153,91 @@ public class Server implements GameServer {
} catch (Exception ignored) {}
}
+ @Override
public List onlineUsers() {
return clientStore.all().stream().toList();
}
- public void closeServer() {
+ @Override
+ public void shutdown() {
scheduler.shutdown();
gameChallenges.clear();
}
+
+ private void serverTask() {
+ checkChallenges();
+ checkSubscriptions();
+ scheduler.schedule(this::serverTask, 500, TimeUnit.MILLISECONDS);
+ }
+
+ private void checkChallenges() {
+ for (int i = gameChallenges.size() - 1; i >= 0; i--) {
+ var challenge = gameChallenges.get(i);
+
+ if (isValidChallenge(challenge)) continue;
+
+ if (challenge.isExpired()) {
+ if (!challenge.isChallengeAccepted()) Arrays.stream(challenge.getUsers())
+ .forEach(user -> warnUserExpiredChallenge(user, challenge.id()));
+
+ gameChallenges.remove(i);
+ }
+ }
+ }
+
+ private void checkSubscriptions() {
+ if (subscriptions.isEmpty()) return;
+
+ List keys = subscriptions.keySet().stream().toList();
+
+ for (String key : keys) {
+ var userNames = subscriptions.get(key);
+ if (userNames.size() < 2) continue;
+
+ Random ran = new Random();
+
+ while (userNames.size() > 1) {
+
+ var left = ran.nextInt(userNames.size());
+ var right = ran.nextInt(userNames.size());
+
+ while (left == right) left = ran.nextInt(userNames.size());
+
+ subscriptions.get(key).remove(userNames.get(left));
+ subscriptions.get(key).remove(userNames.get(right));
+
+ startGame(key, getUser(left), getUser(right));
+ }
+ }
+ }
+
+ private NettyClient getUser(String username) {
+ return clientStore.all().stream().filter(e -> e.name().equalsIgnoreCase(username)).findFirst().orElse(null);
+ }
+
+ private NettyClient getUser(long id) {
+ return clientStore.get(id);
+ }
+
+ private void warnUserExpiredChallenge(NettyClient client, long challengeId) {
+ client.send("SVR GAME CHALLENGE CANCELLED {CHALLENGENUMBER: \"" + challengeId + "\"}" + "\n");
+ }
+
+ private boolean isValidChallenge(GameChallenge gameChallenge) { // TODO move to challenge class
+ for (var user : gameChallenge.getUsers()) {
+ if (clientStore.get(user.id()) == null) {
+ return false;
+ }
+
+ if (user.game() != null) {
+ return false;
+ }
+
+ if (gameChallenge.isExpired()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
}
diff --git a/framework/src/main/java/org/toop/framework/networking/server/client/Client.java b/framework/src/main/java/org/toop/framework/networking/server/client/Client.java
index 96ea515..cf97318 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/client/Client.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/client/Client.java
@@ -1,6 +1,6 @@
package org.toop.framework.networking.server.client;
-import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.OnlineTurnBasedGame;
import org.toop.framework.utils.Pair;
public interface Client {
@@ -9,7 +9,7 @@ public interface Client {
String name();
void setName(String name);
- Game game();
+ OnlineTurnBasedGame game();
P player();
void addGame(Pair gamePair);
diff --git a/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java b/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
index 37eeb4b..22b5254 100644
--- a/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
+++ b/framework/src/main/java/org/toop/framework/networking/server/client/NettyClient.java
@@ -2,14 +2,14 @@ package org.toop.framework.networking.server.client;
import io.netty.channel.ChannelHandlerContext;
import org.toop.framework.game.players.ServerPlayer;
-import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.OnlineTurnBasedGame;
import org.toop.framework.utils.Pair;
-public class NettyClient implements Client {
+public class NettyClient implements Client {
final private long id;
private ChannelHandlerContext ctx;
private String name;
- private Pair gamePair;
+ private Pair gamePair;
public NettyClient(long userId, String name) {
this.id = userId;
@@ -27,7 +27,7 @@ public class NettyClient implements Client {
}
@Override
- public void addGame(Pair gamePair) {
+ public void addGame(Pair gamePair) {
if (this.gamePair == null) {
this.gamePair = gamePair;
}
@@ -39,7 +39,7 @@ public class NettyClient implements Client {
}
@Override
- public Game game() {
+ public OnlineTurnBasedGame game() {
if (this.gamePair == null) {
return null;
}
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 ae1f071..d9df676 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
@@ -3,7 +3,7 @@ package org.toop.framework.networking.server.connectionHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.toop.framework.game.players.ServerPlayer;
-import org.toop.framework.networking.server.Game;
+import org.toop.framework.networking.server.OnlineTurnBasedGame;
import org.toop.framework.networking.server.client.NettyClient;
import org.toop.framework.networking.server.handlers.Handler;
import org.toop.framework.networking.server.parsing.ParsedMessage;
@@ -13,7 +13,7 @@ import org.toop.framework.networking.server.parsing.Parser;
import java.util.Arrays;
-public class NettyClientSession extends SimpleChannelInboundHandler implements ClientSession {
+public class NettyClientSession extends SimpleChannelInboundHandler implements ClientSession {
private final NettyClient client;
private final Server server;
@@ -26,7 +26,7 @@ public class NettyClientSession extends SimpleChannelInboundHandler impl
}
@Override
- public Client