diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java index d434fac..74aa52b 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/ClientCallbackImpl.java @@ -53,15 +53,12 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa */ @Override public void onAction(NetworkEvent event) throws RemoteException { - if(event.getIsError()) { - clientController.view.showError(event.toString()); - } else { - synchronized (clientController) - { - event.apply(clientController.miniModel); - } - clientController.view.render(); - - } + synchronized (clientController) { + if(event.getIsError()) { + clientController.view.showError(event.toString()); + } else { + clientController.view.applyAndRender(event); + } + } } } diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java index f1b14b3..5081e6b 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/GUI.java @@ -2,6 +2,7 @@ package it.polimi.ingsw.gc14.View.GUI; import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Model.MiniModel; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.View.GUI.LoginFXMLController; import it.polimi.ingsw.gc14.View.GUI.MainFXMLController; import it.polimi.ingsw.gc14.View.IView; @@ -29,9 +30,9 @@ public class GUI extends Application implements IView { FXMLLoader loaderMain; Scene mainScene; MainFXMLController controllerMain; + MiniModel miniModel; private ClientController controller; - private MiniModel model; public GUI(Stage stage) { this.primaryStage = stage; @@ -72,30 +73,37 @@ public class GUI extends Application implements IView { @Override public void setModel(MiniModel miniModel) { - this.model=model; + this.miniModel=miniModel; } public void setController(ClientController controller) { this.controller=controller; } + public void applyAndRender(NetworkEvent event) { + Platform.runLater(() -> { + event.apply(miniModel); + if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { + controllerTotem.render(); + primaryStage.setScene(totemScene); + } else { + controllerMain.render(event); + primaryStage.setScene(mainScene); + } + }); + } + public void render() { - if(controller.miniModel.currentState.getGameStage()==TOTEM_CHOICE) { - Platform.runLater(() -> { - synchronized (this) { - controllerTotem.render(); - primaryStage.setScene(totemScene); - primaryStage.setFullScreen(true); - } - }); + if (!Platform.isFxApplicationThread()) { + Platform.runLater(this::render); + return; + } + if (controller.miniModel.currentState.getGameStage() == TOTEM_CHOICE) { + controllerTotem.render(); + primaryStage.setScene(totemScene); } else { - Platform.runLater(() -> { - synchronized (this) { - controllerMain.render(); - primaryStage.setScene(mainScene); - primaryStage.setFullScreen(true); - } - }); + controllerMain.render(); + primaryStage.setScene(mainScene); } } diff --git a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java index ae17de4..35fa593 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/GUI/MainFXMLController.java @@ -4,12 +4,11 @@ import it.polimi.ingsw.gc14.Controller.ClientController; import it.polimi.ingsw.gc14.Model.*; import it.polimi.ingsw.gc14.Model.Cards.BuildingCard; import it.polimi.ingsw.gc14.Model.Cards.TribeCard; -import it.polimi.ingsw.gc14.Model.GamePackage.Board; -import it.polimi.ingsw.gc14.Model.GamePackage.CurrentState; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.Orders.OrderPlayer; +import it.polimi.ingsw.gc14.Network.EventType; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import javafx.animation.ScaleTransition; -import javafx.application.Platform; import javafx.event.Event; import javafx.fxml.FXML; import javafx.geometry.Insets; @@ -30,10 +29,6 @@ import javafx.stage.Window; import javafx.util.Duration; import java.util.*; -import java.util.stream.Collectors; - -import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.RES_ACTIONS; -import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.SLOT_CHOICE; public class MainFXMLController { @@ -55,8 +50,14 @@ public class MainFXMLController { private HBox popupCards; private ClientController controller; - private GameStages old_state_stage; - private String old_state_username; + + // ==== IMAGE CACHE ==== + private static final Map imageCache = new HashMap<>(); + + private Image loadImage(String path) { + return imageCache.computeIfAbsent(path, + p -> new Image(getClass().getResourceAsStream(p))); + } public void setController(ClientController controller) { @@ -64,60 +65,41 @@ public class MainFXMLController { } - - @FXML public void initialize() { - old_state_stage=null; - old_state_username=""; - - - // Import font and apply CSS Font.loadFont(getClass().getResourceAsStream("/Fonts/InknutAntiqua-Regular.ttf"), 14); mainHBox.sceneProperty().addListener((obs, oldScene, newScene) -> { if (newScene != null) { newScene.getRoot().applyCss(); } }); - - // Initialize popup initPopup(); + renderBackground(); // solo una volta } + // ==== RENDER ==== + public void render() { + renderUpper(); + renderBoard(); + renderLower(); + renderMyHand(); + renderSidePanel(); + } - public synchronized void render() { - if (old_state_stage==null) { - renderBackground(); - renderUpper(); + public void render(NetworkEvent event) { + if (event.getEventType() == EventType.SLOT_CHOICE) { renderBoard(); - renderLower(); - renderMyHand(); - renderSidePanel(); - } else if (old_state_stage==SLOT_CHOICE ) { - System.out.println("OLD: "+old_state_stage+", NEW: "+controller.miniModel.currentState.getGameStage()); - System.out.println("RIDISEGNO BOARD\n"); - renderBoard(); - } else if (old_state_stage==RES_ACTIONS) { - System.out.println("OLD: "+old_state_stage+", NEW: "+controller.miniModel.currentState.getGameStage()); - System.out.println("RIDISEGNO TUTTO. USERNAME: "+old_state_username); + } else { renderUpper(); renderBoard(); renderLower(); renderSidePanel(); - if (Objects.equals(old_state_username, controller.myUsername)) { + if (Objects.equals(event.getUsername(), controller.myUsername) + || event.getEventType() == EventType.NEXT_ROUND) { renderMyHand(); } - - // TODO: se sono io a pescare renderizzo myHand, altrimenti no (non รจ scontato) - } else { - System.out.println("NON GESTITO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } - - old_state_stage=controller.miniModel.currentState.getGameStage(); - old_state_username=controller.miniModel.currentState.getCurrentPlayer().getUserName(); - // TODO: le info in sidepanel non vengono aggiornate sempre aggiornate, bisogna prima capire dove metterle - } @@ -130,6 +112,7 @@ public class MainFXMLController { clip.setArcHeight(20); node.setClip(clip); } + private void addHoverZoom(Node node) { ScaleTransition scaleUp = new ScaleTransition(Duration.millis(150), node); scaleUp.setToX(1.1); @@ -138,8 +121,9 @@ public class MainFXMLController { scaleDown.setToX(1.0); scaleDown.setToY(1.0); node.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> { scaleUp.play(); node.setCursor(Cursor.HAND); }); - node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); + node.addEventHandler(MouseEvent.MOUSE_EXITED, e -> { scaleDown.play(); node.setCursor(Cursor.DEFAULT); }); } + private void addShadow(Node node) { DropShadow shadow = new DropShadow(); shadow.setColor(Color.rgb(0, 0, 0, 0.3)); @@ -164,23 +148,23 @@ public class MainFXMLController { // ==== ELEMENTS ==== private StackPane createOrder(String num) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Orders/order-" + num + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Orders/order-" + num + ".png")); img.setFitHeight(240); img.setPreserveRatio(true); addClip(img); - StackPane wrapper = new StackPane(img); - return wrapper; + return new StackPane(img); } + private StackPane createSlot(Slot slot, boolean withZoom, boolean withShadow) { - ImageView img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + slot.getSlotId() + ".png")); img.setFitHeight(240); img.setPreserveRatio(true); addClip(img); StackPane wrapper = new StackPane(img); Player player = controller.miniModel.slotPlayerMap.get(slot); - if (player != null && controller.miniModel.getPositionByUsername(player.getUserName())!=-1) { - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + if (player != null && controller.miniModel.getPositionByUsername(player.getUserName()) != -1) { + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(70); totem.setPreserveRatio(true); StackPane.setAlignment(totem, Pos.TOP_LEFT); @@ -188,32 +172,23 @@ public class MainFXMLController { wrapper.getChildren().add(totem); } - if (withShadow) { - addShadow(wrapper); - } - if (withZoom) { - addHoverZoom(wrapper); - } + if (withShadow) addShadow(wrapper); + if (withZoom) addHoverZoom(wrapper); return wrapper; } + private StackPane createCard(PlayableCard card, boolean withZoom, boolean withShadow) { - String id = card.getIdIMG(); - ImageView img; - img = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Fronts/card-" + id + ".png"))); + ImageView img = new ImageView(loadImage("/GUIImages/Fronts/card-" + card.getIdIMG() + ".png")); img.setFitHeight(200); img.setPreserveRatio(true); addClip(img); - StackPane wrapper = new StackPane(img); - if (withShadow) { - addShadow(wrapper); - } - if (withZoom) { - addHoverZoom(wrapper); - } + if (withShadow) addShadow(wrapper); + if (withZoom) addHoverZoom(wrapper); return wrapper; } + private void renderIcons(HBox iconsRow1, HBox iconsRow2, Player player) { String[][] iconTypes = { {"Artist", "artists"}, @@ -232,7 +207,7 @@ public class MainFXMLController { icon.setFitWidth(28); icon.setFitHeight(28); icon.setPreserveRatio(true); - icon.setImage(new Image(getClass().getResourceAsStream("/GUIImages/Icons/" + iconName + ".png"))); + icon.setImage(loadImage("/GUIImages/Icons/" + iconName + ".png")); ArrayList cards = getPlayerCards(player.getUserName(), fieldName); if (cards.isEmpty()) { @@ -248,6 +223,7 @@ public class MainFXMLController { else iconsRow2.getChildren().add(icon); } } + private ArrayList getPlayerCards(String username, String type) { Player p = controller.miniModel.players.get(username); return switch (type) { @@ -268,59 +244,55 @@ public class MainFXMLController { upperList.setAlignment(Pos.CENTER); upperList.getChildren().clear(); - //synchronized (controller) - //{ - int i = 0; - for (TribeCard card : controller.miniModel.board.upperListTribe) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawUpperTribeCard(controller.myUsername, index)); - upperList.getChildren().add(img); - i++; - } - i = 0; - for (BuildingCard card : controller.miniModel.board.upperListBuilding) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawUpperBuildingCard(controller.myUsername, index)); - upperList.getChildren().add(img); - i++; - } - //} + int i = 0; + for (TribeCard card : controller.miniModel.board.upperListTribe) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawUpperTribeCard(controller.myUsername, index)); + upperList.getChildren().add(img); + i++; + } + i = 0; + for (BuildingCard card : controller.miniModel.board.upperListBuilding) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawUpperBuildingCard(controller.myUsername, index)); + upperList.getChildren().add(img); + i++; + } } + private void renderLower() { lowerList.setSpacing(14); lowerList.setAlignment(Pos.CENTER); lowerList.getChildren().clear(); - //synchronized (controller) - //{ - int i = 0; - for (TribeCard card : controller.miniModel.board.lowerListTribe) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawLowerTribeCard(controller.myUsername, index)); - lowerList.getChildren().add(img); - i++; - } - i = 0; - for (BuildingCard card : controller.miniModel.board.lowerListBuilding) { - final int index = i; - StackPane img = createCard(card, true, true); - img.setOnMouseClicked(e -> controller.drawLowerBuildingCard(controller.myUsername, index)); - lowerList.getChildren().add(img); - i++; - } - //} - } - private void renderDeck() { - String path = ""; - switch (controller.miniModel.currentState.getEra()) { - case 1 -> path = "/GUIImages/Backs/back-001.png"; - case 2 -> path = "/GUIImages/Backs/back-030.png"; - case 3 -> path = "/GUIImages/Backs/back-058.png"; + int i = 0; + for (TribeCard card : controller.miniModel.board.lowerListTribe) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawLowerTribeCard(controller.myUsername, index)); + lowerList.getChildren().add(img); + i++; } - ImageView back = new ImageView(new Image(getClass().getResourceAsStream(path))); + i = 0; + for (BuildingCard card : controller.miniModel.board.lowerListBuilding) { + final int index = i; + StackPane img = createCard(card, true, true); + img.setOnMouseClicked(e -> controller.drawLowerBuildingCard(controller.myUsername, index)); + lowerList.getChildren().add(img); + i++; + } + } + + private void renderDeck() { + String path = switch (controller.miniModel.currentState.getEra()) { + case 1 -> "/GUIImages/Backs/back-001.png"; + case 2 -> "/GUIImages/Backs/back-030.png"; + case 3 -> "/GUIImages/Backs/back-058.png"; + default -> "/GUIImages/Backs/back-001.png"; + }; + ImageView back = new ImageView(loadImage(path)); back.setFitHeight(240); back.setPreserveRatio(true); addClip(back); @@ -328,6 +300,7 @@ public class MainFXMLController { addHoverZoom(back); board.getChildren().add(back); } + private void renderOrder() { StackPane card = createOrder(Integer.toString(controller.miniModel.players.size())); @@ -337,10 +310,10 @@ public class MainFXMLController { StackPane.setMargin(overlay, new Insets(9, 0, 0, 57)); for (OrderPlayer player : controller.miniModel.orderLogicCard.playerList) { - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(70); totem.setPreserveRatio(true); - if(controller.miniModel.slotPlayerMap.containsValue(player.player)) { + if (controller.miniModel.slotPlayerMap.containsValue(player.player)) { totem.setOpacity(0.5); } overlay.getChildren().add(totem); @@ -348,6 +321,7 @@ public class MainFXMLController { card.getChildren().add(overlay); board.getChildren().add(card); } + private void renderSlotMap() { int i = 0; for (Map.Entry entry : controller.miniModel.slotPlayerMap.entrySet()) { @@ -359,6 +333,7 @@ public class MainFXMLController { i++; } } + private void drawMyHandList(ArrayList cardList) { if (!cardList.isEmpty()) { StackPane img = createCard(cardList.getLast(), true, true); @@ -378,6 +353,7 @@ public class MainFXMLController { myHand.getChildren().add(placeholder); } } + private void renderPlayer(Player player) { VBox card = new VBox(3); VBox.setMargin(card, new Insets(5)); @@ -386,10 +362,10 @@ public class MainFXMLController { addHoverZoom(card); addShadow(card); - // Riga 1: icona totem + nome + // Riga 1: totem + nome HBox headerRow = new HBox(8); headerRow.setAlignment(Pos.CENTER); - ImageView totem = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png"))); + ImageView totem = new ImageView(loadImage("/GUIImages/Totems/totem_" + player.totem.toString().toLowerCase(Locale.ROOT) + ".png")); totem.setFitHeight(20); totem.setPreserveRatio(true); Label usernameLabel = new Label(player.getUserName()); @@ -405,7 +381,7 @@ public class MainFXMLController { HBox foodBox = new HBox(4); foodBox.setAlignment(Pos.CENTER); - ImageView foodIcon = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Icons/Food.png"))); + ImageView foodIcon = new ImageView(loadImage("/GUIImages/Icons/Food.png")); foodIcon.setFitHeight(20); foodIcon.setPreserveRatio(true); Label foodLabel = new Label(String.valueOf(player.getFoodValue())); @@ -414,7 +390,7 @@ public class MainFXMLController { HBox prestigeBox = new HBox(1); prestigeBox.setAlignment(Pos.CENTER); - ImageView PPIcon = new ImageView(new Image(getClass().getResourceAsStream("/GUIImages/Icons/PrestigePoint.png"))); + ImageView PPIcon = new ImageView(loadImage("/GUIImages/Icons/PrestigePoint.png")); PPIcon.setFitHeight(35); PPIcon.setPreserveRatio(true); Label prestigeLabel = new Label(String.valueOf(player.getPrestigeValue())); @@ -423,12 +399,12 @@ public class MainFXMLController { statsRow.getChildren().addAll(foodBox, prestigeBox); - // Righe 3-4: icone carte (3 per riga) + // Righe 3-4: icone carte HBox iconsRow1 = new HBox(6); iconsRow1.setAlignment(Pos.CENTER); HBox iconsRow2 = new HBox(6); iconsRow2.setAlignment(Pos.CENTER); - renderIcons(iconsRow1, iconsRow2, player); // vedi sotto + renderIcons(iconsRow1, iconsRow2, player); card.getChildren().addAll(headerRow, statsRow, iconsRow1, iconsRow2); sidePanel.getChildren().add(card); @@ -442,13 +418,14 @@ public class MainFXMLController { false, false, true, true ); mainHBox.setBackground(new Background(new BackgroundImage( - new Image(getClass().getResourceAsStream("/GUIImages/Background.png")), + loadImage("/GUIImages/Background.png"), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER, size ))); } + private void renderBoard() { board.setSpacing(14); board.setAlignment(Pos.CENTER); @@ -457,19 +434,22 @@ public class MainFXMLController { renderOrder(); renderSlotMap(); } + private void renderMyHand() { myHand.getChildren().clear(); myHand.setSpacing(14); myHand.setAlignment(Pos.CENTER); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).artists); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).gatherers); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).inventors); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).builders); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).shamans); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).hunters); - drawMyHandList(controller.miniModel.players.get(controller.myUsername).buildingCards); + Player me = controller.miniModel.players.get(controller.myUsername); + drawMyHandList(me.artists); + drawMyHandList(me.gatherers); + drawMyHandList(me.inventors); + drawMyHandList(me.builders); + drawMyHandList(me.shamans); + drawMyHandList(me.hunters); + drawMyHandList(me.buildingCards); } + private void renderSidePanel() { sidePanel.getChildren().clear(); sidePanel.setSpacing(6); @@ -486,15 +466,7 @@ public class MainFXMLController { } - - - - - - - - - // POPUP + // ==== POPUP ==== private void initPopup() { popupCards = new HBox(10); popupCards.setAlignment(Pos.CENTER); @@ -507,29 +479,29 @@ public class MainFXMLController { "-fx-background-radius: 10;" ); - addClip(popupCards); - popup = new Popup(); popup.getContent().add(popupCards); popup.setAutoHide(true); - // Aspetta che la scena del popup esista, poi la rendi trasparente popup.addEventHandler(Event.ANY, e -> { if (popup.getScene() != null) { popup.getScene().setFill(Color.TRANSPARENT); } }); } + private void openPopup(ArrayList cardList) { popupCards.getChildren().clear(); for (PlayableCard card : cardList) { - StackPane img = createCard(card, false, false); - popupCards.getChildren().add(img); + popupCards.getChildren().add(createCard(card, false, false)); } - Window window = myHand.getScene().getWindow(); - popup.show(window, (window.getWidth() - popup.getWidth()) / 2, (window.getHeight() - popup.getHeight()) / 2); - // La scena esiste solo dopo show() + Window window = myHand.getScene().getWindow(); + popup.show(window, 0, 0); popup.getScene().setFill(Color.TRANSPARENT); + + // centra dopo show() quando le dimensioni sono disponibili + popup.setX(window.getX() + (window.getWidth() - popup.getWidth()) / 2); + popup.setY(window.getY() + (window.getHeight() - popup.getHeight()) / 2); } -} +} \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/View/IView.java b/src/main/java/it/polimi/ingsw/gc14/View/IView.java index dc0aaa4..f10b639 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/IView.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/IView.java @@ -7,6 +7,7 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent; public interface IView { public void setModel(MiniModel miniModel); public void render(); + public void applyAndRender(NetworkEvent event); public void showMessage(String message); public void showError(String message); diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java index deed706..b463966 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/TUI.java @@ -1,6 +1,7 @@ package it.polimi.ingsw.gc14.View.TUI; import it.polimi.ingsw.gc14.Model.*; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; +import it.polimi.ingsw.gc14.Network.NetworkEvent; import it.polimi.ingsw.gc14.View.IView; import java.util.ArrayList; @@ -58,6 +59,10 @@ public class TUI implements IView { this.model = model; this.username = ""; } + public void applyAndRender(NetworkEvent event) { + event.apply(model); + render(); + } /** * Sets the username of the local player.