921 lines
24 KiB
Java
921 lines
24 KiB
Java
/**
|
|
* Copyright (c) 2012-2020, Andy Janata
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
|
* provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice, this list of conditions
|
|
* and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
|
* conditions and the following disclaimer in the documentation and/or other materials provided
|
|
* with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
|
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
package net.socialgamer.cah;
|
|
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
|
|
import net.socialgamer.cah.data.Game;
|
|
|
|
|
|
/**
|
|
* Constants needed on both the CAH server and client. This file is examined with reflection to
|
|
* produce a Javascript version for the client to use.
|
|
*
|
|
* All of the enums in here take a string in their constructor to define the over-the-wire value to
|
|
* be used to represent that enum value. This allows for verbose names while debugging, and short
|
|
* names to reduce traffic and latency, by only having to change it in one place for both the server
|
|
* and client.
|
|
*
|
|
* @author Andy Janata (ajanata@socialgamer.net)
|
|
*/
|
|
public class Constants {
|
|
|
|
public static final int CHAT_FLOOD_MESSAGE_COUNT = 4;
|
|
public static final int CHAT_FLOOD_TIME = 30 * 1000;
|
|
public static final int CHAT_MAX_LENGTH = 200;
|
|
|
|
/**
|
|
* Enums that implement this interface are valid keys for data returned to clients.
|
|
*/
|
|
public interface ReturnableData {
|
|
}
|
|
|
|
/**
|
|
* Enums that implement this interface have a user-visible string associated with them.
|
|
*
|
|
* There presently is not support for localization, but the name fits.
|
|
*/
|
|
public interface Localizable {
|
|
/**
|
|
* @return The user-visible string that is associated with this enum value.
|
|
*/
|
|
public String getString();
|
|
}
|
|
|
|
/**
|
|
* Enums that implement this interface have two user-visible strings associated with them.
|
|
*
|
|
* There presently is not support for localization, but the name fits.
|
|
*/
|
|
public interface DoubleLocalizable {
|
|
/**
|
|
* @return The first user-visible string that is associated with this enum value.
|
|
*/
|
|
public String getString();
|
|
|
|
/**
|
|
* @return The second user-visible string that is associated with this enum value.
|
|
*/
|
|
public String getString2();
|
|
}
|
|
|
|
/**
|
|
* Reason why a client disconnected.
|
|
*/
|
|
public enum DisconnectReason implements Localizable {
|
|
/**
|
|
* The client was banned by the server administrator.
|
|
*/
|
|
BANNED("B&", "Banned"),
|
|
/**
|
|
* The client made no user-caused requests within the timeout window.
|
|
*/
|
|
IDLE_TIMEOUT("it", "Kicked due to idle"),
|
|
/**
|
|
* The client was kicked by the server administrator.
|
|
*/
|
|
KICKED("k", "Kicked by server administrator"),
|
|
/**
|
|
* The user clicked the "log out" button.
|
|
*/
|
|
MANUAL("man", "Leaving"),
|
|
/**
|
|
* The client failed to make any queries within the timeout window.
|
|
*/
|
|
PING_TIMEOUT("pt", "Ping timeout");
|
|
|
|
private final String reason;
|
|
private final String message;
|
|
|
|
DisconnectReason(final String reason, final String message) {
|
|
this.reason = reason;
|
|
this.message = message;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return reason;
|
|
}
|
|
|
|
@Override
|
|
public String getString() {
|
|
return message;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The next thing the client should do during reconnect phase.
|
|
*
|
|
* Leaving these as longer strings as they are only used once per client.
|
|
*/
|
|
public enum ReconnectNextAction {
|
|
/**
|
|
* The client should load a game as part of the reconnect process.
|
|
*/
|
|
GAME("game"),
|
|
/**
|
|
* There is nothing for the client to reload, perhaps because they were not in any special
|
|
* state, or they are a new client.
|
|
*/
|
|
NONE("none");
|
|
|
|
private final String action;
|
|
|
|
ReconnectNextAction(final String action) {
|
|
this.action = action;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return action;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Valid client request operations.
|
|
*/
|
|
public enum AjaxOperation {
|
|
ADMIN_SET_VERBOSE_LOG("svl"),
|
|
BAN("b"),
|
|
CARDCAST_ADD_CARDSET("cac"),
|
|
CARDCAST_LIST_CARDSETS("clc"),
|
|
CARDCAST_REMOVE_CARDSET("crc"),
|
|
CHANGE_GAME_OPTIONS("cgo"),
|
|
CHAT("c"),
|
|
CREATE_GAME("cg"),
|
|
FIRST_LOAD("fl"),
|
|
GAME_CHAT("GC"),
|
|
GAME_LIST("ggl"),
|
|
/**
|
|
* Get all cards for a particular game: black, hand, and round white cards.
|
|
*/
|
|
GET_CARDS("gc"),
|
|
GET_GAME_INFO("ggi"),
|
|
JOIN_GAME("jg"),
|
|
SPECTATE_GAME("vg"),
|
|
JUDGE_SELECT("js"),
|
|
KICK("K"),
|
|
LEAVE_GAME("lg"),
|
|
LOG_OUT("lo"),
|
|
/**
|
|
* Get the names of all clients connected to the server.
|
|
*/
|
|
NAMES("gn"),
|
|
PLAY_CARD("pc"),
|
|
REGISTER("r"),
|
|
SCORE("SC"),
|
|
START_GAME("sg"),
|
|
STOP_GAME("Sg"),
|
|
WHOIS("Wi");
|
|
|
|
private final String op;
|
|
|
|
AjaxOperation(final String op) {
|
|
this.op = op;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return op;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parameters for client requests.
|
|
*/
|
|
@GoStruct
|
|
public enum AjaxRequest {
|
|
@GoDataType("int")
|
|
CARD_ID("cid"),
|
|
CARDCAST_ID("cci"),
|
|
@GoDataType("bool")
|
|
EMOTE("me"),
|
|
@GoDataType("int")
|
|
GAME_ID("gid"),
|
|
@GoDataType("GameOptionData")
|
|
GAME_OPTIONS("go"),
|
|
ID_CODE("idc"),
|
|
MESSAGE("m"),
|
|
NICKNAME("n"),
|
|
OP("o"),
|
|
PASSWORD("pw"),
|
|
PERSISTENT_ID("pid"),
|
|
@GoDataType("int")
|
|
SERIAL("s"),
|
|
@GoDataType("bool")
|
|
WALL("wall");
|
|
|
|
private final String field;
|
|
|
|
AjaxRequest(final String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return field;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Keys for client request responses.
|
|
*/
|
|
@GoStruct
|
|
public enum AjaxResponse implements ReturnableData {
|
|
@GoDataType("int")
|
|
BLACK_CARD("bc"),
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
CARD_ID(AjaxRequest.CARD_ID),
|
|
@GoDataType("[]CardSetData")
|
|
CARD_SETS("css"),
|
|
CLIENT_NAME("cn"),
|
|
@GoDataType("int64")
|
|
CONNECTED_AT("ca"),
|
|
@GoDataType("bool")
|
|
ERROR("e"),
|
|
ERROR_CODE("ec"),
|
|
// This is explicitly a pointer to the value, and not just the value. We need to be able to tell
|
|
// the difference between game 0, and lack of game id.
|
|
// This could be done with an explicit unmarshaller for the type, and a sentinel value, but that
|
|
// would require significantly more work on the code generation.
|
|
@DuplicationAllowed
|
|
@GoDataType("*int")
|
|
GAME_ID(AjaxRequest.GAME_ID),
|
|
@GoDataType("GameInfo")
|
|
GAME_INFO("gi"),
|
|
@DuplicationAllowed
|
|
@GoDataType("GameOptionData")
|
|
GAME_OPTIONS(AjaxRequest.GAME_OPTIONS),
|
|
GAME_STATE_DESCRIPTION("gss"),
|
|
GAME_PERMALINK("gp"),
|
|
@GoDataType("[]GameInfo")
|
|
GAMES("gl"),
|
|
@GoDataType("bool")
|
|
GAME_CHAT_ENABLED("Gce"),
|
|
@GoDataType("bool")
|
|
GLOBAL_CHAT_ENABLED("gce"),
|
|
@GoDataType("[]int")
|
|
HAND("h"),
|
|
@DuplicationAllowed
|
|
ID_CODE(AjaxRequest.ID_CODE),
|
|
@GoDataType("int64")
|
|
IDLE("idl"),
|
|
IP_ADDRESS("IP"),
|
|
/**
|
|
* Whether this client is reconnecting or not.
|
|
*/
|
|
@GoDataType("bool")
|
|
IN_PROGRESS("ip"),
|
|
@GoDataType("int")
|
|
MAX_GAMES("mg"),
|
|
@GoDataType("[]string")
|
|
NAMES("nl"),
|
|
/**
|
|
* Next thing that should be done in reconnect process. Used once, long string OK.
|
|
*/
|
|
NEXT("next"),
|
|
@DuplicationAllowed
|
|
NICKNAME(AjaxRequest.NICKNAME),
|
|
@DuplicationAllowed
|
|
PERSISTENT_ID(AjaxRequest.PERSISTENT_ID),
|
|
@GoDataType("[]GamePlayerInfo")
|
|
PLAYER_INFO("pi"),
|
|
/**
|
|
* Sigil to display next to user's name.
|
|
*/
|
|
SIGIL("?"),
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
SERIAL(AjaxRequest.SERIAL),
|
|
@GoDataType("int64")
|
|
SERVER_STARTED("SS"),
|
|
SESSION_PERMALINK("sP"),
|
|
USER_PERMALINK("up"),
|
|
@GoDataType("[]int")
|
|
WHITE_CARDS("wc");
|
|
|
|
private final String field;
|
|
|
|
AjaxResponse(final String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
AjaxResponse(final Enum<?> field) {
|
|
this.field = field.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return field;
|
|
}
|
|
}
|
|
|
|
// hmm this just gets dumped into the regular data it looks like
|
|
public enum ErrorInformation implements ReturnableData {
|
|
BLACK_CARDS_PRESENT("bcp"),
|
|
BLACK_CARDS_REQUIRED("bcr"),
|
|
WHITE_CARDS_PRESENT("wcp"),
|
|
WHITE_CARDS_REQUIRED("wcr");
|
|
|
|
private final String code;
|
|
|
|
ErrorInformation(final String code) {
|
|
this.code = code;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return code;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Client request and long poll response errors.
|
|
*/
|
|
public enum ErrorCode implements Localizable {
|
|
ACCESS_DENIED("ad", "Access denied."),
|
|
ALREADY_STARTED("as", "The game has already started."),
|
|
ALREADY_STOPPED("aS", "The game has already stopped."),
|
|
BAD_OP("bo", "Invalid operation."),
|
|
BAD_REQUEST("br", "Bad request."),
|
|
@DuplicationAllowed
|
|
BANNED(DisconnectReason.BANNED, "Banned."),
|
|
CANNOT_JOIN_ANOTHER_GAME("cjag", "You cannot join another game."),
|
|
CAPSLOCK("CL", "Try turning caps lock off."),
|
|
CARDCAST_CANNOT_FIND("ccf", "Cannot find Cardcast deck with given ID. If you just added this"
|
|
+ " deck to Cardcast, wait a few minutes and try again."),
|
|
CARDCAST_INVALID_ID("cii", "Invalid Cardcast ID. Must be exactly 5 characters."),
|
|
DO_NOT_HAVE_CARD("dnhc", "You don't have that card."),
|
|
GAME_FULL("gf", "That game is full. Join another."),
|
|
INVALID_CARD("ic", "Invalid card specified."),
|
|
INVALID_GAME("ig", "Invalid game specified."),
|
|
INVALID_ID_CODE("iid", "Identification code, if provided, must be between 8 and 100 characters,"
|
|
+ " inclusive."),
|
|
/**
|
|
* TODO this probably should be pulled in from a static inside the RegisterHandler.
|
|
*/
|
|
INVALID_NICK("in", "Nickname must contain only upper and lower case letters, " +
|
|
"numbers, or underscores, must be 3 to 30 characters long, and must not start with a " +
|
|
"number."),
|
|
/**
|
|
* TODO this probably should be pulled in from a static inside the ChatHandler.
|
|
*/
|
|
MESSAGE_TOO_LONG("mtl", "Messages cannot be longer than " + CHAT_MAX_LENGTH + " characters."),
|
|
NICK_IN_USE("niu", "Nickname is already in use."),
|
|
NO_CARD_SPECIFIED("ncs", "No card specified."),
|
|
NO_GAME_SPECIFIED("ngs", "No game specified."),
|
|
NO_MSG_SPECIFIED("nms", "No message specified."),
|
|
NO_NICK_SPECIFIED("nns", "No nickname specified."),
|
|
NO_SESSION("ns", "Session not detected. Make sure you have cookies enabled."),
|
|
NO_SUCH_USER("nsu", "No such user."),
|
|
NOT_ADMIN("na", "You are not an administrator."),
|
|
NOT_ENOUGH_CARDS("nec", "You must add card sets containing at least "
|
|
+ Game.MINIMUM_BLACK_CARDS + " black cards and " + Game.MINIMUM_WHITE_CARDS_PER_PLAYER
|
|
+ " times the player limit white cards."),
|
|
NOT_ENOUGH_PLAYERS("nep", "There are not enough players to start the game."),
|
|
NOT_ENOUGH_SPACES("nes", "You must use more words in a message that long."),
|
|
NOT_GAME_HOST("ngh", "Only the game host can do that."),
|
|
NOT_IN_THAT_GAME("nitg", "You are not in that game."),
|
|
NOT_JUDGE("nj", "You are not the judge."),
|
|
NOT_REGISTERED("nr", "Not registered. Refresh the page."),
|
|
NOT_YOUR_TURN("nyt", "It is not your turn to play a card."),
|
|
OP_NOT_SPECIFIED("ons", "Operation not specified."),
|
|
PLAYED_ALL_CARDS("pac", "You already played all the necessary cards!"),
|
|
RESERVED_NICK("rn", "That nick is reserved."),
|
|
REPEAT_MESSAGE("rm",
|
|
"You can't repeat the same message multiple times in a row."),
|
|
REPEATED_WORDS("rW", "You must use more unique words in your message."),
|
|
SERVER_ERROR("serr", "An error occurred on the server."),
|
|
SESSION_EXPIRED("se", "Your session has expired. Refresh the page."),
|
|
TOO_FAST("tf", "You are chatting too fast. Wait a few seconds and try again."),
|
|
TOO_MANY_GAMES("tmg", "There are too many games already in progress. Either join " +
|
|
"an existing game, or wait for one to become available."),
|
|
TOO_MANY_SPECIAL_CHARACTERS("tmsc",
|
|
"You used too many special characters in that message."),
|
|
TOO_MANY_USERS("tmu", "There are too many users connected. "
|
|
+ "<strong><a href='https://pretendyoure.xyz/zy'>Try another server.</a></strong>"),
|
|
WRONG_PASSWORD("wp", "That password is incorrect.");
|
|
|
|
private final String code;
|
|
private final String message;
|
|
|
|
/**
|
|
* @param code
|
|
* Error code to send over the wire to the client.
|
|
* @param message
|
|
* Message the client should display for the error code.
|
|
*/
|
|
ErrorCode(final String code, final String message) {
|
|
this.code = code;
|
|
this.message = message;
|
|
}
|
|
|
|
ErrorCode(final Enum<?> code, final String message) {
|
|
this.code = code.toString();
|
|
this.message = message;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return code;
|
|
}
|
|
|
|
@Override
|
|
public String getString() {
|
|
return message;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Events that can be returned in a long poll response.
|
|
*/
|
|
public enum LongPollEvent {
|
|
@DuplicationAllowed
|
|
BANNED(DisconnectReason.BANNED),
|
|
@DuplicationAllowed
|
|
CARDCAST_ADD_CARDSET(AjaxOperation.CARDCAST_ADD_CARDSET),
|
|
@DuplicationAllowed
|
|
CARDCAST_REMOVE_CARDSET(AjaxOperation.CARDCAST_REMOVE_CARDSET),
|
|
@DuplicationAllowed
|
|
CHAT(AjaxOperation.CHAT),
|
|
FILTERED_CHAT("FC"),
|
|
GAME_BLACK_RESHUFFLE("gbr"),
|
|
GAME_JUDGE_LEFT("gjl"),
|
|
GAME_JUDGE_SKIPPED("gjs"),
|
|
GAME_LIST_REFRESH("glr"),
|
|
GAME_OPTIONS_CHANGED("goc"),
|
|
GAME_PLAYER_INFO_CHANGE("gpic"),
|
|
GAME_PLAYER_JOIN("gpj"),
|
|
GAME_PLAYER_KICKED_IDLE("gpki"),
|
|
GAME_PLAYER_LEAVE("gpl"),
|
|
GAME_PLAYER_SKIPPED("gps"),
|
|
GAME_SPECTATOR_JOIN("gvj"),
|
|
GAME_SPECTATOR_LEAVE("gvl"),
|
|
GAME_ROUND_COMPLETE("grc"),
|
|
GAME_STATE_CHANGE("gsc"),
|
|
GAME_WHITE_RESHUFFLE("gwr"),
|
|
HAND_DEAL("hd"),
|
|
HURRY_UP("hu"),
|
|
@DuplicationAllowed
|
|
KICKED(DisconnectReason.KICKED),
|
|
KICKED_FROM_GAME_IDLE("kfgi"),
|
|
NEW_PLAYER("np"),
|
|
/**
|
|
* There has been no other action to inform the client about in a certain timeframe, so inform
|
|
* the client that we have nothing to inform them so the client doesn't think we went away.
|
|
*/
|
|
NOOP("_"),
|
|
PLAYER_LEAVE("pl");
|
|
|
|
private final String event;
|
|
|
|
LongPollEvent(final String event) {
|
|
this.event = event;
|
|
}
|
|
|
|
LongPollEvent(final Enum<?> event) {
|
|
this.event = event.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return event;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data keys that can be in a long poll response.
|
|
*/
|
|
@GoStruct
|
|
public enum LongPollResponse implements ReturnableData {
|
|
@DuplicationAllowed
|
|
@GoDataType("BlackCardData")
|
|
BLACK_CARD(AjaxResponse.BLACK_CARD),
|
|
CARDCAST_DECK_INFO("cdi"),
|
|
@DuplicationAllowed
|
|
@GoDataType("bool")
|
|
EMOTE(AjaxRequest.EMOTE),
|
|
@DuplicationAllowed
|
|
@GoDataType("bool")
|
|
ERROR(AjaxResponse.ERROR),
|
|
@DuplicationAllowed
|
|
ERROR_CODE(AjaxResponse.ERROR_CODE),
|
|
EVENT("E"),
|
|
/**
|
|
* Player a chat message is from.
|
|
*/
|
|
FROM("f"),
|
|
/**
|
|
* A chat message is from an admin. This is going to be done with IP addresses for now.
|
|
* @deprecated Compare the SIGIL field to Sigil.ADMIN.
|
|
*/
|
|
@Deprecated
|
|
@GoDataType("bool")
|
|
FROM_ADMIN("fa"),
|
|
// This is explicitly a pointer to the value, and not just the value. We need to be able to tell
|
|
// the difference between game 0, and lack of game id.
|
|
// This could be done with an explicit unmarshaller for the type, and a sentinel value, but that
|
|
// would require significantly more work on the code generation.
|
|
@DuplicationAllowed
|
|
@GoDataType("*int")
|
|
GAME_ID(AjaxResponse.GAME_ID),
|
|
@DuplicationAllowed
|
|
@GoDataType("GameInfo")
|
|
GAME_INFO(AjaxResponse.GAME_INFO),
|
|
@DuplicationAllowed
|
|
GAME_PERMALINK(AjaxResponse.GAME_PERMALINK),
|
|
GAME_STATE("gs"),
|
|
@DuplicationAllowed
|
|
@GoDataType("[]WhiteCardData")
|
|
HAND(AjaxResponse.HAND),
|
|
@DuplicationAllowed
|
|
ID_CODE(AjaxRequest.ID_CODE),
|
|
/**
|
|
* The delay until the next game round begins.
|
|
*/
|
|
@GoDataType("int")
|
|
INTERMISSION("i"),
|
|
@DuplicationAllowed
|
|
MESSAGE(AjaxRequest.MESSAGE),
|
|
@DuplicationAllowed
|
|
NICKNAME(AjaxRequest.NICKNAME),
|
|
@GoDataType("int")
|
|
PLAY_TIMER("Pt"),
|
|
@DuplicationAllowed
|
|
@GoDataType("[]GamePlayerInfo")
|
|
PLAYER_INFO(AjaxResponse.PLAYER_INFO),
|
|
/**
|
|
* Reason why a player disconnected.
|
|
*/
|
|
REASON("qr"),
|
|
ROUND_PERMALINK("rP"),
|
|
ROUND_WINNER("rw"),
|
|
/**
|
|
* Sigil to display next to user's name.
|
|
*/
|
|
@DuplicationAllowed
|
|
SIGIL(AjaxResponse.SIGIL),
|
|
@GoDataType("int64")
|
|
TIMESTAMP("ts"),
|
|
@DuplicationAllowed
|
|
@GoDataType("bool")
|
|
WALL(AjaxRequest.WALL),
|
|
@DuplicationAllowed
|
|
@GoDataType("[][]WhiteCardData")
|
|
WHITE_CARDS(AjaxResponse.WHITE_CARDS),
|
|
// This is just the ID of one of the cards played by the winner
|
|
@GoDataType("int")
|
|
WINNING_CARD("WC");
|
|
|
|
private final String field;
|
|
|
|
LongPollResponse(final String field) {
|
|
this.field = field;
|
|
}
|
|
|
|
LongPollResponse(final Enum<?> field) {
|
|
this.field = field.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return field;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User sigils. Displayed before the user's name.
|
|
*/
|
|
public enum Sigil {
|
|
ADMIN("@"), ID_CODE("+"), NORMAL_USER("");
|
|
|
|
private final String sigil;
|
|
|
|
Sigil(final String sigil) {
|
|
this.sigil = sigil;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return sigil;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data fields for white cards.
|
|
*/
|
|
@GoStruct
|
|
public enum WhiteCardData {
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
ID(AjaxRequest.CARD_ID),
|
|
TEXT("T"),
|
|
WATERMARK("W"),
|
|
@GoDataType("bool")
|
|
WRITE_IN("wi");
|
|
|
|
private final String key;
|
|
|
|
WhiteCardData(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
WhiteCardData(final Enum<?> key) {
|
|
this.key = key.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data fields for black cards.
|
|
*/
|
|
@GoStruct
|
|
public enum BlackCardData {
|
|
@GoDataType("int")
|
|
DRAW("D"),
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
ID(WhiteCardData.ID),
|
|
@GoDataType("int")
|
|
PICK("PK"),
|
|
@DuplicationAllowed
|
|
TEXT(WhiteCardData.TEXT),
|
|
@DuplicationAllowed
|
|
WATERMARK(WhiteCardData.WATERMARK);
|
|
|
|
private final String key;
|
|
|
|
BlackCardData(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
BlackCardData(final Enum<?> key) {
|
|
this.key = key.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data fields for card sets.
|
|
*/
|
|
@GoStruct
|
|
public enum CardSetData {
|
|
@GoDataType("bool")
|
|
BASE_DECK("bd"),
|
|
@GoDataType("int")
|
|
BLACK_CARDS_IN_DECK("bcid"),
|
|
CARD_SET_DESCRIPTION("csd"),
|
|
CARD_SET_NAME("csn"),
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
ID(WhiteCardData.ID),
|
|
@GoDataType("int")
|
|
WEIGHT("w"),
|
|
@GoDataType("int")
|
|
WHITE_CARDS_IN_DECK("wcid");
|
|
|
|
private final String key;
|
|
|
|
CardSetData(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
CardSetData(final Enum<?> key) {
|
|
this.key = key.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A game's current state.
|
|
*/
|
|
public enum GameState implements Localizable {
|
|
JUDGING("j", "In Progress"),
|
|
LOBBY("l", "Not Started"),
|
|
PLAYING("p", "In Progress"),
|
|
ROUND_OVER("ro", "In Progress");
|
|
|
|
private final String state;
|
|
private final String message;
|
|
|
|
GameState(final String state, final String message) {
|
|
this.state = state;
|
|
this.message = message;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return state;
|
|
}
|
|
|
|
@Override
|
|
public String getString() {
|
|
return message;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fields for information about a game.
|
|
*/
|
|
@GoStruct
|
|
public enum GameInfo {
|
|
@GoDataType("int64")
|
|
CREATED("gca"),
|
|
HOST("H"),
|
|
@DuplicationAllowed
|
|
@GoDataType("int")
|
|
ID(AjaxRequest.GAME_ID),
|
|
@DuplicationAllowed
|
|
@GoDataType("GameOptionData")
|
|
GAME_OPTIONS(AjaxRequest.GAME_OPTIONS),
|
|
@GoDataType("bool")
|
|
HAS_PASSWORD("hp"),
|
|
@GoDataType("[]string")
|
|
PLAYERS("P"),
|
|
@GoDataType("[]string")
|
|
SPECTATORS("V"),
|
|
STATE("S");
|
|
|
|
private final String key;
|
|
|
|
GameInfo(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
GameInfo(final Enum<?> key) {
|
|
this.key = key.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fields for options about a game.
|
|
*/
|
|
@GoStruct
|
|
public enum GameOptionData {
|
|
@GoDataType("int")
|
|
BLANKS_LIMIT("bl"),
|
|
@DuplicationAllowed
|
|
@GoDataType("[]int")
|
|
CARD_SETS(AjaxResponse.CARD_SETS),
|
|
@DuplicationAllowed
|
|
PASSWORD(AjaxRequest.PASSWORD),
|
|
@GoDataType("int")
|
|
PLAYER_LIMIT("pL"),
|
|
@GoDataType("int")
|
|
SPECTATOR_LIMIT("vL"),
|
|
@GoDataType("int")
|
|
SCORE_LIMIT("sl"),
|
|
TIMER_MULTIPLIER("tm");
|
|
|
|
private final String key;
|
|
|
|
GameOptionData(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
GameOptionData(final Enum<?> key) {
|
|
this.key = key.toString();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Keys for the information about players in a game.
|
|
*/
|
|
@GoStruct
|
|
public enum GamePlayerInfo {
|
|
NAME("N"),
|
|
@GoDataType("int")
|
|
SCORE("sc"),
|
|
STATUS("st");
|
|
|
|
private final String key;
|
|
|
|
GamePlayerInfo(final String key) {
|
|
this.key = key;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return key;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* States that a player in a game can be in. The first client string is displayed in the
|
|
* scoreboard, and the second one is displayed in a banner at the top, telling the user what to
|
|
* do.
|
|
*/
|
|
public enum GamePlayerStatus implements DoubleLocalizable {
|
|
HOST("sh", "Host", "Wait for players then click Start Game."),
|
|
IDLE("si", "", "Waiting for players..."),
|
|
JUDGE("sj", "Card Czar", "You are the Card Czar."),
|
|
JUDGING("sjj", "Selecting", "Select a winning card."),
|
|
PLAYING("sp", "Playing", "Select a card to play."),
|
|
WINNER("sw", "Winner!", "You have won!"),
|
|
SPECTATOR("sv", "Spectator", "You are just spectating.");
|
|
|
|
private final String status;
|
|
private final String message;
|
|
private final String message2;
|
|
|
|
GamePlayerStatus(final String status, final String message, final String message2) {
|
|
this.status = status;
|
|
this.message = message;
|
|
this.message2 = message2;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return status;
|
|
}
|
|
|
|
@Override
|
|
public String getString() {
|
|
return message;
|
|
}
|
|
|
|
@Override
|
|
public String getString2() {
|
|
return message2;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attributes stored in a client session.
|
|
*/
|
|
public class SessionAttribute {
|
|
public static final String USER = "user";
|
|
}
|
|
|
|
/**
|
|
* Mark an enum value as being allowed to be the same as another enum value. Should only be used
|
|
* when another enum's value is directly used as the value. This will prevent the test from
|
|
* flagging it as an invalid reuse.
|
|
*/
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
public @interface DuplicationAllowed {
|
|
}
|
|
|
|
/**
|
|
* Mark an enum to generate a struct for it in the Go output. This would be used for things that
|
|
* describe objects, not a list of valid values for a field.
|
|
*/
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
public @interface GoStruct {
|
|
}
|
|
|
|
/**
|
|
* Mark an enum value as having a specific Go data type. The default (if this annotation is not
|
|
* specified) is string.
|
|
*/
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
public @interface GoDataType {
|
|
String value() default "string";
|
|
}
|
|
}
|