Working on putting all protocol messages through Protocol.java.
Some small adjustments & bugfixes to how naming is handled. Added loggedIn boolean for ClientHandler, not meaningfully implemented yet though. Other minor changes.
This commit is contained in:
parent
3c94bd5324
commit
b6d2a04e76
@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user