Starting rework of client request protocol to allow multiplayer

This commit is contained in:
2021-03-20 23:31:33 +01:00
parent 1b4bcd1ec2
commit 9195dbad22
4 changed files with 138 additions and 117 deletions

View File

@@ -9,27 +9,28 @@ public class TicTacToe_Client {
private Engine renderEngine; private Engine renderEngine;
private Client client; private Client client;
private boolean isSingleServer;
private static String clientName; private static String clientName;
private boolean isPlayerOne;
public TicTacToe_Client(){ public TicTacToe_Client() {
renderEngine = Engine.waitForEngine(); renderEngine = Engine.waitForEngine();
}
private void ticTacToe_gameloop(){
//Setup
client = new Client("server", 2589, clientName); client = new Client("server", 2589, clientName);
client.handshake(); client.handshake();
isSingleServer = client.getServerType(); isPlayerOne = client.isPlayerOne();
if (isSingleServer){ this.setWindowTitle(isPlayerOne);
this.setWindowTitle(client.isPlayerOne());
client.sendToServer("ready"); client.sendToServer("ready");
}
private void ticTacToe_gameloop() {
this.drawBoard(client.getGameState());
if (isPlayerOne){
this.userInput();
}
while (client.isConnected() && !renderEngine.isWindowClosed()) { while (client.isConnected() && !renderEngine.isWindowClosed()) {
String message = client.getResponse(); String message = client.getResponse();
//Check if message is gamestate //Check if message is gamestate
if (message.charAt(0) == 'x' || message.charAt(0) == '-' || message.charAt(0) == 'o') { if (message.charAt(0) == 'x' || message.charAt(0) == '-' || message.charAt(0) == 'o') {
this.drawBoard(message); this.drawBoard(message);
this.gameFlow("userInput");
} }
//Handle everything else //Handle everything else
else { else {
@@ -38,18 +39,15 @@ public class TicTacToe_Client {
} }
try { try {
client.exitProcess(); client.exitProcess();
} catch (Exception e){ } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} else {
this.setWindowTitle(client.isPlayerOne());
}
} }
private void gameFlow(String input){ private void gameFlow(String input) {
switch (input) { switch (input) {
case "userInput": case "userInput":
while(!renderEngine.isMouseClicked()){ while (!renderEngine.isMouseClicked()) {
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
@@ -59,26 +57,20 @@ public class TicTacToe_Client {
renderEngine.setMouseClicked(false); renderEngine.setMouseClicked(false);
this.userInput(); this.userInput();
break; break;
case "invalidInput":
this.onInvalidInput();
break;
case ""
} }
} }
private void requestOpponentMove(){
client.sendToServer("opponentMove");
}
private void onGameEnd(){
private void userInput(){
//Send command
client.sendToServer("clientMove");
//Send position
client.sendToServer(String.format("%f|%f", renderEngine.getCoordinates().getX(), renderEngine.getCoordinates().getY()));
//Get gameState
String gameState = client.getResponse();
if (gameState.length() == 9) {
this.drawBoard(gameState);
//Send command
if (!client.getGameEnded()) {
client.sendToServer("computerMove");
this.drawBoard(client.getResponse());
} else {
LinkedList<Integer> winCoordinates = new LinkedList<>(); LinkedList<Integer> winCoordinates = new LinkedList<>();
//Get winning fields //Get winning fields
String response = client.getResponse(); String response = client.getResponse();
@@ -94,6 +86,27 @@ public class TicTacToe_Client {
} }
client.resetBoard(); client.resetBoard();
} }
private void onInvalidInput(){
int column = (int) renderEngine.getCoordinates().getX() / 300;
int row = (int) renderEngine.getCoordinates().getY() / 300;
System.err.printf("You are not allowed to place at %d|%d%n", column, row);
this.userInput();
}
private void userInput() {
client.sendToServer("clientMove");
client.sendToServer(String.format("%f|%f", renderEngine.getCoordinates().getX(), renderEngine.getCoordinates().getY()));
//Get gameState
String gameState = client.getResponse();
if (gameState.length() == 9) {
this.drawBoard(gameState);
//Send command
if (!client.getGameEnded()) {
this.requestOpponentMove();
} else {
this.onGameEnd();
}
} else { } else {
int column = (int) renderEngine.getCoordinates().getX() / 300; int column = (int) renderEngine.getCoordinates().getX() / 300;
int row = (int) renderEngine.getCoordinates().getY() / 300; int row = (int) renderEngine.getCoordinates().getY() / 300;
@@ -110,8 +123,8 @@ public class TicTacToe_Client {
}); });
} }
private void setWindowTitle(boolean isClientOne){ private void setWindowTitle(boolean isClientOne) {
if (isClientOne){ if (isClientOne) {
Platform.runLater(new Runnable() { Platform.runLater(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -129,16 +142,16 @@ public class TicTacToe_Client {
} }
public static void main(String[] args) { public static void main(String[] args) {
new Thread(){ new Thread() {
@Override @Override
public void run(){ public void run() {
javafx.application.Application.launch(Engine.class); javafx.application.Application.launch(Engine.class);
} }
}.start(); }.start();
TicTacToe_Client test = new TicTacToe_Client(); TicTacToe_Client test = new TicTacToe_Client();
try{ try {
clientName = args[0]; clientName = args[0];
} catch (Exception e){ } catch (Exception e) {
clientName = "testing"; clientName = "testing";
} }
test.ticTacToe_gameloop(); test.ticTacToe_gameloop();

View File

@@ -92,6 +92,16 @@ public class Client {
return isClientOne; return isClientOne;
} }
public String getGameState(){
try {
out.writeUTF("gameState");
return this.getResponse();
} catch (IOException e) {
e.printStackTrace();
}
return "---------";
}
public boolean getServerType(){ public boolean getServerType(){
this.sendToServer("serverType"); this.sendToServer("serverType");
boolean serverType = this.getBooleanResponse("isSingleServer"); boolean serverType = this.getBooleanResponse("isSingleServer");

View File

@@ -11,13 +11,12 @@ import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class TicTacToe_Server { public class TicTacToe_Server {
private ServerSocket serverSocket; private ServerSocket serverSocket;
private HashMap<Integer, Socket> clients; private HashMap<Integer, Socket> clients;
private HashMap<Socket, Integer> clientIds;
private HashMap<Socket, String> clientNames; private HashMap<Socket, String> clientNames;
private HashMap<Socket, Boolean> clientMoveAuthorizations; private HashMap<Socket, Boolean> clientMoveAuthorizations;
private HashMap<Socket, DataOutputStream> outstreams; private HashMap<Socket, DataOutputStream> outstreams;
@@ -25,6 +24,7 @@ public class TicTacToe_Server {
private TicTacToe_GameRules ticTacToe_gameRules; private TicTacToe_GameRules ticTacToe_gameRules;
private ServerLogger serverLogger; private ServerLogger serverLogger;
private int requiredConnections; private int requiredConnections;
private boolean[] clientsReady;
public TicTacToe_Server(int port, int requiredConnections) { public TicTacToe_Server(int port, int requiredConnections) {
@@ -32,12 +32,14 @@ public class TicTacToe_Server {
serverSocket = new ServerSocket(port); serverSocket = new ServerSocket(port);
clients = new HashMap<>(); clients = new HashMap<>();
clientNames = new HashMap<>(); clientNames = new HashMap<>();
clientIds = new HashMap<>();
clientMoveAuthorizations = new HashMap<>(); clientMoveAuthorizations = new HashMap<>();
outstreams = new HashMap<>(); outstreams = new HashMap<>();
instreams = new HashMap<>(); instreams = new HashMap<>();
ticTacToe_gameRules = new TicTacToe_GameRules(); ticTacToe_gameRules = new TicTacToe_GameRules();
serverLogger = new ServerLogger(); serverLogger = new ServerLogger();
this.requiredConnections = requiredConnections; this.requiredConnections = requiredConnections;
clientsReady = new boolean[requiredConnections];
serverLogger.printLog("Server started successfully", LogType.Log); serverLogger.printLog("Server started successfully", LogType.Log);
} catch (IOException e) { } catch (IOException e) {
@@ -46,6 +48,7 @@ public class TicTacToe_Server {
} }
private boolean isSingleServer() { private boolean isSingleServer() {
serverLogger.printLog(""+ requiredConnections + (requiredConnections == 1), LogType.Error);
return requiredConnections == 1; return requiredConnections == 1;
} }
@@ -56,6 +59,7 @@ public class TicTacToe_Server {
while (clients.size() < requiredConnections) { while (clients.size() < requiredConnections) {
Socket momentaryClient = serverSocket.accept(); Socket momentaryClient = serverSocket.accept();
clients.put(id, momentaryClient); clients.put(id, momentaryClient);
clientIds.put(clients.get(id), id);
outstreams.put(momentaryClient, new DataOutputStream(momentaryClient.getOutputStream())); outstreams.put(momentaryClient, new DataOutputStream(momentaryClient.getOutputStream()));
instreams.put(momentaryClient, new DataInputStream(momentaryClient.getInputStream())); instreams.put(momentaryClient, new DataInputStream(momentaryClient.getInputStream()));
id++; id++;
@@ -102,7 +106,7 @@ public class TicTacToe_Server {
} }
} }
public String handleInput(Socket client){ public String handleInput(Socket client) {
String message = null; String message = null;
try { try {
message = instreams.get(client).readUTF(); message = instreams.get(client).readUTF();
@@ -117,31 +121,22 @@ public class TicTacToe_Server {
} }
public void ticTacToe_gameloop() { public void ticTacToe_gameloop() {
if (isSingleServer()) { while (clients.size() == requiredConnections) {
Socket client = clients.get(0); for (Socket client : clients.values()) {
//SingleServer GameLoop gameFlow(handleInput(client), client);
while (!client.isClosed()) {
//Get instruction
this.gameFlow(handleInput(client), client);
}
} else {
//MultiServer GameLoop
gameFlow("gameState");
} }
} }
public void gameFlow(String input){
this.gameFlow(input, null);
} }
public void gameFlow(String input, Socket client) { public void gameFlow(String input, Socket client) {
switch (input) { switch (input) {
case "ready": case "ready":
if (isSingleServer()){ if (isSingleServer()) {
sendGameState(); sendGameState();
} else { } else {
sendGameState(client); sendGameState(client);
} }
clientsReady[clientIds.get(client)] = true;
break; break;
case "gameState": case "gameState":
@@ -152,14 +147,12 @@ public class TicTacToe_Server {
try { try {
//Get position (X|Y) //Get position (X|Y)
String position = handleInput(client); String position = handleInput(client);
boolean moveAllowed = ticTacToe_gameRules.makeClientMove(position); boolean moveAllowed = ticTacToe_gameRules.makeClientMove(position, clientIds.get(client));
if (moveAllowed) { if (moveAllowed) {
sendGameState(); sendGameState();
} else { } else {
//send " " outstreams.get(client).writeUTF("invalidInput");
outstreams.get(client).writeUTF("userInput");
outstreams.get(client).flush(); outstreams.get(client).flush();
serverLogger.printLog("Requested userInput", LogType.Log);
serverLogger.printLog(String.format("Move is not allowed!"), clientNames.get(client), LogType.Error); serverLogger.printLog(String.format("Move is not allowed!"), clientNames.get(client), LogType.Error);
} }
} catch (IOException e) { } catch (IOException e) {
@@ -167,9 +160,22 @@ public class TicTacToe_Server {
} }
break; break;
case "computerMove": case "opponentMove":
if (isSingleServer()) {
ticTacToe_gameRules.makeComputerMove(); ticTacToe_gameRules.makeComputerMove();
serverLogger.printLog("Made computer move", LogType.Log);
} else {
//request move from other player
try {
outstreams.get(1-clientIds.get(client)).writeUTF("userInput");
outstreams.get(client).flush();
serverLogger.printLog("Requested opponent userInput", clientNames.get(1-clientIds.get(client)), LogType.Log);
} catch (IOException e) {
e.printStackTrace();
}
}
sendGameState(); sendGameState();
if (isSingleServer()) {
try { try {
outstreams.get(client).writeUTF("userInput"); outstreams.get(client).writeUTF("userInput");
outstreams.get(client).flush(); outstreams.get(client).flush();
@@ -177,11 +183,12 @@ public class TicTacToe_Server {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
}
break; break;
case "serverType": case "serverType":
try { try {
outstreams.get(client).writeBoolean(true); outstreams.get(client).writeBoolean(isSingleServer());
outstreams.get(client).flush(); outstreams.get(client).flush();
serverLogger.printLog("Sent serverType", Boolean.toString(true), clientNames.get(client), LogType.Log); serverLogger.printLog("Sent serverType", Boolean.toString(true), clientNames.get(client), LogType.Log);
} catch (IOException e) { } catch (IOException e) {
@@ -190,20 +197,12 @@ public class TicTacToe_Server {
break; break;
case "isClientOne": case "isClientOne":
for (Map.Entry<Integer, Socket> entry : clients.entrySet()) { boolean isClientOne = clientIds.get(client) == 0;
if (Objects.equals(client, entry.getValue())) {
try { try {
boolean isClientOne = entry.getKey() == 0;
outstreams.get(client).writeBoolean(isClientOne); outstreams.get(client).writeBoolean(isClientOne);
outstreams.get(client).flush();
serverLogger.printLog("Sent isPlayerOne", Boolean.toString(isClientOne), clientNames.get(client), LogType.Log);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else {
serverLogger.printLog("Current client not in clients!", LogType.Error);
}
}
break; break;
case "gameEnded": case "gameEnded":

View File

@@ -12,7 +12,7 @@ public class TicTacToe_GameRules {
Point startWin, endWin; Point startWin, endWin;
public TicTacToe_GameRules(){ public TicTacToe_GameRules(){
gameState = "---------"; gameState = "o--x-o--x";
} }
public void resetGameState() { public void resetGameState() {
@@ -34,13 +34,13 @@ public class TicTacToe_GameRules {
board = this.convertToNumbers(gameState); board = this.convertToNumbers(gameState);
} }
public boolean makeClientMove(String input) { public boolean makeClientMove(String input, int id) {
int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300; int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300;
int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300; int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300;
int index = column * 3 + row; int index = column * 3 + row;
if (isLegalMove(column, row)) { if (isLegalMove(column, row)) {
makeMoveOnBoard(index, 0); makeMoveOnBoard(index, id);
return true; return true;
} else { } else {
return false; return false;
@@ -144,7 +144,6 @@ public class TicTacToe_GameRules {
return horizontalWin() || verticalWin() || diagonalWin(); return horizontalWin() || verticalWin() || diagonalWin();
} }
public Point[] getWinCoordinates(){ public Point[] getWinCoordinates(){
return new Point[]{startWin, endWin}; return new Point[]{startWin, endWin};
} }