Merge latest upstream changes.
This commit is contained in:
commit
7ac328f227
|
@ -377,6 +377,10 @@ span.debug, span.admin {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.game_options {
|
||||||
|
z-index: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.game_right_side_box {
|
.game_right_side_box {
|
||||||
height: 60%;
|
height: 60%;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
|
|
|
@ -95,12 +95,14 @@ HttpSession hSession = request.getSession(true);
|
||||||
If this is your first time playing, you may wish to read <a href="/">the changelog and list of
|
If this is your first time playing, you may wish to read <a href="/">the changelog and list of
|
||||||
known issues</a>.
|
known issues</a>.
|
||||||
</p>
|
</p>
|
||||||
<p tabindex="0">Most recent update: 28 April 2013:</p>
|
<p tabindex="0">Most recent update: 7 August 2013:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li tabindex="0">Version 1.3 of the base Cards Against Humanity game.</li>
|
<li tabindex="0"><strong>The game list will not automatically update all the time now.</strong>
|
||||||
<li tabindex="0">Card sets are grouped by official or custom.</li>
|
You will need to start using the Refresh Games button. The game list will automatically update
|
||||||
<li tabindex="0">You can <a href="viewcards.jsp">view all of the cards in the game</a>,
|
for new games, removed games, when games become passworded, or when you leave a game.</li>
|
||||||
including searching by text and filtering card set.</li>
|
<li tabindex="0">A lot of custom card sets have been added.</li>
|
||||||
|
<li tabindex="0">Cleaned up some error handling.</li>
|
||||||
|
<li tabindex="0">Tried to fix some more of the server crashes.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div id="nickbox">
|
<div id="nickbox">
|
||||||
Nickname:
|
Nickname:
|
||||||
|
|
|
@ -54,6 +54,14 @@ to, for instance, display the number of connected players.
|
||||||
</p>
|
</p>
|
||||||
<p>Recent Changes:</p>
|
<p>Recent Changes:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>7 August 2013:<ul>
|
||||||
|
<li tabindex="0"><strong>The game list will not automatically update all the time now.</strong>
|
||||||
|
You will need to start using the Refresh Games button. The game list will automatically update
|
||||||
|
for new games, removed games, when games become passworded, or when you leave a game.</li>
|
||||||
|
<li tabindex="0">A lot of custom card sets have been added.</li>
|
||||||
|
<li tabindex="0">Cleaned up some error handling.</li>
|
||||||
|
<li tabindex="0">Tried to fix some more of the server crashes.</li>
|
||||||
|
</ul></li>
|
||||||
<li>28 April 2013:<ul>
|
<li>28 April 2013:<ul>
|
||||||
<li tabindex="0">Version 1.3 of the base Cards Against Humanity game.</li>
|
<li tabindex="0">Version 1.3 of the base Cards Against Humanity game.</li>
|
||||||
<li tabindex="0">Card sets are grouped by official or custom.</li>
|
<li tabindex="0">Card sets are grouped by official or custom.</li>
|
||||||
|
|
16301
cah_cards.sql
16301
cah_cards.sql
File diff suppressed because it is too large
Load Diff
|
@ -60,7 +60,7 @@ public class CahModule extends AbstractModule {
|
||||||
@Provides
|
@Provides
|
||||||
@MaxGames
|
@MaxGames
|
||||||
Integer provideMaxGames() {
|
Integer provideMaxGames() {
|
||||||
return 200;
|
return 250;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ public class ConnectedUsers {
|
||||||
/**
|
/**
|
||||||
* Duration of a ping timeout, in nanoseconds.
|
* Duration of a ping timeout, in nanoseconds.
|
||||||
*/
|
*/
|
||||||
public static final long PING_TIMEOUT = 45L * 1000L * 1000000L;
|
public static final long PING_TIMEOUT = TimeUnit.SECONDS.toNanos(45);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key (username) must be stored in lower-case to facilitate case-insensitivity in nicks.
|
* Key (username) must be stored in lower-case to facilitate case-insensitivity in nicks.
|
||||||
|
|
|
@ -196,7 +196,8 @@ public class Game {
|
||||||
data.put(LongPollResponse.NICKNAME, user.getNickname());
|
data.put(LongPollResponse.NICKNAME, user.getNickname());
|
||||||
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
||||||
|
|
||||||
gameManager.broadcastGameListRefresh();
|
// Don't do this anymore, it was driving up a crazy amount of traffic.
|
||||||
|
// gameManager.broadcastGameListRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,7 +265,8 @@ public class Game {
|
||||||
data.put(LongPollResponse.NICKNAME, user.getNickname());
|
data.put(LongPollResponse.NICKNAME, user.getNickname());
|
||||||
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
||||||
|
|
||||||
gameManager.broadcastGameListRefresh();
|
// Don't do this anymore, it was driving up a crazy amount of traffic.
|
||||||
|
// gameManager.broadcastGameListRefresh();
|
||||||
|
|
||||||
if (host == player) {
|
if (host == player) {
|
||||||
if (players.size() > 0) {
|
if (players.size() > 0) {
|
||||||
|
@ -432,13 +434,13 @@ public class Game {
|
||||||
info.put(GameInfo.PASSWORD, password);
|
info.put(GameInfo.PASSWORD, password);
|
||||||
}
|
}
|
||||||
info.put(GameInfo.HAS_PASSWORD, password != null && !password.equals(""));
|
info.put(GameInfo.HAS_PASSWORD, password != null && !password.equals(""));
|
||||||
synchronized (players) {
|
|
||||||
final List<String> playerNames = new ArrayList<String>(players.size());
|
final Player[] playersCopy = players.toArray(new Player[players.size()]);
|
||||||
for (final Player player : players) {
|
final List<String> playerNames = new ArrayList<String>(playersCopy.length);
|
||||||
playerNames.add(player.toString());
|
for (final Player player : playersCopy) {
|
||||||
}
|
playerNames.add(player.toString());
|
||||||
info.put(GameInfo.PLAYERS, playerNames);
|
|
||||||
}
|
}
|
||||||
|
info.put(GameInfo.PLAYERS, playerNames);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,12 +450,11 @@ public class Game {
|
||||||
*/
|
*/
|
||||||
public List<Map<GamePlayerInfo, Object>> getAllPlayerInfo() {
|
public List<Map<GamePlayerInfo, Object>> getAllPlayerInfo() {
|
||||||
final List<Map<GamePlayerInfo, Object>> info;
|
final List<Map<GamePlayerInfo, Object>> info;
|
||||||
synchronized (players) {
|
final Player[] playersCopy = players.toArray(new Player[players.size()]);
|
||||||
info = new ArrayList<Map<GamePlayerInfo, Object>>(players.size());
|
info = new ArrayList<Map<GamePlayerInfo, Object>>(playersCopy.length);
|
||||||
for (final Player player : players) {
|
for (final Player player : playersCopy) {
|
||||||
final Map<GamePlayerInfo, Object> playerInfo = getPlayerInfo(player);
|
final Map<GamePlayerInfo, Object> playerInfo = getPlayerInfo(player);
|
||||||
info.add(playerInfo);
|
info.add(playerInfo);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
@ -553,14 +554,13 @@ public class Game {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean started;
|
boolean started;
|
||||||
synchronized (players) {
|
final int numPlayers = players.size();
|
||||||
if (players.size() >= 3) {
|
if (numPlayers >= 3) {
|
||||||
// Pick a random start judge, though the "next" judge will actually go first.
|
// Pick a random start judge, though the "next" judge will actually go first.
|
||||||
judgeIndex = (int) (Math.random() * players.size());
|
judgeIndex = (int) (Math.random() * numPlayers);
|
||||||
started = true;
|
started = true;
|
||||||
} else {
|
} else {
|
||||||
started = false;
|
started = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (started) {
|
if (started) {
|
||||||
logger.info(String.format("Starting game %d.", id));
|
logger.info(String.format("Starting game %d.", id));
|
||||||
|
@ -591,21 +591,19 @@ public class Game {
|
||||||
* Move the game into the {@code DEALING} state, and deal cards. The game immediately then moves
|
* Move the game into the {@code DEALING} state, and deal cards. The game immediately then moves
|
||||||
* into the {@code PLAYING} state.
|
* into the {@code PLAYING} state.
|
||||||
* <br/>
|
* <br/>
|
||||||
* Synchronizes on {@link #players}.
|
|
||||||
*/
|
*/
|
||||||
private void dealState() {
|
private void dealState() {
|
||||||
state = GameState.DEALING;
|
state = GameState.DEALING;
|
||||||
synchronized (players) {
|
final Player[] playersCopy = players.toArray(new Player[players.size()]);
|
||||||
for (final Player player : players) {
|
for (final Player player : playersCopy) {
|
||||||
final List<WhiteCard> hand = player.getHand();
|
final List<WhiteCard> hand = player.getHand();
|
||||||
final List<WhiteCard> newCards = new LinkedList<WhiteCard>();
|
final List<WhiteCard> newCards = new LinkedList<WhiteCard>();
|
||||||
while (hand.size() < 10) {
|
while (hand.size() < 10) {
|
||||||
final WhiteCard card = getNextWhiteCard();
|
final WhiteCard card = getNextWhiteCard();
|
||||||
hand.add(card);
|
hand.add(card);
|
||||||
newCards.add(card);
|
newCards.add(card);
|
||||||
}
|
|
||||||
sendCardsToPlayer(player, newCards);
|
|
||||||
}
|
}
|
||||||
|
sendCardsToPlayer(player, newCards);
|
||||||
}
|
}
|
||||||
playingState();
|
playingState();
|
||||||
}
|
}
|
||||||
|
@ -765,15 +763,14 @@ public class Game {
|
||||||
logger.info(String.format("Skipping idle player %s in game %d.",
|
logger.info(String.format("Skipping idle player %s in game %d.",
|
||||||
player.getUser().toString(), id));
|
player.getUser().toString(), id));
|
||||||
player.skipped();
|
player.skipped();
|
||||||
final HashMap<ReturnableData, Object> data = getEventMap();
|
|
||||||
|
|
||||||
|
final HashMap<ReturnableData, Object> data = getEventMap();
|
||||||
|
data.put(LongPollResponse.NICKNAME, player.getUser().getNickname());
|
||||||
if (player.getSkipCount() >= MAX_SKIPS_BEFORE_KICK || playedCards.size() < 2) {
|
if (player.getSkipCount() >= MAX_SKIPS_BEFORE_KICK || playedCards.size() < 2) {
|
||||||
data.put(LongPollResponse.EVENT, LongPollEvent.GAME_PLAYER_KICKED_IDLE.toString());
|
data.put(LongPollResponse.EVENT, LongPollEvent.GAME_PLAYER_KICKED_IDLE.toString());
|
||||||
data.put(LongPollResponse.NICKNAME, player.getUser().getNickname());
|
|
||||||
playersToRemove.add(player.getUser());
|
playersToRemove.add(player.getUser());
|
||||||
} else {
|
} else {
|
||||||
data.put(LongPollResponse.EVENT, LongPollEvent.GAME_PLAYER_SKIPPED.toString());
|
data.put(LongPollResponse.EVENT, LongPollEvent.GAME_PLAYER_SKIPPED.toString());
|
||||||
data.put(LongPollResponse.NICKNAME, player.getUser().getNickname());
|
|
||||||
playersToUpdateStatus.add(player);
|
playersToUpdateStatus.add(player);
|
||||||
}
|
}
|
||||||
broadcastToPlayers(MessageType.GAME_EVENT, data);
|
broadcastToPlayers(MessageType.GAME_EVENT, data);
|
||||||
|
@ -917,6 +914,8 @@ public class Game {
|
||||||
data.put(LongPollResponse.PLAYER_INFO, getPlayerInfo(judge));
|
data.put(LongPollResponse.PLAYER_INFO, getPlayerInfo(judge));
|
||||||
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
broadcastToPlayers(MessageType.GAME_PLAYER_EVENT, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gameManager.broadcastGameListRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1019,19 +1018,16 @@ public class Game {
|
||||||
/**
|
/**
|
||||||
* Get the {@code Player} object for a given {@code User} object.
|
* Get the {@code Player} object for a given {@code User} object.
|
||||||
*
|
*
|
||||||
* Synchronizes on {@link #players}.
|
|
||||||
*
|
|
||||||
* @param user
|
* @param user
|
||||||
* @return The {@code Player} object representing {@code user} in this game, or {@code null} if
|
* @return The {@code Player} object representing {@code user} in this game, or {@code null} if
|
||||||
* {@code user} is not in this game.
|
* {@code user} is not in this game.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private Player getPlayerForUser(final User user) {
|
private Player getPlayerForUser(final User user) {
|
||||||
synchronized (players) {
|
final Player[] playersCopy = players.toArray(new Player[players.size()]);
|
||||||
for (final Player player : players) {
|
for (final Player player : playersCopy) {
|
||||||
if (player.getUser() == user) {
|
if (player.getUser() == user) {
|
||||||
return player;
|
return player;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -1163,11 +1159,10 @@ public class Game {
|
||||||
*/
|
*/
|
||||||
private List<User> playersToUsers() {
|
private List<User> playersToUsers() {
|
||||||
final List<User> users;
|
final List<User> users;
|
||||||
synchronized (players) {
|
final Player[] playersCopy = players.toArray(new Player[players.size()]);
|
||||||
users = new ArrayList<User>(players.size());
|
users = new ArrayList<User>(playersCopy.length);
|
||||||
for (final Player player : players) {
|
for (final Player player : playersCopy) {
|
||||||
users.add(player.getUser());
|
users.add(player.getUser());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final int blanksLimit = Integer.parseInt(request.getParameter(AjaxRequest.BLANKS_LIMIT));
|
final int blanksLimit = Integer.parseInt(request.getParameter(AjaxRequest.BLANKS_LIMIT));
|
||||||
|
final String oldPassword = game.getPassword();
|
||||||
String password = request.getParameter(AjaxRequest.PASSWORD);
|
String password = request.getParameter(AjaxRequest.PASSWORD);
|
||||||
if (password == null) {
|
if (password == null) {
|
||||||
password = "";
|
password = "";
|
||||||
|
@ -64,11 +65,16 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler {
|
||||||
useTimer = Boolean.valueOf(useTimerString);
|
useTimer = Boolean.valueOf(useTimerString);
|
||||||
}
|
}
|
||||||
game.updateGameSettings(scoreLimit, playerLimit, cardSets, blanksLimit, password, useTimer);
|
game.updateGameSettings(scoreLimit, playerLimit, cardSets, blanksLimit, password, useTimer);
|
||||||
|
|
||||||
|
// only broadcast an update if the password state has changed, because it needs to change
|
||||||
|
// the text on the join button and the sort order
|
||||||
|
if (!password.equals(oldPassword)) {
|
||||||
|
gameManager.broadcastGameListRefresh();
|
||||||
|
}
|
||||||
} catch (final NumberFormatException nfe) {
|
} catch (final NumberFormatException nfe) {
|
||||||
return error(ErrorCode.BAD_REQUEST);
|
return error(ErrorCode.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
gameManager.broadcastGameListRefresh();
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,6 @@ public class JoinGameHandler extends GameHandler {
|
||||||
} catch (final TooManyPlayersException e) {
|
} catch (final TooManyPlayersException e) {
|
||||||
return error(ErrorCode.GAME_FULL);
|
return error(ErrorCode.GAME_FULL);
|
||||||
}
|
}
|
||||||
gameManager.broadcastGameListRefresh();
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.annotation.WebServlet;
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
@ -60,28 +61,28 @@ public class LongPollServlet extends CahServlet {
|
||||||
/**
|
/**
|
||||||
* Minimum amount of time before timing out and returning a no-op, in nanoseconds.
|
* Minimum amount of time before timing out and returning a no-op, in nanoseconds.
|
||||||
*/
|
*/
|
||||||
private static final long TIMEOUT_BASE = 20 * 1000 * 1000;
|
private static final long TIMEOUT_BASE = TimeUnit.SECONDS.toNanos(20);
|
||||||
// private static final long TIMEOUT_BASE = 10 * 1000 * 1000;
|
// private static final long TIMEOUT_BASE = 10 * 1000 * 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomness factor added to minimum timeout duration, in nanoseconds. The maximum timeout delay
|
* Randomness factor added to minimum timeout duration, in nanoseconds. The maximum timeout delay
|
||||||
* will be TIMEOUT_BASE + TIMEOUT_RANDOMNESS - 1.
|
* will be TIMEOUT_BASE + TIMEOUT_RANDOMNESS - 1.
|
||||||
*/
|
*/
|
||||||
private static final double TIMEOUT_RANDOMNESS = 5 * 1000 * 1000;
|
private static final double TIMEOUT_RANDOMNESS = TimeUnit.SECONDS.toNanos(5);
|
||||||
// private static final double TIMEOUT_RANDOMNESS = 0;
|
// private static final double TIMEOUT_RANDOMNESS = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum number of messages which will be returned to a client during a single poll
|
* The maximum number of messages which will be returned to a client during a single poll
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
private static final int MAX_MESSAGES_PER_POLL = 10;
|
private static final int MAX_MESSAGES_PER_POLL = 20;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An amount of milliseconds to wait after being notified that the user has at least one message
|
* An amount of milliseconds to wait after being notified that the user has at least one message
|
||||||
* to deliver, before we actually deliver messages. This will allow multiple messages that arrive
|
* to deliver, before we actually deliver messages. This will allow multiple messages that arrive
|
||||||
* in close proximity to each other to actually be delivered in the same client request.
|
* in close proximity to each other to actually be delivered in the same client request.
|
||||||
*/
|
*/
|
||||||
private static final int WAIT_FOR_MORE_DELAY = 30;
|
private static final int WAIT_FOR_MORE_DELAY = 50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
|
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
@ -99,9 +100,9 @@ public class LongPollServlet extends CahServlet {
|
||||||
final User user = (User) hSession.getAttribute(SessionAttribute.USER);
|
final User user = (User) hSession.getAttribute(SessionAttribute.USER);
|
||||||
assert (user != null);
|
assert (user != null);
|
||||||
user.contactedServer();
|
user.contactedServer();
|
||||||
while (!(user.hasQueuedMessages()) && System.nanoTime() < end) {
|
while (!(user.hasQueuedMessages()) && System.nanoTime() - end < 0) {
|
||||||
try {
|
try {
|
||||||
user.waitForNewMessageNotification((end - System.nanoTime()) / 1000);
|
user.waitForNewMessageNotification(TimeUnit.NANOSECONDS.toMillis(end - System.nanoTime()));
|
||||||
} catch (final InterruptedException ie) {
|
} catch (final InterruptedException ie) {
|
||||||
// pass
|
// pass
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue