From 2bc79b53a7482540a73a4afff02a411186bd2c7b Mon Sep 17 00:00:00 2001 From: Sebastian Lenzlinger Date: Thu, 28 Apr 2022 12:04:08 +0200 Subject: [PATCH 1/8] Adding Wrapper Classes for Controlls and corresponding EventHandlers. added different fxml views. --- .../client/gui/ClientListViewController.java | 5 ++ .../client/gui/LobbySceneViewController.java | 5 ++ .../gui/ServerMessageViewController.java | 5 ++ .../client/gui/buttons/ChangeNameButton.java | 7 ++ .../client/gui/buttons/JoinGameButton.java | 7 ++ .../client/gui/buttons/LeaveServerButton.java | 7 ++ .../client/gui/buttons/NewGameButton.java | 7 ++ .../client/gui/chat/ChatController.java | 66 ++++++++++++----- .../ChangeNameButtonPressedEventHandler.java | 17 +++++ .../JoinGameButtonPressedEventHandler.java | 17 +++++ .../LeaveServerButtonPressedEventHandler.java | 17 +++++ .../NewGameButtonPressedEventHandler.java | 17 +++++ .../gui/lounge/LoungeSceneViewController.java | 5 ++ .../client/gui/ClientListView.fxml | 14 ++++ .../client/gui/ServerMessageView.fxml | 14 ++++ .../multiplayer/client/gui/chat/ChatView.fxml | 70 ++++++++----------- .../client/gui/lounge/LoungeSceneView.fxml | 6 ++ 17 files changed, 229 insertions(+), 57 deletions(-) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListViewController.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/LobbySceneViewController.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageViewController.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/ChangeNameButton.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/JoinGameButton.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/LeaveServerButton.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/NewGameButton.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/ChangeNameButtonPressedEventHandler.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/JoinGameButtonPressedEventHandler.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/LeaveServerButtonPressedEventHandler.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/NewGameButtonPressedEventHandler.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneViewController.java create mode 100644 src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListView.fxml create mode 100644 src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageView.fxml create mode 100644 src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneView.fxml diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListViewController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListViewController.java new file mode 100644 index 0000000..62bfef6 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListViewController.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class ClientListViewController { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/LobbySceneViewController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/LobbySceneViewController.java new file mode 100644 index 0000000..2d04b3c --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/LobbySceneViewController.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class LobbySceneViewController { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageViewController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageViewController.java new file mode 100644 index 0000000..f7e95be --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageViewController.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class ServerMessageViewController { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/ChangeNameButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/ChangeNameButton.java new file mode 100644 index 0000000..3ef4194 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/ChangeNameButton.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons; + +import javafx.scene.control.Button; + +public class ChangeNameButton extends Button { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/JoinGameButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/JoinGameButton.java new file mode 100644 index 0000000..aed8c2a --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/JoinGameButton.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons; + +import java.awt.Button; + +public class JoinGameButton extends Button { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/LeaveServerButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/LeaveServerButton.java new file mode 100644 index 0000000..3baabdf --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/LeaveServerButton.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons; + +import javafx.scene.control.Button; + +public class LeaveServerButton extends Button { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/NewGameButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/NewGameButton.java new file mode 100644 index 0000000..ef6dd67 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/buttons/NewGameButton.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons; + +import javafx.scene.control.Button; + +public class NewGameButton extends Button { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java index c1664d0..ec9b1fe 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java @@ -4,6 +4,8 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; import ch.unibas.dmi.dbis.cs108.BudaLogConfig; import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ClientModel; import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol; +import com.sun.javafx.scene.control.Properties; +import com.sun.javafx.scene.control.inputmap.KeyBinding; import java.net.URL; import java.util.ResourceBundle; import javafx.application.Platform; @@ -15,16 +17,22 @@ import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; import javafx.scene.control.SplitPane; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; import javafx.scene.layout.Background; +import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.scene.text.TextFlow; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -33,6 +41,12 @@ public class ChatController implements Initializable { public static final Logger LOGGER = LogManager.getLogger(ChatController.class); public static final BudaLogConfig l = new BudaLogConfig(LOGGER); + @FXML + private Group vboxGroup; + @FXML + private GridPane vBoxGridPane; + @FXML + private ScrollPane ChatScrollPane; @FXML private VBox vBoxServerMessage; @FXML @@ -103,32 +117,23 @@ public class ChatController implements Initializable { public void changed(ObservableValue observable, Number oldValue, Number newValue) { vBoxChatMessages.setMaxHeight(newValue.doubleValue()); + ChatScrollPane.setMaxHeight(newValue.doubleValue()*2); } }); - /** * Initialize what happens when the send button is pressed */ sendButton.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { - String msg = chatMsgField.getText().split("\\R")[0]; //cut off extra lines, if present. - if (!msg.isEmpty()) { - client.getClient().sendMsgToServer(cmd.toString() + msg); - LOGGER.info("Message trying to send is: " + cmd.toString() + msg); - Label l; - if (cmd.startsWith(whisper)) { - l = new Label("You whispered to " + whisperTargetSelectField.getText() + ": " + msg); - l.setBackground(Background.fill(Color.LAVENDERBLUSH)); - } else { - l = new Label(client.getUsername() + " (you): " + msg); - l.setBackground(Background.fill(Color.LAVENDER)); - } - vBoxChatMessages.getChildren().add(l); - chatMsgField.clear(); - } else { - LOGGER.debug("Trying to send an empty message."); - } + sendChatMsg(); + } + }); + + chatMsgField.setOnAction(new EventHandler() { + @Override + public void handle(ActionEvent event) { + sendChatMsg(); } }); @@ -158,6 +163,29 @@ public class ChatController implements Initializable { }); } + private void sendChatMsg() { + String msg = chatMsgField.getText();//.split("\\R")[0]; //cut off extra lines, if present. + if (!msg.isEmpty()) { + client.getClient().sendMsgToServer(cmd.toString() + msg); + LOGGER.info("Message trying to send is: " + cmd.toString() + msg); + Label l; + if (cmd.startsWith(whisper)) { + l = new Label("You whispered to " + whisperTargetSelectField.getText() + ": " + msg); + l.setBackground(Background.fill(Color.LAVENDERBLUSH)); + } else { + l = new Label(client.getUsername() + " (you): " + msg); + l.setBackground(Background.fill(Color.LAVENDER)); + l.setWrapText(true); + l.setMaxHeight(Double.MAX_VALUE); + l.setScaleShape(true); + } + vBoxChatMessages.getChildren().add(l); + chatMsgField.clear(); + } else { + LOGGER.debug("Trying to send an empty message."); + } + } + /** * @return the ClientModel whose chat controller this is */ @@ -185,6 +213,8 @@ public class ChatController implements Initializable { */ public void addChatMsgToView(String msg) { Label l = new Label(msg); + l.setWrapText(true); + l.setMaxHeight(Double.MAX_VALUE); if (msg.contains("whispers")) { l.setBackground(Background.fill(Color.SLATEBLUE)); } else { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/ChangeNameButtonPressedEventHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/ChangeNameButtonPressedEventHandler.java new file mode 100644 index 0000000..aab222a --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/ChangeNameButtonPressedEventHandler.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.events; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; + +public class ChangeNameButtonPressedEventHandler implements EventHandler { + + /** + * Invoked when a specific event of the type for which this handler is registered happens. + * + * @param event the event which occurred + */ + @Override + public void handle(ActionEvent event) { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/JoinGameButtonPressedEventHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/JoinGameButtonPressedEventHandler.java new file mode 100644 index 0000000..fed658b --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/JoinGameButtonPressedEventHandler.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.events; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; + +public class JoinGameButtonPressedEventHandler implements EventHandler { + + /** + * Invoked when a specific event of the type for which this handler is registered happens. + * + * @param event the event which occurred + */ + @Override + public void handle(ActionEvent event) { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/LeaveServerButtonPressedEventHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/LeaveServerButtonPressedEventHandler.java new file mode 100644 index 0000000..53ddf74 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/LeaveServerButtonPressedEventHandler.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.events; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; + +public class LeaveServerButtonPressedEventHandler implements EventHandler { + + /** + * Invoked when a specific event of the type for which this handler is registered happens. + * + * @param event the event which occurred + */ + @Override + public void handle(ActionEvent event) { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/NewGameButtonPressedEventHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/NewGameButtonPressedEventHandler.java new file mode 100644 index 0000000..9fb38c7 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/events/NewGameButtonPressedEventHandler.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.events; + +import javafx.event.ActionEvent; +import javafx.event.EventHandler; + +public class NewGameButtonPressedEventHandler implements EventHandler { + + /** + * Invoked when a specific event of the type for which this handler is registered happens. + * + * @param event the event which occurred + */ + @Override + public void handle(ActionEvent event) { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneViewController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneViewController.java new file mode 100644 index 0000000..9a72b54 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneViewController.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge; + +public class LoungeSceneViewController { + +} diff --git a/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListView.fxml b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListView.fxml new file mode 100644 index 0000000..5a8071e --- /dev/null +++ b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientListView.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageView.fxml b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageView.fxml new file mode 100644 index 0000000..2220daf --- /dev/null +++ b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ServerMessageView.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.fxml b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.fxml index 0ee721d..52b6d92 100644 --- a/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.fxml +++ b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.fxml @@ -2,6 +2,7 @@ + @@ -9,10 +10,11 @@ + - + @@ -21,45 +23,18 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + - + @@ -69,25 +44,28 @@ - + - - + - + - + - + @@ -108,5 +86,19 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneView.fxml b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneView.fxml new file mode 100644 index 0000000..92ce78d --- /dev/null +++ b/src/main/resources/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LoungeSceneView.fxml @@ -0,0 +1,6 @@ + + + + + + From 38c02324f5f58ccdf0c8b885325cb2343f7b231a Mon Sep 17 00:00:00 2001 From: Alexandr Sazonov Date: Thu, 28 Apr 2022 11:05:57 +0000 Subject: [PATCH 2/8] Added folder for everything related to milestone 4 --- Meilenstein IV/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Meilenstein IV/.gitkeep diff --git a/Meilenstein IV/.gitkeep b/Meilenstein IV/.gitkeep new file mode 100644 index 0000000..e69de29 From 8a06ed87911f617f5809c1ede5d3a86fc6fd0cf3 Mon Sep 17 00:00:00 2001 From: Alexandr Sazonov Date: Thu, 28 Apr 2022 11:07:21 +0000 Subject: [PATCH 3/8] Dragged diary into current milestone folder --- Meilenstein IV/Diary.txt | 334 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 Meilenstein IV/Diary.txt diff --git a/Meilenstein IV/Diary.txt b/Meilenstein IV/Diary.txt new file mode 100644 index 0000000..167e062 --- /dev/null +++ b/Meilenstein IV/Diary.txt @@ -0,0 +1,334 @@ +NOTE: Dies ist die .txt-Version des Diary, die .docx-Version ist im Ordner "documentation", allerdings unter dem namen "Protokoll" (Name hier geändert um Verwechslung mit client-server-Protokoll zu vermeiden). + + + + +02.03.2022 – alle Gruppenmitglieder + +- Einrichtung Git und IntelliJ + +- Spielidee: Jonas: Werwolf-Spiel + + 6 Spieler, rundenbasiert + + Grobe Idee: Es gibt einen Geist und 5 Personen, die in einem Nachtzug in benachbarten Kabinen fahren. Ein Geist kann in der Nacht einen anderen „gesunden“ Spieler (Person) infizieren. Dabei läuft der Geist neben anderen Personen und sie „hören“ den Geist (Benachrichtigung). Wenn die Nacht vorbei ist, müssen sich alle Spieler entscheiden, ob sie sagen, sie hätten etwas gehört oder nicht (mit Chat). Dann gibt es am Tag eine Abstimmung, wer der Geist ist (Stimme der Geister zählt nicht). Der Spieler mit den meisten Stimmen wird aus dem Spiel geworfen. In der nächsten Nacht stimmen die verbliebenen Geister ab, wen sie infizieren wollen. Anschliessend beginnt die Infektionsphase erneut. + + Das Spiel ist vorbei, wenn nur Geister oder nur Personen übrig sind. + Schräge/isometrische Grafik, prerendered + + + + + +08.03.2022 – alle Gruppenmitglieder + +- Ziele für heute: Spieldesign/Spielregeln, Analyse, Projektplanung + +- Spieldesign: + +- Mindestens 6 Spieler (bei weniger als 6 human players wird der Rest mit NPCs aufgefüllt) + + - Zwei Arten/Rollen von Spielern: ghosts, humans + + - Server kommuniziert Spielern, ob sie humans oder ghosts sind + +- Spieler, der neues Spiel kreiert, ist Admin (darf neues Spiel z.B. auch nur mit NPCs anfangen) + +- ghosts vs. humans: Geister können Menschen infizieren und zu Geistern machen. Sind nur Geister im Spiel übrig, haben Geister gewonnen. Haben die Menschen den ursprünglichen Geist aus dem Spiel geworfen, haben sie gewonnen. + +(- Versucht ein Geist, einen Menschen zu infizieren, ist nicht sicher, ob er es schafft) + +- Eine Runde = ein Tag-Nacht-Zyklus + +- Geister haben separaten Chat, in dem sie entscheiden können, wen sie in der nächsten Nacht infizieren + - Nacht: Geister aktiv, infizieren Menschen + - Infizierte wissen, wer sie infiziert hat + - Läuft der Geist neben Menschen, ohne sie zu infizieren, werden diese benachrichtigt + - Tag: anonyme Abstimmung, wer aus Spiel herausgekickt werden soll + +- time limit: Wenn man in einer bestimmten Zeit nicht abgestimmt hat, kriegt man eine Stimme für sich selbst + +- Spieler dürfen vor der Abstimmung sagen, ob sie einen Geist gehört haben oder nicht (Geister können Menschen dabei täuschen) + + - Stimmen der Geistern zählen nicht + + - Rausgeworfene Spieler werden Zuschauer + +- Nach Abstimmung wissen alle, wer ausgewählt worden ist, und ob der Spieler Geist war. + + +Zusammenfassung: + +- Spielbeginn: 6 Spielfelder. Erste Runde beginnt. Es ist Nacht, es gibt einen Geist. Geist stimmt für einen Menschen, den er infizieren will (Abstimmung mit time-limit; in möglichen späteren Runden stimmen mehrere Geister über zu infizierenden Menschen). Er infiziert diesen Menschen. + +- Infizierter wird benachrichtigt, dass er nun Geist ist; zudem Benachrichtigungen über Bewegung des Geistes + +- Es wird Tag: Menschen stimmen ab (mit Chat für Menschen, mit time limit), Geister-Stimmen zählen nicht. Wenn ein Geist die meisten Stimmen erhalten hat, wird er zum Zuschauer. Wenn Menschen für einen Menschen stimmen, werden sie benachrichtigt, dass er kein Geist ist (er wird nicht rausgeworfen) und das Spiel geht mit ihm weiter. + +- Spielende: entweder es gibt nur Geister (Geister gewonnen) oder erster Geist durch Menschen-Abstimmung aus dem Spiel geworfen (Menschen gewonnen). + +- Spieltitel: “Night train to Budapest” + +- Durchspielen auf Papier + +- Softwareanforderungen: + - 2D-Grafik + - Event-Handler (kümmert sich um Input/Output) + +- Zustandsspeicherung/Zustandsverwaltung (ist Tag / Nacht / Abstimmungszeit / Infektionszeit?) + +- Client/Server-Kommunikation + +- Separate Chatfunktion + + +- Grundlagen der Projektplanung + - Netzwerkprotokoll + - Client/-Serverstruktur + - Chatfunktion + - Spiellogik (Speicherung, Methoden für Veränderung) + - GUI + - Klassenstruktur (Datenstrukturen, Client/Server greifen darauf zu) + + + + + +11.03.2022 – alle Gruppenmitglieder + +- Einrichtung, Synchronisation GanttProject + +- Projektplanung: Anfang (parallelisierbar): Klassenstruktur (Human, Ghost, …), Spiellogik (Spielzustand, Voting), Client/Server (rundenbasiert), später: GUI (2D-Engine, Animation), Chat (mit speziellem Ghost-Modus) + +- Aufgabenaufteilung Meilenstein 1: Vorbereitung Präsentation (Jonas), Übersicht Netzwerk (Sebastian), Softwareanforderungen (Alex), detaillierter Projektplan (Seraina) + +- Netzwerktopologie für das Spiel: Stern + + + +24.03.2022 -alle Gruppenmitglieder + +Stand: +Client und Server Skelette stehen, und ein Broadcast von Chatnachrichten ist möglich. +Allerdings werden die Nachrichten noch als einfacher String übermittelt und noch nicht im richtigen Protokollformat +(d.h. nur chatten ist möglich, es gibt noch keine Befehle). + +Wer macht Was? + +Seraina: bis 25.3 Abends +• QA-Concept +• Fortfahren mit Spiellogik + + +Sebastian: bis 25.3 Abends +Protocol +• Formatter /Parser(Namingconvention überlegen) + o Format: COMND$parameter(i.e. Name)$parameter(i.e. msg) + +• Chat +• Encoding +• Enum: All Legal Protocol Commands + + +Jonas: bis 25.3 Abends +• PingPong-Funktionalität + o PingPong handler + o Every two seconds (what is the standard?) + o Listening for Answer + o Separate threads? + o What do you do when nothing comes back? (Log off? Wait? Ping again?) + +•Erweiterung von Localhost auf IP für Hamachi + o assign Ip (maybe port) method ? + + +Alexandr: bis 26.3 Abends +• Automatic username assignment +• Username duplicate handler + o Login -> username? -> check -> username01 + +• Client logout handling + o Meaningful handling + + + +Rule: Alles was geht in eigene Klassen Methoden schreiben. +Soviel wie möglich commiten mit Aufschlussreichen messages. + +Nächste Absprache Fr 25.3 Abends + + + + +24 & 25.03.2022 -Jonas +Zuhause pingpong & IP-auswahl implementiert. +Für PingPong brauche ich noch Hilfe von Sebastian bzgl. Protocol-Parser + + +25.03.2022 - Seraina +Das QA-Konzept steht, muss aber noch von allen Akzeptiert werden. +Ebenfalls ist hierzu wohl bald ein Treffen nötig, bei welchem ich alle mit den notwenigen Tools +vertraut machen kann. + + +27.03.2022 - Seraina +Kommunikationsschwierigkeiten haben zu einem hektischen letzten Entwicklungstag geführt. +Wir mussten einiges nochmal komplett neu Aufbauen und einige Gruppenmietglieder waren kaum erreichbar. +Fazit daraus für Meilenstein III: + o Wir brauchen fixe Besprechungstermine (-> QA-Konzept) um uns gegenseitig auf dem Laufenden + zu halten und um sicherzustellen, dass alle den Code der anderen zumindest grundlegend verstehen, + sodass nichts logistisch notwendig an einer Person hängen bleibt. + o Wir brauchen fixe deadlines die wir wohl am besten mittels treffen und Buddy-System umsetzten können. + o Wir müssen noch mehr Puffer enplanen und uns auch daran halten den Puffer nicht einfach als + mögliches Verschieben einer deadline zu betrachten. + + +26-28.03.2022 - Alex +- Implementierung eines random-name-Generators +- Behandlung von Duplikaten bei Auswahl des Spielernamens +- Wiederholter Versuch, Logout Handler zu implementieren, jedoch erfolglos + - Problem: broken pipe exceptions und stream closed exceptions beim Logout eines Clients + +31.03.2022 - alle Gruppenmitglieder +- Fortschrittsbesprechung, Reflexion auf Meilenstein 2 + - Was wurde erreicht, was nicht? Wenn nicht, warum nicht? + - Nicht erreicht: Ping-Pong-Funktionalität, Logout-Handling + - Unerwarteter Fehler bei Ping-Pong (beim Client-Logout) + - Diskussion über Kommunikationsschwierigkeiten: In Zukunft bessere Code-Dokumentation nötig, damit Gruppenmitglieder eigenen Code nachvollziehen können. + - Auch: 1-2 Mal pro Woche Meeting zur Fortschrittsbesprechung (Do, Fr), zusätzlich während der Übungsstunde. + - Einführung eines Buddy-Systems: Zwei 2er-Gruppen (Seraina + Sebastian, Jonas + Alex, Teamswitch möglich), gegenseitige Unterstützung/Überprüfung beim Coden, Orientierung an QA-Konzept + - Logger-Implementierung + - Wer macht was für Meilenstein 3? + 1a. Client/Server (Beheben bisheriger Probleme (Ping-Pong, Logout)) (Sebastian, Jonas) + Chat + Lobby + 1b. Spiellogik (Seraina, Alex) + Verbindung 1a-1b: Wie werden Informationen gesammelt und verbreitet? + - Wichtig: Klare Arbeitsteilung innerhalb einer Gruppe + - Client/Server + - PingPong, Logout, Socket Handling, evtl. Protokoll in Enum übertragen, evtl. name suggestion verbressern (Jonas) + - Lobbies, evtl. Chat-GUI (Sebastian) + - Repo-Cleanup (Seraina, bis Mo) + - Spiellogik v.a. Sa, So + +01.04.2022 - Seraina, Jonas, Alex +- Projektplan: Übertragung von TeamGantt (Web-Version) zu GanttProject +- Spiellogik: Brainstorming - wie implementiert man Spiellogik in Java-Code? + - GhostifyHandler: Mensch-Spieler wird zu Geist + - Einteilung: Pre-Game, (night-day-Zyklus (GameStates day, night) bis Spielende) + - ServerGameInfoHandler: Server schickt GameStateInformation an Clients + - ClientGameInfoHandler: Clients senden Event results an Server + - NoiseHandler: Information an Menschen, an denen Geist(er) vorbeilief(en) +--> Erstellen von Klassenskeletten basierend auf Brainstorming +- Aufgabenverteilung: + - Seraina: ServerGameInfoHandler, ClientGameInfoHandler (auch: QA) + - Alex: VoteHandler, NoiseHandler, evtl. Erweiterung GhostifyHandler (auch: Manual) + + +07.04.2022 - Seraina, Jonas, Alex +Stand: + Server - Client: Quit funktioniert, Name Suggestion ist sinnvoller umgesetzt, Namen Duplikate werden thematisch verändert, Disconection Bug am Anfang ist geflickt. + Lobby: ? + Spiellogik: VoteHandler; GhostVote und HumanVote sind implementiert. GhostyfyHandler ist implementiert. + + +ToDo: + Server - Client: Conection loss handling; wenn der Client keine Verbuindung merh hat, muss Server irgendwann Sockets schliessen, Server verliert verbindung. Lösung evtl mit quit? + Lobby: ? + Spiellogik: Ende des Spiels implementieren, NoiseHandling, Server/ClientGameInfoHandler, Testen ob bisherige implementationen tun was sie sollen. + Ziel: SAMSTAG Abend + +08.04.2022 - Seraina, Jonas, Alex +Stand: + Server - Client: Connection loss handling funktioniert nun. + Lobby: ? + Spiellogik: VoteHandler wurde getestet und tut weitestgehenst was er soll + +08.04.2022 - Sebastian +Stand Mittag: + Lobby: Es gibt eine Lobby Class. Sie verwaltet: LobbyID basierend darauf wieviele Lobbys/Spiele laufen; + Wieviele Spieler in der Lobby sind; Wer in der Lobby ist. +Stand 15:00 Uhr: + Folgende Protocol Commands wurden hinzugefügt: LISTL, CRTGM(wurde implementiert, fürt aber noch nichts aus). + Testing: Wenn ich mich mit telnet auf einen Server der auf localhost läuft verbinde, + scheint der Server zu ignorieren, dass er keine Pings bekommt. + TODO: mit LISTL und CRTGM soll wirklich etwas getan werden. JOING muss noch implementiert werden. + Frage: Was ist mit einer Login Sequenz? + Versuch meine commits wieder richtig zuorden zu können indem ich die user.name und user.email + Variablen von git + auf meinem Rechner neu configuriere. +Stand 17:30 Uhr: + Ich habe einen neuen Branch "BudaLobbySebastian" erstellt, worauf ich schaue wie und wo eigentlich eine "Lobby" + lebt. LISTL wurde auch implementiert aber noch nicht getestet. + + +12.04.2022 - Sebastian + Nach dem durchstöbern vieler Literatur endlich die Grundidee für den Chat-GUI. Insbesondere mit Hinblick + auf Integration in einen grösseres GUI-Modul. Wir werden wohl JavaFX(openFX) verwenden. + +ToDo: + Spiellogik: + - Send() methode von Passenger mit Client-Server verknüpfen(Seraina) + - NoiseHandler (Alex) + - Game Zyklus implementieren (Seraina) + + +08.04.2022 - 11.04.2022 - Alex +- Implementierung NoiseHandler, Verbindung mit VoteHandler +- Verbesserung der Lesbarkeit von VoteHandler (Code-Duplikate in eine Methode zusammengefasst) + +11.04.2022 - Seraina +Spiellogik: Es besteht eine basale Verknüpfung zwischen Client-Server und Spiellogik. Ein Client kann +eine Stimme abgeben und sie wird gezählt, NPC können sehr stupide stimmen abgegen (randomisiert). Der +Server schickt dem Client bei einem Voterequest immer seine Position im Zug mit, und der client schickt +sie dem Server wieder zurück. + +11 & 12.04.2022 - Jonas +Implementation aller notwendigen Lobby - funktionen, list-commands, sowie whisper chat. + + +13.04.2022 - Seraina +Spiellogik: Habe Alexs noiseHandling in die restliche Spiellogik integriert und debugged. Ebenso musste +ich den Input der Clients beim Abstimmen geben umstrukturieren. Anstatt dass eine speziefische Methode +für das Voting aufgerufen wird, wird über ein Befehl '/v vote' gemacht der über die gleichen Kanäle geht +wie alle anderen Konsolenbefehle. +TODO: Vote enforcement von Serverseite. Momentan können Humans in der Nacht und umgekehrt reinfunken und +ihre Stimmen werden gezählt. + +14.04.2022 - Alex +- Erste Version des Spiel-Manuals + +14.04.2022 - Jonas, Seraina, Sebi, Alex +Integration von Lobby und gamelogic. + +15.04.2022 - Seraina +Die Spiellogik läuft nun mit Enforcment. Geister und Menschen können nur zu enstprechender Zeit voten, +sonst werden ihre stimmen einfach nicht gewertet. Geister, die schon vom Zug geflogen sind, können nun +auch nicht mehr mitspielen. Habe eine Spectator Klasse hinzugefügt für Spieler, die aus dem Spiel geflogen +sind. + +16.04.2022 - Seraina, Sebi +Es gibt ein Problem mit der Gui, irgendwie funktioniert die Verbindung von Application Klasse zu +fxlm file nicht. + +17.04.2022 - Seraina, Sebi +GUI-Troubleshooting: wir haben das Problem mit der GUI lokalisiert, es wird beim launch einer Application +immer nur ein Objekt der Klasse erstellt, und zwar mit Konstruktor ohne Parametern. Um Parameter zu übergeben, +müssen statische Felder und definiert und diese nach launch und Initialisierung (beim Controller) mittels +Setter übergeben werden. + +17.04.2022 - Sebastian +- Dank Seraina kommuniziert die GUI nun mit dem Client und Nachrichten kommen korrekt an und werden korrekt verschickt. +Im GUI funktioniert der Whisper nun. Folgendes Colorcoding: Eigene Nachrichten sind Lavendelfarben. Normale Chat nachrichten blau, +und im Momentan Whisper Nachrichten violet. + +18.04.2022 - Seraina +Nach etlichem Lesen von Websites zu custom tasks in gradle habe ich endlich die build-cs108 task zum Laufen +gebracht. Es war wie so oft die einfachste Lösung. + +18.04.2022 - Alex +- Aktualisierung des Projektplans für Meilensteine 4 und 5 abgeschlossen (hochgeladen als pdf und xls) +- Änderung des NoiseHandlers: Nun werden human players, selbst wenn nachts mehrmals Geister an ihnen vorbeilaufen, nur einmal benachrichtigt. +- Abschliessende Arbeit am Manual. + +25. & 26. 4.2022 - Jonas +Erstellung der Prototyp-Sprites From 3377b71829c74d54a138129b109bf98cfb488337 Mon Sep 17 00:00:00 2001 From: Alexandr Sazonov Date: Thu, 28 Apr 2022 11:17:55 +0000 Subject: [PATCH 4/8] Update Diary.txt --- Meilenstein IV/Diary.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Meilenstein IV/Diary.txt b/Meilenstein IV/Diary.txt index 167e062..2d1b883 100644 --- a/Meilenstein IV/Diary.txt +++ b/Meilenstein IV/Diary.txt @@ -332,3 +332,9 @@ gebracht. Es war wie so oft die einfachste Lösung. 25. & 26. 4.2022 - Jonas Erstellung der Prototyp-Sprites + +28.04.2022 - alle Gruppenmietglieder +Paralleles Arbeiten an zugewiesenen Aufgaben, ggf. mit gegenseitiger Unterstützung: + Seraina, Sebastian: GUI + Jonas: high score list + Alex: unit tests From 93b6bab957907cee7920c3f93aa33e380435247f Mon Sep 17 00:00:00 2001 From: Alexander Sazonov Date: Thu, 28 Apr 2022 13:25:03 +0200 Subject: [PATCH 5/8] Finished first functioning and successful unit test (tests noise handling) --- .../dbis/cs108/gamelogic/NoiseHandler.java | 4 +- .../dmi/dbis/cs108/gamelogic/VoteHandler.java | 2 +- .../cs108/gamelogic/NoiseHandlerTest.java | 54 +++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandlerTest.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandler.java index 9579dea..e455f3b 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandler.java @@ -15,15 +15,13 @@ public class NoiseHandler { * predator infecting a victim, so if there are already multiple ghosts in the game, the method * should be called for each of them individually. - * @param passengers passengers of the train the game is played in * @param predator ghost that has infected a human player during this night (called upon as * passenger for convenience reasons) * @param victim human player who has been turned into a ghost this night * @param noiseAmount array containing information about how many times each passenger heard a noise this night - * @param game current game instance * @return updated array with info on who heard how many noises */ - public int[] noiseNotifier(Passenger[] passengers, Passenger predator, Passenger victim, int[] noiseAmount, Game game) { + public int[] noiseNotifier(Passenger predator, Passenger victim, int[] noiseAmount) { if (predator.getPosition() - victim.getPosition() > 0) { // if predator is to the right of victim for (int i = predator.getPosition() - 1; i > victim.getPosition(); i--) { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java index 19092be..229e0d4 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java @@ -97,7 +97,7 @@ public class VoteHandler { for (int i = 0; i < passengers.length; i++) { if (passengers[i].getIsGhost() && i != ghostPosition) { NoiseHandler n = new NoiseHandler(); - noiseAmount = n.noiseNotifier(passengers, passengers[i], g, noiseAmount, game); + noiseAmount = n.noiseNotifier(passengers[i], g, noiseAmount); } } for (int i = 0; i < passengers.length; i++) { diff --git a/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandlerTest.java b/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandlerTest.java new file mode 100644 index 0000000..53c99bf --- /dev/null +++ b/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/NoiseHandlerTest.java @@ -0,0 +1,54 @@ +package ch.unibas.dmi.dbis.cs108.gamelogic; + +import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Passenger; +import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler; +import ch.unibas.dmi.dbis.cs108.multiplayer.server.Lobby; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +class NoiseHandlerTest { + Passenger[] passengers = new Passenger[6]; // create new collection of passengers + Passenger predator = new Passenger(); + Passenger victim = new Passenger(); // player who will be turned into a ghost this night + int[] noiseAmount = new int[6]; // collect amount of times a ghost walked by the humans (= noises heard) + int[] noiseAmountGuideline = new int[6]; // array that represents the right people having heard the right noise amount + + @BeforeEach + void preparation() { + for (int i = 0; i < passengers.length; i++) { + passengers[i] = new Passenger(); + } + predator.setGhost(); + } + + @Test + @DisplayName("The right players hear the right amount of noises") + + void noiseTest1() { + /* test 1: people heard the right noise amount for following case: ghost is at position 5 and ghostifies + player at position 2 --> noises at positions 3 and 4 + */ + predator.setPosition(5); + victim.setPosition(2); + passengers[predator.getPosition()] = predator; + passengers[victim.getPosition()] = victim; + + for (int i = 3; i < 5; i++) { + noiseAmountGuideline[i]++; + } + /* call main method of NoiseHandler so that all passengers are notified about all noises (notifications are + updated in noiseAmount array) */ + for (int i = 0; i < passengers.length; i++) { + if (passengers[i].getIsGhost() && i != victim.getPosition()) { + NoiseHandler n = new NoiseHandler(); + noiseAmount = n.noiseNotifier(passengers[i], victim, noiseAmount); + } + } + assertArrayEquals(noiseAmountGuideline, noiseAmount); + } +} \ No newline at end of file From 5fbee579a98ab58138d0c5c32ae857db1fc56640 Mon Sep 17 00:00:00 2001 From: Jonas Date: Thu, 28 Apr 2022 13:35:48 +0200 Subject: [PATCH 6/8] made OgGhostHighScore.java, see documentation for details --- .../dmi/dbis/cs108/gamelogic/GameState.java | 4 +- .../dmi/dbis/cs108/gamelogic/VoteHandler.java | 2 +- .../cs108/highscore/OgGhostHighScore.java | 121 ++++++++++++++++++ .../dbis/cs108/gamelogic/GameStateTests.java | 105 +++++++++++++++ 4 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java create mode 100644 src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameStateTests.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameState.java b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameState.java index 9dd478d..a9467e0 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameState.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameState.java @@ -19,8 +19,8 @@ public class GameState { **/ public final int nrOfPlayers; //sets the length of the train public final int nrOfGhosts; // sets how many Ghosts we start witch - public final int nrOfUsers; // safes how many clients are active in this Game - public final Train train; // safes who sits where + public final int nrOfUsers; // saves how many clients are active in this Game + public final Train train; // saves who sits where /** * contains all Passengers on train, needs to be updated */ diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java index e6a7ceb..b2fd03e 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/VoteHandler.java @@ -54,7 +54,7 @@ public class VoteHandler { int currentMax = ghostVoteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game); - LOGGER.debug("Most votes: " + currentMax + " vote"); + LOGGER.debug("Most votes: " + currentMax + " vote(s)"); // ghostify the player with most votes int ghostPosition = 0; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java b/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java new file mode 100644 index 0000000..6067fd5 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java @@ -0,0 +1,121 @@ +package ch.unibas.dmi.dbis.cs108.highscore; + +import ch.unibas.dmi.dbis.cs108.BudaLogConfig; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * used for logging OG ghost highscore + */ +public class OgGhostHighScore { + + public static final Logger LOGGER = LogManager.getLogger(OgGhostHighScore.class); + public static final BudaLogConfig l = new BudaLogConfig(LOGGER); + + static ArrayList ogGhostWinners = new ArrayList<>(); + static final File ogGhostFile = new File("OgGhostWinners.txt"); + + /** + * Writes the current state of the ogGhostWinners String[] to the ogGhostFile, then closes + * the fileWriter. + */ + static void writeOgGhostWinnersToFile() { + try { + FileWriter fileWriter = new FileWriter(ogGhostFile, false); + for (String name : ogGhostWinners) { + fileWriter.write(name); + fileWriter.write(System.lineSeparator()); + } + fileWriter.close(); + } catch (Exception e) { + LOGGER.debug("Exception while trying to write ogGhostWinners to file."); + LOGGER.debug(e.getMessage()); + } + } + + /** + * adds the given name to the list of og ghost winners and updates the file listing the og ghost + * winners via writeOgGhostWinnersToFile + */ + public static void addOgGhostWinner(String name){ + ogGhostWinners.add(name); + writeOgGhostWinnersToFile(); + } + + /** + * outputs the highscore list as it could be shown to clients. + * @return + */ + public static String formatGhostHighscoreList() { + + //create the hashMap which lists all names along with their number of appearances + //int max = 0; + HashMap hm = new HashMap<>(); + for (String name: ogGhostWinners) { + if (hm.containsKey(name)) { + hm.replace(name, hm.get(name) + 1); + } else { + hm.put(name, 1); + } + //if (max < hm.get(name)) max = hm.get(name); + } + + StringBuilder sb = new StringBuilder(); + + + //add the 5 highest scoring peeps to the StringBuilder sb + for (int i = 0; i < 5; i++) { + //find first place among the remaining members of hm. ("remaining" because we remove people once theyre listed) + if (!hm.isEmpty()) { + String firstplace = (String) hm.keySet().toArray()[0]; //choose one candidate for first place just so we dont get null pointer + for (String name: hm.keySet()) { + if (hm.get(name) > hm.get(firstplace)) firstplace = name; + } + sb.append(firstplace).append(": ").append(hm.get(firstplace)).append(" wins.") + .append(System.lineSeparator()); + hm.remove(firstplace); + } + } + + return sb.toString(); + } + + /** + * reads the highscore file (or if not yet present create it) and reads the ogGhostWinners; + */ + public static void main(String[] args) { + try { + ogGhostWinners = new ArrayList<>(); + //if not already present, the following creates the file and enters the if statement. + //if already present, it reads what's already in the file into the ogGhostWinners array. + if (!ogGhostFile.createNewFile()) { + BufferedReader buffreader = new BufferedReader(new FileReader(ogGhostFile)); + String line = buffreader.readLine(); + while (line != null) { + ogGhostWinners.add(line); + line = buffreader.readLine(); + } + } + + /* + addOgGhostWinner("Seraina"); + ogGhostWinners.add("Jonas, the ultimate winner"); + + writeOgGhostWinnersToFile(); + System.out.println(formatGhostHighscoreList()); + */ + + + + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameStateTests.java b/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameStateTests.java new file mode 100644 index 0000000..eecafac --- /dev/null +++ b/src/test/java/ch/unibas/dmi/dbis/cs108/gamelogic/GameStateTests.java @@ -0,0 +1,105 @@ +package ch.unibas.dmi.dbis.cs108.gamelogic; + +import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.*; +import ch.unibas.dmi.dbis.cs108.multiplayer.server.Lobby; +import ch.unibas.dmi.dbis.cs108.multiplayer.server.Server; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class GameStateTests { + + /* + * Streams to store system.out and system.err content + */ + private ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + private ByteArrayOutputStream errStream = new ByteArrayOutputStream(); + + /* + * Here we store the previous pointers to system.out / system.err + */ + private PrintStream outBackup; + private PrintStream errBackup; + + /** + * This method is executed before each test. + * It redirects System.out and System.err to our variables {@link #outStream} and {@link #errStream}. + * This allows us to test their content later. + */ + @BeforeEach + public void redirectStdOutStdErr() { + System.out.println("im here"); + outBackup = System.out; + errBackup = System.err; + System.setOut(new PrintStream(outStream)); + System.setErr(new PrintStream(errStream)); + outBackup.println("this should"); + } + + /** + * This method is run after each test. + * It redirects System.out / System.err back to the normal streams. + */ + @AfterEach + public void reestablishStdOutStdErr() { + System.setOut(outBackup); + System.setErr(errBackup); + } + + /** + * This is a normal JUnit-Test. It executes the HelloWorld-Method and verifies that it actually wrote "Hello World" to stdout + */ + @Test + public void testMain() { + + /* old test. Todo: delete + new Thread(new Runnable() { + @Override + public void run() { + Server.main(1837); + } + }).start(); + outBackup.println("here now"); + String toTest = outStream.toString(); + outBackup.println(toTest); + //toTest = removeNewline(toTest); + assertTrue(toTest.contains("Port")); + */ + try { + int totalNumberOfPlayers = 6; + int numberOfHumanPlayers = 3; + Passenger[] passengers = new Passenger[totalNumberOfPlayers]; + VoteHandler v = new VoteHandler(); + Lobby l = null; + + Game game = new Game(6, 1, 3, l); + passengers[0] = new GhostNPC(0,"0", true); + passengers[1] = new GhostNPC(1,"1", false); + passengers[2] = new GhostNPC(2,"2", false); + passengers[3] = new HumanNPC(3,"3"); + passengers[4] = new HumanNPC(4,"4"); + passengers[5] = new HumanNPC(5,"5"); + + int[] votesForPlayers = {0, 0, 0, 0, 0, 0}; + int maxVotes = v.ghostVoteEvaluation(passengers, votesForPlayers, null, game); + assertEquals(2, maxVotes); + + } catch (Exception ignored) { + outBackup.println("exception."); + } + outBackup.println("done"); + + } + + private static String removeNewline(String str) { + return str.replace("\n", "").replace("\r", ""); + } + +} From b769991c3663264bb5738b584fe0a3beb2738fc9 Mon Sep 17 00:00:00 2001 From: Sebastian Lenzlinger Date: Thu, 28 Apr 2022 13:41:45 +0200 Subject: [PATCH 7/8] Minor Changes to ChatController adding a TODO and created a LobbyListItem class to represent members of the lobby list view, or at least the data therein. --- .../client/gui/chat/ChatController.java | 7 ++++++- .../client/gui/lounge/LobbyListItem.java | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LobbyListItem.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java index ec9b1fe..aacdf11 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java @@ -32,6 +32,7 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.scene.text.Text; import javafx.scene.text.TextFlow; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -117,7 +118,7 @@ public class ChatController implements Initializable { public void changed(ObservableValue observable, Number oldValue, Number newValue) { vBoxChatMessages.setMaxHeight(newValue.doubleValue()); - ChatScrollPane.setMaxHeight(newValue.doubleValue()*2); + ChatScrollPane.setMaxHeight(newValue.doubleValue() * 2); } }); /** @@ -163,16 +164,20 @@ public class ChatController implements Initializable { }); } + //TODO figure out if to use Text or Label & how to make wrapping work finally @Sebastian private void sendChatMsg() { String msg = chatMsgField.getText();//.split("\\R")[0]; //cut off extra lines, if present. if (!msg.isEmpty()) { client.getClient().sendMsgToServer(cmd.toString() + msg); LOGGER.info("Message trying to send is: " + cmd.toString() + msg); + Text t; Label l; if (cmd.startsWith(whisper)) { + t = new Text("You whispered to " + whisperTargetSelectField.getText() + ": " + msg); l = new Label("You whispered to " + whisperTargetSelectField.getText() + ": " + msg); l.setBackground(Background.fill(Color.LAVENDERBLUSH)); } else { + t = new Text(client.getUsername() + " (you): " + msg); l = new Label(client.getUsername() + " (you): " + msg); l.setBackground(Background.fill(Color.LAVENDER)); l.setWrapText(true); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LobbyListItem.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LobbyListItem.java new file mode 100644 index 0000000..4793b9c --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/lounge/LobbyListItem.java @@ -0,0 +1,14 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge; + +import java.util.List; +import javafx.scene.control.Label; +import javafx.scene.control.ToggleButton; + +public class LobbyListItem { + + private Label lobbyID; + private Label adminName; + private List clientInLobby; + private ToggleButton button; + +} From 96812a04ae927c9a9eccb38a14ee95870259e683 Mon Sep 17 00:00:00 2001 From: Jonas Date: Thu, 28 Apr 2022 15:29:36 +0200 Subject: [PATCH 8/8] High score fully implemented. --- .../ch/unibas/dmi/dbis/cs108/gamelogic/Game.java | 15 +++++++++++++++ .../dbis/cs108/highscore/OgGhostHighScore.java | 13 +------------ .../multiplayer/client/MessageFormatter.java | 3 +++ .../dbis/cs108/multiplayer/helpers/Protocol.java | 7 +++++++ .../cs108/multiplayer/server/ClientHandler.java | 8 ++++++++ .../multiplayer/server/JServerProtocolParser.java | 3 +++ .../dmi/dbis/cs108/multiplayer/server/Server.java | 2 ++ 7 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/Game.java b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/Game.java index 2514ead..27f3f04 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/Game.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/gamelogic/Game.java @@ -7,6 +7,7 @@ import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.GhostPlayer; import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.HumanNPC; import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.HumanPlayer; import ch.unibas.dmi.dbis.cs108.gamelogic.klassenstruktur.Passenger; +import ch.unibas.dmi.dbis.cs108.highscore.OgGhostHighScore; import ch.unibas.dmi.dbis.cs108.multiplayer.server.ClientHandler; import ch.unibas.dmi.dbis.cs108.multiplayer.server.Lobby; import java.util.HashSet; @@ -64,6 +65,17 @@ public class Game implements Runnable { isOngoing = ongoing; } + Passenger getOgGhost(){ + int[] order = gameState.getTrain().getOrderOfTrain(); + Passenger[] passengerTrain = gameState.getPassengerTrain(); + for (int i = 0; i < 6; i++) { + if (passengerTrain[i].getIsOG()) { + return passengerTrain[i]; + } + } + return null; + } + /** * Starts a new game, creates a passenger array and saves it in gameState, sets the OG * currently at gameState.train[3] fills the passengerTrain moving from left to rigth in the @@ -121,6 +133,9 @@ public class Game implements Runnable { } if (gameOverCheck.equals(ClientGameInfoHandler.gameOverGhostsWin) || gameOverCheck.equals( ClientGameInfoHandler.gameOverHumansWin)) { + if (gameOverCheck.equals(ClientGameInfoHandler.gameOverGhostsWin) && getOgGhost().getIsPlayer()) { + OgGhostHighScore.addOgGhostWinner(getOgGhost().getName()); + } lobby.getAdmin().broadcastAnnouncementToLobby(gameOverCheck); lobby.removeGameFromRunningGames(this); lobby.addGameToFinishedGames(this); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java b/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java index 6067fd5..9e31856 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/highscore/OgGhostHighScore.java @@ -93,7 +93,7 @@ public class OgGhostHighScore { public static void main(String[] args) { try { ogGhostWinners = new ArrayList<>(); - //if not already present, the following creates the file and enters the if statement. + //if not already present, the following creates the file. //if already present, it reads what's already in the file into the ogGhostWinners array. if (!ogGhostFile.createNewFile()) { BufferedReader buffreader = new BufferedReader(new FileReader(ogGhostFile)); @@ -103,17 +103,6 @@ public class OgGhostHighScore { line = buffreader.readLine(); } } - - /* - addOgGhostWinner("Seraina"); - ogGhostWinners.add("Jonas, the ultimate winner"); - - writeOgGhostWinnersToFile(); - System.out.println(formatGhostHighscoreList()); - */ - - - } catch (IOException e) { e.printStackTrace(); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java index 3c0c817..6cb6a15 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/MessageFormatter.java @@ -98,6 +98,9 @@ public class MessageFormatter { case "/s": stringBuilder.append(Protocol.startANewGame); break; + case "/h": + stringBuilder.append(Protocol.highScoreList); + break; default: s = msg; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.java index 809fc03..2fc4bad 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/helpers/Protocol.java @@ -138,6 +138,13 @@ public class Protocol { */ public static final String votedFor = "CVOTE"; + /** + * Client requests high score list. + */ + public static final String highScoreList = "HSCOR"; + + + //SERVER TO CLIENT COMMANDS diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java index 071d248..e5928c4 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/ClientHandler.java @@ -4,6 +4,7 @@ import ch.unibas.dmi.dbis.cs108.BudaLogConfig; import ch.unibas.dmi.dbis.cs108.gamelogic.Game; import ch.unibas.dmi.dbis.cs108.gamelogic.TrainOverflow; import ch.unibas.dmi.dbis.cs108.gamelogic.VoteHandler; +import ch.unibas.dmi.dbis.cs108.highscore.OgGhostHighScore; import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol; import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger; @@ -594,4 +595,11 @@ public class ClientHandler implements Runnable { } + public void sendHighScoreList() { + String list = OgGhostHighScore.formatGhostHighscoreList(); + String[] listarray = list.split("\\R"); + for (String s: listarray) { + sendAnnouncementToClient(s); + } + } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java index 84e129b..c9029ba 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/JServerProtocolParser.java @@ -109,6 +109,9 @@ public class JServerProtocolParser { case Protocol.listGames: h.listGames(); break; + case Protocol.highScoreList: + h.sendHighScoreList(); + break; default: System.out.println("Received unknown command"); } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Server.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Server.java index 1df003e..7f53f72 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Server.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Server.java @@ -2,6 +2,7 @@ package ch.unibas.dmi.dbis.cs108.multiplayer.server; import ch.unibas.dmi.dbis.cs108.BudaLogConfig; +import ch.unibas.dmi.dbis.cs108.highscore.OgGhostHighScore; import java.io.*; import java.net.ServerSocket; import java.net.Socket; @@ -30,6 +31,7 @@ public class Server { public void startServer() { try { System.out.println("Port " + gamePort + " is open."); + OgGhostHighScore.main(null); while (!serverSocket.isClosed()) { Socket socket = serverSocket.accept(); ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress());