Removed some ToDos that are done and started creating a Spectator class and I'm in the process of ensuring only non kicked off passengers vote

This commit is contained in:
Seraina 2022-04-15 23:22:38 +02:00
parent 82a4e42b3c
commit d389a8fbb0
12 changed files with 137 additions and 41 deletions

View File

@ -44,7 +44,7 @@ public class ClientVoteData {
try {
this.vote[position] = vote;
} catch (IndexOutOfBoundsException e) {
LOGGER.info("Position is: " + position);
LOGGER.warn("Position is: " + position);
}
}
@ -54,6 +54,10 @@ public class ClientVoteData {
* @param hasVoted the vote state value
*/
public void setHasVoted(int position, boolean hasVoted) {
this.hasVoted[position] = hasVoted;
try {
this.hasVoted[position] = hasVoted;
} catch (Exception e) {
LOGGER.warn("Position is:" + position);
}
}
}

View File

@ -26,7 +26,6 @@ public class Game implements Runnable {
private Lobby lobby;
private String name;
private static int nameCounter = 0;
//TODO: Figure out where Day/Night game state is saved maybe think about a game state class or smt.
/**
* Constructs a Game instance where:
*
@ -35,7 +34,7 @@ public class Game implements Runnable {
* @param nrOfUsers is the number of active users at the time (non NPCs)
*/
public Game(int nrOfPlayers, int nrOfGhosts, int nrOfUsers, Lobby lobby)
throws TrainOverflow { //ToDo: Who handles Exception how and where
throws TrainOverflow {
this.gameState = new GameState(nrOfPlayers, nrOfGhosts, nrOfUsers);
this.lobby = lobby;
nameCounter++;
@ -63,7 +62,6 @@ public class Game implements Runnable {
* currently at gameState.train[3] fills the passengerTrain moving from left to rigth in the
* gameState.train array it connects clientHandlers witch the passengers in those positions
* (Players) and fills the rest with NPC's
* TODO: set ghost in a random position(i), gameState.train[i] so that a lone player can also start as a Ghost maybe use Train class
*/
@Override
public void run() {
@ -76,7 +74,7 @@ public class Game implements Runnable {
LOGGER.info(gameState.toString());
for (ClientHandler client : lobbyClients) { //TODO(Seraina): Adjust for lobbies
for (ClientHandler client : lobbyClients) {
int index = order[i];
if (passengerTrain[index].getIsGhost()) { //if there is a ghost
GhostPlayer ghostPlayer = new GhostPlayer(passengerTrain[index].getPosition(),
@ -104,7 +102,7 @@ public class Game implements Runnable {
LOGGER.info(gameState.toString());
i = 0;
while (true) { //ToDo: was ist die Abbruchbedingung? VoteHandler muss das schicken.
while (true) {
if (!isDay) {
LOGGER.info("NIGHT");
voteHandler.ghostVote(gameState.getPassengerTrain(), this);

View File

@ -44,7 +44,7 @@ public class GameState {
* @throws TrainOverflow if nrOfPlayers < nrOfUsers
*/
GameState(int nrOfPlayers, int nrOfGhosts, int nrOfUsers)
throws TrainOverflow { //ToDo: where will Exception be handled?
throws TrainOverflow {
this.nrOfPlayers = nrOfPlayers;
this.nrOfGhosts = nrOfGhosts;
this.nrOfUsers = nrOfUsers;
@ -52,7 +52,7 @@ public class GameState {
clientVoteData = new ClientVoteData();
Passenger[] passengerTrain = new Passenger[nrOfPlayers]; //Creates an array with Passengers with correlation positions (Train)
for (int i = 0; i < nrOfPlayers; i++) {
if (i == train.getPositionOfGhost()) { //TODO: randomize via Train.ghostposition
if (i == train.getPositionOfGhost()) {
LOGGER.info("OG position: " + train.getOrderOfTrain()[i]);
Ghost g = new Ghost();
g.setPosition(train.getOrderOfTrain()[i]);

View File

@ -5,6 +5,7 @@ import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Ghost;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.GhostNPC;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.GhostPlayer;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Passenger;
import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Spectator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -18,7 +19,7 @@ public class GhostifyHandler {
* @param p Passenger to be ghostified
*/
public Ghost ghost(Passenger p, Game game) { //TODO: Adjust for not only players but also npcs
public static Ghost ghost(Passenger p, Game game) {
LOGGER.debug("Passenger Position " + p.getPosition());
Ghost g;
if (p.getIsPlayer()) {
@ -41,4 +42,24 @@ public class GhostifyHandler {
LOGGER.info("Passenger at position " + p.getPosition() + " has been ghostified");
return g;
}
/**
* Handles a Kick Off event. If the passenger to be kicked off is a Player, the Player will be converted
* into a Spectator to watch the game.
* @param passenger to be kicked off the train
* @param game the game the train and passenger are in
* @return either a new spectator or the oly passenger now with kickeckedOff true
*/
public static Passenger kickOff (Passenger passenger, Game game) {
if (passenger.getIsPlayer()) {
Spectator spectator = new Spectator(passenger.getPosition(), passenger.getName());
spectator.setClientHandler(passenger.getClientHandler());
spectator.setPlayer(true);
game.gameState.addNewPassenger(spectator, passenger.getPosition());
return spectator;
} else {
passenger.setKickedOff(true);
return passenger;
}
}
}

View File

@ -14,7 +14,6 @@ import org.apache.logging.log4j.Logger;
* Handles all communications Server to Client concerning game state or game state related requests
* - Needs a possibility to only send to Ghosts
* - and only humans
* TODO: Figure out what format the messages have, consider protocol add what is needed dont forget about parsing
*/
public class ServerGameInfoHandler {
@ -24,15 +23,17 @@ public class ServerGameInfoHandler {
/**
* Gets a string msg from somewhere and formats it into protocol messages
* @param msg the message to be formatted
* @param passenger the passenger getting the message
* @param game the game in wich the passenger lives
* @return a message in a protocol format
*/
public static String format(String msg, Passenger p, Game game) {
public static String format(String msg, Passenger passenger, Game game) {
switch (msg) {
case ClientGameInfoHandler.ghostVoteRequest:
msg = Protocol.serverRequestsGhostVote + "$" + p.getPosition() +"$" + game.gameState.toString();
msg = Protocol.serverRequestsGhostVote + "$" + passenger.getPosition() +"$" + game.gameState.toString();
break;
case ClientGameInfoHandler.humanVoteRequest:
msg = Protocol.serverRequestsHumanVote + "$" + p.getPosition() +"$"+ game.gameState.humanToString();
msg = Protocol.serverRequestsHumanVote + "$" + passenger.getPosition() +"$"+ game.gameState.humanToString();
break;
default:
msg = Protocol.printToClientConsole + "$"+ msg;
@ -41,6 +42,18 @@ public class ServerGameInfoHandler {
return msg;
}
/**
* //TODO(Seraina): implementation
* Formartiert Nachrichten die für einen Spectator gedacht sind.
* @param msg the message to be formatted
* @param passenger the passenger getting the message
* @param game the game in wich the passenger lives
* @return a message in a protocol format
*/
public static String spectatorFormat(String msg, Passenger passenger, Game game) {
return msg;
}
/**
* Chooses for an NPC what they want to say, so they don't sound the same all the time
* @return a String saying that sm heard sm noise
@ -50,8 +63,8 @@ public class ServerGameInfoHandler {
String b = "noise";
String c = "I heard smt strange tonight";
String d = "Me, noise!";
String e = "Uuuuh, spoky noises";
int number = (int)(Math.random()*4);
String e = "Uuuuh, spoky sounds";
int number = (int)(Math.random()*5);
switch (number) {
case 0:
return a;

View File

@ -22,7 +22,7 @@ public class Train {
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?
throw new TrainOverflow();
}
int[] userTrain = new int[nrOfPlayers];

View File

@ -15,7 +15,7 @@ import org.apache.logging.log4j.Logger;
*
* <p>(All messages going to Clients are handled via ServerGameInfoHandler)
*
* <p>TODO: Think about if the timer needs to be implemented here or in the Game class
* <p>
*/
public class VoteHandler {
public static final Logger LOGGER = LogManager.getLogger(VoteHandler.class);
@ -57,7 +57,7 @@ public class VoteHandler {
LOGGER.warn("Thread " + Thread.currentThread() + " was interrupted");
}
int currentMax = voteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game);
int currentMax = ghostVoteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game);
LOGGER.debug("Most votes: " + currentMax + " vote");
@ -71,11 +71,11 @@ public class VoteHandler {
}
}
LOGGER.info("Most votes for: " + ghostPosition);
GhostifyHandler gh = new GhostifyHandler();
Ghost g = gh.ghost(passengers[ghostPosition], game);
Ghost g = GhostifyHandler.ghost(passengers[ghostPosition], game);
passengers[ghostPosition] = g;
passengers[ghostPosition].send(
ClientGameInfoHandler.youGotGhostyfied, game); // TODO: ServerGameInfoHandler might deal with this one
ClientGameInfoHandler.youGotGhostyfied, game);
try { // waits 20 seconds before votes get collected
Thread.sleep(10);
} catch (InterruptedException e) {
@ -127,7 +127,6 @@ public class VoteHandler {
int[] votesForPlayers = new int[6];
// Walk through entire train, ask humans to vote and ghosts to wait
// TODO: Messages in for-loop should probably be handled by ServerGameInfoHandler
for (Passenger passenger : passengers) {
if (passenger.getIsGhost()) {
passenger.send(ClientGameInfoHandler.itsDayTime, game);
@ -142,7 +141,7 @@ public class VoteHandler {
LOGGER.warn("Thread " + Thread.currentThread() + " was interrupted");
}
int currentMax = voteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game);
int currentMax = humanVoteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game);
// deal with voting results
int voteIndex = 0;
@ -156,12 +155,12 @@ public class VoteHandler {
.getIsGhost()) { // if player with most votes is human, notify everyone about it
for (Passenger passenger : passengers) {
passenger.send(
ClientGameInfoHandler.humansVotedFor + voteIndex + ClientGameInfoHandler.isAHuman, game); // TODO: ServerGameInfoHandler might be better to use here
ClientGameInfoHandler.humansVotedFor + voteIndex + ClientGameInfoHandler.isAHuman, game);
}
}
if (passengers[voteIndex].getIsGhost()) { // if player is a ghost
if (passengers[voteIndex].getIsOG()) { // if ghost is OG --> end game, humans win
System.out.println(ClientGameInfoHandler.gameOverHumansWin); // TODO: correctly handle end of game
System.out.println(ClientGameInfoHandler.gameOverHumansWin);
return ClientGameInfoHandler.gameOverHumansWin;
} else {
/* Special case: if ghost is not OG and if only one human is left (--> last human didn't vote for OG ghost),
@ -179,7 +178,7 @@ public class VoteHandler {
}
// Usual case: there is more than one human left and a normal ghost has been voted for -->
// kick this ghost off
passengers[voteIndex].setKickedOff(true);
passengers[voteIndex] = GhostifyHandler.kickOff(passengers[voteIndex], game);
for (Passenger passenger : passengers) {
passenger.send("Player " + voteIndex + ClientGameInfoHandler.gotKickedOff, game);
}
@ -220,7 +219,7 @@ public class VoteHandler {
}
/**
* Collecting the votes - distribute them among the vote counters for all players. Note: each voting collects
* Collecting the votes of Ghosts- distribute them among the vote counters for all players. Note: each voting collects
* votes for all players even though some might not be concerned (i.e. ghosts during ghost vote). Those players
* will then get 0 votes so it dosen't matter. Returns the max amount of votes a player received.
* @param passengers train passengers
@ -228,10 +227,41 @@ public class VoteHandler {
* @param data deals with Client votes
* @param game current game instance
*/
int voteEvaluation(Passenger[] passengers, int[] votesForPlayers, ClientVoteData data, Game game) {
int ghostVoteEvaluation(Passenger[] passengers, int[] votesForPlayers, ClientVoteData data, Game game) {
for (Passenger passenger : passengers) {
passenger.getVoteFromGameState(data, game);
if (passenger.getHasVoted()) {
if (passenger.getHasVoted() && passenger.getIsGhost() && !passenger.getKickedOff()) {
for (int i = 0; i < votesForPlayers.length; i++) {
if (passenger.getVote() == i) {
votesForPlayers[i]++;
}
}
}
}
/* count the votes - determine which player has the most votes by going through the
votesForPlayers array */
int currentMax = 0;
for (int votesForPlayer : votesForPlayers) {
if (votesForPlayer > currentMax) {
currentMax = votesForPlayer;
}
}
return currentMax;
}
/**
* Collecting the votes of Humans - distribute them among the vote counters for all players. Note: each voting collects
* votes for all players even though some might not be concerned (i.e. ghosts during ghost vote). Those players
* will then get 0 votes so it dosen't matter. Returns the max amount of votes a player received.
* @param passengers train passengers
* @param votesForPlayers array collecting the votes each player received during a voting
* @param data deals with Client votes
* @param game current game instance
*/
int humanVoteEvaluation(Passenger[] passengers, int[] votesForPlayers, ClientVoteData data, Game game) {
for (Passenger passenger : passengers) {
passenger.getVoteFromGameState(data, game);
if (passenger.getHasVoted() && !passenger.getIsGhost() && !passenger.getKickedOff()) {
for (int i = 0; i < votesForPlayers.length; i++) {
if (passenger.getVote() == i) {
votesForPlayers[i]++;

View File

@ -17,7 +17,7 @@ public class Passenger {
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 isOG = false; //true if the player is the original ghost, false by default.
protected boolean isPlayer; //same here
protected boolean kickedOff; //true if the player has been voted off.
protected boolean kickedOff; //true if the player has been voted off
protected ClientHandler clientHandler;//the socket for the client associated with this Passenger, for NPCs, this can be null.
protected boolean hasVoted; //true if the player gave his vote during voting time
protected int vote; //saves the number of the player this passenger voted for during voting (0-5)
@ -67,6 +67,14 @@ public class Passenger {
isOG = true;
}
public void setPlayer(boolean player) {
isPlayer = player;
}
public void setClientHandler(ClientHandler clientHandler) {
this.clientHandler = clientHandler;
}
public int getPosition() {
return position;
}

View File

@ -0,0 +1,29 @@
package ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.gamelogic.Game;
import ch.unibas.dmi.dbis.cs108.gamelogic.ServerGameInfoHandler;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* A class for all Players that have been kicked off, where they can observe everything
*/
public class Spectator extends Passenger{
public static final Logger LOGGER = LogManager.getLogger(Spectator.class);
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
public Spectator(int position, String name) {
this.position = position;
this.name = name;
isGhost = false;
isPlayer = true;
kickedOff = true;
}
@Override
public void send(String msg, Game game) {
clientHandler.sendMsgToClient(ServerGameInfoHandler.format(msg, this, game));
}
}

View File

@ -50,13 +50,11 @@ public class JClientProtocolParser {
LOGGER.debug("Ghost received Vote request");
System.out.println("Ghost Vote:");
c.positionSetter(msg.substring(6));
//TODO(Seraina): How can be enforced, that clients won't vote otherwise? Trigger a methode here that listens to input
break;
case Protocol.serverRequestsHumanVote:
LOGGER.debug("Human received Vote request");
System.out.println("Human Vote:");
c.positionSetter(msg.substring(6));
//TODO(Seraina): How can be enforced, that clients won't vote otherwise? Trigger a methode here that listens to input
break;
case Protocol.serverDeliversLobbyList:
default:

View File

@ -77,11 +77,6 @@ public class ClientHandler implements Runnable {
return socket;
}
/**
* Needed to fill a train with client TODO: how do lobbies fit here?
*
* @return the HashSet of Connected Clients
*/
public static HashSet<ClientHandler> getConnectedClients() {
return connectedClients;
}
@ -300,7 +295,7 @@ public class ClientHandler implements Runnable {
if(vote != Integer.MAX_VALUE) { //gets MAX_VALUE when the vote wasn't valid
getLobby().getGame().getGameState().getClientVoteData().setVote(position,vote);
LOGGER.debug("Player vote: " + vote);
getLobby().getGame().getGameState().getClientVoteData().setHasVoted(position,true); //TODO: move clientVoteData to gamestate
getLobby().getGame().getGameState().getClientVoteData().setHasVoted(position,true);
}
}
@ -490,7 +485,7 @@ public class ClientHandler implements Runnable {
} catch (Exception e) {
sendAnnouncementToClient(" - No running Games");
}
sendAnnouncementToClient("Finished Games");
sendAnnouncementToClient("Finished Games:");
try {
for (Game finishedGame : Lobby.finishedGames) {
sendAnnouncementToClient(" - " + finishedGame.getName() + ", Lobby" + finishedGame.getLobby().getLobbyID());

View File

@ -159,7 +159,7 @@ public class Lobby {
*/
public synchronized boolean addPlayer(ClientHandler client) {
if (lobbyClients.size() < MAX_NO_OF_CLIENTS) {
//todo: check that game hasn't started yet
//todo: check that game hasn't started yet (handled in cleintHandler)
if (clientIsInLobby(client) == -1) {
lobbyClients.add(client);
ClientHandler.broadcastAnnouncementToAll(client.getClientUserName() + " has joined lobby " + this.getLobbyID());