Hold on to your seats kids, it's another installment of "A Boy and His

Blowtorch". Refactored GameConfig and the EZ game framework, cleaning up some
old cruft from GameConfig (which will break other projects and which I'll fix
ASAP) and moved the XML based configuration system from ToyBox into EZGame.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@286 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2007-05-01 22:26:25 +00:00
parent 04dd58d759
commit 7538ddcc7f
47 changed files with 2392 additions and 1114 deletions
+58
View File
@@ -0,0 +1,58 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Contains a reference to the log object used by this package.
*/
public class Log
{
/** We dispatch our log messages through this logger. */
public static Logger log = Logger.getLogger("com.threerings.ezgame");
/** Convenience function. */
public static void debug (String message)
{
log.fine(message);
}
/** Convenience function. */
public static void info (String message)
{
log.info(message);
}
/** Convenience function. */
public static void warning (String message)
{
log.warning(message);
}
/** Convenience function. */
public static void logStackTrace (Throwable t)
{
log.log(Level.WARNING, t.getMessage(), t);
}
}
@@ -0,0 +1,309 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.client;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import org.apache.commons.io.IOUtils;
import com.samskivert.swing.HGroupLayout;
import com.samskivert.swing.SimpleSlider;
import com.threerings.util.MessageBundle;
import com.threerings.util.MessageManager;
import com.threerings.parlor.game.client.SwingGameConfigurator;
import com.threerings.parlor.game.data.GameAI;
import com.threerings.ezgame.data.AIParameter;
import com.threerings.ezgame.data.ChoiceParameter;
import com.threerings.ezgame.data.EZGameConfig;
import com.threerings.ezgame.data.FileParameter;
import com.threerings.ezgame.data.GameDefinition;
import com.threerings.ezgame.data.Parameter;
import com.threerings.ezgame.data.RangeParameter;
import com.threerings.ezgame.data.ToggleParameter;
import com.threerings.ezgame.util.EZGameContext;
import static com.threerings.ezgame.Log.log;
/**
* Handles the configuration of an EZ game. This works in conjunction with the {@link EZGameConfig}
* to provide a generic mechanism for defining and obtaining game configuration settings.
*/
public class EZGameConfigurator extends SwingGameConfigurator
{
// documentation inherited
protected void gotGameConfig ()
{
super.gotGameConfig();
EZGameContext ctx = (EZGameContext)_ctx;
EZGameConfig config = (EZGameConfig)_config;
GameDefinition gamedef = config.getGameDefinition();
// create our parameter editors
if (_editors == null) {
MessageBundle msgs = ctx.getMessageManager().getBundle(config.getGameIdent());
_editors = new ParamEditor[gamedef.params.length];
for (int ii = 0; ii < _editors.length; ii++) {
_editors[ii] = createEditor(ctx, msgs, gamedef.params[ii]);
addControl(new JLabel(msgs.get(gamedef.params[ii].getLabel())),
(JComponent) _editors[ii]);
}
}
// now read our parameters
for (int ii = 0; ii < gamedef.params.length; ii++) {
_editors[ii].readParameter(gamedef.params[ii], config);
}
}
// documentation inherited
protected void flushGameConfig ()
{
super.flushGameConfig();
EZGameConfig config = (EZGameConfig)_config;
GameDefinition gamedef = config.getGameDefinition();
for (int ii = 0; ii < gamedef.params.length; ii++) {
_editors[ii].writeParameter(gamedef.params[ii], config);
}
}
protected ParamEditor createEditor (EZGameContext ctx, MessageBundle msgs, Parameter param)
{
if (param instanceof AIParameter) {
return new AIEditor((AIParameter)param);
} else if (param instanceof RangeParameter) {
return new RangeEditor((RangeParameter)param);
} else if (param instanceof ToggleParameter) {
return new ToggleEditor((ToggleParameter)param);
} else if (param instanceof ChoiceParameter) {
return new ChoiceEditor(msgs, (ChoiceParameter)param);
} else if (param instanceof FileParameter) {
return new FileEditor(ctx, (FileParameter)param);
} else {
log.warning("Unknown parameter type! " + param + ".");
return null;
}
}
/** Provides a uniform interface to our UI components. */
protected static interface ParamEditor
{
public void readParameter (Parameter param, EZGameConfig config);
public void writeParameter (Parameter param, EZGameConfig config);
}
protected class RangeEditor extends SimpleSlider implements ParamEditor
{
public RangeEditor (RangeParameter param)
{
super(null, param.minimum, param.maximum, param.start);
}
public void readParameter (Parameter param, EZGameConfig config)
{
setValue((Integer)config.params.get(param.ident));
}
public void writeParameter (Parameter param, EZGameConfig config)
{
config.params.put(param.ident, getValue());
}
}
protected class ToggleEditor extends JPanel implements ParamEditor
{
public ToggleEditor (ToggleParameter param)
{
setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
add(_box = new JCheckBox(null, null, param.start));
}
public void readParameter (Parameter param, EZGameConfig config)
{
_box.setSelected((Boolean)config.params.get(param.ident));
}
public void writeParameter (Parameter param, EZGameConfig config)
{
config.params.put(param.ident, _box.isSelected());
}
protected JCheckBox _box;
}
protected class ChoiceEditor extends JPanel implements ParamEditor
{
public ChoiceEditor (MessageBundle msgs, ChoiceParameter param)
{
setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
Choice[] choices = new Choice[param.choices.length];
Choice selection = null;
for (int ii = 0; ii < choices.length; ii++) {
String choice = param.choices[ii];
choices[ii] = new Choice();
choices[ii].choice = choice;
choices[ii].label = msgs.get(param.getChoiceLabel(ii));
if (choice.equals(param.start)) {
selection = choices[ii];
}
}
add(_combo = new JComboBox(choices));
if (selection != null) {
_combo.setSelectedItem(selection);
}
}
public void readParameter (Parameter param, EZGameConfig config)
{
Choice selected = new Choice();
selected.choice = (String)config.params.get(param.ident);
_combo.setSelectedItem(selected);
}
public void writeParameter (Parameter param, EZGameConfig config)
{
config.params.put(param.ident, ((Choice)_combo.getSelectedItem()).choice);
}
protected JComboBox _combo;
}
protected static class Choice
{
public String choice;
public String label;
public String toString () {
return label;
}
public boolean equals (Object other) {
return (other instanceof Choice) && choice.equals(((Choice) other).choice);
}
}
protected class FileEditor extends JPanel
implements ParamEditor, ActionListener
{
public FileEditor (EZGameContext ctx, FileParameter param)
{
_ctx = ctx;
_param = param;
setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
String label = ctx.getMessageManager().getBundle(
MessageManager.GLOBAL_BUNDLE).get("m.file_unset");
add(_show = new JButton(label));
_show.addActionListener(this);
}
public void readParameter (Parameter param, EZGameConfig config)
{
// nothing doing
}
public void writeParameter (Parameter param, EZGameConfig config)
{
if (_data != null) {
config.params.put(param.ident, _data);
}
}
public void actionPerformed (ActionEvent event)
{
if (event.getSource() == _show) {
if (_chooser == null) {
_chooser = new JFileChooser();
}
int rv = _chooser.showOpenDialog(this);
if (rv == JFileChooser.APPROVE_OPTION) {
File file = _chooser.getSelectedFile();
try {
if (_param.binary) {
_data = IOUtils.toByteArray(new FileInputStream(file));
} else {
_data = IOUtils.toString(new FileReader(file));
}
_show.setText(file.getName());
} catch (IOException ioe) {
String msg = MessageBundle.tcompose(
"m.file_read_failure", ioe.getMessage());
_ctx.getChatDirector().displayFeedback(null, msg);
log.warning("Failed to read '" + file + "': " + ioe.getMessage());
}
}
}
}
protected EZGameContext _ctx;
protected FileParameter _param;
protected JButton _show;
protected JFileChooser _chooser;
protected Object _data;
}
protected class AIEditor extends SimpleSlider implements ParamEditor
{
public AIEditor (AIParameter param)
{
super(null, 0, param.maximum, 0);
}
public void readParameter (Parameter param, EZGameConfig config)
{
setValue((config.ais == null) ? 0 : config.ais.length);
}
public void writeParameter (Parameter param, EZGameConfig config)
{
config.ais = new GameAI[getValue()];
for (int ii = 0; ii < config.ais.length; ii++) {
// TODO: allow specification of difficulty and personality
config.ais[ii] = new GameAI(0, 0);
}
}
}
protected ParamEditor[] _editors;
}
@@ -38,7 +38,6 @@ import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.ezgame.data.EZGameConfig;
import com.threerings.ezgame.data.EZGameObject;
import com.threerings.ezgame.Game;
@@ -56,16 +55,17 @@ public class EZGamePanel extends JPanel
// add a listener so that we hear about all new children
addContainerListener(this);
EZGameConfig cfg = (EZGameConfig) ctrl.getPlaceConfig();
try {
_gameView = (Component) Class.forName(cfg.gameMedia).newInstance();
add(_gameView);
} catch (RuntimeException re) {
throw re;
// TODO: sort out if and how EZ games will create their views
// EZGameConfig cfg = (EZGameConfig) ctrl.getPlaceConfig();
// try {
// _gameView = (Component) Class.forName(cfg.gameMedia).newInstance();
// add(_gameView);
// } catch (RuntimeException re) {
// throw re;
} catch (Exception e) {
throw new RuntimeException(e);
}
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// TODO: Add a standard chat display?
//addChild(new ChatDisplayBox(ctx));
@@ -0,0 +1,49 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.util.ActionScript;
/**
* Models a parameter that is used to configure AIs.
*/
@ActionScript(omit=true)
public class AIParameter extends Parameter
{
/** Indicates the maximum number of AIs in the game. */
public int maximum;
// TODO: allow specification of difficulty range
// TODO: allow specification of personality types
@Override // documentation inherited
public String getLabel ()
{
return "m.ai_" + ident;
}
@Override // documentation inherited
public Object getDefaultValue ()
{
return 0;
}
}
@@ -0,0 +1,57 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.util.ActionScript;
/**
* Models a parameter that allows the selection of one of a list of choices (specified as strings).
*/
public class ChoiceParameter extends Parameter
{
/** The set of choices available for this parameter. */
public String[] choices;
/** The starting selection. */
public String start;
/**
* Returns the translation key for the specified choice.
*/
@ActionScript(omit=true)
public String getChoiceLabel (int index)
{
return "m.choice_" + choices[index];
}
@Override @ActionScript(omit=true) // documentation inherited
public String getLabel ()
{
return "m.choice_" + ident;
}
@Override // documentation inherited
public Object getDefaultValue ()
{
return start;
}
}
@@ -21,90 +21,80 @@
package com.threerings.ezgame.data;
import com.threerings.util.MessageBundle;
import com.threerings.crowd.client.PlaceController;
import com.threerings.util.StreamableHashMap;
import com.threerings.parlor.game.client.GameConfigurator;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.ezgame.client.EZGameController;
import com.threerings.ezgame.client.EZGameConfigurator;
/**
* A game config for a simple multiplayer game.
*/
public class EZGameConfig extends GameConfig
{
/** The name of the game. */
public String name;
/** Our configuration parameters. These will be seeded with the defaults from the game
* definition and then configured by the player in the lobby. */
public StreamableHashMap<String,Object> params = new StreamableHashMap<String,Object>();
/** If non-zero, a game id used to persistently identify the game.
* This could be thought of as a new-style rating id. */
public int persistentGameId;
/** The media for the game. In flash this is the URL to the SWF file.
* In Java, this will be a class name, or maybe a Jar. TODO? */
public String gameMedia;
/** The game type. */
public byte gameType = SEATED_GAME;
/** Custom configuration for the game. May only be interpretable on the
* client. */
public Object customConfig;
@Override
public byte getGameType ()
/** A zero argument constructor used when unserializing. */
public EZGameConfig ()
{
return gameType;
}
// from abstract GameConfig
public String getBundleName ()
/** Constructs a game config based on the supplied game definition. */
public EZGameConfig (int gameId, GameDefinition gameDef)
{
return "general";
_gameId = gameId;
_gameDef = gameDef;
// set the default values for our parameters
for (int ii = 0; ii < gameDef.params.length; ii++) {
params.put(gameDef.params[ii].ident, gameDef.params[ii].getDefaultValue());
}
}
// from abstract GameConfig
/**
* Returns the non-changing metadata that defines this game.
*/
public GameDefinition getGameDefinition ()
{
return _gameDef;
}
@Override // from GameConfig
public int getGameId ()
{
return _gameId;
}
@Override // from GameConfig
public String getGameIdent ()
{
return _gameDef.ident;
}
@Override // from GameConfig
public int getMatchType ()
{
return _gameDef.match.getMatchType();
}
@Override // from GameConfig
public GameConfigurator createConfigurator ()
{
// TODO
return null;
return new EZGameConfigurator();
}
@Override
public String getGameName ()
{
return MessageBundle.taint(name);
}
@Override // from PlaceConfig
public PlaceController createController ()
{
return new EZGameController();
}
// from abstract PlaceConfig
@Override // from GameConfig
public String getManagerClassName ()
{
return "com.threerings.ezgame.server.EZGameManager";
return _gameDef.manager;
}
@Override
public boolean equals (Object other)
{
if (!super.equals(other)) {
return false;
}
/** Our game's unique id. */
protected int _gameId;
EZGameConfig that = (EZGameConfig) other;
return this.persistentGameId == that.persistentGameId &&
this.gameMedia.equals(that.gameMedia);
}
@Override
public int hashCode ()
{
return super.hashCode() ^ persistentGameId;
}
/** Our game definition. */
protected GameDefinition _gameDef;
}
@@ -0,0 +1,52 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.util.ActionScript;
/**
* Models a paramter that can be used to load the contents of a file into a byte array or string
* and ship it to the server.
*/
@ActionScript(omit=true)
public class FileParameter extends Parameter
{
/** Whether or not the contents of the file should be supplied as binary data. If false, the
* file will be loaded as text in the platform default encoding . */
public boolean binary = false;
@Override // documentation inherited
public String getLabel ()
{
return "m.file_" + ident;
}
@Override // documentation inherited
public Object getDefaultValue ()
{
if (binary) {
return new byte[0];
} else {
return "";
}
}
}
@@ -0,0 +1,101 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import java.util.ArrayList;
import com.samskivert.util.StringUtil;
import com.threerings.io.Streamable;
import com.threerings.util.ActionScript;
/**
* Contains the information about a game as described by the game definition XML file.
*/
public abstract class GameDefinition implements Streamable
{
/** A string identifier for the game. */
public String ident;
/** The class name of the <code>GameController</code> derivation that we use to bootstrap on
* the client. */
public String controller;
/** The class name of the <code>GameManager</code> derivation that we use to manage the game on
* the server. */
public String manager;
/** The MD5 digest of the game media file. */
public String digest;
/** The configuration of the match-making mechanism. */
public MatchConfig match;
/** Parameters used to configure the game itself. */
public Parameter[] params;
/**
* Provides the path to this game's media (a jar file or an SWF).
*
* @param gameId the unique id of the game provided when this game definition was registered
* with the system, or -1 if we're running in test mode.
*/
public abstract String getMediaPath (int gameId);
/**
* Returns true if a single player can play this game (possibly against AI opponents), or if
* opponents are needed.
*/
public boolean isSinglePlayerPlayable ()
{
// maybe it's just single player no problem
int minPlayers = 2;
if (match != null) {
minPlayers = match.getMinimumPlayers();
if (minPlayers <= 1) {
return true;
}
}
// or maybe it has AIs
int aiCount = 0;
for (Parameter param : params) {
if (param instanceof AIParameter) {
aiCount = ((AIParameter)param).maximum;
}
}
return (minPlayers - aiCount) <= 1;
}
/** Called when parsing a game definition from XML. */
@ActionScript(omit=true)
public void setParams (ArrayList<Parameter> list)
{
params = list.toArray(new Parameter[list.size()]);
}
/** Generates a string representation of this instance. */
public String toString ()
{
return StringUtil.fieldsToString(this);
}
}
@@ -0,0 +1,39 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.parlor.game.data.GameConfig;
/**
* Used to configure the match-making interface for a game. Particular match-making mechanisms
* extend this class and specify their own special configuration parameters.
*/
public abstract class MatchConfig extends SimpleStreamableObject
{
/** Returns the matchmaking type to use for this game, e.g. {@link GameConfig.SEATED_GAME}. */
public abstract int getMatchType ();
/** Returns the minimum number of players needed to play this game. */
public abstract int getMinimumPlayers ();
}
@@ -0,0 +1,55 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.samskivert.util.StringUtil;
import com.threerings.io.Streamable;
/**
* Defines a configuration parameter for a game. Various derived classes exist that define
* particular types of configuration parameters including choices, toggles, ranges, etc.
*/
public abstract class Parameter implements Streamable
{
/** A string identifier that names this parameter. */
public String ident;
/** A human readable name for this configuration parameter. */
public String name;
/** A human readable tooltip to display when the mouse is hovered over this configuration
* parameter. */
public String tip;
/** Returns the translation key for this parameter's label. */
public abstract String getLabel ();
/** Returns the default value of this parameter. */
public abstract Object getDefaultValue ();
/** Generates a string representation of this instance. */
public String toString ()
{
return StringUtil.fieldsToString(this);
}
}
@@ -27,6 +27,7 @@ import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamable;
import com.threerings.io.Streamer;
import com.threerings.util.ActionScript;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.NamedEvent;
@@ -34,8 +35,7 @@ import com.threerings.presents.dobj.NamedEvent;
import com.threerings.ezgame.util.EZObjectMarshaller;
/**
* Represents a property change on the actionscript object we
* use in EZGameObject.
* Represents a property change on the actionscript object we use in EZGameObject.
*/
public class PropertySetEvent extends NamedEvent
{
@@ -47,17 +47,16 @@ public class PropertySetEvent extends NamedEvent
/**
* Create a PropertySetEvent.
*/
public PropertySetEvent (
int targetOid, String propName, Object value, int index, Object oldValue)
public PropertySetEvent (int targetOid, String propName, Object value, int index, Object ovalue)
{
super(targetOid, propName);
_data = value;
_index = index;
_oldValue = oldValue;
_oldValue = ovalue;
}
/**
* Get the value that was set for the property.
* Returns the value that was set for the property.
*/
public Object getValue ()
{
@@ -65,7 +64,7 @@ public class PropertySetEvent extends NamedEvent
}
/**
* Get the old value.
* Returns the old value.
*/
public Object getOldValue ()
{
@@ -73,7 +72,7 @@ public class PropertySetEvent extends NamedEvent
}
/**
* Get the index, or -1 if not applicable.
* Returns the index, or -1 if not applicable.
*/
public int getIndex ()
{
@@ -102,7 +101,7 @@ public class PropertySetEvent extends NamedEvent
}
}
@Override
@Override @ActionScript(name="toStringBuf")
protected void toString (StringBuilder buf)
{
buf.append("PropertySetEvent ");
@@ -0,0 +1,51 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.util.ActionScript;
/**
* Models a parameter that can contain an integer value in a specified range.
*/
public class RangeParameter extends Parameter
{
/** The minimum value of this parameter. */
public int minimum;
/** The maximum value of this parameter. */
public int maximum;
/** The starting value for this parameter. */
public int start;
@Override @ActionScript(omit=true) // documentation inherited
public String getLabel ()
{
return "m.range_" + ident;
}
@Override // documentation inherited
public Object getDefaultValue ()
{
return start;
}
}
@@ -0,0 +1,54 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.parlor.game.data.GameConfig;
/**
* Extends {@link MatchConfig} with information about match-making in the table style.
*/
public class TableMatchConfig extends MatchConfig
{
/** The minimum number of seats at this table. */
public int minSeats;
/** The starting setting for the number of seats at this table. */
public int startSeats;
/** The maximum number of seats at this table. */
public int maxSeats;
/** This is set to true if this is a party game. */
public boolean isPartyGame;
@Override // from MatchConfig
public int getMatchType ()
{
return isPartyGame ? GameConfig.PARTY : GameConfig.SEATED_GAME;
}
@Override // from MatchConfig
public int getMinimumPlayers ()
{
return minSeats;
}
}
@@ -0,0 +1,45 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.data;
import com.threerings.util.ActionScript;
/**
* Models a parameter that allows the toggling of a single value.
*/
public class ToggleParameter extends Parameter
{
/** The starting state for this parameter. */
public boolean start;
@Override @ActionScript(omit=true) // documentation inherited
public String getLabel ()
{
return "m.toggle_" + ident;
}
@Override // documentation inherited
public Object getDefaultValue ()
{
return start;
}
}
@@ -58,9 +58,8 @@ import com.threerings.parlor.game.server.GameManager;
import com.threerings.parlor.turn.server.TurnGameManager;
import com.threerings.ezgame.data.EZGameConfig;
import com.threerings.ezgame.data.EZGameObject;
import com.threerings.ezgame.data.EZGameMarshaller;
import com.threerings.ezgame.data.EZGameObject;
import com.threerings.ezgame.data.PropertySetEvent;
import com.threerings.ezgame.data.UserCookie;
@@ -355,7 +354,7 @@ public class EZGameManager extends GameManager
throw new InvocationException(INTERNAL_ERROR);
}
gcm.getCookie(getPersistentGameId(), body, new ResultListener<byte[]>() {
gcm.getCookie(_gameconfig.getGameId(), body, new ResultListener<byte[]>() {
public void requestCompleted (byte[] result) {
// Result may be null: that's ok, it means we've looked up the user's
// nonexistant cookie. Only set the cookie if the playerIndex is still in the
@@ -391,7 +390,7 @@ public class EZGameManager extends GameManager
_gameObj.addToUserCookies(cookie);
}
gcm.setCookie(getPersistentGameId(), caller, value);
gcm.setCookie(_gameconfig.getGameId(), caller, value);
}
/**
@@ -442,26 +441,13 @@ public class EZGameManager extends GameManager
new PropertySetEvent(_gameObj.getOid(), propName, value, index, oldValue));
}
/**
* Get the game id of this ezgame, as set in the config.
*/
protected int getPersistentGameId ()
throws InvocationException
{
int id = ((EZGameConfig) _config).persistentGameId;
if (id == 0) {
throw new InvocationException("Persistent game id not set.");
}
return id;
}
/**
* Validate that the specified user has access to do things in the game.
*/
protected void validateUser (ClientObject caller)
throws InvocationException
{
switch (getGameType()) {
switch (getMatchType()) {
case GameConfig.PARTY:
return; // always validate.
@@ -495,7 +481,7 @@ public class EZGameManager extends GameManager
protected BodyObject getPlayerByOid (int oid)
{
// verify that they're a player
switch (getGameType()) {
switch (getMatchType()) {
case GameConfig.PARTY:
// all occupants are players in a party game
break;
@@ -0,0 +1,35 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.util;
import com.threerings.util.MessageManager;
import com.threerings.parlor.util.ParlorContext;
/**
* Extends the Parlor context with bits needed by the EZ game framework.
*/
public interface EZGameContext extends ParlorContext
{
/** Returns a message manager that can be used to translate strings. */
public MessageManager getMessageManager ();
}
@@ -0,0 +1,203 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.ezgame.xml;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.ObjectCreateRule;
import org.apache.commons.digester.Rule;
import com.samskivert.util.StringUtil;
import com.samskivert.xml.SetFieldRule;
import com.samskivert.xml.SetNextFieldRule;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.ezgame.data.AIParameter;
import com.threerings.ezgame.data.ChoiceParameter;
import com.threerings.ezgame.data.FileParameter;
import com.threerings.ezgame.data.GameDefinition;
import com.threerings.ezgame.data.MatchConfig;
import com.threerings.ezgame.data.RangeParameter;
import com.threerings.ezgame.data.TableMatchConfig;
import com.threerings.ezgame.data.ToggleParameter;
import com.threerings.parlor.game.data.GameConfig;
/**
* Parses the XML definition of a game.
*/
public class GameParser
{
public GameParser ()
{
// create and configure our digester
_digester = new Digester() {
public void fatalError (SAXParseException exception)
throws SAXException {
// the standard digester needlessly logs a fatal warning here
if (errorHandler != null) {
errorHandler.fatalError(exception);
}
}
};
// add the rules to parse the GameDefinition and its fields
_digester.addObjectCreate("game", getGameDefinitionClass());
_digester.addRule("game/ident", new SetFieldRule("ident"));
_digester.addRule("game/controller", new SetFieldRule("controller"));
_digester.addRule("game/manager", new SetFieldRule("manager"));
_digester.addRule("game/match", new Rule() {
public void begin (String namespace, String name, Attributes attrs) throws Exception {
String type = attrs.getValue("type");
if (StringUtil.isBlank(type)) {
String errmsg = "<match> block missing type attribute.";
throw new Exception(errmsg);
}
addMatchParsingRules(digester, type);
}
public void end (String namespace, String name) throws Exception {
MatchConfig match = (MatchConfig)digester.pop();
((GameDefinition)digester.peek()).match = match;
}
});
// these rules handle customization parameters
_digester.addRule("game/params", new ObjectCreateRule(ArrayList.class));
_digester.addSetNext("game/params", "setParams", ArrayList.class.getName());
addParameter("game/params/ai", AIParameter.class);
addParameter("game/params/range", RangeParameter.class);
addParameter("game/params/choice", ChoiceParameter.class);
addParameter("game/params/toggle", ToggleParameter.class);
addParameter("game/params/file", FileParameter.class);
// add a rule to put the parsed definition onto our list
_digester.addSetNext("game", "add", Object.class.getName());
}
/**
* Parses a game definition from the supplied XML file.
*
* @exception IOException thrown if an error occurs reading the file.
* @exception SAXException thrown if an error occurs parsing the XML.
*/
public GameDefinition parseGame (File source)
throws IOException, SAXException
{
return parseGame(new FileReader(source));
}
/**
* Parses a game definition from the supplied XML source.
*
* @exception IOException thrown if an error occurs reading the file.
* @exception SAXException thrown if an error occurs parsing the XML.
*/
public GameDefinition parseGame (Reader source)
throws IOException, SAXException
{
// make sure nothing is lingering on the stack from a previous failure
_digester.clear();
// push an array list on the digester which will receive the parsed game definition
ArrayList list = new ArrayList();
_digester.push(list);
_digester.parse(source);
return (list.size() > 0) ? (GameDefinition)list.get(0) : null;
}
/**
* Returns the {@link GameDefinition} class (or derived class) to use when parsing our game
* definition.
*/
protected String getGameDefinitionClass ()
{
return GameDefinition.class.getName();
}
protected void addParameter (String path, Class pclass)
{
_digester.addRule(path, new ObjectCreateRule(pclass));
_digester.addRule(path, new SetPropertyFieldsRule());
_digester.addSetNext(path, "add", Object.class.getName());
}
/**
* Adds the rules needed to parse a custom match config, as well as the {@link MatchConfig}
* derived instance itself, based on the supplied type.
*/
protected void addMatchParsingRules (Digester digester, String type)
throws Exception
{
int itype = -1;
try {
itype = Integer.valueOf(type);
} catch (Exception e) {
for (int ii = 0; ii < GameConfig.TYPE_STRINGS.length; ii++) {
if (GameConfig.TYPE_STRINGS[ii].equals(type)) {
itype = ii;
break;
}
}
}
switch (itype) {
case GameConfig.SEATED_GAME:
digester.push(createMatchConfig());
digester.addRule("game/match/min_seats", new SetFieldRule("minSeats"));
digester.addRule("game/match/max_seats", new SetFieldRule("maxSeats"));
digester.addRule("game/match/start_seats", new SetFieldRule("startSeats"));
break;
case GameConfig.PARTY:
// party games are handled by a specially configured table
TableMatchConfig config = createMatchConfig();
config.minSeats = config.maxSeats = config.startSeats = 1;
config.isPartyGame = true;
digester.push(config);
break;
case GameConfig.SEATED_CONTINUOUS:
// TODO
default:
String errmsg = "Unknown match-making config type '" + type + "'.";
throw new Exception(errmsg);
}
}
protected TableMatchConfig createMatchConfig ()
{
return new TableMatchConfig();
}
/** Used to process XML descriptions. */
protected Digester _digester;
}