Deleted unused classes, implemented whisper chat, other small fixes & adjustments.

This commit is contained in:
Jonas 2022-04-12 22:16:34 +02:00
parent 8aad32bd2d
commit 503808941b
14 changed files with 77 additions and 252 deletions

View File

@ -5,7 +5,7 @@ import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
import ch.unibas.dmi.dbis.cs108.sebaschi.CentralClientData;
import java.net.Socket;
import java.io.*;
import java.net.UnknownHostException;
@ -24,7 +24,6 @@ public class Client {
private BufferedWriter out;
public ClientPinger clientPinger;
private CentralClientData data;
public Client(Socket socket) {
try {
@ -180,9 +179,6 @@ public class Client {
}
public CentralClientData getData(){
return this.data;
}
public Socket getSocket() {
return socket;

View File

@ -45,7 +45,7 @@ public class MessageFormatter {
}
break;
case "/q":
stringBuilder.append(Protocol.clientQuitRequest + "$");
stringBuilder.append(Protocol.clientQuitRequest);
s = "";
break;
case "/n":
@ -57,13 +57,13 @@ public class MessageFormatter {
}
break;
case "/g":
stringBuilder.append(Protocol.createNewLobby + "$");
s = ""; //command has no parameters
stringBuilder.append(Protocol.createNewLobby);
break;
case "/l":
//LISTL command
stringBuilder.append(Protocol.listLobbies + "$");
s = ""; //Command has no parameters
stringBuilder.append(Protocol.listLobbies);
break;
case "/p":
stringBuilder.append(Protocol.listPlayersInLobby);
break;
case "/j":
stringBuilder.append(Protocol.joinLobby + "$");
@ -72,6 +72,16 @@ public class MessageFormatter {
} catch (Exception ignored) {
}
break;
case "/w":
stringBuilder.append(Protocol.whisper + "$");
try {
s = msg.substring(3);
} catch (Exception ignored) {
}
break;
case "/e":
stringBuilder.append(Protocol.leaveLobby);
break;
default:
s = msg;
}

View File

@ -1,5 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.helpers;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.Lobby;
/**
* 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
@ -87,7 +89,7 @@ public class Protocol {
* Client sends this message when they want to create a new game.
* Client issues this command in {@link ch.unibas.dmi.dbis.cs108.multiplayer.client.MessageFormatter}
* using "/g".
* First a lobby {@link ch.unibas.dmi.dbis.cs108.sebaschi.Lobby} is created of which the requesting client is the admin of.
* First a lobby {@link Lobby} is created of which the requesting client is the admin of.
*/
public static final String createNewLobby = "CRTLB";
@ -114,7 +116,7 @@ public class Protocol {
public static final String leaveLobby = "LEAVL";
/**
* Whisper chat
* Whisper chat. Syntax: {@code WHISP$recipient's username$message}
*/
public static final String whisper ="WHISP";

View File

@ -3,8 +3,7 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.server;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger;
import ch.unibas.dmi.dbis.cs108.sebaschi.CentralServerData;
import ch.unibas.dmi.dbis.cs108.sebaschi.Lobby;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
@ -18,8 +17,6 @@ public class ClientHandler implements Runnable {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
CentralServerData serverData; //todo: does this really need to be instantiated?
private String clientUserName;
private BufferedWriter out;
private BufferedReader in;
@ -45,13 +42,12 @@ public class ClientHandler implements Runnable {
* @param ip the ip of the client, used for re-connection.
* @param socket the socket on which to make the connection.
*/
public ClientHandler(Socket socket, InetAddress ip, CentralServerData serverData) {
public ClientHandler(Socket socket, InetAddress ip) {
try {
this.serverData = serverData;
this.ip = ip;
this.socket = socket;
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.loggedIn = false;
this.clientUserName = nameDuplicateChecker.checkName("U.N. Owen");
connectedClients.add(this);
@ -119,7 +115,6 @@ public class ClientHandler implements Runnable {
/**
* Lets the client change their 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) {
@ -149,12 +144,10 @@ public class ClientHandler implements Runnable {
/**
* Returns the Lobby this ClientHandler is in. If this ClientHandler is not in a Lobby,
* it returns null.
* @return
*/
public Lobby getLobby() {
try {
Lobby l = Lobby.getLobbyFromID(Lobby.clientIsInLobby(this));
return l;
return Lobby.getLobbyFromID(Lobby.clientIsInLobby(this));
} catch (Exception e) {
return null;
}
@ -229,7 +222,17 @@ public class ClientHandler implements Runnable {
}
/**
* Sends a given message to client. The message has to already be protocol-formatted. ALL
* Sends a message only to the specified user, as well as sending a confirmation to the user who sent the message
* that it has been sent. Syntax:
* @param target MUST NOT BE NULL!
*/
public void whisper(String msg, ClientHandler target) {
target.sendMsgToClient(Protocol.printToClientChat + "$" + this.getClientUserName() + " whispers: " + msg);
sendMsgToClient(Protocol.printToClientChat + "$You whispered to " + target.getClientUserName() + ": " + msg);
}
/**
* Sends a given message to this client. The message has to already be protocol-formatted. ALL
* communication with the client has to happen via this method!
*
* @param msg the given message. Should already be protocol-formatted.
@ -247,6 +250,11 @@ public class ClientHandler implements Runnable {
}
}
/**
* Sends an announcement to just this client. Essentially the same as broadcastAnnouncementToAll except
* it only sends an announcement to just this client instead of everyone.
* Can be used for private non-chat messages (e.g. "You are now a ghost").
*/
public void sendAnnouncementToClient(String msg) {
sendMsgToClient(Protocol.printToClientConsole + "$" + msg);
}
@ -261,8 +269,7 @@ public class ClientHandler implements Runnable {
public void removeClientOnConnectionLoss() {
connectedClients.remove(this);
disconnectClient();
serverData.removeClientFromSetOfAllClients(this); //todo: delete?
serverData.removeClientFromLobby(this); //todo: do this via Lobby class directly.
leaveLobby();
broadcastAnnouncementToAll(getClientUserName() + " has left the server due to a connection loss.");
disconnectedClients.add(this);
}
@ -276,8 +283,7 @@ public class ClientHandler implements Runnable {
broadcastAnnouncementToAll(getClientUserName() + " has left the server.");
sendMsgToClient(Protocol.serverConfirmQuit);
connectedClients.remove(this);
serverData.removeClientFromSetOfAllClients(this); //todo: delete?
serverData.removeClientFromLobby(this); //todo: do this via Lobby class directly.
leaveLobby();
disconnectClient();
}
@ -288,7 +294,6 @@ public class ClientHandler implements Runnable {
public void createNewLobby() {
if (Lobby.clientIsInLobby(this) == -1) {
Lobby newGame = new Lobby(this);
serverData.addLobbyToListOfAllLobbies(newGame);
} else {
sendAnnouncementToClient("You are already in lobby nr. " + Lobby.clientIsInLobby(this));
}
@ -310,12 +315,13 @@ public class ClientHandler implements Runnable {
}
/**
* If the client is in a Lobby, they leave it. Otherwise, this method does nothing.
*/
public void leaveLobby() {
Lobby l = Lobby.getLobbyFromID(Lobby.clientIsInLobby(this));
if (l != null) {
l.removePlayer(this);
} else {
sendMsgToClient(Protocol.printToClientConsole + "$Unable to leave lobby.");
}
}
@ -354,6 +360,10 @@ public class ClientHandler implements Runnable {
}
}
/**
* Lists all players in the client's lobby. If the client is not in a Lobby, it will say
* "You are not in a lobby."
*/
public void listPlayersInLobby() {
Lobby l = getLobby();
if (l != null) {
@ -366,7 +376,7 @@ public class ClientHandler implements Runnable {
}
}
} else {
sendAnnouncementToClient("You are not in a Lobby.");
sendAnnouncementToClient("You are not in a lobby.");
}
}

View File

@ -11,11 +11,6 @@ public class JServerProtocolParser {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
/**
* jsdcjkhcsdjksdacjkn
*/
public static final String CHATA = "CHATA";
/**
* Used by the server (i.e. ClientHandler{@link ClientHandler}) to parse an incoming protocol
@ -40,6 +35,25 @@ public class JServerProtocolParser {
case Protocol.chatMsgToLobby:
h.broadcastChatMessageToLobby(msg.substring(6));
break;
case Protocol.whisper:
//find ClientHandler
try {
ClientHandler target = null;
String targetName = msg.substring(6, msg.indexOf("$", 6));
String chatMsg = msg.substring(msg.indexOf("$", 6)+1);
System.out.println(targetName);
System.out.println(chatMsg);
for (ClientHandler c : ClientHandler.getConnectedClients()) {
if (c.getClientUserName().equals(targetName)) {
target = c;
}
}
assert target != null;
h.whisper(chatMsg, target);
} catch (Exception ignored) {
h.sendAnnouncementToClient("Something went wrong.");
}
break;
case Protocol.clientLogin:
h.setLoggedIn(true);
try {

View File

@ -1,7 +1,7 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
import java.util.HashSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -10,7 +10,6 @@ import org.apache.logging.log4j.Logger;
* Use: If a client sends a CRTLB command the server should create a lobby with the client as admin.
* In this state, up to 5 other clients (so 6 in total) are able to join this lobby. Once the admin
* feels like it, they can start a game.
* TODO: is all data in here or should GameSessionData be used to collect all relevant data?
*/
public class Lobby {
@ -20,8 +19,6 @@ public class Lobby {
private static final int MAX_NO_OF_CLIENTS = 6;
//TODO
CentralServerData serverData; //todo: do we need this?
/**
* The Person who created the game and can configure it and decide to start once enough lobbyClients
@ -52,7 +49,7 @@ public class Lobby {
helper++;
}
this.lobbyID = helper;
admin.broadcastAnnouncementToAll("New Lobby created by " + admin.getClientUserName() +
ClientHandler.broadcastAnnouncementToAll("New Lobby created by " + admin.getClientUserName() +
". This lobby's ID: " + this.lobbyID);
}
@ -67,8 +64,7 @@ public class Lobby {
/**
* getter for the lobby ID
*
* @return lobbyID as set in constructor based on number of lobbies.
* @return lobbyID as set in constructor.
*/
public int getLobbyID() {
return this.lobbyID;
@ -121,7 +117,7 @@ public class Lobby {
if (lobbyClients.size() < MAX_NO_OF_CLIENTS) {
if (clientIsInLobby(client) == -1) {
lobbyClients.add(client);
client.broadcastAnnouncementToAll(client.getClientUserName() + " has joined lobby " + this.getLobbyID());
ClientHandler.broadcastAnnouncementToAll(client.getClientUserName() + " has joined lobby " + this.getLobbyID());
//LOGGER.debug(client.getClientUserName() + " has been added to Lobby with ID: " + lobbyID
// + ". Current number of lobbyClients in this lobby: " + lobbyClients.size());
return true;

View File

@ -1,7 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.sebaschi.CentralServerData;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
@ -13,7 +13,6 @@ import org.apache.logging.log4j.Logger;
public class Server {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
private static CentralServerData allData = new CentralServerData();
private static final int gamePort = 42069;
private HashSet<ClientHandler> connectedClients = new HashSet<>();
@ -32,10 +31,9 @@ public class Server {
System.out.println("Port 42069 is open.");
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress(), allData);
ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress());
Thread th = new Thread(nextClient);
connectedClients.add(nextClient); // will leave be for now
allData.addClientToSetOfAllClients(nextClient);
th.start();
}
} catch (IOException e) {

View File

@ -1,10 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
/**
* Each Clients copy of data. In principle it is CentralServerData.
* The Client must update himself.
*/
public class CentralClientData extends CentralServerData{
}

View File

@ -1,106 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* todo: this class is not meaningfully used now, we could probably delete it?
*
*
* 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 if
* they need the same data. This Class is used to query for information in collections.
*/
public class CentralServerData {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
//TODO which datastructures should be used here?
//TODO Static or non static?
private static Set<ClientHandler> clientsOnServer;
private static List<Lobby> allLobbies;
private static Map<Integer, Lobby> lobbyIDMap;
public CentralServerData() {
clientsOnServer = new HashSet<>();
allLobbies = new ArrayList<>();
lobbyIDMap = new HashMap<>();
}
//Getters
/**
* Getter for set of all clients.
*
* @return the set of all clients.
*/
public Set<ClientHandler> getClientsOnServer() {
return clientsOnServer;
}
/**
* Used to add the client to the set of all clients on server.
*
* @param client
*/
public synchronized void addClientToSetOfAllClients(ClientHandler client) {
this.getClientsOnServer().add(client);
}
/**
* Remove a client from the set of clients. Used in ClientHandler.disconnectClient().
*
* @param client to be removed.
*/
public synchronized void removeClientFromSetOfAllClients(ClientHandler client) {
//TODO implement or make sure something equivalent is implemented somewhere else
this.getClientsOnServer().remove(client);
LOGGER.debug(client.getClientUserName() + " removed from CentralServerData list of clients.");
}
public synchronized void removeClientFromLobby(ClientHandler client) {
boolean foundAndRemoved = false;
for (Lobby l : allLobbies) {
foundAndRemoved = l.removePlayer(client);
}
LOGGER.debug("foundAndRemoved value: " + foundAndRemoved);
}
/**
* Getter for List of all lobbies.
*
* @return a list of all lobbies
*/
public List<Lobby> getAllLobbies() {
return allLobbies;
}
/**
* Does exactly what it says on the box.
*
* @param lobby
*/
public synchronized void addLobbyToListOfAllLobbies(Lobby lobby) {
allLobbies.add(lobby);
}
/**
* Mapping from an Integer that repesents a LobbyID to the lobby should be set in {@link Lobby}
* and is then used by clients to join a lobby.
*
* @return a mapping from Integer to Lobby.
*/
public Map<Integer, Lobby> getLobbyIDMap() {
return lobbyIDMap;
}
}

View File

@ -1,18 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Attributes of a client visible to server.
*/
public class ClientAttributes {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
private String clientUserName;
private boolean loggedIn;
private boolean isInALobby;
private Lobby clientsLobby;
}

View File

@ -1,25 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Ghost;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Passenger;
import java.io.BufferedOutputStream;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Class that shall contain all non-game logic information relevant to a game session needed for
* client-server and client-client communication.
*/
public class GameSessionData {
public static final Logger LOGGER = LogManager.getLogger();
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
CentralServerData globalData;
Set<Passenger> passengers;
Set<BufferedOutputStream> clientOutputStreams;
Set<Ghost> ghosts;
}

View File

@ -1,8 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
/**
* Implement the login sequenz when a client wnats to connect to the server.
*/
public class LoginClient {
//TODO implement if needed
}

View File

@ -1,25 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
import java.util.ArrayList;
import java.util.List;
/**
* This class is just everyone on the server, which games are open to join, who is in session. I.E.
* the context of the game just after joining the server, before starting a game and entering into a
* lobby.
*/
public class ServerLobby {
private static List<Lobby> openLobbies;
private static List<ClientHandler> allClients;
static {
openLobbies = new ArrayList<>();
allClients = new ArrayList<>();
}
public static List<Lobby> getOpenLobbies() {
return openLobbies;
}
}

View File

@ -1,9 +0,0 @@
package ch.unibas.dmi.dbis.cs108.sebaschi;
import java.util.ArrayList;
import java.util.List;
public class Session {
List<Lobby> Lobbies = new ArrayList<>();
}