rejoin support for libgdx client
This commit is contained in:
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,24 +36,37 @@ 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()
|
|
||||||
);
|
|
||||||
|
|
||||||
return Optional.of(new Session(
|
client.getGame().storage.credentials = new SavedData.SessionCredentials(session, player, secret);
|
||||||
new SessionData(joined.getSession(), sessionName, -1, configuration),
|
|
||||||
joined.getPlayers(),
|
if (source == Source.REJOIN) {
|
||||||
joined.getPlayer()
|
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(
|
||||||
|
new SessionData(session, sessionName, -1, configuration),
|
||||||
|
players,
|
||||||
|
player
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (message instanceof NackMessage nack) {
|
} else if (message instanceof NackMessage nack) {
|
||||||
switch (nack.getCode()) {
|
switch (nack.getCode()) {
|
||||||
@ -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, SessionData session, String playerName) {
|
public Optional<ClientState> joinSession(Client client, UUID sessionUUID, String playerName) {
|
||||||
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 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> rejoinSession(Client client, @NotNull UUID sessionUUID, @NotNull UUID playerUUID, @NotNull String secret) {
|
||||||
|
var session = sessions.get(sessionUUID);
|
||||||
|
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…
x
Reference in New Issue
Block a user