diff --git a/Projekte/battleship/client/src/main/java/pp/battleship/client/Menu.java b/Projekte/battleship/client/src/main/java/pp/battleship/client/Menu.java index 44a9a74..12afb6d 100644 --- a/Projekte/battleship/client/src/main/java/pp/battleship/client/Menu.java +++ b/Projekte/battleship/client/src/main/java/pp/battleship/client/Menu.java @@ -18,10 +18,11 @@ import com.simsilica.lemur.style.ElementId; import static pp.battleship.Resources.lookup; import pp.battleship.client.gui.GameMusic; -import pp.battleship.client.gui.VolumeSlider; import pp.dialog.Dialog; import pp.dialog.StateCheckboxModel; import pp.dialog.TextInputDialog; +import pp.battleship.client.gui.VolumeSlider; + import static pp.util.PreferencesUtils.getPreferences; /** diff --git a/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/VolumeSlider.java b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/VolumeSlider.java index aa27292..70f9097 100644 --- a/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/VolumeSlider.java +++ b/Projekte/battleship/client/src/main/java/pp/battleship/client/gui/VolumeSlider.java @@ -1,6 +1,7 @@ package pp.battleship.client.gui; import com.simsilica.lemur.Slider; + /** * The VolumeSlider class represents the Volume Slider in the Menu. * It extends the Slider class and provides functionalities for setting the music volume, diff --git a/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy b/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy index 7bac65e..398fdf1 100644 --- a/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy +++ b/Projekte/jme-common/src/main/resources/Interface/Lemur/pp-styles.groovy @@ -21,9 +21,11 @@ def sliderColor = color(0.6, 0.8, 0.8, 1) def sliderBgColor = color(0.5, 0.75, 0.75, 1) def gradientColor = color(0.5, 0.75, 0.85, 0.5) def tabbuttonEnabledColor = color(0.4, 0.45, 0.5, 1) -def solidWhiteBackground = new QuadBackgroundComponent(color(1, 1, 1, 1)) // Solid white -def greyBackground = color(0.8, 0.8, 0.8, 1) // Grey background color -def redBorderColor = color(1, 0, 0, 1) // Red border color +def solidWhiteBackground = new QuadBackgroundComponent(new ColorRGBA(1, 1, 1, 1)) +def greyBackground = new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 1.0f)); +def lightGreyBackground = new QuadBackgroundComponent(new ColorRGBA(0.4f, 0.4f, 0.4f, 1.0f)); +def lightGrey = color(0.6, 0.6, 0.6, 1.0) + @@ -246,7 +248,12 @@ selector("tab.button", "pp") { buttonCommands = stdButtonCommands } selector("settings-title", "pp") { - fontSize = 48 // Set font size + def outerBackground = new QuadBackgroundComponent(color(1, 0.5, 0, 1)) // Grey inner border + def innerBackground = new QuadBackgroundComponent(buttonBgColor) // White outer border background + + background = outerBackground + fontSize = 40 + insets = new Insets3f(3, 3, 3, 3) textHAlignment = HAlignment.Center textVAlignment = VAlignment.Center } diff --git a/Projekte/monopoly/client/client.properties b/Projekte/monopoly/client/client.properties index fd98968..3e2d911 100644 --- a/Projekte/monopoly/client/client.properties +++ b/Projekte/monopoly/client/client.properties @@ -24,10 +24,10 @@ overlay.top.color=1, 1, 1, 1 settings.show=false # # Specifies the width of the application window in pixels. -settings.resolution.width=1920 +settings.resolution.width=1200 # # Specifies the height of the application window in pixels. -settings.resolution.height=1080 +settings.resolution.height=800 # # Determines whether the application runs in full-screen mode. settings.full-screen=false diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java index 791b604..1e6f94e 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameMusic.java @@ -34,7 +34,7 @@ public class GameMusic extends AbstractAppState{ return PREFERENCES.getBoolean(ENABLED_PREF, true); } - /** + /** * Checks if sound is enabled in the preferences. * * @return float to which the volume is set diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java index f2bb02a..2722afa 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/GameSound.java @@ -30,6 +30,7 @@ public class GameSound extends AbstractAppState implements GameEventListener { private static final Logger LOGGER = System.getLogger(GameSound.class.getName()); private static final Preferences PREFERENCES = getPreferences(GameSound.class); private static final String ENABLED_PREF = "enabled"; //NON-NLS + private static final String VOLUME_PREF = "volume"; //NON-NLS private AudioNode passStartSound; private AudioNode eventCardSound; @@ -59,6 +60,15 @@ public class GameSound extends AbstractAppState implements GameEventListener { setEnabled(!isEnabled()); } + /** + * Checks if sound is enabled in the preferences. + * + * @return float to which the volume is set + */ + public static float volumeInPreferences() { + return PREFERENCES.getFloat(VOLUME_PREF, 0.5f); + } + /** * Sets the enabled state of this AppState. * Overrides {@link com.jme3.app.state.AbstractAppState#setEnabled(boolean)} @@ -92,7 +102,7 @@ public class GameSound extends AbstractAppState implements GameEventListener { tradeAcceptedSound = loadSound(app, "Sound/Effects/tradeAccepted.ogg"); tradeRejectedSound = loadSound(app, "Sound/Effects/tradeRejected.ogg"); winnerSound = loadSound(app, "Sound/Effects/winner.ogg"); - looserSound = loadSound(app, "Sound/Effects/looser.ogg"); + looserSound = loadSound(app, "Sound/Effects/loser.ogg"); buttonSound = loadSound(app, "Sound/Effects/button.ogg"); } @@ -193,21 +203,40 @@ public class GameSound extends AbstractAppState implements GameEventListener { if (isEnabled() && buttonSound != null) buttonSound.playInstance(); } + /** + * Sets the volume of the sounds + * @param vol the volume to which the sounds should be set + */ + public void setVolume(float vol){ + passStartSound.setVolume(vol); + eventCardSound.setVolume(vol); + gulagSound.setVolume(vol); + diceRollSound.setVolume(vol); + moneyCollectSound.setVolume(vol); + moneyLostSound.setVolume(vol); + tradeAcceptedSound.setVolume(vol); + tradeRejectedSound.setVolume(vol); + winnerSound.setVolume(vol); + looserSound.setVolume(vol); + buttonSound.setVolume(vol); + + PREFERENCES.putFloat(VOLUME_PREF, vol); + } @Override public void receivedEvent(SoundEvent event) { switch (event.sound()) { case PASS_START -> passStart(); case EVENT_CARD -> eventCard(); - case GULAG -> eventCard(); - case DICE_ROLL -> eventCard(); - case MONEY_COLLECTED -> eventCard(); - case MONEY_LOST -> eventCard(); - case TRADE_ACCEPTED -> eventCard(); - case TRADE_REJECTED -> eventCard(); - case WINNER -> eventCard(); - case LOSER -> eventCard(); - case BUTTON -> eventCard(); + case GULAG -> gulag(); + case DICE_ROLL -> diceRoll(); + case MONEY_COLLECTED -> moneyCollect(); + case MONEY_LOST -> moneyLost(); + case TRADE_ACCEPTED -> tradeAccepted(); + case TRADE_REJECTED -> tradeRejected(); + case WINNER -> winner(); + case LOSER -> looser(); + case BUTTON -> button(); } } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java deleted file mode 100644 index a9a22e5..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/Menu.java +++ /dev/null @@ -1,51 +0,0 @@ -//////////////////////////////////////// -// Programming project code -// UniBw M, 2022, 2023, 2024 -// www.unibw.de/inf2 -// (c) Mark Minas (mark.minas@unibw.de) -//////////////////////////////////////// - -package pp.monopoly.client; - -import java.util.prefs.Preferences; - -import pp.dialog.Dialog; -import static pp.util.PreferencesUtils.getPreferences; - -/** - * The Menu class represents the main menu in the Battleship game application. - * It extends the Dialog class and provides functionalities for loading, saving, - * returning to the game, and quitting the application. - */ -class Menu extends Dialog { - private static final Preferences PREFERENCES = getPreferences(Menu.class); - private static final String LAST_PATH = "last.file.path"; - private final MonopolyApp app; - - - /** - * Constructs the Menu dialog for the Battleship application. - * - * @param app the BattleshipApp instance - */ - public Menu(MonopolyApp app) { - super(app.getDialogManager()); - this.app = app; - } - - /** - * Updates the state of the load and save buttons based on the game logic. - */ - @Override - public void update() { - - } - - /** - * As an escape action, this method closes the menu if it is the top dialog. - */ - @Override - public void escape() { - close(); - } -} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java index c2f0d03..9991bb6 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/MonopolyApp.java @@ -1,298 +1,446 @@ +//////////////////////////////////////// +// Programming project code +// UniBw M, 2022, 2023, 2024 +// www.unibw.de/inf2 +// (c) Mark Minas (mark.minas@unibw.de) +//////////////////////////////////////// + package pp.monopoly.client; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - +import com.jme3.app.DebugKeysAppState; import com.jme3.app.SimpleApplication; +import com.jme3.app.StatsAppState; import com.jme3.font.BitmapFont; import com.jme3.font.BitmapText; import com.jme3.input.KeyInput; +import com.jme3.input.MouseInput; import com.jme3.input.controls.ActionListener; import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.controls.MouseButtonTrigger; import com.jme3.system.AppSettings; import com.simsilica.lemur.GuiGlobals; import com.simsilica.lemur.style.BaseStyles; - +import pp.monopoly.game.client.MonopolyClient; +import pp.monopoly.client.gui.SettingsMenu; +import pp.monopoly.client.gui.StartMenu; +import pp.monopoly.game.client.ClientGameLogic; +import pp.monopoly.game.client.ServerConnection; +import pp.monopoly.notification.ClientStateEvent; +import pp.monopoly.notification.GameEventListener; +import pp.monopoly.notification.InfoTextEvent; +import pp.monopoly.notification.Sound; import pp.dialog.DialogBuilder; import pp.dialog.DialogManager; import pp.graphics.Draw; -import pp.monopoly.client.gui.*; -import pp.monopoly.client.gui.popups.*; -import pp.monopoly.game.client.ClientGameLogic; -import pp.monopoly.game.client.MonopolyClient; -import pp.monopoly.game.client.ServerConnection; -import pp.monopoly.model.card.DeckHelper; // TODO für den Import der Queue notwendig -import pp.monopoly.model.fields.BoardManager; -import pp.monopoly.notification.GameEventListener; -import pp.monopoly.notification.InfoTextEvent; -import pp.monopoly.server.MonopolyServer; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.LogManager; + +import static pp.monopoly.Resources.lookup; + +/** + * The main class for the Battleship client application. + * It manages the initialization, input setup, GUI setup, and game states for the client. + */ public class MonopolyApp extends SimpleApplication implements MonopolyClient, GameEventListener { - private BitmapText topText; - private final ServerConnection serverConnection; - private final ClientGameLogic logic; - private final MonopolyAppConfig config; - private final ActionListener escapeListener = (name, isPressed, tpf) -> handleEscape(isPressed); - private final DialogManager dialogManager = new DialogManager(this); - private final ExecutorService executor = Executors.newCachedThreadPool(); - private final Draw draw; - private SettingsMenu settingsMenu; - private TestWorld testWorld; - private boolean isSettingsMenuOpen = false; - private boolean inputBlocked = false; - private MonopolyServer monopolyServer; - private NetworkSupport networkSupport; - private BoardManager boardManager = new BoardManager(); - - // TODO Temp später entfernen - - - private DeckHelper deckHelper = new DeckHelper(); //TODO für den Import der Queue notwendig - - private EventCard eventCard; - private BuildingPropertyCard buildingProperty; - private FoodFieldCard foodField; - private GateFieldCard gateField; - private BuyCard buyCard; - private boolean isBuyCardPopupOpen = false; - private final ActionListener BListener = (name, isPressed, tpf) -> handleB(isPressed); + /** + * Logger for logging messages within the application. + */ + private static final Logger LOGGER = System.getLogger(MonopolyApp.class.getName()); /** * Path to the styles script for GUI elements. */ - private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; // NON-NLS + private static final String STYLES_SCRIPT = "Interface/Lemur/pp-styles.groovy"; //NON-NLS + /** * Path to the font resource used in the GUI. */ - private static final String FONT = "Interface/Fonts/Default.fnt"; // NON-NLS + private static final String FONT = "Interface/Fonts/Default.fnt"; //NON-NLS + /** + * Path to the client configuration file, if one exists. + */ + private static final File CONFIG_FILE = new File("client.properties"); + + /** + * Input mapping name for mouse clicks. + */ + public static final String CLICK = "CLICK"; + + /** + * Input mapping name for the Escape key. + */ + private static final String ESC = "ESC"; + + /** + * Manager for handling dialogs within the application. + */ + private final DialogManager dialogManager = new DialogManager(this); + + /** + * The server connection instance, used for communicating with the game server. + */ + private final ServerConnection serverConnection; + + /** + * Instance of the {@link Draw} class for rendering graphics. + */ + private Draw draw; + + /** + * Text display at the top of the GUI for showing information to the user. + */ + private BitmapText topText; + + /** + * Executor service for handling asynchronous tasks within the application. + */ + private ExecutorService executor; + + /** + * Handler for managing the client's game logic. + */ + private final ClientGameLogic logic; + + /** + * Configuration settings for the Battleship client application. + */ + private final MonopolyAppConfig config; + + /** + * Listener for handling actions triggered by the Escape key. + */ + private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed); + + static { + // Configure logging + LogManager manager = LogManager.getLogManager(); + try { + manager.readConfiguration(new FileInputStream("logging.properties")); + LOGGER.log(Level.INFO, "Successfully read logging properties"); //NON-NLS + } + catch (IOException e) { + LOGGER.log(Level.INFO, e.getMessage()); + } + } + + /** + * Starts the Battleship application. + * + * @param args Command-line arguments for launching the application. + */ public static void main(String[] args) { new MonopolyApp().start(); } - public MonopolyApp() { - this.draw = new Draw(assetManager); + /** + * Constructs a new {@code MonopolyApp} instance. + * Initializes the configuration, server connection, and game logic listeners. + */ + private MonopolyApp() { config = new MonopolyAppConfig(); - networkSupport = new NetworkSupport(this); // Initialize NetworkSupport - serverConnection = networkSupport; + config.readFromIfExists(CONFIG_FILE); + serverConnection = makeServerConnection(); logic = new ClientGameLogic(serverConnection); logic.addListener(this); setShowSettings(config.getShowSettings()); setSettings(makeSettings()); } - @Override - public MonopolyAppConfig getConfig() { - return config; + /** + * Creates and configures application settings from the client configuration. + * + * @return A configured {@link AppSettings} object. + */ + private AppSettings makeSettings() { + final AppSettings settings = new AppSettings(true); + settings.setTitle(lookup("monopoly.name")); + settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight()); + settings.setFullscreen(config.fullScreen()); + settings.setUseRetinaFrameBuffer(config.useRetinaFrameBuffer()); + settings.setGammaCorrection(config.useGammaCorrection()); + return settings; } + /** + * Factory method for creating a server connection based on the current + * client configuration. + * + * @return A {@link ServerConnection} instance, which could be a real or mock server. + */ + private ServerConnection makeServerConnection() { + return new NetworkSupport(this); + } + + /** + * Returns the dialog manager responsible for managing in-game dialogs. + * + * @return The {@link DialogManager} instance. + */ + public DialogManager getDialogManager() { + return dialogManager; + } + + /** + * Returns the game logic handler for the client. + * + * @return The {@link ClientGameLogic} instance. + */ @Override public ClientGameLogic getGameLogic() { return logic; } - public BoardManager getBoardManager() { - return boardManager; - } - - // TODO analoge Implementierung zum Boardmamager zum Testen der EventCardPopups - - public DeckHelper getDeckHelper(){ - return deckHelper; - } - - public NetworkSupport getNetworkSupport() { - return networkSupport; - } - - private AppSettings makeSettings() { - final AppSettings settings = new AppSettings(true); - settings.setTitle("Monopoly Game"); - settings.setResolution(config.getResolutionWidth(), config.getResolutionHeight()); - settings.setFullscreen(config.fullScreen()); - return settings; + /** + * Returns the current configuration settings for the Battleship client. + * + * @return The {@link BattleshipClientConfig} instance. + */ + @Override + public MonopolyAppConfig getConfig() { + return config; } + /** + * Initializes the application. + * Sets up input mappings, GUI, game states, and connects to the server. + */ @Override public void simpleInitApp() { - GuiGlobals.initialize(this); - BaseStyles.loadStyleResources(STYLES_SCRIPT); - GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); // NON-NLS - BaseStyles.loadStyleResources("com/simsilica/lemur/style/base/glass-styles.groovy"); - GuiGlobals.getInstance().getStyles(); - final BitmapFont normalFont = assetManager.loadFont(FONT); // NON-NLS - + setPauseOnLostFocus(false); + draw = new Draw(assetManager); setupInput(); + setupStates(); setupGui(); - - // Zeige das Startmenü - StartMenu.createStartMenu(this); + new StartMenu(this).open(); } + /** + * Sets up the graphical user interface (GUI) for the application. + */ private void setupGui() { - BitmapFont normalFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); + GuiGlobals.initialize(this); + BaseStyles.loadStyleResources(STYLES_SCRIPT); + BaseStyles.loadGlassStyle(); + GuiGlobals.getInstance().getStyles().setDefaultStyle("pp"); //NON-NLS + final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS topText = new BitmapText(normalFont); - topText.setLocalTranslation(10, settings.getHeight() - 10, 0); + final int height = context.getSettings().getHeight(); + topText.setLocalTranslation(10f, height - 10f, 0f); + topText.setColor(config.getTopColor()); guiNode.attachChild(topText); } + /** + * Configures input mappings and sets up listeners for user interactions. + */ private void setupInput() { inputManager.deleteMapping(INPUT_MAPPING_EXIT); - inputManager.setCursorVisible(true); - inputManager.addMapping("ESC", new KeyTrigger(KeyInput.KEY_ESCAPE)); - inputManager.addListener(escapeListener, "ESC"); - - inputManager.addMapping("B", new KeyTrigger(KeyInput.KEY_B)); - inputManager.addListener(BListener, "B"); + inputManager.setCursorVisible(false); + inputManager.addMapping(ESC, new KeyTrigger(KeyInput.KEY_ESCAPE)); + inputManager.addMapping(CLICK, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + inputManager.addListener(escapeListener, ESC); } - private void handleEscape(boolean isPressed) { - if (isPressed) { - if (settingsMenu != null && isSettingsMenuOpen) { - // Schließe das SettingsMenu - System.out.println("Schließe SettingsMenu..."); - settingsMenu.close(); - settingsMenu = null; - setSettingsMenuOpen(false); - } else { - // Öffne das SettingsMenu - System.out.println("Öffne SettingsMenu..."); - settingsMenu = new SettingsMenu(this); - settingsMenu.open(); - setSettingsMenuOpen(true); - } + /** + * Initializes and attaches the necessary application states for the game. + */ + private void setupStates() { + if (config.getShowStatistics()) { + final BitmapFont normalFont = assetManager.loadFont(FONT); //NON-NLS + final StatsAppState stats = new StatsAppState(guiNode, normalFont); + stateManager.attach(stats); } + flyCam.setEnabled(false); + stateManager.detach(stateManager.getState(StatsAppState.class)); + stateManager.detach(stateManager.getState(DebugKeysAppState.class)); + + attachGameSound(); + attachGameMusic(); } - //logik zum wechselnden erscheinen und verschwinden beim drücken von B //TODO süäter entfernen - private void handleB(boolean isPressed) { - if (isPressed) { - if (eventCard != null && isBuyCardPopupOpen) { - // Schließe das SettingsMenu - System.out.println("Schließe BuyCardPopup..."); - eventCard.close(); - eventCard = null; - setBuyCardPopupOpen(false); - } else { - // Öffne das SettingsMenu - System.out.println("Öffne BuyCardPopup..."); - eventCard = new EventCard(this); - eventCard.open(); - setBuyCardPopupOpen(true); - } - } + /** + * Attaches the game sound state and sets its initial enabled state. + */ + private void attachGameSound() { + final GameSound gameSound = new GameSound(); + logic.addListener(gameSound); + gameSound.setEnabled(GameSound.enabledInPreferences()); + stateManager.attach(gameSound); } - private void blockInputs() { - if (!inputBlocked) { - System.out.println("Blockiere Eingaben..."); - inputManager.setCursorVisible(true); // Cursor sichtbar machen - inputManager.clearMappings(); // Alle Mappings entfernen - inputBlocked = true; - } - } - - public void unblockInputs() { - if (inputBlocked) { - System.out.println("Aktiviere Eingaben..."); - setupInput(); // Standard-Eingaben neu registrieren - inputBlocked = false; - } - } - - public void setInfoText(String text) { - topText.setText(text); + /** + * Attaches the background music state and sets its initial enabled state. + */ + private void attachGameMusic() { + final GameMusic gameSound = new GameMusic(); + gameSound.setEnabled(GameMusic.enabledInPreferences()); + stateManager.attach(gameSound); } + /** + * Updates the application state every frame. + * This method is called once per frame during the game loop. + * + * @param tpf Time per frame in seconds. + */ @Override - public void receivedEvent(InfoTextEvent event) { - setInfoText(event.key()); + public void simpleUpdate(float tpf) { + super.simpleUpdate(tpf); + dialogManager.update(tpf); + logic.update(tpf); } - @Override - public void stop(boolean waitFor) { - if (executor != null) executor.shutdownNow(); - serverConnection.disconnect(); - super.stop(waitFor); - } - - public DialogManager getDialogManager() { - return dialogManager; + /** + * Handles the Escape key action to either close the top dialog or show the main menu. + * + * @param isPressed Indicates whether the Escape key is pressed. + */ + public void escape(boolean isPressed) { + if (!isPressed) return; + if (dialogManager.showsDialog()) + dialogManager.escape(); + else + new SettingsMenu(this).open(); } + /** + * Returns the {@link Draw} instance used for rendering graphical elements in the game. + * + * @return The {@link Draw} instance. + */ public Draw getDraw() { return draw; } - public ExecutorService getExecutor() { - return executor; - } - - public void closeApp() { - stop(); - } - - public void errorDialog(String errorMessage) { - DialogBuilder.simple(dialogManager) - .setTitle("Fehler") - .setText(errorMessage) - .setOkButton("OK") - .build() - .open(); - } - - public void setSettingsMenuOpen(boolean isOpen) { - this.isSettingsMenuOpen = isOpen; - } - - // TODO später entfernen - - public void setBuyCardPopupOpen(boolean isOpen) { - this.isBuyCardPopupOpen = isOpen; - } - - @Override - public void simpleUpdate(float tpf) { - if (testWorld != null) { - testWorld.update(tpf); // Aktualisiere die Kamera in der TestWorld - } - } - - public void startTestWorld() { - guiNode.detachAllChildren(); // Entferne GUI - testWorld = new TestWorld(this); // Erstelle eine Instanz von TestWorld - testWorld.initializeScene(); // Initialisiere die Szene - } - - // TODO später entfernen - - public void startBuyCard() { - } - - public void returnToMenu() { - guiNode.detachAllChildren(); // Entferne die GUI - StartMenu.createStartMenu(this); // Zeige das Startmenü erneut + /** + * Tries to connect + */ + public void connect() { + serverConnection.connect(); } /** - * Startet den Server in einem neuen Thread. + * Handles a request to close the application. + * If the request is initiated by pressing ESC, this parameter is true. + * + * @param esc If true, the request is due to the ESC key being pressed. */ - public void startServer() { - new Thread(() -> { - try { - MonopolyServer.main(new String[0]); // Startet den MonopolyServer - } catch (Exception e) { - errorDialog("Fehler: Server konnte nicht gestartet werden."); - } - }).start(); + @Override + public void requestClose(boolean esc) { /* do nothing */ } + + /** + * Closes the application, displaying a confirmation dialog if the client is connected to a server. + */ + public void closeApp() { + if (serverConnection.isConnected()) + confirmDialog(lookup("confirm.leaving"), this::close); + else + close(); } - public MonopolyServer getMonopolyServer() { - return monopolyServer; + /** + * Closes the application, disconnecting from the server and stopping the application. + */ + private void close() { + serverConnection.disconnect(); + stop(); } - public ServerConnection getServerConnection() { - return serverConnection; + /** + * Updates the informational text displayed in the GUI. + * + * @param text The information text to display. + */ + public void setInfoText(String text) { + LOGGER.log(Level.DEBUG, "setInfoText {0}", text); //NON-NLS + topText.setText(text); + } + + /** + * Updates the informational text in the GUI based on the key received in an {@link InfoTextEvent}. + * + * @param event The {@link InfoTextEvent} containing the key for the text to display. + */ + @Override + public void receivedEvent(InfoTextEvent event) { + LOGGER.log(Level.DEBUG, "received info text {0}", event.key()); //NON-NLS + setInfoText(lookup(event.key())); + } + + /** + * Handles client state events to update the game states accordingly. + * + * @param event The {@link ClientStateEvent} representing the state change. + */ + @Override + public void receivedEvent(ClientStateEvent event) { + } + + /** + * Returns the executor service used for handling multithreaded tasks. + * + * @return The {@link ExecutorService} instance. + */ + public ExecutorService getExecutor() { + if (executor == null) + executor = Executors.newCachedThreadPool(); + return executor; + } + + /** + * Stops the application, shutting down the executor service and halting execution. + * + * @param waitFor If true, waits for the application to stop before returning. + */ + @Override + public void stop(boolean waitFor) { + if (executor != null) executor.shutdownNow(); + super.stop(waitFor); + } + + /** + * Displays a confirmation dialog with a specified question and action for the "Yes" button. + * + * @param question The question to display in the dialog. + * @param yesAction The action to perform if "Yes" is selected. + */ + public void confirmDialog(String question, Runnable yesAction) { + DialogBuilder.simple(dialogManager) + .setTitle(lookup("dialog.question")) + .setText(question) + .setOkButton(lookup("button.yes"), d -> { + getGameLogic().playSound(Sound.BUTTON); // Play sound + yesAction.run(); // Execute the original yesAction + }) + .setNoButton(lookup("button.no"), d -> getGameLogic().playSound(Sound.BUTTON)) + .build() + .open(); + } + + /** + * Displays an error dialog with the specified error message. + * + * @param errorMessage The error message to display in the dialog. + */ + public void errorDialog(String errorMessage) { + DialogBuilder.simple(dialogManager) + .setTitle(lookup("dialog.error")) + .setText(errorMessage) + .setOkButton(lookup("button.ok"), d -> getGameLogic().playSound(Sound.BUTTON)) + .build() + .open(); + } + + public void disconnect() { + serverConnection.disconnect(); } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java deleted file mode 100644 index 23bf5e6..0000000 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkDialog.java +++ /dev/null @@ -1,146 +0,0 @@ -package pp.monopoly.client; - -import java.lang.System.Logger; -import java.lang.System.Logger.Level; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import com.simsilica.lemur.Button; -import com.simsilica.lemur.Container; -import com.simsilica.lemur.Label; -import com.simsilica.lemur.TextField; - -import pp.dialog.Dialog; -import pp.dialog.DialogBuilder; -import pp.dialog.SimpleDialog; - -/** - * Represents a dialog for setting up a network connection in the Monopoly game. - * Allows users to specify the host and port for connecting to a game server. - */ -class NetworkDialog extends SimpleDialog { - private static final Logger LOGGER = System.getLogger(NetworkDialog.class.getName()); - private static final String LOCALHOST = "localhost"; - private static final String DEFAULT_PORT = "42069"; - private final NetworkSupport network; - private final TextField host = new TextField(LOCALHOST); - private final TextField port = new TextField(DEFAULT_PORT); - private String hostname; - private int portNumber; - private Future connectionFuture; - private Dialog progressDialog; - - /** - * Constructs a new NetworkDialog. - * - * @param network The NetworkSupport instance to be used for network operations. - */ - NetworkDialog(NetworkSupport network) { - super(network.getApp().getDialogManager()); - this.network = network; - initializeDialog(); - } - - /** - * Initializes the dialog with input fields and connection buttons. - */ - private void initializeDialog() { - final MonopolyApp app = network.getApp(); - Container inputContainer = new Container(); - - // Titel und Eingabefelder für Host und Port - inputContainer.addChild(new Label("Server-Adresse")); - inputContainer.addChild(host); - - inputContainer.addChild(new Label("Port")); - inputContainer.addChild(port); - - Button connectButton = inputContainer.addChild(new Button("Verbinden")); - connectButton.addClickCommands(source -> connect()); - - Button cancelButton = inputContainer.addChild(new Button("Abbrechen")); - cancelButton.addClickCommands(source -> app.closeApp()); - - app.getGuiNode().attachChild(inputContainer); - } - - /** - * Initiates the connection attempt based on the entered host and port. - */ - private void connect() { - LOGGER.log(Level.INFO, "Connecting to host={0}, port={1}", host, port); - try { - hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText(); - portNumber = Integer.parseInt(port.getText()); - openProgressDialog(); - connectionFuture = network.getApp().getExecutor().submit(this::initNetwork); - } catch (NumberFormatException e) { - network.getApp().errorDialog("Port muss eine Zahl sein."); - } - } - - /** - * Opens a progress dialog while connecting. - */ - private void openProgressDialog() { - progressDialog = DialogBuilder.simple(network.getApp().getDialogManager()) - .setText("Verbinde zum Server...") - .build(); - progressDialog.open(); - } - - /** - * Attempts to initialize the network connection. - * - * @throws RuntimeException If an error occurs when creating the client. - */ - private Object initNetwork() { - try { - network.initNetwork(hostname, portNumber); - return null; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Updates the connection status and handles completion or failure. - */ - @Override - public void update(float delta) { - if (connectionFuture != null && connectionFuture.isDone()) { - try { - connectionFuture.get(); - onSuccess(); - } catch (ExecutionException e) { - onFailure(e.getCause()); - } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "Connection interrupted.", e); - Thread.currentThread().interrupt(); - } - } - } - - /** - * Handles a successful connection to the game server. - */ - private void onSuccess() { - connectionFuture = null; - progressDialog.close(); - this.close(); - network.getApp().setInfoText("Warte auf einen Gegner..."); - } - - /** - * Handles a failed connection attempt. - * - * @param e The cause of the failure. - */ - private void onFailure(Throwable e) { - connectionFuture = null; - progressDialog.close(); - network.getApp().errorDialog("Verbindung zum Server fehlgeschlagen."); - network.getApp().setInfoText(e.getLocalizedMessage()); - } - -} \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java index 40897de..da9198f 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/NetworkSupport.java @@ -1,8 +1,11 @@ -package pp.monopoly.client; +//////////////////////////////////////// +// Programming project code +// UniBw M, 2022, 2023, 2024 +// www.unibw.de/inf2 +// (c) Mark Minas (mark.minas@unibw.de) +//////////////////////////////////////// -import java.io.IOException; -import java.lang.System.Logger; -import java.lang.System.Logger.Level; +package pp.monopoly.client; import com.jme3.network.Client; import com.jme3.network.ClientStateListener; @@ -10,12 +13,19 @@ import com.jme3.network.Message; import com.jme3.network.MessageListener; import com.jme3.network.Network; +import pp.monopoly.client.gui.CreateGameMenu; import pp.monopoly.game.client.ServerConnection; import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.server.ServerMessage; +import java.io.IOException; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; + +import static pp.monopoly.Resources.lookup; + /** - * Manages the network connection for the Monopoly application. + * Manages the network connection for the Battleship application. * Handles connecting to and disconnecting from the server, and sending messages. */ public class NetworkSupport implements MessageListener, ClientStateListener, ServerConnection { @@ -24,28 +34,32 @@ public class NetworkSupport implements MessageListener, ClientStateListe private Client client; /** - * Constructs a NetworkSupport instance for the Monopoly application. + * Constructs a NetworkSupport instance for the given Battleship application. * - * @param app The Monopoly application instance. + * @param app The Battleship application instance. */ public NetworkSupport(MonopolyApp app) { this.app = app; } /** - * Returns the Monopoly application instance. - * - * @return Monopoly application instance + * Return the client connections Id + * @return the client id */ - MonopolyApp getApp() { - return app; - } - public int getId() { if (client == null) return 0; return client.getId(); } + /** + * Returns the Battleship application instance. + * + * @return Battleship application instance + */ + public MonopolyApp getApp() { + return app; + } + /** * Checks if there is a connection to the game server. * @@ -62,9 +76,8 @@ public class NetworkSupport implements MessageListener, ClientStateListe */ @Override public void connect() { - if (client == null) { - new NetworkDialog(this).open(); - } + if (client == null) + new CreateGameMenu(this).open(); } /** @@ -75,7 +88,7 @@ public class NetworkSupport implements MessageListener, ClientStateListe if (client == null) return; client.close(); client = null; - LOGGER.log(Level.INFO, "Client connection closed."); + LOGGER.log(Level.INFO, "client closed"); //NON-NLS } /** @@ -86,9 +99,8 @@ public class NetworkSupport implements MessageListener, ClientStateListe * @throws IOException If an I/O error occurs when creating the client. */ public void initNetwork(String host, int port) throws IOException { - if (client != null) { - throw new IllegalStateException("Already connected to the game server."); - } + if (client != null) + throw new IllegalStateException("trying to join a game again"); client = Network.connectToServer(host, port); client.start(); client.addMessageListener(this); @@ -103,10 +115,9 @@ public class NetworkSupport implements MessageListener, ClientStateListe */ @Override public void messageReceived(Client client, Message message) { - LOGGER.log(Level.INFO, "Message received from server: {0}", message); - if (message instanceof ServerMessage serverMessage) { + LOGGER.log(Level.INFO, "message received from server: {0}", message); //NON-NLS + if (message instanceof ServerMessage serverMessage) app.enqueue(() -> serverMessage.accept(app.getGameLogic())); - } } /** @@ -116,7 +127,7 @@ public class NetworkSupport implements MessageListener, ClientStateListe */ @Override public void clientConnected(Client client) { - LOGGER.log(Level.INFO, "Successfully connected to server: {0}", client); + LOGGER.log(Level.INFO, "Client connected: {0}", client); //NON-NLS } /** @@ -127,9 +138,13 @@ public class NetworkSupport implements MessageListener, ClientStateListe */ @Override public void clientDisconnected(Client client, DisconnectInfo disconnectInfo) { - LOGGER.log(Level.INFO, "Disconnected from server: {0}", disconnectInfo); + LOGGER.log(Level.INFO, "Client {0} disconnected: {1}", client, disconnectInfo); //NON-NLS + if (this.client != client) + throw new IllegalArgumentException("parameter value must be client"); + LOGGER.log(Level.INFO, "client still connected: {0}", client.isConnected()); //NON-NLS this.client = null; - app.enqueue(() -> app.setInfoText("Verbindung zum Server verloren.")); + disconnect(); + app.enqueue(() -> app.setInfoText(lookup("lost.connection.to.server"))); } /** @@ -139,47 +154,10 @@ public class NetworkSupport implements MessageListener, ClientStateListe */ @Override public void send(ClientMessage message) { - LOGGER.log(Level.INFO, "Sending message to server: {0}", message); - if (client == null) { - app.errorDialog("Verbindung zum Server verloren."); - } else { + LOGGER.log(Level.INFO, "sending {0}", message); //NON-NLS + if (client == null) + app.errorDialog(lookup("lost.connection.to.server")); + else client.send(message); - } } - public void startServerAndJoin() { - new Thread(() -> { - // Server starten - app.startServer(); - - // Warten, bis der Server tatsächlich betriebsbereit ist - int retries = 5; - while (retries > 0) { - try { - initNetwork("localhost", app.getConfig().getPort()); - app.enqueue(() -> app.setInfoText("Erfolgreich verbunden!")); - return; // Verbindung erfolgreich - } catch (IOException e) { - retries--; - try { - Thread.sleep(1000); // Eine Sekunde warten und erneut versuchen - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - break; // Abbrechen, wenn der Thread unterbrochen wird - } - } - } - - // Wenn alle Versuche fehlschlagen - app.enqueue(() -> app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen.")); - }).start(); - } - - public void connectToServer(String host, int port) { - try { - initNetwork(host, port); // Verbindung initialisieren - app.setInfoText("Erfolgreich mit Server verbunden!"); - } catch (IOException e) { - app.errorDialog("Fehler: Verbindung zum Server fehlgeschlagen."); - } - } -} \ No newline at end of file +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java index b4c0ca0..82cf38a 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/CreateGameMenu.java @@ -1,151 +1,226 @@ +//////////////////////////////////////// +// Programming project code +// UniBw M, 2022, 2023, 2024 +// www.unibw.de/inf2 +// (c) Mark Minas (mark.minas@unibw.de) +//////////////////////////////////////// + package pp.monopoly.client.gui; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + import com.jme3.material.Material; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; import com.jme3.texture.Texture; -import com.simsilica.lemur.Axis; import com.simsilica.lemur.Button; import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; import com.simsilica.lemur.TextField; import com.simsilica.lemur.component.SpringGridLayout; +import static pp.monopoly.Resources.lookup; + import com.simsilica.lemur.style.ElementId; import pp.monopoly.client.MonopolyApp; -import pp.monopoly.client.StartMenu; - +import pp.monopoly.client.NetworkSupport; +import pp.monopoly.notification.Sound; +import pp.monopoly.server.MonopolyServer; +import pp.dialog.Dialog; +import pp.dialog.DialogBuilder; /** - * CreateGameMenu class represents the menu for creating a new game. + * Represents a dialog for setting up a network connection in the Battleship game. + * Allows users to specify the host and port for connecting to a game server. */ -public class CreateGameMenu { - - private final MonopolyApp app; - private final Container menuContainer; - private Geometry background; - private Label serverStatusLabel; - - public CreateGameMenu(MonopolyApp app) { - this.app = app; - - // Hintergrundbild laden und hinzufügen - addBackgroundImage(); - - // Hauptcontainer für das Menü - menuContainer = new Container(new SpringGridLayout(Axis.Y, Axis.X)); - menuContainer.setPreferredSize(new Vector3f(600, 400, 0)); // Feste Größe des Containers - - // Titel - Label title = menuContainer.addChild(new Label("Neues Spiel", new ElementId("header"))); - title.setFont(app.getAssetManager().loadFont("Interface/Fonts/Metropolis/Metropolis-Bold-42.fnt")); - title.setFontSize(50); - - - // Eingabefelder-Container - Container inputContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X))); - inputContainer.setPreferredSize(new Vector3f(200, 150, 0)); // Eingabefelder nicht ganz so breit - inputContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand - - inputContainer.addChild(new Label("Server-Adresse:")); - TextField playerNameField = inputContainer.addChild(new TextField("localhost")); - playerNameField.setPreferredWidth(400); // Breite des Textfelds - - inputContainer.addChild(new Label("Port:")); - TextField serverAddressField = inputContainer.addChild(new TextField("42069")); - serverAddressField.setPreferredWidth(400); // Breite des Textfelds - - // Button-Container - Container buttonContainer = menuContainer.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y))); - buttonContainer.setPreferredSize(new Vector3f(400, 50, 0)); - buttonContainer.setLocalTranslation(20, 0, 0); // Abstand vom Rand - - // "Abbrechen"-Button - Button cancelButton = buttonContainer.addChild(new Button("Abbrechen")); - cancelButton.setPreferredSize(new Vector3f(120, 40, 0)); - cancelButton.addClickCommands(source -> goBackToStartMenu()); - - // "Selber hosten"-Button - Button hostButton = buttonContainer.addChild(new Button("Selber hosten")); - hostButton.setPreferredSize(new Vector3f(120, 40, 0)); - hostButton.addClickCommands(source -> app.getNetworkSupport().startServerAndJoin()); - - // "Beitreten"-Button - Button joinButton = buttonContainer.addChild(new Button("Beitreten")); - joinButton.setPreferredSize(new Vector3f(120, 40, 0)); - joinButton.addClickCommands(source -> { - try { - String host = playerNameField.getText().trim(); - int port = Integer.parseInt(serverAddressField.getText().trim()); - app.getNetworkSupport().connectToServer(host, port); - - // LobbyMenu öffnen - app.enqueue(() -> { - app.getGuiNode().detachAllChildren(); // Bestehende GUI entfernen - new LobbyMenu(app); // LobbyMenu erstellen - }); - } catch (NumberFormatException e) { - app.errorDialog("Port muss eine Zahl sein."); - } - }); - - // Serverstatus-Label - serverStatusLabel = menuContainer.addChild(new Label("Serverstatus: Noch nicht gestartet")); - serverStatusLabel.setFontSize(24); - - // Zentrierung des Containers - menuContainer.setLocalTranslation( - (app.getCamera().getWidth() - menuContainer.getPreferredSize().x) / 2, - (app.getCamera().getHeight() + menuContainer.getPreferredSize().y) / 2, - 1 // Höhere Z-Ebene für den Vordergrund - ); - app.getInputManager().addMapping("OpenTestWorld", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_T)); - app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() { - @Override - public void onAction(String name, boolean isPressed, float tpf) { - if (name.equals("OpenTestWorld") && isPressed) { - app.startTestWorld(); // Öffnet die TestWorld - } - } - }, "OpenTestWorld"); - - // TODO später entfernen - - app.getInputManager().addMapping("OpenBuyCard", new com.jme3.input.controls.KeyTrigger(com.jme3.input.KeyInput.KEY_B)); - app.getInputManager().addListener(new com.jme3.input.controls.ActionListener() { - @Override - public void onAction(String name, boolean isPressed, float tpf) { - if (name.equals("OpenBuyCard") && isPressed) { - app.startBuyCard(); // Öffnet die TestWorld - } - } - }, "OpenBuyCard"); - - app.getGuiNode().attachChild(menuContainer); - } +public class CreateGameMenu extends Dialog { + private static final Logger LOGGER = System.getLogger(CreateGameMenu.class.getName()); + private static final String LOCALHOST = "localhost"; //NON-NLS + private static final String DEFAULT_PORT = "42069"; //NON-NLS + private final NetworkSupport network; + private final TextField host = new TextField(LOCALHOST); + private final TextField port = new TextField(DEFAULT_PORT); + private final Button serverButton = new Button("Selber hosten"); + private final Button cancelButton = new Button("Abbrechen"); + private final Button joinButton = new Button("Beitreten"); + private String hostname; + private int portNumber; + private Future connectionFuture; + private Dialog progressDialog; /** - * Lädt das Hintergrundbild und fügt es als geometrische Ebene hinzu. + * Constructs a new CreateGameMenu. + * + * @param network The NetworkSupport instance to be used for network operations. */ - private void addBackgroundImage() { + public CreateGameMenu(NetworkSupport network) { + super(network.getApp().getDialogManager()); + this.network = network; + host.setSingleLine(true); + host.setPreferredWidth(400f); + port.setSingleLine(true); + + final MonopolyApp app = network.getApp(); + + int screenWidth = app.getContext().getSettings().getWidth(); + int screenHeight = app.getContext().getSettings().getHeight(); + + // Set up the background image Texture backgroundImage = app.getAssetManager().loadTexture("Pictures/unibw-Bib2.png"); - Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); - background = new Geometry("Background", quad); + Quad quad = new Quad(screenWidth, screenHeight); + Geometry background = new Geometry("Background", quad); Material backgroundMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); backgroundMaterial.setTexture("ColorMap", backgroundImage); background.setMaterial(backgroundMaterial); - background.setLocalTranslation(0, 0, -1); // Hintergrundebene - + background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements app.getGuiNode().attachChild(background); + + addChild(new Label("Spiel erstellen", new ElementId("header"))); //NON-NLS + final Container input = new Container(new SpringGridLayout()); + input.addChild(new Label(lookup("host.name") + ": ")); + input.addChild(host, 1); + input.addChild(new Label(lookup("port.number") + ": ")); + input.addChild(port, 1); + + addChild(input); + // "Abbrechen"-Button + cancelButton.setPreferredSize(new Vector3f(120, 40, 0)); + cancelButton.addClickCommands(s -> ifTopDialog(() -> { + app.getGameLogic().playSound(Sound.BUTTON); + this.close(); + new StartMenu(network.getApp()).open(); + })); + addChild(cancelButton); + + // "Selber hosten"-Button + serverButton.addClickCommands(s -> ifTopDialog( () -> { + network.getApp().getGameLogic().playSound(Sound.BUTTON); + startServerInThread(); + } )); + addChild(serverButton); + + // "Beitreten"-Button + joinButton.setPreferredSize(new Vector3f(120, 40, 0)); + joinButton.addClickCommands(s -> ifTopDialog( () -> { + app.getGameLogic().playSound(Sound.BUTTON); + connect(); + })); + addChild(joinButton); } /** - * Geht zum Startmenü zurück, wenn "Abbrechen" angeklickt wird. + * Handles the action for the connect button in the connection dialog. + * Tries to parse the port number and initiate connection to the server. */ - private void goBackToStartMenu() { - app.getGuiNode().detachChild(menuContainer); - app.getGuiNode().detachChild(background); // Entfernt das Hintergrundbild - StartMenu.createStartMenu(app); + private void connect() { + LOGGER.log(Level.INFO, "connect to host={0}, port={1}", host, port); //NON-NLS + try { + hostname = host.getText().trim().isEmpty() ? LOCALHOST : host.getText(); + portNumber = Integer.parseInt(port.getText()); + openProgressDialog(); + connectionFuture = network.getApp().getExecutor().submit(this::initNetwork); + } + catch (NumberFormatException e) { + network.getApp().errorDialog(lookup("port.must.be.integer")); + } + } + + /** + * Creates a dialog indicating that the connection is in progress. + */ + private void openProgressDialog() { + progressDialog = DialogBuilder.simple(network.getApp().getDialogManager()) + .setText(lookup("label.connecting")) + .build(); + progressDialog.open(); + } + + /** + * Tries to initialize the network connection. + * + * @throws RuntimeException If an error occurs when creating the client. + */ + private Object initNetwork() { + try { + network.initNetwork(hostname, portNumber); + return null; + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void escape() { + new SettingsMenu(network.getApp()).open(); + } + + /** + * This method is called by {@linkplain pp.dialog.DialogManager#update(float)} for periodically + * updating this dialog. T + */ + @Override + public void update(float delta) { + if (connectionFuture != null && connectionFuture.isDone()) + try { + connectionFuture.get(); + success(); + } + catch (ExecutionException e) { + failure(e.getCause()); + } + catch (InterruptedException e) { + LOGGER.log(Level.WARNING, "Interrupted!", e); //NON-NLS + Thread.currentThread().interrupt(); + } + } + + /** + * Handles a successful connection to the game server. + */ + private void success() { + connectionFuture = null; + progressDialog.close(); + this.close(); + new LobbyMenu(network.getApp()).open(); + } + + /** + * Handles a failed connection attempt. + * + * @param e The cause of the failure. + */ + private void failure(Throwable e) { + connectionFuture = null; + progressDialog.close(); + network.getApp().errorDialog(lookup("server.connection.failed")); + network.getApp().setInfoText(e.getLocalizedMessage()); + } + + /** + * Starts the server in a separate thread. + */ + private void startServerInThread() { + serverButton.setEnabled(false); + Thread serverThread = new Thread(() -> { + try { + MonopolyServer.main(null); + } catch (Exception e) { + serverButton.setEnabled(true); + LOGGER.log(Level.ERROR, "Server could not be started", e); + network.getApp().errorDialog("Could not start server: " + e.getMessage()); + } + }); + serverThread.start(); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + connect(); } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java index 30f8731..2368699 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/LobbyMenu.java @@ -22,17 +22,15 @@ import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.core.VersionedList; import com.simsilica.lemur.core.VersionedReference; import com.simsilica.lemur.style.ElementId; + +import pp.dialog.Dialog; import pp.monopoly.client.MonopolyApp; -import pp.monopoly.game.client.ClientGameLogic; -import pp.monopoly.game.server.Player; -import pp.monopoly.game.server.PlayerColor; -import pp.monopoly.game.server.PlayerHandler; -import pp.monopoly.model.Figure; -import pp.monopoly.model.Rotation; +import pp.monopoly.message.client.PlayerReady; +import pp.monopoly.notification.Sound; import java.util.Set; -public class LobbyMenu { +public class LobbyMenu extends Dialog { private final MonopolyApp app; private final Container menuContainer; @@ -48,12 +46,13 @@ public class LobbyMenu { private Selector figureDropdown; - public LobbyMenu(MonopolyApp app) { - this.app = app; - this.playerHandler = ClientGameLogic.getPlayerHandler(); // Initialize PlayerHandler + private TextField playerInputField = new TextField("Spieler 1"); + private TextField startingCapital = new TextField("15000"); + private String figure; - int playerID = app.getNetworkSupport().getId(); // Retrieve the player ID - assignPlayerColor(playerID); //set the Players Color + public LobbyMenu(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; app.getGuiNode().detachAllChildren(); // Entfernt das CreateGameMenu (inklusive Hintergrund) @@ -79,7 +78,7 @@ public class LobbyMenu { spacerBeforeInput.setPreferredSize(new Vector3f(20, 1, 0)); // Width of the spacer // Add an input field (TextField) - TextField startingCapital = horizontalContainer.addChild(new TextField("15 000")); + horizontalContainer.addChild(startingCapital); startingCapital.setPreferredWidth(100); // Set the width of the input field startingCapital.setPreferredSize(new Vector3f(150, 50, 0)); startingCapital.setInsets(new Insets3f(5, 10, 5, 10)); // Add padding around the text inside the field @@ -106,7 +105,6 @@ public class LobbyMenu { playerInputContainer.setBackground(null); - TextField playerInputField = new TextField("Spieler 1"); playerInputField.setPreferredSize(new Vector3f(100, 20, 0)); playerInputField.setInsets(new Insets3f(5, 10, 5, 10)); playerInputField.setBackground(new QuadBackgroundComponent(ColorRGBA.Black)); @@ -146,10 +144,13 @@ public class LobbyMenu { buttonContainer.setBackground(null); // Lower-left container for "Abbrechen" button lowerLeftMenu = new Container(); - Button cancelButton = new Button("Abbrechen"); + Button cancelButton = new Button("Beenden"); cancelButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image cancelButton.setFontSize(18); // Adjust font size - cancelButton.addClickCommands(source -> goBackToCreateGame()); // Add functionality + cancelButton.addClickCommands(s -> ifTopDialog(() -> { + app.closeApp(); + app.getGameLogic().playSound(Sound.BUTTON); + })); lowerLeftMenu.addChild(cancelButton); // Position the container near the bottom-left corner @@ -162,9 +163,10 @@ public class LobbyMenu { readyButton.setPreferredSize(new Vector3f(200, 60, 0)); // Set size to match the appearance in the image readyButton.setFontSize(18); // Adjust font size readyButton.setBackground(new QuadBackgroundComponent(ColorRGBA.Green)); // Add color to match the style - readyButton.addClickCommands(source -> applyStartingCapital(playerID)); - readyButton.addClickCommands(source -> applyPlayerName(playerID)); - readyButton.addClickCommands(source -> applyFigure(playerID)); + readyButton.addClickCommands(s -> ifTopDialog(() -> { + toggleReady(); + app.getGameLogic().playSound(Sound.BUTTON); + })); lowerRightMenu.addChild(readyButton); //TODO aktivieren des Spielers in den ready Status und Sprung in den nächsten Menüzustand @@ -286,41 +288,13 @@ public class LobbyMenu { * * @param playerID the player's ID */ - private void assignPlayerColor(int playerID) { - switch (playerID) { - case 0: - playerColor = PlayerColor.RED.getColor(); - break; - case 1: - playerColor = PlayerColor.GREEN_LIGHT.getColor(); - break; - case 2: - playerColor = PlayerColor.BLUE.getColor(); - break; - case 3: - playerColor = PlayerColor.PINK.getColor(); - break; - case 4: - playerColor = PlayerColor.GREEN_DARK.getColor(); - break; - case 5: - playerColor = PlayerColor.YELLOW.getColor(); - break; - default: - playerColor = ColorRGBA.White; // Default color if ID is unknown - } + private void toggleReady() { + app.getGameLogic().send(new PlayerReady(true, playerInputField.getText(), figure, Integer.parseInt(startingCapital.getText()))); } - /** - * Geht zurück zum CreateGameMenu. - */ - private void goBackToCreateGame() { - app.getGuiNode().detachChild(menuContainer); - app.getGuiNode().detachChild(background); - app.getGuiNode().detachChild(circle); - app.getGuiNode().detachChild(lowerLeftMenu); - app.getGuiNode().detachChild(lowerRightMenu); - new CreateGameMenu(app); + @Override + public void escape() { + new SettingsMenu(app).open(); } /** @@ -364,27 +338,28 @@ public class LobbyMenu { */ private void onDropdownSelectionChanged(String selected) { System.out.println("Selected: " + selected); + app.getGameLogic().playSound(Sound.BUTTON); switch (selected) { case "[0]": - System.out.println("Laptop selected"); + figure = "Laptop"; break; case "[1]": - System.out.println("Flugzeug selected"); + figure = "Flugzeug"; break; case "[2]": - System.out.println("Jägermeister selected"); + figure = "Jägermeister"; break; case "[3]": - System.out.println("Katze selected"); + figure = "Katze"; break; case "[4]": - System.out.println("OOP selected"); + figure = "OOP"; break; case "[5]": - System.out.println("Handyholster selected"); + figure = "Handyholster"; break; default: - System.out.println("Unknown selection"); + break; } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java index 5fabf92..f0faeb5 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SettingsMenu.java @@ -1,123 +1,92 @@ +//////////////////////////////////////// +// Programming project code +// UniBw M, 2022, 2023, 2024 +// www.unibw.de/inf2 +// (c) Mark Minas (mark.minas@unibw.de) +//////////////////////////////////////// + package pp.monopoly.client.gui; -import com.jme3.material.Material; -import com.jme3.material.RenderState.BlendMode; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Vector3f; -import com.jme3.scene.Geometry; -import com.jme3.scene.shape.Quad; +import java.util.prefs.Preferences; + import com.simsilica.lemur.Button; import com.simsilica.lemur.Checkbox; -import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; -import com.simsilica.lemur.Slider; -import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.style.ElementId; -import com.simsilica.lemur.ValueRenderer; -import com.simsilica.lemur.Selector; -import pp.dialog.Dialog; +import static pp.monopoly.Resources.lookup; +import pp.monopoly.client.GameMusic; +import pp.monopoly.client.GameSound; import pp.monopoly.client.MonopolyApp; +import pp.dialog.Dialog; +import pp.dialog.StateCheckboxModel; +import pp.monopoly.notification.Sound; + +import static pp.util.PreferencesUtils.getPreferences; /** - * SettingsMenu ist ein Overlay-Menü, das durch ESC aufgerufen werden kann. + * The Menu class represents the main menu in the Battleship game application. + * It extends the Dialog class and provides functionalities for loading, saving, + * returning to the game, and quitting the application. */ public class SettingsMenu extends Dialog { + private static final Preferences PREFERENCES = getPreferences(SettingsMenu.class); + private static final String LAST_PATH = "last.file.path"; private final MonopolyApp app; - private final Geometry overlayBackground; - private final Container settingsContainer; - private final Container backgroundContainer; + private final VolumeSlider musicSlider; + private final SoundSlider soundSlider; + /** + * Constructs the Menu dialog for the Battleship application. + * + * @param app the MonopolyApp instance + */ public SettingsMenu(MonopolyApp app) { super(app.getDialogManager()); this.app = app; + musicSlider = new VolumeSlider(app.getStateManager().getState(GameMusic.class)); + soundSlider = new SoundSlider(app.getStateManager().getState(GameSound.class)); + addChild(new Label("Einstellungen", new ElementId("settings-title"))); //NON-NLS + addChild(new Label("Sound Effekte", new ElementId("label"))); //NON-NLS - // Halbtransparentes Overlay hinzufügen - overlayBackground = createOverlayBackground(); - app.getGuiNode().attachChild(overlayBackground); + addChild(soundSlider); - // Create the background container - backgroundContainer = new Container(); - backgroundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.8657f, 0.8735f, 0.8892f, 1.0f))); // Darker background - app.getGuiNode().attachChild(backgroundContainer); + addChild(new Checkbox("Soundeffekte an / aus", new StateCheckboxModel(app, GameSound.class))); + + addChild(new Label("Hintergrund Musik", new ElementId("label"))); //NON-NLS + addChild(new Checkbox("Musik an / aus", new StateCheckboxModel(app, GameMusic.class))); + + addChild(musicSlider); - // Hauptcontainer für das Menü - settingsContainer = new Container(); - settingsContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.1f, 0.1f, 0.1f, 0.9f))); - - - - // Titel - Label settingsTitle = settingsContainer.addChild(new Label("Einstellungen", new ElementId("settings-title"))); - settingsTitle.setFontSize(48); - - // Effekt-Sound: Slider und Checkbox - Container effectSoundContainer = settingsContainer.addChild(new Container()); - effectSoundContainer.addChild(new Label("Effekt Sound", new ElementId("label"))); - effectSoundContainer.addChild(new Slider()); - effectSoundContainer.addChild(new Checkbox("Soundeffekte an")).setChecked(true); - effectSoundContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); - // Hintergrundmusik: Slider und Checkbox - Container backgroundMusicContainer = settingsContainer.addChild(new Container()); - backgroundMusicContainer.addChild(new Label("Hintergrund Musik", new ElementId("label"))); - backgroundMusicContainer.addChild(new Slider()); - backgroundMusicContainer.addChild(new Checkbox("Musik an")).setChecked(true); - backgroundMusicContainer.setBackground(new QuadBackgroundComponent(new ColorRGBA(0.4657f, 0.4735f, 0.4892f, 1.0f))); - - // Beenden-Button - Button quitButton = settingsContainer.addChild(new Button("Beenden", new ElementId("menu-button"))); - quitButton.setFontSize(32); - quitButton.addClickCommands(source -> app.stop()); - - float padding = 10; // Padding around the settingsContainer for the background - backgroundContainer.setPreferredSize(settingsContainer.getPreferredSize().addLocal(padding, padding, 0)); - - - // Zentriere das Menü - settingsContainer.setLocalTranslation( - (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x) / 2, - (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y) / 2, - 4 - ); - - backgroundContainer.setLocalTranslation( - (app.getCamera().getWidth() - settingsContainer.getPreferredSize().x - padding) / 2, - (app.getCamera().getHeight() + settingsContainer.getPreferredSize().y+ padding) / 2, - 3 - ); - - app.getGuiNode().attachChild(settingsContainer); + addChild(new Button("Zurück zum Spiel", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> { + this.close(); // Close the StartMenu dialog + app.getGameLogic().playSound(Sound.BUTTON); + })); + addChild(new Button("Beenden", new ElementId("button"))).addClickCommands(s -> ifTopDialog(() -> { + app.getGameLogic().playSound(Sound.BUTTON); + app.closeApp(); + })); + update(); } /** - * Erstellt einen halbtransparenten Hintergrund für das Menü. - * - * @return Geometrie des Overlays - */ - private Geometry createOverlayBackground() { - Quad quad = new Quad(app.getCamera().getWidth(), app.getCamera().getHeight()); - Geometry overlay = new Geometry("Overlay", quad); - Material material = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); - material.setColor("Color", new ColorRGBA(0, 0, 0, 0.5f)); // Halbtransparent - material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); - overlay.setMaterial(material); - overlay.setLocalTranslation(0, 0, 0); - return overlay; - } - - /** - * Schließt das Menü und entfernt die GUI-Elemente. + * Updates the state of the load and save buttons based on the game logic. */ @Override - public void close() { - System.out.println("Schließe SettingsMenu..."); // Debugging-Ausgabe - app.getGuiNode().detachChild(settingsContainer); // Entferne das Menü - app.getGuiNode().detachChild(backgroundContainer); //Entfernt Rand - app.getGuiNode().detachChild(overlayBackground); // Entferne das Overlay - app.setSettingsMenuOpen(false); // Menü als geschlossen markieren - app.unblockInputs(); // Eingaben wieder aktivieren - System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe + public void update() { } + @Override + public void update(float delta) { + musicSlider.update(); + soundSlider.update(); + } + /** + * As an escape action, this method closes the menu if it is the top dialog. + */ + @Override + public void escape() { + close(); + } } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SoundSlider.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SoundSlider.java new file mode 100644 index 0000000..31c547e --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/SoundSlider.java @@ -0,0 +1,31 @@ +package pp.monopoly.client.gui; + +import com.simsilica.lemur.Slider; +import pp.monopoly.client.GameSound; + +public class SoundSlider extends Slider { + + private final pp.monopoly.client.GameSound sound; + private double vol; + + /** + * Constructs the Volume Slider for the Menu dialog + * @param sound the Effects sound instance + */ + public SoundSlider(GameSound sound) { + super(); + this.sound = sound; + vol = GameSound.volumeInPreferences(); + getModel().setPercent(vol); + } + + /** + * when triggered it updates the volume to the value set with the slider + */ + public void update() { + if (vol != getModel().getPercent()) { + vol = getModel().getPercent(); + sound.setVolume( (float) vol); + } + } +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/StartMenu.java similarity index 63% rename from Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java rename to Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/StartMenu.java index 302bd55..8a9c532 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/StartMenu.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/StartMenu.java @@ -1,4 +1,4 @@ -package pp.monopoly.client; +package pp.monopoly.client.gui; import com.jme3.material.Material; import com.jme3.math.Vector3f; @@ -13,8 +13,8 @@ import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.component.SpringGridLayout; import pp.dialog.Dialog; -import pp.monopoly.client.gui.CreateGameMenu; -import pp.monopoly.client.gui.SettingsMenu; +import pp.monopoly.client.MonopolyApp; +import pp.monopoly.notification.Sound; /** * Constructs the startup menu dialog for the Monopoly application. @@ -22,8 +22,6 @@ import pp.monopoly.client.gui.GameMenu; */ public class StartMenu extends Dialog { private final MonopolyApp app; - private Container logoContainer; - private Container unibwLogoContainer; /** * Constructs the Startup Menu dialog for the Monopoly application. @@ -33,13 +31,7 @@ public class StartMenu extends Dialog { public StartMenu(MonopolyApp app) { super(app.getDialogManager()); this.app = app; - } - - /** - * Creates and displays the Start Menu with buttons for starting the game, - * opening settings, and quitting the application. - */ - public static void createStartMenu(MonopolyApp app) { + int screenWidth = app.getContext().getSettings().getWidth(); int screenHeight = app.getContext().getSettings().getHeight(); @@ -53,9 +45,6 @@ public class StartMenu extends Dialog { background.setLocalTranslation(0, 0, -1); // Ensure it is behind other GUI elements app.getGuiNode().attachChild(background); - createMonopolyLogo(app); - createUnibwLogo(app); - // Center container for title and play button Container centerMenu = new Container(new SpringGridLayout(Axis.Y, Axis.X)); @@ -64,7 +53,11 @@ public class StartMenu extends Dialog { startButton.setFontSize(40); // Set the font size for the button text startButton.setTextHAlignment(HAlignment.Center); // Center the text horizontally - startButton.addClickCommands(source -> startGame(app)); + startButton.addClickCommands(s -> ifTopDialog(() -> { + this.close(); // Close the StartMenu dialog + app.connect(); // Perform the connection logic + app.getGameLogic().playSound(Sound.BUTTON); + })); centerMenu.addChild(startButton); // Position the center container in the middle of the screen @@ -73,34 +66,6 @@ public class StartMenu extends Dialog { 0)); app.getGuiNode().attachChild(centerMenu); - // Lower-left container for "Spiel beenden" button - Container lowerLeftMenu = new Container(); - lowerLeftMenu.setLocalTranslation(new Vector3f(100, 90, 0)); - Button quitButton = new Button("Spiel beenden"); - quitButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height) - quitButton.setFontSize(18); - quitButton.addClickCommands(source -> quitGame()); - lowerLeftMenu.addChild(quitButton); - app.getGuiNode().attachChild(lowerLeftMenu); - - // Lower-right container for "Einstellungen" button - Container lowerRightMenu = new Container(); - lowerRightMenu.setLocalTranslation(new Vector3f(screenWidth - 200, 90, 0)); - Button settingsButton = new Button("Einstellungen"); - settingsButton.setPreferredSize(new Vector3f(130, 40, 0)); // Increase button size slightly (width, height) - settingsButton.setFontSize(18); // Increase the font size for the text - settingsButton.addClickCommands(source -> openSettings(app)); - lowerRightMenu.addChild(settingsButton); - app.getGuiNode().attachChild(lowerRightMenu); - } - - /** - * Creates and positions the Monopoly logo container in the center of the screen. - */ - private static void createMonopolyLogo(MonopolyApp app) { - int screenWidth = app.getContext().getSettings().getWidth(); - int screenHeight = app.getContext().getSettings().getHeight(); - // Load the Monopoly logo as a texture Texture logoTexture = app.getAssetManager().loadTexture("Pictures/logo-monopoly.png"); @@ -123,14 +88,6 @@ public class StartMenu extends Dialog { // Attach the container to the GUI node app.getGuiNode().attachChild(logoContainer); - } - - /** - * Creates and positions the Unibw logo container in the center of the screen. - */ - private static void createUnibwLogo(MonopolyApp app) { - int screenWidth = app.getContext().getSettings().getWidth(); - int screenHeight = app.getContext().getSettings().getHeight(); // Load the Unibw logo as a texture Texture unibwTexture = app.getAssetManager().loadTexture("Pictures/logo-unibw.png"); @@ -156,26 +113,14 @@ public class StartMenu extends Dialog { app.getGuiNode().attachChild(unibwContainer); } - /** - * Starts the game by transitioning to the CreateGameMenu. - */ - private static void startGame(MonopolyApp app) { - app.getGuiNode().detachAllChildren(); - new CreateGameMenu(app); + @Override + public void escape() { + new SettingsMenu(app).open(); } - /** - * Opens the settings menu. - */ - private static void openSettings(MonopolyApp app) { + @Override + public void close() { app.getGuiNode().detachAllChildren(); - new SettingsMenu(app); - } - - /** - * Quits the game application. - */ - private static void quitGame() { - System.exit(0); + super.close(); } } \ No newline at end of file diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java index bd49ccf..85c4e07 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/Toolbar.java @@ -14,6 +14,7 @@ import com.simsilica.lemur.component.SpringGridLayout; import com.simsilica.lemur.style.ElementId; import pp.dialog.Dialog; import pp.monopoly.client.MonopolyApp; +import pp.monopoly.notification.Sound; /** * Toolbar Klasse, die am unteren Rand der Szene angezeigt wird. @@ -135,7 +136,10 @@ public class Toolbar extends Dialog { private Button addDiceRollButton() { Button diceButton = new Button("Würfeln"); diceButton.setPreferredSize(new Vector3f(50, 20, 0)); - diceButton.addClickCommands(source -> rollDice()); + diceButton.addClickCommands(s -> ifTopDialog(() -> { + rollDice(); + app.getGameLogic().playSound(Sound.BUTTON); + })); toolbarContainer.addChild(diceButton); return diceButton; } @@ -143,21 +147,30 @@ public class Toolbar extends Dialog { private void addTradeMenuButton() { Button diceButton = new Button("Handeln"); diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons - diceButton.addClickCommands(source -> rollDice()); + diceButton.addClickCommands(s -> ifTopDialog(() -> { + rollDice(); + app.getGameLogic().playSound(Sound.BUTTON); + })); toolbarContainer.addChild(diceButton); } private void addEndTurnButton() { Button diceButton = new Button("Grundstücke"); diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons - diceButton.addClickCommands(source -> rollDice()); + diceButton.addClickCommands(s -> ifTopDialog(() -> { + rollDice(); + app.getGameLogic().playSound(Sound.BUTTON); + })); toolbarContainer.addChild(diceButton); } private void addPropertyMenuButton() { Button diceButton = new Button("Zug beenden"); diceButton.setPreferredSize(new Vector3f(150, 50, 0)); // Größe des Buttons - diceButton.addClickCommands(source -> rollDice()); + diceButton.addClickCommands(s -> ifTopDialog(() -> { + rollDice(); + app.getGameLogic().playSound(Sound.BUTTON); + })); toolbarContainer.addChild(diceButton); } diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/VolumeSlider.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/VolumeSlider.java new file mode 100644 index 0000000..c0c8cc2 --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/VolumeSlider.java @@ -0,0 +1,37 @@ +package pp.monopoly.client.gui; + +import com.simsilica.lemur.Slider; + +import pp.monopoly.client.GameMusic; +/** + * The VolumeSlider class represents the Volume Slider in the Menu. + * It extends the Slider class and provides functionalities for setting the music volume, + * with the help of the Slider in the GUI + */ +public class VolumeSlider extends Slider { + + private final pp.monopoly.client.GameMusic music; + private double vol; + + /** + * Constructs the Volume Slider for the Menu dialog + * @param music the music instance + */ + public VolumeSlider(GameMusic music) { + super(); + this.music = music; + vol = GameMusic.volumeInPreferences(); + getModel().setPercent(vol); + } + + /** + * when triggered it updates the volume to the value set with the slider + */ + public void update() { + if (vol != getModel().getPercent()) { + vol = getModel().getPercent(); + music.setVolume( (float) vol); + } + } + +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java index 85426cd..39e948f 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuildingPropertyCard.java @@ -30,7 +30,7 @@ public class BuildingPropertyCard extends Dialog { this.app = app; //Generate the corresponfing field - BuildingProperty field = (BuildingProperty) app.getBoardManager().getFieldAtIndex(index); + BuildingProperty field = (BuildingProperty) app.getGameLogic().getBoardManager().getFieldAtIndex(index); // Halbtransparentes Overlay hinzufügen overlayBackground = createOverlayBackground(); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java index 88a5dc1..bfae0f6 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/BuyCard.java @@ -5,7 +5,9 @@ import com.jme3.material.RenderState.BlendMode; import com.jme3.math.ColorRGBA; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.simsilica.lemur.*; +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.Label; import com.simsilica.lemur.component.QuadBackgroundComponent; import com.simsilica.lemur.style.ElementId; import pp.dialog.Dialog; @@ -119,4 +121,4 @@ public class BuyCard extends Dialog { app.unblockInputs(); // Eingaben wieder aktivieren System.out.println("SettingsMenu geschlossen."); // Debugging-Ausgabe } -} \ No newline at end of file +} diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java index 05bf891..8b55a4d 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/FoodFieldCard.java @@ -5,7 +5,6 @@ import com.jme3.material.RenderState.BlendMode; import com.jme3.math.ColorRGBA; import com.jme3.scene.Geometry; import com.jme3.scene.shape.Quad; -import com.simsilica.lemur.Button; import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; import com.simsilica.lemur.component.QuadBackgroundComponent; @@ -30,7 +29,7 @@ public class FoodFieldCard extends Dialog { this.app = app; //Generate the corresponfing field - FoodField field = (FoodField) app.getBoardManager().getFieldAtIndex(index); + FoodField field = (FoodField) app.getGameLogic().getBoardManager().getFieldAtIndex(index); // Halbtransparentes Overlay hinzufügen overlayBackground = createOverlayBackground(); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java index 373440b..a736662 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/GateFieldCard.java @@ -28,7 +28,7 @@ public class GateFieldCard extends Dialog { this.app = app; //Generate the corresponfing field - GateField field = (GateField) app.getBoardManager().getFieldAtIndex(index); + GateField field = (GateField) app.getGameLogic().getBoardManager().getFieldAtIndex(index); // Halbtransparentes Overlay hinzufügen overlayBackground = createOverlayBackground(); diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/LooserPopUp.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/LooserPopUp.java new file mode 100644 index 0000000..a24fb2a --- /dev/null +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/LooserPopUp.java @@ -0,0 +1,52 @@ +package pp.monopoly.client.gui.popups; + +import com.simsilica.lemur.Button; +import com.simsilica.lemur.Container; +import com.simsilica.lemur.Label; +import com.simsilica.lemur.component.IconComponent; + +import pp.dialog.Dialog; +import pp.monopoly.client.MonopolyApp; + +public class LooserPopUp extends Dialog { + + private final MonopolyApp app; + + /** + * Constructs a new NetworkDialog. + * + * @param network The NetworkSupport instance to be used for network operations. + */ + public LooserPopUp(MonopolyApp app) { + super(app.getDialogManager()); + this.app = app; + initializeDialog(); + } + + /** + * Initializes the dialog with input fields and connection buttons. + */ + private void initializeDialog() { + Container inputContainer = new Container(); + + // Titel und Eingabefelder für Host und Port + inputContainer.addChild(new Label("Schade, du hast leider verloren!")); + inputContainer.addChild(new Label("Die nächste Runde wird besser!")); + + Label imageLabel = new Label(""); + IconComponent icon = new IconComponent("Pictures/MonopolyLooser.png"); // Icon mit Textur erstellen + icon.setIconScale(1); // Skalierung des Bildes + imageLabel.setIcon(icon); + + // Setze das Icon im Label + inputContainer.addChild(imageLabel); + + Button cancelButton = inputContainer.addChild(new Button("Spiel beenden")); + cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp)); + + inputContainer.setLocalTranslation(300, 800, 0); + app.getGuiNode().attachChild(inputContainer); + + } +} + diff --git a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/WinnerPopUp.java b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/WinnerPopUp.java index fb6f065..ffb4c09 100644 --- a/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/WinnerPopUp.java +++ b/Projekte/monopoly/client/src/main/java/pp/monopoly/client/gui/popups/WinnerPopUp.java @@ -1,8 +1,5 @@ package pp.monopoly.client.gui.popups; -import com.jme3.asset.TextureKey; -import com.jme3.math.Vector2f; -import com.jme3.texture.Texture; import com.simsilica.lemur.Button; import com.simsilica.lemur.Container; import com.simsilica.lemur.Label; @@ -37,20 +34,18 @@ public class WinnerPopUp extends Dialog { inputContainer.addChild(new Label("Du,bist der Monopoly Champion!!!")); Label imageLabel = new Label(""); - TextureKey key = new TextureKey("Pictures/MonopolyWinner.png", true); - Texture texture = app.getAssetManager().loadTexture(key); - IconComponent icon = new IconComponent(texture.toString()); // Icon mit Textur erstellen - icon.setIconSize(new Vector2f(150f, 100f)); // Skalierung des Bildes + IconComponent icon = new IconComponent("Pictures/MonopolyWinner.png"); // Icon mit Textur erstellen + icon.setIconScale(1); // Skalierung des Bildes imageLabel.setIcon(icon); // Setze das Icon im Label - inputContainer.addChild(imageLabel); Button cancelButton = inputContainer.addChild(new Button("Spiel beenden")); cancelButton.addClickCommands(source -> ifTopDialog(app::closeApp)); - inputContainer.setLocalTranslation(300, 500, 0); - attachChild(inputContainer); + + inputContainer.setLocalTranslation(300, 800, 0); + app.getGuiNode().attachChild(inputContainer); } } diff --git a/Projekte/monopoly/client/src/main/resources/Pictures/MonopolyLooser.png b/Projekte/monopoly/client/src/main/resources/Pictures/MonopolyLooser.png new file mode 100644 index 0000000..2de2fa1 Binary files /dev/null and b/Projekte/monopoly/client/src/main/resources/Pictures/MonopolyLooser.png differ diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java index 2fe9495..cbef5e0 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/MonopolyConfig.java @@ -28,7 +28,7 @@ public class MonopolyConfig extends Config { * The default port number for the Monopoly server. */ @Property("port") - private int port = 4321; + private int port = 42069; /** * The width of the game map in terms of grid units. diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java index 9459dca..4467043 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/client/ClientGameLogic.java @@ -5,7 +5,7 @@ import java.lang.System.Logger.Level; import java.util.ArrayList; import java.util.List; -import pp.monopoly.game.server.PlayerHandler; +import pp.monopoly.game.server.Player; import pp.monopoly.message.client.ClientMessage; import pp.monopoly.message.server.BuyPropertyResponse; import pp.monopoly.message.server.DiceResult; @@ -22,6 +22,7 @@ import pp.monopoly.message.server.TradeRequest; import pp.monopoly.message.server.ViewAssetsResponse; import pp.monopoly.model.Board; import pp.monopoly.model.IntPoint; +import pp.monopoly.model.fields.BoardManager; import pp.monopoly.notification.ClientStateEvent; import pp.monopoly.notification.GameEvent; import pp.monopoly.notification.GameEventBroker; @@ -51,7 +52,9 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { /** The current state of the client game logic. */ private ClientState state = new LobbyState(this); - private static PlayerHandler playerHandler; + private List players; + + private BoardManager boardManager = new BoardManager(); /** * Constructs a ClientGameLogic with the specified sender object. @@ -62,6 +65,14 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { this.clientSender = clientSender; } + /** + * Reutns the BoardManager + * @return the boardManager + */ + public BoardManager getBoardManager() { + return boardManager; + } + /** * Returns the current state of the game logic. * @@ -83,8 +94,8 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { state.entry(); } - public static PlayerHandler getPlayerHandler() { - return playerHandler; + public List getPlayers() { + return players; } /** @@ -128,11 +139,12 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { * * @param msg the message to be sent */ - void send(ClientMessage msg) { + public void send(ClientMessage msg) { if (clientSender == null) { LOGGER.log(Level.ERROR, "trying to send {0} with sender==null", msg); //NON-NLS } else { clientSender.send(msg); + System.out.println("Message gesendet"); } } @@ -243,7 +255,7 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker { */ @Override public void received(GameStart msg) { - playerHandler = msg.getPlayerHandler(); + players = msg.getPlayers(); setInfoText("The game has started! Good luck!"); setState(new WaitForTurnState(this)); } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java index eddbe2a..8e41fda 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/Player.java @@ -10,6 +10,8 @@ package pp.monopoly.game.server; import java.util.List; import java.util.Random; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.message.server.DiceResult; import pp.monopoly.model.FieldVisitor; import pp.monopoly.model.Figure; @@ -28,6 +30,7 @@ import pp.monopoly.model.fields.WacheField; /** * Class representing a player */ +@Serializable public class Player implements FieldVisitor{ private final int id; private String name; @@ -40,6 +43,14 @@ public class Player implements FieldVisitor{ private final PlayerHandler handler; private PlayerState state = new LobbyState(); + /** + * Default constructor for serialization purposes. + */ + private Player(){ + id = 0; + handler = null; + } + /** * Constructs a player with the speciefied params * @param id the id of the player diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java index 285e707..aebe09c 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/PlayerHandler.java @@ -8,10 +8,13 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Set; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.LimitedLinkedList; /** * A class for helping with player actions and managing thier turns */ +@Serializable public class PlayerHandler { private List players = new LimitedLinkedList<>(6); private Set readyPlayers = new HashSet<>(); @@ -19,6 +22,11 @@ public class PlayerHandler { private Player hostPlayer; private Player extra = null; + /** + * Default constructor for serialization purposes. + */ + private PlayerHandler() {} + /** * Contructs a PlayerHandler * @param logic the {@link ServerGameLogic} this PlayerHandler is a part of diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java index 53555a5..a901fac 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/game/server/ServerGameLogic.java @@ -204,7 +204,7 @@ public class ServerGameLogic implements ClientInterpreter { if(playerHandler.allPlayersReady()) { playerHandler.setStartBalance(startMoney); for (Player p : playerHandler.getPlayers()) { - send(p, new GameStart(playerHandler)); + send(p, new GameStart(playerHandler.getPlayers())); } playerHandler.randomOrder(); send(playerHandler.getPlayerAtIndex(0), new NextPlayerTurn(playerHandler.getPlayerAtIndex(0))); diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/BuyPropertyRequest.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/BuyPropertyRequest.java index 12a6bc9..6ecd9b3 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/BuyPropertyRequest.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/BuyPropertyRequest.java @@ -1,11 +1,19 @@ package pp.monopoly.message.client; +import com.jme3.network.serializing.Serializable; + /** * Represents a request from a player to buy a property. */ +@Serializable public class BuyPropertyRequest extends ClientMessage{ private int propertyId; + /** + * Default constructor for serialization purposes. + */ + private BuyPropertyRequest() { /* empty */ } + /** * Constructs a BuyPropertyRequest with the specified property ID. * diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/EndTurn.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/EndTurn.java index dae8120..f08e8cd 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/EndTurn.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/EndTurn.java @@ -1,9 +1,18 @@ package pp.monopoly.message.client; + +import com.jme3.network.serializing.Serializable; + /** * Represents a message indicating the player wants to end their turn. */ +@Serializable public class EndTurn extends ClientMessage{ + /** + * Default constructor for serialization purposes. + */ + public EndTurn() { /* empty */ } + @Override public void accept(ClientInterpreter interpreter, int from) { interpreter.received(this, from); diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java index 42aa0d6..ee61d11 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/PlayerReady.java @@ -1,13 +1,21 @@ package pp.monopoly.message.client; +import com.jme3.network.serializing.Serializable; + /** * Represents a message indicating the player is ready to play. */ +@Serializable public class PlayerReady extends ClientMessage { - private final boolean isReady; - private final String name; - private final String figure; - private final int startMoney; + private boolean isReady; + private String name; + private String figure; + private int startMoney; + + /** + * Default constructor for serialization purposes. + */ + private PlayerReady() { /* empty */ } /** * Constructs a PlayerReady message. diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/RollDice.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/RollDice.java index 9fb0b93..a4d5dfc 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/RollDice.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/RollDice.java @@ -1,9 +1,18 @@ package pp.monopoly.message.client; + +import com.jme3.network.serializing.Serializable; + /** * Represents a message requesting to roll the dice. */ +@Serializable public class RollDice extends ClientMessage{ + /** + * Default constructor for serialization purposes. + */ + private RollDice() { /* empty */ } + @Override public void accept(ClientInterpreter interpreter, int from) { interpreter.received(this, from); diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeOffer.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeOffer.java index b614365..edb885f 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeOffer.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeOffer.java @@ -1,14 +1,21 @@ package pp.monopoly.message.client; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.TradeHandler; /** * Represents a trade Request message from one player to another. */ +@Serializable public class TradeOffer extends ClientMessage{ private int receiverId; private TradeHandler tradehandler; + /** + * Default constructor for serialization purposes. + */ + private TradeOffer() { /* empty */ } /** * Constructs a TradeOffer with the specified details. diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeResponse.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeResponse.java index d317c6f..78d38f0 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeResponse.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/TradeResponse.java @@ -1,14 +1,22 @@ package pp.monopoly.message.client; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.TradeHandler; /** * Represents a response to a trade offer. */ +@Serializable public class TradeResponse extends ClientMessage{ private int initiatorId; private TradeHandler tradeHandler; + /** + * Default constructor for serialization purposes. + */ + private TradeResponse() { /* empty */ } + /** * Constructs a TradeResponse with the specified response details. * diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java index afbdc79..11c26af 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/client/ViewAssetsRequest.java @@ -1,13 +1,21 @@ package pp.monopoly.message.client; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.game.server.Player; /** * Represents a request from a player to view their assets. */ +@Serializable public class ViewAssetsRequest extends ClientMessage{ - private final Player player; + private Player player; + + /** + * Default constructor for serialization purposes. + */ + private ViewAssetsRequest() { /* empty */ } public ViewAssetsRequest(Player player) { this.player = player; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/BuyPropertyResponse.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/BuyPropertyResponse.java index e926317..39e1e24 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/BuyPropertyResponse.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/BuyPropertyResponse.java @@ -1,12 +1,20 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + /** * Represents the server's response to a player's request to buy a property. */ +@Serializable public class BuyPropertyResponse extends ServerMessage{ - private final boolean successful; - private final String propertyName; - private final String reason; // Reason for failure, if any + private boolean successful; + private String propertyName; + private String reason; // Reason for failure, if any + + /** + * Default constructor for serialization purposes. + */ + private BuyPropertyResponse() { /* empty */ } public BuyPropertyResponse(boolean successful, String propertyName, String reason) { this.successful = successful; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/DiceResult.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/DiceResult.java index 65a8223..4d63f91 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/DiceResult.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/DiceResult.java @@ -2,10 +2,18 @@ package pp.monopoly.message.server; import java.util.List; +import com.jme3.network.serializing.Serializable; + +@Serializable public class DiceResult extends ServerMessage{ private List rollResult; + /** + * Default constructor for serialization purposes. + */ + private DiceResult() { /* empty */ } + public DiceResult(List rollResult) { this.rollResult = rollResult; } diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/EventDrawCard.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/EventDrawCard.java index 968f2bb..929ac6e 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/EventDrawCard.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/EventDrawCard.java @@ -1,7 +1,15 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + +@Serializable public class EventDrawCard extends ServerMessage{ - private final String cardDescription; + private String cardDescription; + + /** + * Default constructor for serialization purposes. + */ + private EventDrawCard() { /* empty */ } public EventDrawCard(String cardDescription) { this.cardDescription = cardDescription; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameOver.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameOver.java index e91041e..91de2fc 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameOver.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameOver.java @@ -1,7 +1,15 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + +@Serializable public class GameOver extends ServerMessage{ - private final boolean isWinner; + private boolean isWinner; + + /** + * Default constructor for serialization purposes. + */ + private GameOver() { /* empty */ } public GameOver(boolean isWinner) { this.isWinner = isWinner; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java index 17679e5..9dfab8d 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/GameStart.java @@ -1,17 +1,27 @@ package pp.monopoly.message.server; -import pp.monopoly.game.server.PlayerHandler; +import java.util.List; +import com.jme3.network.serializing.Serializable; + +import pp.monopoly.game.server.Player; + +@Serializable public class GameStart extends ServerMessage{ - private final PlayerHandler ph; + private List players; - public GameStart(PlayerHandler ph) { - this.ph = ph; + /** + * Default constructor for serialization purposes. + */ + private GameStart() { /* empty */ } + + public GameStart(List players) { + this.players = players; } - public PlayerHandler getPlayerHandler() { - return ph; + public List getPlayers() { + return players; } @Override diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/JailEvent.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/JailEvent.java index 485a7fd..9996545 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/JailEvent.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/JailEvent.java @@ -1,8 +1,16 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + +@Serializable public class JailEvent extends ServerMessage{ - private final boolean goingToJail; + private boolean goingToJail; + + /** + * Default constructor for serialization purposes. + */ + private JailEvent() { /* empty */ } public JailEvent(boolean goingToJail) { this.goingToJail = goingToJail; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java index f047f90..d0f5a18 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/NextPlayerTurn.java @@ -1,10 +1,18 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.game.server.Player; +@Serializable public class NextPlayerTurn extends ServerMessage{ - private final Player player; + private Player player; + + /** + * Default constructor for serialization purposes. + */ + private NextPlayerTurn() { /* empty */ } public NextPlayerTurn(Player player) { this.player = player; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/PlayerStatusUpdate.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/PlayerStatusUpdate.java index c876108..0a84661 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/PlayerStatusUpdate.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/PlayerStatusUpdate.java @@ -1,12 +1,20 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.game.server.PlayerColor; +@Serializable public class PlayerStatusUpdate extends ServerMessage{ - private final String playerName; - private final String status; - private final PlayerColor color; + private String playerName; + private String status; + private PlayerColor color; + + /** + * Default constructor for serialization purposes. + */ + private PlayerStatusUpdate() { /* empty */ } public PlayerStatusUpdate(String playerName, String status, PlayerColor color) { this.playerName = playerName; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TimeOutWarning.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TimeOutWarning.java index b862170..684ee2a 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TimeOutWarning.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TimeOutWarning.java @@ -1,8 +1,16 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + +@Serializable public class TimeOutWarning extends ServerMessage{ - private final int remainingTime; + private int remainingTime; + + /** + * Default constructor for serialization purposes. + */ + private TimeOutWarning() { /* empty */ } public TimeOutWarning(int remainingTime) { this.remainingTime = remainingTime; diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeReply.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeReply.java index 6535906..38ef4ec 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeReply.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeReply.java @@ -1,14 +1,22 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.TradeHandler; /** * Represents a response to a trade offer. */ +@Serializable public class TradeReply extends ServerMessage{ private int initiatorId; private TradeHandler tradeHandler; + /** + * Default constructor for serialization purposes. + */ + private TradeReply() { /* empty */ } + /** * Constructs a TradeResponse with the specified response details. * diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeRequest.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeRequest.java index 5320953..7afeb34 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeRequest.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/TradeRequest.java @@ -1,15 +1,23 @@ package pp.monopoly.message.server; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.TradeHandler; /** * Represents a trade Request message from one player to another. */ +@Serializable public class TradeRequest extends ServerMessage{ private int receiverId; private TradeHandler tradehandler; + /** + * Default constructor for serialization purposes. + */ + private TradeRequest() { /* empty */ } + /** * Constructs a TradeRequest with the specified details. * diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java index be75108..5c944f4 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/message/server/ViewAssetsResponse.java @@ -2,18 +2,26 @@ package pp.monopoly.message.server; import java.util.List; +import com.jme3.network.serializing.Serializable; + import pp.monopoly.model.fields.BoardManager; import pp.monopoly.model.fields.PropertyField; /** * Represents a response containing the player's assets. */ +@Serializable public class ViewAssetsResponse extends ServerMessage{ - private final List properties; - private final BoardManager board; - private final int accountBalance; - private final int jailCards; + private List properties; + private BoardManager board; + private int accountBalance; + private int jailCards; + + /** + * Default constructor for serialization purposes. + */ + private ViewAssetsResponse() { /* empty */ } /** * Constructs a ViewAssetsResponse with the specified properties and account balance. diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java index 99e6ab9..9ac874b 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/Figure.java @@ -4,9 +4,12 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import com.jme3.network.serializing.Serializable; + import static java.lang.Math.max; import static java.lang.Math.min; +@Serializable public class Figure implements Item{ private final String type; private final int length; // The length of the Figure diff --git a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java index 5a0285e..34990f6 100644 --- a/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java +++ b/Projekte/monopoly/model/src/main/java/pp/monopoly/model/LimitedLinkedList.java @@ -2,14 +2,22 @@ package pp.monopoly.model; import java.util.LinkedList; +import com.jme3.network.serializing.Serializable; + /** * A LinkedList with a maximum size limit. * * @param the type of elements held in this collection */ +@Serializable public class LimitedLinkedList extends LinkedList { - private final int maxSize; + private int maxSize; + + /** + * Default constructor for serialization purposes. + */ + private LimitedLinkedList() {} /** * Constructs a LimitedLinkedList with the specified maximum size. diff --git a/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java b/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java index f4bfa7e..4c1b56d 100644 --- a/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java +++ b/Projekte/monopoly/server/src/main/java/pp/monopoly/server/MonopolyServer.java @@ -26,11 +26,23 @@ import com.jme3.network.serializing.Serializer; import pp.monopoly.MonopolyConfig; import pp.monopoly.game.server.Player; +import pp.monopoly.game.server.PlayerHandler; import pp.monopoly.game.server.ServerGameLogic; import pp.monopoly.game.server.ServerSender; +import pp.monopoly.message.client.BuyPropertyRequest; import pp.monopoly.message.client.ClientMessage; +import pp.monopoly.message.client.EndTurn; +import pp.monopoly.message.client.PlayerReady; +import pp.monopoly.message.client.RollDice; +import pp.monopoly.message.client.TradeOffer; +import pp.monopoly.message.client.TradeResponse; +import pp.monopoly.message.client.ViewAssetsRequest; +import pp.monopoly.message.server.GameStart; +import pp.monopoly.message.server.NextPlayerTurn; import pp.monopoly.message.server.ServerMessage; +import pp.monopoly.model.Figure; import pp.monopoly.model.IntPoint; +import pp.monopoly.model.LimitedLinkedList; /** * Server implementing the visitor pattern as MessageReceiver for ClientMessages @@ -105,14 +117,35 @@ public class MonopolyServer implements MessageListener, Connec private void initializeSerializables() { Serializer.registerClass(IntPoint.class); + Serializer.registerClass(BuyPropertyRequest.class); + Serializer.registerClass(EndTurn.class); + Serializer.registerClass(PlayerReady.class); + Serializer.registerClass(RollDice.class); + Serializer.registerClass(TradeOffer.class); + Serializer.registerClass(TradeResponse.class); + Serializer.registerClass(ViewAssetsRequest.class); + Serializer.registerClass(GameStart.class); + Serializer.registerClass(LimitedLinkedList.class); + Serializer.registerClass(NextPlayerTurn.class); + Serializer.registerClass(Player.class); + Serializer.registerClass(Figure.class); + Serializer.registerClass(PlayerHandler.class); } private void registerListeners() { + myServer.addMessageListener(this, BuyPropertyRequest.class); + myServer.addMessageListener(this, EndTurn.class); + myServer.addMessageListener(this, PlayerReady.class); + myServer.addMessageListener(this, RollDice.class); + myServer.addMessageListener(this, TradeOffer.class); + myServer.addMessageListener(this, TradeResponse.class); + myServer.addMessageListener(this, ViewAssetsRequest.class); myServer.addConnectionListener(this); } @Override public void messageReceived(HostedConnection source, Message message) { + System.out.println("Message recieved"); LOGGER.log(Level.INFO, "message received from {0}: {1}", source.getId(), message); //NON-NLS if (message instanceof ClientMessage clientMessage) pendingMessages.add(new ReceivedMessage(clientMessage, source.getId()));