Merge pull request #3 from cato447/multiplayer_tictactoe
Basics of client server communication and drawing of gamestates finished
This commit is contained in:
22
.idea/artifacts/Client.xml
generated
Normal file
22
.idea/artifacts/Client.xml
generated
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<component name="ArtifactManager">
|
||||||
|
<artifact type="javafx" name="Client">
|
||||||
|
<output-path>$PROJECT_DIR$/out/artifacts/Client</output-path>
|
||||||
|
<properties id="javafx-properties">
|
||||||
|
<options>
|
||||||
|
<option name="appClass" value="game.TicTacToe_Client" />
|
||||||
|
<option name="description" value="" />
|
||||||
|
<option name="height" value="" />
|
||||||
|
<option name="htmlPlaceholderId" value="" />
|
||||||
|
<option name="title" value="" />
|
||||||
|
<option name="vendor" value="" />
|
||||||
|
<option name="version" value="" />
|
||||||
|
<option name="width" value="" />
|
||||||
|
</options>
|
||||||
|
</properties>
|
||||||
|
<root id="root">
|
||||||
|
<element id="archive" name="Client.jar">
|
||||||
|
<element id="module-output" name="Client" />
|
||||||
|
</element>
|
||||||
|
</root>
|
||||||
|
</artifact>
|
||||||
|
</component>
|
||||||
8
.idea/artifacts/Client_jar.xml
generated
8
.idea/artifacts/Client_jar.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<component name="ArtifactManager">
|
|
||||||
<artifact type="jar" name="Client:jar">
|
|
||||||
<output-path>$PROJECT_DIR$/out/artifacts/Client_jar</output-path>
|
|
||||||
<root id="archive" name="Client.jar">
|
|
||||||
<element id="module-output" name="Client" />
|
|
||||||
</root>
|
|
||||||
</artifact>
|
|
||||||
</component>
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Main-Class: networking.Client
|
Main-Class: game.TicTacToe_Client
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package games.TicTacToe;
|
package game;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
@@ -26,8 +26,6 @@ public class TicTacToe_Client extends Application {
|
|||||||
grid.setGridLinesVisible(true);
|
grid.setGridLinesVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void drawCross(int column, int row){
|
private void drawCross(int column, int row){
|
||||||
Text cross = new Text("X");
|
Text cross = new Text("X");
|
||||||
cross.setFont(Font.font("Tahoma", FontWeight.NORMAL, 200));
|
cross.setFont(Font.font("Tahoma", FontWeight.NORMAL, 200));
|
||||||
@@ -40,7 +38,6 @@ public class TicTacToe_Client extends Application {
|
|||||||
grid.add(circle, column, row);
|
grid.add(circle, column, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void drawEmptyField(int column, int row) {
|
private void drawEmptyField(int column, int row) {
|
||||||
Text emptyField = new Text(" ");
|
Text emptyField = new Text(" ");
|
||||||
emptyField.setFont(Font.font("Tahoma", FontWeight.NORMAL, 200));
|
emptyField.setFont(Font.font("Tahoma", FontWeight.NORMAL, 200));
|
||||||
@@ -53,8 +50,8 @@ public class TicTacToe_Client extends Application {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < gameState.length(); i++){
|
for (int i = 0; i < gameState.length(); i++){
|
||||||
int column = i % 3;
|
int column = i / 3;
|
||||||
int row = i / 3;
|
int row = i % 3;
|
||||||
if (gameState.charAt(i) == 'x'){
|
if (gameState.charAt(i) == 'x'){
|
||||||
this.drawCross(column, row);
|
this.drawCross(column, row);
|
||||||
} else if (gameState.charAt(i) == 'o'){
|
} else if (gameState.charAt(i) == 'o'){
|
||||||
@@ -73,8 +70,16 @@ public class TicTacToe_Client extends Application {
|
|||||||
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||||
@Override
|
@Override
|
||||||
public void handle(MouseEvent event) {
|
public void handle(MouseEvent event) {
|
||||||
client.sendToServer(String.format("(%f|%f)", event.getX(), event.getY()));
|
client.sendToServer("update");
|
||||||
client.getGameState();
|
client.sendToServer(String.format("%f|%f", event.getX(), event.getY()));
|
||||||
|
String gameState = client.getResponse();
|
||||||
|
if (gameState.length() == 9) {
|
||||||
|
drawBoard(gameState);
|
||||||
|
} else {
|
||||||
|
int column = (int) event.getX() / 300;
|
||||||
|
int row = (int) event.getY() / 300;
|
||||||
|
System.err.printf("You are not allowed to place at %f|%f%n", column, row);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return scene;
|
return scene;
|
||||||
@@ -82,6 +87,9 @@ public class TicTacToe_Client extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) {
|
public void start(Stage primaryStage) {
|
||||||
|
client = new Client("localhost", 2589, "TestClient");
|
||||||
|
client.handshake();
|
||||||
|
|
||||||
primaryStage.setTitle("TicTacToe");
|
primaryStage.setTitle("TicTacToe");
|
||||||
primaryStage.setResizable(false);
|
primaryStage.setResizable(false);
|
||||||
|
|
||||||
@@ -91,10 +99,7 @@ public class TicTacToe_Client extends Application {
|
|||||||
|
|
||||||
primaryStage.show();
|
primaryStage.show();
|
||||||
|
|
||||||
this.drawBoard("---------");
|
this.drawBoard(client.getGameState());
|
||||||
|
|
||||||
client = new Client("localhost", 2589, "TestClient");
|
|
||||||
client.handshake();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
@@ -2,6 +2,8 @@ package networking;
|
|||||||
|
|
||||||
import logging.ClientLogger;
|
import logging.ClientLogger;
|
||||||
import logging.LogType;
|
import logging.LogType;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -37,8 +39,9 @@ public class Client {
|
|||||||
out.writeInt(165313125);
|
out.writeInt(165313125);
|
||||||
out.flush();
|
out.flush();
|
||||||
success = in.readInt() == 200;
|
success = in.readInt() == 200;
|
||||||
if (success){
|
if (success) {
|
||||||
out.writeUTF(name);
|
out.writeUTF(name);
|
||||||
|
out.flush();
|
||||||
serverName = in.readUTF();
|
serverName = in.readUTF();
|
||||||
clientLogger.printLog("You successfully connected to me", serverName, success, LogType.Log);
|
clientLogger.printLog("You successfully connected to me", serverName, success, LogType.Log);
|
||||||
} else {
|
} else {
|
||||||
@@ -55,18 +58,37 @@ public class Client {
|
|||||||
out.writeUTF(message);
|
out.writeUTF(message);
|
||||||
out.flush();
|
out.flush();
|
||||||
success = in.readInt() == 200;
|
success = in.readInt() == 200;
|
||||||
|
clientLogger.printLog(String.format("Sent the message: %s", message), serverName, success, LogType.Log);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGameState(){
|
public String getResponse() {
|
||||||
try {
|
try {
|
||||||
out.writeUTF("gamestate");
|
String message = in.readUTF();
|
||||||
return in.readUTF();
|
clientLogger.printLog(String.format("Message recieved: %s", message), serverName, success, LogType.Log);
|
||||||
|
return message;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGameState() {
|
||||||
|
this.sendToServer("gameState");
|
||||||
|
String gameState = this.getResponse();
|
||||||
|
return gameState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exitProcess(){
|
||||||
|
try {
|
||||||
|
out.writeUTF("exit()");
|
||||||
|
out.flush();
|
||||||
|
success = in.readInt()==200;
|
||||||
|
clientLogger.printLog("Closing connection to server", serverName, success, LogType.Log);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +96,8 @@ public class Client {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName(){return name;}
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
3
Server/res/META-INF/MANIFEST.MF
Normal file
3
Server/res/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: networking.Server
|
||||||
|
|
||||||
41
Server/src/game/TicTacToe_Server.java
Normal file
41
Server/src/game/TicTacToe_Server.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package game;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class TicTacToe_Server {
|
||||||
|
|
||||||
|
private String gameState;
|
||||||
|
|
||||||
|
public TicTacToe_Server(){
|
||||||
|
gameState = "---------";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGameState(String gameState) {
|
||||||
|
this.gameState = gameState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGameState() {
|
||||||
|
return gameState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int makeClientMove(String input) {
|
||||||
|
int column = Double.valueOf(input.split("\\|")[0]).intValue() / 300;
|
||||||
|
int row = Double.valueOf(input.split("\\|")[1]).intValue() / 300;
|
||||||
|
int index = column * 3 + row;
|
||||||
|
|
||||||
|
if (isLegalMove(column, row)) {
|
||||||
|
byte[] gameStateBytes = gameState.getBytes();
|
||||||
|
gameStateBytes[index] = (byte) 'x';
|
||||||
|
gameState = new String(gameStateBytes, StandardCharsets.UTF_8);
|
||||||
|
return 200;
|
||||||
|
} else {
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLegalMove(int column, int row){
|
||||||
|
int index = column * 3 + row;
|
||||||
|
return gameState.charAt(index) == '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package networking;
|
package networking;
|
||||||
|
|
||||||
|
import game.TicTacToe_Server;
|
||||||
import logging.LogType;
|
import logging.LogType;
|
||||||
import logging.ServerLogger;
|
import logging.ServerLogger;
|
||||||
|
|
||||||
@@ -15,7 +16,8 @@ public class Server {
|
|||||||
private HashMap<Socket, String> clientNames;
|
private HashMap<Socket, String> clientNames;
|
||||||
private HashMap<Socket, DataOutputStream> outstreams;
|
private HashMap<Socket, DataOutputStream> outstreams;
|
||||||
private HashMap<Socket, DataInputStream> instreams;
|
private HashMap<Socket, DataInputStream> instreams;
|
||||||
private ServerLogger logger;
|
private TicTacToe_Server ticTacToe_server;
|
||||||
|
private ServerLogger serverLogger;
|
||||||
private Scanner scanner;
|
private Scanner scanner;
|
||||||
private int requiredConnections;
|
private int requiredConnections;
|
||||||
|
|
||||||
@@ -26,11 +28,12 @@ public class Server {
|
|||||||
clientNames = new HashMap<>();
|
clientNames = new HashMap<>();
|
||||||
outstreams = new HashMap<>();
|
outstreams = new HashMap<>();
|
||||||
instreams = new HashMap<>();
|
instreams = new HashMap<>();
|
||||||
|
ticTacToe_server = new TicTacToe_Server();
|
||||||
scanner = new Scanner(System.in);
|
scanner = new Scanner(System.in);
|
||||||
logger = new ServerLogger();
|
serverLogger = new ServerLogger();
|
||||||
requiredConnections = 1;
|
requiredConnections = 1;
|
||||||
|
|
||||||
logger.printLog("Server started successfully", LogType.Log);
|
serverLogger.printLog("Server started successfully", LogType.Log);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@@ -39,7 +42,7 @@ public class Server {
|
|||||||
public void connectClients(){
|
public void connectClients(){
|
||||||
try {
|
try {
|
||||||
int id = 0;
|
int id = 0;
|
||||||
logger.printLog(String.format("Waiting for %d clients to connect ...", requiredConnections), LogType.Log);
|
serverLogger.printLog(String.format("Waiting for %d clients to connect ...", requiredConnections), LogType.Log);
|
||||||
while(clients.size() < requiredConnections) {
|
while(clients.size() < requiredConnections) {
|
||||||
Socket momentaryClient = serverSocket.accept();
|
Socket momentaryClient = serverSocket.accept();
|
||||||
clients.put(id, momentaryClient);
|
clients.put(id, momentaryClient);
|
||||||
@@ -62,7 +65,7 @@ public class Server {
|
|||||||
clientNames.put(client, instreams.get(client).readUTF());
|
clientNames.put(client, instreams.get(client).readUTF());
|
||||||
outstreams.get(client).writeUTF(serverSocket.getInetAddress().getHostAddress()+":"+serverSocket.getLocalPort());
|
outstreams.get(client).writeUTF(serverSocket.getInetAddress().getHostAddress()+":"+serverSocket.getLocalPort());
|
||||||
outstreams.get(client).flush();
|
outstreams.get(client).flush();
|
||||||
logger.printLog(String.format("%s got connected", clientNames.get(client)), LogType.Log);
|
serverLogger.printLog(String.format("%s got connected", clientNames.get(client)), LogType.Log);
|
||||||
} else {
|
} else {
|
||||||
outstreams.get(client).writeInt(403);
|
outstreams.get(client).writeInt(403);
|
||||||
outstreams.get(client).flush();
|
outstreams.get(client).flush();
|
||||||
@@ -74,19 +77,16 @@ public class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getMessages(){
|
public void ticTacToe_gameloop(){
|
||||||
for (Socket client: clients.values()) {
|
for (Socket client: clients.values()) {
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (!client.isClosed()) {
|
||||||
String message = instreams.get(client).readUTF();
|
String message = instreams.get(client).readUTF();
|
||||||
if (!message.equalsIgnoreCase("exit()")) {
|
serverLogger.printLog(message, clientNames.get(client), LogType.Message);
|
||||||
logger.printLog(message, clientNames.get(client), LogType.Message);
|
|
||||||
} else {
|
|
||||||
outstreams.get(client).writeInt(200);
|
|
||||||
logger.printLog(String.format("%s closed the connection",clientNames.get(client)), LogType.Log);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
outstreams.get(client).writeInt(200);
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
this.gameFlow(message, client);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -97,10 +97,56 @@ public class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clients.clear();
|
}
|
||||||
System.out.println("Do you want to keep the server alive and wait for other clients ? [y]/[n]");
|
|
||||||
if (scanner.nextLine().equalsIgnoreCase("y")){
|
public void gameFlow(String input, Socket client){
|
||||||
this.connectClients();
|
switch (input){
|
||||||
|
case "gameState":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeUTF(ticTacToe_server.getGameState());
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent gameState", clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "update":
|
||||||
|
try {
|
||||||
|
String position = instreams.get(client).readUTF();
|
||||||
|
serverLogger.printLog(position, clientNames.get(client), LogType.Message);
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog("Sent verification code", clientNames.get(client), LogType.Log);
|
||||||
|
int verificationCode = ticTacToe_server.makeClientMove(position);
|
||||||
|
if (verificationCode == 200) {
|
||||||
|
String gameState = ticTacToe_server.getGameState();
|
||||||
|
outstreams.get(client).writeUTF(gameState);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Sent gameState: %s", gameState), clientNames.get(client), LogType.Log);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
outstreams.get(client).writeUTF(" ");
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
serverLogger.printLog(String.format("Move is not allowed!"), clientNames.get(client), LogType.Error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
case "exit()":
|
||||||
|
try {
|
||||||
|
outstreams.get(client).writeInt(200);
|
||||||
|
outstreams.get(client).flush();
|
||||||
|
outstreams.get(client).close();
|
||||||
|
instreams.get(client).close();
|
||||||
|
client.close();
|
||||||
|
serverLogger.printLog(String.format("%s closed the connection",clientNames.get(client)), LogType.Log);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +154,6 @@ public class Server {
|
|||||||
Server server = new Server(2589);
|
Server server = new Server(2589);
|
||||||
server.connectClients();
|
server.connectClients();
|
||||||
server.handshake();
|
server.handshake();
|
||||||
server.getMessages();
|
server.ticTacToe_gameloop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
43
out/artifacts/Client/Client.html
Normal file
43
out/artifacts/Client/Client.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<html><head>
|
||||||
|
<SCRIPT src="http://java.com/js/dtjava.js"></SCRIPT>
|
||||||
|
<script>
|
||||||
|
function launchApplication(jnlpfile) {
|
||||||
|
dtjava.launch( {
|
||||||
|
url : 'Client.jnlp'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
javafx : '8.0+'
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function javafxEmbedClient_id() {
|
||||||
|
dtjava.embed(
|
||||||
|
{
|
||||||
|
id : 'Client_id',
|
||||||
|
url : 'Client.jnlp',
|
||||||
|
placeholder : 'javafx-app-placeholder',
|
||||||
|
width : '900',
|
||||||
|
height : '900'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
javafx : '8.0+'
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
<!-- Embed FX application into web page once page is loaded -->
|
||||||
|
dtjava.addOnloadCallback(javafxEmbedClient_id);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head><body>
|
||||||
|
<h2>Test page for <b>Client</b></h2>
|
||||||
|
<b>Webstart:</b> <a href='Client.jnlp' onclick="return launchApplication('Client.jnlp');">click to launch this app as webstart</a><br><hr><br>
|
||||||
|
|
||||||
|
<!-- Applet will be inserted here -->
|
||||||
|
<div id='javafx-app-placeholder'></div>
|
||||||
|
</body></html>
|
||||||
15
out/artifacts/Client/Client.jnlp
Normal file
15
out/artifacts/Client/Client.jnlp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="Client.jnlp">
|
||||||
|
<information>
|
||||||
|
<title>Client</title>
|
||||||
|
<vendor>Unknown</vendor>
|
||||||
|
<description>Client</description>
|
||||||
|
<offline-allowed/>
|
||||||
|
</information>
|
||||||
|
<resources>
|
||||||
|
<j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se"/>
|
||||||
|
<jar href="Client.jar" size="9642" download="eager" />
|
||||||
|
</resources>
|
||||||
|
<jfx:javafx-desc width="900" height="900" main-class="game.TicTacToe_Client" name="Client" />
|
||||||
|
<update check="background"/>
|
||||||
|
</jnlp>
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
Manifest-Version: 1.0
|
Manifest-Version: 1.0
|
||||||
Main-Class: networking.Client
|
Main-Class: game.TicTacToe_Client
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Reference in New Issue
Block a user