Merge pull request #219 from devgianlu/min-default-max-config

Moved min/default/max to configuration file
This commit is contained in:
Andy Janata 2020-05-23 18:21:22 -07:00 committed by GitHub
commit 4379c14f6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1867 additions and 1659 deletions

View File

@ -32,10 +32,11 @@ created for the user now.
<%@ page import="com.google.inject.Key" %> <%@ page import="com.google.inject.Key" %>
<%@ page import="com.google.inject.TypeLiteral" %> <%@ page import="com.google.inject.TypeLiteral" %>
<%@ page import="javax.servlet.http.HttpSession" %> <%@ page import="javax.servlet.http.HttpSession" %>
<%@ page import="net.socialgamer.cah.CahModule.AllowBlankCards" %>
<%@ page import="net.socialgamer.cah.RequestWrapper" %> <%@ page import="net.socialgamer.cah.RequestWrapper" %>
<%@ page import="net.socialgamer.cah.StartupUtils" %> <%@ page import="net.socialgamer.cah.StartupUtils" %>
<%@ page import="net.socialgamer.cah.data.GameOptions" %> <%@ page import="net.socialgamer.cah.data.GameOptions" %>
<%@ page import="net.socialgamer.cah.CahModule" %>
<%@ page import="net.socialgamer.cah.CahModule.*" %>
<% <%
// Ensure a session exists for the user. // Ensure a session exists for the user.
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -425,9 +426,9 @@ boolean allowBlankCards = injector.getInstance(Key.get(new TypeLiteral<Boolean>(
<label id="score_limit_template_label" for="score_limit_template">Score limit:</label> <label id="score_limit_template_label" for="score_limit_template">Score limit:</label>
<select id="score_limit_template" class="score_limit"> <select id="score_limit_template" class="score_limit">
<% <%
for (int i = GameOptions.MIN_SCORE_LIMIT; i <= GameOptions.MAX_SCORE_LIMIT; i++) { for (int i = injector.getInstance(Key.get(Integer.class, MinScoreLimit.class)); i <= injector.getInstance(Key.get(Integer.class, MaxScoreLimit.class)); i++) {
%> %>
<option <%= i == GameOptions.DEFAULT_SCORE_LIMIT ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option> <option <%=(i == injector.getInstance(Key.get(Integer.class, DefaultScoreLimit.class))) ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option>
<% } %> <% } %>
</select> </select>
<br/> <br/>
@ -435,9 +436,9 @@ boolean allowBlankCards = injector.getInstance(Key.get(new TypeLiteral<Boolean>(
<select id="player_limit_template" class="player_limit" <select id="player_limit_template" class="player_limit"
aria-label="Player limit. Having more than 10 players may cause issues both for screen readers and traditional browsers."> aria-label="Player limit. Having more than 10 players may cause issues both for screen readers and traditional browsers.">
<% <%
for (int i = GameOptions.MIN_PLAYER_LIMIT; i <= GameOptions.MAX_PLAYER_LIMIT; i++) { for (int i = injector.getInstance(Key.get(Integer.class, MinPlayerLimit.class)); i <= injector.getInstance(Key.get(Integer.class, MaxPlayerLimit.class)); i++) {
%> %>
<option <%= i == GameOptions.DEFAULT_PLAYER_LIMIT ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option> <option <%= i == injector.getInstance(Key.get(Integer.class, DefaultPlayerLimit.class)) ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option>
<% } %> <% } %>
</select> </select>
Having more than 10 players may get cramped! Having more than 10 players may get cramped!
@ -446,9 +447,9 @@ boolean allowBlankCards = injector.getInstance(Key.get(new TypeLiteral<Boolean>(
<select id="spectator_limit_template" class="spectator_limit" <select id="spectator_limit_template" class="spectator_limit"
aria-label="Spectator limit."> aria-label="Spectator limit.">
<% <%
for (int i = GameOptions.MIN_SPECTATOR_LIMIT; i <= GameOptions.MAX_SPECTATOR_LIMIT; i++) { for (int i = injector.getInstance(Key.get(Integer.class, MinSpectatorLimit.class)); i <= injector.getInstance(Key.get(Integer.class, MaxSpectatorLimit.class)); i++) {
%> %>
<option <%= i == GameOptions.DEFAULT_SPECTATOR_LIMIT ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option> <option <%= i == injector.getInstance(Key.get(Integer.class, DefaultSpectatorLimit.class)) ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option>
<% } %> <% } %>
</select> </select>
Spectators can watch and chat, but not actually play. Not even as Czar. Spectators can watch and chat, but not actually play. Not even as Czar.
@ -486,9 +487,9 @@ boolean allowBlankCards = injector.getInstance(Key.get(new TypeLiteral<Boolean>(
<label id="blanks_limit_label" title="Blank cards allow a player to type in their own answer."> <label id="blanks_limit_label" title="Blank cards allow a player to type in their own answer.">
Also include <select id="blanks_limit_template" class="blanks_limit"> Also include <select id="blanks_limit_template" class="blanks_limit">
<% <%
for (int i = GameOptions.MIN_BLANK_CARD_LIMIT; i <= GameOptions.MAX_BLANK_CARD_LIMIT; i++) { for (int i = injector.getInstance(Key.get(Integer.class, MinBlankCardLimit.class)); i <= injector.getInstance(Key.get(Integer.class, MaxBlankCardLimit.class)); i++) {
%> %>
<option <%= i == GameOptions.DEFAULT_BLANK_CARD_LIMIT ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option> <option <%= i == injector.getInstance(Key.get(Integer.class, DefaultBlankCardLimit.class)) ? "selected='selected' " : "" %>value="<%= i %>"><%= i %></option>
<% } %> <% } %>
</select> blank white cards. </select> blank white cards.
</label> </label>

View File

@ -59,6 +59,19 @@ pyx.game.flood_count=5
# seconds # seconds
pyx.game.flood_time=30 pyx.game.flood_time=30
# Game options
pyx.game.min_score_limit=4
pyx.game.default_score_limit=8
pyx.game.max_score_limit=69
pyx.game.min_player_limit=3
pyx.game.default_player_limit=10
pyx.game.max_player_limit=20
pyx.game.min_spectator_limit=0
pyx.game.default_spectator_limit=10
pyx.game.max_spectator_limit=20
pyx.game.min_blank_card_limit=0
pyx.game.default_blank_card_limit=0
pyx.game.max_blank_card_limit=30
# for production use, use postgres # for production use, use postgres
#hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect #hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

View File

@ -25,6 +25,19 @@ pyx.chat.game.flood_time=${pyx.game.flood_time}
pyx.build=${buildNumber} pyx.build=${buildNumber}
pyx.banned_nicks=${pyx.banned_nicks} pyx.banned_nicks=${pyx.banned_nicks}
pyx.game.min_score_limit=${pyx.game.min_score_limit}
pyx.game.default_score_limit=${pyx.game.default_score_limit}
pyx.game.max_score_limit=${pyx.game.max_score_limit}
pyx.game.min_player_limit=${pyx.game.min_player_limit}
pyx.game.default_player_limit=${pyx.game.default_player_limit}
pyx.game.max_player_limit=${pyx.game.max_player_limit}
pyx.game.min_spectator_limit=${pyx.game.min_spectator_limit}
pyx.game.default_spectator_limit=${pyx.game.default_spectator_limit}
pyx.game.max_spectator_limit=${pyx.game.max_spectator_limit}
pyx.game.min_blank_card_limit=${pyx.game.min_blank_card_limit}
pyx.game.default_blank_card_limit=${pyx.game.default_blank_card_limit}
pyx.game.max_blank_card_limit=${pyx.game.max_blank_card_limit}
pyx.metrics.game.enabled=${pyx.metrics.game.enabled} pyx.metrics.game.enabled=${pyx.metrics.game.enabled}
pyx.metrics.game.url_format=${pyx.metrics.game.url_format} 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}

View File

@ -37,14 +37,12 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import com.google.inject.*;
import net.socialgamer.cah.data.GameOptions;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.hibernate.Session; import org.hibernate.Session;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.assistedinject.FactoryModuleBuilder;
import net.socialgamer.cah.data.GameManager; import net.socialgamer.cah.data.GameManager;
@ -427,4 +425,160 @@ public class CahModule extends AbstractModule {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface AllowBlankCards { public @interface AllowBlankCards {
} }
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MinScoreLimit {
}
@Provides
@MinScoreLimit
Integer provideMinScoreLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.min_score_limit", "4"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultScoreLimit {
}
@Provides
@DefaultScoreLimit
Integer provideDefaultScoreLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.default_score_limit", "8"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxScoreLimit {
}
@Provides
@MaxScoreLimit
Integer provideMaxScoreLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.max_score_limit", "69"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MinPlayerLimit {
}
@Provides
@MinPlayerLimit
Integer provideMinPlayerLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.min_player_limit", "3"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultPlayerLimit {
}
@Provides
@DefaultPlayerLimit
Integer provideDefaultPlayerLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.default_player_limit", "10"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxPlayerLimit {
}
@Provides
@MaxPlayerLimit
Integer provideMaxPlayerLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.max_player_limit", "20"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MinSpectatorLimit {
}
@Provides
@MinSpectatorLimit
Integer provideMinSpectatorLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.min_spectator_limit", "0"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultSpectatorLimit {
}
@Provides
@DefaultSpectatorLimit
Integer provideDefaultSpectatorLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.default_spectator_limit", "10"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxSpectatorLimit {
}
@Provides
@MaxSpectatorLimit
Integer provideMaxSpectatorLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.max_spectator_limit", "20"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MinBlankCardLimit {
}
@Provides
@MinBlankCardLimit
Integer provideMinBlankCardLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.min_blank_card_limit", "0"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface DefaultBlankCardLimit {
}
@Provides
@DefaultBlankCardLimit
Integer provideDefaultBlankCardLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.default_blank_card_limit", "0"));
}
}
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxBlankCardLimit {
}
@Provides
@MaxBlankCardLimit
Integer provideMaxBlankCardLimit() {
synchronized (properties) {
return Integer.valueOf(properties.getProperty("pyx.game.max_blank_card_limit", "30"));
}
}
} }

View File

@ -1,16 +1,16 @@
/** /**
* Copyright (c) 2012-2018, Andy Janata * Copyright (c) 2012-2018, Andy Janata
* All rights reserved. * All rights reserved.
* * <p>
* 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:
* * <p>
* * 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.
* * <p>
* 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
@ -23,34 +23,34 @@
package net.socialgamer.cah.cardcast; package net.socialgamer.cah.cardcast;
import com.google.inject.*;
import net.socialgamer.cah.CahModule;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import com.google.inject.AbstractModule;
import com.google.inject.BindingAnnotation;
import com.google.inject.Provides;
import net.socialgamer.cah.data.GameOptions;
public class CardcastModule extends AbstractModule { public class CardcastModule extends AbstractModule {
AtomicInteger cardId = new AtomicInteger(-(GameOptions.MAX_BLANK_CARD_LIMIT + 1)); private AtomicInteger cardId;
private Provider<Integer> maxBlankCardLimitProvider;
@Override @Override
protected void configure() { protected void configure() {
} maxBlankCardLimitProvider = getProvider(Key.get(Integer.class, CahModule.MaxBlankCardLimit.class));
}
@Provides @Provides
@CardcastCardId @CardcastCardId
Integer provideCardId() { Integer provideCardId() {
return cardId.decrementAndGet(); if (cardId == null) cardId = new AtomicInteger(-(maxBlankCardLimitProvider.get() + 1));
} return cardId.decrementAndGet();
}
@BindingAnnotation @BindingAnnotation
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface CardcastCardId { public @interface CardcastCardId {
/**/ /**/
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
/** /**
* Copyright (c) 2012-2018, Andy Janata * Copyright (c) 2012-2018, Andy Janata
* All rights reserved. * All rights reserved.
* * <p>
* 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:
* * <p>
* * 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.
* * <p>
* 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
@ -23,14 +23,17 @@
package net.socialgamer.cah.data; package net.socialgamer.cah.data;
import com.google.inject.Inject;
import com.google.inject.Provider;
import net.socialgamer.cah.CahModule.*;
import net.socialgamer.cah.Constants.GameOptionData;
import net.socialgamer.cah.JsonWrapper;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.socialgamer.cah.Constants.GameOptionData;
import net.socialgamer.cah.JsonWrapper;
/** /**
* Options for an individual game. * Options for an individual game.
@ -38,112 +41,129 @@ import net.socialgamer.cah.JsonWrapper;
* @author Gavin Lambert (uecasm) * @author Gavin Lambert (uecasm)
*/ */
public class GameOptions { public class GameOptions {
// TODO move these out to pyx.properties public final Set<Integer> cardSetIds = new HashSet<Integer>();
public static final int MIN_SCORE_LIMIT = 4; public final int maxPlayerLimit;
public static final int DEFAULT_SCORE_LIMIT = 8; public final int defaultPlayerLimit;
public static final int MAX_SCORE_LIMIT = 69; public final int minPlayerLimit;
public static final int MIN_PLAYER_LIMIT = 3; public final int maxSpectatorLimit;
public static final int DEFAULT_PLAYER_LIMIT = 10; public final int defaultSpectatorLimit;
public static final int MAX_PLAYER_LIMIT = 20; public final int minSpectatorLimit;
public static final int MIN_SPECTATOR_LIMIT = 0; public final int minScoreLimit;
public static final int DEFAULT_SPECTATOR_LIMIT = 10; public final int maxScoreLimit;
public static final int MAX_SPECTATOR_LIMIT = 20; public final int defaultScoreLimit;
public static final int MIN_BLANK_CARD_LIMIT = 0; public final int minBlankCardLimit;
public static final int DEFAULT_BLANK_CARD_LIMIT = 0; public final int defaultBlankCardLimit;
public static final int MAX_BLANK_CARD_LIMIT = 30; public final int maxBlankCardLimit;
// These are the default values new games get.
public int blanksInDeck;
public int playerLimit;
public int spectatorLimit;
public int scoreGoal;
public String password = "";
public String timerMultiplier = "1x";
// These are the default values new games get. @Inject
public int blanksInDeck = DEFAULT_BLANK_CARD_LIMIT; public GameOptions(@MaxPlayerLimit int maxPlayerLimit, @DefaultPlayerLimit int defaultPlayerLimit, @MinPlayerLimit int minPlayerLimit,
public int playerLimit = DEFAULT_PLAYER_LIMIT; @MaxSpectatorLimit int maxSpectatorLimit, @DefaultSpectatorLimit int defaultSpectatorLimit, @MinSpectatorLimit int minSpectatorLimit,
public int spectatorLimit = DEFAULT_SPECTATOR_LIMIT; @MinScoreLimit int minScoreLimit, @MaxScoreLimit int maxScoreLimit, @DefaultScoreLimit int defaultScoreLimit,
public int scoreGoal = DEFAULT_SCORE_LIMIT; @MinBlankCardLimit int minBlankCardLimit, @DefaultBlankCardLimit int defaultBlankCardLimit, @MaxBlankCardLimit int maxBlankCardLimit) {
public final Set<Integer> cardSetIds = new HashSet<Integer>(); this.maxPlayerLimit = maxPlayerLimit;
public String password = ""; this.defaultPlayerLimit = playerLimit = defaultPlayerLimit;
public String timerMultiplier = "1x"; this.minPlayerLimit = minPlayerLimit;
this.maxSpectatorLimit = maxSpectatorLimit;
/** this.defaultSpectatorLimit = spectatorLimit = defaultSpectatorLimit;
* Update the options in-place (so that the Game doesn't need more locks). this.minSpectatorLimit = minSpectatorLimit;
* this.minScoreLimit = minScoreLimit;
* @param newOptions this.maxScoreLimit = maxScoreLimit;
* The new options to use. this.defaultScoreLimit = scoreGoal = defaultScoreLimit;
*/ this.minBlankCardLimit = minBlankCardLimit;
public void update(final GameOptions newOptions) { this.defaultBlankCardLimit = blanksInDeck = defaultBlankCardLimit;
this.scoreGoal = newOptions.scoreGoal; this.maxBlankCardLimit = maxBlankCardLimit;
this.playerLimit = newOptions.playerLimit;
this.spectatorLimit = newOptions.spectatorLimit;
synchronized (this.cardSetIds) {
this.cardSetIds.clear();
this.cardSetIds.addAll(newOptions.cardSetIds);
}
this.blanksInDeck = newOptions.blanksInDeck;
this.password = newOptions.password;
this.timerMultiplier = newOptions.timerMultiplier;
}
/**
* Get the options in a form that can be sent to clients.
*
* @param includePassword
* Include the actual password with the information. This should only be
* sent to people in the game.
* @return This game's general information: ID, host, state, player list, etc.
*/
public Map<GameOptionData, Object> serialize(final boolean includePassword) {
final Map<GameOptionData, Object> info = new HashMap<GameOptionData, Object>();
info.put(GameOptionData.CARD_SETS, cardSetIds);
info.put(GameOptionData.BLANKS_LIMIT, blanksInDeck);
info.put(GameOptionData.PLAYER_LIMIT, playerLimit);
info.put(GameOptionData.SPECTATOR_LIMIT, spectatorLimit);
info.put(GameOptionData.SCORE_LIMIT, scoreGoal);
info.put(GameOptionData.TIMER_MULTIPLIER, timerMultiplier);
if (includePassword) {
info.put(GameOptionData.PASSWORD, password);
} }
return info; public static GameOptions deserialize(Provider<GameOptions> provider, final String text) {
} final GameOptions options = provider.get();
public static GameOptions deserialize(final String text) { if (text == null || text.isEmpty()) {
final GameOptions options = new GameOptions(); return options;
}
if (text == null || text.isEmpty()) { final JsonWrapper json = new JsonWrapper(text);
return options;
final String[] cardSetsParsed = json.getString(GameOptionData.CARD_SETS, "").split(",");
for (final String cardSetId : cardSetsParsed) {
if (!cardSetId.isEmpty()) {
options.cardSetIds.add(Integer.parseInt(cardSetId));
}
}
options.blanksInDeck = Math.max(options.minBlankCardLimit, Math.min(options.maxBlankCardLimit,
json.getInteger(GameOptionData.BLANKS_LIMIT, options.blanksInDeck)));
options.playerLimit = Math.max(options.minPlayerLimit, Math.min(options.maxPlayerLimit,
json.getInteger(GameOptionData.PLAYER_LIMIT, options.playerLimit)));
options.spectatorLimit = Math.max(options.minSpectatorLimit, Math.min(options.maxSpectatorLimit,
json.getInteger(GameOptionData.SPECTATOR_LIMIT, options.spectatorLimit)));
options.scoreGoal = Math.max(options.minScoreLimit, Math.min(options.maxScoreLimit,
json.getInteger(GameOptionData.SCORE_LIMIT, options.scoreGoal)));
options.timerMultiplier = json.getString(GameOptionData.TIMER_MULTIPLIER, options.timerMultiplier);
options.password = json.getString(GameOptionData.PASSWORD, options.password);
return options;
} }
final JsonWrapper json = new JsonWrapper(text); /**
* Update the options in-place (so that the Game doesn't need more locks).
final String[] cardSetsParsed = json.getString(GameOptionData.CARD_SETS, "").split(","); *
for (final String cardSetId : cardSetsParsed) { * @param newOptions
if (!cardSetId.isEmpty()) { * The new options to use.
options.cardSetIds.add(Integer.parseInt(cardSetId)); */
} public void update(final GameOptions newOptions) {
this.scoreGoal = newOptions.scoreGoal;
this.playerLimit = newOptions.playerLimit;
this.spectatorLimit = newOptions.spectatorLimit;
synchronized (this.cardSetIds) {
this.cardSetIds.clear();
this.cardSetIds.addAll(newOptions.cardSetIds);
}
this.blanksInDeck = newOptions.blanksInDeck;
this.password = newOptions.password;
this.timerMultiplier = newOptions.timerMultiplier;
} }
options.blanksInDeck = Math.max(MIN_BLANK_CARD_LIMIT, Math.min(MAX_BLANK_CARD_LIMIT, /**
json.getInteger(GameOptionData.BLANKS_LIMIT, options.blanksInDeck))); * Get the options in a form that can be sent to clients.
options.playerLimit = Math.max(MIN_PLAYER_LIMIT, Math.min(MAX_PLAYER_LIMIT, *
json.getInteger(GameOptionData.PLAYER_LIMIT, options.playerLimit))); * @param includePassword
options.spectatorLimit = Math.max(MIN_SPECTATOR_LIMIT, Math.min(MAX_SPECTATOR_LIMIT, * Include the actual password with the information. This should only be
json.getInteger(GameOptionData.SPECTATOR_LIMIT, options.spectatorLimit))); * sent to people in the game.
options.scoreGoal = Math.max(MIN_SCORE_LIMIT, Math.min(MAX_SCORE_LIMIT, * @return This game's general information: ID, host, state, player list, etc.
json.getInteger(GameOptionData.SCORE_LIMIT, options.scoreGoal))); */
options.timerMultiplier = json.getString(GameOptionData.TIMER_MULTIPLIER, options.timerMultiplier); public Map<GameOptionData, Object> serialize(final boolean includePassword) {
options.password = json.getString(GameOptionData.PASSWORD, options.password); final Map<GameOptionData, Object> info = new HashMap<GameOptionData, Object>();
return options; info.put(GameOptionData.CARD_SETS, cardSetIds);
} info.put(GameOptionData.BLANKS_LIMIT, blanksInDeck);
info.put(GameOptionData.PLAYER_LIMIT, playerLimit);
info.put(GameOptionData.SPECTATOR_LIMIT, spectatorLimit);
info.put(GameOptionData.SCORE_LIMIT, scoreGoal);
info.put(GameOptionData.TIMER_MULTIPLIER, timerMultiplier);
if (includePassword) {
info.put(GameOptionData.PASSWORD, password);
}
/** return info;
* @return Selected card set IDs which are local to PYX, for querying the database. }
*/
public Set<Integer> getPyxCardSetIds() { /**
final Set<Integer> pyxCardSetIds = new HashSet<Integer>(); * @return Selected card set IDs which are local to PYX, for querying the database.
for (final Integer cardSetId : cardSetIds) { */
if (cardSetId > 0) { public Set<Integer> getPyxCardSetIds() {
pyxCardSetIds.add(cardSetId); final Set<Integer> pyxCardSetIds = new HashSet<Integer>();
} for (final Integer cardSetId : cardSetIds) {
if (cardSetId > 0) {
pyxCardSetIds.add(cardSetId);
}
}
return pyxCardSetIds;
} }
return pyxCardSetIds;
}
} }

View File

@ -46,13 +46,13 @@ public class WhiteDeck {
/** /**
* Create a new white card deck, loading the cards from the database and shuffling them. * Create a new white card deck, loading the cards from the database and shuffling them.
*/ */
public WhiteDeck(final Collection<CardSet> cardSets, final int numBlanks) { public WhiteDeck(int maxBlankCardLimit, final Collection<CardSet> cardSets, final int numBlanks) {
final Set<WhiteCard> allCards = new HashSet<WhiteCard>(); final Set<WhiteCard> allCards = new HashSet<WhiteCard>();
for (final CardSet cardSet : cardSets) { for (final CardSet cardSet : cardSets) {
allCards.addAll(cardSet.getWhiteCards()); allCards.addAll(cardSet.getWhiteCards());
} }
deck = new ArrayList<WhiteCard>(allCards); deck = new ArrayList<WhiteCard>(allCards);
for (int i = 0; i < numBlanks && i < GameOptions.MAX_BLANK_CARD_LIMIT; i++) { for (int i = 0; i < numBlanks && i < maxBlankCardLimit; i++) {
deck.add(createBlankCard()); deck.add(createBlankCard());
} }
Collections.shuffle(deck); Collections.shuffle(deck);

View File

@ -5,6 +5,8 @@ import java.util.Map;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import com.google.inject.Provider;
import net.socialgamer.cah.CahModule;
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;
@ -22,10 +24,12 @@ import com.google.inject.Inject;
public class ChangeGameOptionHandler extends GameWithPlayerHandler { public class ChangeGameOptionHandler extends GameWithPlayerHandler {
public static final String OP = AjaxOperation.CHANGE_GAME_OPTIONS.toString(); public static final String OP = AjaxOperation.CHANGE_GAME_OPTIONS.toString();
private Provider<GameOptions> gameOptionsProvider;
@Inject @Inject
public ChangeGameOptionHandler(final GameManager gameManager) { public ChangeGameOptionHandler(final GameManager gameManager, Provider<GameOptions> gameOptionsProvider) {
super(gameManager); super(gameManager);
this.gameOptionsProvider = gameOptionsProvider;
} }
@Override @Override
@ -40,7 +44,7 @@ public class ChangeGameOptionHandler extends GameWithPlayerHandler {
} else { } else {
try { try {
final String value = request.getParameter(AjaxRequest.GAME_OPTIONS); final String value = request.getParameter(AjaxRequest.GAME_OPTIONS);
final GameOptions options = GameOptions.deserialize(value); final GameOptions options = GameOptions.deserialize(gameOptionsProvider, value);
final String oldPassword = game.getPassword(); final String oldPassword = game.getPassword();
game.updateGameSettings(options); game.updateGameSettings(options);

View File

@ -36,6 +36,7 @@ import javax.servlet.http.HttpServletResponse;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import net.socialgamer.cah.CahModule;
import net.socialgamer.cah.CahModule.BroadcastConnectsAndDisconnects; import net.socialgamer.cah.CahModule.BroadcastConnectsAndDisconnects;
import net.socialgamer.cah.CahModule.CookieDomain; import net.socialgamer.cah.CahModule.CookieDomain;
import net.socialgamer.cah.CahModule.GameChatEnabled; import net.socialgamer.cah.CahModule.GameChatEnabled;
@ -92,6 +93,22 @@ public class JavascriptConfigServlet extends HttpServlet {
builder.append(String.format("cah.INSECURE_ID_ALLOWED = %b;\n", insecureIdAllowed)); builder.append(String.format("cah.INSECURE_ID_ALLOWED = %b;\n", insecureIdAllowed));
builder.append(String.format("cah.BROADCASTING_USERS = %b;\n", broadcastingUsers)); builder.append(String.format("cah.BROADCASTING_USERS = %b;\n", broadcastingUsers));
builder.append(String.format("cah.game.MIN_PLAYER_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MinPlayerLimit.class))));
builder.append(String.format("cah.game.DEFAULT_PLAYER_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.DefaultPlayerLimit.class))));
builder.append(String.format("cah.game.MAX_PLAYER_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MaxPlayerLimit.class))));
builder.append(String.format("cah.game.MIN_SPECTATOR_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MinSpectatorLimit.class))));
builder.append(String.format("cah.game.DEFAULT_SPECTATOR_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.DefaultSpectatorLimit.class))));
builder.append(String.format("cah.game.MAX_SPECTATOR_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MaxSpectatorLimit.class))));
builder.append(String.format("cah.game.MIN_SCORE_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MinScoreLimit.class))));
builder.append(String.format("cah.game.DEFAULT_SCORE_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.DefaultScoreLimit.class))));
builder.append(String.format("cah.game.MAX_SCORE_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MaxScoreLimit.class))));
builder.append(String.format("cah.game.MIN_BLANK_CARD_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MinBlankCardLimit.class))));
builder.append(String.format("cah.game.DEFAULT_BLANK_CARD_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.DefaultBlankCardLimit.class))));
builder.append(String.format("cah.game.MAX_BLANK_CARD_LIMIT = %d;\n", injector.getInstance(Key.get(Integer.class, CahModule.MaxBlankCardLimit.class))));
resp.setContentType("text/javascript"); resp.setContentType("text/javascript");
final PrintWriter out = resp.getWriter(); final PrintWriter out = resp.getWriter();
out.println(builder.toString()); out.println(builder.toString());

View File

@ -79,6 +79,15 @@ public class GameManagerTest {
private int gameId; private int gameId;
private final ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(1); private final ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(1);
private Metrics metricsMock; private Metrics metricsMock;
private final Provider<GameOptions> gameOptionsProvider = new Provider<GameOptions>() {
@Override
public GameOptions get() {
return new GameOptions(20, 10, 3,
20, 10, 0,
4, 69, 8,
0, 0, 30);
}
};
private final Provider<Boolean> falseProvider = new Provider<Boolean>() { private final Provider<Boolean> falseProvider = new Provider<Boolean>() {
@Override @Override
public Boolean get() { public Boolean get() {
@ -123,6 +132,7 @@ public class GameManagerTest {
bind(Boolean.class).annotatedWith(ShowGamePermalink.class).toProvider(falseProvider); bind(Boolean.class).annotatedWith(ShowGamePermalink.class).toProvider(falseProvider);
bind(String.class).annotatedWith(GamePermalinkUrlFormat.class).toProvider(formatProvider); bind(String.class).annotatedWith(GamePermalinkUrlFormat.class).toProvider(formatProvider);
bind(Boolean.class).annotatedWith(AllowBlankCards.class).toProvider(falseProvider); bind(Boolean.class).annotatedWith(AllowBlankCards.class).toProvider(falseProvider);
bind(GameOptions.class).toProvider(gameOptionsProvider);
} }
@Provides @Provides
@ -173,15 +183,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, falseProvider, formatProvider, falseProvider)); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider));
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, falseProvider, formatProvider, falseProvider)); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider));
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, falseProvider, formatProvider, falseProvider)); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider));
// 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());
@ -191,7 +201,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, falseProvider, formatProvider, falseProvider)); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider));
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
@ -199,7 +209,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, falseProvider, formatProvider, falseProvider)); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider));
assertEquals(-1, gameManager.get().intValue()); assertEquals(-1, gameManager.get().intValue());
gameManager.destroyGame(2); gameManager.destroyGame(2);

View File

@ -60,6 +60,15 @@ public class GameTest {
private GameManager gmMock; private GameManager gmMock;
private Metrics metricsMock; private Metrics metricsMock;
private final ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(1); private final ScheduledThreadPoolExecutor timer = new ScheduledThreadPoolExecutor(1);
private final Provider<GameOptions> gameOptionsProvider = new Provider<GameOptions>() {
@Override
public GameOptions get() {
return new GameOptions(20, 10, 3,
20, 10, 0,
4, 69, 8,
0, 0, 30);
}
};
private final Provider<Boolean> falseProvider = new Provider<Boolean>() { private final Provider<Boolean> falseProvider = new Provider<Boolean>() {
@Override @Override
public Boolean get() { public Boolean get() {
@ -79,7 +88,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, falseProvider, formatProvider, falseProvider); formatProvider, falseProvider, formatProvider, falseProvider, gameOptionsProvider);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")