@@ -0,0 +1,26 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link CardMessage} is sent whenever a player plays a card.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class CardMessage extends ObserverMessage {
|
||||
/**
|
||||
* The UUID of the player.
|
||||
*/
|
||||
private final @NotNull UUID player;
|
||||
/**
|
||||
* The card played.
|
||||
*/
|
||||
private final @NotNull Card card;
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link HandMessage} is sent when the player receives information about hit own or another player's hand cards.
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class HandMessage extends ObserverMessage {
|
||||
/**
|
||||
* The UUID of player whose hand cards are sent.
|
||||
*/
|
||||
private final @NotNull UUID player;
|
||||
/**
|
||||
* A list of all the hand cards. May consist only of {@link Card#HIDDEN} if the cars are not visible to the player
|
||||
* receiving this message
|
||||
*/
|
||||
private final @NotNull List<@NotNull Card> hand;
|
||||
|
||||
public HandMessage(@NotNull UUID player, @NotNull List<@NotNull Card> hand) {
|
||||
this.player = player;
|
||||
this.hand = List.copyOf(hand);
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class JugglingMessage extends ObserverMessage {
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import eu.jonahbauer.wizard.common.util.SealedClassTypeAdapterFactory;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract sealed class ObserverMessage permits CardMessage, HandMessage, JugglingMessage, PredictionMessage, ScoreMessage, StateMessage, TrickMessage, TrumpMessage, UserInputMessage {
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(SealedClassTypeAdapterFactory.of(ObserverMessage.class, "Message"))
|
||||
.create();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GSON.toJson(this, ObserverMessage.class);
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link PredictionMessage} is sent after a player makes (or changes) his prediction.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class PredictionMessage extends ObserverMessage {
|
||||
/**
|
||||
* The UUID of the player who made a prediction.
|
||||
*/
|
||||
private final @NotNull UUID player;
|
||||
/**
|
||||
* The prediction.
|
||||
*/
|
||||
private final @Range(from = 0, to = Integer.MAX_VALUE) int prediction;
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link ScoreMessage} is sent at the end of each round and at the end of the game. It contains the number of points
|
||||
* gained by each player in this round or the final result.
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class ScoreMessage extends ObserverMessage {
|
||||
/**
|
||||
* The number of points for each player.
|
||||
*/
|
||||
private final @NotNull Map<@NotNull UUID, @NotNull Integer> points;
|
||||
|
||||
public ScoreMessage(@NotNull Map<@NotNull UUID, @NotNull Integer> points) {
|
||||
this.points = Map.copyOf(points);
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* A {@link StateMessage} is sent whenever the game changes its internal state.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class StateMessage extends ObserverMessage {
|
||||
/**
|
||||
* The name of the new state in snake_case.
|
||||
*/
|
||||
private final String state;
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link TrickMessage} is sent when a trick is completed. It contains the player who won the trick and a list of the
|
||||
* cards played.
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class TrickMessage extends ObserverMessage {
|
||||
/**
|
||||
* The UUID of the player who won the trick.
|
||||
*/
|
||||
private final UUID player;
|
||||
/**
|
||||
* The cards played.
|
||||
*/
|
||||
private final List<Card> cards;
|
||||
|
||||
public TrickMessage(UUID player, List<Card> cards) {
|
||||
this.player = player;
|
||||
this.cards = List.copyOf(cards);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link TrumpMessage} is sent when the trump suit of the current round is (being) determined.
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class TrumpMessage extends ObserverMessage {
|
||||
/**
|
||||
* The {@link Card} that was revealed to determine the {@linkplain Card.Suit trump suit} or {@code null} no cards
|
||||
* were left.
|
||||
*/
|
||||
private final @Nullable Card card;
|
||||
/**
|
||||
* The trump suit or {@code null} is the dealer has yet to decide.
|
||||
*/
|
||||
private final @Nullable Card.Suit suit;
|
||||
|
||||
public TrumpMessage(@Nullable Card card, @Nullable Card.Suit suit) {
|
||||
if (card == null && suit == null) throw new IllegalArgumentException("Card and suit must not both be null");
|
||||
|
||||
this.card = card;
|
||||
this.suit = suit;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package eu.jonahbauer.wizard.common.messages.observer;
|
||||
|
||||
import eu.jonahbauer.wizard.common.messages.player.PickTrumpMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PlayCardMessage;
|
||||
import eu.jonahbauer.wizard.common.messages.player.PredictMessage;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link UserInputMessage} is sent when user input is required.
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class UserInputMessage extends ObserverMessage {
|
||||
/**
|
||||
* The UUID of the player whose input is required.
|
||||
*/
|
||||
private final UUID player;
|
||||
/**
|
||||
* The type of input that is required.
|
||||
*/
|
||||
private final Action action;
|
||||
/**
|
||||
* A timeout in {@link System#currentTimeMillis() UNIX time} after which a default action is taken.
|
||||
*/
|
||||
private final long timeout;
|
||||
|
||||
public enum Action {
|
||||
/**
|
||||
* An action that indicates that a player should make a prediction. A {@link UserInputMessage} with this
|
||||
* {@link UserInputMessage#getAction()} should be responded to with a {@link PredictMessage}.
|
||||
*/
|
||||
MAKE_PREDICTION,
|
||||
/**
|
||||
* An action that indicates that a player should change his a prediction by ±1. A {@link UserInputMessage} with
|
||||
* this {@link UserInputMessage#getAction()} should be responded to with a {@link PredictMessage}.
|
||||
*/
|
||||
CHANGE_PREDICTION,
|
||||
/**
|
||||
* An action that indicates that a player should play a card. A {@link UserInputMessage} with this
|
||||
* {@link UserInputMessage#getAction()} should be responded to with a {@link PlayCardMessage}.
|
||||
*/
|
||||
PLAY_CARD,
|
||||
/**
|
||||
* An action that indicates that a player should pick a trump suit. A {@link UserInputMessage} with this
|
||||
* {@link UserInputMessage#getAction()} should be responded to with a {@link PickTrumpMessage}.
|
||||
*/
|
||||
PICK_TRUMP
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package eu.jonahbauer.wizard.common.messages.player;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class PickTrumpMessage extends PlayerMessage {
|
||||
private final Card.Suit trumpSuit;
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package eu.jonahbauer.wizard.common.messages.player;
|
||||
|
||||
import eu.jonahbauer.wizard.common.model.card.Card;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class PlayCardMessage extends PlayerMessage {
|
||||
private final Card card;
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package eu.jonahbauer.wizard.common.messages.player;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import eu.jonahbauer.wizard.common.util.SealedClassTypeAdapterFactory;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public abstract sealed class PlayerMessage permits PickTrumpMessage, PlayCardMessage, PredictMessage {
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(SealedClassTypeAdapterFactory.of(PlayerMessage.class, "Message"))
|
||||
.create();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return GSON.toJson(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package eu.jonahbauer.wizard.common.messages.player;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public final class PredictMessage extends PlayerMessage {
|
||||
private final int prediction;
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package eu.jonahbauer.wizard.common.model.card;
|
||||
|
||||
public enum Card {
|
||||
HIDDEN,
|
||||
BLUE_1, RED_1, GREEN_1, YELLOW_1,
|
||||
BLUE_2, RED_2, GREEN_2, YELLOW_2,
|
||||
BLUE_3, RED_3, GREEN_3, YELLOW_3,
|
||||
BLUE_4, RED_4, GREEN_4, YELLOW_4,
|
||||
BLUE_5, RED_5, GREEN_5, YELLOW_5,
|
||||
BLUE_6, RED_6, GREEN_6, YELLOW_6,
|
||||
BLUE_7, RED_7, GREEN_7, YELLOW_7,
|
||||
BLUE_8, RED_8, GREEN_8, YELLOW_8,
|
||||
BLUE_9, RED_9, GREEN_9, YELLOW_9,
|
||||
BLUE_10, RED_10, GREEN_10, YELLOW_10,
|
||||
BLUE_11, RED_11, GREEN_11, YELLOW_11,
|
||||
BLUE_12, RED_12, GREEN_12, YELLOW_12,
|
||||
BLUE_13, RED_13, GREEN_13, YELLOW_13,
|
||||
BLUE_WIZARD, RED_WIZARD, GREEN_WIZARD, YELLOW_WIZARD,
|
||||
BLUE_JESTER, RED_JESTER, GREEN_JESTER, YELLOW_JESTER,
|
||||
CHANGELING, CHANGELING_WIZARD, CHANGELING_JESTER,
|
||||
BOMB,
|
||||
WEREWOLF,
|
||||
DRAGON,
|
||||
FAIRY,
|
||||
CLOUD, CLOUD_BLUE, CLOUD_RED, CLOUD_GREEN, CLOUD_YELLOW,
|
||||
JUGGLER, JUGGLER_BLUE, JUGGLER_RED, JUGGLER_GREEN, JUGGLER_YELLOW;
|
||||
|
||||
public enum Suit {
|
||||
NONE, YELLOW, RED, GREEN, BLUE
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
package eu.jonahbauer.wizard.common.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public final class SealedClassTypeAdapterFactory<T> implements TypeAdapterFactory {
|
||||
private final RuntimeTypeAdapterFactory<T> factory;
|
||||
|
||||
public static <T> SealedClassTypeAdapterFactory<T> of(Class<T> clazz) {
|
||||
return new SealedClassTypeAdapterFactory<>(clazz, null);
|
||||
}
|
||||
|
||||
public static <T> SealedClassTypeAdapterFactory<T> of(Class<T> clazz, @Nullable String suffix) {
|
||||
return new SealedClassTypeAdapterFactory<>(clazz, suffix);
|
||||
}
|
||||
|
||||
private SealedClassTypeAdapterFactory(Class<T> clazz, @Nullable String suffix) {
|
||||
factory = RuntimeTypeAdapterFactory.of(clazz);
|
||||
for (Class<?> subclass : clazz.getPermittedSubclasses()) {
|
||||
String name = subclass.getSimpleName();
|
||||
|
||||
// remove suffix
|
||||
if (suffix != null) {
|
||||
if (name.endsWith(suffix)) name = name.substring(0, name.length() - suffix.length());
|
||||
}
|
||||
|
||||
// transform camelCast to snake_case
|
||||
name = name.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase(Locale.ROOT);
|
||||
|
||||
factory.registerSubtype(subclass.asSubclass(clazz), name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> TypeAdapter<S> create(Gson gson, TypeToken<S> type) {
|
||||
return factory.create(gson, type);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user