Build a new construct for the LobbyLists from scratch. now it is based on a tree view and constantly updated by the server

This commit is contained in:
Seraina 2022-05-16 15:57:30 +02:00
parent 7a81987316
commit d383ef1267
15 changed files with 451 additions and 7 deletions

View File

@ -19,7 +19,7 @@ public class BudaLogConfig {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration config = ctx.getConfiguration();
LoggerConfig loggerConfig = config.getLoggerConfig(LogManager.ROOT_LOGGER_NAME);
loggerConfig.setLevel(Level.WARN); // change level here
loggerConfig.setLevel(Level.INFO); // change level here
ctx.updateLoggers(); // This causes all Loggers to refetch information from their LoggerConfig.
}

View File

@ -10,6 +10,7 @@ import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ChatApp;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.Sprites;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat.ChatController;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.game.GameController;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.LobbyDisplayHandler;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.LoungeApp;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.LoungeSceneViewController;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ClientPinger;
@ -48,6 +49,7 @@ public class Client {
private GameStateModel gameStateModel;
private GameController gameController;
private DayNightChangeListener dayNightChangeListener;
private LobbyDisplayHandler lobbyDisplayHandler;
private GUI gui;
@ -92,6 +94,7 @@ public class Client {
this.gameController = new GameController(ChatApp.getClientModel(), gameStateModel);
this.loungeApp = new LoungeApp(ChatApp.getClientModel());
this.loungeSceneViewController = new LoungeSceneViewController();
this.lobbyDisplayHandler = new LobbyDisplayHandler();
LoungeSceneViewController.setClient(ChatApp.getClientModel());
} catch (IOException e) {
e.printStackTrace();
@ -412,6 +415,10 @@ public class Client {
case GuiParameters.removeLobby:
removeLobbyFromGui(data);
break;
case GuiParameters.updateLobbyString:
lobbyDisplayHandler.updateLobbies(data);
ChatApp.getListController().updateList();
break;
default:
notificationTextDisplay(data);
//TODO(Sebi,Seraina): should the gameController be in the Application just like the ChatController?

View File

@ -65,13 +65,12 @@ public class JClientProtocolParser {
c.changeUsername(msg.substring(6));
break;
case Protocol.printToGUI:
LOGGER.info("First line of printToGui case!");
String substring = msg.substring(6);
LOGGER.debug("Following parameters where recieved: " + substring);
int index = substring.indexOf("$");
LOGGER.debug("Index of $: " + index);
String parameter = "";
String data = substring;
LOGGER.debug(data);
try {
parameter = substring.substring(0, index);
data = substring.substring(index + 1);

View File

@ -4,6 +4,7 @@ import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ClientModel;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.chat.ChatController;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.game.GameController;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.ListOfLobbiesController;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.LoungeSceneViewController;
import java.net.URL;
import java.util.Objects;
@ -28,10 +29,13 @@ public class ChatApp extends Application {
private GameController gameC;
private static LoungeSceneViewController loungeSceneViewController;
private LoungeSceneViewController lSVController;
private static ListOfLobbiesController listController;
private ListOfLobbiesController listOfLobbiesController;
public Node chat;
public Node game;
public Node backgroundDay;
public Node lobbyList;
public ChatApp() {
super();
@ -137,6 +141,22 @@ public class ChatApp extends Application {
loungeSceneViewController = controller;
}
public void setListOfLobbiesController(
ListOfLobbiesController listOfLobbiesController) {
this.listOfLobbiesController = listOfLobbiesController;
}
public static void setListController(ListOfLobbiesController controller) {
listController = controller;
}
public static ListOfLobbiesController getListController() {
return listController;
}
public ListOfLobbiesController getListOfLobbiesController() {
return listOfLobbiesController;
}
/**
* The main entry point for all JavaFX applications. The start method is called after the init
@ -165,9 +185,11 @@ public class ChatApp extends Application {
URL chatResource = ChatApp.class.getResource("chat/ChatView.fxml");
URL gameResource = ChatApp.class.getResource("game/GameDayAll.fxml");
URL bgDayResource = ChatApp.class.getResource("TrainAnimationViewDay.fxml");
URL listForLobbiesResource = ChatApp.class.getResource("lounge/ListOfLobbiesScrollPane.fxml");
this.chat = FXMLLoader.load(Objects.requireNonNull(chatResource));
this.game = FXMLLoader.load(Objects.requireNonNull(gameResource));
this.backgroundDay = FXMLLoader.load(Objects.requireNonNull(bgDayResource));
this.lobbyList = FXMLLoader.load(Objects.requireNonNull(listForLobbiesResource));
LOGGER.debug(bgDayResource);
} catch (Exception e) {
LOGGER.warn("There was an Exception while loading");
@ -180,6 +202,8 @@ public class ChatApp extends Application {
Objects.requireNonNull(loungeResource));
this.setlSVController(loungeSceneViewController);
lSVController.setChatApp(this);
listOfLobbiesController = listController;
listOfLobbiesController.setChatApp(this);
// TODO bin chatController.getChatPaneRoot() border to root border for rezising
Scene scene = new Scene(lounge);
scene.setRoot(lounge);

View File

@ -0,0 +1,126 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge;
import static javafx.scene.control.PopupControl.USE_COMPUTED_SIZE;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.Client;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ChatApp;
import ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.ClientModel;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.Lobby;
import ch.unibas.dmi.dbis.cs108.multiplayer.server.LobbyUpdater;
import java.net.URL;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Background;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
public class ListOfLobbiesController implements Initializable {
@FXML
private ScrollPane backDropScrolePane;
@FXML
private AnchorPane scollingAnchorPane;
@FXML
private VBox LobbyListVBox;
private ChatApp chatApp; //TODO: VeryImportant to set this one right!
private HashSet<TreeView> treeViews = new HashSet<TreeView>();
public void setChatApp(ChatApp chatApp) {
this.chatApp = chatApp;
}
public void updateList() {
clearVBox();
for (LobbyModel lobby : LobbyDisplayHandler.getLobbies()) {
newTreeView(lobby.getId(), lobby.getAdmin(), chatApp.getcModel().getUsername(), lobby.getMembers());
}
}
/**
* Creates one new TreeView for one Lobby
* @param lobbyId the id of the lobby
* @param admin the admin of the lobby
* @param userName the username of the client
*/
public void newTreeView(int lobbyId, String admin, String userName, HashSet<String> members) {
try {
Button button = new Button();
if (admin.equals(userName)) { // the client of this user is the admin of this lobby
button.setOnAction(event -> startGame());
button.setText("Start");
} else {
button.setOnAction(event -> joinALobby(lobbyId));
button.setText("Join");
}
HBox rootHBox = new HBox();
rootHBox.setPrefWidth(195);
rootHBox.setMaxHeight(20);
Label adminLabel = new Label(lobbyId + " " + admin);
adminLabel.setTextFill(Color.WHITE);
rootHBox.getChildren().add(adminLabel);
rootHBox.getChildren().add(button);
TreeItem<HBox> root = new TreeItem<HBox>(rootHBox);
for (String member : members) {
HBox memberBox = new HBox();
memberBox.setPrefWidth(195);
memberBox.setMaxHeight(20);
Label memberLabel = new Label(member);
memberLabel.setTextFill(Color.WHITE);
memberBox.getChildren().add(memberLabel);
root.getChildren().add(new TreeItem<HBox>(memberBox));
}
TreeView<HBox> treeView = new TreeView<>(root);
treeView.setVisible(true);
treeView.setPrefWidth(195);
treeView.setMaxHeight(USE_COMPUTED_SIZE);
Platform.runLater(new Runnable() {
@Override
public void run() {
LobbyListVBox.getChildren().add(treeView);
LobbyListVBox.setVisible(true);
//LobbyListVBox.setBackground(Background.fill(Color.DARKBLUE));
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void clearVBox() {
Platform.runLater(new Runnable() {
@Override
public void run() {
LobbyListVBox.getChildren().clear();
}
});
}
public void startGame() {
chatApp.getcModel().getClient().sendMsgToServer(Protocol.startANewGame); //TODO: Very important to get right!
}
public void joinALobby(int id) {
chatApp.getcModel().getClient().sendMsgToServer(Protocol.joinLobby + "$" + id);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
ChatApp.setListController(this);
}
}

View File

@ -0,0 +1,114 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import java.util.HashSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LobbyDisplayHandler {
public static final Logger LOGGER = LogManager.getLogger(LobbyDisplayHandler.class);
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
private static HashSet<LobbyModel> lobbies = new HashSet<>();
public static HashSet<LobbyModel> getLobbies() {
return lobbies;
}
/**
* searches lobbies for a lobby with a certain id
* @param id the int representing a Lobby id to be lookes for
* @return the LobbyModel with the id if found and null otherwise
*/
public LobbyModel searchForLobbyId(int id) {
for(LobbyModel lobby : lobbies) {
if (lobby.getId() == id) {
return lobby;
}
}
return null;
}
public void updateLobbies(String data) {
try {
for (LobbyModel model : lobbies) {
model.setHasBeenVisited(false);
}
String[] lobbiesString = data.split("\\$");
//System.out.println(lobbiesString.length);
for (String lobby : lobbiesString) {
String[] oneLobby = lobby.split(":");
//System.out.println(oneLobby.length);
int id = Integer.parseInt(oneLobby[0]);
String admin = oneLobby[1];
boolean isOpen = Boolean.parseBoolean(oneLobby[2]);
if (searchForLobbyId(id) == null) { //the lobby is new and has not been saved yet
addLobbyFromString(id, admin, isOpen, oneLobby);
} else { // the lobby exists but might need to be updated
updateExistingLobby(id, isOpen, oneLobby);
}
}
//System.out.println("lobby size before removal: " + lobbies.size());
lobbies.removeIf(
lobby -> !lobby.isHasBeenVisited()); //removes all lobbies that aren't in this string
} catch (Exception e) {
e.printStackTrace();
LOGGER.info("empty list");
}
}
private void addLobbyFromString(int id, String admin, boolean isOpen, String[] oneLobby) {
//System.out.println("add Lobby");
LobbyModel newLobby = new LobbyModel(id, admin);
newLobby.setHasBeenVisited(true);
//System.out.println(newLobby);
newLobby.setLobbyIsOpen(isOpen);
for (int i = 3; i < oneLobby.length; i++) {
newLobby.addMember(oneLobby[i]);
//System.out.println(oneLobby[i]);
}
lobbies.add(newLobby);
//System.out.println("lobby size: " + lobbies.size());
}
private void updateExistingLobby(int id, boolean isOpen, String[] oneLobby) {
//System.out.println("update");
LobbyModel oldLobby = searchForLobbyId(id);
oldLobby.setHasBeenVisited(true);
oldLobby.setLobbyIsOpen(isOpen);
oldLobby.removeAllMembers();
for (int i = 3; i < oneLobby.length; i++) {
oldLobby.addMember(oneLobby[i]);
}
}
public static void main(String[] args) {
LobbyDisplayHandler handler = new LobbyDisplayHandler();
String lobby = "1:Seraina:true:Alex:Jonas$2:Sebi:false:Maria:Claudia:Hansli$3:Vanessa:true:Lara:Flu";
handler.updateLobbies(lobby);
System.out.println("lobby size in main:" + lobbies.size());
for (LobbyModel model : lobbies) {
//System.out.println(model);
System.out.println("Lobby " + model.getId() + " " + model.isLobbyIsOpen() + " (" + model.getAdmin() + "):");
for (String member : model.getMembers()) {
System.out.println("- " + member);
}
}
String lobby2 = "1:Seraina:true:Alex:Jonas$3:Vanessa:true:Lara:Flu:Sebastian";
handler.updateLobbies(lobby2);
System.out.println("lobby size in main:" + lobbies.size());
for (LobbyModel model : lobbies) {
//System.out.println(model);
System.out.println("Lobby " + model.getId() + " " + model.isLobbyIsOpen() + " (" + model.getAdmin() + "):");
for (String member : model.getMembers()) {
System.out.println("- " + member);
}
}
System.out.println("done");
}
}

View File

@ -0,0 +1,60 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge;
import java.util.HashSet;
/**
* This is a simple model of a Lobby designed to save Lobby objects for display
*/
public class LobbyModel {
private final int id;
private final String admin;
private HashSet<String> members = new HashSet<String>(5);
private boolean lobbyIsOpen = true;
private boolean hasBeenVisited = false;
public LobbyModel(int id, String admin) {
this.id = id;
this.admin = admin;
}
public void addMember(String name) {
members.add(name);
}
public void removeMember(String name) {
members.remove(name);
}
public void removeAllMembers() {
members.clear();
}
public HashSet<String> getMembers() {
return members;
}
public int getId() {
return id;
}
public String getAdmin() {
return admin;
}
public void setHasBeenVisited(boolean hasBeenVisited) {
this.hasBeenVisited = hasBeenVisited;
}
public boolean isHasBeenVisited() {
return hasBeenVisited;
}
public void setLobbyIsOpen(boolean lobbyIsOpen) {
this.lobbyIsOpen = lobbyIsOpen;
}
public boolean isLobbyIsOpen() {
return lobbyIsOpen;
}
}

View File

@ -48,6 +48,8 @@ public class LoungeSceneViewController implements Initializable {
public static final Logger LOGGER = LogManager.getLogger(LoungeSceneViewController.class);
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
@FXML
private AnchorPane listLobbyAnchorPane;
@FXML
private AnchorPane buttonPane;
@FXML
@ -146,6 +148,7 @@ public class LoungeSceneViewController implements Initializable {
LOGGER.debug("Lobby in initialize" + LobbyListView);
addChatView();
addBackgroundDay();
addListOfLobbiesView();
LOGGER.debug("cApp = " + cApp);
LOGGER.debug("chatApp = " + chatApp);
TrainAnimationDayController.setcApp(cApp);
@ -153,6 +156,7 @@ public class LoungeSceneViewController implements Initializable {
bgAnimationView.setFitHeight(1950);
bgAnimationView.setFitWidth(6667.968);
LobbyListView.setItems(lobbies);
LOGGER.debug("In Initialize 2 LobbyListView" + LobbyListView);
LobbyListView.setCellFactory(param -> {
@ -257,6 +261,22 @@ public class LoungeSceneViewController implements Initializable {
LobbyListView.setVisible(true);
}
/**
* Adds the new LobbyListView
*/
public void addListOfLobbiesView() {
Platform.runLater(new Runnable() {
@Override
public void run() {
try {
listLobbyAnchorPane.getChildren().add(chatApp.lobbyList);
} catch (Exception e) {
LOGGER.warn(e.getMessage());
}
}
});
}
/**
* Adds the gameView to the existing LobbyView
*/
@ -303,7 +323,6 @@ public class LoungeSceneViewController implements Initializable {
public void run() {
try {
ChatArea.getChildren().add(chatApp.chat);
LOGGER.debug("¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ ChatArea: " + ChatArea);
} catch (Exception e) {
LOGGER.debug("Not yet initialized: chatAnchorPane");
}

View File

@ -105,4 +105,9 @@ public class GuiParameters {
* Tells the GUI at which position you are sitting {@code POSITION$integer}
*/
public static final String yourPosition = "POSITION";
/**
* Tells gui to Update its lobbies from a String {@code ULS$id:admin:meber1:member2:...$id:admin:member1...}
*/
public static final String updateLobbyString = "ULS";
}

View File

@ -59,6 +59,7 @@ public class Lobby {
* @param admin the Client who called CRTGM
*/
public Lobby(ClientHandler admin) {
this.admin = admin;
this.lobbyClients.add(admin);
lobbies.add(this);
@ -69,6 +70,7 @@ public class Lobby {
this.lobbyID = helper;
ClientHandler.broadcastAnnouncementToAll("New Lobby created by " + admin.getClientUserName() +
". This lobby's ID: " + this.lobbyID);
System.out.println(lobbiesToString());
}
/**
@ -260,4 +262,20 @@ public class Lobby {
*/
}
public static String lobbiesToString() {
StringBuilder lobbyStringBuilder = new StringBuilder();
for (Lobby lobby : lobbies) {
ClientHandler admin = lobby.getAdmin();
lobbyStringBuilder.append(lobby.getLobbyID()).append(":").append(admin.getClientUserName())
.append(":").append(lobby.getLobbyIsOpen());
for (ClientHandler client : lobby.getLobbyClients()) {
if (!client.equals(admin)) {
lobbyStringBuilder.append(":").append(client.getClientUserName());
}
}
lobbyStringBuilder.append("$");
}
return lobbyStringBuilder.toString();
}
}

View File

@ -0,0 +1,34 @@
package ch.unibas.dmi.dbis.cs108.multiplayer.server;
import ch.unibas.dmi.dbis.cs108.BudaLogConfig;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.GuiParameters;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.Protocol;
import ch.unibas.dmi.dbis.cs108.multiplayer.helpers.ServerPinger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* This class creates a thread that constantly sends a String to the Clients containing the Lobbies
*/
public class LobbyUpdater implements Runnable{
public static final Logger LOGGER = LogManager.getLogger(LobbyUpdater.class);
public static final BudaLogConfig l = new BudaLogConfig(LOGGER);
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
LOGGER.warn(e.getMessage());
}
String lobbiesAsString = Lobby.lobbiesToString();
for (ClientHandler client : ClientHandler.getConnectedClients()) {
if (!Lobby.lobbies.isEmpty()) {
client.sendMsgToClient(
Protocol.printToGUI + "$" + GuiParameters.updateLobbyString + "$" + lobbiesAsString);
}
}
}
}
}

View File

@ -32,6 +32,7 @@ public class Server {
try {
System.out.println("Port " + gamePort + " is open.");
OgGhostHighScore.main(null);
new Thread(new LobbyUpdater()).start();
while (!serverSocket.isClosed()) {
Socket socket = serverSocket.accept();
ClientHandler nextClient = new ClientHandler(socket, socket.getInetAddress());

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<ScrollPane fx:id="backDropScrolePane" hbarPolicy="NEVER" prefHeight="300.0" prefWidth="200.0" stylesheets="@listStyle.css" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.unibas.dmi.dbis.cs108.multiplayer.client.gui.lounge.ListOfLobbiesController">
<content>
<AnchorPane fx:id="scollingAnchorPane">
<children>
<VBox fx:id="LobbyListVBox" fillWidth="false" prefWidth="200.0" />
</children></AnchorPane>
</content>
</ScrollPane>

View File

@ -13,9 +13,6 @@
<children>
<AnchorPane fx:id="backGroundAnimationPane" maxHeight="843.75" maxWidth="1500.0" />
<BorderPane fx:id="LoungeSceneBorderPane" layoutX="860.0" layoutY="440.0" pickOnBounds="false" prefHeight="843.75" prefWidth="1500.0" stylesheets="@boarderPane.css" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<right>
<ListView fx:id="LobbyListView" pickOnBounds="false" BorderPane.alignment="CENTER" />
</right>
<top>
<ToolBar fx:id="NTtBToolBar" pickOnBounds="false" prefHeight="30.0" BorderPane.alignment="CENTER">
<items>
@ -53,6 +50,14 @@
</children>
</TilePane>
</bottom>
<right>
<AnchorPane prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<ListView fx:id="LobbyListView" opacity="0.0" pickOnBounds="false" />
<AnchorPane fx:id="listLobbyAnchorPane" />
</children>
</AnchorPane>
</right>
</BorderPane>
<AnchorPane fx:id="gameDisplayAnchorPane" maxHeight="843.75" maxWidth="1500.0" pickOnBounds="false" />
</children>

View File

@ -0,0 +1,18 @@
*{
-fx-background-color: midnightblue;
}
.button{
-fx-text-fill: black;
-fx-background-color: lightGrey;
}
.button:hover{
-fx-effect: innershadow(gaussian, grey, 10, 0.2 , 2, 2);
}
.button:pressed{
-fx-background-color: grey;
}
.tree-cell .tree-disclosure-node .arrow {
-fx-background-color: white;
}