rejoin support for libgdx client

main
Jonah Bauer 3 years ago
parent e37efcc5b4
commit a04ff1f2cb

@ -85,7 +85,6 @@ public class TrumpOverlay extends Overlay {
animateSuit = suit != null && suit != CardUtil.getDefaultTrumpSuit(card); animateSuit = suit != null && suit != CardUtil.getDefaultTrumpSuit(card);
if (animateSuit) { if (animateSuit) {
trumpSuitActor.setRotation(0); trumpSuitActor.setRotation(0);
trumpSuitActor.setOrigin(0, 0);
cardGroup.addActor(trumpSuitActor); cardGroup.addActor(trumpSuitActor);
trumpSuitActor.setCard(suit); trumpSuitActor.setCard(suit);
} else { } else {

@ -1,9 +1,11 @@
package eu.jonahbauer.wizard.client.libgdx.actors; package eu.jonahbauer.wizard.client.libgdx.actors;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.scenes.scene2d.*; import com.badlogic.gdx.scenes.scene2d.*;
import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings; import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings;
import eu.jonahbauer.wizard.client.libgdx.WizardGame; import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
import eu.jonahbauer.wizard.common.model.Card;
import lombok.Data; import lombok.Data;
import java.util.*; import java.util.*;
@ -52,12 +54,33 @@ public class CardStack extends Group {
(float) random.nextGaussian(0, COLLAPSED_ROTATION_DEVIATION), (float) random.nextGaussian(0, COLLAPSED_ROTATION_DEVIATION),
(float) random.nextGaussian(0, EXPANDED_ROTATION_DEVIATION) (float) random.nextGaussian(0, EXPANDED_ROTATION_DEVIATION)
); );
addActor(card); super.addActor(card);
if (expanded) entry.expand(); if (expanded) entry.expand();
else entry.collapse(); else entry.collapse();
cards.add(entry); cards.add(entry);
} }
public void add(GameScreen.Seat seat, Card card, TextureAtlas atlas) {
var actor = new CardActor(card, atlas);
var x = (float) random.nextGaussian((WizardGame.WIDTH - actor.getWidth()) / 2, COLLAPSED_POSITION_DEVIATION);
var y = (float) random.nextGaussian((WizardGame.HEIGHT - actor.getHeight()) / 2, COLLAPSED_POSITION_DEVIATION);
var collapsedRotation = (float) random.nextGaussian(0, COLLAPSED_ROTATION_DEVIATION);
var expandedRotation = (float) random.nextGaussian(0, EXPANDED_ROTATION_DEVIATION);
if (expanded) {
actor.setPosition(seat.getFrontX(), seat.getFrontY());
actor.setRotation(expandedRotation);
} else {
actor.setPosition(x, y);
actor.setRotation(collapsedRotation);
}
var entry = new Entry(actor, seat, x, y, collapsedRotation, expandedRotation);
super.addActor(actor);
cards.add(entry);
}
@Override @Override
protected void childrenChanged() { protected void childrenChanged() {
hover.toFront(); hover.toFront();

@ -109,4 +109,18 @@ public class PadOfTruth extends Table {
if (round < 0 || round >= predictions.length || round >= scores.length) throw new ArrayIndexOutOfBoundsException(round); if (round < 0 || round >= predictions.length || round >= scores.length) throw new ArrayIndexOutOfBoundsException(round);
if (player < 0 || player >= predictions[round].length || player >= scores[round].length) throw new ArrayIndexOutOfBoundsException(player); if (player < 0 || player >= predictions[round].length || player >= scores[round].length) throw new ArrayIndexOutOfBoundsException(player);
} }
public void clearValues() {
for (var row : predictions) {
for (var label : row) {
label.setText(null);
}
}
for (var row : scores) {
for (var label : row) {
label.setText(null);
}
}
}
} }

@ -22,6 +22,8 @@ import eu.jonahbauer.wizard.client.libgdx.actors.CardsGroup;
import eu.jonahbauer.wizard.client.libgdx.actors.PadOfTruth; import eu.jonahbauer.wizard.client.libgdx.actors.PadOfTruth;
import eu.jonahbauer.wizard.client.libgdx.state.Game; import eu.jonahbauer.wizard.client.libgdx.state.Game;
import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings; import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings;
import eu.jonahbauer.wizard.client.libgdx.util.CardUtil;
import eu.jonahbauer.wizard.client.libgdx.util.Pair;
import eu.jonahbauer.wizard.client.libgdx.util.WizardAssetManager; import eu.jonahbauer.wizard.client.libgdx.util.WizardAssetManager;
import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage; import eu.jonahbauer.wizard.common.messages.observer.UserInputMessage;
import eu.jonahbauer.wizard.common.model.Card; import eu.jonahbauer.wizard.common.model.Card;
@ -626,6 +628,86 @@ public class GameScreen extends WizardScreen {
})); }));
execute(sequence); execute(sequence);
} }
public void setTrump(@Nullable Card card, @Nullable Card.Suit suit) {
initTrumpCards();
if (suit != null && suit != CardUtil.getDefaultTrumpSuit(card)) {
trumpSuitActor.setPosition(TRUMP_SUIT_POSITION.x, TRUMP_SUIT_POSITION.y);
trumpSuitActor.setRotation(TRUMP_SUIT_ROTATION);
trumpSuitActor.setCard(suit);
contentRoot.addActor(trumpSuitActor);
} else {
trumpSuitActor.remove();
}
if (card != null) {
trumpCardActor.setPosition(TRUMP_CARD_POSITION.x, TRUMP_CARD_POSITION.y);
trumpCardActor.setCard(card);
contentRoot.addActor(trumpCardActor);
} else {
trumpCardActor.remove();
}
}
public void setStack(@NotNull List<Pair<UUID, Card>> stack) {
cardStack.clearChildren();
for (var pair : stack) {
cardStack.add(seats.getOrDefault(pair.first(), Seat.FALLBACK), pair.second(), atlas);
}
}
public void setPredictions(@NotNull Map<Integer, Map<UUID, Integer>> predictions) {
predictions.forEach((round, roundPredictions) -> {
roundPredictions.forEach((player, prediction) -> {
var index = orderedPlayers.indexOf(player);
if (index == -1) throw new NoSuchElementException();
padOfTruth.setPrediction(index, round, prediction);
});
});
}
public void setScores(@NotNull Map<Integer, Map<UUID, Integer>> scores) {
scores.forEach((round, roundScores) -> {
roundScores.forEach((player, score) -> {
var index = orderedPlayers.indexOf(player);
if (index == -1) throw new NoSuchElementException();
padOfTruth.setScore(index, round, score);
});
});
}
public void clearMessages() {
messageStack.clear();
persistentMessage = null;
}
public void clear() {
// stop all actions
pendingActions.clear();
stage.getRoot().removeAction(currentAction);
currentAction = null;
pendingSync.set(false);
// remove ui elements
clearMessages();
dim(LAYER_BELOW_OVERLAY, false);
overlayRoot.clear();
cardStack.clearChildren();
handCards.clearChildren();
if (trumpCardActor != null) {
trumpCardActor.remove();
}
if (trumpSuitActor != null) {
trumpSuitActor.remove();
}
padOfTruth.clearValues();
nameLabels.values().forEach(label -> label.setStyle(labelStyleDefault));
}
//</editor-fold> //</editor-fold>
//<editor-fold desc="Overlays" defaultstate="collapsed"> //<editor-fold desc="Overlays" defaultstate="collapsed">

@ -17,6 +17,7 @@ public class LobbyScreen extends MenuScreen {
private TextButton buttonBack; private TextButton buttonBack;
private TextButton buttonJoin; private TextButton buttonJoin;
private TextButton buttonRejoin;
private TextButton buttonCreate; private TextButton buttonCreate;
private TextField playerName; private TextField playerName;
@ -24,7 +25,7 @@ public class LobbyScreen extends MenuScreen {
private Label labelSessionPlayerCount; private Label labelSessionPlayerCount;
private Label labelSessionConfiguration; private Label labelSessionConfiguration;
private SessionData selectedSession; private UUID selectedSession;
private List<SessionData> sessions; private List<SessionData> sessions;
private ScrollPane sessionListContainer; private ScrollPane sessionListContainer;
@ -40,6 +41,9 @@ public class LobbyScreen extends MenuScreen {
} else if (actor == buttonCreate) { } else if (actor == buttonCreate) {
game.getClient().execute(Lobby.class, Lobby::showCreateScreen); game.getClient().execute(Lobby.class, Lobby::showCreateScreen);
sfxClick(); sfxClick();
} else if (actor == buttonRejoin) {
game.getClient().execute(Lobby.class, Lobby::showRejoinScreen);
sfxClick();
} }
} }
}; };
@ -60,6 +64,10 @@ public class LobbyScreen extends MenuScreen {
buttonCreate.addListener(listener); buttonCreate.addListener(listener);
getButtonGroup().addActor(buttonCreate); getButtonGroup().addActor(buttonCreate);
buttonRejoin = new TextButton(messages.get("menu.lobby.rejoin"), skin);
buttonRejoin.addListener(listener);
getButtonGroup().addActor(buttonRejoin);
buttonJoin = new TextButton(messages.get("menu.lobby.join"), skin); buttonJoin = new TextButton(messages.get("menu.lobby.join"), skin);
buttonJoin.addListener(listener); buttonJoin.addListener(listener);
getButtonGroup().addActor(buttonJoin); getButtonGroup().addActor(buttonJoin);
@ -93,10 +101,13 @@ public class LobbyScreen extends MenuScreen {
content.layout(); content.layout();
stage.addActor(content); stage.addActor(content);
stage.addCaptureListener(new KeyboardFocusManager(sessions, playerName, buttonBack, buttonCreate, buttonJoin)); stage.addCaptureListener(new KeyboardFocusManager(
sessions, playerName, buttonBack, buttonCreate, buttonRejoin, buttonJoin
));
buttonBack.setName("button_back"); buttonBack.setName("button_back");
buttonJoin.setName("button_join"); buttonJoin.setName("button_join");
buttonJoin.setName("button_rejoin");
buttonCreate.setName("button_create"); buttonCreate.setName("button_create");
sessions.setName("session_list"); sessions.setName("session_list");
playerName.setName("player_name"); playerName.setName("player_name");
@ -154,7 +165,7 @@ public class LobbyScreen extends MenuScreen {
this.sessions.invalidateHierarchy(); this.sessions.invalidateHierarchy();
} }
if (selectedSession != null && selectedSession.getUuid().equals(session)) { if (selectedSession != null && selectedSession.equals(session)) {
updateData(null); updateData(null);
} }
} }
@ -164,7 +175,7 @@ public class LobbyScreen extends MenuScreen {
this.sessions.getItems().set(index, session); this.sessions.getItems().set(index, session);
this.sessions.invalidateHierarchy(); this.sessions.invalidateHierarchy();
if (selectedSession != null && selectedSession.getUuid().equals(session.getUuid())) { if (selectedSession != null && selectedSession.equals(session.getUuid())) {
updateData(session); updateData(session);
} }
} }
@ -182,7 +193,7 @@ public class LobbyScreen extends MenuScreen {
labelSessionName.setText(data.getName()); labelSessionName.setText(data.getName());
labelSessionPlayerCount.setText(Integer.toString(data.getPlayerCount())); labelSessionPlayerCount.setText(Integer.toString(data.getPlayerCount()));
labelSessionConfiguration.setText(data.getConfiguration().toString()); labelSessionConfiguration.setText(data.getConfiguration().toString());
selectedSession = data; selectedSession = data.getUuid();
} else { } else {
labelSessionName.setText(""); labelSessionName.setText("");
labelSessionPlayerCount.setText(""); labelSessionPlayerCount.setText("");
@ -209,7 +220,13 @@ public class LobbyScreen extends MenuScreen {
if (!error) { if (!error) {
var client = game.getClient(); var client = game.getClient();
client.execute(Lobby.class, (s, c) -> s.joinSession(client, selectedSession, playerName)); try {
client.execute(Lobby.class, (s, c) -> s.joinSession(c, selectedSession, playerName));
} catch (IllegalArgumentException e) {
// only if session is not known
log.warn(e.getMessage());
this.sessionListContainer.setStyle(getScrollPaneErrorStyle());
}
} }
} }

@ -0,0 +1,150 @@
package eu.jonahbauer.wizard.client.libgdx.screens;
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.listeners.KeyboardFocusManager;
import eu.jonahbauer.wizard.client.libgdx.listeners.ResetErrorListener;
import eu.jonahbauer.wizard.client.libgdx.state.Lobby;
import lombok.extern.log4j.Log4j2;
import java.util.UUID;
@Log4j2
public class RejoinScreen extends MenuScreen {
private TextButton buttonBack;
private TextButton buttonContinue;
private TextField sessionUUID;
private TextField playerUUID;
private TextField secret;
private final ChangeListener listener = new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
if (actor == buttonBack) {
game.getClient().execute(Lobby.class, Lobby::showListScreen);
sfxClick();
} else if (actor == buttonContinue) {
rejoin();
sfxClick();
}
}
};
public RejoinScreen(WizardGame game) {
super(game);
}
@Override
public void show() {
super.show();
var credentials = game.storage.credentials;
buttonBack = new TextButton(messages.get("menu.rejoin.back"), skin);
buttonBack.addListener(listener);
getButtonGroup().addActor(buttonBack);
buttonContinue = new TextButton(messages.get("menu.rejoin.continue"), skin);
buttonContinue.addListener(listener);
getButtonGroup().addActor(buttonContinue);
var errorListener = new ResetErrorListener(skin);
sessionUUID = new TextField(credentials != null ? credentials.session().toString() : null , skin);
sessionUUID.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.5f);
sessionUUID.setSize(0.4f * WizardGame.WIDTH, 64);
sessionUUID.addListener(errorListener);
sessionUUID.setProgrammaticChangeEvents(true);
playerUUID = new TextField(credentials != null ? credentials.player().toString() : null, skin);
playerUUID.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.45f);
playerUUID.setSize(0.4f * WizardGame.WIDTH, 64);
playerUUID.addListener(errorListener);
secret = new TextField(credentials != null ? credentials.secret() : null, skin);
secret.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.4f);
secret.setSize(0.4f * WizardGame.WIDTH, 64);
secret.addListener(errorListener);
var contentTable = new Table(skin).center().left();
contentTable.columnDefaults(0).growX().width(0.4f * WizardGame.WIDTH - 20);
contentTable.setSize(0.4f * WizardGame.WIDTH - 20, 400);
contentTable.setPosition(WizardGame.WIDTH * 0.3f, WizardGame.HEIGHT * 0.3f);
contentTable.add(messages.get("menu.rejoin.session_uuid.label")).row();
contentTable.add(sessionUUID).row();
contentTable.add(messages.get("menu.rejoin.player_uuid.label")).row();
contentTable.add(playerUUID).row();
contentTable.add(messages.get("menu.rejoin.player_secret.label")).row();
contentTable.add(secret).row();
stage.addActor(contentTable);
stage.addCaptureListener(new KeyboardFocusManager(sessionUUID, playerUUID, secret, buttonBack, buttonContinue));
buttonBack.setName("button_back");
buttonContinue.setName("button_continue");
sessionUUID.setName("session_uuid");
playerUUID.setName("player_uuid");
secret.setName("player_secret");
}
private void rejoin() {
boolean error = false;
String sessionUUIDText = this.sessionUUID.getText();
UUID sessionUUID = null;
if (sessionUUIDText.isBlank()) {
log.warn("Please enter the session uuid.");
this.sessionUUID.setStyle(getTextFieldErrorStyle());
error = true;
} else {
try {
sessionUUID = UUID.fromString(sessionUUIDText);
} catch (IllegalArgumentException e) {
log.warn("Please enter a valid session uuid.");
this.sessionUUID.setStyle(getTextFieldErrorStyle());
error = true;
}
}
String playerUUIDText = this.playerUUID.getText();
UUID playerUUID = null;
if (playerUUIDText.isBlank()) {
log.warn("Please enter the player uuid.");
this.playerUUID.setStyle(getTextFieldErrorStyle());
error = true;
} else {
try {
playerUUID = UUID.fromString(playerUUIDText);
} catch (IllegalArgumentException e) {
log.warn("Please enter a valid player uuid.");
this.playerUUID.setStyle(getTextFieldErrorStyle());
error = true;
}
}
String playerSecret = this.secret.getText();
if (playerSecret.isBlank()) {
log.warn("Please enter the player secret.");
this.secret.setStyle(getTextFieldErrorStyle());
error = true;
}
var fPlayerUUID = playerUUID;
var fSessionUUID = sessionUUID;
if (!error) {
var client = game.getClient();
try {
client.execute(Lobby.class, (s, c) -> s.rejoinSession(c, fSessionUUID, fPlayerUUID, playerSecret));
} catch (IllegalArgumentException e) {
// only if session is not known
log.warn(e.getMessage());
this.sessionUUID.setStyle(getTextFieldErrorStyle());
}
}
}
}

@ -0,0 +1,60 @@
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.observer.ObserverMessage;
import eu.jonahbauer.wizard.common.messages.server.AckMessage;
import eu.jonahbauer.wizard.common.messages.server.GameMessage;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.common.messages.server.StartingGameMessage;
import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import java.util.*;
@Log4j2
@RequiredArgsConstructor
public final class AwaitingGameLog extends BaseState {
private static final int TIMEOUT_MILLIS = 10_000;
private final UUID self;
private final UUID session;
private final String sessionName;
private final Configuration configuration;
private final LinkedHashMap<UUID, String> players;
private final List<ObserverMessage> messages = new ArrayList<>();
private boolean started = false;
@Override
public Optional<ClientState> onEnter(Client client) {
log.info("Waiting for game log...");
client.getGame().setScreen(new LoadingScreen(client.getGame(), "menu.loading.rejoining"));
client.timeout(this, TIMEOUT_MILLIS);
return Optional.empty();
}
@Override
public Optional<ClientState> onMessage(Client client, ServerMessage message) {
if (!started) {
if (message instanceof StartingGameMessage) {
started = true;
return Optional.empty();
} else {
return unexpectedMessage(message);
}
} else if (message instanceof GameMessage gameMessage) {
messages.add(gameMessage.getObserverMessage());
return Optional.empty();
} else if (message instanceof AckMessage) {
var game = new Game(self, session, sessionName, configuration, players);
game.init(messages);
return Optional.of(game);
} else {
return unexpectedMessage(message);
}
}
}

@ -9,7 +9,10 @@ import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -18,10 +21,10 @@ import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
public final class AwaitingJoinSession extends Awaiting { public final class AwaitingJoinSession extends Awaiting {
private final UUID session; private final @Nullable UUID session;
private final String sessionName; private final @NotNull String sessionName;
private final Configuration configuration; private final @NotNull Configuration configuration;
private final String playerName; private final @NotNull Source source;
@Override @Override
public Optional<ClientState> onEnter(Client client) { public Optional<ClientState> onEnter(Client client) {
@ -33,25 +36,38 @@ public final class AwaitingJoinSession extends Awaiting {
@Override @Override
public Optional<ClientState> onMessage(Client client, ServerMessage message) { public Optional<ClientState> onMessage(Client client, ServerMessage message) {
if (message instanceof SessionJoinedMessage joined) { if (message instanceof SessionJoinedMessage joined) {
if (session != null && !session.equals(joined.getSession())) { var session = joined.getSession();
if (this.session != null && !this.session.equals(session)) {
return super.onMessage(client, message); return super.onMessage(client, message);
} else { } else {
log.info("There are {} players in this session.", joined.getPlayers().size()); var players = joined.getPlayers();
log.info("Your uuid is {}.", joined.getPlayer()); var player = joined.getPlayer();
log.info("Your secret is {}.", joined.getSecret()); var secret = joined.getSecret();
client.getGame().storage.credentials = new SavedData.SessionCredentials( log.info("There are {} players in this session.", players.size());
joined.getSession(), log.info("Your uuid is {}.", player);
joined.getPlayer(), log.info("Your secret is {}.", secret);
joined.getSecret()
);
client.getGame().storage.credentials = new SavedData.SessionCredentials(session, player, secret);
if (source == Source.REJOIN) {
var playerMap = new LinkedHashMap<UUID, String>();
players.forEach(p -> playerMap.put(p.getUuid(), p.getName()));
return Optional.of(new AwaitingGameLog(
player,
session,
sessionName,
configuration,
playerMap
));
} else {
return Optional.of(new Session( return Optional.of(new Session(
new SessionData(joined.getSession(), sessionName, -1, configuration), new SessionData(session, sessionName, -1, configuration),
joined.getPlayers(), players,
joined.getPlayer() player
)); ));
} }
}
} else if (message instanceof NackMessage nack) { } else if (message instanceof NackMessage nack) {
switch (nack.getCode()) { switch (nack.getCode()) {
case NackMessage.GAME_ALREADY_STARTED -> log.error("Game has already started."); case NackMessage.GAME_ALREADY_STARTED -> log.error("Game has already started.");
@ -72,4 +88,8 @@ public final class AwaitingJoinSession extends Awaiting {
return super.onMessage(client, message); return super.onMessage(client, message);
} }
} }
public enum Source {
JOIN, CREATE, REJOIN
}
} }

@ -17,6 +17,7 @@ import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.model.Configuration; import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -35,17 +36,20 @@ import static eu.jonahbauer.wizard.common.messages.observer.UserInputMessage.Act
@Log4j2 @Log4j2
@Getter @Getter
@RequiredArgsConstructor
public final class Game extends BaseState { public final class Game extends BaseState {
private final UUID self; private final UUID self;
private final UUID session; private final UUID session;
private final String sessionName; private final String sessionName;
private final Configuration configuration; private final Configuration configuration;
private List<ObserverMessage> pendingMessages;
private final LinkedHashMap<UUID, String> players; private final LinkedHashMap<UUID, String> players;
private final Map<UUID, Integer> scores = new HashMap<>(); private final Map<Integer, @Unmodifiable Map<UUID, Integer>> scores = new HashMap<>();
private final Map<Integer, Map<UUID, Integer>> predictions = new HashMap<>();
private int round = -1; private int round = -1;
private final Map<UUID, Integer> predictions = new HashMap<>();
private final Map<UUID, List<Card>> hands = new HashMap<>(); private final Map<UUID, List<Card>> hands = new HashMap<>();
private final Map<UUID, List<List<Card>>> tricks = new HashMap<>(); private final Map<UUID, List<List<Card>>> tricks = new HashMap<>();
@ -57,25 +61,25 @@ public final class Game extends BaseState {
private Card trumpCard; private Card trumpCard;
private Card.Suit trumpSuit; private Card.Suit trumpSuit;
private GameScreen gameScreen; private @Nullable GameScreen gameScreen;
private final AtomicBoolean sending = new AtomicBoolean(false); private final AtomicBoolean sending = new AtomicBoolean(false);
private boolean juggling; private boolean juggling;
private Card juggleCard; private Card juggleCard;
private boolean werewolf; private boolean werewolf;
public Game(UUID self, UUID session, String sessionName, Configuration configuration, LinkedHashMap<UUID, String> players) { public void init(List<ObserverMessage> messages) {
this.self = self; pendingMessages = messages;
this.session = session;
this.sessionName = sessionName;
this.configuration = configuration;
this.players = players;
} }
@Override @Override
public Optional<ClientState> onEnter(Client client) { public Optional<ClientState> onEnter(Client client) {
var out = handlePendingMessages();
if (out.isPresent()) return out;
gameScreen = new GameScreen(client.getGame(), self, players); gameScreen = new GameScreen(client.getGame(), self, players);
client.getGame().setScreen(gameScreen); client.getGame().setScreen(gameScreen);
updateScreen();
return super.onEnter(client); return super.onEnter(client);
} }
@ -85,7 +89,22 @@ public final class Game extends BaseState {
try { try {
if (message instanceof GameMessage game) { if (message instanceof GameMessage game) {
var observerMessage = game.getObserverMessage(); var observerMessage = game.getObserverMessage();
if (observerMessage instanceof StateMessage state) { return onMessage(observerMessage);
} else if (message instanceof NackMessage nack) {
return onNackMessage(nack);
} else if (message instanceof AckMessage) {
onAckMessage();
return Optional.empty();
} else {
return unexpectedMessage(message);
}
} finally {
executeDelayedFinishInteraction();
}
}
private Optional<ClientState> onMessage(ObserverMessage message) {
if (message instanceof StateMessage state) {
switch (state.getState()) { switch (state.getState()) {
case "starting_round" -> onStartRound(); case "starting_round" -> onStartRound();
case "starting_trick" -> onStartTrick(); case "starting_trick" -> onStartTrick();
@ -99,54 +118,41 @@ public final class Game extends BaseState {
return returnToSession(); return returnToSession();
} }
} }
} else if (observerMessage instanceof HandMessage hand) { } else if (message instanceof HandMessage hand) {
onHandMessage(hand.getPlayer(), hand.getHand()); onHandMessage(hand.getPlayer(), hand.getHand());
} else if (observerMessage instanceof PredictionMessage prediction) { } else if (message instanceof PredictionMessage prediction) {
onPredictionMessage(prediction.getPlayer(), prediction.getPrediction()); onPredictionMessage(prediction.getPlayer(), prediction.getPrediction());
} else if (observerMessage instanceof TrumpMessage trump) { } else if (message instanceof TrumpMessage trump) {
onTrumpMessage(trump.getCard(), trump.getSuit()); onTrumpMessage(trump.getCard(), trump.getSuit());
} else if (observerMessage instanceof TrickMessage trick) { } else if (message instanceof TrickMessage trick) {
onTrickMessage(trick.getPlayer(), trick.getCards()); onTrickMessage(trick.getPlayer(), trick.getCards());
} else if (observerMessage instanceof CardMessage card) { } else if (message instanceof CardMessage card) {
onCardMessage(card.getPlayer(), card.getCard()); onCardMessage(card.getPlayer(), card.getCard());
} else if (observerMessage instanceof ScoreMessage score) { } else if (message instanceof ScoreMessage score) {
onScoreMessage(score.getPoints()); onScoreMessage(score.getPoints());
} else if (observerMessage instanceof UserInputMessage input) { } else if (message instanceof UserInputMessage input) {
onUserInputMessage(input.getPlayer(), input.getAction(), input.getTimeout()); onUserInputMessage(input.getPlayer(), input.getAction(), input.getTimeout());
} else if (observerMessage instanceof TimeoutMessage) { } else if (message instanceof TimeoutMessage) {
onTimeoutMessage(); onTimeoutMessage();
} else { } else {
log.fatal("Unknown observer message type {}.", observerMessage.getClass()); log.fatal("Unknown observer message type {}.", message.getClass());
// TODO user feedback // TODO user feedback
return Optional.of(new Menu()); return Optional.of(new Menu());
} }
return Optional.empty(); return Optional.empty();
} else if (message instanceof NackMessage nack) {
return onNackMessage(nack);
} else if (message instanceof AckMessage) {
onAckMessage();
return Optional.empty();
} else {
return unexpectedMessage(message);
}
} finally {
if (pendingClearActivePlayer > 0 && --pendingClearActivePlayer == 0) {
finishInteraction();
}
}
} }
private void onStartRound() { private void onStartRound() {
log.info("Round {} is starting...", round + 1); log.info("Round {} is starting...", round + 1);
round ++; round ++;
predictions.clear();
tricks.clear(); tricks.clear();
trumpSuit = null; trumpSuit = null;
trumpCard = null; trumpCard = null;
stack.clear(); stack.clear();
trick = -1; trick = -1;
gameScreen.startRound(round);
if (gameScreen != null) gameScreen.startRound(round);
} }
private void onStartTrick() { private void onStartTrick() {
@ -154,7 +160,7 @@ public final class Game extends BaseState {
trick ++; trick ++;
stack.clear(); stack.clear();
finishInteraction(); finishInteraction();
gameScreen.startTrick(); if (gameScreen != null) gameScreen.startTrick();
} }
private void onJuggle() { private void onJuggle() {
@ -178,8 +184,10 @@ public final class Game extends BaseState {
finishInteraction(); finishInteraction();
hands.put(player, new ArrayList<>(hand)); hands.put(player, new ArrayList<>(hand));
if (gameScreen != null) {
gameScreen.setSelectedCard(null); gameScreen.setSelectedCard(null);
gameScreen.setHand(player, hand, juggling); gameScreen.setHand(player, hand, juggling);
}
juggling = false; juggling = false;
} }
@ -191,8 +199,8 @@ public final class Game extends BaseState {
boolean changed = currentInteraction != null && currentInteraction.action() == CHANGE_PREDICTION; boolean changed = currentInteraction != null && currentInteraction.action() == CHANGE_PREDICTION;
finishInteraction(); finishInteraction();
predictions.put(player, prediction); predictions.computeIfAbsent(round, r -> new HashMap<>()).put(player, prediction);
gameScreen.addPrediction(round, player, prediction, changed); if (gameScreen != null) gameScreen.addPrediction(round, player, prediction, changed);
} }
private void onTrumpMessage(@Nullable Card trumpCard, @Nullable Card.Suit trumpSuit) { private void onTrumpMessage(@Nullable Card trumpCard, @Nullable Card.Suit trumpSuit) {
@ -210,7 +218,7 @@ public final class Game extends BaseState {
werewolf = true; werewolf = true;
} else { } else {
werewolf = false; werewolf = false;
gameScreen.showTrumpOverlay(player, trumpCard, trumpSuit); if (gameScreen != null) gameScreen.showTrumpOverlay(player, trumpCard, trumpSuit);
} }
} }
@ -221,7 +229,7 @@ public final class Game extends BaseState {
this.stack.clear(); this.stack.clear();
this.tricks.computeIfAbsent(player, p -> new ArrayList<>()) this.tricks.computeIfAbsent(player, p -> new ArrayList<>())
.add(cards); .add(cards);
gameScreen.finishTrick(player); if (gameScreen != null) gameScreen.finishTrick(player);
} }
private void onCardMessage(@NotNull UUID player, @NotNull Card card) { private void onCardMessage(@NotNull UUID player, @NotNull Card card) {
@ -244,15 +252,17 @@ public final class Game extends BaseState {
hand.remove(handCard); hand.remove(handCard);
} }
gameScreen.playCard(player, handCard); if (gameScreen != null) gameScreen.playCard(player, handCard);
} }
private void onScoreMessage(@Unmodifiable Map<@NotNull UUID, @NotNull Integer> points) { private void onScoreMessage(@Unmodifiable Map<@NotNull UUID, @NotNull Integer> points) {
log.info("The scores are as follows: " + points); log.info("The scores are as follows: " + points);
points.forEach((player, p) -> scores.merge(player, p, Integer::sum)); scores.put(round, points);
if (gameScreen != null) {
gameScreen.addScores(round, points); gameScreen.addScores(round, points);
gameScreen.showScoreOverlay(); gameScreen.showScoreOverlay();
} }
}
private void onUserInputMessage(@Nullable UUID player, @NotNull UserInputMessage.Action action, long timeout) { private void onUserInputMessage(@Nullable UUID player, @NotNull UserInputMessage.Action action, long timeout) {
checkPlayer(player); checkPlayer(player);
@ -264,23 +274,11 @@ public final class Game extends BaseState {
); );
if (action == UserInputMessage.Action.SYNC) { if (action == UserInputMessage.Action.SYNC) {
gameScreen.sync(); if (gameScreen != null) gameScreen.sync();
} else { } else {
currentInteraction = new Interaction(player, action, timeout); currentInteraction = new Interaction(player, action, timeout);
gameScreen.setActivePlayer(player, action, timeout);
if (player != null && werewolf && action == PICK_TRUMP) { showCurrentInteraction();
gameScreen.swapTrumpCard(player);
}
if (isActive()) {
switch (action) {
case PICK_TRUMP -> currentInteraction.overlay(gameScreen.showPickTrumpOverlay(timeout, werewolf));
case MAKE_PREDICTION -> currentInteraction.overlay(gameScreen.showMakePredictionOverlay(round, timeout));
case CHANGE_PREDICTION -> currentInteraction.overlay(gameScreen.showChangePredictionOverlay(round, predictions.get(player), timeout));
case PLAY_CARD -> gameScreen.setPersistentMessage("game.message.play_card.self");
}
}
if (werewolf && action == PICK_TRUMP) { if (werewolf && action == PICK_TRUMP) {
werewolf = false; werewolf = false;
@ -291,7 +289,7 @@ public final class Game extends BaseState {
private void onTimeoutMessage() { private void onTimeoutMessage() {
log.info("The previous interaction timed out."); log.info("The previous interaction timed out.");
delayedFinishInteraction(); delayedFinishInteraction();
gameScreen.timeout(); if (gameScreen != null) gameScreen.timeout();
} }
private Optional<ClientState> onNackMessage(@NotNull NackMessage nack) { private Optional<ClientState> onNackMessage(@NotNull NackMessage nack) {
@ -304,8 +302,10 @@ public final class Game extends BaseState {
int code = nack.getCode(); int code = nack.getCode();
if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) { if (code == NackMessage.ILLEGAL_ARGUMENT || code == NackMessage.ILLEGAL_STATE) {
log.error(nack.getMessage()); log.error(nack.getMessage());
if (gameScreen != null) {
gameScreen.addMessage(true, "game.message.literal", nack.getMessage()); gameScreen.addMessage(true, "game.message.literal", nack.getMessage());
gameScreen.ready(false); gameScreen.ready(false);
}
return Optional.empty(); return Optional.empty();
} else { } else {
return unexpectedMessage(nack); return unexpectedMessage(nack);
@ -317,16 +317,17 @@ public final class Game extends BaseState {
sending.set(false); sending.set(false);
if (isActive() && currentInteraction.action() == JUGGLE_CARD && juggleCard != null) { if (isActive() && currentInteraction.action() == JUGGLE_CARD && juggleCard != null) {
gameScreen.setSelectedCard(juggleCard); if (gameScreen != null) gameScreen.setSelectedCard(juggleCard);
juggleCard = null; juggleCard = null;
} }
gameScreen.ready(true); if (gameScreen != null) gameScreen.ready(true);
} }
//</editor-fold> //</editor-fold>
//<editor-fold desc="Screen Callbacks" defaultstate="collapsed"> //<editor-fold desc="Screen Callbacks" defaultstate="collapsed">
public Optional<ClientState> onCardClicked(Client client, @NotNull Card card) { public Optional<ClientState> onCardClicked(Client client, @NotNull Card card) {
assert gameScreen != null;
if (isActive()) { if (isActive()) {
if (currentInteraction.action() == PLAY_CARD) { if (currentInteraction.action() == PLAY_CARD) {
if (card == Card.CLOUD || card == Card.JUGGLER) { if (card == Card.CLOUD || card == Card.JUGGLER) {
@ -348,6 +349,7 @@ public final class Game extends BaseState {
} }
public Optional<ClientState> onSuitClicked(Client client, @NotNull Card.Suit suit) { public Optional<ClientState> onSuitClicked(Client client, @NotNull Card.Suit suit) {
assert gameScreen != null;
if (isActive() && currentInteraction.action() == PICK_TRUMP) { if (isActive() && currentInteraction.action() == PICK_TRUMP) {
send(client, new PickTrumpMessage(suit)); send(client, new PickTrumpMessage(suit));
} else { } else {
@ -357,6 +359,7 @@ public final class Game extends BaseState {
} }
public Optional<ClientState> onPredictionMade(Client client, int prediction) { public Optional<ClientState> onPredictionMade(Client client, int prediction) {
assert gameScreen != null;
if (isActive()) { if (isActive()) {
if (currentInteraction.action() == MAKE_PREDICTION || currentInteraction.action() == CHANGE_PREDICTION) { if (currentInteraction.action() == MAKE_PREDICTION || currentInteraction.action() == CHANGE_PREDICTION) {
send(client, new PredictMessage(prediction)); send(client, new PredictMessage(prediction));
@ -369,14 +372,15 @@ public final class Game extends BaseState {
} }
public Optional<ClientState> sync(Client client) { public Optional<ClientState> sync(Client client) {
assert gameScreen != null;
send(client, new ContinueMessage()); send(client, new ContinueMessage());
return Optional.empty(); return Optional.empty();
} }
//</editor-fold>
public Optional<ClientState> returnToMenu() { public Optional<ClientState> returnToMenu() {
return Optional.of(new Menu()); return Optional.of(new Menu());
} }
//</editor-fold>
private Optional<ClientState> returnToSession() { private Optional<ClientState> returnToSession() {
return Optional.of(new Session( return Optional.of(new Session(
@ -397,11 +401,12 @@ public final class Game extends BaseState {
client.send(new InteractionMessage(message)); client.send(new InteractionMessage(message));
return true; return true;
} else { } else {
gameScreen.addMessage(true, "game.message.nack.too_fast"); if (gameScreen != null) gameScreen.addMessage(true, "game.message.nack.too_fast");
return false; return false;
} }
} }
//<editor-fold desc="Interactions" defaultstate="collapsed">
/** /**
* Checks whether some action from the player is expected. * Checks whether some action from the player is expected.
*/ */
@ -409,6 +414,29 @@ public final class Game extends BaseState {
return currentInteraction != null && (currentInteraction.player() == null || self.equals(currentInteraction.player())); return currentInteraction != null && (currentInteraction.player() == null || self.equals(currentInteraction.player()));
} }
private void showCurrentInteraction() {
if (gameScreen == null) return;
var player = currentInteraction.player();
var action = currentInteraction.action();
var timeout = currentInteraction.timeout();
gameScreen.setActivePlayer(player, action, timeout);
if (player != null && werewolf && action == PICK_TRUMP) {
gameScreen.swapTrumpCard(player);
}
if (isActive()) {
switch (action) {
case PICK_TRUMP -> currentInteraction.overlay(gameScreen.showPickTrumpOverlay(timeout, werewolf));
case MAKE_PREDICTION -> currentInteraction.overlay(gameScreen.showMakePredictionOverlay(round, timeout));
case CHANGE_PREDICTION -> currentInteraction.overlay(gameScreen.showChangePredictionOverlay(round, predictions.get(round).get(player), timeout ));
case PLAY_CARD -> gameScreen.setPersistentMessage("game.message.play_card.self");
}
}
}
/** /**
* Close the interaction overlay associated with the current interaction and reset the current interaction. * Close the interaction overlay associated with the current interaction and reset the current interaction.
*/ */
@ -419,7 +447,7 @@ public final class Game extends BaseState {
} }
currentInteraction = null; currentInteraction = null;
gameScreen.clearActivePlayer(); if (gameScreen != null) gameScreen.clearActivePlayer();
} }
/** /**
@ -432,8 +460,50 @@ public final class Game extends BaseState {
var overlay = currentInteraction.overlay(); var overlay = currentInteraction.overlay();
if (overlay != null) overlay.close(); if (overlay != null) overlay.close();
} }
if (gameScreen != null) gameScreen.clearActivePlayer();
}
private void executeDelayedFinishInteraction() {
if (pendingClearActivePlayer > 0 && --pendingClearActivePlayer == 0) {
finishInteraction();
}
}
//</editor-fold>
private Optional<ClientState> handlePendingMessages() {
if (pendingMessages != null) {
for (var message : pendingMessages) {
var result = onMessage(message);
if (result.isPresent()) {
return result;
}
executeDelayedFinishInteraction();
}
pendingMessages = null;
}
return Optional.empty();
}
private void updateScreen() {
if (gameScreen == null) return;
gameScreen.clear();
gameScreen.setPredictions(predictions);
gameScreen.setScores(scores);
gameScreen.setTrump(trumpCard, trumpSuit);
gameScreen.setStack(stack);
var hand = hands.get(self);
if (hand != null) {
gameScreen.setHand(self, hand, false);
}
if (currentInteraction != null) {
showCurrentInteraction();
} else {
gameScreen.clearActivePlayer(); gameScreen.clearActivePlayer();
} }
}
//<editor-fold desc="Logging" defaultState="collapsed"> //<editor-fold desc="Logging" defaultState="collapsed">

@ -3,14 +3,19 @@ package eu.jonahbauer.wizard.client.libgdx.state;
import eu.jonahbauer.wizard.client.libgdx.Client; import eu.jonahbauer.wizard.client.libgdx.Client;
import eu.jonahbauer.wizard.client.libgdx.screens.CreateGameScreen; import eu.jonahbauer.wizard.client.libgdx.screens.CreateGameScreen;
import eu.jonahbauer.wizard.client.libgdx.screens.LobbyScreen; import eu.jonahbauer.wizard.client.libgdx.screens.LobbyScreen;
import eu.jonahbauer.wizard.client.libgdx.screens.RejoinScreen;
import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage; import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage;
import eu.jonahbauer.wizard.common.messages.client.JoinSessionMessage; import eu.jonahbauer.wizard.common.messages.client.JoinSessionMessage;
import eu.jonahbauer.wizard.common.messages.client.RejoinMessage;
import eu.jonahbauer.wizard.common.messages.data.SessionData; import eu.jonahbauer.wizard.common.messages.data.SessionData;
import eu.jonahbauer.wizard.common.messages.server.*; import eu.jonahbauer.wizard.common.messages.server.*;
import eu.jonahbauer.wizard.common.model.Configuration; import eu.jonahbauer.wizard.common.model.Configuration;
import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
import static eu.jonahbauer.wizard.client.libgdx.state.AwaitingJoinSession.Source.*;
public final class Lobby extends BaseState { public final class Lobby extends BaseState {
private final Map<UUID, SessionData> sessions = new HashMap<>(); private final Map<UUID, SessionData> sessions = new HashMap<>();
@ -64,14 +69,29 @@ public final class Lobby extends BaseState {
return Optional.of(new Menu()); return Optional.of(new Menu());
} }
public Optional<ClientState> createSession(Client client, String sessionName, Configuration config, long timeout, String playerName) { public Optional<ClientState> createSession(Client client, @NotNull String sessionName, @NotNull Configuration config, long timeout, @NotNull String playerName) {
client.send(new CreateSessionMessage(sessionName, playerName, timeout, config)); client.send(new CreateSessionMessage(sessionName, playerName, timeout, config));
return Optional.of(new AwaitingJoinSession(null, sessionName, config, playerName)); return Optional.of(new AwaitingJoinSession(null, sessionName, config, CREATE));
}
public Optional<ClientState> joinSession(Client client, UUID sessionUUID, String playerName) {
var session = sessions.get(sessionUUID);
if (session != null) {
client.send(new JoinSessionMessage(sessionUUID, playerName));
return Optional.of(new AwaitingJoinSession(session.getUuid(), session.getName(), session.getConfiguration(), JOIN));
} else {
throw new IllegalArgumentException("Session does not exist.");
}
} }
public Optional<ClientState> joinSession(Client client, SessionData session, String playerName) { public Optional<ClientState> rejoinSession(Client client, @NotNull UUID sessionUUID, @NotNull UUID playerUUID, @NotNull String secret) {
client.send(new JoinSessionMessage(session.getUuid(), playerName)); var session = sessions.get(sessionUUID);
return Optional.of(new AwaitingJoinSession(session.getUuid(), session.getName(), session.getConfiguration(), playerName)); if (session != null) {
client.send(new RejoinMessage(sessionUUID, playerUUID, secret));
return Optional.of(new AwaitingJoinSession(sessionUUID, session.getName(), session.getConfiguration(), REJOIN));
} else {
throw new IllegalArgumentException("Session does not exist.");
}
} }
public Optional<ClientState> showCreateScreen(Client client) { public Optional<ClientState> showCreateScreen(Client client) {
@ -88,4 +108,11 @@ public final class Lobby extends BaseState {
lobbyScreen.setSessions(sessions.values().toArray(SessionData[]::new)); lobbyScreen.setSessions(sessions.values().toArray(SessionData[]::new));
return Optional.empty(); return Optional.empty();
} }
public Optional<ClientState> showRejoinScreen(Client client) {
var game = client.getGame();
lobbyScreen = null;
game.setScreen(new RejoinScreen(game));
return Optional.empty();
}
} }

@ -8,6 +8,7 @@ menu.connect.address.label=Enter Server Address
menu.connect.uri.hint=Server Address menu.connect.uri.hint=Server Address
menu.lobby.join=Join menu.lobby.join=Join
menu.lobby.rejoin=Rejoin
menu.lobby.create=Create menu.lobby.create=Create
menu.lobby.back=Back menu.lobby.back=Back
menu.lobby.player_name.label=Player Name menu.lobby.player_name.label=Player Name
@ -23,8 +24,15 @@ menu.create_game.session_configuration.label=Configuration
menu.create_game.back=Back menu.create_game.back=Back
menu.create_game.create=Create menu.create_game.create=Create
menu.rejoin.session_uuid.label=Session ID
menu.rejoin.player_uuid.label=Player ID
menu.rejoin.player_secret.label=Secret
menu.rejoin.back=Back
menu.rejoin.continue=Join
menu.loading.loading=Loading... menu.loading.loading=Loading...
menu.loading.connecting=Connecting... menu.loading.connecting=Connecting...
menu.loading.rejoining=Waiting for game log...
menu.loading.joining_session=Joining session... menu.loading.joining_session=Joining session...
menu.loading.joining_lobby=Joining lobby... menu.loading.joining_lobby=Joining lobby...
menu.loading.back=Return To Main Menu menu.loading.back=Return To Main Menu

@ -8,6 +8,7 @@ menu.connect.address.label=Server-Adresse eingeben
menu.connect.uri.hint=Server Address menu.connect.uri.hint=Server Address
menu.lobby.join=Beitreten menu.lobby.join=Beitreten
menu.lobby.rejoin=Rejoin
menu.lobby.create=Erstellen menu.lobby.create=Erstellen
menu.lobby.back=Verlassen menu.lobby.back=Verlassen
menu.lobby.player_name.label=Spielername menu.lobby.player_name.label=Spielername
@ -23,8 +24,15 @@ menu.create_game.session_configuration.label=Spielvariante
menu.create_game.back=Zurück menu.create_game.back=Zurück
menu.create_game.create=Erstellen menu.create_game.create=Erstellen
menu.rejoin.session_uuid.label=Sitzungs-ID
menu.rejoin.player_uuid.label=Spieler-ID
menu.rejoin.player_secret.label=Passwort
menu.rejoin.back=Zurück
menu.rejoin.continue=Beitreten
menu.loading.loading=Laden... menu.loading.loading=Laden...
menu.loading.connecting=Verbinde... menu.loading.connecting=Verbinde...
menu.loading.rejoining=Warte auf Spiellog...
menu.loading.joining_session=Trete Sitzung bei... menu.loading.joining_session=Trete Sitzung bei...
menu.loading.joining_lobby=Trete Warteraum bei... menu.loading.joining_lobby=Trete Warteraum bei...
menu.loading.back=Zurück zum Hauptmenü menu.loading.back=Zurück zum Hauptmenü

@ -110,6 +110,7 @@ public class Session implements Observer {
player.send(message.getValue()); player.send(message.getValue());
} }
} }
player.send(new AckMessage());
return sessionPlayer.toData(); return sessionPlayer.toData();
} }

@ -25,7 +25,6 @@ public class LobbyState implements ClientState {
if (message instanceof CreateSessionMessage create) { if (message instanceof CreateSessionMessage create) {
Lobby.getInstance().leave(player); Lobby.getInstance().leave(player);
try { try {
player.buffer();
var session = Lobby.getInstance().createSession( var session = Lobby.getInstance().createSession(
create.getSessionName(), create.getSessionName(),
create.getTimeout(), create.getTimeout(),
@ -42,7 +41,6 @@ public class LobbyState implements ClientState {
} else if (message instanceof JoinSessionMessage join) { } else if (message instanceof JoinSessionMessage join) {
Lobby.getInstance().leave(player); Lobby.getInstance().leave(player);
try { try {
player.buffer();
var session = Lobby.getInstance().getSession(join.getSession()); var session = Lobby.getInstance().getSession(join.getSession());
if (session == null) { if (session == null) {
throw new NackException(NackMessage.NOT_FOUND, "Session not found."); throw new NackException(NackMessage.NOT_FOUND, "Session not found.");
@ -59,7 +57,6 @@ public class LobbyState implements ClientState {
} else if (message instanceof RejoinMessage rejoin) { } else if (message instanceof RejoinMessage rejoin) {
Lobby.getInstance().leave(player); Lobby.getInstance().leave(player);
try { try {
player.buffer();
var session = Lobby.getInstance().getSession(rejoin.getSession()); var session = Lobby.getInstance().getSession(rejoin.getSession());
if (session == null) { if (session == null) {
throw new NackException(NackMessage.NOT_FOUND, "Session not found."); throw new NackException(NackMessage.NOT_FOUND, "Session not found.");

Loading…
Cancel
Save