This commit is contained in:
brausjonas
2023-03-23 22:25:20 +00:00
parent bf15b6bf12
commit b7dba32a0b
6 changed files with 145 additions and 36 deletions
+19 -20
View File
@@ -2,16 +2,7 @@
<project version="4"> <project version="4">
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="e1ac5a43-1258-486e-9afa-562e60808847" name="Changes" comment=""> <list default="true" id="e1ac5a43-1258-486e-9afa-562e60808847" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/.idea/.idea.FlufflParty/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/.idea/.idea.FlufflParty/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Client.cs" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Client.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/ItemShop.cs" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/ItemShop.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/NoPlayablePlayer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/NoPlayablePlayer.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/PlayablePlayer.cs" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/PlayablePlayer.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/Player.cs" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Assets/Scripts/Players/Player.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/FlufflParty/Packages/packages-lock.json" beforeDir="false" afterPath="$PROJECT_DIR$/FlufflParty/Packages/packages-lock.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Server/src/Room.java" beforeDir="false" afterPath="$PROJECT_DIR$/Server/src/Room.java" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -29,18 +20,20 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent"><![CDATA[{ <component name="PropertiesComponent">{
"keyToString": { &quot;keyToString&quot;: {
"RunOnceActivity.OpenProjectViewOnStart": "true", &quot;RunOnceActivity.GIT_CREDENTIAL_SETUP&quot;: &quot;true&quot;,
"RunOnceActivity.ShowReadmeOnStart": "true", &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
"WebServerToolWindowFactoryState": "false", &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
"last_opened_file_path": "C:/flufflparty/Server", &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
"project.structure.last.edited": "Project", &quot;last_opened_file_path&quot;: &quot;C:/flufflparty/Server&quot;,
"project.structure.proportion": "0.15", &quot;project.structure.last.edited&quot;: &quot;Project&quot;,
"project.structure.side.proportion": "0.0", &quot;project.structure.proportion&quot;: &quot;0.15&quot;,
"settings.editor.selected.configurable": "preferences.lookFeel" &quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.lookFeel&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}]]></component> }</component>
<component name="RunManager"> <component name="RunManager">
<configuration default="true" type="JetRunConfigurationType"> <configuration default="true" type="JetRunConfigurationType">
<module name="flufflparty" /> <module name="flufflparty" />
@@ -66,6 +59,8 @@
<updated>1676488026665</updated> <updated>1676488026665</updated>
<workItem from="1676488028412" duration="3783000" /> <workItem from="1676488028412" duration="3783000" />
<workItem from="1676925887035" duration="132000" /> <workItem from="1676925887035" duration="132000" />
<workItem from="1679608517340" duration="53000" />
<workItem from="1679608805409" duration="22000" />
</task> </task>
<servers /> <servers />
</component> </component>
@@ -83,4 +78,8 @@
</map> </map>
</option> </option>
</component> </component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />
<select />
</component>
</project> </project>
+3
View File
@@ -2,6 +2,9 @@ import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.net.Socket; import java.net.Socket;
/**
* Instance of a Client connected
*/
public class Client public class Client
{ {
public DataOutputStream output; public DataOutputStream output;
+4
View File
@@ -1,5 +1,9 @@
public class Main public class Main
{ {
/**
* Main Function
* @param args
*/
public static void main(String[] args) public static void main(String[] args)
{ {
new Server().start(); new Server().start();
+57 -1
View File
@@ -8,17 +8,27 @@ import java.util.List;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
/**
* this class handels all operations / syncs performed in a single room
*/
public class Room public class Room
{ {
//tells how many clients can connect to a room
private Client[] players = new Client[2]; private Client[] players = new Client[2];
//the array of players start positions
private Vector3[] startPositions; private Vector3[] startPositions;
//the generated roomcode
private String roomCode; private String roomCode;
//the instance to the main server
private Server server; private Server server;
//all threads created stored in this list to close them after room closure
private List<Thread> threads = new ArrayList<>(); private List<Thread> threads = new ArrayList<>();
//count of players in the game
private int playerCount = 0; private int playerCount = 0;
//tells players turn (array index)
private int currentPlayer = 0; private int currentPlayer = 0;
private long timeOut = 0; private long timeOut = 0;
@@ -31,6 +41,7 @@ public class Room
this.roomCode = roomCode; this.roomCode = roomCode;
startPositions = new Vector3[4]; startPositions = new Vector3[4];
//set up the start positions
startPositions[0] = new Vector3(96, 1, 126); startPositions[0] = new Vector3(96, 1, 126);
startPositions[1] = new Vector3(92, 1, 126); startPositions[1] = new Vector3(92, 1, 126);
startPositions[2] = new Vector3(96, 1, 128); startPositions[2] = new Vector3(96, 1, 128);
@@ -38,6 +49,7 @@ public class Room
this.server = server; this.server = server;
//calculates a room timeout
try try
{ {
t = new Timer(); t = new Timer();
@@ -79,29 +91,40 @@ public class Room
} }
} }
/**
* Adds a Client to the game (on new player joined the room)
* @param client
*/
public void addClient(Client client) public void addClient(Client client)
{ {
//the timeout variable for a single player
timeOut = System.currentTimeMillis(); timeOut = System.currentTimeMillis();
//loops through all players existing and sends the needed information
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//places the new joined player in the next free slot
if (players[i] == null) if (players[i] == null)
{ {
players[i] = client; players[i] = client;
playerCount++; playerCount++;
//LOG
System.out.println("[" + Server.getDateTime() + "] " + client.name.replace(" ", "") + " joined room " + roomCode + " successfully as player " + i); System.out.println("[" + Server.getDateTime() + "] " + client.name.replace(" ", "") + " joined room " + roomCode + " successfully as player " + i);
//creates a thread for the connection with the joined player
Thread t = new Thread(new Runnable() Thread t = new Thread(new Runnable()
{ {
@Override @Override
public void run() public void run()
{ {
//assignes a player id
int player = playerCount - 1; int player = playerCount - 1;
DataInputStream input = null; DataInputStream input = null;
try try
{ {
//tries to get the input stream (TCP)
input = new DataInputStream(players[player].socket.getInputStream()); input = new DataInputStream(players[player].socket.getInputStream());
} catch (IOException e) } catch (IOException e)
{ {
@@ -112,10 +135,13 @@ public class Room
{ {
try try
{ {
//this is a buffer for all data being received by the player
byte[] readData = new byte[10]; byte[] readData = new byte[10];
//read the data to the buffer
input.read(readData); input.read(readData);
//reset the timeout once something is received
timeOut = System.currentTimeMillis(); timeOut = System.currentTimeMillis();
@@ -128,6 +154,7 @@ public class Room
---------------------------------------- ----------------------------------------
---------------------------------------- ----------------------------------------
*/ */
//Checks which action (array[0]) is received
switch (readData[0]) switch (readData[0])
{ {
@@ -136,6 +163,7 @@ public class Room
case 3: case 3:
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//sync to all OTHER players
if (i != player) if (i != player)
{ {
players[i].output.write(new byte[]{3, (byte) player, readData[1], 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{3, (byte) player, readData[1], 0, 0, 0, 0, 0, 0, 0});
@@ -147,6 +175,7 @@ public class Room
case 4: case 4:
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//sync to all OTHER players
if (i != player) if (i != player)
{ {
players[i].output.write(new byte[]{4, (byte) player, readData[1], 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{4, (byte) player, readData[1], 0, 0, 0, 0, 0, 0, 0});
@@ -157,11 +186,13 @@ public class Room
//Spieler ist fertig mit seinem Zug //Spieler ist fertig mit seinem Zug
//1 x, x = next player //1 x, x = next player
case 5: case 5:
//calculate the next player
currentPlayer++; currentPlayer++;
if (currentPlayer >= players.length) if (currentPlayer >= players.length)
{ {
currentPlayer = 0; currentPlayer = 0;
} }
//sync the activation of the current player to ALL clients
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
players[i].output.write(new byte[]{2, (byte) currentPlayer, 0, 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{2, (byte) currentPlayer, 0, 0, 0, 0, 0, 0, 0, 0});
@@ -173,6 +204,7 @@ public class Room
case 6: case 6:
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//sync to OTHER players
if (i != player) if (i != player)
{ {
players[i].output.write(new byte[]{6, (byte)player, readData[1], 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{6, (byte)player, readData[1], 0, 0, 0, 0, 0, 0, 0});
@@ -183,6 +215,7 @@ public class Room
//Eventstop (ItemShop, BuyStar, ...) ist fertig //Eventstop (ItemShop, BuyStar, ...) ist fertig
//1 x, x = player //1 x, x = player
case 7: case 7:
//sync to ALL players
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
players[i].output.write(new byte[]{7, (byte)player, 0, 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{7, (byte)player, 0, 0, 0, 0, 0, 0, 0, 0});
@@ -192,6 +225,7 @@ public class Room
case 8: case 8:
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//sync to OTHER players
if (i != player) if (i != player)
{ {
players[i].output.write(new byte[]{8, (byte)player, 0, 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{8, (byte)player, 0, 0, 0, 0, 0, 0, 0, 0});
@@ -204,12 +238,14 @@ public class Room
case 9: case 9:
for (int i = 0; i < players.length; i++) for (int i = 0; i < players.length; i++)
{ {
//Sync to OTHER players
if (i != player) if (i != player)
{ {
players[i].output.write(new byte[]{9, (byte)player, readData[1], 0, 0, 0, 0, 0, 0, 0}); players[i].output.write(new byte[]{9, (byte)player, readData[1], 0, 0, 0, 0, 0, 0, 0});
} }
} }
break; break;
//the timeout check action
case 126: case 126:
players[player].lastTimeSendTimeOutCheck = System.currentTimeMillis(); players[player].lastTimeSendTimeOutCheck = System.currentTimeMillis();
break; break;
@@ -217,13 +253,17 @@ public class Room
} catch (IOException e) } catch (IOException e)
{ {
//if something is crashing, the room is being deleted
server.deleteRoom(roomCode); server.deleteRoom(roomCode);
} }
} }
} }
}); });
//name the thread for better debugging
t.setName("Thread Player: " + (playerCount - 1)); t.setName("Thread Player: " + (playerCount - 1));
//start the thread
t.start(); t.start();
//add the thread to the threads list
threads.add(t); threads.add(t);
break; break;
} }
@@ -241,11 +281,16 @@ public class Room
//1 1 playable character //1 1 playable character
//2-3-4 default pos //2-3-4 default pos
//5 player index //5 player index
//if the player should be playable
if (j == k) if (j == k)
{ {
try try
{ {
//sends the inital message to the player
players[j].output.write(new byte[]{1, 1, (byte) startPositions[k].x, (byte) startPositions[k].y, (byte) startPositions[k].z, (byte) k, 0, 0, 0, 0}); players[j].output.write(new byte[]{1, 1, (byte) startPositions[k].x, (byte) startPositions[k].y, (byte) startPositions[k].z, (byte) k, 0, 0, 0, 0});
//sends the name of the player (ASCII encoding)............................................................................
byte[] name = players[k].name.substring(0, 8).getBytes(StandardCharsets.US_ASCII); byte[] name = players[k].name.substring(0, 8).getBytes(StandardCharsets.US_ASCII);
byte[] send = new byte[10]; byte[] send = new byte[10];
send[0] = 5; send[0] = 5;
@@ -257,11 +302,14 @@ public class Room
} }
players[j].output.write(send); players[j].output.write(send);
//stop sending the name................................................................................
} catch (IOException e) } catch (IOException e)
{ {
} }
} else }
//if the player should be a bot
else
{ {
try try
{ {
@@ -287,6 +335,8 @@ public class Room
//0 2, activate a player //0 2, activate a player
//1 x, x = idx //1 x, x = idx
//send the inital activation message
try try
{ {
for (Client c : players) for (Client c : players)
@@ -300,13 +350,18 @@ public class Room
} }
} }
/**
* Closes the room
*/
public void closeRoom() public void closeRoom()
{ {
//try to cick all the players (still connected) of the room
try try
{ {
if (players[0] != null) if (players[0] != null)
{ {
//127 is the action for room cick
players[0].output.write(new byte[]{127, 0, 0, 0, 0, 0, 0, 0, 0, 0}); players[0].output.write(new byte[]{127, 0, 0, 0, 0, 0, 0, 0, 0, 0});
} }
@@ -348,6 +403,7 @@ public class Room
} }
//try to close all open threads (not crashed yet)
for (int i = 0; i < threads.size(); i++) for (int i = 0; i < threads.size(); i++)
{ {
try try
+55 -12
View File
@@ -10,20 +10,29 @@ import java.util.HashMap;
public class Server public class Server
{ {
//the server socket (for accepting new connections)
private ServerSocket serverSocket; private ServerSocket serverSocket;
//Roomcodes and Room objects are mapped here
private HashMap<String, Room> rooms = new HashMap<>(); private HashMap<String, Room> rooms = new HashMap<>();
//hier ArrayList für public rooms //Server reference
private final Server server = this; private final Server server = this;
//A Formatter for date and time log outputs
private static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); private static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
/**
* returns a date and time stamp
* @return
*/
public static String getDateTime() public static String getDateTime()
{ {
return dtf.format(LocalDateTime.now()); return dtf.format(LocalDateTime.now());
} }
/**
* tries to delete a room by its roomcode
*/
public void deleteRoom(String code) public void deleteRoom(String code)
{ {
rooms.get(code).closeRoom(); rooms.get(code).closeRoom();
@@ -33,73 +42,96 @@ public class Server
System.out.println("[" + getDateTime() + "] Room" + code + " successfully deleted"); System.out.println("[" + getDateTime() + "] Room" + code + " successfully deleted");
} }
/**
* Starts the Server
*/
public void start() public void start()
{ {
try try
{ {
//create the listening server socket on port 8501
serverSocket = new ServerSocket(8051); serverSocket = new ServerSocket(8051);
//LOG
System.out.println("[" + getDateTime() + "] Server started! IP 185.245.96.48 PORT 8051"); System.out.println("[" + getDateTime() + "] Server started! IP 185.245.96.48 PORT 8051");
//a endless loop for accepting new connections
while(true) while(true)
{ {
//accept a connection from a client
Socket tempClient = serverSocket.accept(); Socket tempClient = serverSocket.accept();
//LOG
System.out.println("[" + getDateTime() + "] Client with IP " + tempClient.getInetAddress().getHostName() + " connected!"); System.out.println("[" + getDateTime() + "] Client with IP " + tempClient.getInetAddress().getHostName() + " connected!");
//create a new thread for the connected client to free up main thread resources for new connections
new Thread(new Runnable() new Thread(new Runnable()
{ {
@Override @Override
public void run() public void run()
{ {
//cache the connected client in the thread (if not it could be overwritten by a new connection)
Socket client = tempClient; Socket client = tempClient;
try try
{ {
//get the input stream of the client (TCP)
DataInputStream input = new DataInputStream(client.getInputStream()); DataInputStream input = new DataInputStream(client.getInputStream());
//get the output stream of the client (TCP)
DataOutputStream output = new DataOutputStream(client.getOutputStream()); DataOutputStream output = new DataOutputStream(client.getOutputStream());
//A buffer for incoming data
byte[] readData = new byte[10]; byte[] readData = new byte[10];
//read incoming data into the buffer
input.read(readData); input.read(readData);
//check for the incoming actions
switch(readData[0]) switch(readData[0])
{ {
//hier case 3 für public match making //this case generates a new room and sends the room code to the requester (not for join)
//dsfjlksdfjlöasdfjlsdkjflksdjflksdjflksdjflksdjflksdjflksdjflkjsdlkfjsdlkfsdjlkfsdlkfjsdlkfjsdlkfjlsdkfjlsdkjfldksjfjlk
//fsjfklsdjflksdjflsdjflksdjflksdfjlksdjflksdjflksdjflksdjflksdjflksdjflksdjflksdjflksdjflsdkjflksdjflksdjflksdjflksdjf
//schleife um zu checken ob ein offener room existiert (Liste)
//ansonsten einen neuen room erstellen und zur liste inhzufügen
case 2: case 2:
//cache the generated room code
byte[] code = generateRoomCode(); byte[] code = generateRoomCode();
//send the room code to the requester
output.write(code); output.write(code);
//create the room object
Room room = new Room(new String(code, StandardCharsets.US_ASCII), server); Room room = new Room(new String(code, StandardCharsets.US_ASCII), server);
//map the room object to the room code
rooms.put(new String(code, StandardCharsets.US_ASCII), room); rooms.put(new String(code, StandardCharsets.US_ASCII), room);
//LOG
System.out.println("[" + getDateTime() + "] Room " + new String(code, StandardCharsets.US_ASCII) + " successfully created!"); System.out.println("[" + getDateTime() + "] Room " + new String(code, StandardCharsets.US_ASCII) + " successfully created!");
break; break;
//in this case a player wants to join an existing room (even the room creator will join via this method)
case 1: case 1:
//fill the buffer with the incoming data (second data send after inital data transfer)
input.read(readData); input.read(readData);
//deocde the roomcode to a string (ascii -> string)
String roomCode = new String(readData, StandardCharsets.US_ASCII); String roomCode = new String(readData, StandardCharsets.US_ASCII);
//read the third message
input.read(readData); input.read(readData);
//deocde the players name
String name = new String(readData, StandardCharsets.US_ASCII); String name = new String(readData, StandardCharsets.US_ASCII);
name = name.replace("?", " "); name = name.replace("?", " ");
//check if the room exists
if(rooms.containsKey(roomCode)) if(rooms.containsKey(roomCode))
{ {
//create the reference to the client
Client client1 = new Client(output, input, client, name); Client client1 = new Client(output, input, client, name);
//move the client to the room
rooms.get(roomCode).addClient(client1); rooms.get(roomCode).addClient(client1);
} }
else else
{ {
//room is not available, so the player should automatically go back to the start menu (kick action)
output.write(new byte[]{127, 0, 0, 0, 0, 0, 0, 0, 0, 0}); output.write(new byte[]{127, 0, 0, 0, 0, 0, 0, 0, 0, 0});
} }
@@ -107,34 +139,45 @@ public class Server
} }
} catch (Exception e){ } catch (Exception e){
//do not end the program on any main thread errors (unwated connection losses), because other players wont be able to connect to the server
} }
} }
}).start(); }).start();
} }
} }
catch(Exception e){} catch(Exception e){
//do not end the program on any main thread errors (unwated connection losses), because other players wont be able to connect to the server
}
} }
/**
* Generates a ascii byte[] room code
* please see the ascii table
* @return
*/
private byte[] generateRoomCode() private byte[] generateRoomCode()
{ {
//buffer to store the code
byte[] code = new byte[10]; byte[] code = new byte[10];
for(int i = 0; i < code.length; i++) for(int i = 0; i < code.length; i++)
{ {
//for the first 5 indexes user numbers (1-9)
if(i < code.length / 2) if(i < code.length / 2)
{ {
code[i] = (byte)(Math.random() * 8 + 49); code[i] = (byte)(Math.random() * 8 + 49);
} }
//for the last 5 indexes use letters (A-Z)
else else
{ {
code[i] = (byte)(Math.random() * 25 + 97); code[i] = (byte)(Math.random() * 25 + 97);
} }
} }
//decode the generated room code to a string
String roomCode = new String(code, StandardCharsets.US_ASCII); String roomCode = new String(code, StandardCharsets.US_ASCII);
//avoide double codes (just in case^^) //in case the room code does allready exists, the roomcode generation will be called recursively
if(rooms.containsKey(roomCode)) if(rooms.containsKey(roomCode))
{ {
code = generateRoomCode(); code = generateRoomCode();
+4
View File
@@ -1,3 +1,7 @@
/**
* A Simple Vector class according to the Unity vector
*/
public class Vector3 public class Vector3
{ {
public float x, y, z; public float x, y, z;