diff --git a/Meilenstein III/Diary.txt b/Meilenstein III/Diary.txt index 41f6472..ef660a0 100644 --- a/Meilenstein III/Diary.txt +++ b/Meilenstein III/Diary.txt @@ -194,9 +194,9 @@ Fazit daraus für Meilenstein III: - 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 + - 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) @@ -205,7 +205,7 @@ Fazit daraus für Meilenstein III: 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) + - 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 @@ -261,11 +261,19 @@ Stand 17:30 Uhr: 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) - +14.04.2022 - Alex +- Erste Version des Spiel-Manuals diff --git a/Meilenstein III/Manual_1.0.docx b/Meilenstein III/Manual_1.0.docx new file mode 100644 index 0000000..9555c9d Binary files /dev/null and b/Meilenstein III/Manual_1.0.docx differ diff --git a/README.md b/README.md index 8f37c0f..7513ae9 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,19 @@ Votes are held in the night for the ghosts to decide who will be next and during * ... ## Console Commands -* /c "message" - sends a chat message to all connected players -* /n "name" - changes player name +* /c _message_ - sends a chat message to all players in the same lobby. If you are not in a lobby, the message will be sent to all players who are also not in a lobby. +* /b _message_ - broadcasts a message to all connected clients, regardless of lobbies. +* /w _username$message_ - sends a message to the specified user only. +* /g - create (&join) a new lobby. +* /j _1_ - join lobby 1. To join lobby 2, use /j _2_, etc. +* /l - list all connected clients and all lobbies +* /p - list all players in your lobby. +* /e - exit your lobby +* /n _name_ - changes player name. If unavailable, it adds a fun and quirky suffix * /q - quit +* /s - start game in your current lobby. +* /v 1 - vote for person 1 (same for other numbers) + ## Installation ... diff --git a/build.gradle b/build.gradle index 8e8f567..fbfe82c 100644 --- a/build.gradle +++ b/build.gradle @@ -11,8 +11,8 @@ javafx { } group 'ch.unibas.dmi.dbis' -version '0.0.1-ALPHA' -mainClassName = 'ch.unibas.dmi.dbis.cs108.multiplayer.client.Client' +version '0.0.2' +mainClassName = 'ch.unibas.dmi.dbis.cs108.NightTrainToBudapest' java { toolchain { diff --git a/settings.gradle b/settings.gradle index 145cdd9..65352eb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -rootProject.name = 'Night Train to Budapest' +rootProject.name = 'NightTrainToBudapest' diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/NightTrainToBudapest.java b/src/main/java/ch/unibas/dmi/dbis/cs108/NightTrainToBudapest.java new file mode 100644 index 0000000..5c27eb3 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/NightTrainToBudapest.java @@ -0,0 +1,39 @@ +package ch.unibas.dmi.dbis.cs108; + +import ch.unibas.dmi.dbis.cs108.multiplayer.client.Client; +import ch.unibas.dmi.dbis.cs108.multiplayer.server.Server; +import java.net.InetAddress; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.IParameterRenderer; + +public class NightTrainToBudapest { + + public static void main(String[] args){ + try{ + String clientOrServer = args[0]; + if (clientOrServer.equalsIgnoreCase("client")) { + String addrString = args[1].substring(0,args[1].indexOf(":")); + InetAddress addr = InetAddress.getByName(addrString); + int port = Integer.parseInt(args[1].substring(args[1].indexOf(":") + 1)); + String username = null; + if (args.length > 2) { //if the client provided a username + //StringBuilder usernamebuilder = new StringBuilder(); todo: support username with spaces. + username = args[2]; + } + Client.main(addr, port, username); + } else if (clientOrServer.equalsIgnoreCase("server")) { + int port = Integer.parseInt(args[1]); + Server.main(port); + } else { + System.out.println("invalid arguments!"); + } + + } catch (Exception e) { + System.out.println("Please give more arguments."); + System.out.println("Syntax:"); + System.out.println("client : [] | server "); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java index 2715d6b..4d94632 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client.java @@ -7,6 +7,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.multiplayer.server.JServerProtocolParser; +import java.net.InetAddress; import java.net.Socket; import java.io.*; import java.net.UnknownHostException; @@ -31,7 +32,7 @@ public class Client { int position = Integer.MAX_VALUE; - public Client(Socket socket) { + public Client(Socket socket, String username) { try { this.socket = socket; this.out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); @@ -39,12 +40,16 @@ public class Client { //sending the initial name to server. String systemName; - try { - systemName = System.getProperty("user.name"); - } catch (Exception e) { - systemName = "U.N. Owen"; + if (username == null) { + try { + systemName = System.getProperty("user.name"); + } catch (Exception e) { + systemName = "U.N. Owen"; + } + if (systemName == null) systemName = "U.N. Owen"; + } else { + systemName = username; } - if (systemName == null) systemName = "U.N. Owen"; sendMsgToServer(Protocol.clientLogin + "$" + systemName); clientPinger = new ClientPinger(this, this.socket); @@ -183,7 +188,7 @@ public class Client { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String hostname; - int port = 42069; //can be set via argument later if needed. + int port = 1873; if (args.length < 1) { System.out.println("Enter the host's IP address (or type l for localhost)"); hostname = sc.next(); @@ -196,7 +201,7 @@ public class Client { Socket socket; try { socket = new Socket(hostname, 42069); - Client client = new Client(socket); + Client client = new Client(socket, null); client.chatListener(); Thread cP = new Thread(client.clientPinger); cP.start(); @@ -209,6 +214,22 @@ public class Client { } + public static void main(InetAddress address, int port, String username) { + Scanner sc = new Scanner(System.in); + Socket socket; + try { + socket = new Socket(address, port); + Client client = new Client(socket, username); + client.chatListener(); + Thread cP = new Thread(client.clientPinger); + cP.start(); + client.userInputListener(); //this one blocks. + } catch (UnknownHostException e) { + System.out.println("Invalid host IP"); + } catch (IOException e) { + e.printStackTrace(); + } + } public Socket getSocket() { return socket; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_01.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_01.java deleted file mode 100644 index bd2e499..0000000 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_01.java +++ /dev/null @@ -1,8 +0,0 @@ -package ch.unibas.dmi.dbis.cs108.multiplayer.client; - -public class Client_01 { - public static void main(String[] args) { - Client.main(args); - } - -} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_02.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_02.java deleted file mode 100644 index 23c9122..0000000 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/Client_02.java +++ /dev/null @@ -1,7 +0,0 @@ -package ch.unibas.dmi.dbis.cs108.multiplayer.client; - -public class Client_02 { - public static void main(String[] args) { - Client.main(args); - } -} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientController.java new file mode 100644 index 0000000..b993dba --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientController.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class ClientController { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientModel.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientModel.java new file mode 100644 index 0000000..da11ecc --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientModel.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class ClientModel { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientView.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientView.java new file mode 100644 index 0000000..7440425 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/ClientView.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui; + +public class ClientView { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/BroadcastButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/BroadcastButton.java new file mode 100644 index 0000000..c050725 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/BroadcastButton.java @@ -0,0 +1,25 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.collections.ObservableMap; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.Control; +import javafx.scene.control.Label; +import javafx.scene.control.RadioButton; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.Pane; + +/** + * Represents toggling to broadcast to everyone + */ +public class BroadcastButton extends Node implements ControlWrapper { + + private static RadioButton broadcast = new RadioButton("Broadcast"); + @Override + public Control getControl() { + return broadcast; + } +} 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 new file mode 100644 index 0000000..97fb8a1 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatController.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public class ChatController { + + public void setChatView(){}; + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatMsg.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatMsg.java new file mode 100644 index 0000000..69954a1 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatMsg.java @@ -0,0 +1,7 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public interface ChatMsg { + + public String display(String msg); + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatObserver.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatObserver.java new file mode 100644 index 0000000..c89cde3 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatObserver.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public interface ChatObserver { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatTargetToggle.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatTargetToggle.java new file mode 100644 index 0000000..d7606f8 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatTargetToggle.java @@ -0,0 +1,81 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.Property; +import javafx.collections.ObservableMap; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.RadioButton; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; + +/** + * If this is toggled than the client chat is operating in whisper mode. + */ + +public abstract class ChatTargetToggle extends Node implements Toggle{ + + BooleanProperty isToggled; + ObjectProperty myFriends; + + /** + * Returns The {@link ToggleGroup} to which this {@code Toggle} belongs. + * + * @return The {@link ToggleGroup} to which this {@code Toggle} belongs. + */ + @Override + public ToggleGroup getToggleGroup() { + return myFriends.get(); + } + + /** + * Sets the {@link ToggleGroup} to which this {@code Toggle} belongs. + * + * @param toggleGroup The new {@link ToggleGroup}. + */ + @Override + public void setToggleGroup(ToggleGroup toggleGroup) { + myFriends.bindBidirectional((Property) toggleGroup); + } + + /** + * The {@link ToggleGroup} to which this {@code Toggle} belongs. + * + * @return the toggle group property + */ + @Override + public ObjectProperty toggleGroupProperty() { + return myFriends; + } + + /** + * Indicates whether this {@code Toggle} is selected. + * + * @return {@code true} if this {@code Toggle} is selected. + */ + @Override + public boolean isSelected() { + return isToggled.get(); + } + + /** + * Sets this {@code Toggle} as selected or unselected. + * + * @param selected {@code true} to make this {@code Toggle} selected. + */ + @Override + public void setSelected(boolean selected) { + this.isToggled.set(selected); + } + + /** + * The selected state for this {@code Toggle}. + * + * @return the selected property + */ + @Override + public BooleanProperty selectedProperty() { + return isToggled; + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.java new file mode 100644 index 0000000..fb51094 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChatView.java @@ -0,0 +1,78 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.geometry.Orientation; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.SplitPane; +import javafx.scene.control.TextArea; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javax.print.attribute.standard.OrientationRequested; + +/** + * This is the view of the client chat gui. + */ +public class ChatView extends Node implements NodeWithChildren, ChildNode { + + + private Pane root; + + public void createNodeHierarchy(){ + Button send = new SendButton(); + AnchorPane whereTheSendFieldLives = new AnchorPane(); + whereTheSendFieldLives.getChildren().add(send); + + OutMsgTargetChooserNode chooseTarget = new OutMsgTargetChooserNode(); + AnchorPane whereTheTargetFieldLives = new AnchorPane(); + whereTheTargetFieldLives.getChildren().add(chooseTarget.getChildren()); + + TextArea clientOutgoingChatMsg = new TextArea(); + AnchorPane whereOutTextLives = new AnchorPane(); + whereOutTextLives.getChildren().add(clientOutgoingChatMsg); + + + TextArea target = new TextArea(); + + + SplitPane inputOutputSeperation = new SplitPane(); + SplitPane sendAndToggleSeperation = new SplitPane(); + HBox buttonAndTextSeperation = new HBox(); + + + + sendAndToggleSeperation.setOrientation(Orientation.HORIZONTAL); + sendAndToggleSeperation.getItems().add(whereTheSendFieldLives); + sendAndToggleSeperation.getItems().add(whereTheTargetFieldLives); + /* + buttonAndTextSeperation.a + buttonAndTextSeperation.getItems().add(sendAndToggleSeperation); + buttonAndTextSeperation.getItems().add() + */ + + inputOutputSeperation.setOrientation(Orientation.HORIZONTAL); + inputOutputSeperation.getItems().add(sendAndToggleSeperation); + + } + + @Override + public Pane getRootPane() { + return root; + } + + @Override + public ChildNode getInstance() { + return this; + } + + @Override + public void create() { + + } + + @Override + public Node getChildren() { + //TODO implement + return NodeWithChildren.super.getChildren(); + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChildNode.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChildNode.java new file mode 100644 index 0000000..537e609 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ChildNode.java @@ -0,0 +1,10 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.scene.layout.Pane; + +public interface ChildNode { + + public Pane getRootPane(); + public ChildNode getInstance(); + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ControlWrapper.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ControlWrapper.java new file mode 100644 index 0000000..578919e --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/ControlWrapper.java @@ -0,0 +1,9 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.scene.control.Control; + +public interface ControlWrapper { + + public Control getControl(); + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InChatObserver.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InChatObserver.java new file mode 100644 index 0000000..7dcb7da --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InChatObserver.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public interface InChatObserver { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InComingChMsg.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InComingChMsg.java new file mode 100644 index 0000000..9f37b26 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/InComingChMsg.java @@ -0,0 +1,225 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.beans.InvalidationListener; +import javafx.beans.property.Property; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +/** + * This class represents an incoming chat message to be displayed by the clients gui. When creating + * an instance we should make sure we are also passing a String, otherwise {@code incomingChatMsg} + * will have a null value. For now the {@code getValue()} and {@code setValue(Object value)} are the + * main focus. + */ + +public class InComingChMsg implements Property { + + private String incomingChatMsg; + + public InComingChMsg(String incomingChatMsg) { + this.incomingChatMsg = incomingChatMsg; + } + + public InComingChMsg() { + this.incomingChatMsg = null; + } + + /** + * Create a unidirection binding for this {@code Property}. + *

+ * Note that JavaFX has all the bind calls implemented through weak listeners. This means the + * bound property can be garbage collected and stopped from being updated. + * + * @param observable The observable this {@code Property} should be bound to. + * @throws NullPointerException if {@code observable} is {@code null} + */ + @Override + public void bind(ObservableValue observable) { + + } + + /** + * Remove the unidirectional binding for this {@code Property}. + *

+ * If the {@code Property} is not bound, calling this method has no effect. + * + * @see #bind(ObservableValue) + */ + @Override + public void unbind() { + + } + + /** + * Can be used to check, if a {@code Property} is bound. + * + * @return {@code true} if the {@code Property} is bound, {@code false} otherwise + * @see #bind(ObservableValue) + */ + @Override + public boolean isBound() { + return false; + } + + /** + * Create a bidirectional binding between this {@code Property} and another one. Bidirectional + * bindings exists independently of unidirectional bindings. So it is possible to add + * unidirectional binding to a property with bidirectional binding and vice-versa. However, this + * practice is discouraged. + *

+ * It is possible to have multiple bidirectional bindings of one Property. + *

+ * JavaFX bidirectional binding implementation use weak listeners. This means bidirectional + * binding does not prevent properties from being garbage collected. + * + * @param other the other {@code Property} + * @throws NullPointerException if {@code other} is {@code null} + * @throws IllegalArgumentException if {@code other} is {@code this} + */ + @Override + public void bindBidirectional(Property other) { + + } + + /** + * Remove a bidirectional binding between this {@code Property} and another one. + *

+ * If no bidirectional binding between the properties exists, calling this method has no effect. + *

+ * It is possible to unbind by a call on the second property. This code will work: + * + *

+   *     property1.bindBirectional(property2);
+   *     property2.unbindBidirectional(property1);
+   * 
+ * + * @param other the other {@code Property} + * @throws NullPointerException if {@code other} is {@code null} + * @throws IllegalArgumentException if {@code other} is {@code this} + */ + @Override + public void unbindBidirectional(Property other) { + + } + + /** + * Returns the {@code Object} that contains this property. If this property is not contained in an + * {@code Object}, {@code null} is returned. + * + * @return the containing {@code Object} or {@code null} + */ + @Override + public Object getBean() { + return null; + } + + /** + * Returns the name of this property. If the property does not have a name, this method returns an + * empty {@code String}. + * + * @return the name or an empty {@code String} + */ + @Override + public String getName() { + return null; + } + + /** + * Adds a {@link ChangeListener} which will be notified whenever the value of the {@code + * ObservableValue} changes. If the same listener is added more than once, then it will be + * notified more than once. That is, no check is made to ensure uniqueness. + *

+ * Note that the same actual {@code ChangeListener} instance may be safely registered for + * different {@code ObservableValues}. + *

+ * The {@code ObservableValue} stores a strong reference to the listener which will prevent the + * listener from being garbage collected and may result in a memory leak. It is recommended to + * either unregister a listener by calling {@link #removeListener(ChangeListener) removeListener} + * after use or to use an instance of {@link WeakChangeListener} avoid this situation. + * + * @param listener The listener to register + * @throws NullPointerException if the listener is null + * @see #removeListener(ChangeListener) + */ + @Override + public void addListener(ChangeListener listener) { + + } + + /** + * Removes the given listener from the list of listeners that are notified whenever the value of + * the {@code ObservableValue} changes. + *

+ * If the given listener has not been previously registered (i.e. it was never added) then this + * method call is a no-op. If it had been previously added then it will be removed. If it had been + * added more than once, then only the first occurrence will be removed. + * + * @param listener The listener to remove + * @throws NullPointerException if the listener is null + * @see #addListener(ChangeListener) + */ + @Override + public void removeListener(ChangeListener listener) { + + } + + /** + * Returns the current value of this {@code ObservableValue} + * + * @return The current value + */ + @Override + public String getValue() { + return this.incomingChatMsg; + } + + /** + * Set the wrapped value. + * + * @param value The new value + */ + @Override + public void setValue(Object value) { + this.incomingChatMsg = (String) value; + } + + /** + * Adds an {@link InvalidationListener} which will be notified whenever the {@code Observable} + * becomes invalid. If the same listener is added more than once, then it will be notified more + * than once. That is, no check is made to ensure uniqueness. + *

+ * Note that the same actual {@code InvalidationListener} instance may be safely registered for + * different {@code Observables}. + *

+ * The {@code Observable} stores a strong reference to the listener which will prevent the + * listener from being garbage collected and may result in a memory leak. It is recommended to + * either unregister a listener by calling {@link #removeListener(InvalidationListener) + * removeListener} after use or to use an instance of {@link WeakInvalidationListener} avoid this + * situation. + * + * @param listener The listener to register + * @throws NullPointerException if the listener is null + * @see #removeListener(InvalidationListener) + */ + @Override + public void addListener(InvalidationListener listener) { + + } + + /** + * Removes the given listener from the list of listeners, that are notified whenever the value of + * the {@code Observable} becomes invalid. + *

+ * If the given listener has not been previously registered (i.e. it was never added) then this + * method call is a no-op. If it had been previously added then it will be removed. If it had been + * added more than once, then only the first occurrence will be removed. + * + * @param listener The listener to remove + * @throws NullPointerException if the listener is null + * @see #addListener(InvalidationListener) + */ + @Override + public void removeListener(InvalidationListener listener) { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/NodeWithChildren.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/NodeWithChildren.java new file mode 100644 index 0000000..709c193 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/NodeWithChildren.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.scene.Node; + +/** + * Any class that represents a JavaFX node and has children should implement this interface + */ +public interface NodeWithChildren { + + void create(); + + public default Node getChildren() { + return null; + } + + void createNodeHierarchy(); +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutChatObserver.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutChatObserver.java new file mode 100644 index 0000000..aa93e98 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutChatObserver.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public interface OutChatObserver { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutMsgTargetChooserNode.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutMsgTargetChooserNode.java new file mode 100644 index 0000000..0a54cbc --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/OutMsgTargetChooserNode.java @@ -0,0 +1,32 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.collections.ObservableList; +import javafx.scene.Node; +import javafx.scene.control.Toggle; +import javafx.scene.control.ToggleGroup; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; + +public class OutMsgTargetChooserNode extends ToggleGroup implements NodeWithChildren { + + private Pane root; + private ObservableList targets; + + @Override + public void create() { + + } + + @Override + public Node getChildren() { + return NodeWithChildren.super.getChildren(); + } + + @Override + public void createNodeHierarchy() { + this.root = new HBox(); + for(Node n : targets) + root.getChildren().add(n); + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/PropertyButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/PropertyButton.java new file mode 100644 index 0000000..2e0f1fc --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/PropertyButton.java @@ -0,0 +1,5 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +public interface PropertyButton { + +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/SendButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/SendButton.java new file mode 100644 index 0000000..56ebe45 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/SendButton.java @@ -0,0 +1,20 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.scene.Node; +import javafx.scene.control.Button; + +/** + * Represents the button in the chat to send a chat message. + */ +public class SendButton extends Button implements UINode { + + + public SendButton() { + super("Send"); + } + + @Override + public void listen() { + + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/UINode.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/UINode.java new file mode 100644 index 0000000..7baa136 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/UINode.java @@ -0,0 +1,9 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +/** + * Any class that represents a JavaFX node that takes user input should implement this interface. + */ +public interface UINode { + + void listen(); +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/WhisperButton.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/WhisperButton.java new file mode 100644 index 0000000..2f18c42 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/client/gui/chat/WhisperButton.java @@ -0,0 +1,16 @@ +package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat; + +import javafx.scene.control.Control; +import javafx.scene.control.RadioButton; + +/** + * Represents the toggle for a whisper chat. + */ +public class WhisperButton implements ControlWrapper { + + private static RadioButton whisper = new RadioButton("Whisper"); + @Override + public Control getControl() { + return null; + } +} 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 1bc06ca..b974ff4 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 @@ -86,7 +86,7 @@ public class Protocol { public static final String clientQuitRequest = "QUITR"; /** - * Client sends this message when they want to create a new game. + * Client sends this message when they want to create a new lobby (& automatically join it). * Client issues this command in {@link ch.unibas.dmi.dbis.cs108.multiplayer.client.MessageFormatter} * using "/g". * First a lobby {@link Lobby} is created of which the requesting client is the admin of. @@ -94,7 +94,7 @@ public class Protocol { public static final String createNewLobby = "CRTLB"; /** - * Represents a clients' request for a list of lobbies + * Represents a clients' request for a list of lobbies, plus what players are in them. */ public static final String listLobbies = "LISTL"; diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Lobby.java b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Lobby.java index 68b46ee..c943f24 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Lobby.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/multiplayer/server/Lobby.java @@ -115,6 +115,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 if (clientIsInLobby(client) == -1) { lobbyClients.add(client); ClientHandler.broadcastAnnouncementToAll(client.getClientUserName() + " has joined lobby " + this.getLobbyID()); 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 d67f759..052a7d7 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 @@ -14,7 +14,7 @@ public class Server { public static final Logger LOGGER = LogManager.getLogger(); public static final BudaLogConfig l = new BudaLogConfig(LOGGER); - private static final int gamePort = 42069; + private static int gamePort; private HashSet connectedClients = new HashSet<>(); private ServerSocket serverSocket; Scanner sc = new Scanner(System.in); @@ -28,7 +28,7 @@ public class Server { */ public void startServer() { try { - System.out.println("Port 42069 is open."); + System.out.println("Port " + gamePort + " is open."); while (!serverSocket.isClosed()) { Socket socket = serverSocket.accept(); ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress()); @@ -53,6 +53,19 @@ public class Server { } public static void main(String[] args) { + ServerSocket serverSocket = null; + gamePort = 1873; + try { + serverSocket = new ServerSocket(gamePort); + } catch (IOException e) { + e.printStackTrace(); + } + Server server = new Server(serverSocket); + server.startServer(); + } + + public static void main(int port) { + gamePort = port; ServerSocket serverSocket = null; try { serverSocket = new ServerSocket(gamePort);