mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Compare commits
11 Commits
4d31a8ed44
...
afcd9be71e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afcd9be71e | ||
| a9145d44cf | |||
| c015100ebf | |||
|
|
cd5736afc8 | ||
|
|
89a9cb1e55 | ||
|
|
22270e58dc | ||
|
|
edd2c24b65 | ||
| c929abc4b8 | |||
|
|
8b85915c74 | ||
|
|
150fb2986f | ||
|
|
9c20fcbc39 |
@@ -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<String, Class<? extends TurnBasedGame>>();
|
||||
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();
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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<String, Class<? extends TurnBasedGame>>();
|
||||
games.put("tic-tac-toe", 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
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
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 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<ImmutablePair<String, Integer>> onPlayerMove;
|
||||
/**
|
||||
* Creates a new base behaviour for the specified game.
|
||||
*
|
||||
* @param game the turn-based game to control
|
||||
*/
|
||||
public ServerThreadBehaviour(TurnBasedGame game, Consumer<ImmutablePair<String, Integer>> onPlayerMove) {
|
||||
super(game);
|
||||
}
|
||||
|
||||
private void notifyPlayerMove(ImmutablePair<String, Integer> pair) {
|
||||
onPlayerMove.accept(pair);
|
||||
}
|
||||
|
||||
/** 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();
|
||||
|
||||
if (state != TURN_SKIPPED){
|
||||
notifyPlayerMove(new ImmutablePair<>(currentPlayer.getName(), Long.numberOfTrailingZeros(move)));
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case WIN, DRAW -> {
|
||||
isRunning.set(false);
|
||||
}
|
||||
case NORMAL, TURN_SKIPPED -> { /* continue normally */ }
|
||||
default -> {
|
||||
logger.error("Unexpected state {}", state);
|
||||
isRunning.set(false);
|
||||
throw new RuntimeException("Unknown state: " + state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<Long> 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: \"<bericht voor deze beurt>\"}\n");
|
||||
try {
|
||||
return lastMove.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -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. */
|
||||
|
||||
@@ -2,21 +2,27 @@ 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 ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
public class ConnectionHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private String returnQuotedString(Iterator<String> 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<String> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
|
||||
|
||||
IO.println(msg);
|
||||
|
||||
ParsedMessage p = parse(msg);
|
||||
if (p == null) return;
|
||||
|
||||
@@ -45,24 +54,29 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean allowedArgs(String... args) {
|
||||
if (args.length < 1) return false;
|
||||
return true;
|
||||
// DO NOT INVERT
|
||||
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" -> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +93,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
}
|
||||
|
||||
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")) {
|
||||
@@ -87,14 +101,14 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
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;
|
||||
@@ -104,7 +118,10 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
}
|
||||
|
||||
private void handleMove(ParsedMessage p) {
|
||||
// TODO
|
||||
if(!hasArgs(p.args())) return;
|
||||
|
||||
// TODO check if not number
|
||||
user.serverPlayer().setMove(1L << Integer.parseInt(p.args()[0]));
|
||||
}
|
||||
|
||||
private ParsedMessage parse(String msg) {
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.toop.framework.networking.server;
|
||||
|
||||
import org.toop.framework.game.gameThreads.ServerThreadBehaviour;
|
||||
import org.toop.framework.gameFramework.model.game.TurnBasedGame;
|
||||
|
||||
public class Game implements OnlineGame<TurnBasedGame> {
|
||||
@@ -7,12 +8,19 @@ public class Game implements OnlineGame<TurnBasedGame> {
|
||||
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, (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: \"<reactie spel op zet>\", MOVE: \"%s\"}", speler, move));
|
||||
users[1].sendMessage(String.format("SVR GAME MOVE {PLAYER: \"%s\", DETAILS: \"<reactie spel op zet>\", MOVE: \"%s\"}", speler, move));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long id() {
|
||||
return id;
|
||||
@@ -27,4 +35,9 @@ public class Game implements OnlineGame<TurnBasedGame> {
|
||||
public User[] users() {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(){
|
||||
this.gameThread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -4,4 +4,5 @@ public interface OnlineGame<T> {
|
||||
long id();
|
||||
T game();
|
||||
User[] users();
|
||||
void start();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.toop.framework.networking.server;
|
||||
|
||||
import org.toop.framework.game.players.LocalPlayer;
|
||||
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;
|
||||
@@ -13,7 +13,7 @@ import java.time.Duration;
|
||||
public class Server implements GameServer {
|
||||
|
||||
final private Map<String, Class<? extends TurnBasedGame>> gameTypes;
|
||||
final private Map<Long, ServerUser> users = new ConcurrentHashMap<>();
|
||||
final private Map<Long, User> users = new ConcurrentHashMap<>();
|
||||
final private List<GameChallenge> gameChallenges = new CopyOnWriteArrayList<>();
|
||||
final private List<OnlineGame<TurnBasedGame>> 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<String> gameTypes() {
|
||||
return gameTypes.keySet().stream().toList();
|
||||
}
|
||||
|
||||
public List<OnlineGame<TurnBasedGame>> 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) {
|
||||
@@ -100,7 +100,7 @@ public class Server implements GameServer {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user.games().length > 0) {
|
||||
if (user.game() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -142,28 +144,32 @@ 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());
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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) {}
|
||||
}
|
||||
|
||||
// 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);
|
||||
public List<User> onlineUsers() {
|
||||
return users.values().stream().toList();
|
||||
}
|
||||
|
||||
public void closeServer() {
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
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[] games();
|
||||
void addGame(Game game);
|
||||
void removeGame(Game game);
|
||||
Game game();
|
||||
ServerPlayer serverPlayer();
|
||||
void addGame(Pair<Game, ServerPlayer> gamePair);
|
||||
void removeGame();
|
||||
void setName(String name);
|
||||
void sendMessage(String message);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package org.toop.framework.networking.server;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.toop.framework.game.players.ServerPlayer;
|
||||
import org.toop.framework.utils.Pair;
|
||||
|
||||
public class User implements ServerUser {
|
||||
final private long id;
|
||||
private String name;
|
||||
private final List<Game> games = new ArrayList<>();
|
||||
private Pair<Game, ServerPlayer> gamePair;
|
||||
private ChannelHandlerContext connectionContext;
|
||||
|
||||
public User(long userId, String name) {
|
||||
@@ -26,21 +25,25 @@ public class User implements ServerUser {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void addGame(Game game) {
|
||||
games.add(game);
|
||||
public void addGame(Pair<Game, ServerPlayer> gamePair) {
|
||||
if (this.gamePair == null) {
|
||||
this.gamePair = gamePair;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGame(Game game) {
|
||||
games.remove(game);
|
||||
public void removeGame() {
|
||||
this.gamePair = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Game[] games() {
|
||||
return games.toArray(new Game[0]);
|
||||
public Game game() {
|
||||
return this.gamePair.getLeft();
|
||||
}
|
||||
|
||||
public ServerPlayer serverPlayer() {
|
||||
return this.gamePair.getRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.toop.framework.utils;
|
||||
|
||||
public class ImmutablePair<T, K> implements Pair<T,K> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.toop.framework.utils;
|
||||
|
||||
public class MutablePair<T, K> implements Pair<T,K> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.toop.framework.utils;
|
||||
|
||||
public interface Pair<T, K> {
|
||||
T getLeft();
|
||||
K getRight();
|
||||
}
|
||||
@@ -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<String, Class<? extends TurnBasedGame>>();
|
||||
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<String, Class<? extends TurnBasedGame>>();
|
||||
// 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());
|
||||
// }
|
||||
//
|
||||
//
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user