Moving bits into src/main and src/test. Reinstatement of actual test

workingness coming shortly.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@995 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2010-11-18 05:01:16 +00:00
parent c2cddf5249
commit ec27a1122d
495 changed files with 39 additions and 27 deletions
@@ -0,0 +1,59 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import com.threerings.io.SimpleStreamableObject;
/**
* A simple class for keeping track of information for each lobby in
* operation on the server.
*/
public class Lobby extends SimpleStreamableObject
{
/** The object id of the lobby place object. */
public int placeOid;
/** The universal game identifier string for the game matchmade by
* this lobby. */
public String gameIdent;
/** The human readable name of the lobby. */
public String name;
/**
* Constructs a lobby record and initializes it with the specified
* values.
*/
public Lobby (int placeOid, String gameIdent, String name)
{
this.placeOid = placeOid;
this.gameIdent = gameIdent;
this.name = name;
}
/**
* Constructs a blank lobby record suitable for unserialization.
*/
public Lobby ()
{
}
}
@@ -0,0 +1,111 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import java.util.Properties;
import javax.swing.JComponent;
import javax.swing.JLabel;
import com.samskivert.util.StringUtil;
import com.threerings.crowd.client.PlaceController;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.micasa.util.MiCasaContext;
public class LobbyConfig extends PlaceConfig
{
@Override
public PlaceController createController ()
{
return new LobbyController();
}
@Override
public String getManagerClassName ()
{
return "com.threerings.micasa.lobby.LobbyManager";
}
/**
* Derived classes override this function and create the appropriate
* matchmaking user interface component.
*/
public JComponent createMatchMakingView (MiCasaContext ctx)
{
return new JLabel("Match-making view goes here.");
}
/**
* Instantiates and returns a game config instance using the game
* config classname provided by the lobby configuration parameters.
*
* @exception Exception thrown if a problem occurs loading or
* instantiating the class.
*/
public GameConfig getGameConfig ()
throws Exception
{
return (GameConfig)Class.forName(_gameConfigClass).newInstance();
}
/**
* Initializes this lobby config object with the properties that are
* used to configure the lobby. This is called on the server when the
* lobby is loaded.
*/
public void init (Properties config)
throws Exception
{
_gameConfigClass = getConfigValue(config, "game_config");
}
@Override
protected void toString (StringBuilder buf)
{
super.toString(buf);
if (buf.length() > 1) {
buf.append(", ");
}
buf.append("game_config=").append(_gameConfigClass);
}
/** Looks up a configuration property in the supplied properties
* object and throws an exception if it's not found. */
protected String getConfigValue (Properties config, String key)
throws Exception
{
String value = config.getProperty(key);
if (StringUtil.isBlank(value)) {
throw new Exception("Missing '" + key + "' definition in " +
"lobby configuration.");
}
return value;
}
/** The name of the game config class that represents the type of game
* we are matchmaking for in this lobby. */
protected String _gameConfigClass;
}
@@ -0,0 +1,125 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import com.threerings.util.Name;
import com.threerings.crowd.client.PlaceController;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.parlor.client.Invitation;
import com.threerings.parlor.client.InvitationHandler;
import com.threerings.parlor.client.InvitationResponseObserver;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.micasa.util.MiCasaContext;
import static com.threerings.micasa.Log.log;
public class LobbyController extends PlaceController
implements InvitationHandler, InvitationResponseObserver
{
@Override
public void init (CrowdContext ctx, PlaceConfig config)
{
// cast our context reference
_ctx = (MiCasaContext)ctx;
_config = (LobbyConfig)config;
super.init(ctx, config);
// register ourselves as the invitation handler
_ctx.getParlorDirector().setInvitationHandler(this);
}
@Override
protected PlaceView createPlaceView (CrowdContext ctx)
{
return new LobbyPanel(_ctx, _config);
}
@Override
public void willEnterPlace (PlaceObject plobj)
{
super.willEnterPlace(plobj);
try {
// if a system property has been specified requesting that we
// invite another player, do so now
String invitee = System.getProperty("invitee");
if (invitee != null) {
// create a game config object
try {
GameConfig config = _config.getGameConfig();
_ctx.getParlorDirector().invite(
new Name(invitee), config, this);
} catch (Exception e) {
log.warning("Error instantiating game config.", e);
}
}
} catch (SecurityException se) {
// nothing to see here, move it along...
}
}
// documentation inherited from interface
public void invitationReceived (Invitation invite)
{
log.info("Invitation received [invite=" + invite + "].");
// accept the invitation. we're game...
invite.accept();
}
// documentation inherited from interface
public void invitationCancelled (Invitation invite)
{
log.info("Invitation cancelled " + invite + ".");
}
// documentation inherited from interface
public void invitationAccepted (Invitation invite)
{
log.info("Invitation accepted " + invite + ".");
}
// documentation inherited from interface
public void invitationRefused (Invitation invite, String message)
{
log.info("Invitation refused [invite=" + invite +
", message=" + message + "].");
}
// documentation inherited from interface
public void invitationCountered (Invitation invite, GameConfig config)
{
log.info("Invitation countered [invite=" + invite +
", config=" + config + "].");
}
protected MiCasaContext _ctx;
protected LobbyConfig _config;
}
@@ -0,0 +1,75 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import javax.annotation.Generated;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationDispatcher;
import com.threerings.presents.server.InvocationException;
/**
* Dispatches requests to the {@link LobbyProvider}.
*/
@Generated(value={"com.threerings.presents.tools.GenServiceTask"},
comments="Derived from LobbyService.java.")
public class LobbyDispatcher extends InvocationDispatcher<LobbyMarshaller>
{
/**
* Creates a dispatcher that may be registered to dispatch invocation
* service requests for the specified provider.
*/
public LobbyDispatcher (LobbyProvider provider)
{
this.provider = provider;
}
@Override
public LobbyMarshaller createMarshaller ()
{
return new LobbyMarshaller();
}
@Override
public void dispatchRequest (
ClientObject source, int methodId, Object[] args)
throws InvocationException
{
switch (methodId) {
case LobbyMarshaller.GET_CATEGORIES:
((LobbyProvider)provider).getCategories(
source, (LobbyService.CategoriesListener)args[0]
);
return;
case LobbyMarshaller.GET_LOBBIES:
((LobbyProvider)provider).getLobbies(
source, (String)args[0], (LobbyService.LobbiesListener)args[1]
);
return;
default:
super.dispatchRequest(source, methodId, args);
return;
}
}
}
@@ -0,0 +1,82 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import java.util.Properties;
import com.samskivert.util.StringUtil;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.server.PlaceManager;
import static com.threerings.micasa.Log.log;
/**
* Takes care of the server side of a particular lobby.
*/
public class LobbyManager extends PlaceManager
{
/**
* Initializes this lobby manager with its configuration properties.
*
* @exception Exception thrown if a configuration error is detected.
*/
public void init (LobbyRegistry lobreg, Properties config)
throws Exception
{
// look up some configuration parameters
_gameIdent = getConfigValue(config, "ugi");
_name = getConfigValue(config, "name");
// let the lobby registry know that we're up and running
lobreg.lobbyReady(_plobj.getOid(), _gameIdent, _name);
log.info("Lobby manager initialized [ident=" + _gameIdent +
", name=" + _name + "].");
}
/** Looks up a configuration property in the supplied properties
* object and throws an exception if it's not found. */
protected String getConfigValue (Properties config, String key)
throws Exception
{
String value = config.getProperty(key);
if (StringUtil.isBlank(value)) {
throw new Exception("Missing '" + key + "' definition in " +
"lobby configuration.");
}
return value;
}
@Override // from PlaceManager
protected PlaceObject createPlaceObject ()
{
return new LobbyObject();
}
/** The universal game identifier for the game matchmade by this
* lobby. */
protected String _gameIdent;
/** The human readable name of this lobby. */
protected String _name;
}
@@ -0,0 +1,139 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import javax.annotation.Generated;
import com.threerings.presents.client.Client;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
import java.util.List;
/**
* Provides the implementation of the {@link LobbyService} interface
* that marshalls the arguments and delivers the request to the provider
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*/
@Generated(value={"com.threerings.presents.tools.GenServiceTask"},
comments="Derived from LobbyService.java.")
public class LobbyMarshaller extends InvocationMarshaller
implements LobbyService
{
/**
* Marshalls results to implementations of {@link LobbyService.CategoriesListener}.
*/
public static class CategoriesMarshaller extends ListenerMarshaller
implements CategoriesListener
{
/** The method id used to dispatch {@link #gotCategories}
* responses. */
public static final int GOT_CATEGORIES = 1;
// from interface CategoriesMarshaller
public void gotCategories (String[] arg1)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, GOT_CATEGORIES,
new Object[] { arg1 }, transport));
}
@Override // from InvocationMarshaller
public void dispatchResponse (int methodId, Object[] args)
{
switch (methodId) {
case GOT_CATEGORIES:
((CategoriesListener)listener).gotCategories(
(String[])args[0]);
return;
default:
super.dispatchResponse(methodId, args);
return;
}
}
}
/**
* Marshalls results to implementations of {@link LobbyService.LobbiesListener}.
*/
public static class LobbiesMarshaller extends ListenerMarshaller
implements LobbiesListener
{
/** The method id used to dispatch {@link #gotLobbies}
* responses. */
public static final int GOT_LOBBIES = 1;
// from interface LobbiesMarshaller
public void gotLobbies (List<Lobby> arg1)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, GOT_LOBBIES,
new Object[] { arg1 }, transport));
}
@Override // from InvocationMarshaller
@SuppressWarnings("unchecked")
public void dispatchResponse (int methodId, Object[] args)
{
switch (methodId) {
case GOT_LOBBIES:
((LobbiesListener)listener).gotLobbies(
(List<Lobby>)args[0]);
return;
default:
super.dispatchResponse(methodId, args);
return;
}
}
}
/** The method id used to dispatch {@link #getCategories} requests. */
public static final int GET_CATEGORIES = 1;
// from interface LobbyService
public void getCategories (Client arg1, LobbyService.CategoriesListener arg2)
{
LobbyMarshaller.CategoriesMarshaller listener2 = new LobbyMarshaller.CategoriesMarshaller();
listener2.listener = arg2;
sendRequest(arg1, GET_CATEGORIES, new Object[] {
listener2
});
}
/** The method id used to dispatch {@link #getLobbies} requests. */
public static final int GET_LOBBIES = 2;
// from interface LobbyService
public void getLobbies (Client arg1, String arg2, LobbyService.LobbiesListener arg3)
{
LobbyMarshaller.LobbiesMarshaller listener3 = new LobbyMarshaller.LobbiesMarshaller();
listener3.listener = arg3;
sendRequest(arg1, GET_LOBBIES, new Object[] {
arg2, listener3
});
}
}
@@ -0,0 +1,33 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import com.threerings.crowd.data.PlaceObject;
/**
* Presently the lobby object contains nothing specific, but the class
* acts as a placeholder in case lobby-wide fields are needed in the
* future.
*/
public class LobbyObject extends PlaceObject
{
}
@@ -0,0 +1,121 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.samskivert.swing.Controller;
import com.samskivert.swing.HGroupLayout;
import com.samskivert.swing.VGroupLayout;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.micasa.client.ChatPanel;
import com.threerings.micasa.client.OccupantList;
import com.threerings.micasa.util.MiCasaContext;
/**
* Used to display the interface for the lobbies. It contains a lobby
* selection mechanism, a chat interface and a user interface for whatever
* match-making mechanism is appropriate for this particular lobby.
*/
public class LobbyPanel
extends JPanel implements PlaceView
{
/**
* Constructs a new lobby panel and the associated user interface
* elements.
*/
public LobbyPanel (MiCasaContext ctx, LobbyConfig config)
{
// we want a five pixel border around everything
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// create our primary layout which divides the display in two
// horizontally
HGroupLayout hgl = new HGroupLayout(HGroupLayout.STRETCH);
hgl.setOffAxisPolicy(HGroupLayout.STRETCH);
hgl.setJustification(HGroupLayout.RIGHT);
setLayout(hgl);
// create our main panel
VGroupLayout vgl = new VGroupLayout(VGroupLayout.STRETCH);
vgl.setOffAxisPolicy(VGroupLayout.STRETCH);
_main = new JPanel(vgl);
// create our match-making view
_main.add(config.createMatchMakingView(ctx));
// create a chat box and stick that in as well
_main.add(new ChatPanel(ctx));
// now add the main panel into the mix
add(_main);
// create our sidebar panel
vgl = new VGroupLayout(VGroupLayout.STRETCH);
vgl.setOffAxisPolicy(VGroupLayout.STRETCH);
JPanel sidePanel = new JPanel(vgl);
// the sidebar contains a lobby info display...
// ...a lobby selector...
JLabel label = new JLabel("Select a lobby...");
sidePanel.add(label, VGroupLayout.FIXED);
LobbySelector selector = new LobbySelector(ctx);
sidePanel.add(selector);
// and an occupants list
label = new JLabel("People in lobby");
sidePanel.add(label, VGroupLayout.FIXED);
_occupants = new OccupantList(ctx);
sidePanel.add(_occupants);
JButton logoff = new JButton("Logoff");
logoff.addActionListener(Controller.DISPATCHER);
logoff.setActionCommand("logoff");
sidePanel.add(logoff, VGroupLayout.FIXED);
// add our sidebar panel into the mix
add(sidePanel, VGroupLayout.FIXED);
}
// documentation inherited
public void willEnterPlace (PlaceObject plobj)
{
}
// documentation inherited
public void didLeavePlace (PlaceObject plobj)
{
}
/** Contains the match-making view and the chatbox. */
protected JPanel _main;
/** Our occupant list display. */
protected OccupantList _occupants;
}
@@ -0,0 +1,48 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import javax.annotation.Generated;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationProvider;
/**
* Defines the server-side of the {@link LobbyService}.
*/
@Generated(value={"com.threerings.presents.tools.GenServiceTask"},
comments="Derived from LobbyService.java.")
public interface LobbyProvider extends InvocationProvider
{
/**
* Handles a {@link LobbyService#getCategories} request.
*/
void getCategories (ClientObject caller, LobbyService.CategoriesListener arg1)
throws InvocationException;
/**
* Handles a {@link LobbyService#getLobbies} request.
*/
void getLobbies (ClientObject caller, String arg1, LobbyService.LobbiesListener arg2)
throws InvocationException;
}
@@ -0,0 +1,262 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.samskivert.util.StringUtil;
import com.threerings.util.StreamableArrayList;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationCodes;
import com.threerings.presents.server.InvocationManager;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.server.PlaceRegistry;
import com.threerings.micasa.lobby.LobbyService.CategoriesListener;
import com.threerings.micasa.lobby.LobbyService.LobbiesListener;
import com.threerings.micasa.server.MiCasaConfig;
import static com.threerings.micasa.Log.log;
/**
* The lobby registry is the primary class that coordinates the lobby services on the client. It
* sets up the necessary invocation services and keeps track of the lobbies in operation on the
* server. Only one lobby registry should be created on a server.
*
* <p> Presently, the lobby registry is configured with lobbies via the server configuration. An
* example configuration follows:
*
* <pre>
* lobby_ids = foolobby, barlobby, bazlobby
*
* foolobby.mgrclass = com.threerings.micasa.lobby.LobbyManager
* foolobby.ugi = <universal game identifier>
* foolobby.name = <human readable lobby name>
* foolobby.config1 = some config value
* foolobby.config2 = some other config value
*
* barlobby.mgrclass = com.threerings.micasa.lobby.LobbyManager
* barlobby.ugi = <universal game identifier>
* barlobby.name = <human readable lobby name>
* ...
* </pre>
*
* This information will be loaded from the MiCasa server configuration which means that it should
* live in <code>rsrc/config/micasa/server.properties</code> somwhere in the classpath where it
* will override the default MiCasa server properties file.
*
* <p> The <code>UGI</code> or universal game identifier is a string that is used to uniquely
* identify every type of game and also to classify it according to meaningful keywords. It is best
* described with a few examples:
*
* <pre>
* backgammon,board,strategy
* spades,card,partner
* yahtzee,dice
* </pre>
*
* As you can see, a UGI should start with an identifier uniquely identifying the type of game and
* can be followed by a list of keywords that classify it as a member of a particular category of
* games (eg. board, card, dice, partner game, strategy game). A game can belong to multiple
* categories.
*
* <p> As long as the UGIs in use by a particular server make some kind of sense, the client will
* be able to use them to search for lobbies containing games of similar types using the provided
* facilities.
*/
public class LobbyRegistry
implements LobbyProvider
{
@Inject public LobbyRegistry (InvocationManager invmgr)
{
// register ourselves as an invocation service handler
invmgr.registerDispatcher(new LobbyDispatcher(this), InvocationCodes.GLOBAL_GROUP);
}
/**
* Initializes the registry, creating our default lobbies.
*/
public void init ()
{
// create our lobby managers
String[] lmgrs = null;
lmgrs = MiCasaConfig.config.getValue(LOBIDS_KEY, lmgrs);
if (lmgrs == null || lmgrs.length == 0) {
log.warning("No lobbies specified in config file (via '" + LOBIDS_KEY + "' parameter).");
} else {
for (String lmgr : lmgrs) {
loadLobby(lmgr);
}
}
}
/**
* Returns the oid of the default lobby.
*/
public int getDefaultLobbyOid ()
{
return _defLobbyOid;
}
/**
* Extracts the properties for a lobby from the server config and creates and initializes the
* lobby manager.
*/
protected void loadLobby (String lobbyId)
{
try {
// extract the properties for this lobby
Properties props = MiCasaConfig.config.getSubProperties(lobbyId);
// get the lobby manager class and UGI
String cfgClass = props.getProperty("config");
if (StringUtil.isBlank(cfgClass)) {
throw new Exception("Missing 'config' definition in lobby configuration.");
}
// create and initialize the lobby config object
LobbyConfig config = (LobbyConfig)Class.forName(cfgClass).newInstance();
config.init(props);
// create and initialize the lobby manager. it will call lobbyReady() when it has
// obtained a reference to its lobby object and is ready to roll
LobbyManager lobmgr = (LobbyManager)_plreg.createPlace(config);
lobmgr.init(this, props);
} catch (Exception e) {
log.warning("Unable to create lobby manager [lobbyId=" + lobbyId +
", error=" + e + "].");
}
}
/**
* Returns information about all lobbies hosting games in the specified category.
*
* @param requester the body object of the client requesting the lobby list (which can be used
* to filter the list based on their capabilities).
* @param category the category of game for which the lobbies are desired.
* @param target the list into which the matching lobbies will be deposited.
*/
public void getLobbies (BodyObject requester, String category, List<Lobby> target)
{
List<Lobby> list = _lobbies.get(category);
if (list != null) {
target.addAll(list);
}
}
/**
* Returns an array containing the category identifiers of all the categories in which lobbies
* have been registered with the registry.
*
* @param requester the body object of the client requesting the category list (which can be
* used to filter the list based on their capabilities).
*/
public String[] getCategories (BodyObject requester)
{
String[] cats = new String[_lobbies.size()];
Iterator<String> iter = _lobbies.keySet().iterator();
for (int ii = 0; iter.hasNext(); ii++) {
cats[ii] = iter.next();
}
return cats;
}
/**
* Processes a request by the client to obtain a list of the lobby categories available on this
* server.
*/
public void getCategories (ClientObject caller, CategoriesListener listener)
{
listener.gotCategories(getCategories((BodyObject)caller));
}
/**
* Processes a request by the client to obtain a list of lobbies matching the supplied category
* string.
*/
public void getLobbies (ClientObject caller, String category, LobbiesListener listener)
{
List<Lobby> target = StreamableArrayList.newList();
List<Lobby> list = _lobbies.get(category);
if (list != null) {
target.addAll(list);
}
listener.gotLobbies(target);
}
/**
* Called by our lobby managers once they have started up and are ready to do their lobby
* duties.
*/
protected void lobbyReady (int placeOid, String gameIdent, String name)
{
// create a lobby record
Lobby record = new Lobby(placeOid, gameIdent, name);
// if we don't already have a default lobby, this one is the big winner
if (_defLobbyOid == -1) {
_defLobbyOid = placeOid;
}
// and register it in all the right lobby tables
StringTokenizer tok = new StringTokenizer(gameIdent, ",");
while (tok.hasMoreTokens()) {
String category = tok.nextToken();
registerLobby(category, record);
}
}
/** Registers the supplied lobby in the specified category table. */
protected void registerLobby (String category, Lobby record)
{
List<Lobby> catlist = _lobbies.get(category);
if (catlist == null) {
catlist = Lists.newArrayList();
_lobbies.put(category, catlist);
}
catlist.add(record);
log.info("Registered lobby", "cat", category, "record", record);
}
@Inject protected PlaceRegistry _plreg;
/** A table containing references to our lobby records (in the form of category lists. */
protected Map<String,List<Lobby>> _lobbies = Maps.newHashMap();
/** The oid of the default lobby. */
protected int _defLobbyOid = -1;
/** The configuration key for the lobby managers list. */
protected static final String LOBIDS_KEY = "lobby_ids";
}
@@ -0,0 +1,230 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import java.util.List;
import java.util.Map;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JPanel;
import com.google.common.collect.Maps;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.micasa.util.MiCasaContext;
import static com.threerings.micasa.Log.log;
/**
* The lobby selector displays a drop-down box listing the categories of
* lobbies available on this server and when a category is selected, it
* displays a list of the lobbies that are available in that category. If
* a lobby is double-clicked, it moves the client into that lobby room.
*/
public class LobbySelector extends JPanel
implements ActionListener, LobbyService.CategoriesListener,
LobbyService.LobbiesListener
{
/**
* Constructs a new lobby selector component. It will wait until it is
* visible before issuing a get categories request to download a list
* of categories.
*/
public LobbySelector (MiCasaContext ctx)
{
setLayout(new BorderLayout());
// keep this around for later
_ctx = ctx;
// create our drop-down box with a bogus entry at the moment
String[] options = new String[] { CAT_FIRST_ITEM };
_combo = new JComboBox(options);
_combo.addActionListener(this);
add(_combo, BorderLayout.NORTH);
// and create our empty lobby list
_loblist = new JList();
_loblist.setCellRenderer(new LobbyCellRenderer());
// add a mouse listener that tells us about double clicks
MouseListener ml = new MouseAdapter() {
@Override
public void mouseClicked (MouseEvent e) {
if (e.getClickCount() == 2) {
Object item = _loblist.getSelectedValue();
enterLobby((Lobby)item);
}
}
};
_loblist.addMouseListener(ml);
add(_loblist, BorderLayout.CENTER);
}
@Override
public void addNotify ()
{
super.addNotify();
// get a handle on our lobby service instance
_lservice = _ctx.getClient().requireService(LobbyService.class);
// and use them to look up the lobby categories
_lservice.getCategories(_ctx.getClient(), this);
}
/**
* Called when the user selects a category or double-clicks on a
* lobby.
*/
public void actionPerformed (ActionEvent evt)
{
if (evt.getSource() == _combo) {
String selcat = (String)_combo.getSelectedItem();
if (!selcat.equals(CAT_FIRST_ITEM)) {
selectCategory(selcat);
}
}
}
// documentation inherited from interface
public void gotCategories (String[] categories)
{
// append these to our "unselected" item
for (String categorie : categories) {
_combo.addItem(categorie);
}
}
// documentation inherited from interface
public void gotLobbies (List<Lobby> lobbies)
{
// create a list model for this category
DefaultListModel model = new DefaultListModel();
// populate it with the lobby info
for (Lobby lobby : lobbies) {
model.addElement(lobby);
}
// stick it in the table
_catlists.put(_pendingCategory, model);
// finally tell the lobby list to update the display (which we do
// by setting the combo box to this category in case the luser
// decided to try to select some new category while we weren't
// looking)
_combo.setSelectedItem(_pendingCategory);
// clear out our pending category indicator
_pendingCategory = null;
}
// documentation inherited from interface
public void requestFailed (String reason)
{
log.info("Request failed [reason=" + reason + "].");
// clear out our pending category indicator in case this was a
// failed getLobbies() request
_pendingCategory = null;
}
/**
* Fetches the list of lobbies available in a particular category (if
* they haven't already been fetched) and displays them in the lobby
* list.
*/
protected void selectCategory (String category)
{
DefaultListModel model = _catlists.get(category);
if (model != null) {
_loblist.setModel(model);
} else if (_pendingCategory == null) {
// make a note that we're loading up this category
_pendingCategory = category;
// issue a request to load up the lobbies in this category
_lservice.getLobbies(_ctx.getClient(), category, this);
} else {
log.info("Ignoring category select request because " +
"one is outstanding [pcat=" + _pendingCategory +
", newcat=" + category + "].");
}
}
/** Called when the user selects a lobby from the lobby list. */
protected void enterLobby (Lobby lobby)
{
// make sure we're not already in this lobby
PlaceObject plobj = _ctx.getLocationDirector().getPlaceObject();
if (plobj != null && plobj.getOid() == lobby.placeOid) {
return;
}
// otherwise request that we go there
_ctx.getLocationDirector().moveTo(lobby.placeOid);
log.info("Entering lobby " + lobby + ".");
}
/** Used to render Lobby instances in our lobby list. */
protected static class LobbyCellRenderer
extends DefaultListCellRenderer
{
@Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
// use the lobby's name rather than the value of toString()
value = ((Lobby)value).name;
return super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
}
}
protected MiCasaContext _ctx;
protected LobbyService _lservice;
protected JComboBox _combo;
protected JList _loblist;
protected Map<String, DefaultListModel> _catlists = Maps.newHashMap();
protected String _pendingCategory;
protected static final String CAT_FIRST_ITEM = "<categories...>";
}
@@ -0,0 +1,74 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby;
import java.util.List;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Provides an interface to the various parlor services that are directly
* invokable by the client (by means of the invocation services).
*/
public interface LobbyService extends InvocationService
{
/**
* Used to communicate the results of a {@link LobbyService#getCategories} request.
*/
public static interface CategoriesListener extends InvocationListener
{
/**
* Supplies the listener with the results of a {@link LobbyService#getCategories} request.
*/
public void gotCategories (String[] categories);
}
/**
* Used to communicate the results of a {@link LobbyService#getLobbies} request.
*/
public static interface LobbiesListener extends InvocationListener
{
/**
* Supplies the listener with the results of a {@link LobbyService#getLobbies} request.
*/
public void gotLobbies (List<Lobby> lobbies);
}
/**
* Requests the list of lobby categories that are available on this
* server.
*
* @param client a connected, operational client instance.
* @param listener the listener that will receive and process the response.
*/
public void getCategories (Client client, CategoriesListener listener);
/**
* Requests information on all active lobbies that match the specified category.
*
* @param client a connected, operational client instance.
* @param category the category of game for which a list of lobbies is desired.
* @param listener the listener that will receive and process the response.
*/
public void getLobbies (Client client, String category, LobbiesListener listener);
}
@@ -0,0 +1,252 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby.table;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.threerings.util.Name;
import com.threerings.crowd.data.BodyObject;
import com.threerings.parlor.client.SeatednessObserver;
import com.threerings.parlor.client.TableDirector;
import com.threerings.parlor.data.Table;
import com.threerings.micasa.util.MiCasaContext;
import static com.threerings.micasa.Log.log;
/**
* A table item displays the user interface for a single table (whether it
* be in-play or still being matchmade).
*/
public class TableItem
extends JPanel
implements ActionListener, SeatednessObserver
{
/** A reference to the table we are displaying. */
public Table table;
/**
* Creates a new table item to display and interact with the supplied
* table.
*/
public TableItem (MiCasaContext ctx, TableDirector tdtr, Table table)
{
// keep track of these
_tdtr = tdtr;
_ctx = ctx;
// add ourselves as a seatedness observer
_tdtr.addSeatednessObserver(this);
// figure out who we are
_self = ((BodyObject)ctx.getClient().getClientObject()).getVisibleName();
// now create our user interface
setBorder(BorderFactory.createLineBorder(Color.black));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
// create a label for the table
JLabel tlabel = new JLabel("Table " + table.tableId);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(2, 0, 0, 0);
add(tlabel, gbc);
// we have one button for every "seat" at the table
int bcount = table.players.length;
// create blank buttons for now and then we'll update everything
// with the current state when we're done
gbc.weightx = 1.0;
gbc.insets = new Insets(2, 0, 2, 0);
_seats = new JButton[bcount];
for (int ii = 0; ii < bcount; ii++) {
// create the button
_seats[ii] = new JButton(JOIN_LABEL);
_seats[ii].addActionListener(this);
// if we're on the left
if (ii % 2 == 0) {
// if we're the last seat, then we've got an odd number
// and need to center this final seat
if (ii == bcount-1) {
gbc.gridwidth = GridBagConstraints.REMAINDER;
} else {
gbc.gridwidth = 1;
}
} else {
gbc.gridwidth = GridBagConstraints.REMAINDER;
}
// adjust the insets of our last element
if (ii == bcount-1) {
gbc.insets = new Insets(2, 0, 4, 0);
}
// and add the button with the configured constraints
add(_seats[ii], gbc);
// if we just added the first button, add the "go" button
// right after it
if (ii == 0) {
_goButton = new JButton("Go");
_goButton.setActionCommand("go");
_goButton.addActionListener(this);
add(_goButton, gbc);
}
}
// and update ourselves based on the contents of the occupants
// list
tableUpdated(table);
}
/**
* Called when our table has been updated and we need to update the UI
* to reflect the new information.
*/
public void tableUpdated (Table table)
{
// grab this new table reference
this.table = table;
// first look to see if we're already sitting at a table
boolean isSeated = _tdtr.isSeated();
// now enable and label the buttons accordingly
int slength = _seats.length;
for (int ii = 0; ii < slength; ii++) {
if (table.players[ii] == null) {
_seats[ii].setText(JOIN_LABEL);
_seats[ii].setEnabled(!isSeated);
_seats[ii].setActionCommand("join");
} else if (table.players[ii].equals(_self) &&
!table.inPlay()) {
_seats[ii].setText(LEAVE_LABEL);
_seats[ii].setEnabled(true);
_seats[ii].setActionCommand("leave");
} else {
_seats[ii].setText(table.players[ii].toString());
_seats[ii].setEnabled(false);
}
}
// show or hide our "go" button appropriately
_goButton.setVisible(table.gameOid != -1);
}
/**
* Called by the table list view prior to removing us. Here we clean
* up.
*/
public void tableRemoved ()
{
// no more observy
_tdtr.removeSeatednessObserver(this);
}
// documentation inherited
public void actionPerformed (ActionEvent event)
{
String cmd = event.getActionCommand();
if (cmd.equals("join")) {
// figure out what position this button is in
int position = -1;
for (int ii = 0; ii < _seats.length; ii++) {
if (_seats[ii] == event.getSource()) {
position = ii;
break;
}
}
// sanity check
if (position == -1) {
log.warning("Unable to figure out what position a <join> " +
"click came from [event=" + event + "].");
} else {
// otherwise, request to join the table at this position
_tdtr.joinTable(table.tableId, position);
}
} else if (cmd.equals("leave")) {
// if we're not joining, we're leaving
_tdtr.leaveTable(table.tableId);
} else if (cmd.equals("go")) {
// they want to see the game... so go there
_ctx.getLocationDirector().moveTo(table.gameOid);
} else {
log.warning("Received unknown action [event=" + event + "].");
}
}
// documentation inherited
public void seatednessDidChange (boolean isSeated)
{
// just update ourselves
tableUpdated(table);
// enable or disable the go button based on our seatedness
if (_goButton.isVisible()) {
_goButton.setEnabled(!isSeated);
}
}
/** A reference to our context. */
protected MiCasaContext _ctx;
/** Our username. */
protected Name _self;
/** A reference to our table director. */
protected TableDirector _tdtr;
/** We have a button for each "seat" at the table. */
protected JButton[] _seats;
/** We have a button for going to games that are already in
* progress. */
protected JButton _goButton;
/** The text shown for seats at which the user can join. */
protected static final String JOIN_LABEL = "<join>";
/** The text shown for the seat in which this user occupies and which
* lets her/him know that they can leave that seat by clicking. */
protected static final String LEAVE_LABEL = "<leave>";
}
@@ -0,0 +1,302 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby.table;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.samskivert.swing.HGroupLayout;
import com.samskivert.swing.VGroupLayout;
import com.samskivert.swing.util.SwingUtil;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.client.SeatednessObserver;
import com.threerings.parlor.client.TableConfigurator;
import com.threerings.parlor.client.TableDirector;
import com.threerings.parlor.client.TableObserver;
import com.threerings.parlor.data.Table;
import com.threerings.parlor.game.client.GameConfigurator;
import com.threerings.parlor.game.client.SwingGameConfigurator;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.micasa.lobby.LobbyConfig;
import com.threerings.micasa.util.MiCasaContext;
import static com.threerings.micasa.Log.log;
/**
* A view that displays the tables in a table lobby. It displays two
* separate lists, one of tables being matchmade and another of games in
* progress. These tables are updated dynamically as they proceed through
* the matchmaking process. UI mechanisms for creating and joining tables
* are also provided.
*/
public class TableListView extends JPanel
implements PlaceView, TableObserver, ActionListener, SeatednessObserver
{
/**
* Creates a new table list view, suitable for providing the user
* interface for table-style matchmaking in a table lobby.
*/
public TableListView (MiCasaContext ctx, LobbyConfig config)
{
// keep track of these
_config = config;
_ctx = ctx;
// create our table director
_tdtr = new TableDirector(ctx, TableLobbyObject.TABLE_SET, this);
// add ourselves as a seatedness observer
_tdtr.addSeatednessObserver(this);
// set up a layout manager
HGroupLayout gl = new HGroupLayout(HGroupLayout.STRETCH);
gl.setOffAxisPolicy(HGroupLayout.STRETCH);
setLayout(gl);
// we have two lists of tables, one of tables being matchmade...
VGroupLayout pgl = new VGroupLayout(VGroupLayout.STRETCH);
pgl.setOffAxisPolicy(VGroupLayout.STRETCH);
JPanel panel = new JPanel(pgl);
panel.add(new JLabel("Pending tables"), VGroupLayout.FIXED);
VGroupLayout mgl = new VGroupLayout(VGroupLayout.NONE);
mgl.setOffAxisPolicy(VGroupLayout.STRETCH);
mgl.setJustification(VGroupLayout.TOP);
_matchList = new JPanel(mgl);
_matchList.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(new JScrollPane(_matchList));
// create and initialize the configurator interface
GameConfig gconfig = null;
try {
gconfig = config.getGameConfig();
_tableFigger = gconfig.createTableConfigurator();
if (_tableFigger == null) {
log.warning("Game config has not been set up to work with " +
"tables: it needs to return non-null from " +
"createTableConfigurator().");
// let's just wait until we throw an NPE below
}
_figger = gconfig.createConfigurator();
_tableFigger.init(_ctx, _figger);
if (_figger != null) {
_figger.init(_ctx);
_figger.setGameConfig(gconfig);
panel.add(((SwingGameConfigurator) _figger).getPanel(),
VGroupLayout.FIXED);
}
_create = new JButton("Create table");
_create.addActionListener(this);
panel.add(_create, VGroupLayout.FIXED);
} catch (Exception e) {
log.warning("Unable to create configurator interface " +
"[config=" + gconfig + "].", e);
// stick something in the UI to let them know we're hosed
panel.add(new JLabel("Aiya! Can't create tables. " +
"Configuration borked."), VGroupLayout.FIXED);
}
add(panel);
// ...and one of games in progress
panel = new JPanel(pgl);
panel.add(new JLabel("Games in progress"), VGroupLayout.FIXED);
_playList = new JPanel(mgl);
_playList.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(new JScrollPane(_playList));
add(panel);
}
// documentation inherited
public void willEnterPlace (PlaceObject place)
{
// pass the good word on to our table director
_tdtr.setTableObject(place);
// iterate over the tables already active in this lobby and put
// them in their respective lists
TableLobbyObject tlobj = (TableLobbyObject)place;
for (Table table : tlobj.tableSet) {
tableAdded(table);
}
}
// documentation inherited
public void didLeavePlace (PlaceObject place)
{
// pass the good word on to our table director
_tdtr.clearTableObject();
// clear out our table lists
_matchList.removeAll();
_playList.removeAll();
}
// documentation inherited
public void tableAdded (Table table)
{
log.info("Table added [table=" + table + "].");
// create a table item for this table and insert it into the
// appropriate list
JPanel panel = table.inPlay() ? _playList : _matchList;
panel.add(new TableItem(_ctx, _tdtr, table));
SwingUtil.refresh(panel);
}
// documentation inherited
public void tableUpdated (Table table)
{
log.info("Table updated [table=" + table + "].");
// locate the table item associated with this table
TableItem item = getTableItem(table.tableId);
if (item == null) {
log.warning("Received table updated notification for " +
"unknown table [table=" + table + "].");
return;
}
// let the item perform any updates it finds necessary
item.tableUpdated(table);
// and we may need to move the item from the match to the in-play
// list if it just transitioned
if (table.gameOid != -1 && item.getParent() == _matchList) {
_matchList.remove(item);
SwingUtil.refresh(_matchList);
_playList.add(item);
SwingUtil.refresh(_playList);
}
}
// documentation inherited
public void tableRemoved (int tableId)
{
log.info("Table removed [tableId=" + tableId + "].");
// locate the table item associated with this table
TableItem item = getTableItem(tableId);
if (item == null) {
log.warning("Received table removed notification for " +
"unknown table [tableId=" + tableId + "].");
return;
}
// remove this item from the user interface
JPanel panel = (JPanel)item.getParent();
panel.remove(item);
SwingUtil.refresh(panel);
// let the little fellow know that we gave him the boot
item.tableRemoved();
}
// documentation inherited
public void actionPerformed (ActionEvent event)
{
// the create table button was clicked. use the game config as
// configured by the configurator to create a table
_tdtr.createTable(_tableFigger.getTableConfig(),
_figger.getGameConfig());
}
// documentation inherited
public void seatednessDidChange (boolean isSeated)
{
// update the create table button
_create.setEnabled(!isSeated);
}
/**
* Fetches the table item component associated with the specified
* table id.
*/
protected TableItem getTableItem (int tableId)
{
// first check the match list
int ccount = _matchList.getComponentCount();
for (int ii = 0; ii < ccount; ii++) {
TableItem child = (TableItem)_matchList.getComponent(ii);
if (child.table.tableId == tableId) {
return child;
}
}
// then the inplay list
ccount = _playList.getComponentCount();
for (int ii = 0; ii < ccount; ii++) {
TableItem child = (TableItem)_playList.getComponent(ii);
if (child.table.tableId == tableId) {
return child;
}
}
// sorry charlie
return null;
}
/** A reference to the client context. */
protected MiCasaContext _ctx;
/** A reference to the lobby config for the lobby in which we are
* doing table-style matchmaking. */
protected LobbyConfig _config;
/** A reference to our table director. */
protected TableDirector _tdtr;
/** The list of tables currently being matchmade. */
protected JPanel _matchList;
/** The list of tables that are in play. */
protected JPanel _playList;
/** The interface used to configure the table for a game. */
protected TableConfigurator _tableFigger;
/** The interface used to configure a game before creating it. */
protected GameConfigurator _figger;
/** Our create table button. */
protected JButton _create;
/** Our number of players indicator. */
protected JLabel _pcount;
}
@@ -0,0 +1,46 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby.table;
import javax.swing.JComponent;
import com.threerings.micasa.lobby.LobbyConfig;
import com.threerings.micasa.util.MiCasaContext;
/**
* Instructs the lobby services to use a {@link TableListView} as the
* matchmaking component.
*/
public class TableLobbyConfig extends LobbyConfig
{
@Override
public String getManagerClassName ()
{
return "com.threerings.micasa.lobby.table.TableLobbyManager";
}
@Override
public JComponent createMatchMakingView (MiCasaContext ctx)
{
return new TableListView(ctx, this);
}
}
@@ -0,0 +1,59 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby.table;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.server.TableManager;
import com.threerings.micasa.lobby.LobbyManager;
/**
* Extends lobby manager only to ensure that a table lobby object is used for table lobbies.
*/
public class TableLobbyManager extends LobbyManager
{
@Override
protected void didStartup ()
{
super.didStartup();
// now that we have our place object, we can create our table manager
_tmgr = new TableManager(_omgr, _invmgr, _registry, getPlaceObject());
}
@Override
protected void didShutdown ()
{
super.didShutdown();
// clean up our table manager
_tmgr.shutdown();
}
@Override
protected PlaceObject createPlaceObject ()
{
return new TableLobbyObject();
}
/** A reference to our table manager. */
protected TableManager _tmgr;
}
@@ -0,0 +1,150 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://code.google.com/p/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.micasa.lobby.table;
import javax.annotation.Generated;
import com.threerings.presents.dobj.DSet;
import com.threerings.parlor.data.Table;
import com.threerings.parlor.data.TableMarshaller;
import com.threerings.micasa.lobby.LobbyObject;
public class TableLobbyObject extends LobbyObject
implements com.threerings.parlor.data.TableLobbyObject
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>tableSet</code> field. */
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public static final String TABLE_SET = "tableSet";
/** The field name of the <code>tableService</code> field. */
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public static final String TABLE_SERVICE = "tableService";
// AUTO-GENERATED: FIELDS END
/** A set containing all of the tables being managed by this lobby. */
public DSet<Table> tableSet = new DSet<Table>();
/** Handles our table services. */
public TableMarshaller tableService;
// from interface TableLobbyObject
public DSet<Table> getTables ()
{
return tableSet;
}
// from interface TableLobbyObject
public void addToTables (Table table)
{
addToTableSet(table);
}
// from interface TableLobbyObject
public void updateTables (Table table)
{
updateTableSet(table);
}
// from interface TableLobbyObject
public void removeFromTables (Comparable<?> key)
{
removeFromTableSet(key);
}
// from interface TableLobbyObject
public TableMarshaller getTableService ()
{
return tableService;
}
// AUTO-GENERATED: METHODS START
/**
* Requests that the specified entry be added to the
* <code>tableSet</code> set. The set will not change until the event is
* actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void addToTableSet (Table elem)
{
requestEntryAdd(TABLE_SET, tableSet, elem);
}
/**
* Requests that the entry matching the supplied key be removed from
* the <code>tableSet</code> set. The set will not change until the
* event is actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void removeFromTableSet (Comparable<?> key)
{
requestEntryRemove(TABLE_SET, tableSet, key);
}
/**
* Requests that the specified entry be updated in the
* <code>tableSet</code> set. The set will not change until the event is
* actually propagated through the system.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void updateTableSet (Table elem)
{
requestEntryUpdate(TABLE_SET, tableSet, elem);
}
/**
* Requests that the <code>tableSet</code> field be set to the
* specified value. Generally one only adds, updates and removes
* entries of a distributed set, but certain situations call for a
* complete replacement of the set value. The local value will be
* updated immediately and an event will be propagated through the
* system to notify all listeners that the attribute did
* change. Proxied copies of this object (on clients) will apply the
* value change when they received the attribute changed notification.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void setTableSet (DSet<Table> value)
{
requestAttributeChange(TABLE_SET, value, this.tableSet);
DSet<Table> clone = (value == null) ? null : value.clone();
this.tableSet = clone;
}
/**
* Requests that the <code>tableService</code> field be set to the
* specified value. The local value will be updated immediately and an
* event will be propagated through the system to notify all listeners
* that the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
public void setTableService (TableMarshaller value)
{
TableMarshaller ovalue = this.tableService;
requestAttributeChange(
TABLE_SERVICE, value, ovalue);
this.tableService = value;
}
// AUTO-GENERATED: METHODS END
}