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(); $("#welcome").hide();
$("#canvass").show(); $("#canvass").show();
cah.logUserPermalinks(data);
cah.ajax.after_registered(); cah.ajax.after_registered();
}; };
@ -59,6 +60,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.FIRST_LOAD] = function(data) {
if (data[cah.$.AjaxResponse.IN_PROGRESS]) { if (data[cah.$.AjaxResponse.IN_PROGRESS]) {
cah.ajax.StoreClientInformation_(data); cah.ajax.StoreClientInformation_(data);
cah.log.status("You have reconnected as " + cah.nickname); cah.log.status("You have reconnected as " + cah.nickname);
cah.logUserPermalinks(data);
$("#welcome").hide(); $("#welcome").hide();
$("#canvass").show(); $("#canvass").show();
cah.ajax.after_registered(); cah.ajax.after_registered();
@ -66,7 +68,7 @@ cah.ajax.SuccessHandlers[cah.$.AjaxOperation.FIRST_LOAD] = function(data) {
switch (data[cah.$.AjaxResponse.NEXT]) { switch (data[cah.$.AjaxResponse.NEXT]) {
case cah.$.ReconnectNextAction.GAME: case cah.$.ReconnectNextAction.GAME:
cah.log.status("Reconnecting to 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; cah.ajax.hasAutojoinedGame_ = true;
break; break;
case cah.$.ReconnectNextAction.NONE: 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.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.ajax.SuccessHandlers[cah.$.AjaxOperation.SPECTATE_GAME] = cah.ajax.SuccessHandlers[cah.$.AjaxOperation.JOIN_GAME];
cah.Game.joinGame(req[cah.$.AjaxRequest.GAME_ID]);
};
cah.ajax.SuccessHandlers[cah.$.AjaxOperation.CREATE_GAME] = function(data) { 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) { 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; var bottomHeight = $(window).height() - $("#main").height() - $("#menubar").height() - 29;
logElement.height(bottomHeight - chatElement.height() - 40); 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.$ = {};
cah.$.AjaxOperation = function() { cah.$.GamePlayerStatus = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.AjaxOperation.prototype.dummyForAutocomplete = undefined; cah.$.GamePlayerStatus.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxOperation.NAMES = "gn"; cah.$.GamePlayerStatus.SPECTATOR = "sv";
cah.$.AjaxOperation.SCORE = "SC"; cah.$.GamePlayerStatus.WINNER = "sw";
cah.$.AjaxOperation.LEAVE_GAME = "lg"; cah.$.GamePlayerStatus.IDLE = "si";
cah.$.AjaxOperation.JOIN_GAME = "jg"; cah.$.GamePlayerStatus.HOST = "sh";
cah.$.AjaxOperation.CHAT = "c"; cah.$.GamePlayerStatus.JUDGING = "sjj";
cah.$.AjaxOperation.GAME_LIST = "ggl"; cah.$.GamePlayerStatus.JUDGE = "sj";
cah.$.AjaxOperation.CARDCAST_ADD_CARDSET = "cac"; cah.$.GamePlayerStatus.PLAYING = "sp";
cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS = "clc"; cah.$.GamePlayerStatus_msg = {};
cah.$.AjaxOperation.PLAY_CARD = "pc"; cah.$.GamePlayerStatus_msg['sjj'] = "Selecting";
cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo"; cah.$.GamePlayerStatus_msg['sv'] = "Spectator";
cah.$.AjaxOperation.GET_GAME_INFO = "ggi"; cah.$.GamePlayerStatus_msg['sw'] = "Winner!";
cah.$.AjaxOperation.GET_CARDS = "gc"; cah.$.GamePlayerStatus_msg['sh'] = "Host";
cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl"; cah.$.GamePlayerStatus_msg['si'] = "";
cah.$.AjaxOperation.REGISTER = "r"; cah.$.GamePlayerStatus_msg['sj'] = "Card Czar";
cah.$.AjaxOperation.CARDCAST_REMOVE_CARDSET = "crc"; cah.$.GamePlayerStatus_msg['sp'] = "Playing";
cah.$.AjaxOperation.WHOIS = "Wi"; cah.$.GamePlayerStatus_msg_2 = {};
cah.$.AjaxOperation.KICK = "K"; cah.$.GamePlayerStatus_msg_2['sjj'] = "Select a winning card.";
cah.$.AjaxOperation.FIRST_LOAD = "fl"; cah.$.GamePlayerStatus_msg_2['sv'] = "You are just spectating.";
cah.$.AjaxOperation.START_GAME = "sg"; cah.$.GamePlayerStatus_msg_2['sw'] = "You have won!";
cah.$.AjaxOperation.LOG_OUT = "lo"; cah.$.GamePlayerStatus_msg_2['sh'] = "Wait for players then click Start Game.";
cah.$.AjaxOperation.BAN = "b"; cah.$.GamePlayerStatus_msg_2['si'] = "Waiting for players...";
cah.$.AjaxOperation.CREATE_GAME = "cg"; cah.$.GamePlayerStatus_msg_2['sj'] = "You are the Card Czar.";
cah.$.AjaxOperation.STOP_GAME = "Sg"; cah.$.GamePlayerStatus_msg_2['sp'] = "Select a card to play.";
cah.$.AjaxOperation.GAME_CHAT = "GC";
cah.$.AjaxOperation.SPECTATE_GAME = "vg";
cah.$.AjaxOperation.JUDGE_SELECT = "js";
cah.$.AjaxRequest = function() { cah.$.GamePlayerInfo = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.AjaxRequest.prototype.dummyForAutocomplete = undefined; cah.$.GamePlayerInfo.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxRequest.SERIAL = "s"; cah.$.GamePlayerInfo.STATUS = "st";
cah.$.AjaxRequest.OP = "o"; cah.$.GamePlayerInfo.SCORE = "sc";
cah.$.AjaxRequest.WALL = "wall"; cah.$.GamePlayerInfo.NAME = "N";
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.$.AjaxResponse = function() { cah.$.GameOptionData = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.AjaxResponse.prototype.dummyForAutocomplete = undefined; cah.$.GameOptionData.prototype.dummyForAutocomplete = undefined;
cah.$.AjaxResponse.NAMES = "nl"; cah.$.GameOptionData.TIMER_MULTIPLIER = "tm";
cah.$.AjaxResponse.CLIENT_NAME = "cn"; cah.$.GameOptionData.PASSWORD = "pw";
cah.$.AjaxResponse.PLAYER_INFO = "pi"; cah.$.GameOptionData.SPECTATOR_LIMIT = "vL";
cah.$.AjaxResponse.CONNECTED_AT = "ca"; cah.$.GameOptionData.SCORE_LIMIT = "sl";
cah.$.AjaxResponse.WHITE_CARDS = "wc"; cah.$.GameOptionData.BLANKS_LIMIT = "bl";
cah.$.AjaxResponse.HAND = "h"; cah.$.GameOptionData.PLAYER_LIMIT = "pL";
cah.$.AjaxResponse.ERROR_CODE = "ec"; cah.$.GameOptionData.CARD_SETS = "css";
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.$.BlackCardData = function() { cah.$.GameInfo = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.BlackCardData.prototype.dummyForAutocomplete = undefined; cah.$.GameInfo.prototype.dummyForAutocomplete = undefined;
cah.$.BlackCardData.DRAW = "D"; cah.$.GameInfo.GAME_OPTIONS = "go";
cah.$.BlackCardData.PICK = "PK"; cah.$.GameInfo.CREATED = "gca";
cah.$.BlackCardData.TEXT = "T"; cah.$.GameInfo.PLAYERS = "P";
cah.$.BlackCardData.ID = "cid"; cah.$.GameInfo.SPECTATORS = "V";
cah.$.BlackCardData.WATERMARK = "W"; 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() { cah.$.CardSetData = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
@ -105,21 +89,96 @@ cah.$.CardSetData.BASE_DECK = "bd";
cah.$.CardSetData.ID = "cid"; cah.$.CardSetData.ID = "cid";
cah.$.CardSetData.WEIGHT = "w"; cah.$.CardSetData.WEIGHT = "w";
cah.$.DisconnectReason = function() { cah.$.BlackCardData = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.DisconnectReason.prototype.dummyForAutocomplete = undefined; cah.$.BlackCardData.prototype.dummyForAutocomplete = undefined;
cah.$.DisconnectReason.PING_TIMEOUT = "pt"; cah.$.BlackCardData.DRAW = "D";
cah.$.DisconnectReason.BANNED = "B&"; cah.$.BlackCardData.PICK = "PK";
cah.$.DisconnectReason.IDLE_TIMEOUT = "it"; cah.$.BlackCardData.TEXT = "T";
cah.$.DisconnectReason.KICKED = "k"; cah.$.BlackCardData.ID = "cid";
cah.$.DisconnectReason.MANUAL = "man"; cah.$.BlackCardData.WATERMARK = "W";
cah.$.DisconnectReason_msg = {};
cah.$.DisconnectReason_msg['B&'] = "Banned"; cah.$.WhiteCardData = function() {
cah.$.DisconnectReason_msg['pt'] = "Ping timeout"; // Dummy constructor to make Eclipse auto-complete.
cah.$.DisconnectReason_msg['it'] = "Kicked due to idle"; };
cah.$.DisconnectReason_msg['k'] = "Kicked by server administrator"; cah.$.WhiteCardData.prototype.dummyForAutocomplete = undefined;
cah.$.DisconnectReason_msg['man'] = "Leaving"; 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() { cah.$.ErrorCode = function() {
// Dummy constructor to make Eclipse auto-complete. // 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_REQUIRED = "bcr";
cah.$.ErrorInformation.BLACK_CARDS_PRESENT = "bcp"; cah.$.ErrorInformation.BLACK_CARDS_PRESENT = "bcp";
cah.$.GameInfo = function() { cah.$.AjaxResponse = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.GameInfo.prototype.dummyForAutocomplete = undefined; cah.$.AjaxResponse.prototype.dummyForAutocomplete = undefined;
cah.$.GameInfo.GAME_OPTIONS = "go"; cah.$.AjaxResponse.NAMES = "nl";
cah.$.GameInfo.CREATED = "gca"; cah.$.AjaxResponse.CLIENT_NAME = "cn";
cah.$.GameInfo.PLAYERS = "P"; cah.$.AjaxResponse.PLAYER_INFO = "pi";
cah.$.GameInfo.SPECTATORS = "V"; cah.$.AjaxResponse.CONNECTED_AT = "ca";
cah.$.GameInfo.HOST = "H"; cah.$.AjaxResponse.WHITE_CARDS = "wc";
cah.$.GameInfo.STATE = "S"; cah.$.AjaxResponse.HAND = "h";
cah.$.GameInfo.ID = "gid"; cah.$.AjaxResponse.ERROR_CODE = "ec";
cah.$.GameInfo.HAS_PASSWORD = "hp"; 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. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.GameOptionData.prototype.dummyForAutocomplete = undefined; cah.$.AjaxRequest.prototype.dummyForAutocomplete = undefined;
cah.$.GameOptionData.TIMER_MULTIPLIER = "tm"; cah.$.AjaxRequest.SERIAL = "s";
cah.$.GameOptionData.PASSWORD = "pw"; cah.$.AjaxRequest.OP = "o";
cah.$.GameOptionData.SPECTATOR_LIMIT = "vL"; cah.$.AjaxRequest.WALL = "wall";
cah.$.GameOptionData.SCORE_LIMIT = "sl"; cah.$.AjaxRequest.PERSISTENT_ID = "pid";
cah.$.GameOptionData.BLANKS_LIMIT = "bl"; cah.$.AjaxRequest.EMOTE = "me";
cah.$.GameOptionData.PLAYER_LIMIT = "pL"; cah.$.AjaxRequest.CARDCAST_ID = "cci";
cah.$.GameOptionData.CARD_SETS = "css"; 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. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.GamePlayerInfo.prototype.dummyForAutocomplete = undefined; cah.$.AjaxOperation.prototype.dummyForAutocomplete = undefined;
cah.$.GamePlayerInfo.STATUS = "st"; cah.$.AjaxOperation.NAMES = "gn";
cah.$.GamePlayerInfo.SCORE = "sc"; cah.$.AjaxOperation.SCORE = "SC";
cah.$.GamePlayerInfo.NAME = "N"; cah.$.AjaxOperation.LEAVE_GAME = "lg";
cah.$.AjaxOperation.JOIN_GAME = "jg";
cah.$.GamePlayerStatus = function() { cah.$.AjaxOperation.CHAT = "c";
// Dummy constructor to make Eclipse auto-complete. cah.$.AjaxOperation.GAME_LIST = "ggl";
}; cah.$.AjaxOperation.CARDCAST_ADD_CARDSET = "cac";
cah.$.GamePlayerStatus.prototype.dummyForAutocomplete = undefined; cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS = "clc";
cah.$.GamePlayerStatus.SPECTATOR = "sv"; cah.$.AjaxOperation.PLAY_CARD = "pc";
cah.$.GamePlayerStatus.WINNER = "sw"; cah.$.AjaxOperation.CHANGE_GAME_OPTIONS = "cgo";
cah.$.GamePlayerStatus.IDLE = "si"; cah.$.AjaxOperation.GET_GAME_INFO = "ggi";
cah.$.GamePlayerStatus.HOST = "sh"; cah.$.AjaxOperation.GET_CARDS = "gc";
cah.$.GamePlayerStatus.JUDGING = "sjj"; cah.$.AjaxOperation.ADMIN_SET_VERBOSE_LOG = "svl";
cah.$.GamePlayerStatus.JUDGE = "sj"; cah.$.AjaxOperation.REGISTER = "r";
cah.$.GamePlayerStatus.PLAYING = "sp"; cah.$.AjaxOperation.CARDCAST_REMOVE_CARDSET = "crc";
cah.$.GamePlayerStatus_msg = {}; cah.$.AjaxOperation.WHOIS = "Wi";
cah.$.GamePlayerStatus_msg['sjj'] = "Selecting"; cah.$.AjaxOperation.KICK = "K";
cah.$.GamePlayerStatus_msg['sv'] = "Spectator"; cah.$.AjaxOperation.FIRST_LOAD = "fl";
cah.$.GamePlayerStatus_msg['sw'] = "Winner!"; cah.$.AjaxOperation.START_GAME = "sg";
cah.$.GamePlayerStatus_msg['sh'] = "Host"; cah.$.AjaxOperation.LOG_OUT = "lo";
cah.$.GamePlayerStatus_msg['si'] = ""; cah.$.AjaxOperation.BAN = "b";
cah.$.GamePlayerStatus_msg['sj'] = "Card Czar"; cah.$.AjaxOperation.CREATE_GAME = "cg";
cah.$.GamePlayerStatus_msg['sp'] = "Playing"; cah.$.AjaxOperation.STOP_GAME = "Sg";
cah.$.GamePlayerStatus_msg_2 = {}; cah.$.AjaxOperation.GAME_CHAT = "GC";
cah.$.GamePlayerStatus_msg_2['sjj'] = "Select a winning card."; cah.$.AjaxOperation.SPECTATE_GAME = "vg";
cah.$.GamePlayerStatus_msg_2['sv'] = "You are just spectating."; cah.$.AjaxOperation.JUDGE_SELECT = "js";
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.$.ReconnectNextAction = function() { cah.$.ReconnectNextAction = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
@ -371,20 +375,19 @@ cah.$.ReconnectNextAction.prototype.dummyForAutocomplete = undefined;
cah.$.ReconnectNextAction.GAME = "game"; cah.$.ReconnectNextAction.GAME = "game";
cah.$.ReconnectNextAction.NONE = "none"; cah.$.ReconnectNextAction.NONE = "none";
cah.$.Sigil = function() { cah.$.DisconnectReason = function() {
// Dummy constructor to make Eclipse auto-complete. // Dummy constructor to make Eclipse auto-complete.
}; };
cah.$.Sigil.prototype.dummyForAutocomplete = undefined; cah.$.DisconnectReason.prototype.dummyForAutocomplete = undefined;
cah.$.Sigil.NORMAL_USER = ""; cah.$.DisconnectReason.PING_TIMEOUT = "pt";
cah.$.Sigil.ADMIN = "@"; cah.$.DisconnectReason.BANNED = "B&";
cah.$.Sigil.ID_CODE = "+"; cah.$.DisconnectReason.IDLE_TIMEOUT = "it";
cah.$.DisconnectReason.KICKED = "k";
cah.$.WhiteCardData = function() { cah.$.DisconnectReason.MANUAL = "man";
// Dummy constructor to make Eclipse auto-complete. cah.$.DisconnectReason_msg = {};
}; cah.$.DisconnectReason_msg['B&'] = "Banned";
cah.$.WhiteCardData.prototype.dummyForAutocomplete = undefined; cah.$.DisconnectReason_msg['pt'] = "Ping timeout";
cah.$.WhiteCardData.WRITE_IN = "wi"; cah.$.DisconnectReason_msg['it'] = "Kicked due to idle";
cah.$.WhiteCardData.TEXT = "T"; cah.$.DisconnectReason_msg['k'] = "Kicked by server administrator";
cah.$.WhiteCardData.ID = "cid"; cah.$.DisconnectReason_msg['man'] = "Leaving";
cah.$.WhiteCardData.WATERMARK = "W";

View File

@ -321,8 +321,10 @@ cah.Game = function(id) {
* *
* @param {Number} * @param {Number}
* gameId The game id. * 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_GAME_INFO).withGameId(gameId).run();
cah.Ajax.build(cah.$.AjaxOperation.GET_CARDS).withGameId(gameId).run(); cah.Ajax.build(cah.$.AjaxOperation.GET_CARDS).withGameId(gameId).run();
cah.Ajax.build(cah.$.AjaxOperation.CARDCAST_LIST_CARDSETS).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); var game = new cah.Game(gameId);
cah.currentGames[gameId] = game; cah.currentGames[gameId] = game;
game.insertIntoDocument(); game.insertIntoDocument();
game.showGamePermalink_(data);
cah.updateHash('game=' + gameId); 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. * Toggle showing the previous round result.
* *
@ -1405,6 +1422,7 @@ cah.Game.prototype.stateChange = function(data) {
this.hideOptions_(); this.hideOptions_();
this.refreshGameStatus(); this.refreshGameStatus();
this.setBlackCard(data[cah.$.LongPollResponse.BLACK_CARD]); this.setBlackCard(data[cah.$.LongPollResponse.BLACK_CARD]);
this.showGamePermalink_(data);
break; break;
case cah.$.GameState.JUDGING: 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.use_query_cache=false
hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider 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 # 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 Kafka metrics implementation, and have # 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-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 # 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. # set to false.
pyx.metrics.game.enabled=false
pyx.metrics.round.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 pyx.metrics.session.enabled=false
# replaced with the round's ID. pyx.metrics.user.enabled=false
pyx.metrics.round.url_format=http://localhost:4080/static/round.html#%s # Format string to the URL to view previous gameplay. Must contain exactly one %s which will be
# Metrics implementation. # 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 pyx.metrics.impl=net.socialgamer.cah.metrics.NoOpMetrics
# for kafka metrics # 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.chat.game.flood_time=${pyx.game.flood_time}
pyx.build=${buildNumber} 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.enabled=${pyx.metrics.round.enabled}
pyx.metrics.round.url_format=${pyx.metrics.round.url_format} 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 # this is NOT allowed to be changed during a reload, as metrics depend on previous events
pyx.metrics.impl=${pyx.metrics.impl} 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 @Provides
@ShowRoundPermalink @ShowRoundPermalink
Boolean provideShowRoundPermalink() { 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 @Provides
@InsecureIdAllowed @InsecureIdAllowed
Boolean provideInsecureIdAllowed() { Boolean provideInsecureIdAllowed() {
@ -251,6 +299,16 @@ public class CahModule extends AbstractModule {
public @interface MaxUsers { public @interface MaxUsers {
} }
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface ShowGamePermalink {
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface GamePermalinkUrlFormat {
}
@BindingAnnotation @BindingAnnotation
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ShowRoundPermalink { public @interface ShowRoundPermalink {
@ -261,6 +319,26 @@ public class CahModule extends AbstractModule {
public @interface RoundPermalinkUrlFormat { 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 @BindingAnnotation
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface BroadcastConnectsAndDisconnects { public @interface BroadcastConnectsAndDisconnects {

View File

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

View File

@ -48,9 +48,12 @@ import org.hibernate.Session;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import net.socialgamer.cah.CahModule.GamePermalinkUrlFormat;
import net.socialgamer.cah.CahModule.RoundPermalinkUrlFormat; import net.socialgamer.cah.CahModule.RoundPermalinkUrlFormat;
import net.socialgamer.cah.CahModule.ShowGamePermalink;
import net.socialgamer.cah.CahModule.ShowRoundPermalink; import net.socialgamer.cah.CahModule.ShowRoundPermalink;
import net.socialgamer.cah.CahModule.UniqueId; import net.socialgamer.cah.CahModule.UniqueId;
import net.socialgamer.cah.Constants.AjaxResponse;
import net.socialgamer.cah.Constants.BlackCardData; import net.socialgamer.cah.Constants.BlackCardData;
import net.socialgamer.cah.Constants.ErrorCode; import net.socialgamer.cah.Constants.ErrorCode;
import net.socialgamer.cah.Constants.GameInfo; import net.socialgamer.cah.Constants.GameInfo;
@ -114,6 +117,8 @@ public class Game {
private final GameOptions options = new GameOptions(); private final GameOptions options = new GameOptions();
private final Set<String> cardcastDeckIds = Collections.synchronizedSet(new HashSet<String>()); private final Set<String> cardcastDeckIds = Collections.synchronizedSet(new HashSet<String>());
private final Metrics metrics; private final Metrics metrics;
private final Provider<Boolean> showGameLinkProvider;
private final Provider<String> gamePermalinkFormatProvider;
private final Provider<Boolean> showRoundLinkProvider; private final Provider<Boolean> showRoundLinkProvider;
private final Provider<String> roundPermalinkFormatProvider; private final Provider<String> roundPermalinkFormatProvider;
private final long created = System.currentTimeMillis(); private final long created = System.currentTimeMillis();
@ -209,7 +214,9 @@ public class Game {
final Provider<CardcastService> cardcastServiceProvider, final Provider<CardcastService> cardcastServiceProvider,
@UniqueId final Provider<String> uniqueIdProvider, @UniqueId final Provider<String> uniqueIdProvider,
final Metrics metrics, @ShowRoundPermalink final Provider<Boolean> showRoundLinkProvider, 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.id = id;
this.connectedUsers = connectedUsers; this.connectedUsers = connectedUsers;
this.gameManager = gameManager; this.gameManager = gameManager;
@ -220,10 +227,24 @@ public class Game {
this.metrics = metrics; this.metrics = metrics;
this.showRoundLinkProvider = showRoundLinkProvider; this.showRoundLinkProvider = showRoundLinkProvider;
this.roundPermalinkFormatProvider = roundPermalinkFormatProvider; this.roundPermalinkFormatProvider = roundPermalinkFormatProvider;
this.showGameLinkProvider = showGameLinkProvider;
this.gamePermalinkFormatProvider = gamePermalinkFormatProvider;
state = GameState.LOBBY; 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. * 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 * Deal cards for this round. The game immediately then moves into the {@code PLAYING} state.
* into the {@code PLAYING} state.
* <br/> * <br/>
*/ */
private void dealState() { private void dealState() {
state = GameState.DEALING;
final Player[] playersCopy = players.toArray(new Player[players.size()]); final Player[] playersCopy = players.toArray(new Player[players.size()]);
for (final Player player : playersCopy) { for (final Player player : playersCopy) {
final List<WhiteCard> hand = player.getHand(); final List<WhiteCard> hand = player.getHand();
@ -827,6 +846,7 @@ public class Game {
* Synchronizes on {@link #players}, {@link #blackCardLock}, and {@link #roundTimerLock}. * Synchronizes on {@link #players}, {@link #blackCardLock}, and {@link #roundTimerLock}.
*/ */
private void playingState() { private void playingState() {
final GameState oldState = state;
state = GameState.PLAYING; state = GameState.PLAYING;
playedCards.clear(); playedCards.clear();
@ -863,6 +883,10 @@ public class Game {
data.put(LongPollResponse.BLACK_CARD, getBlackCard()); data.put(LongPollResponse.BLACK_CARD, getBlackCard());
data.put(LongPollResponse.GAME_STATE, GameState.PLAYING.toString()); data.put(LongPollResponse.GAME_STATE, GameState.PLAYING.toString());
data.put(LongPollResponse.PLAY_TIMER, playTimer); 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); broadcastToPlayers(MessageType.GAME_EVENT, data);
@ -1125,6 +1149,7 @@ public class Game {
playedCards.clear(); playedCards.clear();
roundPlayers.clear(); roundPlayers.clear();
state = GameState.LOBBY; state = GameState.LOBBY;
currentUniqueId = null;
final Player judge = getJudge(); final Player judge = getJudge();
judgeIndex = 0; judgeIndex = 0;

View File

@ -1,16 +1,16 @@
/** /**
* Copyright (c) 2012, Andy Janata * Copyright (c) 2012-2018, Andy Janata
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted * Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met: * provided that the following conditions are met:
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions * * Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer. * and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of * * 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 * conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution. * with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * 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 * 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 * 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 javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation; import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxResponse; import net.socialgamer.cah.Constants.AjaxResponse;
import net.socialgamer.cah.Constants.ErrorCode; 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.GameManager;
import net.socialgamer.cah.data.User; import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/** /**
* Handler to create a new game. * Handler to create a new game.
* *
* @author Andy Janata (ajanata@socialgamer.net) * @author Andy Janata (ajanata@socialgamer.net)
*/ */
public class CreateGameHandler extends Handler { public class CreateGameHandler extends Handler {
@ -75,6 +75,7 @@ public class CreateGameHandler extends Handler {
return error(ErrorCode.TOO_MANY_GAMES); return error(ErrorCode.TOO_MANY_GAMES);
} else { } else {
ret.put(AjaxResponse.GAME_ID, game.getId()); ret.put(AjaxResponse.GAME_ID, game.getId());
game.maybeAddPermalinkToData(ret);
return ret; return ret;
} }
} }

View File

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

View File

@ -1,16 +1,16 @@
/** /**
* Copyright (c) 2012, Andy Janata * Copyright (c) 2012-2018, Andy Janata
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted * Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met: * provided that the following conditions are met:
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions * * Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer. * and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of * * 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 * conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution. * with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * 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 * 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 * 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 javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation; import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest; import net.socialgamer.cah.Constants.AjaxRequest;
import net.socialgamer.cah.Constants.ErrorCode; 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.GameManager;
import net.socialgamer.cah.data.User; import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/** /**
* Handler to join a game. * Handler to join a game.
* *
* @author Andy Janata (ajanata@socialgamer.net) * @author Andy Janata (ajanata@socialgamer.net)
*/ */
public class JoinGameHandler extends GameHandler { public class JoinGameHandler extends GameHandler {
@ -69,6 +69,7 @@ public class JoinGameHandler extends GameHandler {
} }
try { try {
game.addPlayer(user); game.addPlayer(user);
game.maybeAddPermalinkToData(data);
} catch (final IllegalStateException e) { } catch (final IllegalStateException e) {
return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME); return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME);
} catch (final TooManyPlayersException e) { } 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.Admins;
import net.socialgamer.cah.CahModule.BanList; 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.CahModule.UserPersistentId;
import net.socialgamer.cah.Constants.AjaxOperation; import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest; import net.socialgamer.cah.Constants.AjaxRequest;
@ -72,18 +76,30 @@ public class RegisterHandler extends Handler {
private final User.Factory userFactory; private final User.Factory userFactory;
private final Provider<String> persistentIdProvider; private final Provider<String> persistentIdProvider;
private final IdCodeMangler idCodeMangler; private final IdCodeMangler idCodeMangler;
private final boolean showSessionPermalink;
private final String sessionPermalinkFormatString;
private final boolean showUserPermalink;
private final String userPermalinkFormatString;
@Inject @Inject
public RegisterHandler(final ConnectedUsers users, @BanList final Set<String> banList, public RegisterHandler(final ConnectedUsers users, @BanList final Set<String> banList,
final User.Factory userFactory, final IdCodeMangler idCodeMangler, final User.Factory userFactory, final IdCodeMangler idCodeMangler,
@UserPersistentId final Provider<String> persistentIdProvider, @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.users = users;
this.banList = banList; this.banList = banList;
this.userFactory = userFactory; this.userFactory = userFactory;
this.persistentIdProvider = persistentIdProvider; this.persistentIdProvider = persistentIdProvider;
this.idCodeMangler = idCodeMangler; this.idCodeMangler = idCodeMangler;
this.adminList = adminList; this.adminList = adminList;
this.showSessionPermalink = showSessionPermalink;
this.sessionPermalinkFormatString = sessionPermalinkFormatString;
this.showUserPermalink = showUserPermalink;
this.userPermalinkFormatString = userPermalinkFormatString;
} }
@Override @Override
@ -122,6 +138,8 @@ public class RegisterHandler extends Handler {
adminList.contains(request.getRemoteAddr()), persistentId, adminList.contains(request.getRemoteAddr()), persistentId,
request.getHeader(HttpHeaders.ACCEPT_LANGUAGE), request.getHeader(HttpHeaders.ACCEPT_LANGUAGE),
request.getHeader(HttpHeaders.USER_AGENT)); request.getHeader(HttpHeaders.USER_AGENT));
user.userDidSomething();
user.contactedServer();
final ErrorCode errorCode = users.checkAndAdd(user); final ErrorCode errorCode = users.checkAndAdd(user);
if (null == errorCode) { if (null == errorCode) {
// There is a findbugs warning on this line: // 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.PERSISTENT_ID, persistentId);
data.put(AjaxResponse.ID_CODE, user.getIdCode()); data.put(AjaxResponse.ID_CODE, user.getIdCode());
data.put(AjaxResponse.SIGIL, user.getSigil().toString()); 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 { } else {
return error(errorCode); return error(errorCode);
} }

View File

@ -1,16 +1,16 @@
/** /**
* Copyright (c) 2012, Andy Janata * Copyright (c) 2012-2018, Andy Janata
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted * Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met: * provided that the following conditions are met:
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions * * Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer. * and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of * * 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 * conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution. * with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * 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 * 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 * 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 javax.servlet.http.HttpSession;
import com.google.inject.Inject;
import net.socialgamer.cah.Constants.AjaxOperation; import net.socialgamer.cah.Constants.AjaxOperation;
import net.socialgamer.cah.Constants.AjaxRequest; import net.socialgamer.cah.Constants.AjaxRequest;
import net.socialgamer.cah.Constants.ErrorCode; 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.GameManager;
import net.socialgamer.cah.data.User; import net.socialgamer.cah.data.User;
import com.google.inject.Inject;
/** /**
* Handler to spectate a game. * Handler to spectate a game.
* *
* @author Gavin Lambert (cah@mirality.co.nz) * @author Gavin Lambert (cah@mirality.co.nz)
*/ */
public class SpectateGameHandler extends GameHandler { public class SpectateGameHandler extends GameHandler {
@ -69,6 +69,7 @@ public class SpectateGameHandler extends GameHandler {
} }
try { try {
game.addSpectator(user); game.addSpectator(user);
game.maybeAddPermalinkToData(data);
} catch (final IllegalStateException e) { } catch (final IllegalStateException e) {
return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME); return error(ErrorCode.CANNOT_JOIN_ANOTHER_GAME);
} catch (final TooManySpectatorsException e) { } catch (final TooManySpectatorsException e) {

View File

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

View File

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