Merge branch 'Jonas_Stuff' into 'master'
Added a Class and Method that can reformat the terminal commands into commands... See merge request cs108-fs22/Gruppe-8!1
This commit is contained in:
commit
44893525fd
Binary file not shown.
@ -1,30 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.BudaClientServerStuff;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class BudaClient {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Socket sock = null;
|
|
||||||
try {
|
|
||||||
sock = new Socket("localhost", 8090);
|
|
||||||
OutputStream out= sock.getOutputStream();
|
|
||||||
BufferedReader conin = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
String line = ""; //this String is the line that will be sent to the server
|
|
||||||
while (true) {
|
|
||||||
line = conin.readLine();
|
|
||||||
out.write(line.getBytes());
|
|
||||||
if (line.equalsIgnoreCase("Quitx")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//line.startsWith() //todo: automatically handle name lengths
|
|
||||||
//TODO: Implement inputStream in.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.BudaClientServerStuff;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class BudaClientThread implements Runnable {
|
|
||||||
int number;
|
|
||||||
Socket socket;
|
|
||||||
String name;
|
|
||||||
|
|
||||||
|
|
||||||
public BudaClientThread(int number, Socket socket) {
|
|
||||||
this.number = number;
|
|
||||||
this.socket = socket;
|
|
||||||
name = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
System.out.println("Connection " + number + " established.");
|
|
||||||
try {
|
|
||||||
InputStream in = socket.getInputStream();
|
|
||||||
OutputStream out = socket.getOutputStream();
|
|
||||||
byte[] command;
|
|
||||||
String comString;
|
|
||||||
while (true) {
|
|
||||||
command = new byte[5];
|
|
||||||
in.read(command); //BudaClientThread waits to receive a line from the inputstream.
|
|
||||||
comString = new String(command);
|
|
||||||
if (comString.equalsIgnoreCase("Quitx")) { //todo: do as switch.
|
|
||||||
BudaServer.quit = true;
|
|
||||||
System.out.println("I just set quit to true!");
|
|
||||||
break;
|
|
||||||
} else if (comString.equalsIgnoreCase("NAME:")) {
|
|
||||||
setName(in);
|
|
||||||
} else if (comString.equalsIgnoreCase("NAMES")) {
|
|
||||||
printnames();
|
|
||||||
} else {
|
|
||||||
System.out.println("Client number " + number + " sent this message: \"" + comString + "\" and I'm not sure what it means.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printnames() {
|
|
||||||
for (BudaClientThread t: BudaServer.Clients) {
|
|
||||||
System.out.println("user named "+ t.name + " is connected (#" + t.number + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(InputStream in) throws IOException {
|
|
||||||
String nameString = "";
|
|
||||||
int i;
|
|
||||||
while (true) {
|
|
||||||
i = in.read();
|
|
||||||
if (i == 46) break; //the name ends with a "."
|
|
||||||
nameString = nameString + (char) i;
|
|
||||||
}
|
|
||||||
this.name = nameString;
|
|
||||||
System.out.println("Client number " + number + " changed their name to: " + nameString);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.BudaClientServerStuff;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
public class BudaServer {
|
|
||||||
public static boolean quit = false; //todo: meaningfully implement this
|
|
||||||
public static HashSet<BudaClientThread> Clients = new HashSet<BudaClientThread>();
|
|
||||||
static int connections = 0;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
ServerConnector ServC = new ServerConnector();
|
|
||||||
Thread ServCThread = new Thread(ServC);
|
|
||||||
ServCThread.start(); //the ServCThread listens for new connections so the server can do other things
|
|
||||||
while (!quit) {
|
|
||||||
//Main server stuff goes here
|
|
||||||
}
|
|
||||||
//ServCThread.stop(); //todo: find some alternative for this.
|
|
||||||
System.out.println("stopping the main BudaServer thread.");
|
|
||||||
System.out.println("Quitting after the next connection is made.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import java.io.*;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class ClientListener implements Runnable{
|
|
||||||
private final Socket sock;
|
|
||||||
|
|
||||||
public ClientListener(Socket sock) {
|
|
||||||
this.sock = sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run(){
|
|
||||||
byte[] command = new byte[5];
|
|
||||||
String comString;
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream in = sock.getInputStream();
|
|
||||||
in.read(command);
|
|
||||||
System.out.println("Got a line!");
|
|
||||||
comString = new String(command);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
This is a demo of some (basic) client / server functionality.
|
|
||||||
Run BudaClient.java for the Client and BudaServer.java for the Server. Everything connects locally via port 8090
|
|
||||||
|
|
||||||
The client reads from the console input and sends that to the server. The Server generally reads messages in five characters (so a text-based protocol could be based on commands of five characters).
|
|
||||||
|
|
||||||
The server can connect to an arbitrary number of clients.
|
|
||||||
|
|
||||||
Type "Name:Jonas B." to change the client's name to Jonas B (the "." is where the name stops).
|
|
||||||
|
|
||||||
Type "Names" for the Server to display everyone who is connected along with their name (if they have set a name).
|
|
||||||
|
|
||||||
Typing "Quitx" should quit everything but I havent quite managed to implement that yet so just repeatedly use ctrl+c to quit everything.
|
|
||||||
|
|
||||||
-Jonas
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.BudaClientServerStuff;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class ServerConnector implements Runnable{
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
System.out.println(
|
|
||||||
"Warte auf Verbindungen auf Port 8090...");
|
|
||||||
ServerSocket servSock = new ServerSocket(8090);
|
|
||||||
while (true) {
|
|
||||||
Socket socket = servSock.accept();
|
|
||||||
System.out.println("got a connection: socket " + BudaServer.connections + socket.toString());
|
|
||||||
BudaClientThread newClientThread = new BudaClientThread(++BudaServer.connections, socket);
|
|
||||||
BudaServer.Clients.add(newClientThread);
|
|
||||||
Thread bCT = new Thread(newClientThread);
|
|
||||||
bCT.start();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("server got an error");
|
|
||||||
System.err.println(e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
||||||
|
|
||||||
public class Ghost extends Passenger {
|
public class Ghost extends Passenger {
|
||||||
|
|
||||||
protected boolean isOG; //true if the Ghost is the original ghost.
|
protected boolean isOG; //true if the Ghost is the original ghost.
|
||||||
|
|
||||||
public boolean getIsOG() {
|
public boolean getIsOG() {
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
||||||
|
|
||||||
public class GhostNPC extends Ghost{
|
public class GhostNPC extends Ghost {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new GhostNPC. Should be used at game start or if a HumanNPC is turned into a ghost.
|
* Creates a new GhostNPC. Should be used at game start or if a HumanNPC is turned into a ghost.
|
||||||
|
*
|
||||||
* @param position position on the train
|
* @param position position on the train
|
||||||
* @param name player name. if null, then a default name is used.
|
* @param name player name. if null, then a default name is used.
|
||||||
* @param isOG true if the ghost is the original ghost.
|
* @param isOG true if the ghost is the original ghost.
|
||||||
@ -17,6 +18,8 @@ public class GhostNPC extends Ghost{
|
|||||||
kickedOff = false;
|
kickedOff = false;
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
this.name = "Robot Nr. " + position;
|
this.name = "Robot Nr. " + position;
|
||||||
} else this.name = name;
|
} else {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,12 @@ package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
|||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||||
|
|
||||||
public class GhostPlayer extends Ghost{
|
public class GhostPlayer extends Ghost {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new GhostPlayer. Should be used at game start or if a HumanPlayer is turned into a ghost.
|
* Creates a new GhostPlayer. Should be used at game start or if a HumanPlayer is turned into a
|
||||||
|
* ghost.
|
||||||
|
*
|
||||||
* @param position position on the train
|
* @param position position on the train
|
||||||
* @param name name. if null, then a default name is used.
|
* @param name name. if null, then a default name is used.
|
||||||
* @param isOG true if the ghost is the original ghost.
|
* @param isOG true if the ghost is the original ghost.
|
||||||
@ -19,7 +21,9 @@ public class GhostPlayer extends Ghost{
|
|||||||
kickedOff = false;
|
kickedOff = false;
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
this.name = "Player Nr. " + position;
|
this.name = "Player Nr. " + position;
|
||||||
} else this.name = name;
|
} else {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
||||||
|
|
||||||
public class Human extends Passenger {
|
public class Human extends Passenger {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
||||||
|
|
||||||
public class HumanNPC extends Human {
|
public class HumanNPC extends Human {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new HumanNPC.
|
* Creates a new HumanNPC.
|
||||||
|
*
|
||||||
* @param position position on the train
|
* @param position position on the train
|
||||||
* @param name player name. if null, then a default name is used.
|
* @param name player name. if null, then a default name is used.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public HumanNPC(int position, String name) {
|
public HumanNPC(int position, String name) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
@ -15,6 +16,8 @@ public class HumanNPC extends Human {
|
|||||||
kickedOff = false;
|
kickedOff = false;
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
this.name = "Robot Nr. " + position;
|
this.name = "Robot Nr. " + position;
|
||||||
} else this.name = name;
|
} else {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,12 @@ package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
|||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||||
|
|
||||||
public class HumanPlayer extends Human{
|
public class HumanPlayer extends Human {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new GhostPlayer. Should be used at game start or if a HumanPlayer is turned into a ghost.
|
* Creates a new GhostPlayer. Should be used at game start or if a HumanPlayer is turned into a
|
||||||
|
* ghost.
|
||||||
|
*
|
||||||
* @param position position on the train
|
* @param position position on the train
|
||||||
* @param name name. if null, then a default name is used.
|
* @param name name. if null, then a default name is used.
|
||||||
*/
|
*/
|
||||||
@ -16,7 +19,9 @@ public class HumanPlayer extends Human{
|
|||||||
kickedOff = false;
|
kickedOff = false;
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
this.name = "Player Nr. " + position;
|
this.name = "Player Nr. " + position;
|
||||||
} else this.name = name;
|
} else {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.Klassenstruktur;
|
|||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||||
|
|
||||||
public class Passenger {
|
public class Passenger {
|
||||||
|
|
||||||
protected int position; //the player's Cabin number (0 to 5)
|
protected int position; //the player's Cabin number (0 to 5)
|
||||||
protected String name; //the player's Name
|
protected String name; //the player's Name
|
||||||
protected Boolean isGhost; //boolean regarding if the player is a ghost. Could probably be removed since ghost is a subclass but I'm keeping it in.
|
protected Boolean isGhost; //boolean regarding if the player is a ghost. Could probably be removed since ghost is a subclass but I'm keeping it in.
|
||||||
@ -12,6 +13,7 @@ public class Passenger {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a protocol message to the respective player.
|
* Sends a protocol message to the respective player.
|
||||||
|
*
|
||||||
* @param msg the message that is sent to this player.
|
* @param msg the message that is sent to this player.
|
||||||
**/
|
**/
|
||||||
public void send(String msg) {
|
public void send(String msg) {
|
||||||
@ -20,6 +22,7 @@ public class Passenger {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the Position of this passenger
|
* sets the Position of this passenger
|
||||||
|
*
|
||||||
* @param position the position of this passenger
|
* @param position the position of this passenger
|
||||||
*/
|
*/
|
||||||
public void setPosition(int position) {
|
public void setPosition(int position) {
|
||||||
@ -28,6 +31,7 @@ public class Passenger {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the name of this passenger.
|
* sets the name of this passenger.
|
||||||
|
*
|
||||||
* @param name the new name for this passenger.
|
* @param name the new name for this passenger.
|
||||||
*/
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
@ -36,6 +40,7 @@ public class Passenger {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* sets the kickedOff status of this Passenger
|
* sets the kickedOff status of this Passenger
|
||||||
|
*
|
||||||
* @param kickedOff should be set to true if the passenger has been kicked off.
|
* @param kickedOff should be set to true if the passenger has been kicked off.
|
||||||
*/
|
*/
|
||||||
public void setKickedOff(boolean kickedOff) {
|
public void setKickedOff(boolean kickedOff) {
|
||||||
|
|||||||
@ -1,44 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Spiellogikentwurf;
|
|
||||||
|
|
||||||
public class Game {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be extended for optional Game-settings
|
|
||||||
**/
|
|
||||||
protected int nrOfPlayers; //sets the length of the train
|
|
||||||
protected int nrOfGhosts; // sets how many Ghosts we start witch
|
|
||||||
protected int nrOfUsers; // safes how many clients are active in this Game
|
|
||||||
protected GameFunctions gameFunctions;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Game instance where:
|
|
||||||
*
|
|
||||||
* @param nrOfPlayers is the length of the Train
|
|
||||||
* @param nrOfGhosts is the number of OG Ghosts you want to start with and
|
|
||||||
* @param nrOfUsers is the number of active users at the time (non NPCs)
|
|
||||||
*/
|
|
||||||
Game(int nrOfPlayers, int nrOfGhosts, int nrOfUsers)
|
|
||||||
throws TrainOverflow { //ToDo: Who handles Exception how and where
|
|
||||||
this.nrOfPlayers = nrOfPlayers;
|
|
||||||
this.nrOfGhosts = nrOfGhosts;
|
|
||||||
this.nrOfUsers = nrOfUsers;
|
|
||||||
this.gameFunctions = new GameFunctions(nrOfPlayers, nrOfGhosts, nrOfUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
Game game1 = new Game(6, 1, 1);
|
|
||||||
for (int j = 0; j < game1.nrOfPlayers; j++) {
|
|
||||||
System.out.println(game1.gameFunctions.passengerTrain[j].getPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (TrainOverflow e) {
|
|
||||||
System.out.println(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Spiellogikentwurf;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.Klassenstruktur.Human;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.Klassenstruktur.Passenger;
|
|
||||||
|
|
||||||
public class GameFunctions {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be extended for optional Game-settings
|
|
||||||
**/
|
|
||||||
int nrOfPlayers; //sets the length of the train
|
|
||||||
int nrOfGhosts; // sets how many Ghosts we start witch
|
|
||||||
int nrOfUsers; // safes how many clients are active in this Game
|
|
||||||
Train train; // safes who sits where
|
|
||||||
Passenger[] passengerTrain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a GameFunctions instance where nrOfPlayers >= nrOfUsers. Fills passengerTrain with
|
|
||||||
* only humans
|
|
||||||
*
|
|
||||||
* @param nrOfPlayers is the length of the Train
|
|
||||||
* @param nrOfGhosts is the number of OG Ghosts you want to start with and
|
|
||||||
* @param nrOfUsers is the number of active users at the time (non NPCs)
|
|
||||||
* @throws TrainOverflow if nrOfPlayers < nrOfUsers
|
|
||||||
*/
|
|
||||||
GameFunctions(int nrOfPlayers, int nrOfGhosts, int nrOfUsers)
|
|
||||||
throws TrainOverflow { //ToDo: where will Exception be handled?
|
|
||||||
this.nrOfPlayers = nrOfPlayers;
|
|
||||||
this.nrOfGhosts = nrOfGhosts;
|
|
||||||
this.nrOfUsers = nrOfUsers;
|
|
||||||
this.train = new Train(nrOfPlayers, nrOfUsers);
|
|
||||||
Passenger[] passengerTrain = new Passenger[nrOfPlayers]; //Creates an array with Passengers with correlation positions (Train)
|
|
||||||
for (int i = 0; i < nrOfPlayers; i++) {
|
|
||||||
Human h = new Human();
|
|
||||||
h.setPosition(train.orderOfTrain[i]);
|
|
||||||
passengerTrain[i] = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNrOfGhosts() {
|
|
||||||
return nrOfGhosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNrOfPlayers() {
|
|
||||||
return nrOfPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNrOfUsers() {
|
|
||||||
return nrOfUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ghostyfy(int position) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Passenger voteEval() {
|
|
||||||
return new Passenger();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,79 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Spiellogikentwurf;
|
|
||||||
|
|
||||||
public class Train {
|
|
||||||
|
|
||||||
int[] orderOfTrain; //gives the random order in which the passengers enter the train
|
|
||||||
int positionOfGhost;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a Train with orderOfTrain of the size nrOfPlayers, filled with a Random order of the
|
|
||||||
* numbers 0-5. Puts the ghost approx in the middle of this order.
|
|
||||||
*
|
|
||||||
* @param nrOfPlayers sets how many Players fit in the Train
|
|
||||||
* @param nrOfUsers sets how many of the Players are Users (vs NPCs)
|
|
||||||
* @throws TrainOverflow if you want to play with to many users (Train is to small)
|
|
||||||
*/
|
|
||||||
Train(int nrOfPlayers, int nrOfUsers) throws TrainOverflow {
|
|
||||||
|
|
||||||
if (nrOfPlayers < nrOfUsers) {
|
|
||||||
throw new TrainOverflow(); //ToDo: What kind of Exception must be thrown here and who handles it how?
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] userTrain = new int[nrOfPlayers];
|
|
||||||
int[] check = new int[nrOfPlayers];
|
|
||||||
int i = 0;
|
|
||||||
int zeroCounter = 0;
|
|
||||||
while (i < nrOfPlayers) {
|
|
||||||
int randomNr = (int) ((Math.random() * ((nrOfPlayers)) + 0));
|
|
||||||
if (randomNr == 0) {
|
|
||||||
if (zeroCounter == 0) {
|
|
||||||
i++;
|
|
||||||
zeroCounter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isInArray(check, randomNr)) {
|
|
||||||
userTrain[i] = randomNr;
|
|
||||||
check[randomNr] = randomNr;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
this.orderOfTrain = userTrain;
|
|
||||||
this.positionOfGhost = nrOfPlayers / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the key is to be found in an array
|
|
||||||
*
|
|
||||||
* @param array the array to be searched
|
|
||||||
* @param key the value searched for
|
|
||||||
* @return true if and only if key is found
|
|
||||||
*/
|
|
||||||
static public boolean isInArray(int[] array, int key) {
|
|
||||||
int i = 0;
|
|
||||||
while (i < array.length) {
|
|
||||||
if (array[i] == key) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
int[] a = {1, 2, 3, 4, 5};
|
|
||||||
System.out.println(isInArray(a, 0));
|
|
||||||
//Test
|
|
||||||
try {
|
|
||||||
Train t = new Train(6, 1);
|
|
||||||
for (int i = 0; i < 6; i++) {
|
|
||||||
System.out.print("|" + t.orderOfTrain[i] + "|");
|
|
||||||
}
|
|
||||||
System.out.println(" Ghost:" + t.positionOfGhost);
|
|
||||||
|
|
||||||
} catch (TrainOverflow e) {
|
|
||||||
System.out.println(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.Spiellogikentwurf;
|
|
||||||
|
|
||||||
public class TrainOverflow extends Exception {
|
|
||||||
|
|
||||||
private static final String message = "Too many users are logged on";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.example;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple HelloWorld class.
|
|
||||||
*/
|
|
||||||
public class HelloWorld {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Hello World");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.example.gui.javafx;
|
|
||||||
|
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.scene.control.Label;
|
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an example JavaFX-Application.
|
|
||||||
*/
|
|
||||||
public class GUI extends Application {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launching this method will not work on some platforms.
|
|
||||||
* What you should do is to create a separate main class and launch the GUI class from there as is done in {@link Main}
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Stage stage) {
|
|
||||||
String javaVersion = System.getProperty("java.version");
|
|
||||||
String javafxVersion = System.getProperty("javafx.version");
|
|
||||||
Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
|
|
||||||
Scene scene = new Scene(new StackPane(l), 640, 480);
|
|
||||||
stage.setScene(scene);
|
|
||||||
stage.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.example.gui.javafx;
|
|
||||||
|
|
||||||
import javafx.application.Application;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is simply a wrapper to launch the {@link GUI} class.
|
|
||||||
* The reason this class exists is documented in {@link GUI#main(String[])}
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Application.launch(GUI.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.example.gui.swing;
|
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an example Swing Application
|
|
||||||
*/
|
|
||||||
public class SwingGUI {
|
|
||||||
|
|
||||||
private static void createAndShowGUI() {
|
|
||||||
// Make sure we have nice window decorations
|
|
||||||
JFrame.setDefaultLookAndFeelDecorated(true);
|
|
||||||
// Create and set up the window.
|
|
||||||
JFrame frame = new JFrame("HelloWorldSwing");
|
|
||||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add the ubiquitous "Hello World" label
|
|
||||||
JLabel label = new JLabel("Hello World");
|
|
||||||
frame.getContentPane().add(label);
|
|
||||||
// Display the window
|
|
||||||
frame.pack();
|
|
||||||
frame.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
// Schedule a job for the event-dispatching thread: // creating and showing this application's GUI
|
|
||||||
javax.swing.SwingUtilities.invokeLater(() -> createAndShowGUI());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,19 +1,20 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NoLegalProtocolCommandStringFoundException;
|
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger;
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.NameGenerator;
|
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
|
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private BufferedReader in;
|
private BufferedReader in;
|
||||||
private BufferedWriter out;
|
private BufferedWriter out;
|
||||||
public String userName;
|
public String userName;
|
||||||
|
public ClientPinger clientPinger;
|
||||||
|
|
||||||
public Client(Socket socket, String userName) {
|
public Client(Socket socket, String userName) {
|
||||||
try {
|
try {
|
||||||
@ -21,61 +22,43 @@ public class Client {
|
|||||||
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||||
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
||||||
|
|
||||||
|
//TODO add the system based generated username here.
|
||||||
//TODO hide connecting logik(next 4 lines)
|
//TODO hide connecting logik(next 4 lines)
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
this.out.write(getUsername());
|
this.out.write(getUsername());
|
||||||
this.out.newLine();
|
this.out.newLine();
|
||||||
this.out.flush();
|
this.out.flush();
|
||||||
|
clientPinger = new ClientPinger(this.out, this.socket);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
closeEverything(socket, in, out);
|
closeEverything(socket, in, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
public void sendMessage() {
|
public void sendMessage() {
|
||||||
try {
|
try {
|
||||||
Scanner sc = new Scanner(System.in);
|
Scanner sc = new Scanner(System.in);
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
String msg = sc.nextLine();
|
String msg = sc.nextLine();
|
||||||
String encodedMsg = "";
|
String formattedMSG = MessageFormatter.formatMsg(msg);
|
||||||
try {
|
out.write(formattedMSG);
|
||||||
encodedMsg = encodeMessage(msg);
|
|
||||||
} catch (NoLegalProtocolCommandStringFoundException e) {
|
|
||||||
System.out.println("ERROR: no legal command found");
|
|
||||||
encodedMsg = "";
|
|
||||||
} catch (EmptyClientInputException e) {
|
|
||||||
//Maybe this exception shouldn't do anything.
|
|
||||||
} finally {
|
|
||||||
out.write(encodedMsg);
|
|
||||||
out.newLine();
|
out.newLine();
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
closeEverything(socket, in, out);
|
closeEverything(socket, in, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses <code>NTtBProtocolParser</code> to turn Client input into the NTtB Protocol format. Must
|
|
||||||
* be called before a client input is sent to the server.
|
|
||||||
*
|
|
||||||
* @param msg the msg to be encoded.
|
|
||||||
* @return Message encoded adhering to the NTtB Protocoll.
|
|
||||||
*/
|
|
||||||
private String encodeMessage(String msg)
|
|
||||||
throws NoLegalProtocolCommandStringFoundException, EmptyClientInputException {
|
|
||||||
NTtBProtocolParser pp = new NTtBProtocolParser(this);
|
|
||||||
return pp.parseMsg(msg);
|
|
||||||
}
|
|
||||||
//TODO implement decoding of server input
|
|
||||||
private String decodeServerMsg(String msg){return null;}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for incoming messages
|
* Starts a thread which listens for incoming messages
|
||||||
*/
|
*/
|
||||||
public void chatListener() {
|
public void chatListener() {
|
||||||
/*TODO: what type of decoding has to be done
|
/*TODO: what type of decoding has to be done
|
||||||
@ -84,12 +67,13 @@ public class Client {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
String chatMsg;
|
String chatMsg;
|
||||||
|
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
try {
|
try {
|
||||||
chatMsg = in.readLine();
|
chatMsg = in.readLine();
|
||||||
System.out.println(chatMsg);
|
parse(chatMsg);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
closeEverything(socket, in, out);
|
closeEverything(socket, in, out);
|
||||||
@ -100,6 +84,29 @@ public class Client {
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a message to the server, as is.
|
||||||
|
* @param msg the message sent. Should already be protocol-formatted.
|
||||||
|
*/
|
||||||
|
public void sendMsgToServer(String msg) {
|
||||||
|
try {
|
||||||
|
out.write(msg);
|
||||||
|
out.newLine();
|
||||||
|
out.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parses a received message according to the client protocol.
|
||||||
|
* @param msg the message to be parsed.
|
||||||
|
*/
|
||||||
|
public void parse(String msg) {
|
||||||
|
JClientProtocolParser.parse(msg, this);
|
||||||
|
}
|
||||||
|
|
||||||
public void closeEverything(Socket socket, BufferedReader in, BufferedWriter out) {
|
public void closeEverything(Socket socket, BufferedReader in, BufferedWriter out) {
|
||||||
//TODO Correctly closing a clients connection
|
//TODO Correctly closing a clients connection
|
||||||
|
|
||||||
@ -129,14 +136,17 @@ public class Client {
|
|||||||
} else {
|
} else {
|
||||||
hostname = args[0];
|
hostname = args[0];
|
||||||
}
|
}
|
||||||
System.out.println("Choose a nickname: ");
|
String systemName = System.getProperty("user.name");
|
||||||
|
System.out.println("Choose a nickname (Suggestion: " + systemName + "): ");
|
||||||
String username = sc.next();
|
String username = sc.next();
|
||||||
Socket socket;
|
Socket socket;
|
||||||
try {
|
try {
|
||||||
socket = new Socket(hostname, 42069);
|
socket = new Socket(hostname, 42069);
|
||||||
Client client = new Client(socket, username);
|
Client client = new Client(socket, username);
|
||||||
client.chatListener();
|
client.chatListener();
|
||||||
client.sendMessage();
|
Thread cP = new Thread(client.clientPinger);
|
||||||
|
cP.start();
|
||||||
|
client.sendMessage(); //this one blocks.
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
System.out.println("Invalid host IP");
|
System.out.println("Invalid host IP");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -148,6 +158,4 @@ public class Client {
|
|||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return userName;
|
return userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
|
||||||
|
|
||||||
public class EmptyClientInputException extends Exception {
|
|
||||||
String exceptionMsg;
|
|
||||||
Client whoDunIt;
|
|
||||||
public EmptyClientInputException(Client whoDunIt) {
|
|
||||||
this.whoDunIt = whoDunIt;
|
|
||||||
this.exceptionMsg = whoDunIt.getUsername() + " tried to send an empty message";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExceptionMsg(){
|
|
||||||
return exceptionMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NightTrainProtocol;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NoLegalProtocolCommandStringFoundException;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
public class InputToProtocolMap {
|
|
||||||
|
|
||||||
private static final HashMap<String, NightTrainProtocol.NTtBCommands> encoding;
|
|
||||||
private static final HashSet<String> legalClientInput;
|
|
||||||
|
|
||||||
static {
|
|
||||||
//First add all legal commands to a map
|
|
||||||
HashMap<String, NightTrainProtocol.NTtBCommands> builder = new HashMap<>();
|
|
||||||
builder.put("chat", NightTrainProtocol.NTtBCommands.CHATA);
|
|
||||||
builder.put("cn", NightTrainProtocol.NTtBCommands.CUSRN);
|
|
||||||
builder.put("list", NightTrainProtocol.NTtBCommands.LISTP);
|
|
||||||
builder.put("exit", NightTrainProtocol.NTtBCommands.LEAVG);
|
|
||||||
//TODO extend according to extended function
|
|
||||||
//Initialize static final map and set
|
|
||||||
legalClientInput = new HashSet<>(builder.keySet());
|
|
||||||
encoding = new HashMap<>(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String encode(String toEncode) throws NoLegalProtocolCommandStringFoundException {
|
|
||||||
if (legalClientInput.contains(toEncode)) {
|
|
||||||
return encoding.get(toEncode).toString();
|
|
||||||
} else {
|
|
||||||
throw new NoLegalProtocolCommandStringFoundException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
||||||
|
|
||||||
|
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||||
|
|
||||||
|
public class JClientProtocolParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the client to parse an incoming protocol message.
|
||||||
|
* @param msg the encoded message that needs to be parsed
|
||||||
|
* @param c this Client(required so this method can access the Client's methods)
|
||||||
|
*/
|
||||||
|
public static void parse(String msg, Client c) {
|
||||||
|
String header = ""; //"header" is the first 5 characters, i.e. the protocol part
|
||||||
|
try {
|
||||||
|
header = msg.substring(0, 5);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
System.out.println("Received unknown command");
|
||||||
|
}
|
||||||
|
//System.out.println(header); helpful for debugging
|
||||||
|
switch (header) {
|
||||||
|
case "SPING":
|
||||||
|
c.sendMsgToServer("PINGB");
|
||||||
|
break;
|
||||||
|
case "PINGB":
|
||||||
|
c.clientPinger.setGotPingBack(true);
|
||||||
|
break;
|
||||||
|
case "CHATM":
|
||||||
|
System.out.println(msg.substring(6));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Received unknown command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
||||||
|
|
||||||
|
public class MessageFormatter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a given Message and reformats it to where the JServerProtocolParser.parse() method can
|
||||||
|
* handle it. May need to be redesigned one the games uses a GUI
|
||||||
|
*
|
||||||
|
* @param msg the Messaged to be reformatted
|
||||||
|
* @return the reformatted message in the form HEADR$msg
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static String formatMsg(String msg) {
|
||||||
|
String header = ""; //header is first two characters
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
String s; // just a friendly helper to save message in
|
||||||
|
try {
|
||||||
|
header = msg.substring(0, 2);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
switch (header) {
|
||||||
|
case "/c":
|
||||||
|
stringBuilder.append("CHATA$");
|
||||||
|
s = msg.substring(3);
|
||||||
|
break;
|
||||||
|
case "/q":
|
||||||
|
stringBuilder.append("QUITS$");
|
||||||
|
s = msg.substring(3);
|
||||||
|
break;
|
||||||
|
case "/n":
|
||||||
|
stringBuilder.append("NAMEC$");
|
||||||
|
s = msg.substring(3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = msg;
|
||||||
|
}
|
||||||
|
stringBuilder.append(s);
|
||||||
|
return stringBuilder.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,76 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NoLegalProtocolCommandStringFoundException;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a protocol parser for the NTtB protocoll, that transforms client input into a server
|
|
||||||
* readable format.
|
|
||||||
*/
|
|
||||||
public class NTtBProtocolParser implements ProtocolParser {
|
|
||||||
|
|
||||||
//TODO Possibly bad name, rename to clientMsgParser?
|
|
||||||
public final Client caller;
|
|
||||||
public static InputToProtocolMap legalCommands = new InputToProtocolMap();
|
|
||||||
|
|
||||||
|
|
||||||
public NTtBProtocolParser(Client caller) {
|
|
||||||
this.caller = caller;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String parseMsg(String msg)
|
|
||||||
throws NoLegalProtocolCommandStringFoundException, EmptyClientInputException {
|
|
||||||
Scanner sc = new Scanner(msg);
|
|
||||||
ArrayList<String> input = new ArrayList<>();
|
|
||||||
String parsedMsg;
|
|
||||||
|
|
||||||
while (sc.hasNext()) {
|
|
||||||
input.add(sc.next());
|
|
||||||
}
|
|
||||||
return buildProtocolMsg(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String buildProtocolMsg(ArrayList<String> input)
|
|
||||||
throws EmptyClientInputException, NoLegalProtocolCommandStringFoundException {
|
|
||||||
//TODO
|
|
||||||
if (emptyClientInput(input)) {
|
|
||||||
throw new EmptyClientInputException(caller);
|
|
||||||
}
|
|
||||||
StringBuilder s = new StringBuilder(); //friendly little helper
|
|
||||||
s.append(InputToProtocolMap.encode(input.get(0)));
|
|
||||||
if (containsParameters(input)) {
|
|
||||||
int size = input.size();
|
|
||||||
for (int i = 1; i < size; i++) {
|
|
||||||
s.append("$");
|
|
||||||
s.append(input.get(i).toLowerCase()); //parameters are always lower case (is that good?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if input has parameters
|
|
||||||
* <p>
|
|
||||||
* if the list size is smaller than 2, i.e. not larger than 1, the input only contains a command.
|
|
||||||
*
|
|
||||||
* @param input the tokenized input string.
|
|
||||||
* @return true if input list is larger than 2.
|
|
||||||
*/
|
|
||||||
private boolean containsParameters(ArrayList<String> input) {
|
|
||||||
return input.size() > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks if client input is empty
|
|
||||||
*
|
|
||||||
* @param clientInput the clients input.
|
|
||||||
* @return true if client didn't send any input besides whitespace
|
|
||||||
*/
|
|
||||||
private boolean emptyClientInput(ArrayList<String> clientInput) {
|
|
||||||
return clientInput.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
|
||||||
|
|
||||||
public interface ProtocolParser {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes a String from client input and parses into server readable message.
|
|
||||||
*
|
|
||||||
* @param msg the message to be parsed
|
|
||||||
* @return a String message formatted for the specific protocol
|
|
||||||
*/
|
|
||||||
String parseMsg(String msg) throws Exception;
|
|
||||||
}
|
|
||||||
@ -31,27 +31,27 @@ public class ClientPinger implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
gotPingBack = false;
|
gotPingBack = false;
|
||||||
out.write("CPING");
|
out.write("CPING");
|
||||||
out.newLine();
|
out.newLine();
|
||||||
out.flush();
|
out.flush();
|
||||||
Thread.sleep(2000);
|
Thread.sleep(4000);
|
||||||
if (gotPingBack) {
|
if (gotPingBack) {
|
||||||
if (!isConnected) { //if !isConnected, then the connection had been lost before.
|
if (!isConnected) { //if !isConnected, then the connection had been lost before.
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
System.out.println("Connection regained!");
|
System.out.println("Connection regained!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (isConnected) {
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
System.out.println("Lost connection. Waiting to reconnect...");
|
System.out.println("Lost connection. Waiting to reconnect...");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
isConnected = false; //in case the socket accidentally disconnects (can this happen?)
|
isConnected = false; //in case the socket accidentally disconnects (can this happen?)
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException | IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
Client commands:
|
||||||
|
|
||||||
|
Implemented:
|
||||||
|
* CHATA$message Send chat message to all
|
||||||
|
* QUITS quit server/ leave server
|
||||||
|
* CPING Ping from client to server.
|
||||||
|
* PINGB Pingback from client to server.
|
||||||
|
* NAMEC$name Change name to whatever is specified
|
||||||
|
|
||||||
|
Future / planned:
|
||||||
|
* CRTGM Create a new game
|
||||||
|
* CHATW whisper chat
|
||||||
|
* CHATG ghost chat
|
||||||
|
* LEAVG leave a game
|
||||||
|
* JOING join a game
|
||||||
|
* VOTEG ghost voting who to infect
|
||||||
|
* VOTEH humans voting who is the ghost
|
||||||
|
* LISTP list players/clients in session with the Server
|
||||||
|
|
||||||
|
Server Commands:
|
||||||
|
|
||||||
|
Implemented:
|
||||||
|
* SPING Ping from server to client
|
||||||
|
* PINGB Pingback from client to server.
|
||||||
|
|
||||||
|
Future / planned:
|
||||||
|
* MSGRS "Message received": Paramaters: a string detailing to the client that and what the server received as command.
|
||||||
|
* SEROR Server had an error. (used for debugging)
|
||||||
|
* NOCMD No command found.
|
||||||
|
|
||||||
|
|
||||||
@ -31,26 +31,27 @@ public class ServerPinger implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected()) {
|
||||||
gotPingBack = false;
|
gotPingBack = false;
|
||||||
out.write("SPING");
|
out.write("SPING");
|
||||||
out.newLine();
|
out.newLine();
|
||||||
out.flush();
|
out.flush();
|
||||||
Thread.sleep(2000);
|
Thread.sleep(4000);
|
||||||
if (gotPingBack) {
|
if (gotPingBack) {
|
||||||
if (!isConnected) { //if !isConnected, then the connection had been lost before.
|
if (!isConnected) { //if !isConnected, then the connection had been lost before.
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
System.out.println("Connection regained!");
|
System.out.println("Connection regained!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (isConnected) {
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
System.out.println("Lost connection. Waiting to reconnect...");
|
System.out.println("Lost connection. Waiting to reconnect...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
isConnected = false; //in case the socket accidentally disconnects (can this happen?)
|
isConnected = false; //in case the socket accidentally disconnects (can this happen?)
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException | IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,50 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class defines what type the ClientMsgDecoder returns after decoding the message. This is
|
|
||||||
* done so the output can be split into a response to the client and action in to the game logik.
|
|
||||||
* commands should map to methods(maybe classes) parameters map to method parameters
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class NTtBFormatMsg {
|
|
||||||
|
|
||||||
private String msgToClient;
|
|
||||||
private NightTrainProtocol.NTtBCommands command;
|
|
||||||
private final String[] parameters; //TODO maybe use array?
|
|
||||||
|
|
||||||
public NTtBFormatMsg(String msgToClient, NightTrainProtocol.NTtBCommands command,
|
|
||||||
String[] parameters) {
|
|
||||||
this.msgToClient = msgToClient;
|
|
||||||
this.command = command;
|
|
||||||
this.parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NTtBFormatMsg() {
|
|
||||||
this.msgToClient = "";
|
|
||||||
this.command = null;
|
|
||||||
this.parameters = new String[]{""};
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return msgToClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NightTrainProtocol.NTtBCommands getCommand() {
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getParameters() {
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setMsgToClient(String msgToClient) {
|
|
||||||
this.msgToClient = msgToClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setCommand(NightTrainProtocol.NTtBCommands command) {
|
|
||||||
this.command = command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
public interface NTtBInputType {
|
|
||||||
String msg = null;
|
|
||||||
public String getValue();
|
|
||||||
public void setValue();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
public class NTtBParameter implements NTtBInputType {
|
|
||||||
String parameterValue;
|
|
||||||
|
|
||||||
public NTtBParameter(String parameterValue) {
|
|
||||||
this.parameterValue = parameterValue;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public String getValue() {
|
|
||||||
return parameterValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue() {
|
|
||||||
//Possibly do not need
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* Client commands:
|
|
||||||
* CRTGM: Create a new game
|
|
||||||
* CHATA: chat to all
|
|
||||||
* CHATW: whisper chat
|
|
||||||
* CHATG: ghost chat
|
|
||||||
* LEAVG: leave a game
|
|
||||||
* JOING: join a game
|
|
||||||
* VOTEG: ghost voting who to infect
|
|
||||||
* VOTEH: humans voting who is the ghost
|
|
||||||
* QUITS: quit server/ leave server
|
|
||||||
* LISTP: list players/clients in session with the Server
|
|
||||||
* CPING: Ping from client to server.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
Server Commands:
|
|
||||||
* MSGRS: "Message received": Paramaters: a string detailing to the client that and what the server received as command.
|
|
||||||
* SEROR: Server had an error. (used for debugging)
|
|
||||||
* SPING: Ping from server to client;
|
|
||||||
* NOCMD: Co command found.
|
|
||||||
*/
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
/*
|
|
||||||
The NightTrainProtocol implements the Communication-Protocol of the
|
|
||||||
"Night Train to Budapest"" game. It acts as an Interface between Client and server. All Client Messages are
|
|
||||||
piped through this protocol, in order for the Server to execute the correct action. It is used by the ClientHandler
|
|
||||||
for this purpose.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class NightTrainProtocol {
|
|
||||||
//TODO: initialite the fields
|
|
||||||
|
|
||||||
private static HashMap<String, NTtBCommands> stringNTtBCommandsHashMap = initializeMapping();
|
|
||||||
private static ProtocolValidator protocolValidator;
|
|
||||||
private static HashSet<String> legalStrings = new HashSet<>(stringNTtBCommandsHashMap.keySet());
|
|
||||||
|
|
||||||
public enum NTtBCommands {
|
|
||||||
//Client Commands
|
|
||||||
CRTGM, CHATA, CHATW, CHATG, LEAVG, JOING, VOTEG, QUITS, LISTP, CUSRN,CPING,
|
|
||||||
//Server Responses
|
|
||||||
MSGRS, SEROR, SPING, NOCMD
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HashMap<String, NTtBCommands> initializeMapping(){
|
|
||||||
HashMap<String, NTtBCommands> map = new HashMap<>();
|
|
||||||
for(NTtBCommands cmd: NTtBCommands.values()) {
|
|
||||||
map.put(cmd.toString(), cmd);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
//getters & setters
|
|
||||||
|
|
||||||
public static HashMap<String, NTtBCommands> getStringNTtBCommandsHashMap() {
|
|
||||||
return stringNTtBCommandsHashMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HashSet<String> getLegalStrings() {
|
|
||||||
return legalStrings;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Utility Methods:
|
|
||||||
/**
|
|
||||||
* Validates a given string is a valid representation
|
|
||||||
* of a protocol command
|
|
||||||
* @param cmd, the string command to be validated
|
|
||||||
* @return true if <code>cmd</code> is a valid command
|
|
||||||
*/
|
|
||||||
public static boolean isLegalCmdString(String cmd) {
|
|
||||||
return legalStrings.contains(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NTtBCommands getCmdEnumObject(String cmd) throws NoLegalProtocolCommandStringFoundException {
|
|
||||||
if(isLegalCmdString(cmd)){
|
|
||||||
return stringNTtBCommandsHashMap.get(cmd);
|
|
||||||
} else {
|
|
||||||
throw new NoLegalProtocolCommandStringFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO analyize what methods are needed
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
public class NoLegalProtocolCommandStringFoundException extends Exception {
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
public interface ProtocolDecoder {
|
|
||||||
|
|
||||||
public NTtBFormatMsg decodeMsg(String msg);
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.protocol;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashSet;
|
|
||||||
//TODO Possibly redundant!!
|
|
||||||
|
|
||||||
public class ProtocolValidator {
|
|
||||||
|
|
||||||
//TODO String or NTtBCommands HashSet?
|
|
||||||
public static HashSet<NightTrainProtocol.NTtBCommands> legalCommands = initializeLegalCommands();
|
|
||||||
|
|
||||||
//Initialize the legalCommands set with the protocol values.
|
|
||||||
private static HashSet<NightTrainProtocol.NTtBCommands> initializeLegalCommands(){
|
|
||||||
EnumSet<NightTrainProtocol.NTtBCommands> enumVals = EnumSet.allOf(NightTrainProtocol.NTtBCommands.class);
|
|
||||||
return new HashSet<>(enumVals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean validateCommand(String s) {
|
|
||||||
//TODO implement if needed
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,13 +1,21 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
||||||
|
|
||||||
/* This class is built to contain the usernames of all players in a single string.
|
/**
|
||||||
|
* This class is built to contain the usernames of all players in a single string.
|
||||||
* This allows a duplicate check (--> ClientHandler) when a new player chooses
|
* This allows a duplicate check (--> ClientHandler) when a new player chooses
|
||||||
* a name: does the string with all the previous names contain the new player's
|
* a name: does the string with all the previous names contain the new player's
|
||||||
* desired username? If yes, he is being assigned a random name. If no, he can keep
|
* desired username? If yes, he is being assigned a random name. If no, he can keep
|
||||||
* his desired name. */
|
* his desired name.
|
||||||
|
* **/
|
||||||
|
|
||||||
public class AllClientNames {
|
public class AllClientNames {
|
||||||
static StringBuilder names = new StringBuilder();
|
static StringBuilder names = new StringBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safes a new name to the List of all Names
|
||||||
|
* @param currentName the new name to be added
|
||||||
|
* @return All names adding the new currentName
|
||||||
|
*/
|
||||||
public static String allNames(String currentName) {
|
public static String allNames(String currentName) {
|
||||||
return names.append(currentName).toString();
|
return names.append(currentName).toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +1,26 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NTtBFormatMsg;
|
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class ClientHandler implements Runnable {
|
public class ClientHandler implements Runnable {
|
||||||
|
|
||||||
private String clientUserName;
|
private String clientUserName;
|
||||||
private BufferedWriter out;
|
private BufferedWriter out;
|
||||||
private BufferedReader in;
|
private BufferedReader in;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
Scanner sc;
|
Scanner sc;
|
||||||
|
public ServerPinger serverPinger;
|
||||||
public static HashSet<ClientHandler> connectedClients = new HashSet<>();
|
public static HashSet<ClientHandler> connectedClients = new HashSet<>();
|
||||||
public static HashSet<ClientHandler> lobby = new HashSet<>();
|
public static HashSet<ClientHandler> lobby = new HashSet<>();
|
||||||
public static HashSet<ClientHandler> ghostClients = new HashSet<>();
|
public static HashSet<ClientHandler> ghostClients = new HashSet<>();
|
||||||
private ClientMsgDecoder clientMsgDecoder = new ClientMsgDecoder();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the login logik in client-server
|
* Implements the login logic in client-server architecture.
|
||||||
* architecture.
|
*
|
||||||
* @param socket the socket on which to make the connection.
|
* @param socket the socket on which to make the connection.
|
||||||
*/
|
*/
|
||||||
public ClientHandler(Socket socket) {
|
public ClientHandler(Socket socket) {
|
||||||
@ -28,15 +29,16 @@ public class ClientHandler implements Runnable {
|
|||||||
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||||
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
this.in = new BufferedReader((new InputStreamReader((socket.getInputStream()))));
|
||||||
this.clientUserName = in.readLine();
|
this.clientUserName = in.readLine();
|
||||||
|
|
||||||
// duplicate handling: if username already taken, assign random name to client
|
// duplicate handling: if username already taken, assign random name to client
|
||||||
if (AllClientNames.allNames("").contains(clientUserName)) {
|
if (AllClientNames.allNames("").contains(clientUserName)) {
|
||||||
clientUserName = NameGenerator.randomName();
|
clientUserName = NameGenerator.randomName(clientUserName);
|
||||||
}
|
}
|
||||||
// add username to list of all client names for future duplicate checking
|
// add username to list of all client names for future duplicate checking
|
||||||
AllClientNames.allNames(clientUserName);
|
AllClientNames.allNames(clientUserName);
|
||||||
|
|
||||||
connectedClients.add(this);
|
connectedClients.add(this);
|
||||||
|
serverPinger = new ServerPinger(out, socket);
|
||||||
|
Thread sP = new Thread(serverPinger);
|
||||||
|
sP.start();
|
||||||
broadcastMessage("SERVER: " + clientUserName + " has joined the Server");
|
broadcastMessage("SERVER: " + clientUserName + " has joined the Server");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -53,6 +55,10 @@ public class ClientHandler implements Runnable {
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Socket getSocket() {
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
public static HashSet<ClientHandler> getConnectedClients() {
|
public static HashSet<ClientHandler> getConnectedClients() {
|
||||||
return connectedClients;
|
return connectedClients;
|
||||||
}
|
}
|
||||||
@ -65,31 +71,21 @@ public class ClientHandler implements Runnable {
|
|||||||
return ghostClients;
|
return ghostClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientMsgDecoder getClientMsgDecoder() {
|
|
||||||
return clientMsgDecoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Setters
|
//Setters
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
/**
|
/**
|
||||||
* The main logik of the client handler.
|
* The main logic of the client handler.
|
||||||
* Since every client is put on a string this is where
|
* Since every client is put on a string this is where
|
||||||
* most interactions between client and server are held..
|
* most interactions between client and server are held
|
||||||
*/
|
**/
|
||||||
public void run() {
|
public void run() {
|
||||||
String msg;
|
String msg;
|
||||||
NTtBFormatMsg response;
|
while (socket.isConnected()) {
|
||||||
while(socket.isConnected()) {
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
msg = in.readLine();
|
msg = in.readLine();
|
||||||
response = clientMsgDecoder.decodeMsg(msg); //The response of the server to the clients message
|
JServerProtocolParser.parse(msg, this);
|
||||||
out.write(response.getMessage());
|
|
||||||
out.newLine();
|
|
||||||
out.flush();
|
|
||||||
//TODO if merely an acknowledgement is sent back to the client, how does the client recieve game updates?
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
closeEverything(socket, in, out);
|
closeEverything(socket, in, out);
|
||||||
@ -102,20 +98,44 @@ public class ClientHandler implements Runnable {
|
|||||||
return clientUserName;
|
return clientUserName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets the client change their respective username, if the username is already taken, a similar option is chosen
|
||||||
|
* @param newName The desired new name to replace the old one with.
|
||||||
|
*/
|
||||||
|
public void changeUsername(String newName) {
|
||||||
|
if (AllClientNames.allNames("").contains(newName)) {
|
||||||
|
newName = NameGenerator.randomName(newName);
|
||||||
|
}
|
||||||
|
String h = this.clientUserName; //just a friendly little helper
|
||||||
|
this.clientUserName = newName;
|
||||||
|
AllClientNames.allNames(newName);
|
||||||
|
broadcastMessage(h +" have changed their nickname to " + clientUserName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcasts a Message to all active clients in the form "Username: msg"
|
||||||
|
* @param msg the Message to be broadcasted
|
||||||
|
*/
|
||||||
|
|
||||||
public void broadcastMessage(String msg) {
|
public void broadcastMessage(String msg) {
|
||||||
for (ClientHandler client : connectedClients) {
|
for (ClientHandler client : connectedClients) {
|
||||||
try {
|
client.sendMsgToClient("CHATM:" + clientUserName + ": \"" + msg + "\"");
|
||||||
if(!client.clientUserName.equals((clientUserName))) {
|
|
||||||
client.out.write(msg);
|
|
||||||
} else {
|
|
||||||
client.out.write("Message: **" + msg + "** sent!");
|
|
||||||
}
|
}
|
||||||
client.out.newLine();
|
}
|
||||||
client.out.flush();
|
|
||||||
|
//TODO: Documentation
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param msg
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void sendMsgToClient(String msg) {
|
||||||
|
try {
|
||||||
|
out.write(msg);
|
||||||
|
out.newLine();
|
||||||
|
out.flush();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
closeEverything(socket, in ,out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +161,7 @@ public class ClientHandler implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decodeMsg(String msg){
|
public void decodeMsg(String msg) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,96 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NTtBFormatMsg;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NightTrainProtocol;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NightTrainProtocol.NTtBCommands;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NoLegalProtocolCommandStringFoundException;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.ProtocolDecoder;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes the correctly formatted String containing command and parameters. For reasons of
|
|
||||||
* seperation of work this class only tokenizes the string and acknowledges to the client that smth
|
|
||||||
* was recieved. Actual method calls, change of state, method calles etc. are delegated to{@link
|
|
||||||
* ch.unibas.dmi.dbis.cs108.multiplayer.server.cmd.methods.CommandExecuter} from within {@link
|
|
||||||
* ClientHandler}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ClientMsgDecoder implements ProtocolDecoder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The point of contact for the ClientHandler who calls this method to convert a String in to
|
|
||||||
* usable, tokanized format defined by {@link NTtBFormatMsg}.
|
|
||||||
*
|
|
||||||
* @param msg coming from the client handlers input reader.
|
|
||||||
* @return {@link NTtBFormatMsg}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public NTtBFormatMsg decodeMsg(String msg) {
|
|
||||||
//Declare needed variables
|
|
||||||
String[] msgTokens; //List where we'll put the string tokens seperated by $.
|
|
||||||
String ackMsg; //The command token
|
|
||||||
String[] parameters;
|
|
||||||
NightTrainProtocol.NTtBCommands cmdObject;
|
|
||||||
//Initalize fields for return object
|
|
||||||
msgTokens = tokenizeMsg(msg);
|
|
||||||
ackMsg = serverResponseBuilder(msgTokens);
|
|
||||||
parameters = new String[msgTokens.length - 1];
|
|
||||||
cmdObject = getCommandConstant(msgTokens[0]);
|
|
||||||
return new NTtBFormatMsg(ackMsg, cmdObject, parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the server acknowledgement response witch is instantly sent back to the client. The
|
|
||||||
* response is merely that a command was recieved and which one.
|
|
||||||
* <p>
|
|
||||||
* If garbage was recieved a SEROR will be appended. It is assumed that the msgTokens array is not
|
|
||||||
* empty.
|
|
||||||
*
|
|
||||||
* @param msgTokens an array containing the command String
|
|
||||||
* @return a String containing the immediate response of the server to the client.
|
|
||||||
*/
|
|
||||||
private String serverResponseBuilder(String[] msgTokens) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
//assumes non-empty array!
|
|
||||||
sb.append("SERVER: ");
|
|
||||||
NightTrainProtocol.NTtBCommands cmd = getCommandConstant(msgTokens[0]);
|
|
||||||
|
|
||||||
if (cmd.equals(NTtBCommands.SEROR)) {
|
|
||||||
return cmd + "invalid input";
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append("Command *").append(cmd).append("* recieved!");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns the string into a command object. If no matching protocol command was found, it returns
|
|
||||||
* an SEROR type.
|
|
||||||
*
|
|
||||||
* @param stringToken String that should match the String representation of a NTtBCommands,java
|
|
||||||
* field.
|
|
||||||
* @return type {@link ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NightTrainProtocol.NTtBCommands}
|
|
||||||
* object
|
|
||||||
*/
|
|
||||||
private NightTrainProtocol.NTtBCommands getCommandConstant(String stringToken) {
|
|
||||||
try {
|
|
||||||
return NightTrainProtocol.getCmdEnumObject(stringToken);
|
|
||||||
} catch (NoLegalProtocolCommandStringFoundException e) {
|
|
||||||
return NightTrainProtocol.NTtBCommands.SEROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO What happens if there is no delimeter?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Splits the input string along the delimiter "$".
|
|
||||||
*
|
|
||||||
* @param msg Clients input
|
|
||||||
* @return an array of String objects containing the command and parameters of the message.
|
|
||||||
*/
|
|
||||||
private String[] tokenizeMsg(String msg) {
|
|
||||||
return msg.split("$");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
|
||||||
|
|
||||||
public class InSessionLogik {
|
|
||||||
Server server;
|
|
||||||
public InSessionLogik(Server server) {
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
||||||
|
|
||||||
|
|
||||||
|
public class JServerProtocolParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the server (i.e. ClientHandler) to parse an incoming protocol message.
|
||||||
|
*
|
||||||
|
* @param msg the encoded message that needs to be parsed
|
||||||
|
* @param h this ClientHandler (required so this method can access the ClientHandler's methods)
|
||||||
|
*/
|
||||||
|
public static void parse(String msg, ClientHandler h) {
|
||||||
|
String header = ""; //"header" is the first 5 characters, i.e. the protocol part
|
||||||
|
try {
|
||||||
|
header = msg.substring(0, 5);
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
System.out.println("Received unknown command");
|
||||||
|
}
|
||||||
|
//System.out.println(header); helpful for debugging
|
||||||
|
switch (header) {
|
||||||
|
case "CHATA":
|
||||||
|
h.broadcastMessage(msg.substring(6));
|
||||||
|
break;
|
||||||
|
case "NAMEC":
|
||||||
|
h.changeUsername(msg.substring(6));
|
||||||
|
break;
|
||||||
|
case "CPING":
|
||||||
|
h.sendMsgToClient("PINGB");
|
||||||
|
break;
|
||||||
|
case "PINGB":
|
||||||
|
h.serverPinger.setGotPingBack(true);
|
||||||
|
break;
|
||||||
|
case "QUITS":
|
||||||
|
h.closeEverything(h.getSocket(), h.getIn(), h.getOut());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
System.out.println("Received unknown command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,19 +2,29 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
|||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
// Creates a String beginning with "player_" followed by 4 random letters
|
|
||||||
|
|
||||||
public class NameGenerator {
|
public class NameGenerator {
|
||||||
static String randomName() {
|
|
||||||
StringBuilder name = new StringBuilder();
|
/**
|
||||||
|
* Creates a random alteration of a Name by adding 4 numbers at the end of the Name that shall be alterd
|
||||||
|
* @param username the to be altered username
|
||||||
|
* @return username + four numbers
|
||||||
|
*/
|
||||||
|
static String randomName(String username) {
|
||||||
|
StringBuilder name;
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
name = new StringBuilder();
|
||||||
Random r = new Random();
|
Random r = new Random();
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
char c = (char)(r.nextInt(26) + 'a');
|
int c = r.nextInt(10);
|
||||||
name.append(c);
|
name.append(c);
|
||||||
}
|
}
|
||||||
return "player_" + name;
|
if (!AllClientNames.allNames("").contains(username + name)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
public static void main (String[] args) {
|
|
||||||
System.out.println(randomName());
|
|
||||||
}
|
}
|
||||||
|
return username + name;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
|
||||||
|
|
||||||
public class NoCommandTokenException extends Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -26,6 +26,12 @@ public class Server {
|
|||||||
Thread th = new Thread(nextClient);
|
Thread th = new Thread(nextClient);
|
||||||
connectedClients.add(nextClient);
|
connectedClients.add(nextClient);
|
||||||
th.start();
|
th.start();
|
||||||
|
// close socket + remove client if client is disconnected
|
||||||
|
if (socket.getInputStream().read() == -1) {
|
||||||
|
System.out.println("client disconnected. closing socket");
|
||||||
|
socket.close();
|
||||||
|
connectedClients.remove(nextClient);
|
||||||
|
}
|
||||||
|
|
||||||
// close socket + remove client if client is disconnected
|
// close socket + remove client if client is disconnected
|
||||||
if (socket.getInputStream().read() == -1) {
|
if (socket.getInputStream().read() == -1) {
|
||||||
|
|||||||
@ -1,110 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server.cmd.methods;
|
|
||||||
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NTtBFormatMsg;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.protocol.NightTrainProtocol.NTtBCommands;
|
|
||||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This Class implements actually acting on the clients messages.
|
|
||||||
*/
|
|
||||||
public class CommandExecuter {
|
|
||||||
|
|
||||||
private ClientHandler caller;
|
|
||||||
private static String msgPrefix = "SERVER: ";
|
|
||||||
|
|
||||||
public void execute(NTtBFormatMsg msg) {
|
|
||||||
switch (msg.getCommand()) {
|
|
||||||
case CRTGM:
|
|
||||||
break;
|
|
||||||
case CHATA:
|
|
||||||
broadcastClientMsg(msg.getParameters());
|
|
||||||
break;
|
|
||||||
case CHATG:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case LEAVG:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case JOING:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case VOTEG:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case QUITS:
|
|
||||||
quitServer();
|
|
||||||
break;
|
|
||||||
case CHATW:
|
|
||||||
wisper(msg.getParameters());
|
|
||||||
break;
|
|
||||||
case LISTP:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case CUSRN:
|
|
||||||
changeNickname(msg.getParameters());
|
|
||||||
break;
|
|
||||||
case CPING:
|
|
||||||
pongS();
|
|
||||||
break;
|
|
||||||
case MSGRS:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case SEROR:
|
|
||||||
//TODO
|
|
||||||
break;
|
|
||||||
case SPING:
|
|
||||||
pongC();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.noCommand();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wisper(String[] parameters) {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeNickname(String[] parameters) {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private void quitServer() {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pongC() {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pongS() {
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
private void noCommand() {
|
|
||||||
try {
|
|
||||||
caller.getOut().write(msgPrefix + String.valueOf(NTtBCommands.NOCMD));
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("IOException in noCommand() in CommandExecuter.java");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* boradcast chat message to everyone
|
|
||||||
*
|
|
||||||
* @param parameters should only have one entry i.e. parameters.length == 1 should be true;
|
|
||||||
*/
|
|
||||||
private static void broadcastClientMsg(String[] parameters) {
|
|
||||||
try {
|
|
||||||
for (ClientHandler clients : ClientHandler.connectedClients) {
|
|
||||||
clients.getOut().write(parameters[0]);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("IOEXCEPTION in CommandExecuter.java at broadcastClientMsg");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server.cmd.methods;
|
|
||||||
|
|
||||||
public interface msgToMethod {
|
|
||||||
|
|
||||||
void quit();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the communication protocol in the connecting phase.
|
|
||||||
* After this one can consider the server and client in session;
|
|
||||||
*/
|
|
||||||
public class connectingLogik {
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user