Show more permalinks to users.

When users connect (or reload the page), show a permalink to that session's games as well as a permalink to their entire play history, if they haven't opted out of that tracking. When a game starts, or a player/specator joins a game in progress, show a permalink to that game's rounds.

The "when a game starts" bit required removing the tracking of the 'dealing' state, as there was no other easy way to determine that a game was starting. Nothing actually used that dealing state, so it was harmless to remove. Now, a transition from lobby to playing can be detected as a game start, as opposed to a transition from round over to playing.
This commit is contained in:
Andy Janata 2018-05-30 12:19:53 -07:00
parent 2906ffaa33
commit 1e3351a23b
16 changed files with 509 additions and 295 deletions

View File

@ -43,6 +43,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.REGISTER] = function(data) {
$("#welcome").hide();
$("#canvass").show();
cah.logUserPermalinks(data);
cah.ajax.after_registered();
};
@ -59,6 +60,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.FIRST_LOAD] = function(data) {
if (data[cah.$.AjaxResponse.IN_PROGRESS]) {
cah.ajax.StoreClientInformation_(data);
cah.log.status("You have reconnected as " + cah.nickname);
cah.logUserPermalinks(data);
$("#welcome").hide();
$("#canvass").show();
cah.ajax.after_registered();
@ -66,7 +68,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.FIRST_LOAD] = function(data) {
switch (data[cah.$.AjaxResponse.NEXT]) {
case cah.$.ReconnectNextAction.GAME:
cah.log.status("Reconnecting to game...");
cah.Game.joinGame(data[cah.$.AjaxResponse.GAME_ID]);
cah.Game.joinGame(data[cah.$.AjaxResponse.GAME_ID], data);
cah.ajax.hasAutojoinedGame_ = true;
break;
case cah.$.ReconnectNextAction.NONE:
@ -167,15 +169,13 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.GAME_LIST] = function(data) {
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.JOIN_GAME] = function(data, req) {
cah.Game.joinGame(req[cah.$.AjaxRequest.GAME_ID]);
cah.Game.joinGame(req[cah.$.AjaxRequest.GAME_ID], data);
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.SPECTATE_GAME] = function(data, req) {
cah.Game.joinGame(req[cah.$.AjaxRequest.GAME_ID]);
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.SPECTATE_GAME] = cah.ajax.SuccessHandlers[cah.$.AjaxOperation.JOIN_GAME];
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.CREATE_GAME] = function(data) {
cah.Game.joinGame(data[cah.$.AjaxResponse.GAME_ID]);
cah.Game.joinGame(data[cah.$.AjaxResponse.GAME_ID], data);
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.GET_GAME_INFO] = function(data, req) {

View File

@ -428,3 +428,19 @@ function do_app_resize(chatElement, logElement) {
var bottomHeight = $(window).height() - $("#main").height() - $("#menubar").height() - 29;
logElement.height(bottomHeight - chatElement.height() - 40);
}
cah.logUserPermalinks = function(data) {
var linkMsg = "";
if (cah.$.AjaxResponse.SESSION_PERMALINK in data) {
linkMsg += "<a href='" + data[cah.$.AjaxResponse.SESSION_PERMALINK]
+ "'rel='noopener' target='_blank'>Permanent link to games you play this session.</a> ";
}
if (cah.$.AjaxResponse.USER_PERMALINK in data && !cah.noPersistentId) {
linkMsg += "<a href='"
+ data[cah.$.AjaxResponse.USER_PERMALINK]
+ "'rel='noopener' target='_blank'>Permanent link to every time you've played on this device.</a> ";
}
if ("" != linkMsg) {
cah.log.status(linkMsg, undefined, true);
}
}

View File

@ -2,96 +2,80 @@
cah.$ = {};
cah.$.AjaxOperation = function() {
cah.$.GamePlayerStatus = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.AjaxOperation.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxOperation.NAMES = "gn";
cah.$.AjaxOperation.SCORE = "SC";
cah.$.AjaxOperation.LEAVE_GAME = "lg";
cah.$.AjaxOperation.JOIN_GAME = "jg";
cah.$.AjaxOperation.CHAT = "c";
cah.$.AjaxOperation.GAME_LIST = "ggl";
cah.$.AjaxOperation.CARDCAST_ADD_CARDSET = "cac";
cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS = "clc";
cah.$.AjaxOperation.PLAY_CARD = "pc";
cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
cah.$.AjaxOperation.GET_CARDS = "gc";
cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl";
cah.$.AjaxOperation.REGISTER = "r";
cah.$.AjaxOperation.CARDCAST_REMOVE_CARDSET = "crc";
cah.$.AjaxOperation.WHOIS = "Wi";
cah.$.AjaxOperation.KICK = "K";
cah.$.AjaxOperation.FIRST_LOAD = "fl";
cah.$.AjaxOperation.START_GAME = "sg";
cah.$.AjaxOperation.LOG_OUT = "lo";
cah.$.AjaxOperation.BAN = "b";
cah.$.AjaxOperation.CREATE_GAME = "cg";
cah.$.AjaxOperation.STOP_GAME = "Sg";
cah.$.AjaxOperation.GAME_CHAT = "GC";
cah.$.AjaxOperation.SPECTATE_GAME = "vg";
cah.$.AjaxOperation.JUDGE_SELECT = "js";
cah.$.GamePlayerStatus.prototype.dummyForAutocomplete = undefined;
cah.$.GamePlayerStatus.SPECTATOR = "sv";
cah.$.GamePlayerStatus.WINNER = "sw";
cah.$.GamePlayerStatus.IDLE = "si";
cah.$.GamePlayerStatus.HOST = "sh";
cah.$.GamePlayerStatus.JUDGING = "sjj";
cah.$.GamePlayerStatus.JUDGE = "sj";
cah.$.GamePlayerStatus.PLAYING = "sp";
cah.$.GamePlayerStatus_msg = {};
cah.$.GamePlayerStatus_msg['sjj'] = "Selecting";
cah.$.GamePlayerStatus_msg['sv'] = "Spectator";
cah.$.GamePlayerStatus_msg['sw'] = "Winner!";
cah.$.GamePlayerStatus_msg['sh'] = "Host";
cah.$.GamePlayerStatus_msg['si'] = "";
cah.$.GamePlayerStatus_msg['sj'] = "Card Czar";
cah.$.GamePlayerStatus_msg['sp'] = "Playing";
cah.$.GamePlayerStatus_msg_2 = {};
cah.$.GamePlayerStatus_msg_2['sjj'] = "Select a winning card.";
cah.$.GamePlayerStatus_msg_2['sv'] = "You are just spectating.";
cah.$.GamePlayerStatus_msg_2['sw'] = "You have won!";
cah.$.GamePlayerStatus_msg_2['sh'] = "Wait for players then click Start Game.";
cah.$.GamePlayerStatus_msg_2['si'] = "Waiting for players...";
cah.$.GamePlayerStatus_msg_2['sj'] = "You are the Card Czar.";
cah.$.GamePlayerStatus_msg_2['sp'] = "Select a card to play.";
cah.$.AjaxRequest = function() {
cah.$.GamePlayerInfo = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.AjaxRequest.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxRequest.SERIAL = "s";
cah.$.AjaxRequest.OP = "o";
cah.$.AjaxRequest.WALL = "wall";
cah.$.AjaxRequest.PERSISTENT_ID = "pid";
cah.$.AjaxRequest.EMOTE = "me";
cah.$.AjaxRequest.CARDCAST_ID = "cci";
cah.$.AjaxRequest.GAME_ID = "gid";
cah.$.AjaxRequest.GAME_OPTIONS = "go";
cah.$.AjaxRequest.MESSAGE = "m";
cah.$.AjaxRequest.NICKNAME = "n";
cah.$.AjaxRequest.PASSWORD = "pw";
cah.$.AjaxRequest.CARD_ID = "cid";
cah.$.AjaxRequest.ID_CODE = "idc";
cah.$.GamePlayerInfo.prototype.dummyForAutocomplete = undefined;
cah.$.GamePlayerInfo.STATUS = "st";
cah.$.GamePlayerInfo.SCORE = "sc";
cah.$.GamePlayerInfo.NAME = "N";
cah.$.AjaxResponse = function() {
cah.$.GameOptionData = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.AjaxResponse.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxResponse.NAMES = "nl";
cah.$.AjaxResponse.CLIENT_NAME = "cn";
cah.$.AjaxResponse.PLAYER_INFO = "pi";
cah.$.AjaxResponse.CONNECTED_AT = "ca";
cah.$.AjaxResponse.WHITE_CARDS = "wc";
cah.$.AjaxResponse.HAND = "h";
cah.$.AjaxResponse.ERROR_CODE = "ec";
cah.$.AjaxResponse.SERVER_STARTED = "SS";
cah.$.AjaxResponse.NEXT = "next";
cah.$.AjaxResponse.GAME_INFO = "gi";
cah.$.AjaxResponse.ERROR = "e";
cah.$.AjaxResponse.GAME_STATE_DESCRIPTION = "gss";
cah.$.AjaxResponse.ID_CODE = "idc";
cah.$.AjaxResponse.CARD_SETS = "css";
cah.$.AjaxResponse.SERIAL = "s";
cah.$.AjaxResponse.PERSISTENT_ID = "pid";
cah.$.AjaxResponse.GAMES = "gl";
cah.$.AjaxResponse.SIGIL = "?";
cah.$.AjaxResponse.GAME_ID = "gid";
cah.$.AjaxResponse.MAX_GAMES = "mg";
cah.$.AjaxResponse.IN_PROGRESS = "ip";
cah.$.AjaxResponse.GAME_OPTIONS = "go";
cah.$.AjaxResponse.NICKNAME = "n";
cah.$.AjaxResponse.BLACK_CARD = "bc";
cah.$.AjaxResponse.IDLE = "idl";
cah.$.AjaxResponse.CARD_ID = "cid";
cah.$.AjaxResponse.IP_ADDRESS = "IP";
cah.$.GameOptionData.prototype.dummyForAutocomplete = undefined;
cah.$.GameOptionData.TIMER_MULTIPLIER = "tm";
cah.$.GameOptionData.PASSWORD = "pw";
cah.$.GameOptionData.SPECTATOR_LIMIT = "vL";
cah.$.GameOptionData.SCORE_LIMIT = "sl";
cah.$.GameOptionData.BLANKS_LIMIT = "bl";
cah.$.GameOptionData.PLAYER_LIMIT = "pL";
cah.$.GameOptionData.CARD_SETS = "css";
cah.$.BlackCardData = function() {
cah.$.GameInfo = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.BlackCardData.prototype.dummyForAutocomplete = undefined;
cah.$.BlackCardData.DRAW = "D";
cah.$.BlackCardData.PICK = "PK";
cah.$.BlackCardData.TEXT = "T";
cah.$.BlackCardData.ID = "cid";
cah.$.BlackCardData.WATERMARK = "W";
cah.$.GameInfo.prototype.dummyForAutocomplete = undefined;
cah.$.GameInfo.GAME_OPTIONS = "go";
cah.$.GameInfo.CREATED = "gca";
cah.$.GameInfo.PLAYERS = "P";
cah.$.GameInfo.SPECTATORS = "V";
cah.$.GameInfo.HOST = "H";
cah.$.GameInfo.STATE = "S";
cah.$.GameInfo.ID = "gid";
cah.$.GameInfo.HAS_PASSWORD = "hp";
cah.$.GameState = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GameState.prototype.dummyForAutocomplete = undefined;
cah.$.GameState.ROUND_OVER = "ro";
cah.$.GameState.LOBBY = "l";
cah.$.GameState.JUDGING = "j";
cah.$.GameState.PLAYING = "p";
cah.$.GameState_msg = {};
cah.$.GameState_msg['p'] = "In Progress";
cah.$.GameState_msg['j'] = "In Progress";
cah.$.GameState_msg['l'] = "Not Started";
cah.$.GameState_msg['ro'] = "In Progress";
cah.$.CardSetData = function() {
// Dummy constructor to make Eclipse auto-complete.
@ -105,21 +89,96 @@ cah.$.CardSetData.BASE_DECK = "bd";
cah.$.CardSetData.ID = "cid";
cah.$.CardSetData.WEIGHT = "w";
cah.$.DisconnectReason = function() {
cah.$.BlackCardData = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.DisconnectReason.prototype.dummyForAutocomplete = undefined;
cah.$.DisconnectReason.PING_TIMEOUT = "pt";
cah.$.DisconnectReason.BANNED = "B&";
cah.$.DisconnectReason.IDLE_TIMEOUT = "it";
cah.$.DisconnectReason.KICKED = "k";
cah.$.DisconnectReason.MANUAL = "man";
cah.$.DisconnectReason_msg = {};
cah.$.DisconnectReason_msg['B&'] = "Banned";
cah.$.DisconnectReason_msg['pt'] = "Ping timeout";
cah.$.DisconnectReason_msg['it'] = "Kicked due to idle";
cah.$.DisconnectReason_msg['k'] = "Kicked by server administrator";
cah.$.DisconnectReason_msg['man'] = "Leaving";
cah.$.BlackCardData.prototype.dummyForAutocomplete = undefined;
cah.$.BlackCardData.DRAW = "D";
cah.$.BlackCardData.PICK = "PK";
cah.$.BlackCardData.TEXT = "T";
cah.$.BlackCardData.ID = "cid";
cah.$.BlackCardData.WATERMARK = "W";
cah.$.WhiteCardData = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.WhiteCardData.prototype.dummyForAutocomplete = undefined;
cah.$.WhiteCardData.WRITE_IN = "wi";
cah.$.WhiteCardData.TEXT = "T";
cah.$.WhiteCardData.ID = "cid";
cah.$.WhiteCardData.WATERMARK = "W";
cah.$.Sigil = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.Sigil.prototype.dummyForAutocomplete = undefined;
cah.$.Sigil.NORMAL_USER = "";
cah.$.Sigil.ADMIN = "@";
cah.$.Sigil.ID_CODE = "+";
cah.$.LongPollResponse = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.LongPollResponse.prototype.dummyForAutocomplete = undefined;
cah.$.LongPollResponse.PLAY_TIMER = "Pt";
cah.$.LongPollResponse.PLAYER_INFO = "pi";
cah.$.LongPollResponse.FROM = "f";
cah.$.LongPollResponse.WHITE_CARDS = "wc";
cah.$.LongPollResponse.EVENT = "E";
cah.$.LongPollResponse.HAND = "h";
cah.$.LongPollResponse.ERROR_CODE = "ec";
cah.$.LongPollResponse.MESSAGE = "m";
cah.$.LongPollResponse.WINNING_CARD = "WC";
cah.$.LongPollResponse.FROM_ADMIN = "fa";
cah.$.LongPollResponse.TIMESTAMP = "ts";
cah.$.LongPollResponse.GAME_INFO = "gi";
cah.$.LongPollResponse.ERROR = "e";
cah.$.LongPollResponse.ID_CODE = "idc";
cah.$.LongPollResponse.REASON = "qr";
cah.$.LongPollResponse.WALL = "wall";
cah.$.LongPollResponse.ROUND_WINNER = "rw";
cah.$.LongPollResponse.SIGIL = "?";
cah.$.LongPollResponse.EMOTE = "me";
cah.$.LongPollResponse.CARDCAST_DECK_INFO = "cdi";
cah.$.LongPollResponse.GAME_ID = "gid";
cah.$.LongPollResponse.ROUND_PERMALINK = "rP";
cah.$.LongPollResponse.NICKNAME = "n";
cah.$.LongPollResponse.BLACK_CARD = "bc";
cah.$.LongPollResponse.GAME_PERMALINK = "gp";
cah.$.LongPollResponse.GAME_STATE = "gs";
cah.$.LongPollResponse.INTERMISSION = "i";
cah.$.LongPollEvent = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.LongPollEvent.prototype.dummyForAutocomplete = undefined;
cah.$.LongPollEvent.GAME_ROUND_COMPLETE = "grc";
cah.$.LongPollEvent.BANNED = "B&";
cah.$.LongPollEvent.NOOP = "_";
cah.$.LongPollEvent.CHAT = "c";
cah.$.LongPollEvent.GAME_PLAYER_INFO_CHANGE = "gpic";
cah.$.LongPollEvent.HAND_DEAL = "hd";
cah.$.LongPollEvent.CARDCAST_ADD_CARDSET = "cac";
cah.$.LongPollEvent.PLAYER_LEAVE = "pl";
cah.$.LongPollEvent.GAME_BLACK_RESHUFFLE = "gbr";
cah.$.LongPollEvent.GAME_JUDGE_SKIPPED = "gjs";
cah.$.LongPollEvent.GAME_LIST_REFRESH = "glr";
cah.$.LongPollEvent.NEW_PLAYER = "np";
cah.$.LongPollEvent.GAME_PLAYER_SKIPPED = "gps";
cah.$.LongPollEvent.GAME_PLAYER_JOIN = "gpj";
cah.$.LongPollEvent.GAME_WHITE_RESHUFFLE = "gwr";
cah.$.LongPollEvent.CARDCAST_REMOVE_CARDSET = "crc";
cah.$.LongPollEvent.GAME_OPTIONS_CHANGED = "goc";
cah.$.LongPollEvent.GAME_PLAYER_KICKED_IDLE = "gpki";
cah.$.LongPollEvent.GAME_SPECTATOR_LEAVE = "gvl";
cah.$.LongPollEvent.GAME_PLAYER_LEAVE = "gpl";
cah.$.LongPollEvent.GAME_SPECTATOR_JOIN = "gvj";
cah.$.LongPollEvent.HURRY_UP = "hu";
cah.$.LongPollEvent.GAME_JUDGE_LEFT = "gjl";
cah.$.LongPollEvent.KICKED = "k";
cah.$.LongPollEvent.KICKED_FROM_GAME_IDLE = "kfgi";
cah.$.LongPollEvent.FILTERED_CHAT = "FC";
cah.$.LongPollEvent.GAME_STATE_CHANGE = "gsc";
cah.$.ErrorCode = function() {
// Dummy constructor to make Eclipse auto-complete.
@ -224,145 +283,90 @@ cah.$.ErrorInformation.WHITE_CARDS_REQUIRED = "wcr";
cah.$.ErrorInformation.BLACK_CARDS_REQUIRED = "bcr";
cah.$.ErrorInformation.BLACK_CARDS_PRESENT = "bcp";
cah.$.GameInfo = function() {
cah.$.AjaxResponse = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GameInfo.prototype.dummyForAutocomplete = undefined;
cah.$.GameInfo.GAME_OPTIONS = "go";
cah.$.GameInfo.CREATED = "gca";
cah.$.GameInfo.PLAYERS = "P";
cah.$.GameInfo.SPECTATORS = "V";
cah.$.GameInfo.HOST = "H";
cah.$.GameInfo.STATE = "S";
cah.$.GameInfo.ID = "gid";
cah.$.GameInfo.HAS_PASSWORD = "hp";
cah.$.AjaxResponse.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxResponse.NAMES = "nl";
cah.$.AjaxResponse.CLIENT_NAME = "cn";
cah.$.AjaxResponse.PLAYER_INFO = "pi";
cah.$.AjaxResponse.CONNECTED_AT = "ca";
cah.$.AjaxResponse.WHITE_CARDS = "wc";
cah.$.AjaxResponse.HAND = "h";
cah.$.AjaxResponse.ERROR_CODE = "ec";
cah.$.AjaxResponse.GLOBAL_CHAT_ENABLED = "gce";
cah.$.AjaxResponse.SERVER_STARTED = "SS";
cah.$.AjaxResponse.NEXT = "next";
cah.$.AjaxResponse.GAME_INFO = "gi";
cah.$.AjaxResponse.ERROR = "e";
cah.$.AjaxResponse.GAME_STATE_DESCRIPTION = "gss";
cah.$.AjaxResponse.ID_CODE = "idc";
cah.$.AjaxResponse.CARD_SETS = "css";
cah.$.AjaxResponse.SERIAL = "s";
cah.$.AjaxResponse.PERSISTENT_ID = "pid";
cah.$.AjaxResponse.USER_PERMALINK = "up";
cah.$.AjaxResponse.GAMES = "gl";
cah.$.AjaxResponse.SIGIL = "?";
cah.$.AjaxResponse.GAME_ID = "gid";
cah.$.AjaxResponse.MAX_GAMES = "mg";
cah.$.AjaxResponse.IN_PROGRESS = "ip";
cah.$.AjaxResponse.GAME_OPTIONS = "go";
cah.$.AjaxResponse.NICKNAME = "n";
cah.$.AjaxResponse.BLACK_CARD = "bc";
cah.$.AjaxResponse.GAME_PERMALINK = "gp";
cah.$.AjaxResponse.IDLE = "idl";
cah.$.AjaxResponse.CARD_ID = "cid";
cah.$.AjaxResponse.IP_ADDRESS = "IP";
cah.$.AjaxResponse.SESSION_PERMALINK = "sP";
cah.$.GameOptionData = function() {
cah.$.AjaxRequest = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GameOptionData.prototype.dummyForAutocomplete = undefined;
cah.$.GameOptionData.TIMER_MULTIPLIER = "tm";
cah.$.GameOptionData.PASSWORD = "pw";
cah.$.GameOptionData.SPECTATOR_LIMIT = "vL";
cah.$.GameOptionData.SCORE_LIMIT = "sl";
cah.$.GameOptionData.BLANKS_LIMIT = "bl";
cah.$.GameOptionData.PLAYER_LIMIT = "pL";
cah.$.GameOptionData.CARD_SETS = "css";
cah.$.AjaxRequest.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxRequest.SERIAL = "s";
cah.$.AjaxRequest.OP = "o";
cah.$.AjaxRequest.WALL = "wall";
cah.$.AjaxRequest.PERSISTENT_ID = "pid";
cah.$.AjaxRequest.EMOTE = "me";
cah.$.AjaxRequest.CARDCAST_ID = "cci";
cah.$.AjaxRequest.GAME_ID = "gid";
cah.$.AjaxRequest.GAME_OPTIONS = "go";
cah.$.AjaxRequest.MESSAGE = "m";
cah.$.AjaxRequest.NICKNAME = "n";
cah.$.AjaxRequest.PASSWORD = "pw";
cah.$.AjaxRequest.CARD_ID = "cid";
cah.$.AjaxRequest.ID_CODE = "idc";
cah.$.GamePlayerInfo = function() {
cah.$.AjaxOperation = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GamePlayerInfo.prototype.dummyForAutocomplete = undefined;
cah.$.GamePlayerInfo.STATUS = "st";
cah.$.GamePlayerInfo.SCORE = "sc";
cah.$.GamePlayerInfo.NAME = "N";
cah.$.GamePlayerStatus = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GamePlayerStatus.prototype.dummyForAutocomplete = undefined;
cah.$.GamePlayerStatus.SPECTATOR = "sv";
cah.$.GamePlayerStatus.WINNER = "sw";
cah.$.GamePlayerStatus.IDLE = "si";
cah.$.GamePlayerStatus.HOST = "sh";
cah.$.GamePlayerStatus.JUDGING = "sjj";
cah.$.GamePlayerStatus.JUDGE = "sj";
cah.$.GamePlayerStatus.PLAYING = "sp";
cah.$.GamePlayerStatus_msg = {};
cah.$.GamePlayerStatus_msg['sjj'] = "Selecting";
cah.$.GamePlayerStatus_msg['sv'] = "Spectator";
cah.$.GamePlayerStatus_msg['sw'] = "Winner!";
cah.$.GamePlayerStatus_msg['sh'] = "Host";
cah.$.GamePlayerStatus_msg['si'] = "";
cah.$.GamePlayerStatus_msg['sj'] = "Card Czar";
cah.$.GamePlayerStatus_msg['sp'] = "Playing";
cah.$.GamePlayerStatus_msg_2 = {};
cah.$.GamePlayerStatus_msg_2['sjj'] = "Select a winning card.";
cah.$.GamePlayerStatus_msg_2['sv'] = "You are just spectating.";
cah.$.GamePlayerStatus_msg_2['sw'] = "You have won!";
cah.$.GamePlayerStatus_msg_2['sh'] = "Wait for players then click Start Game.";
cah.$.GamePlayerStatus_msg_2['si'] = "Waiting for players...";
cah.$.GamePlayerStatus_msg_2['sj'] = "You are the Card Czar.";
cah.$.GamePlayerStatus_msg_2['sp'] = "Select a card to play.";
cah.$.GameState = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.GameState.prototype.dummyForAutocomplete = undefined;
cah.$.GameState.ROUND_OVER = "ro";
cah.$.GameState.LOBBY = "l";
cah.$.GameState.DEALING = "d";
cah.$.GameState.JUDGING = "j";
cah.$.GameState.PLAYING = "p";
cah.$.GameState_msg = {};
cah.$.GameState_msg['p'] = "In Progress";
cah.$.GameState_msg['d'] = "In Progress";
cah.$.GameState_msg['j'] = "In Progress";
cah.$.GameState_msg['l'] = "Not Started";
cah.$.GameState_msg['ro'] = "In Progress";
cah.$.LongPollEvent = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.LongPollEvent.prototype.dummyForAutocomplete = undefined;
cah.$.LongPollEvent.GAME_ROUND_COMPLETE = "grc";
cah.$.LongPollEvent.BANNED = "B&";
cah.$.LongPollEvent.NOOP = "_";
cah.$.LongPollEvent.CHAT = "c";
cah.$.LongPollEvent.GAME_PLAYER_INFO_CHANGE = "gpic";
cah.$.LongPollEvent.HAND_DEAL = "hd";
cah.$.LongPollEvent.CARDCAST_ADD_CARDSET = "cac";
cah.$.LongPollEvent.PLAYER_LEAVE = "pl";
cah.$.LongPollEvent.GAME_BLACK_RESHUFFLE = "gbr";
cah.$.LongPollEvent.GAME_JUDGE_SKIPPED = "gjs";
cah.$.LongPollEvent.GAME_LIST_REFRESH = "glr";
cah.$.LongPollEvent.NEW_PLAYER = "np";
cah.$.LongPollEvent.GAME_PLAYER_SKIPPED = "gps";
cah.$.LongPollEvent.GAME_PLAYER_JOIN = "gpj";
cah.$.LongPollEvent.GAME_WHITE_RESHUFFLE = "gwr";
cah.$.LongPollEvent.CARDCAST_REMOVE_CARDSET = "crc";
cah.$.LongPollEvent.GAME_OPTIONS_CHANGED = "goc";
cah.$.LongPollEvent.GAME_PLAYER_KICKED_IDLE = "gpki";
cah.$.LongPollEvent.GAME_SPECTATOR_LEAVE = "gvl";
cah.$.LongPollEvent.GAME_PLAYER_LEAVE = "gpl";
cah.$.LongPollEvent.GAME_SPECTATOR_JOIN = "gvj";
cah.$.LongPollEvent.HURRY_UP = "hu";
cah.$.LongPollEvent.GAME_JUDGE_LEFT = "gjl";
cah.$.LongPollEvent.KICKED = "k";
cah.$.LongPollEvent.KICKED_FROM_GAME_IDLE = "kfgi";
cah.$.LongPollEvent.FILTERED_CHAT = "FC";
cah.$.LongPollEvent.GAME_STATE_CHANGE = "gsc";
cah.$.LongPollResponse = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.LongPollResponse.prototype.dummyForAutocomplete = undefined;
cah.$.LongPollResponse.PLAY_TIMER = "Pt";
cah.$.LongPollResponse.PLAYER_INFO = "pi";
cah.$.LongPollResponse.FROM = "f";
cah.$.LongPollResponse.WHITE_CARDS = "wc";
cah.$.LongPollResponse.EVENT = "E";
cah.$.LongPollResponse.HAND = "h";
cah.$.LongPollResponse.ERROR_CODE = "ec";
cah.$.LongPollResponse.MESSAGE = "m";
cah.$.LongPollResponse.WINNING_CARD = "WC";
cah.$.LongPollResponse.FROM_ADMIN = "fa";
cah.$.LongPollResponse.TIMESTAMP = "ts";
cah.$.LongPollResponse.GAME_INFO = "gi";
cah.$.LongPollResponse.ERROR = "e";
cah.$.LongPollResponse.ID_CODE = "idc";
cah.$.LongPollResponse.REASON = "qr";
cah.$.LongPollResponse.WALL = "wall";
cah.$.LongPollResponse.ROUND_WINNER = "rw";
cah.$.LongPollResponse.SIGIL = "?";
cah.$.LongPollResponse.EMOTE = "me";
cah.$.LongPollResponse.CARDCAST_DECK_INFO = "cdi";
cah.$.LongPollResponse.GAME_ID = "gid";
cah.$.LongPollResponse.ROUND_PERMALINK = "rP";
cah.$.LongPollResponse.NICKNAME = "n";
cah.$.LongPollResponse.BLACK_CARD = "bc";
cah.$.LongPollResponse.GAME_STATE = "gs";
cah.$.LongPollResponse.INTERMISSION = "i";
cah.$.AjaxOperation.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxOperation.NAMES = "gn";
cah.$.AjaxOperation.SCORE = "SC";
cah.$.AjaxOperation.LEAVE_GAME = "lg";
cah.$.AjaxOperation.JOIN_GAME = "jg";
cah.$.AjaxOperation.CHAT = "c";
cah.$.AjaxOperation.GAME_LIST = "ggl";
cah.$.AjaxOperation.CARDCAST_ADD_CARDSET = "cac";
cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS = "clc";
cah.$.AjaxOperation.PLAY_CARD = "pc";
cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
cah.$.AjaxOperation.GET_CARDS = "gc";
cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl";
cah.$.AjaxOperation.REGISTER = "r";
cah.$.AjaxOperation.CARDCAST_REMOVE_CARDSET = "crc";
cah.$.AjaxOperation.WHOIS = "Wi";
cah.$.AjaxOperation.KICK = "K";
cah.$.AjaxOperation.FIRST_LOAD = "fl";
cah.$.AjaxOperation.START_GAME = "sg";
cah.$.AjaxOperation.LOG_OUT = "lo";
cah.$.AjaxOperation.BAN = "b";
cah.$.AjaxOperation.CREATE_GAME = "cg";
cah.$.AjaxOperation.STOP_GAME = "Sg";
cah.$.AjaxOperation.GAME_CHAT = "GC";
cah.$.AjaxOperation.SPECTATE_GAME = "vg";
cah.$.AjaxOperation.JUDGE_SELECT = "js";
cah.$.ReconnectNextAction = function() {
// Dummy constructor to make Eclipse auto-complete.
@ -371,20 +375,19 @@ cah.$.ReconnectNextAction.prototype.dummyForAutocomplete = undefined;
cah.$.ReconnectNextAction.GAME = "game";
cah.$.ReconnectNextAction.NONE = "none";
cah.$.Sigil = function() {
cah.$.DisconnectReason = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.Sigil.prototype.dummyForAutocomplete = undefined;
cah.$.Sigil.NORMAL_USER = "";
cah.$.Sigil.ADMIN = "@";
cah.$.Sigil.ID_CODE = "+";
cah.$.WhiteCardData = function() {
// Dummy constructor to make Eclipse auto-complete.
};
cah.$.WhiteCardData.prototype.dummyForAutocomplete = undefined;
cah.$.WhiteCardData.WRITE_IN = "wi";
cah.$.WhiteCardData.TEXT = "T";
cah.$.WhiteCardData.ID = "cid";
cah.$.WhiteCardData.WATERMARK = "W";
cah.$.DisconnectReason.prototype.dummyForAutocomplete = undefined;
cah.$.DisconnectReason.PING_TIMEOUT = "pt";
cah.$.DisconnectReason.BANNED = "B&";
cah.$.DisconnectReason.IDLE_TIMEOUT = "it";
cah.$.DisconnectReason.KICKED = "k";
cah.$.DisconnectReason.MANUAL = "man";
cah.$.DisconnectReason_msg = {};
cah.$.DisconnectReason_msg['B&'] = "Banned";
cah.$.DisconnectReason_msg['pt'] = "Ping timeout";
cah.$.DisconnectReason_msg['it'] = "Kicked due to idle";
cah.$.DisconnectReason_msg['k'] = "Kicked by server administrator";
cah.$.DisconnectReason_msg['man'] = "Leaving";

View File

@ -321,8 +321,10 @@ cah.Game = function(id) {
*
* @param {Number}
* gameId The game id.
* @param {Object}
* data The data returned by the server.
*/
cah.Game.joinGame = function(gameId) {
cah.Game.joinGame = function(gameId, data) {
cah.Ajax.build(cah.$.AjaxOperation.GET_GAME_INFO).withGameId(gameId).run();
cah.Ajax.build(cah.$.AjaxOperation.GET_CARDS).withGameId(gameId).run();
cah.Ajax.build(cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS).withGameId(gameId).run();
@ -330,10 +332,25 @@ cah.Game.joinGame = function(gameId) {
var game = new cah.Game(gameId);
cah.currentGames[gameId] = game;
game.insertIntoDocument();
game.showGamePermalink_(data);
cah.updateHash('game=' + gameId);
};
/**
* Show the permanent link to this game, if it is in the provider server data.
*
* @param {Object}
* data The data returned by the server, from either an AJAX call or an long poll response.
*/
cah.Game.prototype.showGamePermalink_ = function(data) {
if (cah.$.AjaxResponse.GAME_PERMALINK in data) {
cah.log.status_with_game(this, "<a href='" + data[cah.$.AjaxResponse.GAME_PERMALINK] +
"' rel='noopener' target='_blank'>Permanent link to this game's rounds.</a>", undefined,
true);
}
}
/**
* Toggle showing the previous round result.
*
@ -1405,6 +1422,7 @@ cah.Game.prototype.stateChange = function(data) {
this.hideOptions_();
this.refreshGameStatus();
this.setBlackCard(data[cah.$.LongPollResponse.BLACK_CARD]);
this.showGamePermalink_(data);
break;
case cah.$.GameState.JUDGING:

View File

@ -86,17 +86,23 @@ hibernate.cache.use_second_level_cache=false
hibernate.cache.use_query_cache=false
hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
# If the server should send round IDs to clients after the round is over, and if the client should
# display a permalink to them. You must be using the Kafka metrics implementation, and have
# If the server should send replay IDs to clients after certain events, and if the client should
# display a permalink to them. You must be using the KafkaMetrics implementation, and have
# pyx-metrics-processor running somewhere to put the data into a database, and have
# pyx-metrics-viewer running somewhere connected to that database. The URL to the viewer is provided
# below. If you don't know what any of that is, you certainly don't have it running, so leave this
# below. If you don't know what any of that is, you certainly don't have it running, so leave these
# set to false.
pyx.metrics.game.enabled=false
pyx.metrics.round.enabled=false
# Format string to the URL to view a previous round. Must contain exactly one %s which will be
# replaced with the round's ID.
pyx.metrics.round.url_format=http://localhost:4080/static/round.html#%s
# Metrics implementation.
pyx.metrics.session.enabled=false
pyx.metrics.user.enabled=false
# Format string to the URL to view previous gameplay. Must contain exactly one %s which will be
# replaced with the event's ID.
pyx.metrics.game.url_format=http://localhost:4080/game/%s
pyx.metrics.round.url_format=http://localhost:4080/round/%s
pyx.metrics.session.url_format=http://localhost:4080/session/%s
pyx.metrics.user.url_format=http://localhost:4080/user/%s
# Metrics logger implementation.
pyx.metrics.impl=net.socialgamer.cah.metrics.NoOpMetrics
# for kafka metrics

View File

@ -22,8 +22,15 @@ pyx.chat.game.flood_count=${pyx.game.flood_count}
pyx.chat.game.flood_time=${pyx.game.flood_time}
pyx.build=${buildNumber}
pyx.metrics.game.enabled=${pyx.metrics.game.enabled}
pyx.metrics.game.url_format=${pyx.metrics.game.url_format}
pyx.metrics.round.enabled=${pyx.metrics.round.enabled}
pyx.metrics.round.url_format=${pyx.metrics.round.url_format}
pyx.metrics.session.enabled=${pyx.metrics.session.enabled}
pyx.metrics.session.url_format=${pyx.metrics.session.url_format}
pyx.metrics.user.enabled=${pyx.metrics.user.enabled}
pyx.metrics.user.url_format=${pyx.metrics.user.url_format}
# this is NOT allowed to be changed during a reload, as metrics depend on previous events
pyx.metrics.impl=${pyx.metrics.impl}

View File

@ -169,6 +169,22 @@ public class CahModule extends AbstractModule {
}
}
@Provides
@ShowGamePermalink
Boolean provideShowGamePermalink() {
synchronized (properties) {
return Boolean.valueOf(properties.getProperty("pyx.metrics.game.enabled", "false"));
}
}
@Provides
@GamePermalinkUrlFormat
String provideGamePermalinkUrlFormat() {
synchronized (properties) {
return properties.getProperty("pyx.metrics.game.url_format", "about:blank#%s");
}
}
@Provides
@ShowRoundPermalink
Boolean provideShowRoundPermalink() {
@ -185,6 +201,38 @@ public class CahModule extends AbstractModule {
}
}
@Provides
@ShowSessionPermalink
Boolean provideShowSessionPermalink() {
synchronized (properties) {
return Boolean.valueOf(properties.getProperty("pyx.metrics.session.enabled", "false"));
}
}
@Provides
@SessionPermalinkUrlFormat
String provideSessionPermalinkUrlFormat() {
synchronized (properties) {
return properties.getProperty("pyx.metrics.session.url_format", "about:blank#%s");
}
}
@Provides
@ShowUserPermalink
Boolean provideShowUserPermalink() {
synchronized (properties) {
return Boolean.valueOf(properties.getProperty("pyx.metrics.user.enabled", "false"));
}
}
@Provides
@UserPermalinkUrlFormat
String provideUserPermalinkUrlFormat() {
synchronized (properties) {
return properties.getProperty("pyx.metrics.user.url_format", "about:blank#%s");
}
}
@Provides
@InsecureIdAllowed
Boolean provideInsecureIdAllowed() {
@ -251,6 +299,16 @@ public class CahModule extends AbstractModule {
public @interface MaxUsers {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowGamePermalink {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface GamePermalinkUrlFormat {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowRoundPermalink {
@ -261,6 +319,26 @@ public class CahModule extends AbstractModule {
public @interface RoundPermalinkUrlFormat {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowSessionPermalink {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface SessionPermalinkUrlFormat {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowUserPermalink {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface UserPermalinkUrlFormat {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface BroadcastConnectsAndDisconnects {

View File

@ -270,8 +270,11 @@ public class Constants {
@GoDataType("GameOptionData")
GAME_OPTIONS(AjaxRequest.GAME_OPTIONS),
GAME_STATE_DESCRIPTION("gss"),
GAME_PERMALINK("gp"),
@GoDataType("[]GameInfo")
GAMES("gl"),
@GoDataType("bool")
GLOBAL_CHAT_ENABLED("gce"),
@GoDataType("[]int")
HAND("h"),
@DuplicationAllowed
@ -307,10 +310,10 @@ public class Constants {
SERIAL(AjaxRequest.SERIAL),
@GoDataType("int64")
SERVER_STARTED("SS"),
SESSION_PERMALINK("sP"),
USER_PERMALINK("up"),
@GoDataType("[]int")
WHITE_CARDS("wc"),
@GoDataType("bool")
GLOBAL_CHAT_ENABLED("gce");
WHITE_CARDS("wc");
private final String field;
@ -539,6 +542,8 @@ public class Constants {
@DuplicationAllowed
@GoDataType("GameInfo")
GAME_INFO(AjaxResponse.GAME_INFO),
@DuplicationAllowed
GAME_PERMALINK(AjaxResponse.GAME_PERMALINK),
GAME_STATE("gs"),
@DuplicationAllowed
@GoDataType("[]WhiteCardData")
@ -717,7 +722,6 @@ public class Constants {
* A game's current state.
*/
public enum GameState implements Localizable {
DEALING("d", "In Progress"),
JUDGING("j", "In Progress"),
LOBBY("l", "Not Started"),
PLAYING("p", "In Progress"),

View File

@ -48,9 +48,12 @@ import org.hibernate.Session;
import com.google.inject.Inject;
import com.google.inject.Provider;
import net.socialgamer.cah.CahModule.GamePermalinkUrlFormat;
import net.socialgamer.cah.CahModule.RoundPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.ShowGamePermalink;
import net.socialgamer.cah.CahModule.ShowRoundPermalink;
import net.socialgamer.cah.CahModule.UniqueId;
import net.socialgamer.cah.Constants.AjaxResponse;
import net.socialgamer.cah.Constants.BlackCardData;
import net.socialgamer.cah.Constants.ErrorCode;
import net.socialgamer.cah.Constants.GameInfo;
@ -114,6 +117,8 @@ public class Game {
private final GameOptions options = new GameOptions();
private final Set<String> cardcastDeckIds = Collections.synchronizedSet(new HashSet<String>());
private final Metrics metrics;
private final Provider<Boolean> showGameLinkProvider;
private final Provider<String> gamePermalinkFormatProvider;
private final Provider<Boolean> showRoundLinkProvider;
private final Provider<String> roundPermalinkFormatProvider;
private final long created = System.currentTimeMillis();
@ -209,7 +214,9 @@ public class Game {
final Provider<CardcastService> cardcastServiceProvider,
@UniqueId final Provider<String> uniqueIdProvider,
final Metrics metrics, @ShowRoundPermalink final Provider<Boolean> showRoundLinkProvider,
@RoundPermalinkUrlFormat final Provider<String> roundPermalinkFormatProvider) {
@RoundPermalinkUrlFormat final Provider<String> roundPermalinkFormatProvider,
@ShowGamePermalink final Provider<Boolean> showGameLinkProvider,
@GamePermalinkUrlFormat final Provider<String> gamePermalinkFormatProvider) {
this.id = id;
this.connectedUsers = connectedUsers;
this.gameManager = gameManager;
@ -220,10 +227,24 @@ public class Game {
this.metrics = metrics;
this.showRoundLinkProvider = showRoundLinkProvider;
this.roundPermalinkFormatProvider = roundPermalinkFormatProvider;
this.showGameLinkProvider = showGameLinkProvider;
this.gamePermalinkFormatProvider = gamePermalinkFormatProvider;
state = GameState.LOBBY;
}
/**
* Adds a permalink to this game to the client request response data, if said permalinks are
* enabled.
* @param data A map of data being returned to a client request.
*/
public void maybeAddPermalinkToData(final Map<ReturnableData, Object> data) {
if (showGameLinkProvider.get() && null != currentUniqueId) {
data.put(AjaxResponse.GAME_PERMALINK,
String.format(gamePermalinkFormatProvider.get(), currentUniqueId));
}
}
/**
* Add a player to the game.
*
@ -799,12 +820,10 @@ public class Game {
}
/**
* Move the game into the {@code DEALING} state, and deal cards. The game immediately then moves
* into the {@code PLAYING} state.
* Deal cards for this round. The game immediately then moves into the {@code PLAYING} state.
* <br/>
*/
private void dealState() {
state = GameState.DEALING;
final Player[] playersCopy = players.toArray(new Player[players.size()]);
for (final Player player : playersCopy) {
final List<WhiteCard> hand = player.getHand();
@ -827,6 +846,7 @@ public class Game {
* Synchronizes on {@link #players}, {@link #blackCardLock}, and {@link #roundTimerLock}.
*/
private void playingState() {
final GameState oldState = state;
state = GameState.PLAYING;
playedCards.clear();
@ -863,6 +883,10 @@ public class Game {
data.put(LongPollResponse.BLACK_CARD, getBlackCard());
data.put(LongPollResponse.GAME_STATE, GameState.PLAYING.toString());
data.put(LongPollResponse.PLAY_TIMER, playTimer);
// if we're moving from lobby to playing, this is the first round
if (GameState.LOBBY == oldState) {
maybeAddPermalinkToData(data);
}
broadcastToPlayers(MessageType.GAME_EVENT, data);
@ -1125,6 +1149,7 @@ public class Game {
playedCards.clear();
roundPlayers.clear();
state = GameState.LOBBY;
currentUniqueId = null;
final Player judge = getJudge();
judgeIndex = 0;

View File

@ -1,16 +1,16 @@
/**
* Copyright (c) 2012, Andy Janata
* Copyright (c) 2012-2018, 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
@ -28,6 +28,8 @@ import java.util.Map;
import javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxResponse;
import net.socialgamer.cah.Constants.ErrorCode;
@ -38,12 +40,10 @@ import net.socialgamer.cah.data.Game;
import net.socialgamer.cah.data.GameManager;
import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/**
* Handler to create a new game.
*
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
public class CreateGameHandler extends Handler {
@ -75,6 +75,7 @@ public class CreateGameHandler extends Handler {
return error(ErrorCode.TOO_MANY_GAMES);
} else {
ret.put(AjaxResponse.GAME_ID, game.getId());
game.maybeAddPermalinkToData(ret);
return ret;
}
}

View File

@ -32,17 +32,20 @@ import java.util.Set;
import javax.servlet.http.HttpSession;
import net.socialgamer.cah.CahModule;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.google.inject.Inject;
import com.google.inject.Provider;
import net.socialgamer.cah.CahModule.BanList;
import net.socialgamer.cah.CahModule.GlobalChatEnabled;
import net.socialgamer.cah.CahModule.IncludeInactiveCardsets;
import net.socialgamer.cah.CahModule.ServerStarted;
import net.socialgamer.cah.CahModule.SessionPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.ShowSessionPermalink;
import net.socialgamer.cah.CahModule.ShowUserPermalink;
import net.socialgamer.cah.CahModule.UserPermalinkUrlFormat;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxResponse;
import net.socialgamer.cah.Constants.CardSetData;
@ -68,20 +71,32 @@ public class FirstLoadHandler extends Handler {
private final Set<String> banList;
private final Session hibernateSession;
private final Provider<Boolean> includeInactiveCardsetsProvider;
private final boolean includeInactiveCardsets;
private final boolean globalChatEnabled;
private final boolean showSessionPermalink;
private final String sessionPermalinkFormatString;
private final boolean showUserPermalink;
private final String userPermalinkFormatString;
private final Date serverStarted;
@Inject
public FirstLoadHandler(final Session hibernateSession, @BanList final Set<String> banList,
@IncludeInactiveCardsets final Provider<Boolean> includeInactiveCardsetsProvider,
@CahModule.GlobalChatEnabled final boolean globalChatEnabled,
@ServerStarted final Date serverStarted) {
@IncludeInactiveCardsets final boolean includeInactiveCardsets,
@GlobalChatEnabled final boolean globalChatEnabled,
@ServerStarted final Date serverStarted,
@ShowSessionPermalink final boolean showSessionPermalink,
@SessionPermalinkUrlFormat final String sessionPermalinkFormatString,
@ShowUserPermalink final boolean showUserPermalink,
@UserPermalinkUrlFormat final String userPermalinkFormatString) {
this.banList = banList;
this.hibernateSession = hibernateSession;
this.includeInactiveCardsetsProvider = includeInactiveCardsetsProvider;
this.includeInactiveCardsets = includeInactiveCardsets;
this.globalChatEnabled = globalChatEnabled;
this.serverStarted = serverStarted;
this.showSessionPermalink = showSessionPermalink;
this.sessionPermalinkFormatString = sessionPermalinkFormatString;
this.showUserPermalink = showUserPermalink;
this.userPermalinkFormatString = userPermalinkFormatString;
}
@Override
@ -108,10 +123,19 @@ public class FirstLoadHandler extends Handler {
ret.put(AjaxResponse.PERSISTENT_ID, user.getPersistentId());
ret.put(AjaxResponse.ID_CODE, user.getIdCode());
ret.put(AjaxResponse.SIGIL, user.getSigil().toString());
if (showSessionPermalink) {
ret.put(AjaxResponse.SESSION_PERMALINK,
String.format(sessionPermalinkFormatString, user.getSessionId()));
}
if (showUserPermalink) {
ret.put(AjaxResponse.USER_PERMALINK,
String.format(userPermalinkFormatString, user.getPersistentId()));
}
if (user.getGame() != null) {
ret.put(AjaxResponse.NEXT, ReconnectNextAction.GAME.toString());
ret.put(AjaxResponse.GAME_ID, user.getGame().getId());
user.getGame().maybeAddPermalinkToData(ret);
} else {
ret.put(AjaxResponse.NEXT, ReconnectNextAction.NONE.toString());
}
@ -122,7 +146,7 @@ public class FirstLoadHandler extends Handler {
final Transaction transaction = hibernateSession.beginTransaction();
@SuppressWarnings("unchecked")
final List<PyxCardSet> cardSets = hibernateSession
.createQuery(PyxCardSet.getCardsetQuery(includeInactiveCardsetsProvider.get()))
.createQuery(PyxCardSet.getCardsetQuery(includeInactiveCardsets))
.setReadOnly(true)
.setCacheable(true)
.list();

View File

@ -1,16 +1,16 @@
/**
* Copyright (c) 2012, Andy Janata
* Copyright (c) 2012-2018, 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
@ -28,6 +28,8 @@ import java.util.Map;
import javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest;
import net.socialgamer.cah.Constants.ErrorCode;
@ -38,12 +40,10 @@ import net.socialgamer.cah.data.Game.TooManyPlayersException;
import net.socialgamer.cah.data.GameManager;
import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/**
* Handler to join a game.
*
*
* @author Andy Janata (ajanata@socialgamer.net)
*/
public class JoinGameHandler extends GameHandler {
@ -69,6 +69,7 @@ public class JoinGameHandler extends GameHandler {
}
try {
game.addPlayer(user);
game.maybeAddPermalinkToData(data);
} catch (final IllegalStateException e) {
return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME);
} catch (final TooManyPlayersException e) {

View File

@ -39,6 +39,10 @@ import com.google.inject.Provider;
import net.socialgamer.cah.CahModule.Admins;
import net.socialgamer.cah.CahModule.BanList;
import net.socialgamer.cah.CahModule.SessionPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.ShowSessionPermalink;
import net.socialgamer.cah.CahModule.ShowUserPermalink;
import net.socialgamer.cah.CahModule.UserPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.UserPersistentId;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest;
@ -72,18 +76,30 @@ public class RegisterHandler extends Handler {
private final User.Factory userFactory;
private final Provider<String> persistentIdProvider;
private final IdCodeMangler idCodeMangler;
private final boolean showSessionPermalink;
private final String sessionPermalinkFormatString;
private final boolean showUserPermalink;
private final String userPermalinkFormatString;
@Inject
public RegisterHandler(final ConnectedUsers users, @BanList final Set<String> banList,
final User.Factory userFactory, final IdCodeMangler idCodeMangler,
@UserPersistentId final Provider<String> persistentIdProvider,
@Admins final Set<String> adminList) {
@Admins final Set<String> adminList,
@ShowSessionPermalink final boolean showSessionPermalink,
@SessionPermalinkUrlFormat final String sessionPermalinkFormatString,
@ShowUserPermalink final boolean showUserPermalink,
@UserPermalinkUrlFormat final String userPermalinkFormatString) {
this.users = users;
this.banList = banList;
this.userFactory = userFactory;
this.persistentIdProvider = persistentIdProvider;
this.idCodeMangler = idCodeMangler;
this.adminList = adminList;
this.showSessionPermalink = showSessionPermalink;
this.sessionPermalinkFormatString = sessionPermalinkFormatString;
this.showUserPermalink = showUserPermalink;
this.userPermalinkFormatString = userPermalinkFormatString;
}
@Override
@ -122,6 +138,8 @@ public class RegisterHandler extends Handler {
adminList.contains(request.getRemoteAddr()), persistentId,
request.getHeader(HttpHeaders.ACCEPT_LANGUAGE),
request.getHeader(HttpHeaders.USER_AGENT));
user.userDidSomething();
user.contactedServer();
final ErrorCode errorCode = users.checkAndAdd(user);
if (null == errorCode) {
// There is a findbugs warning on this line:
@ -137,6 +155,14 @@ public class RegisterHandler extends Handler {
data.put(AjaxResponse.PERSISTENT_ID, persistentId);
data.put(AjaxResponse.ID_CODE, user.getIdCode());
data.put(AjaxResponse.SIGIL, user.getSigil().toString());
if (showSessionPermalink) {
data.put(AjaxResponse.SESSION_PERMALINK,
String.format(sessionPermalinkFormatString, user.getSessionId()));
}
if (showUserPermalink) {
data.put(AjaxResponse.USER_PERMALINK,
String.format(userPermalinkFormatString, user.getPersistentId()));
}
} else {
return error(errorCode);
}

View File

@ -1,16 +1,16 @@
/**
* Copyright (c) 2012, Andy Janata
* Copyright (c) 2012-2018, 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
@ -28,6 +28,8 @@ import java.util.Map;
import javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest;
import net.socialgamer.cah.Constants.ErrorCode;
@ -38,12 +40,10 @@ import net.socialgamer.cah.data.Game.TooManySpectatorsException;
import net.socialgamer.cah.data.GameManager;
import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/**
* Handler to spectate a game.
*
*
* @author Gavin Lambert (cah@mirality.co.nz)
*/
public class SpectateGameHandler extends GameHandler {
@ -69,6 +69,7 @@ public class SpectateGameHandler extends GameHandler {
}
try {
game.addSpectator(user);
game.maybeAddPermalinkToData(data);
} catch (final IllegalStateException e) {
return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME);
} catch (final TooManySpectatorsException e) {

View File

@ -50,7 +50,9 @@ import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.Provides;
import net.socialgamer.cah.CahModule.GamePermalinkUrlFormat;
import net.socialgamer.cah.CahModule.RoundPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.ShowGamePermalink;
import net.socialgamer.cah.CahModule.ShowRoundPermalink;
import net.socialgamer.cah.CahModule.UniqueId;
import net.socialgamer.cah.HibernateUtil;
@ -117,6 +119,8 @@ public class GameManagerTest {
bind(Metrics.class).to(NoOpMetrics.class);
bind(Boolean.class).annotatedWith(ShowRoundPermalink.class).toProvider(falseProvider);
bind(String.class).annotatedWith(RoundPermalinkUrlFormat.class).toProvider(formatProvider);
bind(Boolean.class).annotatedWith(ShowGamePermalink.class).toProvider(falseProvider);
bind(String.class).annotatedWith(GamePermalinkUrlFormat.class).toProvider(formatProvider);
}
@Provides
@ -167,15 +171,15 @@ public class GameManagerTest {
assertEquals(0, gameManager.get().intValue());
gameManager.getGames().put(0,
new Game(0, cuMock, gameManager, timer, null, null, null, metricsMock, falseProvider,
formatProvider));
formatProvider, falseProvider, formatProvider));
assertEquals(1, gameManager.get().intValue());
gameManager.getGames().put(1,
new Game(1, cuMock, gameManager, timer, null, null, null, metricsMock, falseProvider,
formatProvider));
formatProvider, falseProvider, formatProvider));
assertEquals(2, gameManager.get().intValue());
gameManager.getGames().put(2,
new Game(2, cuMock, gameManager, timer, null, null, null, metricsMock, falseProvider,
formatProvider));
formatProvider, falseProvider, formatProvider));
// make sure it says it can't make any more
assertEquals(-1, gameManager.get().intValue());
@ -185,7 +189,7 @@ public class GameManagerTest {
assertEquals(1, gameManager.get().intValue());
gameManager.getGames().put(1,
new Game(1, cuMock, gameManager, timer, null, null, null, metricsMock, falseProvider,
formatProvider));
formatProvider, falseProvider, formatProvider));
assertEquals(-1, gameManager.get().intValue());
// remove game 1 out from under it, to make sure it'll fix itself
@ -193,7 +197,7 @@ public class GameManagerTest {
assertEquals(1, gameManager.get().intValue());
gameManager.getGames().put(1,
new Game(1, cuMock, gameManager, timer, null, null, null, metricsMock, falseProvider,
formatProvider));
formatProvider, falseProvider, formatProvider));
assertEquals(-1, gameManager.get().intValue());
gameManager.destroyGame(2);

View File

@ -79,7 +79,7 @@ public class GameTest {
gmMock = createMock(GameManager.class);
metricsMock = createMock(Metrics.class);
game = new Game(0, cuMock, gmMock, timer, null, null, null, metricsMock, falseProvider,
formatProvider);
formatProvider, falseProvider, formatProvider);
}
@SuppressWarnings("unchecked")