diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/ScoreOverlay.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/ScoreOverlay.java index 80d4057..14095e2 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/ScoreOverlay.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/ScoreOverlay.java @@ -12,6 +12,8 @@ import java.util.Objects; import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*; import static eu.jonahbauer.wizard.client.libgdx.actions.MyActions.changeParent; +import static eu.jonahbauer.wizard.client.libgdx.screens.GameScreen.PAD_OF_TRUTH_POSITION; +import static eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings.OVERLAY_SHARED_ELEMENT; public class ScoreOverlay extends Overlay { private final PadOfTruth padOfTruth; @@ -36,13 +38,13 @@ public class ScoreOverlay extends Overlay { root.addAction(sequence( run(() -> padOfTruth.setEnabled(false)), parallel( - targeting(padOfTruth, scaleTo(1, 1, AnimationTimings.OVERLAY_SHARED_ELEMENT)), - targeting(padOfTruth, moveTo((WizardGame.WIDTH - padOfTruth.getWidth()) / 2, (WizardGame.HEIGHT - padOfTruth.getHeight()) / 2, AnimationTimings.OVERLAY_SHARED_ELEMENT)) + targeting(padOfTruth, scaleTo(1, 1, OVERLAY_SHARED_ELEMENT)), + targeting(padOfTruth, moveTo((WizardGame.WIDTH - padOfTruth.getWidth()) / 2, (WizardGame.HEIGHT - padOfTruth.getHeight()) / 2, OVERLAY_SHARED_ELEMENT)) ), delay(AnimationTimings.OVERLAY_HOLD), parallel( - targeting(padOfTruth, scaleTo(PadOfTruth.COLLAPSED_SCALE, PadOfTruth.COLLAPSED_SCALE, AnimationTimings.OVERLAY_SHARED_ELEMENT)), - targeting(padOfTruth, moveTo(WizardGame.WIDTH - 10 - PadOfTruth.EXTENDED_WIDTH, 10, AnimationTimings.OVERLAY_SHARED_ELEMENT)) + targeting(padOfTruth, scaleTo(PadOfTruth.COLLAPSED_SCALE, PadOfTruth.COLLAPSED_SCALE, OVERLAY_SHARED_ELEMENT)), + targeting(padOfTruth, moveTo(PAD_OF_TRUTH_POSITION.x, PAD_OF_TRUTH_POSITION.y, OVERLAY_SHARED_ELEMENT)) ), targeting(padOfTruth, changeParent(screen.getContentRoot())), run(() -> padOfTruth.setEnabled(true)), diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/TrumpOverlay.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/TrumpOverlay.java index ed29fd9..0953c0a 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/TrumpOverlay.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/actions/overlay/TrumpOverlay.java @@ -2,7 +2,6 @@ package eu.jonahbauer.wizard.client.libgdx.actions.overlay; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; -import com.badlogic.gdx.scenes.scene2d.actions.ParallelAction; import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; @@ -10,78 +9,19 @@ import eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings; import eu.jonahbauer.wizard.client.libgdx.actions.MyActions; import eu.jonahbauer.wizard.client.libgdx.actors.CardActor; import eu.jonahbauer.wizard.client.libgdx.screens.GameScreen; +import eu.jonahbauer.wizard.client.libgdx.util.CardUtil; import eu.jonahbauer.wizard.common.model.Card; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; import java.util.Objects; import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*; import static eu.jonahbauer.wizard.client.libgdx.actions.MyActions.*; +import static eu.jonahbauer.wizard.client.libgdx.screens.GameScreen.*; +import static eu.jonahbauer.wizard.client.libgdx.util.AnimationTimings.OVERLAY_SHARED_ELEMENT; public class TrumpOverlay extends Overlay { - @SuppressWarnings("RedundantTypeArguments") - private static final Map DEFAULT_SUITES = Map.ofEntries( - Map.entry(Card.BLUE_1, Card.Suit.BLUE), - Map.entry(Card.BLUE_2, Card.Suit.BLUE), - Map.entry(Card.BLUE_3, Card.Suit.BLUE), - Map.entry(Card.BLUE_4, Card.Suit.BLUE), - Map.entry(Card.BLUE_5, Card.Suit.BLUE), - Map.entry(Card.BLUE_6, Card.Suit.BLUE), - Map.entry(Card.BLUE_7, Card.Suit.BLUE), - Map.entry(Card.BLUE_8, Card.Suit.BLUE), - Map.entry(Card.BLUE_9, Card.Suit.BLUE), - Map.entry(Card.BLUE_10, Card.Suit.BLUE), - Map.entry(Card.BLUE_11, Card.Suit.BLUE), - Map.entry(Card.BLUE_12, Card.Suit.BLUE), - Map.entry(Card.BLUE_13, Card.Suit.BLUE), - Map.entry(Card.RED_1, Card.Suit.RED), - Map.entry(Card.RED_2, Card.Suit.RED), - Map.entry(Card.RED_3, Card.Suit.RED), - Map.entry(Card.RED_4, Card.Suit.RED), - Map.entry(Card.RED_5, Card.Suit.RED), - Map.entry(Card.RED_6, Card.Suit.RED), - Map.entry(Card.RED_7, Card.Suit.RED), - Map.entry(Card.RED_8, Card.Suit.RED), - Map.entry(Card.RED_9, Card.Suit.RED), - Map.entry(Card.RED_10, Card.Suit.RED), - Map.entry(Card.RED_11, Card.Suit.RED), - Map.entry(Card.RED_12, Card.Suit.RED), - Map.entry(Card.RED_13, Card.Suit.RED), - Map.entry(Card.GREEN_1, Card.Suit.GREEN), - Map.entry(Card.GREEN_2, Card.Suit.GREEN), - Map.entry(Card.GREEN_3, Card.Suit.GREEN), - Map.entry(Card.GREEN_4, Card.Suit.GREEN), - Map.entry(Card.GREEN_5, Card.Suit.GREEN), - Map.entry(Card.GREEN_6, Card.Suit.GREEN), - Map.entry(Card.GREEN_7, Card.Suit.GREEN), - Map.entry(Card.GREEN_8, Card.Suit.GREEN), - Map.entry(Card.GREEN_9, Card.Suit.GREEN), - Map.entry(Card.GREEN_10, Card.Suit.GREEN), - Map.entry(Card.GREEN_11, Card.Suit.GREEN), - Map.entry(Card.GREEN_12, Card.Suit.GREEN), - Map.entry(Card.GREEN_13, Card.Suit.GREEN), - Map.entry(Card.YELLOW_1, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_2, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_3, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_4, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_5, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_6, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_7, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_8, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_9, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_10, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_11, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_12, Card.Suit.YELLOW), - Map.entry(Card.YELLOW_13, Card.Suit.YELLOW), - Map.entry(Card.RED_JESTER, Card.Suit.NONE), - Map.entry(Card.GREEN_JESTER, Card.Suit.NONE), - Map.entry(Card.BLUE_JESTER, Card.Suit.NONE), - Map.entry(Card.YELLOW_JESTER, Card.Suit.NONE), - Map.entry(Card.BOMB, Card.Suit.NONE), - Map.entry(Card.FAIRY, Card.Suit.NONE) - ); private final @Nullable String player; private final @Nullable Card card; @@ -142,7 +82,7 @@ public class TrumpOverlay extends Overlay { trumpCardActor.setCard(card != null ? card : Card.HIDDEN); } - animateSuit = suit != null && suit != DEFAULT_SUITES.get(card); + animateSuit = suit != null && suit != CardUtil.getDefaultTrumpSuit(card); if (animateSuit) { trumpSuitActor.setRotation(0); trumpSuitActor.setOrigin(0, 0); @@ -186,15 +126,13 @@ public class TrumpOverlay extends Overlay { // animate parallel = parallel(); if (animateSuit) { - parallel.addAction(targeting(trumpSuitActor, rotateTo(-90, AnimationTimings.OVERLAY_SHARED_ELEMENT))); + parallel.addAction(targeting(trumpSuitActor, rotateTo(TRUMP_SUIT_ROTATION, OVERLAY_SHARED_ELEMENT))); parallel.addAction( - targeting(trumpSuitActor, - moveTo(10, 10 + (trumpSuitActor.getHeight() + trumpSuitActor.getWidth()) / 2, AnimationTimings.OVERLAY_SHARED_ELEMENT) - ) + targeting(trumpSuitActor, moveTo(TRUMP_SUIT_POSITION.x, TRUMP_SUIT_POSITION.y, OVERLAY_SHARED_ELEMENT)) ); } if (animateCard) { - parallel.addAction(targeting(trumpCardActor, moveTo(10, 10, AnimationTimings.OVERLAY_SHARED_ELEMENT))); + parallel.addAction(targeting(trumpCardActor, moveTo(TRUMP_CARD_POSITION.x, TRUMP_CARD_POSITION.y, OVERLAY_SHARED_ELEMENT))); } cardAnimation.addAction(parallel); diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java index b2f67c1..d37493c 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/screens/GameScreen.java @@ -40,6 +40,12 @@ public class GameScreen extends WizardScreen { public static final int LAYER_BELOW_OVERLAY = 0; public static final int LAYER_BELOW_MENU = 1; + // positions for externally animated actors + public static final Vector2 TRUMP_CARD_POSITION = new Vector2(10, 10); + public static final Vector2 TRUMP_SUIT_POSITION = new Vector2(10, 10 + (CardActor.PREF_HEIGHT + CardActor.PREF_WIDTH) / 2); + public static final float TRUMP_SUIT_ROTATION = -90; + public static final Vector2 PAD_OF_TRUTH_POSITION = new Vector2(WizardGame.WIDTH - 10 - PadOfTruth.EXTENDED_WIDTH, 10); + @Getter private TextureAtlas atlas; @@ -131,7 +137,7 @@ public class GameScreen extends WizardScreen { messageStack.setTouchable(Touchable.disabled); padOfTruth = new PadOfTruth(skin, new TextureRegionDrawable(atlas.findRegion(GameAtlas.PAD_OF_TRUTH))); - padOfTruth.setPosition(WizardGame.WIDTH - 10 - PadOfTruth.EXTENDED_WIDTH, 10); + padOfTruth.setPosition(PAD_OF_TRUTH_POSITION.x, PAD_OF_TRUTH_POSITION.y); padOfTruth.setOrigin(PadOfTruth.EXTENDED_WIDTH, 0); cardStack = new CardStack(); @@ -620,14 +626,7 @@ public class GameScreen extends WizardScreen { } public void showTrumpOverlay(@Nullable UUID player, @Nullable Card trumpCard, @Nullable Card.Suit trumpSuit) { - if (trumpCardActor == null) { - trumpCardActor = new CardActor(Card.HIDDEN, atlas); - } - - if (trumpSuitActor == null) { - trumpSuitActor = new CardActor(Card.HIDDEN, atlas); - } - + initTrumpCards(); execute(new TrumpOverlay(this, players.get(player), trumpCard, trumpSuit)); } @@ -812,6 +811,16 @@ public class GameScreen extends WizardScreen { return false; } + private void initTrumpCards() { + if (trumpCardActor == null) { + trumpCardActor = new CardActor(Card.HIDDEN, atlas); + } + + if (trumpSuitActor == null) { + trumpSuitActor = new CardActor(Card.HIDDEN, atlas); + } + } + @Getter public enum Seat { FALLBACK(WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT * 0.5f, 0, 0, 0, WizardGame.WIDTH * 0.5f, WizardGame.HEIGHT * 0.5f), diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java index 47de96c..7e5a713 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/Awaiting.java @@ -9,6 +9,8 @@ import java.util.Optional; @Log4j2 public abstract class Awaiting extends BaseState implements ClientState { + private static final int TIMEOUT_MILLIS = 10_000; + @Override public Optional onMessage(Client client, ServerMessage message) { return unexpectedMessage(message); @@ -17,7 +19,7 @@ public abstract class Awaiting extends BaseState implements ClientState { @Override @SneakyThrows public Optional onEnter(Client client) { - client.timeout(this, 10_000); + client.timeout(this, TIMEOUT_MILLIS); return Optional.empty(); } diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java index 28d0432..f0c919c 100644 --- a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/state/AwaitingConnection.java @@ -7,7 +7,7 @@ import lombok.extern.log4j.Log4j2; import java.util.Optional; @Log4j2 -public class AwaitingConnection extends Awaiting { +public final class AwaitingConnection extends Awaiting { @Override public Optional onEnter(Client client) { diff --git a/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/util/CardUtil.java b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/util/CardUtil.java new file mode 100644 index 0000000..c6e8485 --- /dev/null +++ b/wizard-client/wizard-client-libgdx/core/src/main/java/eu/jonahbauer/wizard/client/libgdx/util/CardUtil.java @@ -0,0 +1,75 @@ +package eu.jonahbauer.wizard.client.libgdx.util; + +import eu.jonahbauer.wizard.common.model.Card; +import lombok.experimental.UtilityClass; + +import java.util.Map; + +@UtilityClass +public class CardUtil { + @SuppressWarnings("RedundantTypeArguments") + private static final Map DEFAULT_SUITES = Map.ofEntries( + Map.entry(Card.BLUE_1, Card.Suit.BLUE), + Map.entry(Card.BLUE_2, Card.Suit.BLUE), + Map.entry(Card.BLUE_3, Card.Suit.BLUE), + Map.entry(Card.BLUE_4, Card.Suit.BLUE), + Map.entry(Card.BLUE_5, Card.Suit.BLUE), + Map.entry(Card.BLUE_6, Card.Suit.BLUE), + Map.entry(Card.BLUE_7, Card.Suit.BLUE), + Map.entry(Card.BLUE_8, Card.Suit.BLUE), + Map.entry(Card.BLUE_9, Card.Suit.BLUE), + Map.entry(Card.BLUE_10, Card.Suit.BLUE), + Map.entry(Card.BLUE_11, Card.Suit.BLUE), + Map.entry(Card.BLUE_12, Card.Suit.BLUE), + Map.entry(Card.BLUE_13, Card.Suit.BLUE), + Map.entry(Card.RED_1, Card.Suit.RED), + Map.entry(Card.RED_2, Card.Suit.RED), + Map.entry(Card.RED_3, Card.Suit.RED), + Map.entry(Card.RED_4, Card.Suit.RED), + Map.entry(Card.RED_5, Card.Suit.RED), + Map.entry(Card.RED_6, Card.Suit.RED), + Map.entry(Card.RED_7, Card.Suit.RED), + Map.entry(Card.RED_8, Card.Suit.RED), + Map.entry(Card.RED_9, Card.Suit.RED), + Map.entry(Card.RED_10, Card.Suit.RED), + Map.entry(Card.RED_11, Card.Suit.RED), + Map.entry(Card.RED_12, Card.Suit.RED), + Map.entry(Card.RED_13, Card.Suit.RED), + Map.entry(Card.GREEN_1, Card.Suit.GREEN), + Map.entry(Card.GREEN_2, Card.Suit.GREEN), + Map.entry(Card.GREEN_3, Card.Suit.GREEN), + Map.entry(Card.GREEN_4, Card.Suit.GREEN), + Map.entry(Card.GREEN_5, Card.Suit.GREEN), + Map.entry(Card.GREEN_6, Card.Suit.GREEN), + Map.entry(Card.GREEN_7, Card.Suit.GREEN), + Map.entry(Card.GREEN_8, Card.Suit.GREEN), + Map.entry(Card.GREEN_9, Card.Suit.GREEN), + Map.entry(Card.GREEN_10, Card.Suit.GREEN), + Map.entry(Card.GREEN_11, Card.Suit.GREEN), + Map.entry(Card.GREEN_12, Card.Suit.GREEN), + Map.entry(Card.GREEN_13, Card.Suit.GREEN), + Map.entry(Card.YELLOW_1, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_2, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_3, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_4, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_5, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_6, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_7, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_8, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_9, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_10, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_11, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_12, Card.Suit.YELLOW), + Map.entry(Card.YELLOW_13, Card.Suit.YELLOW), + Map.entry(Card.RED_JESTER, Card.Suit.NONE), + Map.entry(Card.GREEN_JESTER, Card.Suit.NONE), + Map.entry(Card.BLUE_JESTER, Card.Suit.NONE), + Map.entry(Card.YELLOW_JESTER, Card.Suit.NONE), + Map.entry(Card.BOMB, Card.Suit.NONE), + Map.entry(Card.FAIRY, Card.Suit.NONE) + ); + + public Card.Suit getDefaultTrumpSuit(Card card) { + return DEFAULT_SUITES.get(card); + } +} diff --git a/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/SessionJoinedMessage.java b/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/SessionJoinedMessage.java index 0bb311d..23da3fe 100644 --- a/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/SessionJoinedMessage.java +++ b/wizard-common/src/main/java/eu/jonahbauer/wizard/common/messages/server/SessionJoinedMessage.java @@ -34,5 +34,16 @@ public final class SessionJoinedMessage extends ServerMessage implements Respons this.player = player; this.players = List.copyOf(players); this.secret = secret; + + boolean found = false; + for (var playerData : players) { + if (playerData.getUuid().equals(player)) { + found = true; + break; + } + } + if (!found) { + throw new IllegalArgumentException("Player not contained in players."); + } } } diff --git a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java index 0d4dbca..ea1dc97 100644 --- a/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java +++ b/wizard-server/src/main/java/eu/jonahbauer/wizard/server/Lobby.java @@ -21,6 +21,7 @@ public class Lobby { private final Map sessions = new ConcurrentHashMap<>(); private final List players = new ArrayList<>(); + // read lock is required whenever players are read or sessions are modified, write lock is required when players are modified private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private Lobby() {} @@ -79,6 +80,9 @@ public class Lobby { } } + /** + * Adds a player to the lobby. + */ public void join(Player player) { lock.writeLock().lock(); try { @@ -89,6 +93,11 @@ public class Lobby { } } + /** + * Removes a player from the lobby. It is ensured that no further lobby related messages + * ({@link SessionCreatedMessage}, {@link SessionModifiedMessage}, {@link SessionRemovedMessage}) are set to this + * player after the call to this method returns. + */ public void leave(Player player) { lock.writeLock().lock(); try {