mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Game receives commands
This commit is contained in:
@@ -39,7 +39,12 @@ public class Main {
|
|||||||
|
|
||||||
GlobalEventBus.post(new Events.ServerEvents.RunTicTacToeGame(serverId, ticTacToeGameId));
|
GlobalEventBus.post(new Events.ServerEvents.RunTicTacToeGame(serverId, ticTacToeGameId));
|
||||||
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "0"));
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "0"));
|
||||||
GlobalEventBus.post(new Events.ServerEvents.EndTicTacToeGame(serverId, ticTacToeGameId));
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "1"));
|
||||||
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "2"));
|
||||||
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "3"));
|
||||||
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "4"));
|
||||||
|
GlobalEventBus.post(new Events.ServerEvents.Command(connectionId, "MOVE", "5"));
|
||||||
|
// GlobalEventBus.post(new Events.ServerEvents.EndTicTacToeGame(serverId, ticTacToeGameId));
|
||||||
|
|
||||||
// for (int i = 0; i < 1; i++) {
|
// for (int i = 0; i < 1; i++) {
|
||||||
// Thread thread = new Thread(() -> {
|
// Thread thread = new Thread(() -> {
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ public class Events implements IEvents {
|
|||||||
*/
|
*/
|
||||||
public record StartConnectionRequest(String ip, String port, CompletableFuture<String> future) {}
|
public record StartConnectionRequest(String ip, String port, CompletableFuture<String> future) {}
|
||||||
|
|
||||||
|
// public record StartGameConnectionRequest(String ip, String port, CompletableFuture<String> future) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Triggers when a connection to a server is established.
|
* Triggers when a connection to a server is established.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package org.toop.server.backend;
|
|||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.toop.server.backend.tictactoe.ParsedCommand;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
import static java.lang.Thread.sleep;
|
import static java.lang.Thread.sleep;
|
||||||
@@ -14,10 +17,13 @@ public class TcpServer implements Runnable {
|
|||||||
protected static final Logger logger = LogManager.getLogger(TcpServer.class);
|
protected static final Logger logger = LogManager.getLogger(TcpServer.class);
|
||||||
|
|
||||||
private final ExecutorService executor = Executors.newFixedThreadPool(2);
|
private final ExecutorService executor = Executors.newFixedThreadPool(2);
|
||||||
private final BlockingQueue<String> receivedQueue = new LinkedBlockingQueue<>();
|
public final BlockingQueue<String> receivedQueue = new LinkedBlockingQueue<>();
|
||||||
private final BlockingQueue<String> sendQueue = new LinkedBlockingQueue<>();
|
public final BlockingQueue<ParsedCommand> commandQueue = new LinkedBlockingQueue<>();
|
||||||
private final int WAIT_TIME = 500; // MS
|
public final BlockingQueue<String> sendQueue = new LinkedBlockingQueue<>();
|
||||||
private final int RETRY_ATTEMPTS = 3;
|
public final Map<Socket, String> knownPlayers = new HashMap<>();
|
||||||
|
public final Map<String, String> playersGames = new HashMap<>();
|
||||||
|
public final int WAIT_TIME = 500; // MS
|
||||||
|
public final int RETRY_ATTEMPTS = 3;
|
||||||
|
|
||||||
protected int port;
|
protected int port;
|
||||||
protected ServerSocket serverSocket = null;
|
protected ServerSocket serverSocket = null;
|
||||||
@@ -62,17 +68,23 @@ public class TcpServer implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getNewestCommand() {
|
protected ParsedCommand getNewestCommand() {
|
||||||
try { return receivedQueue.poll(this.WAIT_TIME, TimeUnit.MILLISECONDS); }
|
try {
|
||||||
|
String rec = receivedQueue.poll(this.WAIT_TIME, TimeUnit.MILLISECONDS);
|
||||||
|
if (rec != null) {
|
||||||
|
return new ParsedCommand(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
logger.error("Interrupted", e);
|
logger.error("Interrupted", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
//
|
||||||
protected void sendMessage(String message) throws InterruptedException {
|
// protected void sendMessage(String message) throws InterruptedException {
|
||||||
sendQueue.put(message);
|
// sendQueue.put(message);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected void startWorkers(Socket clientSocket) {
|
protected void startWorkers(Socket clientSocket) {
|
||||||
running = true;
|
running = true;
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package org.toop.server.backend.tictactoe;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ParsedCommand {
|
||||||
|
public TicTacToeServerCommand command;
|
||||||
|
public ArrayList<Object> arguments;
|
||||||
|
public boolean isValidCommand;
|
||||||
|
public boolean isServerCommand;
|
||||||
|
public TicTacToeServerMessage returnMessage;
|
||||||
|
public String errorMessage;
|
||||||
|
public String originalCommand;
|
||||||
|
|
||||||
|
public ParsedCommand(String receivedCommand) {
|
||||||
|
|
||||||
|
if (receivedCommand.isEmpty()) {
|
||||||
|
this.command = null;
|
||||||
|
this.arguments = null;
|
||||||
|
this.isValidCommand = false;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.ERR;
|
||||||
|
this.errorMessage = "The received command is empty";
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] segments = receivedCommand.split(" ");
|
||||||
|
if (segments[0].isEmpty()) {
|
||||||
|
this.command = null;
|
||||||
|
this.arguments = null;
|
||||||
|
this.isValidCommand = false;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.ERR;
|
||||||
|
this.errorMessage = "The received command is empty or couldn't be split";
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TicTacToeServerCommand commandEnum = TicTacToeServerCommand.getCommand(segments[0]);
|
||||||
|
|
||||||
|
switch (commandEnum) {
|
||||||
|
case MOVE -> {
|
||||||
|
if (segments.length == 2 && !segments[1].isEmpty()) {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = new ArrayList<>(1);
|
||||||
|
this.arguments.add(segments[1]);
|
||||||
|
this.returnMessage = TicTacToeServerMessage.OK;
|
||||||
|
this.isValidCommand = true;
|
||||||
|
this.isServerCommand = false;
|
||||||
|
this.errorMessage = null;
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MESSAGE -> {
|
||||||
|
if (segments.length == 3 && !segments[2].isEmpty()) {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = new ArrayList<>(2);
|
||||||
|
this.arguments.add(segments[2]);
|
||||||
|
this.returnMessage = TicTacToeServerMessage.OK;
|
||||||
|
this.isValidCommand = true;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = null;
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case CHALLENGE -> {
|
||||||
|
if (!segments[1].isEmpty() && segments[1].equals("accept") &&
|
||||||
|
!segments[2].isEmpty()) {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = new ArrayList<>(2);
|
||||||
|
this.arguments.add(segments[1]);
|
||||||
|
this.arguments.add(segments[2]); // TODO: Needs to be a number.
|
||||||
|
this.returnMessage = TicTacToeServerMessage.OK;
|
||||||
|
this.isValidCommand = true;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = null;
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = null;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.ERR;
|
||||||
|
this.isValidCommand = false;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = "The challenge was not parsable";
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case LOGIN -> { // TODO: Challenge needs to accept different game types later.
|
||||||
|
if (!segments[1].isEmpty()) {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = new ArrayList<>(1);
|
||||||
|
this.arguments.add(segments[1]);
|
||||||
|
this.returnMessage = TicTacToeServerMessage.OK;
|
||||||
|
this.isValidCommand = true;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = null;
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = null;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.ERR;
|
||||||
|
this.isValidCommand = false;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = "The received name is empty or couldn't be understood";
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// case GET -> { // TODO: Get needs to accept different game types later. And get the players
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
case BYE, DISCONNECT, LOGOUT, QUIT, EXIT, FORFEIT, SUBSCRIBE -> {
|
||||||
|
this.command = commandEnum;
|
||||||
|
this.arguments = null;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.OK;
|
||||||
|
this.isValidCommand = true;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = null;
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case null, default -> {
|
||||||
|
this.command = null;
|
||||||
|
this.arguments = null;
|
||||||
|
this.returnMessage = TicTacToeServerMessage.ERR;
|
||||||
|
this.isValidCommand = false;
|
||||||
|
this.isServerCommand = true;
|
||||||
|
this.errorMessage = segments[0] + " is not a supported command";
|
||||||
|
this.originalCommand = receivedCommand;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// public ParsedCommand parseCommand(String command) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import java.io.IOException;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class TicTacToeServer extends TcpServer {
|
public class TicTacToeServer extends TcpServer {
|
||||||
|
|
||||||
@@ -32,17 +33,54 @@ public class TicTacToeServer extends TcpServer {
|
|||||||
logger.info("Connected to client: {}", clientSocket.getInetAddress());
|
logger.info("Connected to client: {}", clientSocket.getInetAddress());
|
||||||
|
|
||||||
new Thread(() -> this.startWorkers(clientSocket)).start();
|
new Thread(() -> this.startWorkers(clientSocket)).start();
|
||||||
|
new Thread(this::gameManagerThread).start();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ParsedCommand getNewestCommand() {
|
||||||
|
try {
|
||||||
|
String rec = receivedQueue.poll(this.WAIT_TIME, TimeUnit.MILLISECONDS);
|
||||||
|
if (rec != null) {
|
||||||
|
return new ParsedCommand(rec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
logger.error("Interrupted", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void gameManagerThread() {
|
||||||
|
while (true) { // TODO: Very heavy on thread
|
||||||
|
try {
|
||||||
|
wait(250);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.error("Interrupted", e);
|
||||||
|
}
|
||||||
|
ParsedCommand command = getNewestCommand();
|
||||||
|
if (command != null && !command.isServerCommand) {
|
||||||
|
TicTacToe testGame = games.values().iterator().next(); // TODO: Is to get first for testing, must be done a different way later.
|
||||||
|
testGame.addCommandToQueue(command);
|
||||||
|
logger.info("Added command to the game queue: {}", command);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public String newGame(String playerA, String playerB) {
|
public String newGame(String playerA, String playerB) {
|
||||||
logger.info("Creating a new game: {} vs {}", playerA, playerB);
|
logger.info("Creating a new game: {} vs {}", playerA, playerB);
|
||||||
String gameId = UUID.randomUUID().toString();
|
String gameId = UUID.randomUUID().toString();
|
||||||
TicTacToe game = new TicTacToe(playerA, playerB);
|
TicTacToe game = new TicTacToe(playerA, playerB);
|
||||||
this.games.put(gameId, game);
|
this.games.put(gameId, game);
|
||||||
|
// this.knownPlayers.put(sockA, playerA); // TODO: For remembering players and validation.
|
||||||
|
// this.knownPlayers.put(sockB, playerB);
|
||||||
|
// this.playersGames.put(playerA, gameId);
|
||||||
|
// this.playersGames.put(playerB, gameId);
|
||||||
logger.info("Created a new game: {}. {} vs {}", gameId, playerA, playerB);
|
logger.info("Created a new game: {}. {} vs {}", gameId, playerA, playerB);
|
||||||
return gameId;
|
return gameId;
|
||||||
}
|
}
|
||||||
@@ -56,93 +94,12 @@ public class TicTacToeServer extends TcpServer {
|
|||||||
public void endGame(String gameId) {
|
public void endGame(String gameId) {
|
||||||
TicTacToe game = this.games.get(gameId);
|
TicTacToe game = this.games.get(gameId);
|
||||||
this.games.remove(gameId);
|
this.games.remove(gameId);
|
||||||
|
// this.knownPlayers.put(sockA, playerA); // TODO: Remove players when game is done.
|
||||||
|
// this.knownPlayers.put(sockB, playerB);
|
||||||
|
// this.playersGames.put(playerA, gameId);
|
||||||
|
// this.playersGames.put(playerB, gameId);
|
||||||
logger.info("Ended game: {}", gameId);
|
logger.info("Ended game: {}", gameId);
|
||||||
// TODO: Multithreading, close game in a graceful matter, etc.
|
// TODO: Multithreading, close game in a graceful matter, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ParsedCommand {
|
|
||||||
public TicTacToeServerCommand command;
|
|
||||||
public ArrayList<Object> arguments;
|
|
||||||
public boolean isValidCommand;
|
|
||||||
public TicTacToeServerMessage returnMessage;
|
|
||||||
public String errorMessage;
|
|
||||||
public String originalCommand;
|
|
||||||
|
|
||||||
ParsedCommand(String receivedCommand) {
|
|
||||||
|
|
||||||
if (receivedCommand.isEmpty()) {
|
|
||||||
this.command = null;
|
|
||||||
this.arguments = null;
|
|
||||||
this.isValidCommand = false;
|
|
||||||
this.returnMessage = TicTacToeServerMessage.ERR;
|
|
||||||
this.errorMessage = "The received command is empty";
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] segments = receivedCommand.split(" ");
|
|
||||||
if (segments[0].isEmpty()) {
|
|
||||||
this.command = null;
|
|
||||||
this.arguments = null;
|
|
||||||
this.isValidCommand = false;
|
|
||||||
this.returnMessage = TicTacToeServerMessage.ERR;
|
|
||||||
this.errorMessage = "The received command is empty or couldn't be split";
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
TicTacToeServerCommand commandEnum = TicTacToeServerCommand.getCommand(segments[0]);
|
|
||||||
switch (commandEnum) {
|
|
||||||
case MOVE -> {
|
|
||||||
if (segments.length == 2 && !segments[1].isEmpty()) {
|
|
||||||
this.command = commandEnum;
|
|
||||||
this.arguments = new ArrayList<Object>(1);
|
|
||||||
this.arguments.add(segments[1]);
|
|
||||||
this.returnMessage = TicTacToeServerMessage.OK;
|
|
||||||
this.isValidCommand = true;
|
|
||||||
this.errorMessage = null;
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case FORFEIT -> {
|
|
||||||
this.command = commandEnum;
|
|
||||||
this.arguments = null;
|
|
||||||
this.returnMessage = TicTacToeServerMessage.OK;
|
|
||||||
this.isValidCommand = true;
|
|
||||||
this.errorMessage = null;
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case MESSAGE -> {
|
|
||||||
if (segments.length == 3 && !segments[2].isEmpty()) {
|
|
||||||
this.command = commandEnum;
|
|
||||||
this.arguments = new ArrayList<Object>(2);
|
|
||||||
this.arguments.add(segments[2]);
|
|
||||||
this.returnMessage = TicTacToeServerMessage.OK;
|
|
||||||
this.isValidCommand = true;
|
|
||||||
this.errorMessage = null;
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case BYE, DISCONNECT, LOGOUT, QUIT, EXIT -> {
|
|
||||||
this.command = commandEnum;
|
|
||||||
this.arguments = null;
|
|
||||||
this.returnMessage = TicTacToeServerMessage.OK;
|
|
||||||
this.isValidCommand = true;
|
|
||||||
this.errorMessage = null;
|
|
||||||
this.originalCommand = receivedCommand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.command = command;
|
|
||||||
this.arguments = arguments;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ParsedCommand parseCommand(String command) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,19 @@ package org.toop.server.backend.tictactoe.game;
|
|||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.toop.Main;
|
import org.toop.server.backend.tictactoe.ParsedCommand;
|
||||||
|
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
|
||||||
public class TicTacToe extends GameBase implements Runnable {
|
public class TicTacToe extends GameBase implements Runnable {
|
||||||
private static final Logger logger = LogManager.getLogger(TicTacToe.class);
|
private static final Logger logger = LogManager.getLogger(TicTacToe.class);
|
||||||
|
|
||||||
public int moveCount;
|
public int moveCount;
|
||||||
public Thread gameThread;
|
public Thread gameThread;
|
||||||
|
public BlockingQueue<ParsedCommand> commandQueue = new LinkedBlockingQueue<>();
|
||||||
|
public BlockingQueue<String> sendQueue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
public TicTacToe(String player1, String player2) {
|
public TicTacToe(String player1, String player2) {
|
||||||
super(3); // 3x3 Grid
|
super(3); // 3x3 Grid
|
||||||
@@ -19,6 +25,10 @@ public class TicTacToe extends GameBase implements Runnable {
|
|||||||
moveCount = 0;
|
moveCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addCommandToQueue(ParsedCommand command) {
|
||||||
|
commandQueue.add(command);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
this.gameThread = new Thread(this::gameThread);
|
this.gameThread = new Thread(this::gameThread);
|
||||||
@@ -31,6 +41,10 @@ public class TicTacToe extends GameBase implements Runnable {
|
|||||||
// command = this.parseCommand(command).toString();
|
// command = this.parseCommand(command).toString();
|
||||||
// if (command == null) { continue; }
|
// if (command == null) { continue; }
|
||||||
|
|
||||||
|
if (commandQueue.poll() != null) {
|
||||||
|
logger.info(commandQueue.poll());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Game
|
// TODO: Game
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user