Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
33d8f779a2
@ -4,6 +4,7 @@ import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger;
|
||||
|
||||
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
|
||||
import java.net.Socket;
|
||||
import java.io.*;
|
||||
import java.net.UnknownHostException;
|
||||
@ -36,7 +37,7 @@ public class Client {
|
||||
systemName = "U.N. Owen";
|
||||
}
|
||||
if (systemName == null) systemName = "U.N. Owen";
|
||||
sendMsgToServer("LOGON$" + systemName);
|
||||
sendMsgToServer(Protocol.clientLogin + "$" + systemName);
|
||||
|
||||
clientPinger = new ClientPinger(this, this.socket);
|
||||
} catch (IOException e) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package ch.unibas.dmi.dbis.cs108.multiplayer.client;
|
||||
|
||||
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@ -10,7 +11,7 @@ public class MessageFormatter {
|
||||
|
||||
/**
|
||||
* Takes a given Message and reformats it to where the JServerProtocolParser.parse() method can
|
||||
* handle it (see Protocol.txt). May need to be redesigned once the games uses a GUI
|
||||
* handle it (see Protocol.java). May need to be redesigned once the games uses a GUI
|
||||
*
|
||||
* @param msg the Messaged to be reformatted
|
||||
* @return the reformatted message in the form HEADR$msg
|
||||
@ -27,7 +28,7 @@ public class MessageFormatter {
|
||||
}
|
||||
switch (header) {
|
||||
case "/c":
|
||||
stringBuilder.append("CHATA$");
|
||||
stringBuilder.append(Protocol.chatMsgToAll + "$");
|
||||
try {
|
||||
s = msg.substring(3);
|
||||
} catch (Exception e) {
|
||||
@ -35,15 +36,15 @@ public class MessageFormatter {
|
||||
}
|
||||
break;
|
||||
case "/q":
|
||||
stringBuilder.append("QUITS$");
|
||||
stringBuilder.append(Protocol.clientQuitRequest + "$");
|
||||
s = "";
|
||||
break;
|
||||
case "/n":
|
||||
stringBuilder.append("NAMEC$");
|
||||
stringBuilder.append(Protocol.nameChange + "$");
|
||||
try {
|
||||
s = msg.substring(3);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Well what do you want your name to be?");
|
||||
s = "U.N. Owen";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package ch.unibas.dmi.dbis.cs108.multiplayer.helpers;
|
||||
|
||||
/**
|
||||
* This class is where the Protocol commands are saved as strings.
|
||||
* The idea is that every class that uses protocol messages does not
|
||||
* directly use e.g. "CHATA" in the code but rather uses
|
||||
* Protocol.chatMsgToAll. This improves legibility as well as
|
||||
* allowing for quick modification of Protocol messages if needed.
|
||||
* Most importantly, the Protocol commands can be documented in this
|
||||
* class, and then in every other class that uses protocol messages,
|
||||
* documentation for a command can be viewed by hovering over the
|
||||
* specific variable, rather than having to document everywhere.
|
||||
*/
|
||||
public class Protocol {
|
||||
|
||||
//BIDIRECTIONAL COMMANDS:
|
||||
|
||||
/**
|
||||
* Ping-back message from client to server / server to client.
|
||||
* To be sent upon receiving "CPING" / "SPING".
|
||||
* The other party then registers this in its ClientPinger / ServerPinger
|
||||
* thread.
|
||||
*/
|
||||
public static final String pingBack = "PINGB";
|
||||
|
||||
|
||||
//CLIENT TO SERVER COMMANDS:
|
||||
|
||||
/**
|
||||
* When the server receives this, it broadcasts a chat message
|
||||
* to all clients. The message has to be given in the protocol
|
||||
* message after {@code CHATA$}, for example the protocol message
|
||||
* {@code CHATA$Hello everybody!}, if sent from the user named Poirot,
|
||||
* will print {@code Poirot: Hello everybody!} to every connected
|
||||
* client's chat console (note the absence / presence of spaces).
|
||||
*/
|
||||
public static final String chatMsgToAll = "CHATA";
|
||||
|
||||
/**
|
||||
* The message sent by the client on login to set their name. For example,
|
||||
* {@code LOGIN$Poirot} will use the clientHandler.setUsernameOnLogin() method
|
||||
* to set this client's username to Poirot, and broadcast the announcement:
|
||||
* {@code "Poirot has joined the Server"}. Also, it will set this clientHandler's
|
||||
* loggedIn boolean to true, which could be used later to refuse access to users
|
||||
* who haven't formally logged in using this command => //todo: shun non-logged-in users
|
||||
*
|
||||
*/
|
||||
public static final String clientLogin = "LOGIN";
|
||||
|
||||
/**
|
||||
* todo:doc
|
||||
*
|
||||
*/
|
||||
public static final String nameChange = "NAMEC";
|
||||
|
||||
/**
|
||||
* todo:doc
|
||||
*/
|
||||
public static final String pingFromClient = "CPING";
|
||||
|
||||
/**
|
||||
* todo: doc
|
||||
*/
|
||||
public static final String clientQuitRequest = "QUITS";
|
||||
|
||||
}
|
||||
@ -19,8 +19,15 @@ public class ClientHandler implements Runnable {
|
||||
private BufferedReader in;
|
||||
private Socket socket;
|
||||
private InetAddress ip;
|
||||
private
|
||||
Scanner sc;
|
||||
|
||||
/**
|
||||
* notes if the client has formally logged in yet. If connecting through the normal Client class,
|
||||
* the client is logged in automatically, if connecting though some external application, the
|
||||
* client has to use the {@code Protocol.clientLogin} command.
|
||||
*/
|
||||
private boolean loggedIn;
|
||||
|
||||
private Scanner sc;
|
||||
public ServerPinger serverPinger;
|
||||
public static HashSet<ClientHandler> connectedClients = new HashSet<>();
|
||||
public static HashSet<ClientHandler> disconnectedClients = new HashSet<>(); //todo: implement re-connection
|
||||
@ -38,6 +45,7 @@ public class ClientHandler implements Runnable {
|
||||
this.socket = socket;
|
||||
this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||
this.in = new BufferedReader(new InputStreamReader((socket.getInputStream())));
|
||||
this.loggedIn = false;
|
||||
this.clientUserName = nameDuplicateChecker.checkName("U.N. Owen");
|
||||
connectedClients.add(this);
|
||||
serverPinger = new ServerPinger(socket, this);
|
||||
@ -73,7 +81,18 @@ public class ClientHandler implements Runnable {
|
||||
return ghostClients;
|
||||
}
|
||||
|
||||
//Setters
|
||||
public boolean isLoggedIn() {
|
||||
return loggedIn;
|
||||
}
|
||||
|
||||
public void setLoggedIn(boolean loggedIn) {
|
||||
this.loggedIn = loggedIn;
|
||||
}
|
||||
|
||||
//Setters:
|
||||
public String getClientUserName() {
|
||||
return clientUserName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@ -81,7 +100,7 @@ public class ClientHandler implements Runnable {
|
||||
String msg;
|
||||
while (socket.isConnected() && !socket.isClosed()) {
|
||||
try {
|
||||
msg = in.readLine(); //todo: here is where the server throws an exception when the client quits
|
||||
msg = in.readLine();
|
||||
JServerProtocolParser.parse(msg, this);
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
@ -92,9 +111,7 @@ public class ClientHandler implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public String getClientUserName() {
|
||||
return clientUserName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lets the client change their username, if the username is already taken, a similar
|
||||
@ -148,12 +165,10 @@ public class ClientHandler implements Runnable {
|
||||
|
||||
/** Sends a given message to client. The message has to already be protocol-formatted. ALL
|
||||
* communication with the client has to happen via this method!
|
||||
* todo: check for exception if out is closed.
|
||||
* @param msg the given message. Should already be protocol-formatted.
|
||||
*/
|
||||
public void sendMsgToClient(String msg) {
|
||||
try {
|
||||
//todo: socket closed handling
|
||||
out.write(msg);
|
||||
out.newLine();
|
||||
out.flush();
|
||||
|
||||
@ -4,6 +4,7 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.server;
|
||||
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
|
||||
|
||||
public class JServerProtocolParser {
|
||||
public static final Logger LOGGER = LogManager.getLogger();
|
||||
@ -17,6 +18,9 @@ public class JServerProtocolParser {
|
||||
|
||||
/**
|
||||
* Used by the server (i.e. ClientHandler) to parse an incoming protocol message.
|
||||
* For documentation on the individual Protocol messages, view the Protocol.java
|
||||
* class or hover over the commands (e.g. Protocol.chatMsgToAll) with your mouse
|
||||
* in this class.
|
||||
*
|
||||
* @param msg the encoded message that needs to be parsed
|
||||
* @param h this ClientHandler (required so this method can access the ClientHandler's methods)
|
||||
@ -30,33 +34,27 @@ public class JServerProtocolParser {
|
||||
System.out.println("Received unknown command");
|
||||
}
|
||||
switch (header) {
|
||||
case CHATA:
|
||||
//sends chat message to all connected clients
|
||||
case Protocol.chatMsgToAll:
|
||||
h.broadcastChatMessage(msg.substring(6));
|
||||
break;
|
||||
case "LOGON":
|
||||
//sets name to whatever follows LOGON$
|
||||
case Protocol.clientLogin:
|
||||
h.setLoggedIn(true);
|
||||
try {
|
||||
h.setUsernameOnLogin(msg.substring(6));
|
||||
} catch (Exception e) {
|
||||
h.setUsernameOnLogin("U.N. Owen");
|
||||
}
|
||||
break;
|
||||
case "NAMEC":
|
||||
//changes name to whatever follows NAMEC$. If the new name is already in use, it will append
|
||||
//random numbers to the name.
|
||||
case Protocol.nameChange:
|
||||
h.changeUsername(msg.substring(6));
|
||||
break;
|
||||
case "CPING":
|
||||
//sends a pingback to the client
|
||||
h.sendMsgToClient("PINGB");
|
||||
case Protocol.pingFromClient:
|
||||
h.sendMsgToClient(Protocol.pingBack);
|
||||
break;
|
||||
case "PINGB":
|
||||
//registers pingback from client
|
||||
case Protocol.pingBack:
|
||||
h.serverPinger.setGotPingBack(true);
|
||||
break;
|
||||
case "QUITS":
|
||||
//safely disconnects the user
|
||||
case Protocol.clientQuitRequest:
|
||||
h.removeClientOnLogout();
|
||||
break;
|
||||
default:
|
||||
|
||||
@ -54,13 +54,14 @@ public class nameDuplicateChecker {
|
||||
* Also, if the name is empty, it assigns a default value ("U.N. Owen").
|
||||
*/
|
||||
public static String checkName(String name) {
|
||||
String rtrn = name; //if this line is used, only duplicate names get a suffix.
|
||||
//String rtrn = extendName(name); //if this line is used, all clients get a suffix
|
||||
rtrn = rtrn.replace("$","");
|
||||
rtrn = rtrn.replace(":","");
|
||||
if (rtrn.equalsIgnoreCase("")) {rtrn = "U.N. Owen";}
|
||||
String tempname = name; //if this line is used, only duplicate names get a suffix.
|
||||
//String tempname = extendName(name); //if this line is used, all clients get a suffix
|
||||
tempname = tempname.replace("$","");
|
||||
tempname = tempname.replace(":","");
|
||||
if (tempname.equalsIgnoreCase("")) {tempname = "U.N. Owen";}
|
||||
String rtrn = tempname;
|
||||
while (isTaken(rtrn)) { //todo: handle the (very unlikely) case that all names are taken.
|
||||
rtrn = extendName(name);
|
||||
rtrn = extendName(tempname);
|
||||
}
|
||||
return rtrn;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.sebaschi;
|
||||
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
|
||||
import ch.unibas.dmi.dbis.cs108.gamelogic.Game;
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.client.Client;
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -11,7 +12,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This Class Represents an Object containing different Maps, Lists and Sets wherein a server object
|
||||
* can find all needed data. An instance of this object can also be passed to other class-objects uf
|
||||
* can find all needed data. An instance of this object can also be passed to other class-objects if
|
||||
* they need the same data. This Class is used to query for information in collections.
|
||||
*/
|
||||
public class CentralServerData {
|
||||
@ -19,11 +20,11 @@ public class CentralServerData {
|
||||
public static final Logger LOGGER = LogManager.getLogger();
|
||||
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
|
||||
|
||||
private Set<Client> clientsOnServer;
|
||||
private Set<ClientHandler> clientsOnServer;
|
||||
private Set<Game> activeGames;
|
||||
private Set<Game> gamesOpenToJoin;
|
||||
|
||||
private Map<Client, Socket> clientSocketMap;
|
||||
private Map<Socket, Client> socketClientMap;
|
||||
private Map<Game, Client> gameClientMap;
|
||||
private Map<ClientHandler, Socket> clientSocketMap;
|
||||
private Map<Socket, ClientHandler> socketClientMap;
|
||||
private Map<Game, ClientHandler> gameClientMap;
|
||||
}
|
||||
|
||||
@ -1,5 +1,67 @@
|
||||
package ch.unibas.dmi.dbis.cs108.sebaschi;
|
||||
|
||||
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Lobby one is in after a client sends the CRTGM command. THe Server
|
||||
*/
|
||||
public class Lobby {
|
||||
|
||||
private static final int MAX_NO_OF_CLIENTS = 6;
|
||||
private static int lobbies;
|
||||
|
||||
/**
|
||||
* The Person who created the game and can configure it and decide to start once enough players
|
||||
* have entered the lobby.
|
||||
*/
|
||||
private final ClientHandler admin;
|
||||
|
||||
/**
|
||||
* Everyone who's in the lobby.
|
||||
*/
|
||||
private List<ClientHandler> players = new ArrayList<>(6);
|
||||
|
||||
|
||||
private int numberOfPlayersInLobby;
|
||||
private final int lobbyID = lobbies++;
|
||||
|
||||
|
||||
static {
|
||||
lobbies = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor. Sets the admin to who created the lobby. Adds the admin to the list of players.
|
||||
* Increases the number of players from 0 to 1.
|
||||
*
|
||||
* @param admin the Client who called CRTGM
|
||||
*/
|
||||
public Lobby(ClientHandler admin) {
|
||||
this.admin = admin;
|
||||
this.players.add(admin);
|
||||
this.numberOfPlayersInLobby = 1;
|
||||
lobbies++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter
|
||||
*
|
||||
* @return the admin of the lobby.
|
||||
*/
|
||||
public ClientHandler getAdmin() {
|
||||
return this.admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the lobby.
|
||||
*
|
||||
* @param player who wants to join the lobby.
|
||||
*/
|
||||
public void addPlayer(ClientHandler player) {
|
||||
players.add(player);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user