From e8b2d64119f5523b221f897948bf36791de7dc8c Mon Sep 17 00:00:00 2001 From: Johannes Teubler Date: Thu, 9 Dec 2021 21:36:40 +0100 Subject: [PATCH] #16 + updated CreateGameScreen functionality of CreateGameScreen WIP --- wizard-client/build.gradle.kts | 1 + .../wizard/client/libgdx/Client.java | 59 ++++++ .../wizard/client/libgdx/ClientSocket.java | 47 +++++ .../wizard/client/libgdx/WizardGame.java | 83 +++++++- .../libgdx/actors/game/overlay/Overlay.java | 3 +- .../client/libgdx/screens/ConnectScreen.java | 44 +++-- .../libgdx/screens/CreateGameScreen.java | 151 ++++++++++----- .../client/libgdx/screens/GameScreen.java | 78 ++++---- .../client/libgdx/screens/LoadingScreen.java | 37 ++++ .../client/libgdx/screens/LobbyScreen.java | 182 ++++++++++++------ .../client/libgdx/screens/MainMenuScreen.java | 25 ++- .../client/libgdx/screens/MenuScreen.java | 121 +++--------- .../client/libgdx/screens/WaitingScreen.java | 149 +++++++++----- .../wizard/client/libgdx/state/Awaiting.java | 28 +++ .../libgdx/state/AwaitingConnection.java | 29 +++ .../libgdx/state/AwaitingJoinLobby.java | 27 +++ .../libgdx/state/AwaitingJoinSession.java | 46 +++++ .../wizard/client/libgdx/state/BaseState.java | 35 ++++ .../client/libgdx/state/ClientState.java | 16 ++ .../wizard/client/libgdx/state/Creation.java | 34 ++++ .../wizard/client/libgdx/state/Lobby.java | 54 ++++++ .../wizard/client/libgdx/state/Menu.java | 35 ++++ .../wizard/client/libgdx/state/Session.java | 84 ++++++++ .../main/resources/i18n/messages.properties | 6 + .../resources/i18n/messages_de.properties | 6 + 25 files changed, 1041 insertions(+), 339 deletions(-) create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/Client.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/ClientSocket.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LoadingScreen.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinLobby.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/BaseState.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/ClientState.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Creation.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Lobby.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Menu.java create mode 100644 wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Session.java diff --git a/wizard-client/build.gradle.kts b/wizard-client/build.gradle.kts index 45a24b9..78fb591 100644 --- a/wizard-client/build.gradle.kts +++ b/wizard-client/build.gradle.kts @@ -1,5 +1,6 @@ subprojects { dependencies { implementation(project(":wizard-common")) + implementation(JavaWebSocket.id) } } \ No newline at end of file diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/Client.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/Client.java new file mode 100644 index 0000000..b754f65 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/Client.java @@ -0,0 +1,59 @@ +package eu.jonahbauer.wizard.client.libgdx; + +import eu.jonahbauer.wizard.client.libgdx.state.ClientState; +import eu.jonahbauer.wizard.client.libgdx.state.Menu; +import eu.jonahbauer.wizard.common.machine.TimeoutContext; +import eu.jonahbauer.wizard.common.messages.client.ClientMessage; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import lombok.Getter; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class Client extends TimeoutContext { + + @Getter + private final WizardGame game; + + @Getter + private ClientSocket socket; + + public Client(WizardGame game) { + super(new Menu()); + this.game = game; + } + + @Override + protected void handleError(Throwable t) { + // TODO better error handling + t.printStackTrace(); + } + + public void setSocket(ClientSocket socket) { + this.socket = socket; + if (socket != null) { + this.socket.setAttachment(this); + } + } + + public void onOpen() { + execute(s -> s.onOpen(this)); + } + + public void onClose(int code, String reason, boolean remote) { + execute(s -> s.onClose(this, code, reason, remote)); + } + + public void onMessage(ServerMessage message) { + log.debug(message.toString()); + execute(s -> s.onMessage(this, message)); + } + + @Override + protected void onTransition(ClientState from, ClientState to) { + System.out.println("Transistion from " + from.getClass().getSimpleName() + " to " + to.getClass().getSimpleName()); + } + + public void send(ClientMessage message) { + getSocket().send(message.toString()); + } +} \ No newline at end of file diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/ClientSocket.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/ClientSocket.java new file mode 100644 index 0000000..6e7d98b --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/ClientSocket.java @@ -0,0 +1,47 @@ +package eu.jonahbauer.wizard.client.libgdx; + +import com.badlogic.gdx.Gdx; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import org.java_websocket.client.WebSocketClient; +import org.java_websocket.framing.CloseFrame; +import org.java_websocket.handshake.ServerHandshake; + +import javax.net.ssl.SSLSocketFactory; +import java.net.URI; + +public class ClientSocket extends WebSocketClient { + public ClientSocket(URI serverUri) { + super(serverUri); + + if ("wss".equals(getURI().getScheme())) { + setSocketFactory(SSLSocketFactory.getDefault()); + } + } + + @Override + public void onOpen(ServerHandshake serverHandshake) { + Gdx.app.postRunnable(() -> getClient().onOpen()); + } + + @Override + public void onMessage(String s) { + ServerMessage message = ServerMessage.parse(s); + Gdx.app.postRunnable(() -> getClient().onMessage(message)); + } + + @Override + public void onClose(int i, String s, boolean b) { + Gdx.app.postRunnable(() -> getClient().onClose(i, s, b)); + } + + @Override + public void onError(Exception e) { + e.printStackTrace(); + close(CloseFrame.ABNORMAL_CLOSE, e.getMessage()); + } + + private Client getClient() { + return getAttachment(); + } +} + diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/WizardGame.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/WizardGame.java index 12fafe9..96af164 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/WizardGame.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/WizardGame.java @@ -5,10 +5,20 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Graphics; import com.badlogic.gdx.Input; import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.utils.I18NBundle; -import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; +import com.badlogic.gdx.utils.viewport.ExtendViewport; +import com.badlogic.gdx.utils.viewport.FitViewport; +import eu.jonahbauer.wizard.client.libgdx.screens.MainMenuScreen; +import lombok.Getter; import java.util.Locale; @@ -19,10 +29,14 @@ public class WizardGame extends Game { public SpriteBatch batch; public I18NBundle messages; + public Data data; private boolean toggle; private int oldHeight, oldWidth; + + @Getter + private final Client client = new Client(this); @Override public void create() { @@ -40,7 +54,7 @@ public class WizardGame extends Game { Gdx.graphics.setCursor(Gdx.graphics.newCursor(cursor, 0, 0)); cursor.dispose(); - this.setScreen(new GameScreen(this)); + this.setScreen(new MainMenuScreen(this)); } @Override @@ -71,5 +85,70 @@ public class WizardGame extends Game { @Override public void dispose () { batch.dispose(); + client.shutdownNow(); + var socket = client.getSocket(); + if (socket != null) { + socket.close(); + } + } + + public static class Data { + public final ExtendViewport extendViewport; + public final FitViewport fitViewport; + + public final Sound buttonClickSound; + + public final TextureAtlas uiskinAtlas; + public final TextureAtlas menuAtlas; + + public final TextureRegion title; + public final TextureRegion background; + public final TextureRegion[] corners = new TextureRegion[4]; + public final TextureRegion[] symbols = new TextureRegion[4]; + + public final Skin skin; + public final Stage stage; + + public Data() { + this.extendViewport = new ExtendViewport(WizardGame.WIDTH, WizardGame.HEIGHT); + this.fitViewport = new FitViewport(WizardGame.WIDTH, WizardGame.HEIGHT); + + this.buttonClickSound = Gdx.audio.newSound(Gdx.files.internal("button_click_s.mp3")); + + this.uiskinAtlas = new TextureAtlas(Gdx.files.internal(UiskinAtlas.$PATH)); + this.menuAtlas = new TextureAtlas(Gdx.files.internal(MenuAtlas.$PATH)); + + this.title = menuAtlas.findRegion(MenuAtlas.TITLE); + this.background = menuAtlas.findRegion(MenuAtlas.BACKGROUND); + this.corners[0] = menuAtlas.findRegion(MenuAtlas.ECKE_LO); + this.corners[1] = menuAtlas.findRegion(MenuAtlas.ECKE_LU); + this.corners[2] = menuAtlas.findRegion(MenuAtlas.ECKE_RU); + this.corners[3] = menuAtlas.findRegion(MenuAtlas.ECKE_RO); + this.symbols[0] = menuAtlas.findRegion(MenuAtlas.SYMBOL0); + this.symbols[1] = menuAtlas.findRegion(MenuAtlas.SYMBOL1); + this.symbols[2] = menuAtlas.findRegion(MenuAtlas.SYMBOL2); + this.symbols[3] = menuAtlas.findRegion(MenuAtlas.SYMBOL3); + + this.skin = new Skin(Gdx.files.internal("uiskin.json"), uiskinAtlas); + this.skin.getAll(BitmapFont.class).forEach(entry -> + entry.value.getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear) + ); + this.stage = new Stage(fitViewport); + if (WizardGame.DEBUG) { + stage.setDebugAll(true); + } + } + + public void reset() { + stage.clear(); + } + + public void dispose() { + buttonClickSound.dispose(); + uiskinAtlas.dispose(); + menuAtlas.dispose(); + skin.dispose(); + stage.dispose(); + } } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actors/game/overlay/Overlay.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actors/game/overlay/Overlay.java index f3936d2..cb9a8c2 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actors/game/overlay/Overlay.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actors/game/overlay/Overlay.java @@ -8,11 +8,10 @@ import com.badlogic.gdx.scenes.scene2d.ui.Container; import com.badlogic.gdx.scenes.scene2d.utils.Drawable; import eu.jonahbauer.wizard.client.libgdx.WizardGame; import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; -import eu.jonahbauer.wizard.client.libgdx.screens.MenuScreen; public abstract class Overlay { - protected final MenuScreen.Data data; + protected final WizardGame.Data data; protected final TextureAtlas atlas; private Container root; diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/ConnectScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/ConnectScreen.java index ee16f1d..39f50c4 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/ConnectScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/ConnectScreen.java @@ -7,7 +7,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.ui.TextField; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.utils.Align; +import eu.jonahbauer.wizard.client.libgdx.ClientSocket; import eu.jonahbauer.wizard.client.libgdx.WizardGame; +import eu.jonahbauer.wizard.client.libgdx.state.AwaitingConnection; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import lombok.SneakyThrows; + +import java.net.URI; public class ConnectScreen extends MenuScreen { @@ -16,47 +22,53 @@ public class ConnectScreen extends MenuScreen { private TextField uri; + public ConnectScreen(WizardGame game) { + super(game); + } + private final ChangeListener listener = new ChangeListener() { + @SneakyThrows @Override public void changed(ChangeEvent event, Actor actor) { if (actor == buttonBack) { - game.setScreen(new MainMenuScreen(game, data)); + game.setScreen(new MainMenuScreen(game)); sfxClick(); } else if (actor == buttonConnect) { - game.setScreen(new LobbyScreen(game, data)); + // TODO error handling, uri syntax, etc. + ClientSocket socket = new ClientSocket(new URI(uri.getText())); + game.getClient().setSocket(socket); + game.getClient().transition(new AwaitingConnection()); + socket.connect(); sfxClick(); } } }; - public ConnectScreen(WizardGame game, Data data) { - super(game, data); - } - @Override public void show() { super.show(); - buttonBack = new TextButton(game.messages.get("menu.connect.back"), data.skin); + buttonBack = new TextButton(game.messages.get("menu.connect.back"), game.data.skin); buttonBack.setPosition(WizardGame.WIDTH * 0.275f, BUTTON_BAR_Y); - buttonConnect = new TextButton(game.messages.get("menu.connect.connect"), data.skin); + buttonConnect = new TextButton(game.messages.get("menu.connect.connect"), game.data.skin); buttonConnect.setPosition(WizardGame.WIDTH * 0.725f - buttonConnect.getWidth(), BUTTON_BAR_Y); - var label = new Label(game.messages.get("menu.connect.address.label"), data.skin); + var label = new Label(game.messages.get("menu.connect.address.label"), game.data.skin); label.setSize(0.4f * WizardGame.WIDTH, 64); label.setAlignment(Align.center); label.setPosition(0.5f * (WizardGame.WIDTH - label.getWidth()), 0.55f * (WizardGame.HEIGHT - label.getHeight())); - uri = new TextField("", data.skin); - uri.setMessageText("wss://localhost/wizard"); + // TODO sensible default value + uri = new TextField("wss://webdev.jonahbauer.eu/wizard/", game.data.skin); + uri.setMessageText(game.messages.get("menu.connect.uri.hint")); uri.setSize(0.4f * WizardGame.WIDTH, 64); uri.setPosition(0.5f * (WizardGame.WIDTH - uri.getWidth()), 0.45f * (WizardGame.HEIGHT - uri.getHeight())); - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(buttonBack); - data.stage.addActor(buttonConnect); - data.stage.addActor(uri); - data.stage.addActor(label); + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(buttonBack); + game.data.stage.addActor(buttonConnect); + game.data.stage.addActor(uri); + game.data.stage.addActor(label); buttonBack.addListener(listener); buttonConnect.addListener(listener); diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java index 0dffc5b..c3937b5 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/CreateGameScreen.java @@ -2,79 +2,124 @@ package eu.jonahbauer.wizard.client.libgdx.screens; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.TextField; +import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.Array; import eu.jonahbauer.wizard.client.libgdx.WizardGame; +import eu.jonahbauer.wizard.client.libgdx.state.Session; +import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage; +import eu.jonahbauer.wizard.common.messages.data.SessionData; +import eu.jonahbauer.wizard.common.messages.server.SessionJoinedMessage; +import eu.jonahbauer.wizard.common.model.Configuration; public class CreateGameScreen extends MenuScreen { - TextButton backButton; - TextButton continueButton; + + private TextButton buttonBack; + private TextButton buttonContinue; - TextField option1; - TextField option2; - TextField option3; - TextField option4; - TextField option5; - TextField option6; + private TextField sessionName; + private TextField playerName; + private TextField timeOut; - ChangeListener listener = new ChangeListener() { + long selectedTimeOut; + String userName; + SelectBox configurations; + + private final ChangeListener listener = new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { - if (actor == backButton) { - game.setScreen(new LobbyScreen(game, data)); - sfxClick(); - } else if (actor == continueButton) { - game.setScreen(new WaitingScreen(game, data)); + if (actor == buttonBack) { + game.setScreen(new LobbyScreen(game)); sfxClick(); + } else if (actor == buttonContinue) { + if( sessionName.getText() == null ) { + System.out.println("Please select a session name."); + sessionName.clear(); + } + if (playerName.getText() == null) { + userName = "Mallory"; + System.out.println("Your name will be " + userName + "."); + } + try{ + selectedTimeOut = Long.parseLong(timeOut.getText()); + } catch (NumberFormatException e) { + System.out.println("Please select a valid timeout."); + timeOut.clear(); + } + int selected = configurations.getSelectedIndex(); + Configuration config = Configuration.values()[selected]; + game.getClient().send(new CreateSessionMessage(sessionName.getText(), playerName.getText(), selectedTimeOut, config)); } } }; - - public CreateGameScreen(WizardGame game, Data data) { - super(game, data); + + public CreateGameScreen(WizardGame game) { + super(game); } - + @Override public void show() { super.show(); - backButton = new TextButton("Zurück", data.skin); - backButton.setPosition(WizardGame.WIDTH * 0.275f, BUTTON_BAR_Y); - continueButton = new TextButton("Erstellen", data.skin); - continueButton.setPosition(WizardGame.WIDTH * 0.725f - continueButton.getWidth(), BUTTON_BAR_Y); + buttonBack = new TextButton(game.messages.get("menu.connect.back"), game.data.skin); + buttonBack.setPosition(WizardGame.WIDTH * 0.275f, BUTTON_BAR_Y); + buttonContinue = new TextButton("Erstellen", game.data.skin); + buttonContinue.setPosition(WizardGame.WIDTH * 0.725f - buttonContinue.getWidth(), BUTTON_BAR_Y); - option1 = new TextField("1", data.skin); - option1.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.6f); - option1.setSize(250, continueButton.getHeight()); - option2 = new TextField("2", data.skin); - option2.setPosition(option1.getX(), option1.getY() - WizardGame.HEIGHT * 0.12f); - option2.setSize(250, continueButton.getHeight()); - option3 = new TextField("3", data.skin); - option3.setPosition(option2.getX(), option2.getY() - WizardGame.HEIGHT * 0.12f); - option3.setSize(250, continueButton.getHeight()); + sessionName = new TextField("", game.data.skin); + sessionName.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.5f); + sessionName.setSize(0.4f * WizardGame.WIDTH, 64); - option4 = new TextField("4", data.skin); - option4.setPosition(WizardGame.WIDTH * 0.65f - option4.getWidth(), option1.getY()); - option4.setSize(250, continueButton.getHeight()); - option5 = new TextField("5", data.skin); - option5.setPosition(option4.getX(), option2.getY()); - option5.setSize(250, continueButton.getHeight()); - option6 = new TextField("6", data.skin); - option6.setPosition(option4.getX(), option3.getY()); - option6.setSize(250, continueButton.getHeight()); + playerName = new TextField("", game.data.skin); + playerName.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.45f); + playerName.setSize(0.4f * WizardGame.WIDTH, 64); - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(backButton); - data.stage.addActor(continueButton); - data.stage.addActor(option1); - data.stage.addActor(option2); - data.stage.addActor(option3); - data.stage.addActor(option4); - data.stage.addActor(option5); - data.stage.addActor(option6); + timeOut = new TextField("", game.data.skin); + timeOut.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.4f); + timeOut.setSize(0.4f * WizardGame.WIDTH, 64); + + configurations = new SelectBox<>(game.data.skin); + configurations.setSize(400, 64); + configurations.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.3f); + + Array values = new Array<>(); + for (Configuration value: Configuration.values() ) { + values.add(value.toString()); + } - backButton.addListener(listener); - continueButton.addListener(listener); + configurations.setItems(values); + + var contentTable = new Table().center().left(); + contentTable.columnDefaults(0).growX().width(0.4f * WizardGame.WIDTH - 20); + contentTable.setSize(0.4f * WizardGame.WIDTH - 20, 400); + + contentTable.add(new Label(game.messages.get("menu.lobby.player_name.label"), game.data.skin)).row(); + contentTable.add(playerName).row(); + contentTable.add(new Label(game.messages.get("menu.lobby.session_name.label"), game.data.skin)).row(); + contentTable.add(sessionName).row(); + contentTable.add(new Label(game.messages.get("menu.lobby.create_session.timeout.label"), game.data.skin)).row(); + contentTable.add(timeOut).row(); + contentTable.add(new Label(game.messages.get("menu.lobby.session_configuration.label"), game.data.skin)).row(); + contentTable.add(configurations).row(); + + contentTable.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.3f); + + + + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(buttonContinue); + game.data.stage.addActor(contentTable); + game.data.stage.addActor(buttonBack); + + buttonContinue.addListener(listener); + buttonBack.addListener(listener); + } + + public void performTransition(SessionJoinedMessage joined) { + int selected = configurations.getSelectedIndex(); + Configuration config = Configuration.values()[selected]; + System.out.println("Transition from Lobby to Session"); + SessionData sessionData = new SessionData(joined.getSession(), sessionName.getText(), joined.getPlayers().size(), config); + game.getClient().transition(new Session(joined, sessionData, playerName.getText())); } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java index fff470c..15baa3d 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java @@ -72,11 +72,7 @@ public class GameScreen extends MenuScreen { private final Map nameLabels = new HashMap<>(); public GameScreen(WizardGame game) { - this(game, null); - } - - public GameScreen(WizardGame game, Data data) { - super(game, data); + super(game); this.game = game; // @@ -99,7 +95,7 @@ public class GameScreen extends MenuScreen { public void show() { super.show(); atlas = new TextureAtlas(Gdx.files.internal(GameAtlas.$PATH)); - overlay = new TextureRegionDrawable(data.uiskinAtlas.findRegion(UiskinAtlas.WHITE)).tint(new Color(0,0,0,0.5f)); + overlay = new TextureRegionDrawable(game.data.uiskinAtlas.findRegion(UiskinAtlas.WHITE)).tint(new Color(0,0,0,0.5f)); seat(); prepareLabels(); @@ -116,7 +112,7 @@ public class GameScreen extends MenuScreen { messages.setSize(1200, 0); messages.setTouchable(Touchable.disabled); - padOfTruth = new PadOfTruth(data.skin, new TextureRegionDrawable(atlas.findRegion(GameAtlas.PAD_OF_TRUTH))); + padOfTruth = new PadOfTruth(game.data.skin, new TextureRegionDrawable(atlas.findRegion(GameAtlas.PAD_OF_TRUTH))); padOfTruth.setPosition(1910 - 636f, 10); padOfTruth.setOrigin(636f, 0); @@ -125,16 +121,16 @@ public class GameScreen extends MenuScreen { setNames(); - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(container); - data.stage.addActor(cardStack); - data.stage.addActor(padOfTruth); - data.stage.addActor(messages); - data.stage.addActor(debugButtons()); + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(container); + game.data.stage.addActor(cardStack); + game.data.stage.addActor(padOfTruth); + game.data.stage.addActor(messages); + game.data.stage.addActor(debugButtons()); } private Group debugButtons() { - var trump = new TextButton("Trump", data.skin, "simple"); + var trump = new TextButton("Trump", game.data.skin, "simple"); trump.align(Align.left); trump.addListener(new ChangeListener() { @Override @@ -146,7 +142,7 @@ public class GameScreen extends MenuScreen { } }); - var playCard = new TextButton("Play Card", data.skin, "simple"); + var playCard = new TextButton("Play Card", game.data.skin, "simple"); playCard.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -160,7 +156,7 @@ public class GameScreen extends MenuScreen { } }); - var deal = new TextButton("Deal", data.skin, "simple"); + var deal = new TextButton("Deal", game.data.skin, "simple"); deal.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -169,7 +165,7 @@ public class GameScreen extends MenuScreen { } }); - var round = new TextButton("Round", data.skin, "simple"); + var round = new TextButton("Round", game.data.skin, "simple"); round.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -178,7 +174,7 @@ public class GameScreen extends MenuScreen { } }); - var scores = new TextButton("Scores", data.skin, "simple"); + var scores = new TextButton("Scores", game.data.skin, "simple"); scores.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -187,7 +183,7 @@ public class GameScreen extends MenuScreen { } }); - var predictions = new TextButton("Predictions", data.skin, "simple"); + var predictions = new TextButton("Predictions", game.data.skin, "simple"); predictions.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -195,7 +191,7 @@ public class GameScreen extends MenuScreen { } }); - var playOtherCard = new TextButton("Play Other Card", data.skin, "simple"); + var playOtherCard = new TextButton("Play Other Card", game.data.skin, "simple"); playOtherCard.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -208,7 +204,7 @@ public class GameScreen extends MenuScreen { } }); - var makePrediction = new TextButton("Make Prediction", data.skin, "simple"); + var makePrediction = new TextButton("Make Prediction", game.data.skin, "simple"); makePrediction.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -216,7 +212,7 @@ public class GameScreen extends MenuScreen { } }); - var changePrediction = new TextButton("Change Prediction", data.skin, "simple"); + var changePrediction = new TextButton("Change Prediction", game.data.skin, "simple"); changePrediction.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -224,7 +220,7 @@ public class GameScreen extends MenuScreen { } }); - var chooseTrump = new TextButton("Choose Trump", data.skin, "simple"); + var chooseTrump = new TextButton("Choose Trump", game.data.skin, "simple"); chooseTrump.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { @@ -250,17 +246,17 @@ public class GameScreen extends MenuScreen { @Override protected void renderBackground(float delta) { float scale = Math.max( - data.extendViewport.getWorldWidth() / WizardGame.WIDTH, - data.extendViewport.getWorldHeight() / WizardGame.HEIGHT + game.data.extendViewport.getWorldWidth() / WizardGame.WIDTH, + game.data.extendViewport.getWorldHeight() / WizardGame.HEIGHT ); game.batch.setColor(1, 1, 1, 0.25f); - game.batch.draw(data.background, 0,0, scale * WizardGame.WIDTH, scale * WizardGame.HEIGHT); + game.batch.draw(game.data.background, 0,0, scale * WizardGame.WIDTH, scale * WizardGame.HEIGHT); game.batch.draw( - data.title, - (data.extendViewport.getWorldWidth() - data.title.getRegionWidth() * 0.75f) / 2f, - (data.extendViewport.getWorldHeight() - data.title.getRegionHeight() * 0.75f) / 2f, - 0.75f * data.title.getRegionWidth(), - 0.75f * data.title.getRegionHeight() + game.data.title, + (game.data.extendViewport.getWorldWidth() - game.data.title.getRegionWidth() * 0.75f) / 2f, + (game.data.extendViewport.getWorldHeight() - game.data.title.getRegionHeight() * 0.75f) / 2f, + 0.75f * game.data.title.getRegionWidth(), + 0.75f * game.data.title.getRegionHeight() ); } @@ -287,13 +283,13 @@ public class GameScreen extends MenuScreen { private void prepareLabels() { for (UUID player : players) { if (self.equals(player)) continue; - var label = new Label("", data.skin); + var label = new Label("", game.data.skin); var seat = seats.get(player); label.setX(seat.getLabelX()); label.setY(seat.getLabelY()); label.setAlignment(seat.getLabelAlign()); this.nameLabels.put(player, label); - data.stage.addActor(label); + game.data.stage.addActor(label); } } @@ -327,7 +323,7 @@ public class GameScreen extends MenuScreen { cardStack.clearChildren(); stack.clear(); - new StartRoundOverlay(this, round).show(data.stage); + new StartRoundOverlay(this, round).show(game.data.stage); } private void startTrick() { @@ -364,7 +360,7 @@ public class GameScreen extends MenuScreen { trumpCardActor = new CardActor(Card.HIDDEN, atlas); } - new TrumpOverlay(this, null, trumpCard, trumpSuit).show(data.stage); + new TrumpOverlay(this, null, trumpCard, trumpSuit).show(game.data.stage); } private void addPrediction(UUID player, int prediction) { @@ -427,7 +423,7 @@ public class GameScreen extends MenuScreen { } private void addMessage(String text) { - var label = new Label(text, data.skin); + var label = new Label(text, game.data.skin); label.addAction(sequence( delay(1.5f), alpha(0, 0.25f), @@ -461,9 +457,9 @@ public class GameScreen extends MenuScreen { setActivePlayer(userInput.getPlayer(), userInput.getAction()); if (self.equals(userInput.getPlayer())) { switch (userInput.getAction()) { - case PICK_TRUMP -> new PickTrumpOverlay(this, false).show(data.stage); - case MAKE_PREDICTION -> new MakePredictionOverlay(this, round).show(data.stage); - case CHANGE_PREDICTION -> new ChangePredictionOverlay(this, round, predictions.get(self)).show(data.stage); + case PICK_TRUMP -> new PickTrumpOverlay(this, false).show(game.data.stage); + case MAKE_PREDICTION -> new MakePredictionOverlay(this, round).show(game.data.stage); + case CHANGE_PREDICTION -> new ChangePredictionOverlay(this, round, predictions.get(self)).show(game.data.stage); } // TODO do something } @@ -479,8 +475,8 @@ public class GameScreen extends MenuScreen { } } - public MenuScreen.Data getData() { - return data; + public WizardGame.Data getData() { + return game.data; } @Getter diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LoadingScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LoadingScreen.java new file mode 100644 index 0000000..4b6eb04 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LoadingScreen.java @@ -0,0 +1,37 @@ +package eu.jonahbauer.wizard.client.libgdx.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; +import eu.jonahbauer.wizard.client.libgdx.WizardGame; + +public class LoadingScreen extends MenuScreen { + private final String key; + + @Deprecated + public LoadingScreen(WizardGame game) { + this(game, "menu.loading.loading"); + } + + public LoadingScreen(WizardGame game, String key) { + super(game); + this.key = key; + } + + @Override + public void show() { + super.show(); + + var label = new Label(game.messages.get(key), game.data.skin); + + var content = new VerticalGroup(); + content.setPosition(WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT*0.5f); + content.addActor(label); + + game.data.stage.addActor(content); + + Gdx.input.setInputProcessor(game.data.stage); + } + +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java index e94cb68..6a7e1ea 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/LobbyScreen.java @@ -6,56 +6,73 @@ import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import eu.jonahbauer.wizard.client.libgdx.WizardGame; import eu.jonahbauer.wizard.client.libgdx.actors.AutoFocusScrollPane; +import eu.jonahbauer.wizard.client.libgdx.state.AwaitingJoinSession; +import eu.jonahbauer.wizard.client.libgdx.state.Creation; +import eu.jonahbauer.wizard.client.libgdx.state.Lobby; +import eu.jonahbauer.wizard.client.libgdx.state.Menu; +import eu.jonahbauer.wizard.common.messages.client.JoinSessionMessage; import eu.jonahbauer.wizard.common.messages.data.SessionData; -import eu.jonahbauer.wizard.common.model.Configuration; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; -import java.util.stream.IntStream; import java.util.stream.StreamSupport; public class LobbyScreen extends MenuScreen { - + private TextButton buttonBack; private TextButton buttonJoin; private TextButton buttonCreate; - + private TextField playerName; private Label labelSessionName; private Label labelSessionPlayerCount; private Label labelSessionConfiguration; - + + private UUID selectedSession; private List sessions; - + private final Map sessionData = new HashMap<>(); + private final ChangeListener listener = new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { if (actor == buttonBack) { - game.setScreen(new ConnectScreen(game, data)); + game.getClient().transition(new Menu()); sfxClick(); } else if (actor == buttonJoin) { - game.setScreen(new WaitingScreen(game, data)); + if(playerName.getText().isEmpty()) { + System.out.println("Please choose a player name"); + game.getClient().transition(new Menu()); + } + if (selectedSession != null) { + var name = playerName.getText(); + var session = sessionData.get(selectedSession); + game.getClient().transition(new AwaitingJoinSession(session, name)); + game.getClient().send(new JoinSessionMessage(selectedSession, name)); + } sfxClick(); } else if (actor == buttonCreate) { - game.setScreen(new CreateGameScreen(game, data)); + game.setScreen(new CreateGameScreen(game)); sfxClick(); } } }; - - public LobbyScreen(WizardGame game, Data data) { - super(game, data); + + public LobbyScreen(WizardGame game) { + super(game); } - + @Override public void show() { super.show(); - - buttonBack = new TextButton(game.messages.get("menu.lobby.back"), data.skin); - buttonJoin = new TextButton(game.messages.get("menu.lobby.join"), data.skin); + + buttonBack = new TextButton(game.messages.get("menu.lobby.back"), game.data.skin); + buttonJoin = new TextButton(game.messages.get("menu.lobby.join"), game.data.skin); buttonJoin.setDisabled(true); - buttonCreate = new TextButton(game.messages.get("menu.lobby.create"), data.skin); - - sessions = new List<>(data.skin) { + buttonCreate = new TextButton(game.messages.get("menu.lobby.create"), game.data.skin); + + sessions = new List<>(game.data.skin) { @Override public String toString(SessionData session) { return session.getName(); @@ -64,18 +81,21 @@ public class LobbyScreen extends MenuScreen { sessions.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { - updateData(sessions.getSelected()); + var selected = sessions.getSelected(); + updateData(selected); } }); - - var listContainer = new AutoFocusScrollPane(sessions, data.skin); - + + var listContainer = new AutoFocusScrollPane(sessions, game.data.skin); + listContainer.layout(); + var content = new HorizontalGroup().grow().space(20); content.setPosition(0.25f * WizardGame.WIDTH, 0.3f * WizardGame.HEIGHT); content.setSize(0.5f * WizardGame.WIDTH, 400); content.addActor(new Container<>(listContainer).width(0.2f * WizardGame.WIDTH).height(400)); content.addActor(createInfoTable()); - + content.layout(); + var buttons = new HorizontalGroup(); buttons.setPosition(WizardGame.WIDTH * 0.2f, BUTTON_BAR_Y); buttons.setSize(WizardGame.WIDTH * 0.60f, 125); @@ -83,67 +103,103 @@ public class LobbyScreen extends MenuScreen { buttons.addActor(buttonCreate); buttons.addActor(buttonJoin); buttons.space(Math.max(0, (float) (buttons.getWidth() - StreamSupport.stream(buttons.getChildren().spliterator(), false).mapToDouble(Actor::getWidth).sum()) / (buttons.getChildren().size - 1))); - - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(content); - data.stage.addActor(buttons); - + + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(content); + game.data.stage.addActor(buttons); + buttonBack.addListener(listener); buttonJoin.addListener(listener); buttonCreate.addListener(listener); - - addSessions( - IntStream.range(1, 16) - .mapToObj(i -> new SessionData( - UUID.randomUUID(), - "Session " + i, - i % 5, - Configuration.values()[i % Configuration.values().length] - )) - .toArray(SessionData[]::new) - ); } - - public void addSessions(SessionData...sessions) { - for (SessionData session : sessions) { - this.sessions.getItems().add(session); + + public void addSession(SessionData session) { + this.sessionData.put(session.getUuid(), session); + this.sessions.getItems().add(session); + this.sessions.invalidateHierarchy(); + } + + public void removeSession(UUID session) { + this.sessionData.remove(session); + var items = this.sessions.getItems(); + for (int i = 0; i < items.size; i++) { + if (items.get(i).getUuid().equals(session)) { + items.removeIndex(i); + break; + } } this.sessions.invalidateHierarchy(); + + if (session.equals(selectedSession)) { + updateData(null); + } } - + + public void modifySession(SessionData session) { + this.sessionData.put(session.getUuid(), session); + var items = this.sessions.getItems(); + for (int i = 0; i < items.size; i++) { + if (items.get(i).getUuid().equals(session.getUuid())) { + items.set(i, session); + break; + } + } + this.sessions.invalidateHierarchy(); + + if (session.getUuid().equals(selectedSession)) { + updateData(session); + } + } + + public void setSessions(SessionData... sessions) { + this.sessionData.clear(); + Arrays.stream(sessions).forEach(s -> this.sessionData.put(s.getUuid(), s)); + var items = this.sessions.getItems(); + items.clear(); + items.addAll(sessions); + this.sessions.invalidateHierarchy(); + } + private void updateData(SessionData data) { - System.out.println(data); - labelSessionName.setText(data.getName()); - labelSessionPlayerCount.setText(Integer.toString(data.getPlayerCount())); - labelSessionConfiguration.setText(data.getConfiguration().toString()); + if (data != null) { + labelSessionName.setText(data.getName()); + labelSessionPlayerCount.setText(Integer.toString(data.getPlayerCount())); + labelSessionConfiguration.setText(data.getConfiguration().toString()); + selectedSession = data.getUuid(); + } else { + labelSessionName.setText(""); + labelSessionPlayerCount.setText(""); + labelSessionConfiguration.setText(""); + selectedSession = null; + } buttonJoin.setDisabled(data == null); } - + private Table createInfoTable() { float infoTableWidth = 0.3f * WizardGame.WIDTH - 20; - - playerName = new TextField("", data.skin); - labelSessionName = new Label("", data.skin, "textfield"); - labelSessionConfiguration = new Label("", data.skin, "textfield"); - labelSessionPlayerCount = new Label("", data.skin, "textfield"); - + + playerName = new TextField("", game.data.skin); + labelSessionName = new Label("", game.data.skin, "textfield"); + labelSessionConfiguration = new Label("", game.data.skin, "textfield"); + labelSessionPlayerCount = new Label("", game.data.skin, "textfield"); + labelSessionName.setEllipsis(true); labelSessionConfiguration.setEllipsis(true); labelSessionPlayerCount.setEllipsis(true); - + var infoTable = new Table().center().left(); infoTable.columnDefaults(0).growX().width(infoTableWidth); infoTable.setSize(infoTableWidth, 400); - - infoTable.add(new Label(game.messages.get("menu.lobby.player_name.label"), data.skin)).row(); + + infoTable.add(new Label(game.messages.get("menu.lobby.player_name.label"), game.data.skin)).row(); infoTable.add(playerName).row(); - infoTable.add(new Label(game.messages.get("menu.lobby.session_name.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.lobby.session_name.label"), game.data.skin)).row(); infoTable.add(labelSessionName).row(); - infoTable.add(new Label(game.messages.get("menu.lobby.session_configuration.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.lobby.session_configuration.label"), game.data.skin)).row(); infoTable.add(labelSessionConfiguration).row(); - infoTable.add(new Label(game.messages.get("menu.lobby.session_player_count.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.lobby.session_player_count.label"), game.data.skin)).row(); infoTable.add(labelSessionPlayerCount).row(); - + return infoTable; } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MainMenuScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MainMenuScreen.java index 31df2ec..c4994dc 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MainMenuScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MainMenuScreen.java @@ -5,6 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import eu.jonahbauer.wizard.client.libgdx.WizardGame; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; public class MainMenuScreen extends MenuScreen { @@ -15,7 +16,7 @@ public class MainMenuScreen extends MenuScreen { @Override public void changed(ChangeEvent event, Actor actor) { if (actor == buttonPlay) { - game.setScreen(new ConnectScreen(game, data)); + game.setScreen(new ConnectScreen(game)); sfxClick(); } else if (actor == buttonQuit) { sfxClick(); @@ -29,22 +30,18 @@ public class MainMenuScreen extends MenuScreen { super(game); } - public MainMenuScreen(WizardGame game, Data data) { - super(game, data); - } - @Override public void show() { super.show(); - buttonPlay = new TextButton(game.messages.get("menu.main.play"), data.skin); + buttonPlay = new TextButton(game.messages.get("menu.main.play"), game.data.skin); buttonPlay.setPosition((WizardGame.WIDTH - buttonPlay.getWidth()) / 2f, 192 + 504 - 120f - 125f); - buttonQuit = new TextButton(game.messages.get("menu.main.quit"), data.skin); + buttonQuit = new TextButton(game.messages.get("menu.main.quit"), game.data.skin); buttonQuit.setPosition((WizardGame.WIDTH - buttonQuit.getWidth()) / 2f, 192 + 120f); - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(buttonPlay); - data.stage.addActor(buttonQuit); + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(buttonPlay); + game.data.stage.addActor(buttonQuit); buttonPlay.addListener(listener); buttonQuit.addListener(listener); @@ -55,9 +52,9 @@ public class MainMenuScreen extends MenuScreen { super.renderForeground(delta); int width = 160, height = 224; int left = 384, right = 384, top = 384, bottom = 192; - this.game.batch.draw(data.symbols[0], left, bottom, width, height); - this.game.batch.draw(data.symbols[1], left, WizardGame.HEIGHT - top - height, width, height); - this.game.batch.draw(data.symbols[2], WizardGame.WIDTH - right - width, bottom, width, height); - this.game.batch.draw(data.symbols[3], WizardGame.WIDTH - right - width, WizardGame.HEIGHT - top - height, width, height); + this.game.batch.draw(game.data.symbols[0], left, bottom, width, height); + this.game.batch.draw(game.data.symbols[1], left, WizardGame.HEIGHT - top - height, width, height); + this.game.batch.draw(game.data.symbols[2], WizardGame.WIDTH - right - width, bottom, width, height); + this.game.batch.draw(game.data.symbols[3], WizardGame.WIDTH - right - width, WizardGame.HEIGHT - top - height, width, height); } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MenuScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MenuScreen.java index 4460d28..571f438 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MenuScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/MenuScreen.java @@ -2,18 +2,7 @@ package eu.jonahbauer.wizard.client.libgdx.screens; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; -import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.BitmapFont; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.Skin; -import com.badlogic.gdx.utils.viewport.ExtendViewport; -import com.badlogic.gdx.utils.viewport.FitViewport; -import eu.jonahbauer.wizard.client.libgdx.MenuAtlas; -import eu.jonahbauer.wizard.client.libgdx.UiskinAtlas; import eu.jonahbauer.wizard.client.libgdx.WizardGame; public abstract class MenuScreen implements Screen { @@ -21,85 +10,19 @@ public abstract class MenuScreen implements Screen { protected WizardGame game; - // shared data between all menu screens - public static class Data { - public final ExtendViewport extendViewport; - public final FitViewport fitViewport; - - public final Sound buttonClickSound; - - public final TextureAtlas uiskinAtlas; - public final TextureAtlas menuAtlas; - - public final TextureRegion title; - public final TextureRegion background; - public final TextureRegion[] corners = new TextureRegion[4]; - public final TextureRegion[] symbols = new TextureRegion[4]; - - public final Skin skin; - public final Stage stage; - - public Data() { - this.extendViewport = new ExtendViewport(WizardGame.WIDTH, WizardGame.HEIGHT); - this.fitViewport = new FitViewport(WizardGame.WIDTH, WizardGame.HEIGHT); - - this.buttonClickSound = Gdx.audio.newSound(Gdx.files.internal("button_click_s.mp3")); - - this.uiskinAtlas = new TextureAtlas(Gdx.files.internal(UiskinAtlas.$PATH)); - this.menuAtlas = new TextureAtlas(Gdx.files.internal(MenuAtlas.$PATH)); - - this.title = menuAtlas.findRegion(MenuAtlas.TITLE); - this.background = menuAtlas.findRegion(MenuAtlas.BACKGROUND); - this.corners[0] = menuAtlas.findRegion(MenuAtlas.ECKE_LO); - this.corners[1] = menuAtlas.findRegion(MenuAtlas.ECKE_LU); - this.corners[2] = menuAtlas.findRegion(MenuAtlas.ECKE_RU); - this.corners[3] = menuAtlas.findRegion(MenuAtlas.ECKE_RO); - this.symbols[0] = menuAtlas.findRegion(MenuAtlas.SYMBOL0); - this.symbols[1] = menuAtlas.findRegion(MenuAtlas.SYMBOL1); - this.symbols[2] = menuAtlas.findRegion(MenuAtlas.SYMBOL2); - this.symbols[3] = menuAtlas.findRegion(MenuAtlas.SYMBOL3); - - this.skin = new Skin(Gdx.files.internal("uiskin.json"), uiskinAtlas); - this.skin.getAll(BitmapFont.class).forEach(entry -> - entry.value.getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear) - ); - this.stage = new Stage(fitViewport); - } - - public void reset() { - stage.clear(); - } - - public void dispose() { - buttonClickSound.dispose(); - uiskinAtlas.dispose(); - menuAtlas.dispose(); - skin.dispose(); - stage.dispose(); - } - } - protected Data data; + // shared game.data between all menu screens protected boolean dispose; public MenuScreen(WizardGame game) { this.game = game; } - protected MenuScreen(WizardGame game, Data data) { - this.game = game; - this.data = data; - } - @Override public void show() { - if (data == null) { - data = new Data(); + if (game.data == null) { + game.data = new WizardGame.Data(); } else { - data.reset(); - } - - if (WizardGame.DEBUG) { - data.stage.setDebugAll(true); + game.data.reset(); } } @@ -108,42 +31,42 @@ public abstract class MenuScreen implements Screen { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT | (Gdx.graphics.getBufferFormat().coverageSampling?GL20.GL_COVERAGE_BUFFER_BIT_NV:0)); // Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - data.extendViewport.apply(true); - game.batch.setProjectionMatrix(data.extendViewport.getCamera().combined); + game.data.extendViewport.apply(true); + game.batch.setProjectionMatrix(game.data.extendViewport.getCamera().combined); game.batch.begin(); renderBackground(delta); game.batch.end(); - data.fitViewport.apply(); - game.batch.setProjectionMatrix(data.fitViewport.getCamera().combined); + game.data.fitViewport.apply(); + game.batch.setProjectionMatrix(game.data.fitViewport.getCamera().combined); game.batch.begin(); renderForeground(delta); game.batch.end(); - data.stage.act(delta); - data.stage.draw(); + game.data.stage.act(delta); + game.data.stage.draw(); } protected void renderBackground(float delta) { float scale = Math.max( - data.extendViewport.getWorldWidth() / WizardGame.WIDTH, - data.extendViewport.getWorldHeight() / WizardGame.HEIGHT + game.data.extendViewport.getWorldWidth() / WizardGame.WIDTH, + game.data.extendViewport.getWorldHeight() / WizardGame.HEIGHT ); - game.batch.draw(data.background, 0, 0, scale * WizardGame.WIDTH, scale * WizardGame.HEIGHT); - game.batch.draw(data.corners[0], 0, data.extendViewport.getWorldHeight() - data.corners[0].getRegionHeight()); - game.batch.draw(data.corners[1], 0, 0); - game.batch.draw(data.corners[2], data.extendViewport.getWorldWidth() - data.corners[2].getRegionWidth(), 0); - game.batch.draw(data.corners[3], data.extendViewport.getWorldWidth() - data.corners[3].getRegionWidth(), data.extendViewport.getWorldHeight() - data.corners[3].getRegionHeight()); + game.batch.draw(game.data.background, 0, 0, scale * WizardGame.WIDTH, scale * WizardGame.HEIGHT); + game.batch.draw(game.data.corners[0], 0, game.data.extendViewport.getWorldHeight() - game.data.corners[0].getRegionHeight()); + game.batch.draw(game.data.corners[1], 0, 0); + game.batch.draw(game.data.corners[2], game.data.extendViewport.getWorldWidth() - game.data.corners[2].getRegionWidth(), 0); + game.batch.draw(game.data.corners[3], game.data.extendViewport.getWorldWidth() - game.data.corners[3].getRegionWidth(), game.data.extendViewport.getWorldHeight() - game.data.corners[3].getRegionHeight()); } protected void renderForeground(float delta) { - game.batch.draw(data.title, 555, WizardGame.HEIGHT - 192 - 96, 810, 192); + game.batch.draw(game.data.title, 555, WizardGame.HEIGHT - 192 - 96, 810, 192); } @Override public final void resize(int width, int height) { - data.extendViewport.update(width, height); - data.fitViewport.update(width, height); + game.data.extendViewport.update(width, height); + game.data.fitViewport.update(width, height); } @Override @@ -164,11 +87,11 @@ public abstract class MenuScreen implements Screen { @Override public void dispose() { if (dispose) { - data.dispose(); + game.data.dispose(); } } protected void sfxClick() { - data.buttonClickSound.play(0.6f); + game.data.buttonClickSound.play(0.6f); } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/WaitingScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/WaitingScreen.java index 69f15cd..4ce30a9 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/WaitingScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/WaitingScreen.java @@ -1,122 +1,173 @@ package eu.jonahbauer.wizard.client.libgdx.screens; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.*; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import eu.jonahbauer.wizard.client.libgdx.WizardGame; import eu.jonahbauer.wizard.client.libgdx.actors.AutoFocusScrollPane; +import eu.jonahbauer.wizard.client.libgdx.state.AwaitingJoinLobby; +import eu.jonahbauer.wizard.client.libgdx.state.Session; +import eu.jonahbauer.wizard.common.messages.client.LeaveSessionMessage; +import eu.jonahbauer.wizard.common.messages.client.ReadyMessage; import eu.jonahbauer.wizard.common.messages.data.PlayerData; import eu.jonahbauer.wizard.common.messages.data.SessionData; -import eu.jonahbauer.wizard.common.model.Configuration; import java.util.UUID; public class WaitingScreen extends MenuScreen { - + private TextButton buttonLeave; private TextButton buttonReady; - - private SessionData session; - private UUID myUUID; - private String myName; - private boolean myReady; + + private Label labelSessionName; + private Label labelSessionUUID; + private Label labelSessionConfiguration; + private Label labelPlayerName; + private List players; - - { - // sample data - session = new SessionData(UUID.randomUUID(), "Session X", -1, Configuration.DEFAULT); - myUUID = UUID.randomUUID(); - myName = "Max Mustermann"; - } - + + private AutoFocusScrollPane listContainer; + private final ChangeListener listener = new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { if (actor == buttonLeave) { - game.setScreen(new LobbyScreen(game, data)); + game.getClient().transition(new AwaitingJoinLobby()); + game.getClient().send(new LeaveSessionMessage()); sfxClick(); } else if (actor == buttonReady) { - ready(!myReady); + var state = (Session) game.getClient().getState(); + state.setNextReady(!state.isReady()); + game.getClient().send(new ReadyMessage(!state.isReady())); + buttonReady.setDisabled(true); sfxClick(); } } }; - public WaitingScreen(WizardGame game, Data data) { - super(game, data); + public WaitingScreen(WizardGame game) { + super(game); } @Override public void show() { super.show(); - buttonLeave = new TextButton(game.messages.get("menu.waiting.leave"), data.skin); + buttonLeave = new TextButton(game.messages.get("menu.waiting.leave"), game.data.skin); buttonLeave.setPosition(WizardGame.WIDTH * 0.275f, BUTTON_BAR_Y); - buttonReady = new TextButton(game.messages.get("menu.waiting.ready"), data.skin); + buttonReady = new TextButton(game.messages.get("menu.waiting.ready"), game.data.skin); buttonReady.setPosition(WizardGame.WIDTH * 0.725f - buttonReady.getWidth(), BUTTON_BAR_Y); - players = new List<>(data.skin) { + players = new List<>(game.data.skin) { @Override public String toString(PlayerData player) { return player.getName(); } }; - var listContainer = new AutoFocusScrollPane(players, data.skin); + listContainer = new AutoFocusScrollPane(players, game.data.skin); + listContainer.layout(); var content = new HorizontalGroup().grow().space(20); content.setPosition(0.25f * WizardGame.WIDTH, 0.3f * WizardGame.HEIGHT); content.setSize(0.5f * WizardGame.WIDTH, 400); content.addActor(new Container<>(listContainer).width(0.2f * WizardGame.WIDTH).height(400)); content.addActor(createInfoTable()); + content.layout(); - Gdx.input.setInputProcessor(data.stage); - data.stage.addActor(buttonLeave); - data.stage.addActor(buttonReady); - data.stage.addActor(content); + Gdx.input.setInputProcessor(game.data.stage); + game.data.stage.addActor(buttonLeave); + game.data.stage.addActor(buttonReady); + game.data.stage.addActor(content); buttonLeave.addListener(listener); buttonReady.addListener(listener); - - // sample data - for (int i = 1; i <= 4; i++) { - players.getItems().add(new PlayerData(UUID.randomUUID(), "Player " + i, false)); - } - players.invalidateHierarchy(); } - private void ready(boolean ready) { - this.myReady = ready; + public void setReady(boolean ready) { + buttonReady.setDisabled(false); buttonReady.setText(game.messages.get(ready ? "menu.waiting.not_ready" : "menu.waiting.ready")); } - + + public void addPlayer(PlayerData player) { + this.players.getItems().add(player); + var items = this.players.getItems(); + for (int i = 0; i < items.size; i++) { + if (items.get(i).getUuid().equals(player.getUuid())) { + items.set(i, player); + break; + } + } + this.players.invalidateHierarchy(); + } + + public void removePlayer(UUID player) { + var items = this.players.getItems(); + for (int i = 0; i < items.size; i++) { + if (items.get(i).getUuid().equals(player)) { + items.removeIndex(i); + break; + } + } + this.players.invalidateHierarchy(); + } + + public void modifyPlayer(PlayerData data) { + var items = this.players.getItems(); + for (int i = 0; i < items.size; i++) { + if (items.get(i).getUuid().equals(data.getUuid())) { + items.set(i, data); + break; + } + } + this.players.invalidateHierarchy(); + } + + public void setPlayers(PlayerData... players) { + var items = this.players.getItems(); + items.clear(); + items.addAll(players); + this.players.invalidateHierarchy(); + } + + public void setSession(SessionData session) { + this.labelSessionName.setText(session.getName()); + this.labelSessionUUID.setText(session.getUuid().toString()); + this.labelSessionConfiguration.setText(session.getConfiguration().toString()); + } + + public void setPlayerName(String name) { + this.labelPlayerName.setText(name); + } + private Table createInfoTable() { float infoTableWidth = 0.3f * WizardGame.WIDTH - 20; - - var labelSessionName = new Label(session.getName(), data.skin, "textfield"); - var labelSessionUUID = new Label(session.getUuid().toString(), data.skin, "textfield"); - var labelSessionConfiguration = new Label(session.getConfiguration().toString(), data.skin, "textfield"); - var labelPlayerName = new Label(myName, data.skin, "textfield"); - + + labelSessionName = new Label("", game.data.skin, "textfield"); + labelSessionUUID = new Label("", game.data.skin, "textfield"); + labelSessionConfiguration = new Label("", game.data.skin, "textfield"); + labelPlayerName = new Label("", game.data.skin, "textfield"); + labelSessionName.setEllipsis(true); labelSessionUUID.setEllipsis(true); labelSessionConfiguration.setEllipsis(true); labelPlayerName.setEllipsis(true); - + var infoTable = new Table().center().left(); infoTable.columnDefaults(0).growX().width(infoTableWidth); infoTable.setSize(infoTableWidth, 400); - - infoTable.add(new Label(game.messages.get("menu.waiting.session_name.label"), data.skin)).row(); + + infoTable.add(new Label(game.messages.get("menu.waiting.session_name.label"), game.data.skin)).row(); infoTable.add(labelSessionName).row(); - infoTable.add(new Label(game.messages.get("menu.waiting.session_uuid.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.waiting.session_uuid.label"), game.data.skin)).row(); infoTable.add(labelSessionUUID).row(); - infoTable.add(new Label(game.messages.get("menu.waiting.session_configuration.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.waiting.session_configuration.label"), game.data.skin)).row(); infoTable.add(labelSessionConfiguration).row(); - infoTable.add(new Label(game.messages.get("menu.waiting.player_name.label"), data.skin)).row(); + infoTable.add(new Label(game.messages.get("menu.waiting.player_name.label"), game.data.skin)).row(); infoTable.add(labelPlayerName).row(); - + return infoTable; } } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java new file mode 100644 index 0000000..e026357 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java @@ -0,0 +1,28 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import lombok.SneakyThrows; + +import java.util.Optional; + +public abstract class Awaiting extends BaseState implements ClientState { + @Override + public Optional onMessage(Client client, ServerMessage message) { + return unexpectedMessage(client, message); + } + + @Override + @SneakyThrows + public Optional onEnter(Client client) { + client.timeout(this, 10_000); + return Optional.empty(); + } + + @Override + public Optional onTimeout(Client client) { + System.out.println("Timed out. Returning to menu"); + return Optional.of(new Menu()); + } + +} \ No newline at end of file diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java new file mode 100644 index 0000000..b4394f2 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java @@ -0,0 +1,29 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.LoadingScreen; +import eu.jonahbauer.wizard.client.libgdx.screens.LobbyScreen; + +import java.util.Optional; + +public class AwaitingConnection extends Awaiting { + + @Override + public Optional onEnter(Client client) { + System.out.println("Awaiting connection..."); + client.getGame().setScreen(new LoadingScreen(client.getGame())); + return super.onEnter(client); + } + + @Override + public Optional onOpen(Client client) { + System.out.println("Connection established."); + return Optional.of(new AwaitingJoinLobby()); + } + + @Override + public Optional onClose(Client client, int code, String reason, boolean remote) { + System.out.println("Connection could not be established. (code=%d, reason=%s)" + code + reason); + return Optional.of(new Menu()); + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinLobby.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinLobby.java new file mode 100644 index 0000000..7f768b5 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinLobby.java @@ -0,0 +1,27 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.LoadingScreen; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import eu.jonahbauer.wizard.common.messages.server.SessionListMessage; + +import java.util.Optional; + +public final class AwaitingJoinLobby extends Awaiting { + + @Override + public Optional onEnter(Client client) { + System.out.println("Waiting for session list..."); + client.getGame().setScreen(new LoadingScreen(client.getGame())); + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + if (message instanceof SessionListMessage list) { + return Optional.of(new Lobby(list)); + } else { + return super.onMessage(client, message); + } + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java new file mode 100644 index 0000000..2799268 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingJoinSession.java @@ -0,0 +1,46 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.LoadingScreen; +import eu.jonahbauer.wizard.common.messages.data.SessionData; +import eu.jonahbauer.wizard.common.messages.server.*; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; + +@Getter +@RequiredArgsConstructor +public final class AwaitingJoinSession extends Awaiting { + + private final SessionData session; + private final String playerName; + + @Override + public Optional onEnter(Client client) { + System.out.println("Waiting for acknowledgment..."); + client.getGame().setScreen(new LoadingScreen(client.getGame())); + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + if (message instanceof SessionJoinedMessage joined) { + return Optional.of(new Session(joined, session, playerName)); + } else if (message instanceof NackMessage nack) { + switch (nack.getCode()) { + case NackMessage.GAME_ALREADY_STARTED -> System.out.println("Error: Game has already started."); + case NackMessage.SESSION_FULL -> System.out.println("Error: The session is full."); + case NackMessage.SESSION_NOT_FOUND -> System.out.println("Error: Session not found."); + case NackMessage.NAME_TAKEN -> System.out.println("Error: Name already taken."); + default -> { return super.onMessage(client, message); } + } + return Optional.of(new AwaitingJoinLobby()); + } else if (message instanceof SessionModifiedMessage || message instanceof SessionRemovedMessage) { + // drop + return Optional.empty(); + } else { + return super.onMessage(client, message); + } + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/BaseState.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/BaseState.java new file mode 100644 index 0000000..45f37f9 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/BaseState.java @@ -0,0 +1,35 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; + +import java.util.Optional; + +public abstract class BaseState implements ClientState { + + @Override + public Optional onEnter(Client context) { + return ClientState.super.onEnter(context); + } + + @Override + public Optional onOpen(Client client) { + throw new IllegalStateException(); + } + + @Override + public Optional onClose(Client client, int code, String reason, boolean remote) { + if (remote) { + System.out.println("Lost connection " + code + " " + reason); + } else { + System.out.println("Connection closed " + code + " " + reason); + } + return Optional.of(new Menu()); + } + + protected static Optional unexpectedMessage(Client client, ServerMessage message) { + // return to menu on unexpected message + System.out.println("Fatal: Unexpected message " + message + ". Returning to menu."); + return Optional.of(new Menu()); + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/ClientState.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/ClientState.java new file mode 100644 index 0000000..de619a4 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/ClientState.java @@ -0,0 +1,16 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.common.machine.TimeoutState; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; + +import java.util.Optional; + +public interface ClientState extends TimeoutState { + Optional onOpen(Client client); + + Optional onMessage(Client client, ServerMessage message); + + Optional onClose(Client client, int code, String reason, boolean remote); + +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Creation.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Creation.java new file mode 100644 index 0000000..bee76f3 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Creation.java @@ -0,0 +1,34 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.CreateGameScreen; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import eu.jonahbauer.wizard.common.messages.server.SessionCreatedMessage; + +import java.util.Optional; + +public final class Creation extends BaseState { + + private CreateGameScreen createScreen; + + public Creation() { + } + + @Override + public Optional onEnter(Client client) { + createScreen = new CreateGameScreen(client.getGame()); + client.getGame().setScreen(createScreen); + + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + if (message instanceof SessionCreatedMessage created) { + + return Optional.empty(); + } else { + return unexpectedMessage(client, message); + } + } +} \ No newline at end of file diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Lobby.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Lobby.java new file mode 100644 index 0000000..bd867dc --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Lobby.java @@ -0,0 +1,54 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import com.badlogic.gdx.utils.reflect.ClassReflection; +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.CreateGameScreen; +import eu.jonahbauer.wizard.client.libgdx.screens.LobbyScreen; +import eu.jonahbauer.wizard.common.messages.data.SessionData; +import eu.jonahbauer.wizard.common.messages.server.*; + +import java.util.Optional; + +public final class Lobby extends BaseState { + + private SessionListMessage list; + private LobbyScreen lobbyScreen; + private CreateGameScreen createScreen; + + public Lobby(SessionListMessage list) { + this.list = list; + } + + @Override + public Optional onEnter(Client client) { + lobbyScreen = new LobbyScreen(client.getGame()); + client.getGame().setScreen(lobbyScreen); + lobbyScreen.setSessions(list.getSessions().toArray(new SessionData[0])); + + list = null; + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + if (message instanceof SessionCreatedMessage created) { + lobbyScreen.addSession(created.getSession()); + return Optional.empty(); + } else if (message instanceof SessionRemovedMessage removed) { + lobbyScreen.removeSession(removed.getSession()); + return Optional.empty(); + } else if (message instanceof SessionModifiedMessage modified) { + lobbyScreen.modifySession(modified.getSession()); + return Optional.empty(); + } else if (message instanceof SessionListMessage list) { + lobbyScreen.setSessions(list.getSessions().toArray(new SessionData[0])); + return Optional.empty(); + } else if (message instanceof SessionJoinedMessage joined) { + //TODO find solution + createScreen = new CreateGameScreen(client.getGame()); + return Optional.empty(); + } else { + return unexpectedMessage(client, message); + } + } +} \ No newline at end of file diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Menu.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Menu.java new file mode 100644 index 0000000..cc526b3 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Menu.java @@ -0,0 +1,35 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.MainMenuScreen; +import eu.jonahbauer.wizard.common.messages.server.ServerMessage; +import lombok.SneakyThrows; +import org.java_websocket.framing.CloseFrame; + +import java.util.Optional; + +public final class Menu extends BaseState { + + @Override + @SneakyThrows + public Optional onEnter(Client client) { + if (client.getSocket() != null && client.getSocket().isOpen()) { + client.getSocket().close(CloseFrame.GOING_AWAY); + } + client.getGame().setScreen(new MainMenuScreen(client.getGame())); + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + // it is possible that there are messages still queued after + // returning to the menu as a result of a previous message + return Optional.empty(); + } + + @Override + public Optional onClose(Client client, int code, String reason, boolean remote) { + super.onClose(client, code, reason, remote); + return Optional.empty(); + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Session.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Session.java new file mode 100644 index 0000000..24ee8a8 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Session.java @@ -0,0 +1,84 @@ +package eu.jonahbauer.wizard.client.libgdx.state; + +import eu.jonahbauer.wizard.client.libgdx.Client; +import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; +import eu.jonahbauer.wizard.client.libgdx.screens.WaitingScreen; +import eu.jonahbauer.wizard.common.messages.data.PlayerData; +import eu.jonahbauer.wizard.common.messages.data.SessionData; +import eu.jonahbauer.wizard.common.messages.server.*; +import eu.jonahbauer.wizard.common.model.Configuration; +import lombok.Getter; +import lombok.Setter; + +import java.util.Optional; +import java.util.UUID; + +@Getter +public final class Session extends BaseState { + + private SessionJoinedMessage joined; + private WaitingScreen sessionScreen; + + private final UUID self; + private final String secret; + + private final SessionData session; + private final String playerName; + + private boolean ready; + @Setter + private Boolean nextReady; + + public Session(SessionJoinedMessage joined, SessionData session, String playerName) { + if (!joined.getSession().equals(session.getUuid())) throw new RuntimeException(); + + this.self = joined.getPlayer(); + this.secret = joined.getSecret(); + this.session = session; + this.joined = joined; + this.playerName = playerName; + } + + @Override + public Optional onEnter(Client client) { + sessionScreen = new WaitingScreen(client.getGame()); + client.getGame().setScreen(sessionScreen); + sessionScreen.setPlayers(joined.getPlayers().toArray(new PlayerData[0])); + sessionScreen.setReady(false); + sessionScreen.setPlayerName(playerName); + sessionScreen.setSession(session); + + joined = null; + return super.onEnter(client); + } + + @Override + public Optional onMessage(Client client, ServerMessage message) { + if (message instanceof PlayerJoinedMessage join) { + sessionScreen.addPlayer(join.getPlayer()); + return Optional.empty(); + } else if (message instanceof PlayerLeftMessage leave) { + sessionScreen.removePlayer(leave.getPlayer()); + return Optional.empty(); + } else if (message instanceof PlayerModifiedMessage modified) { + sessionScreen.modifyPlayer(modified.getPlayer()); + return Optional.empty(); + } else if (message instanceof StartingGameMessage) { + client.getGame().setScreen(new GameScreen(client.getGame())); + return Optional.empty(); + } else if (nextReady != null && message instanceof NackMessage nack) { + // TODO display error + System.out.println("Error: " + nack.getMessage()); + sessionScreen.setReady(!nextReady); + nextReady = null; + return Optional.empty(); + } else if (nextReady != null && message instanceof AckMessage) { + sessionScreen.setReady(nextReady); + ready = nextReady; + nextReady = null; + return Optional.empty(); + } else { + return unexpectedMessage(client, message); + } + } +} diff --git a/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages.properties b/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages.properties index 795e4d4..c9adbcf 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages.properties +++ b/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages.properties @@ -4,6 +4,7 @@ menu.main.quit=Close menu.connect.connect=Connect menu.connect.back=Back menu.connect.address.label=Enter Server Address +menu.connect.uri.hint=Server Address menu.lobby.join=Join menu.lobby.create=Create @@ -13,6 +14,11 @@ menu.lobby.session_name.label=Session Name menu.lobby.session_player_count.label=Current Player Count menu.lobby.session_configuration.label=Configuration +menu.lobby.create_session.timeout.label=Timeout + +menu.loading.loading=Loading... +menu.loading.back=Return To Main Menu + menu.waiting.ready=Ready menu.waiting.not_ready=Not Ready menu.waiting.leave=Leave diff --git a/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages_de.properties b/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages_de.properties index b5a9175..4f6ad19 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages_de.properties +++ b/wizard-client/wizard-client-libgdx/core/src/main/resources/i18n/messages_de.properties @@ -4,6 +4,7 @@ menu.main.quit=Verlassen menu.connect.connect=Verbinden menu.connect.back=Zurück menu.connect.address.label=Server-Adresse eingeben +menu.connect.uri.hint=Server Address menu.lobby.join=Beitreten menu.lobby.create=Erstellen @@ -13,6 +14,11 @@ menu.lobby.session_name.label=Session Name menu.lobby.session_player_count.label=Spieleranzahl menu.lobby.session_configuration.label=Spielvariante +menu.lobby.create_session.timeout.label=Timeout + +menu.loading.loading=Laden... +menu.loading.back=Zurück zum Hauptmenü + menu.waiting.ready=Bereit menu.waiting.not_ready=Nicht Bereit menu.waiting.leave=Verlassen