Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Sazonov 2022-04-28 13:30:05 +02:00
commit b94c1ab3f4
367 changed files with 969 additions and 95 deletions

View File

@ -329,3 +329,6 @@ gebracht. Es war wie so oft die einfachste Lösung.
- 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

0
Meilenstein IV/.gitkeep Normal file
View File

340
Meilenstein IV/Diary.txt Normal file
View File

@ -0,0 +1,340 @@
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
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

View File

@ -36,6 +36,7 @@ dependencies {
implementation 'org.openjfx:javafx-controls:18'
implementation 'org.apache.commons:commons-collections4:4.4'
implementation 'org.openjfx:javafx:19-ea+5'
implementation 'org.testng:testng:7.1.0'
testImplementation('org.junit.jupiter:junit-jupiter:5.8.2')
}

View File

@ -60,4 +60,5 @@ public class ClientVoteData {
LOGGER.warn("Position is:" + position);
}
}
}

View File

@ -92,13 +92,13 @@ public class GameState {
}
/**
* Collects the current position of all ghosts and saves them in an array
* Collects the current position of all not kicked off ghosts and saves them in an array
* @return Boolean array, true if there is a ghost at that position
*/
public boolean[] getPositionOfGhosts(){
boolean[] ghosts = new boolean[passengerTrain.length];
for(int i = 0; i < passengerTrain.length; i++) {
if(passengerTrain[i].getIsGhost()) {
if(passengerTrain[i].getIsGhost() && !passengerTrain[i].getKickedOff()) {
ghosts[i] = true;
}
}

View File

@ -0,0 +1,75 @@
package ch.unibas.dmi.dbis.cs108.gamelogic;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* A class that handles all timed events in the game, such as vote times
*/
public class Timer {
public static final Logger LOGGER = LogManager.getLogger(Timer.class);
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
/**
* The maximum length of the ghost vote in the night, in seconds
*/
public static final int ghostVote = 30;
/**
* The maximum length of the human vote in the day, in seconds
*/
public static final int humanVote = 60;
/**
* The checking intervall in seconds
*/
public static final int intervall = 1;
/**
* The timer for the ghost vote. Checks every {@code intervall} seconds if every ghost has already voted.
* If all have voted or if the {@code ghostVote} value is reached, the timer ends
* @param game the game this Timer has been called in
*/
public static void ghostVoteTimer(Game game) {
int counter = 0;
while(counter < ghostVote) {
if(haveAllGhostsVoted(game)) { //if all ghost have voted
return;
}
try {
Thread.sleep(intervall*1000);
} catch (InterruptedException e) {
LOGGER.warn("Thread " + Thread.currentThread() + " was interrupted");
}
counter = counter + (intervall*1000);
}
}
/**
* Checks if all ghosts in the game have already voted, returns true if so
* @param game the Game the ghosts live in
* @return true if all Ghosts have voted and false if at least 1 didn't
*/
public static boolean haveAllGhostsVoted(Game game) {
int nrOfGhosts = 0;
int j = 0; //counter
boolean[] positionOfGhosts = game.gameState.getPositionOfGhosts();
boolean[] whoHasVoted = game.getGameState().getClientVoteData().getHasVoted();
for (boolean positionOfGhost : positionOfGhosts) { //determines how many ghosts are in the game
if (positionOfGhost) {
nrOfGhosts++;
}
}
for(int i = 0; i < positionOfGhosts.length; i++) {
if (positionOfGhosts[i]) {
if(whoHasVoted[i]) {
j++;
}
}
}
return nrOfGhosts == j;
}
}

View File

@ -50,11 +50,7 @@ public class VoteHandler {
}
}
try { // waits 30 seconds before votes get collected
Thread.sleep(10*1000);
} catch (InterruptedException e) {
LOGGER.warn("Thread " + Thread.currentThread() + " was interrupted");
}
Timer.ghostVoteTimer(game);
int currentMax = ghostVoteEvaluation(passengers, votesForPlayers, game.getGameState().getClientVoteData(), game);

View File

@ -71,6 +71,7 @@ public class GhostNPC extends Ghost {
int randomPosition = (int) (Math.random() * humanPositions.length);
vote = humanPositions[randomPosition];
hasVoted = true;
game.getGameState().getClientVoteData().setHasVoted(position,hasVoted);
LOGGER.info("GhostNPC at Position: " + this.getPosition() + " has voted for: " + vote);
}
}

View File

@ -67,6 +67,7 @@ public class HumanNPC extends Human {
int randomNr = (int) (Math.random() * inGamePositions.length);
vote = inGamePositions[randomNr];
hasVoted = true;
game.getGameState().getClientVoteData().setHasVoted(position,hasVoted);
LOGGER.info("HumanNPC at Position: " + this.getPosition() + " has voted for: " + vote);
}
}

View File

@ -0,0 +1,5 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui;
public class ClientListViewController {
}

View File

@ -0,0 +1,5 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui;
public class LobbyListView {
}

View File

@ -0,0 +1,5 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui;
public class LobbySceneViewController {
}

View File

@ -0,0 +1,5 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui;
public class ServerMessageViewController {
}

View File

@ -0,0 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons;
import javafx.scene.control.Button;
public class ChangeNameButton extends Button {
}

View File

@ -0,0 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons;
import java.awt.Button;
public class JoinGameButton extends Button {
}

View File

@ -0,0 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons;
import javafx.scene.control.Button;
public class LeaveServerButton extends Button {
}

View File

@ -0,0 +1,7 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.buttons;
import javafx.scene.control.Button;
public class NewGameButton extends Button {
}

View File

@ -84,7 +84,7 @@ public class ChatApp extends Application {
public void start(Stage primaryStage) throws Exception {
this.setcModel(clientModel);
URL resource = ChatApp.class.getResource(
"splitPaneChatView.fxml");
"ChatView.fxml");
if (resource == null) {
System.out.println("File wasnt found");
}
@ -92,7 +92,7 @@ public class ChatApp extends Application {
try {
Parent root = FXMLLoader.load(
Objects.requireNonNull(ChatApp.class.getResource(
"splitPaneChatView.fxml")));
"ChatView.fxml")));
// TODO bin chatController.getChatPaneRoot() border to root border for rezising
Scene scene = new Scene(root);
scene.setRoot(root);

View File

@ -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,15 +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,7 +42,15 @@ public class ChatController implements Initializable {
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
@FXML
private SplitPane chatPaneRoot;
private Group vboxGroup;
@FXML
private GridPane vBoxGridPane;
@FXML
private ScrollPane ChatScrollPane;
@FXML
private VBox vBoxServerMessage;
@FXML
private Pane chatPaneRoot;
@FXML
private VBox vBoxChatMessages;
@FXML
@ -41,7 +58,7 @@ public class ChatController implements Initializable {
@FXML
private TextField whisperTargetSelectField;
@FXML
private TextArea chatMsgField;
private TextField chatMsgField;
private static ClientModel client;
@ -100,32 +117,23 @@ public class ChatController implements Initializable {
public void changed(ObservableValue<? extends Number> 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<ActionEvent>() {
@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<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
sendChatMsg();
}
});
@ -155,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
*/
@ -171,7 +202,7 @@ public class ChatController implements Initializable {
this.client = client;
}
public SplitPane getChatPaneRoot() {
public Pane getChatPaneRoot() {
return chatPaneRoot;
}
@ -182,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 {

View File

@ -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<ActionEvent> {
/**
* 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) {
}
}

View File

@ -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<ActionEvent> {
/**
* 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) {
}
}

View File

@ -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<ActionEvent> {
/**
* 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) {
}
}

View File

@ -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<ActionEvent> {
/**
* 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) {
}
}

View File

@ -0,0 +1,49 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.game;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.text.TextFlow;
public class GameController {
@FXML
private Group roomButtonGroupDay;
@FXML
private Button buttonRoom0;
@FXML
private Button buttonRoom1;
@FXML
private Button buttonRoom2;
@FXML
private Button buttonRoom3;
@FXML
private Button buttonRoom4;
@FXML
private Button buttonRoom5;
@FXML
private HBox roomLables;
@FXML
private TextField lableRoom0;
@FXML
private TextField lableRoom1;
@FXML
private TextField lableRoom2;
@FXML
private TextField lableRoom3;
@FXML
private TextField lableRoom4;
@FXML
private TextField lableRoom5;
@FXML
private Button noiseButton;
@FXML
private TextFlow notificationText;
}

View File

@ -0,0 +1,5 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge;
public class LoungeSceneViewController {
}

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ClientListViewController"
prefHeight="400.0" prefWidth="600.0">
</AnchorPane>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.LobbyListView"
prefHeight="400.0" prefWidth="600.0">
</AnchorPane>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ServerMessageViewController"
prefHeight="400.0" prefWidth="600.0">
</AnchorPane>

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollBar?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane fx:id="chatPaneRoot" prefHeight="251.0" prefWidth="343.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat.ChatController">
<children>
<GridPane alignment="CENTER" layoutY="149.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="251.0" prefWidth="343.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="10.0" percentHeight="70.0" valignment="TOP" vgrow="ALWAYS" />
<RowConstraints maxHeight="-Infinity" minHeight="10.0" percentHeight="30.0" valignment="CENTER" vgrow="ALWAYS" />
</rowConstraints>
<children>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<children>
<ScrollPane fx:id="ChatScrollPane" fitToHeight="true" fitToWidth="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="176.0" prefWidth="343.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<VBox fx:id="vBoxChatMessages" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefWidth="170.0" spacing="2.0" />
</content>
</ScrollPane>
</children>
</AnchorPane>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" GridPane.rowIndex="1">
<children>
<GridPane alignment="CENTER" layoutX="10.0" layoutY="20.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="75.0" prefWidth="343.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="7.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="67.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="90.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="92.0" prefWidth="98.0" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS">
<children>
<Button fx:id="sendButton" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" prefHeight="157.0" prefWidth="223.5" text="Send" textOverrun="CENTER_WORD_ELLIPSIS" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<font>
<Font size="10.0" />
</font></Button>
</children>
<GridPane.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</GridPane.margin>
</AnchorPane>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="92.0" prefWidth="85.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS">
<children>
<TextField fx:id="whisperTargetSelectField" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="50.0" prefWidth="79.0" promptText="whisper..." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
<GridPane.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</GridPane.margin>
</AnchorPane>
<AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="92.0" prefWidth="366.0" GridPane.columnIndex="2" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.valignment="CENTER" GridPane.vgrow="ALWAYS">
<children>
<TextField fx:id="chatMsgField" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="50.0" prefWidth="213.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
<GridPane.margin>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</GridPane.margin>
</AnchorPane>
</children>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding>
</GridPane>
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets bottom="2.0" left="5.0" right="5.0" top="5.0" />
</padding>
</AnchorPane>
</children>
</GridPane>
<GridPane fx:id="vBoxGridPane" alignment="CENTER" disable="true" layoutX="-14.0" layoutY="-235.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="167.0" prefWidth="331.0">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="73.0" prefWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="66.0" prefWidth="100.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="10.0" percentWidth="7.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints fillHeight="false" maxHeight="1.7976931348623157E308" minHeight="10.0" percentHeight="100.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<ScrollBar orientation="VERTICAL" prefHeight="196.0" prefWidth="16.0" GridPane.columnIndex="2" />
<VBox fx:id="vBoxServerMessage" alignment="TOP_RIGHT" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="184.0" prefWidth="212.0" spacing="2.0" GridPane.columnIndex="1" />
</children>
</GridPane>
</children>
</AnchorPane>

View File

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat.ChatController">
<children>
<SplitPane fx:id="chatPaneRoot" dividerPositions="0.5" layoutX="214.0" layoutY="92.0" orientation="VERTICAL" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<ScrollPane layoutX="149.0" layoutY="-18.0" prefHeight="196.0" prefWidth="598.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<VBox fx:id="vBoxChatMessages" prefHeight="200.0" prefWidth="581.0" />
</content>
</ScrollPane>
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<SplitPane dividerPositions="0.29797979797979796" layoutX="166.0" layoutY="8.0" prefHeight="195.0" prefWidth="598.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<SplitPane dividerPositions="0.5" layoutY="-3.0" orientation="VERTICAL" prefHeight="193.0" prefWidth="174.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<Button fx:id="sendButton" layoutX="50.0" layoutY="21.0" mnemonicParsing="false" prefHeight="92.0" prefWidth="172.0" text="Send" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<TextField fx:id="whisperTargetSelectField" layoutY="14.0" prefHeight="92.0" prefWidth="172.0" promptText="whisper..." AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
<padding>
<Insets bottom="5.0" left="5.0" top="3.0" />
</padding>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<TextArea fx:id="chatMsgField" layoutX="120.0" layoutY="-30.0" prefHeight="193.0" prefWidth="415.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
<padding>
<Insets bottom="5.0" right="5.0" />
</padding>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>
</items>
</SplitPane>
</children>
</AnchorPane>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -0,0 +1,26 @@
*{
}
.button{
}
.roomButtonGroup{
-fx-background-color: transparent;
}
.text-field{
-fx-text-fill: white;
-fx-background-color: transparent;
-fx-effect: null;
-fx-animated: null;
}
.notificationText{
-fx-alignment: center;
-fx-text-fill: black;
-fx-font-family: Bahnschrift;
-fx-font-weight: bold;
}

View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.TextFlow?>
<AnchorPane id="BG" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="812.0" prefWidth="1200.0" styleClass="theme" stylesheets="@GameDay.css" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.game.GameController">
<children>
<Group fx:id="roomButtonGroupDay" layoutX="230.5" layoutY="220.0">
<children>
<Button id="room1" fx:id="buttonRoom0" accessibleRole="RADIO_BUTTON" alignment="TOP_CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="21.5" minWidth="-Infinity" mnemonicParsing="false" prefHeight="110.0" prefWidth="90.0" text="room0">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room1button.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button id="room1" fx:id="buttonRoom1" accessibleRole="RADIO_BUTTON" alignment="CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="114.5" layoutY="19.800003051757812" minWidth="-Infinity" mnemonicParsing="false" prefHeight="101.0" prefWidth="90.0" text="room1">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room2button.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button id="room1" fx:id="buttonRoom2" accessibleRole="RADIO_BUTTON" alignment="CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="207.5" layoutY="39.59999084472656" minWidth="-Infinity" mnemonicParsing="false" prefHeight="110.0" prefWidth="90.0" text="room2">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room3button.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button id="room1" fx:id="buttonRoom3" accessibleRole="RADIO_BUTTON" alignment="CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="300.5" layoutY="59.40000915527344" minWidth="-Infinity" mnemonicParsing="false" prefHeight="110.0" prefWidth="90.0" text="room3">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room4button.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button id="room1" fx:id="buttonRoom4" accessibleRole="RADIO_BUTTON" alignment="CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="393.5999755859375" layoutY="79.40000915527344" minWidth="-Infinity" mnemonicParsing="false" prefHeight="110.0" prefWidth="90.0" text="room4">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room5button.png" />
</image>
</ImageView>
</graphic>
</Button>
<Button id="room1" fx:id="buttonRoom5" accessibleRole="RADIO_BUTTON" alignment="CENTER" contentDisplay="GRAPHIC_ONLY" layoutX="486.8499755859375" layoutY="99.99998474121094" minWidth="-Infinity" mnemonicParsing="false" prefHeight="110.0" prefWidth="90.0" text="room5">
<font>
<Font size="25.0" />
</font>
<graphic>
<ImageView fitHeight="109.2" fitWidth="136.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@DayOpen/room6button.png" />
</image>
</ImageView>
</graphic>
</Button>
<HBox fx:id="roomLables" alignment="CENTER" layoutX="10.0" layoutY="50.0" prefHeight="62.0" prefWidth="571.0" rotate="12.4">
<children>
<TextField fx:id="lableRoom0" alignment="CENTER" editable="false" prefHeight="40.0" text="Seraina Ghost">
<font>
<Font size="14.0" />
</font>
</TextField>
<TextField fx:id="lableRoom1" accessibleRole="TEXT" alignment="CENTER" editable="false" prefHeight="40.0">
<font>
<Font size="14.0" />
</font>
</TextField>
<TextField fx:id="lableRoom2" accessibleRole="TEXT" alignment="CENTER" editable="false" prefHeight="40.0">
<font>
<Font size="14.0" />
</font>
</TextField>
<TextField fx:id="lableRoom3" accessibleRole="TEXT" alignment="CENTER" editable="false" prefHeight="40.0">
<font>
<Font size="14.0" />
</font>
</TextField>
<TextField fx:id="lableRoom4" accessibleRole="TEXT" alignment="CENTER" editable="false" prefHeight="40.0">
<font>
<Font size="14.0" />
</font>
</TextField>
<TextField fx:id="lableRoom5" accessibleRole="TEXT" alignment="CENTER" editable="false" prefHeight="40.0">
<font>
<Font size="14.0" />
</font>
</TextField>
</children>
</HBox>
</children>
</Group>
<Button fx:id="noiseButton" alignment="CENTER" layoutX="236.0" layoutY="606.0" mnemonicParsing="false" prefHeight="59.0" prefWidth="128.0" text="I heard some noise" />
<TextFlow fx:id="notificationText" layoutX="359.0" layoutY="14.0" prefHeight="200.0" prefWidth="500.0" textAlignment="CENTER" />
</children>
</AnchorPane>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="1080.0" prefWidth="1920.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Some files were not shown because too many files have changed in this diff Show More