main
Jonah Bauer 3 years ago
parent ec77b05b0d
commit 2375a5ed83

@ -1,6 +0,0 @@
subprojects {
dependencies {
implementation(project(":wizard-common"))
implementation(JavaWebSocket.id)
}
}

@ -3,6 +3,8 @@ plugins {
} }
dependencies { dependencies {
implementation(project(":wizard-common"))
implementation(JLine.id) implementation(JLine.id)
implementation(Jansi.id) implementation(Jansi.id)
implementation(JavaWebSocket.id) implementation(JavaWebSocket.id)

@ -3,12 +3,8 @@ package eu.jonahbauer.wizard.client.cli.commands;
import eu.jonahbauer.wizard.client.cli.Client; import eu.jonahbauer.wizard.client.cli.Client;
import eu.jonahbauer.wizard.client.cli.ClientSocket; import eu.jonahbauer.wizard.client.cli.ClientSocket;
import eu.jonahbauer.wizard.client.cli.state.AwaitingConnection; import eu.jonahbauer.wizard.client.cli.state.AwaitingConnection;
import eu.jonahbauer.wizard.client.cli.state.Lobby;
import eu.jonahbauer.wizard.common.messages.server.SessionListMessage;
import java.net.URI; import java.net.URI;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static picocli.CommandLine.*; import static picocli.CommandLine.*;

@ -17,7 +17,7 @@ public final class AwaitingJoinLobby extends Awaiting {
@Override @Override
public Optional<ClientState> onMessage(Client client, ServerMessage message) { public Optional<ClientState> onMessage(Client client, ServerMessage message) {
if (message instanceof SessionListMessage list) { if (message instanceof SessionListMessage list) {
return Optional.of(new Lobby(list)); return Optional.of(new Lobby(list.getSessions()));
} else { } else {
return super.onMessage(client, message); return super.onMessage(client, message);
} }

@ -12,8 +12,8 @@ public final class Lobby extends BaseState {
@Getter @Getter
private final Map<UUID, SessionData> sessions = new HashMap<>(); private final Map<UUID, SessionData> sessions = new HashMap<>();
public Lobby(SessionListMessage list) { public Lobby(Collection<SessionData> sessions) {
list.getSessions().forEach(session -> sessions.put(session.getUuid(), session)); sessions.forEach(session -> this.sessions.put(session.getUuid(), session));
} }
@Override @Override

@ -14,5 +14,7 @@ project(":wizard-client:wizard-client-libgdx:core") {
dependencies { dependencies {
api(LibGDX.api) api(LibGDX.api)
implementation(project(":wizard-common"))
implementation(JavaWebSocket.id)
} }
} }

@ -28,7 +28,11 @@ public class Client extends TimeoutContext<ClientState, Client> {
@Override @Override
protected void handleError(Throwable t) { protected void handleError(Throwable t) {
// TODO better error handling // TODO better error handling
t.printStackTrace(); log.error("", t);
var menu = new Menu();
forceTransition(menu);
menu.onEnter(this);
} }
public void setSocket(ClientSocket socket) { public void setSocket(ClientSocket socket) {
@ -39,15 +43,27 @@ public class Client extends TimeoutContext<ClientState, Client> {
} }
public void onOpen() { public void onOpen() {
execute(s -> s.onOpen(this)); try {
execute(s -> s.onOpen(this));
} catch (Throwable t) {
handleError(t);
}
} }
public void onClose(int code, String reason, boolean remote) { public void onClose(int code, String reason, boolean remote) {
execute(s -> s.onClose(this, code, reason, remote)); try {
execute(s -> s.onClose(this, code, reason, remote));
} catch (Throwable t) {
handleError(t);
}
} }
public void onMessage(ServerMessage message) { public void onMessage(ServerMessage message) {
execute(s -> s.onMessage(this, message)); try {
execute(s -> s.onMessage(this, message));
} catch (Throwable t) {
handleError(t);
}
} }
@Override @Override

@ -39,7 +39,7 @@ public class ClientSocket extends WebSocketClient {
@Override @Override
public void onError(Exception e) { public void onError(Exception e) {
e.printStackTrace(); log.error("", e);
close(CloseFrame.ABNORMAL_CLOSE, e.getMessage()); close(CloseFrame.ABNORMAL_CLOSE, e.getMessage());
} }

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor; import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;

@ -0,0 +1,5 @@
package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
public interface InteractionOverlay {
void close();
}

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup; import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureAtlas;

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputEvent;

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.Group;

@ -1,4 +1,4 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay; package eu.jonahbauer.wizard.client.libgdx.actions.overlay;
import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Actor;
@ -85,7 +85,7 @@ public class TrumpOverlay extends Overlay {
); );
private final @Nullable String player; private final @Nullable String player;
private final @NotNull Card card; private final @Nullable Card card;
private final @Nullable Card.Suit suit; private final @Nullable Card.Suit suit;
private final @NotNull CardActor trumpCardActor; private final @NotNull CardActor trumpCardActor;
@ -93,7 +93,7 @@ public class TrumpOverlay extends Overlay {
private boolean animateCard = true; private boolean animateCard = true;
public TrumpOverlay(@NotNull GameScreen gameScreen, @Nullable String player, @NotNull Card card, @Nullable Card.Suit suit) { public TrumpOverlay(@NotNull GameScreen gameScreen, @Nullable String player, @Nullable Card card, @Nullable Card.Suit suit) {
super(gameScreen, Long.MAX_VALUE); super(gameScreen, Long.MAX_VALUE);
this.player = player; this.player = player;
this.card = card; this.card = card;
@ -140,7 +140,7 @@ public class TrumpOverlay extends Overlay {
} else { } else {
trumpCardActor.remove(); trumpCardActor.remove();
cardGroup.addActor(trumpCardActor); cardGroup.addActor(trumpCardActor);
trumpCardActor.setCard(card); trumpCardActor.setCard(card != null ? card : Card.HIDDEN);
} }
trumpSuitActor.remove(); trumpSuitActor.remove();

@ -1,5 +0,0 @@
package eu.jonahbauer.wizard.client.libgdx.actors.game.overlay;
public interface InteractionOverlay {
void close();
}

@ -16,11 +16,11 @@ import com.badlogic.gdx.utils.I18NBundle;
import eu.jonahbauer.wizard.client.libgdx.AnimationTimings; import eu.jonahbauer.wizard.client.libgdx.AnimationTimings;
import eu.jonahbauer.wizard.client.libgdx.GameAtlas; import eu.jonahbauer.wizard.client.libgdx.GameAtlas;
import eu.jonahbauer.wizard.client.libgdx.WizardGame; import eu.jonahbauer.wizard.client.libgdx.WizardGame;
import eu.jonahbauer.wizard.client.libgdx.actions.overlay.*;
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor; import eu.jonahbauer.wizard.client.libgdx.actors.game.CardActor;
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardStack; import eu.jonahbauer.wizard.client.libgdx.actors.game.CardStack;
import eu.jonahbauer.wizard.client.libgdx.actors.game.CardsGroup; import eu.jonahbauer.wizard.client.libgdx.actors.game.CardsGroup;
import eu.jonahbauer.wizard.client.libgdx.actors.game.PadOfTruth; import eu.jonahbauer.wizard.client.libgdx.actors.game.PadOfTruth;
import eu.jonahbauer.wizard.client.libgdx.actors.game.overlay.*;
import eu.jonahbauer.wizard.client.libgdx.state.Game; import eu.jonahbauer.wizard.client.libgdx.state.Game;
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;
@ -451,7 +451,7 @@ public class GameScreen extends MenuScreen {
} }
//<editor-fold desc="Overlays" defaultstate="collapsed"> //<editor-fold desc="Overlays" defaultstate="collapsed">
public void showTrumpOverlay(@Nullable UUID player, @NotNull Card trumpCard, @Nullable Card.Suit trumpSuit) { public void showTrumpOverlay(@Nullable UUID player, @Nullable Card trumpCard, @Nullable Card.Suit trumpSuit) {
if (trumpCardActor == null) { if (trumpCardActor == null) {
trumpCardActor = new CardActor(Card.HIDDEN, atlas); trumpCardActor = new CardActor(Card.HIDDEN, atlas);
} }
@ -489,7 +489,7 @@ public class GameScreen extends MenuScreen {
delay(AnimationTimings.OVERLAY_HOLD), delay(AnimationTimings.OVERLAY_HOLD),
parallel( parallel(
targeting(padOfTruth, scaleTo(PadOfTruth.COLLAPSED_SCALE, PadOfTruth.COLLAPSED_SCALE, AnimationTimings.OVERLAY_SHARED_ELEMENT)), targeting(padOfTruth, scaleTo(PadOfTruth.COLLAPSED_SCALE, PadOfTruth.COLLAPSED_SCALE, AnimationTimings.OVERLAY_SHARED_ELEMENT)),
targeting(padOfTruth, moveTo(WizardGame.WIDTH - 10 - PadOfTruth.EXTENDED_WIDTH, 10)) targeting(padOfTruth, moveTo(WizardGame.WIDTH - 10 - PadOfTruth.EXTENDED_WIDTH, 10, AnimationTimings.OVERLAY_SHARED_ELEMENT))
), ),
run(() -> padOfTruth.setEnabled(true)) run(() -> padOfTruth.setEnabled(true))
)); ));

@ -8,7 +8,7 @@ import eu.jonahbauer.wizard.client.libgdx.WizardGame;
public abstract class MenuScreen implements Screen { public abstract class MenuScreen implements Screen {
protected final float BUTTON_BAR_Y = WizardGame.HEIGHT * 0.15f; protected final float BUTTON_BAR_Y = WizardGame.HEIGHT * 0.15f;
protected WizardGame game; protected final WizardGame game;
public MenuScreen(WizardGame game) { public MenuScreen(WizardGame game) {
this.game = game; this.game = game;

@ -29,9 +29,7 @@ public class WaitingScreen extends MenuScreen {
private Label labelPlayerName; private Label labelPlayerName;
private List<PlayerData> players; private List<PlayerData> players;
private AutoFocusScrollPane listContainer;
private final ChangeListener listener = new ChangeListener() { private final ChangeListener listener = new ChangeListener() {
@Override @Override
public void changed(ChangeEvent event, Actor actor) { public void changed(ChangeEvent event, Actor actor) {
@ -81,7 +79,7 @@ public class WaitingScreen extends MenuScreen {
} }
}; };
listContainer = new AutoFocusScrollPane(players, game.data.skin); var listContainer = new AutoFocusScrollPane(players, game.data.skin);
listContainer.layout(); listContainer.layout();
var content = new HorizontalGroup().grow().space(20); var content = new HorizontalGroup().grow().space(20);

@ -11,7 +11,7 @@ import java.util.Optional;
public abstract class Awaiting extends BaseState implements ClientState { public abstract class Awaiting extends BaseState implements ClientState {
@Override @Override
public Optional<ClientState> onMessage(Client client, ServerMessage message) { public Optional<ClientState> onMessage(Client client, ServerMessage message) {
return unexpectedMessage(client, message); return unexpectedMessage(message);
} }
@Override @Override

@ -29,7 +29,7 @@ public abstract class BaseState implements ClientState {
return Optional.of(new Menu()); return Optional.of(new Menu());
} }
protected static Optional<ClientState> unexpectedMessage(Client client, ServerMessage message) { protected static Optional<ClientState> unexpectedMessage(ServerMessage message) {
// return to menu on unexpected message // return to menu on unexpected message
log.fatal("Unexpected message {}. Returning to menu.", message); log.fatal("Unexpected message {}. Returning to menu.", message);
return Optional.of(new Menu()); return Optional.of(new Menu());

@ -1,7 +1,7 @@
package eu.jonahbauer.wizard.client.libgdx.state; 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.actors.game.overlay.InteractionOverlay; import eu.jonahbauer.wizard.client.libgdx.actions.overlay.InteractionOverlay;
import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen;
import eu.jonahbauer.wizard.client.libgdx.util.Pair; import eu.jonahbauer.wizard.client.libgdx.util.Pair;
import eu.jonahbauer.wizard.common.messages.client.InteractionMessage; import eu.jonahbauer.wizard.common.messages.client.InteractionMessage;
@ -14,10 +14,15 @@ import eu.jonahbauer.wizard.common.messages.server.GameMessage;
import eu.jonahbauer.wizard.common.messages.server.NackMessage; import eu.jonahbauer.wizard.common.messages.server.NackMessage;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage; import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.common.model.Card; import eu.jonahbauer.wizard.common.model.Card;
import eu.jonahbauer.wizard.common.model.Configuration;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
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.Nullable;
import org.jetbrains.annotations.Range;
import org.jetbrains.annotations.Unmodifiable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.time.Instant; import java.time.Instant;
@ -34,6 +39,7 @@ 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 String secret; private final String secret;
private final LinkedHashMap<UUID, String> players; private final LinkedHashMap<UUID, String> players;
@ -59,10 +65,11 @@ public final class Game extends BaseState {
private Card juggleCard; private Card juggleCard;
private boolean werewolf; private boolean werewolf;
public Game(UUID self, UUID session, String sessionName, String secret, LinkedHashMap<UUID, String> players) { public Game(UUID self, UUID session, String sessionName, Configuration configuration, String secret, LinkedHashMap<UUID, String> players) {
this.self = self; this.self = self;
this.session = session; this.session = session;
this.sessionName = sessionName; this.sessionName = sessionName;
this.configuration = configuration;
this.secret = secret; this.secret = secret;
this.players = players; this.players = players;
} }
@ -117,12 +124,12 @@ public final class Game extends BaseState {
} }
return Optional.empty(); return Optional.empty();
} else if (message instanceof NackMessage nack) { } else if (message instanceof NackMessage nack) {
return onNackMessage(client, message, nack); return onNackMessage(nack);
} else if (message instanceof AckMessage) { } else if (message instanceof AckMessage) {
onAckMessage(); onAckMessage();
return Optional.empty(); return Optional.empty();
} else { } else {
return unexpectedMessage(client, message); return unexpectedMessage(message);
} }
} finally { } finally {
if (pendingClearActivePlayer > 0 && --pendingClearActivePlayer == 0) { if (pendingClearActivePlayer > 0 && --pendingClearActivePlayer == 0) {
@ -165,7 +172,7 @@ public final class Game extends BaseState {
log.error("The game has finished with an error."); log.error("The game has finished with an error.");
} }
private void onHandMessage(UUID player, List<Card> hand) { private void onHandMessage(@NotNull UUID player, @Unmodifiable @NotNull List<@NotNull Card> hand) {
checkPlayer(player); checkPlayer(player);
log.info("{} hand cards are: {}", nameOf(player, true, true), hand); log.info("{} hand cards are: {}", nameOf(player, true, true), hand);
@ -178,7 +185,7 @@ public final class Game extends BaseState {
juggling = false; juggling = false;
} }
private void onPredictionMessage(UUID player, int prediction) { private void onPredictionMessage(@NotNull UUID player, @Range(from = 0, to = Integer.MAX_VALUE) int prediction) {
checkPlayer(player); checkPlayer(player);
checkActivePlayer(player, MAKE_PREDICTION, CHANGE_PREDICTION); checkActivePlayer(player, MAKE_PREDICTION, CHANGE_PREDICTION);
log.info("{} predicted: {}", nameOf(player, true, false), prediction); log.info("{} predicted: {}", nameOf(player, true, false), prediction);
@ -190,13 +197,13 @@ public final class Game extends BaseState {
gameScreen.addPrediction(round, player, prediction, changed); gameScreen.addPrediction(round, player, prediction, changed);
} }
private void onTrumpMessage(Card trumpCard, Card.Suit trumpSuit) { private void onTrumpMessage(@Nullable Card trumpCard, @Nullable Card.Suit trumpSuit) {
if (trumpCard == null) { if (trumpCard == null) {
log.info("There is no trump in this round."); log.info("There is no trump in this round.");
} else { } else {
log.info("The trump suit is {} ({}).", trumpSuit != null ? trumpSuit : "yet to be determined.", trumpCard); log.info("The trump suit is {} ({}).", trumpSuit != null ? trumpSuit : "yet to be determined.", trumpCard);
} }
var player = currentInteraction != null && currentInteraction.action() == PICK_TRUMP ? currentInteraction.player() : null;
finishInteraction(); finishInteraction();
this.trumpCard = trumpCard; this.trumpCard = trumpCard;
@ -205,11 +212,11 @@ public final class Game extends BaseState {
werewolf = true; werewolf = true;
} else { } else {
werewolf = false; werewolf = false;
gameScreen.showTrumpOverlay(null, trumpCard, trumpSuit); gameScreen.showTrumpOverlay(player, trumpCard, trumpSuit);
} }
} }
private void onTrickMessage(UUID player, List<Card> cards) { private void onTrickMessage(@NotNull UUID player, @Unmodifiable @NotNull List<@NotNull Card> cards) {
checkPlayer(player); checkPlayer(player);
log.info("This trick {} goes to {}.", cards, nameOf(player)); log.info("This trick {} goes to {}.", cards, nameOf(player));
@ -219,7 +226,7 @@ public final class Game extends BaseState {
gameScreen.finishTrick(player); gameScreen.finishTrick(player);
} }
private void onCardMessage(UUID player, Card card) { private void onCardMessage(@NotNull UUID player, @NotNull Card card) {
checkPlayer(player); checkPlayer(player);
checkActivePlayer(player, PLAY_CARD); checkActivePlayer(player, PLAY_CARD);
log.info("{} played {}.", nameOf(player, true, false), card); log.info("{} played {}.", nameOf(player, true, false), card);
@ -242,14 +249,14 @@ public final class Game extends BaseState {
gameScreen.playCard(player, handCard); gameScreen.playCard(player, handCard);
} }
private void onScoreMessage(Map<UUID, 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)); points.forEach((player, p) -> scores.merge(player, p, Integer::sum));
gameScreen.addScores(round, points); gameScreen.addScores(round, points);
gameScreen.showScoreOverlay(); gameScreen.showScoreOverlay();
} }
private void onUserInputMessage(UUID player, UserInputMessage.Action action, long timeout) { private void onUserInputMessage(@Nullable UUID player, @NotNull UserInputMessage.Action action, long timeout) {
checkPlayer(player); checkPlayer(player);
log.info( log.info(
"Waiting for input {} from {}. (times out at {})", "Waiting for input {} from {}. (times out at {})",
@ -264,7 +271,7 @@ public final class Game extends BaseState {
currentInteraction = new Interaction(player, action, timeout); currentInteraction = new Interaction(player, action, timeout);
gameScreen.setActivePlayer(player, action, timeout); gameScreen.setActivePlayer(player, action, timeout);
if (werewolf && action == PICK_TRUMP) { if (player != null && werewolf && action == PICK_TRUMP) {
gameScreen.swapTrumpCard(player); gameScreen.swapTrumpCard(player);
} }
@ -289,7 +296,7 @@ public final class Game extends BaseState {
gameScreen.timeout(); gameScreen.timeout();
} }
private Optional<ClientState> onNackMessage(Client client, ServerMessage message, NackMessage nack) { private Optional<ClientState> onNackMessage(@NotNull NackMessage nack) {
sending.set(false); sending.set(false);
if (isActive() && currentInteraction.action() == JUGGLE_CARD && juggleCard != null) { if (isActive() && currentInteraction.action() == JUGGLE_CARD && juggleCard != null) {
@ -303,7 +310,7 @@ public final class Game extends BaseState {
gameScreen.ready(false); gameScreen.ready(false);
return Optional.empty(); return Optional.empty();
} else { } else {
return unexpectedMessage(client, message); return unexpectedMessage(nack);
} }
} }
@ -321,7 +328,7 @@ public final class Game extends BaseState {
//</editor-fold> //</editor-fold>
//<editor-fold desc="Screen Callbacks" defaultstate="collapsed"> //<editor-fold desc="Screen Callbacks" defaultstate="collapsed">
public Optional<ClientState> onCardClicked(Client client, Card card) { public Optional<ClientState> onCardClicked(Client client, @NotNull Card card) {
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) {
@ -342,7 +349,7 @@ public final class Game extends BaseState {
return Optional.empty(); return Optional.empty();
} }
public Optional<ClientState> onSuitClicked(Client client, Card.Suit suit) { public Optional<ClientState> onSuitClicked(Client client, @NotNull Card.Suit suit) {
if (isActive() && currentInteraction.action() == PICK_TRUMP) { if (isActive() && currentInteraction.action() == PICK_TRUMP) {
send(client, new PickTrumpMessage(suit)); send(client, new PickTrumpMessage(suit));
} else { } else {
@ -371,7 +378,7 @@ public final class Game extends BaseState {
private Optional<ClientState> returnToSession() { private Optional<ClientState> returnToSession() {
return Optional.of(new Session( return Optional.of(new Session(
new SessionData(session, sessionName, -1, null), new SessionData(session, sessionName, -1, configuration),
players.entrySet().stream() players.entrySet().stream()
.map(entry -> new PlayerData(entry.getKey(), entry.getValue(), false)) .map(entry -> new PlayerData(entry.getKey(), entry.getValue(), false))
.toList(), .toList(),

@ -63,7 +63,7 @@ public final class Lobby extends BaseState {
} }
return Optional.empty(); return Optional.empty();
} else { } else {
return unexpectedMessage(client, message); return unexpectedMessage(message);
} }
} }

@ -24,7 +24,7 @@ public final class Session extends BaseState {
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 final List<PlayerData> players = new ArrayList<>(); private final Map<UUID, PlayerData> players = new LinkedHashMap<>();
private boolean sending; private boolean sending;
@ -32,7 +32,7 @@ public final class Session extends BaseState {
this.session = session.getUuid(); this.session = session.getUuid();
this.sessionName = session.getName(); this.sessionName = session.getName();
this.configuration = session.getConfiguration(); this.configuration = session.getConfiguration();
this.players.addAll(players); players.forEach(player -> this.players.put(player.getUuid(), player));
this.self = self; this.self = self;
this.secret = secret; this.secret = secret;
@ -42,7 +42,7 @@ public final class Session extends BaseState {
public Optional<ClientState> onEnter(Client client) { public Optional<ClientState> onEnter(Client client) {
sessionScreen = new WaitingScreen(client.getGame()); sessionScreen = new WaitingScreen(client.getGame());
client.getGame().setScreen(sessionScreen); client.getGame().setScreen(sessionScreen);
sessionScreen.setPlayers(players.toArray(new PlayerData[0])); sessionScreen.setPlayers(players.values().toArray(new PlayerData[0]));
sessionScreen.setReady(false); sessionScreen.setReady(false);
sessionScreen.setPlayerName(getName()); sessionScreen.setPlayerName(getName());
sessionScreen.setSession(session, sessionName, configuration); sessionScreen.setSession(session, sessionName, configuration);
@ -53,19 +53,20 @@ public final class Session extends BaseState {
@Override @Override
public Optional<ClientState> onMessage(Client client, ServerMessage message) { public Optional<ClientState> onMessage(Client client, ServerMessage message) {
if (message instanceof PlayerJoinedMessage join) { if (message instanceof PlayerJoinedMessage join) {
sessionScreen.addPlayer(join.getPlayer()); var player = join.getPlayer();
players.add(join.getPlayer()); sessionScreen.addPlayer(player);
players.put(player.getUuid(), player);
return Optional.empty(); return Optional.empty();
} else if (message instanceof PlayerLeftMessage leave) { } else if (message instanceof PlayerLeftMessage leave) {
sessionScreen.removePlayer(leave.getPlayer()); var player = leave.getPlayer();
players.remove(new PlayerData(leave.getPlayer(), null, false)); sessionScreen.removePlayer(player);
players.remove(player);
return Optional.empty(); return Optional.empty();
} else if (message instanceof PlayerModifiedMessage modified) { } else if (message instanceof PlayerModifiedMessage modified) {
var player = modified.getPlayer(); var player = modified.getPlayer();
sessionScreen.modifyPlayer(player); sessionScreen.modifyPlayer(player);
players.remove(player); players.put(player.getUuid(), player);
players.add(player);
if (self.equals(player.getUuid())) { if (self.equals(player.getUuid())) {
sessionScreen.setReady(player.isReady()); sessionScreen.setReady(player.isReady());
@ -74,8 +75,8 @@ public final class Session extends BaseState {
return Optional.empty(); return Optional.empty();
} else if (message instanceof StartingGameMessage) { } else if (message instanceof StartingGameMessage) {
var players = new LinkedHashMap<UUID, String>(); var players = new LinkedHashMap<UUID, String>();
this.players.forEach(player -> players.put(player.getUuid(), player.getName())); this.players.forEach((uuid, player) -> players.put(uuid, player.getName()));
return Optional.of(new Game(self, session, sessionName, secret, players)); return Optional.of(new Game(self, session, sessionName, configuration, secret, players));
} else if (sending && message instanceof NackMessage nack) { } else if (sending && message instanceof NackMessage nack) {
// TODO display error // TODO display error
log.error(nack.getMessage()); log.error(nack.getMessage());
@ -87,7 +88,7 @@ public final class Session extends BaseState {
sessionScreen.setSending(false); sessionScreen.setSending(false);
return Optional.empty(); return Optional.empty();
} else { } else {
return unexpectedMessage(client, message); return unexpectedMessage(message);
} }
} }
@ -112,7 +113,7 @@ public final class Session extends BaseState {
} }
private boolean isReady() { private boolean isReady() {
for (PlayerData player : players) { for (PlayerData player : players.values()) {
if (self.equals(player.getUuid())) { if (self.equals(player.getUuid())) {
return player.isReady(); return player.isReady();
} }
@ -121,7 +122,7 @@ public final class Session extends BaseState {
} }
private String getName() { private String getName() {
for (PlayerData player : players) { for (PlayerData player : players.values()) {
if (self.equals(player.getUuid())) { if (self.equals(player.getUuid())) {
return player.getName(); return player.getName();
} }

@ -3,7 +3,6 @@ package eu.jonahbauer.wizard.common.messages.observer;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Unmodifiable; import org.jetbrains.annotations.Unmodifiable;
import java.util.Map; import java.util.Map;

@ -4,7 +4,6 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
/** /**
* A {@link StateMessage} is sent whenever the game changes its internal state. * A {@link StateMessage} is sent whenever the game changes its internal state.

@ -152,34 +152,6 @@ public final class GameData {
return new GameData(newValues, newPresent); return new GameData(newValues, newPresent);
} }
/**
* @see #with(Key, Object)
*/
public <T1, T2, T3> GameData with(@NotNull Key<T1> key1, T1 value1, Key<T2> key2, T2 value2, Key<T3> key3, T3 value3) {
int index1 = key1.index();
int index2 = key2.index();
int index3 = key3.index();
if (present[index1]
&& present[index2]
&& present[index3]
&& Objects.equals(values[index1], value1)
&& Objects.equals(values[index2], value2)
&& Objects.equals(values[index3], value3)) {
return this;
}
Object[] newValues = Arrays.copyOf(this.values, SIZE);
boolean[] newPresent = Arrays.copyOf(this.present, SIZE);
newValues[index1] = value1;
newPresent[index1] = true;
newValues[index2] = value2;
newPresent[index2] = true;
newValues[index3] = value3;
newPresent[index3] = true;
return new GameData(newValues, newPresent);
}
/** /**
* Returns {@code this} if this map contains a mapping for the specified key or throws a * Returns {@code this} if this map contains a mapping for the specified key or throws a
* {@link NoSuchElementException} otherwise. * {@link NoSuchElementException} otherwise.

@ -35,9 +35,6 @@ public final class PlayingCard extends TrickState {
@Override @Override
public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) { public Optional<GameState> onMessage(Game game, UUID player, PlayerMessage message) {
if (get(CURRENT_PLAYER).equals(player) && message instanceof PlayCardMessage cardMessage) { if (get(CURRENT_PLAYER).equals(player) && message instanceof PlayCardMessage cardMessage) {
if (cardMessage.getCard() == null) {
throw new IllegalArgumentException("Card must not be null.");
}
return transition(game, cardMessage.getCard()); return transition(game, cardMessage.getCard());
} else { } else {
return super.onMessage(game, player, message); return super.onMessage(game, player, message);

@ -3,8 +3,6 @@ package eu.jonahbauer.wizard.core.machine.states.trick;
import eu.jonahbauer.wizard.core.machine.Game; import eu.jonahbauer.wizard.core.machine.Game;
import eu.jonahbauer.wizard.core.machine.GameState; import eu.jonahbauer.wizard.core.machine.GameState;
import eu.jonahbauer.wizard.core.machine.states.GameData; import eu.jonahbauer.wizard.core.machine.states.GameData;
import eu.jonahbauer.wizard.core.machine.states.SyncState;
import eu.jonahbauer.wizard.core.machine.states.round.RoundState;
import java.util.Optional; import java.util.Optional;

@ -7,7 +7,6 @@ import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;

@ -24,7 +24,6 @@ import static eu.jonahbauer.wizard.core.machine.GameTestUtils.doFinish;
import static eu.jonahbauer.wizard.core.machine.states.GameData.*; import static eu.jonahbauer.wizard.core.machine.states.GameData.*;
import static eu.jonahbauer.wizard.core.machine.states.GameData.TypedValue.entry; import static eu.jonahbauer.wizard.core.machine.states.GameData.TypedValue.entry;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
public class DeterminingTrumpTest { public class DeterminingTrumpTest {

@ -1,6 +1,5 @@
package eu.jonahbauer.wizard.server; package eu.jonahbauer.wizard.server;
import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage;
import eu.jonahbauer.wizard.common.messages.server.ServerMessage; import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
import eu.jonahbauer.wizard.common.messages.server.SessionCreatedMessage; import eu.jonahbauer.wizard.common.messages.server.SessionCreatedMessage;
import eu.jonahbauer.wizard.common.messages.server.SessionListMessage; import eu.jonahbauer.wizard.common.messages.server.SessionListMessage;
@ -26,17 +25,12 @@ public class Lobby {
private Lobby() {} private Lobby() {}
public Session createSession(CreateSessionMessage create) { public Session createSession(@NotNull String name, long timeout, @NotNull Configuration configuration) {
lock.readLock().lock(); lock.readLock().lock();
try { try {
Session session; Session session;
do { do {
session = new Session( session = new Session(UUID.randomUUID(), name, timeout, configuration);
UUID.randomUUID(),
create.getSessionName(),
create.getTimeout(),
create.getConfiguration()
);
} while (sessions.putIfAbsent(session.getUuid(), session) != null); } while (sessions.putIfAbsent(session.getUuid(), session) != null);
notifyPlayers(new SessionCreatedMessage(session.toData())); notifyPlayers(new SessionCreatedMessage(session.toData()));

@ -1,9 +1,11 @@
package eu.jonahbauer.wizard.server; package eu.jonahbauer.wizard.server;
import eu.jonahbauer.wizard.common.messages.server.NackMessage; import eu.jonahbauer.wizard.common.messages.server.NackMessage;
import lombok.Getter;
import org.intellij.lang.annotations.MagicConstant; import org.intellij.lang.annotations.MagicConstant;
public class NackException extends RuntimeException { public class NackException extends RuntimeException {
@Getter(onMethod = @__({@MagicConstant(valuesFromClass = NackMessage.class)}))
private final int code; private final int code;
public NackException(@MagicConstant(valuesFromClass = NackMessage.class) int code, String message) { public NackException(@MagicConstant(valuesFromClass = NackMessage.class) int code, String message) {
@ -11,11 +13,6 @@ public class NackException extends RuntimeException {
this.code = code; this.code = code;
} }
@MagicConstant(valuesFromClass = NackMessage.class)
public int getCode() {
return code;
}
public NackMessage toMessage() { public NackMessage toMessage() {
return new NackMessage(code, getMessage()); return new NackMessage(code, getMessage());
} }

@ -26,7 +26,11 @@ public class LobbyState implements ClientState {
Lobby.getInstance().leave(player); Lobby.getInstance().leave(player);
try { try {
player.buffer(); player.buffer();
var session = Lobby.getInstance().createSession(create); var session = Lobby.getInstance().createSession(
create.getSessionName(),
create.getTimeout(),
create.getConfiguration()
);
var uuid = session.join(player, create.getPlayerName()); var uuid = session.join(player, create.getPlayerName());
return Optional.of(new SessionState(session.getUuid(), uuid, create.getPlayerName())); return Optional.of(new SessionState(session.getUuid(), uuid, create.getPlayerName()));
} catch (NackException nack) { } catch (NackException nack) {

Loading…
Cancel
Save