Moved the serverless game stuff out of msoy and back into the vilya library.
We'll be using this in game gardens, at least. Note that the actionscript side currently doesn't compile because of limitations in building a .swc file, but that'll be fixed soon. git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@47 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
package com.threerings.ezgame.client {
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.dobj.MessageAdapter;
|
||||
import com.threerings.presents.dobj.MessageListener;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
|
||||
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.game.client.GameController;
|
||||
|
||||
import com.threerings.parlor.turn.client.TurnGameController;
|
||||
import com.threerings.parlor.turn.client.TurnGameControllerDelegate;
|
||||
|
||||
import com.threerings.ezgame.data.EZGameObject;
|
||||
import com.threerings.ezgame.data.PropertySetEvent;
|
||||
import com.threerings.ezgame.data.PropertySetListener;
|
||||
import com.threerings.ezgame.util.EZObjectMarshaller;
|
||||
|
||||
import com.threerings.ezgame.MessageReceivedEvent;
|
||||
import com.threerings.ezgame.PropertyChangedEvent;
|
||||
import com.threerings.ezgame.StateChangedEvent;
|
||||
|
||||
/**
|
||||
* A controller for flash games.
|
||||
*/
|
||||
public class EZGameController extends GameController
|
||||
implements TurnGameController, PropertySetListener, MessageListener
|
||||
{
|
||||
/** The implementation of the GameObject interface for users. */
|
||||
public var gameObjImpl :GameObjectImpl;
|
||||
|
||||
/**
|
||||
*/
|
||||
public function EZGameController ()
|
||||
{
|
||||
addDelegate(_turnDelegate = new TurnGameControllerDelegate(this));
|
||||
}
|
||||
|
||||
override public function willEnterPlace (plobj :PlaceObject) :void
|
||||
{
|
||||
_ezObj = (plobj as EZGameObject);
|
||||
gameObjImpl = new GameObjectImpl(_ctx, _ezObj);
|
||||
|
||||
_ctx.getClient().getClientObject().addListener(_userListener);
|
||||
|
||||
super.willEnterPlace(plobj);
|
||||
}
|
||||
|
||||
override public function didLeavePlace (plobj :PlaceObject) :void
|
||||
{
|
||||
super.didLeavePlace(plobj);
|
||||
|
||||
_ctx.getClient().getClientObject().removeListener(_userListener);
|
||||
|
||||
_ezObj = null;
|
||||
}
|
||||
|
||||
// from TurnGameController
|
||||
public function turnDidChange (turnHolder :Name) :void
|
||||
{
|
||||
dispatchUserEvent(
|
||||
new StateChangedEvent(StateChangedEvent.TURN_CHANGED));
|
||||
}
|
||||
|
||||
// from PropertySetListener
|
||||
public function propertyWasSet (event :PropertySetEvent) :void
|
||||
{
|
||||
// notify the user game
|
||||
dispatchUserEvent(new PropertyChangedEvent(
|
||||
event.getName(), event.getValue(), event.getOldValue(),
|
||||
event.getIndex()));
|
||||
}
|
||||
|
||||
// from MessageListener
|
||||
public function messageReceived (event :MessageEvent) :void
|
||||
{
|
||||
var name :String = event.getName();
|
||||
if (EZGameObject.USER_MESSAGE == name) {
|
||||
dispatchUserMessage(event.getArgs());
|
||||
|
||||
} else if (EZGameObject.GAME_CHAT == name) {
|
||||
// this is chat send by the game, let's route it like
|
||||
// localChat, which is also sent by the game
|
||||
gameObjImpl.localChat(String(event.getArgs()[0]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by our user listener when we receive a message event
|
||||
* on the user object.
|
||||
*/
|
||||
protected function messageReceivedOnUserObject (event :MessageEvent) :void
|
||||
{
|
||||
// see if it's a message about user games
|
||||
var msgName :String =
|
||||
EZGameObject.USER_MESSAGE + ":" + _ezObj.getOid();
|
||||
if (msgName == event.getName()) {
|
||||
dispatchUserMessage(event.getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the user message.
|
||||
*/
|
||||
protected function dispatchUserMessage (args :Array) :void
|
||||
{
|
||||
dispatchUserEvent(new MessageReceivedEvent(
|
||||
(args[0] as String),
|
||||
EZObjectMarshaller.decode(args[1])));
|
||||
}
|
||||
|
||||
override protected function createPlaceView (ctx :CrowdContext) :PlaceView
|
||||
{
|
||||
return new EZGamePanel(ctx, this);
|
||||
}
|
||||
|
||||
override protected function gameDidStart () :void
|
||||
{
|
||||
super.gameDidStart();
|
||||
dispatchUserEvent(
|
||||
new StateChangedEvent(StateChangedEvent.GAME_STARTED));
|
||||
}
|
||||
|
||||
override protected function gameDidEnd () :void
|
||||
{
|
||||
super.gameDidEnd();
|
||||
dispatchUserEvent(
|
||||
new StateChangedEvent(StateChangedEvent.GAME_ENDED));
|
||||
}
|
||||
|
||||
protected function dispatchUserEvent (event :Event) :void
|
||||
{
|
||||
gameObjImpl.dispatch(event);
|
||||
}
|
||||
|
||||
protected var _ezObj :EZGameObject;
|
||||
|
||||
protected var _turnDelegate :TurnGameControllerDelegate;
|
||||
|
||||
protected var _userListener :MessageAdapter =
|
||||
new MessageAdapter(messageReceivedOnUserObject);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.threerings.ezgame.client {
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.DisplayObjectContainer;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
import mx.containers.Canvas;
|
||||
import mx.containers.VBox;
|
||||
|
||||
import mx.core.Container;
|
||||
import mx.core.IChildList;
|
||||
|
||||
import mx.utils.DisplayUtil;
|
||||
|
||||
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;
|
||||
|
||||
public class EZGamePanel extends VBox
|
||||
implements PlaceView
|
||||
{
|
||||
public function EZGamePanel (ctx :CrowdContext, ctrl :EZGameController)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_ctrl = ctrl;
|
||||
|
||||
// add a listener so that we hear about all new children
|
||||
addEventListener(Event.ADDED, childAdded);
|
||||
|
||||
// TODO: figure out how we're going to add the client game
|
||||
var cfg :EZGameConfig = (ctrl.getPlaceConfig() as EZGameConfig);
|
||||
//_gameView = new MsoySprite(cfg.game);
|
||||
//addChild(_gameView);
|
||||
|
||||
// TODO: move chat component into narya?
|
||||
//addChild(new ChatTextArea(ctx));
|
||||
}
|
||||
|
||||
// from PlaceView
|
||||
public function willEnterPlace (plobj :PlaceObject) :void
|
||||
{
|
||||
// don't start notifying anything of the game until we've
|
||||
// notified the game manager that we're in the game
|
||||
// (done in GameController, and it uses callLater, so we do it twice!)
|
||||
_ctx.getClient().callLater(function () :void {
|
||||
_ctx.getClient().callLater(function () :void {
|
||||
_ezObj = (plobj as EZGameObject);
|
||||
|
||||
notifyOfGame(this);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// from PlaceView
|
||||
public function didLeavePlace (plobj :PlaceObject) :void
|
||||
{
|
||||
_ezObj = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ADDED events.
|
||||
*/
|
||||
protected function childAdded (event :Event) :void
|
||||
{
|
||||
if (_ezObj != null) {
|
||||
notifyOfGame(event.target as DisplayObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find any children of the specified object that implement
|
||||
* com.metasoy.game.Game and provide them with the GameObject.
|
||||
*/
|
||||
protected function notifyOfGame (root :DisplayObject) :void
|
||||
{
|
||||
DisplayUtil.walkDisplayObjects(root,
|
||||
function (disp :DisplayObject) :void
|
||||
{
|
||||
if (disp is Game) {
|
||||
// only notify the Game if we haven't seen it before
|
||||
if (null == _seenGames[disp]) {
|
||||
(disp as Game).setGameObject(_ctrl.gameObjImpl);
|
||||
_seenGames[disp] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected var _ctx :CrowdContext;
|
||||
protected var _ctrl :EZGameController;
|
||||
|
||||
/** A weak-key hash of the Game interfaces we've already seen. */
|
||||
protected var _seenGames :Dictionary = new Dictionary(true);
|
||||
|
||||
protected var _ezObj :EZGameObject;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
package com.threerings.ezgame.client {
|
||||
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
import com.threerings.io.TypedArray;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.InvocationService;
|
||||
import com.threerings.presents.client.InvocationService_ConfirmListener;
|
||||
import com.threerings.presents.client.InvocationService_InvocationListener;
|
||||
|
||||
/**
|
||||
* Provides services for ez games.
|
||||
*/
|
||||
public interface EZGameService extends InvocationService
|
||||
{
|
||||
/**
|
||||
* Request to set the specified property.
|
||||
*/
|
||||
function setProperty (
|
||||
client :Client, propName :String, value :Object, index :int,
|
||||
listener :InvocationService_InvocationListener) :void;
|
||||
|
||||
/**
|
||||
* Request to end the turn, possibly futzing the next turn holder unless
|
||||
* -1 is specified for the nextPlayerIndex.
|
||||
*/
|
||||
function endTurn (
|
||||
client :Client, nextPlayerIndex :int,
|
||||
listener :InvocationService_InvocationListener) :void;
|
||||
|
||||
/**
|
||||
* Request to end the game, with the specified player indices assigned
|
||||
* as winners.
|
||||
*/
|
||||
function endGame (
|
||||
client :Client, winners :TypedArray /* of int */,
|
||||
listener :InvocationService_InvocationListener) :void;
|
||||
|
||||
/**
|
||||
* Request to send a private message to one other player in
|
||||
* the game.
|
||||
*/
|
||||
function sendMessage (
|
||||
client :Client, msgName :String, value :Object, playerIdx :int,
|
||||
listener :InvocationService_InvocationListener) :void;
|
||||
|
||||
/**
|
||||
* Add to the specified named collection.
|
||||
*
|
||||
* @param clearExisting if true, wipe the old contents.
|
||||
*/
|
||||
function addToCollection (
|
||||
client :Client, collName :String, data :TypedArray /* of ByteArray */,
|
||||
clearExisting :Boolean, listener :InvocationService_InvocationListener)
|
||||
:void;
|
||||
|
||||
/**
|
||||
* Merge the specified collection into the other.
|
||||
*/
|
||||
function mergeCollection (
|
||||
client :Client, srcColl :String, intoColl :String,
|
||||
listener :InvocationService_InvocationListener) :void;
|
||||
|
||||
/**
|
||||
* Pick or deal some number of elements from the specified collection,
|
||||
* and either set a property in the flash object, or delivery the
|
||||
* picks to the specified player index via a game message.
|
||||
*/
|
||||
function getFromCollection (
|
||||
client :Client, collName :String, consume :Boolean, count :int,
|
||||
msgOrPropName :String, playerIndex :int,
|
||||
listener :InvocationService_ConfirmListener) :void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.threerings.ezgame.client {
|
||||
|
||||
import flash.errors.IllegalOperationError;
|
||||
|
||||
import flash.utils.Proxy;
|
||||
|
||||
import flash.utils.flash_proxy;
|
||||
|
||||
use namespace flash_proxy;
|
||||
|
||||
public class GameData extends Proxy
|
||||
{
|
||||
public function GameData (gameObjImpl :GameObjectImpl, props :Object)
|
||||
{
|
||||
_gameObjImpl = gameObjImpl;
|
||||
_props = props;
|
||||
}
|
||||
|
||||
public function hasOwnProperty (propName :String) :Boolean
|
||||
{
|
||||
// pass-through
|
||||
return _props.hasOwnProperty(propName);
|
||||
}
|
||||
|
||||
public function propertyIsEnumerable (propName :String) :Boolean
|
||||
{
|
||||
// pass-through
|
||||
return _props.propertyIsEnumerable(propName);
|
||||
}
|
||||
|
||||
public function setPropertyIsEnumerable (
|
||||
propName :String, isEnum :Boolean = true) :void
|
||||
{
|
||||
// pass-through
|
||||
_props.setPropertyIsEnumerable(propName, isEnum);
|
||||
}
|
||||
|
||||
override flash_proxy function callProperty (propName :*, ... rest) :*
|
||||
{
|
||||
// don't allow function calls
|
||||
throw new IllegalOperationError();
|
||||
}
|
||||
|
||||
override flash_proxy function getDescendants (name :*) :*
|
||||
{
|
||||
// we don't need this XML business
|
||||
throw new IllegalOperationError();
|
||||
}
|
||||
|
||||
override flash_proxy function isAttribute (name :*) :Boolean
|
||||
{
|
||||
// we don't need this XML business
|
||||
throw new IllegalOperationError();
|
||||
}
|
||||
|
||||
override flash_proxy function getProperty (propName :*) :*
|
||||
{
|
||||
// pass-through
|
||||
return _props[propName];
|
||||
}
|
||||
|
||||
override flash_proxy function hasProperty (propName :*) :Boolean
|
||||
{
|
||||
// pass-through
|
||||
return (_props[propName] !== undefined);
|
||||
}
|
||||
|
||||
override flash_proxy function setProperty (propName :*, value :*) :void
|
||||
{
|
||||
_gameObjImpl.set(String(propName), value);
|
||||
}
|
||||
|
||||
override flash_proxy function deleteProperty (propName :*) :Boolean
|
||||
{
|
||||
var hasProp :Boolean = hasProperty(propName);
|
||||
_gameObjImpl.set(String(propName), null);
|
||||
return hasProp;
|
||||
}
|
||||
|
||||
override flash_proxy function nextNameIndex (index :int) :int
|
||||
{
|
||||
// possibly set up the property list on the first call
|
||||
if (index == 0) {
|
||||
_propertyList = [];
|
||||
for (var prop :String in _props) {
|
||||
_propertyList.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
// return a 1-based index to indicate that there is a property
|
||||
if (index < _propertyList.length) {
|
||||
return index + 1;
|
||||
|
||||
} else {
|
||||
// we're done, clear the prop list
|
||||
_propertyList = null;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
override flash_proxy function nextName (index :int) :String
|
||||
{
|
||||
// the index is 1-based, so subtract one
|
||||
return (_propertyList[index - 1] as String);
|
||||
}
|
||||
|
||||
override flash_proxy function nextValue (index :int) :*
|
||||
{
|
||||
return _props[nextName(index)];
|
||||
}
|
||||
|
||||
/** The GameObject that controls things. */
|
||||
protected var _gameObjImpl :GameObjectImpl;
|
||||
|
||||
/** The object we're proxying. */
|
||||
protected var _props :Object;
|
||||
|
||||
/** Used temporarily while iterating over our names or values. */
|
||||
protected var _propertyList :Array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
package com.threerings.ezgame.client {
|
||||
|
||||
import flash.errors.IllegalOperationError;
|
||||
|
||||
import flash.events.Event;
|
||||
import flash.events.EventDispatcher;
|
||||
|
||||
import flash.utils.IExternalizable;
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
import com.threerings.io.TypedArray;
|
||||
|
||||
import com.threerings.util.ClassUtil;
|
||||
import com.threerings.util.MessageBundle;
|
||||
import com.threerings.util.Name;
|
||||
import com.threerings.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.client.ConfirmAdapter;
|
||||
import com.threerings.presents.client.InvocationService_ConfirmListener;
|
||||
|
||||
import com.threerings.crowd.data.BodyObject;
|
||||
import com.threerings.crowd.util.CrowdContext;
|
||||
|
||||
import com.threerings.ezgame.data.EZGameObject;
|
||||
import com.threerings.ezgame.data.PropertySetEvent;
|
||||
import com.threerings.ezgame.util.EZObjectMarshaller;
|
||||
|
||||
import com.threerings.ezgame.GameObject;
|
||||
import com.threerings.ezgame.PropertyChangedEvent;
|
||||
|
||||
public class GameObjectImpl extends EventDispatcher
|
||||
implements GameObject
|
||||
{
|
||||
public function GameObjectImpl (ctx :CrowdContext, ezObj :EZGameObject)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_ezObj = ezObj;
|
||||
_gameData = new GameData(this, _ezObj.getUserProps());
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function get data () :Object
|
||||
{
|
||||
return _gameData;
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function get (propName :String, index :int = -1) :Object
|
||||
{
|
||||
var value :Object = data[propName];
|
||||
if (index >= 0) {
|
||||
if (value is Array) {
|
||||
return (value as Array)[index];
|
||||
|
||||
} else {
|
||||
throw new ArgumentError("Property " + propName +
|
||||
" is not an array.");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function set (propName :String, value :Object, index :int = -1) :void
|
||||
{
|
||||
validatePropertyChange(propName, value, index);
|
||||
|
||||
var encoded :Object = EZObjectMarshaller.encode(value);
|
||||
_ezObj.ezGameService.setProperty(
|
||||
_ctx.getClient(), propName, encoded, index,
|
||||
createLoggingListener("setProperty"));
|
||||
|
||||
// set it immediately in the game object
|
||||
_ezObj.applyPropertySet(propName, value, index);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function setCollection (collName :String, values :Array) :void
|
||||
{
|
||||
populateCollection(collName, values, true);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function addToCollection (collName :String, values :Array) :void
|
||||
{
|
||||
populateCollection(collName, values, false);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function pickFromCollection (
|
||||
collName :String, count :int, msgOrPropName :String,
|
||||
playerIndex :int = -1) :void
|
||||
{
|
||||
getFromCollection(collName, count, msgOrPropName, playerIndex,
|
||||
false, null);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function dealFromCollection (
|
||||
collName :String, count :int, msgOrPropName :String,
|
||||
callback :Function = null, playerIndex :int = -1) :void
|
||||
{
|
||||
getFromCollection(collName, count, msgOrPropName, playerIndex,
|
||||
true, callback);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function mergeCollection (srcColl :String, intoColl :String) :void
|
||||
{
|
||||
validateName(srcColl);
|
||||
validateName(intoColl);
|
||||
_ezObj.ezGameService.mergeCollection(_ctx.getClient(),
|
||||
srcColl, intoColl, createLoggingListener("mergeCollection"));
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function sendMessage (
|
||||
messageName :String, value :Object, playerIndex :int = -1) :void
|
||||
{
|
||||
validateName(messageName);
|
||||
validateValue(value);
|
||||
|
||||
var encoded :Object = EZObjectMarshaller.encode(value);
|
||||
_ezObj.ezGameService.sendMessage(_ctx.getClient(),
|
||||
messageName, encoded, playerIndex,
|
||||
createLoggingListener("sendMessage"));
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function sendChat (msg :String) :void
|
||||
{
|
||||
validateChat(msg);
|
||||
// Post a message to the game object, the controller
|
||||
// will listen and call localChat().
|
||||
_ezObj.postMessage(EZGameObject.GAME_CHAT, [ msg ]);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function localChat (msg :String) :void
|
||||
{
|
||||
validateChat(msg);
|
||||
// The sendChat() messages will end up being routed
|
||||
// through this method on each client.
|
||||
// TODO: make this look distinct from other system chat
|
||||
_ctx.getChatDirector().displayInfo(null, MessageBundle.taint(msg));
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function getPlayerNames () :Array
|
||||
{
|
||||
var names :Array = new Array();
|
||||
for each (var name :Name in _ezObj.players) {
|
||||
names.push((name == null) ? null : name.toString());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function getMyIndex () :int
|
||||
{
|
||||
return _ezObj.getPlayerIndex(getUsername());
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function getTurnHolderIndex () :int
|
||||
{
|
||||
return _ezObj.getPlayerIndex(_ezObj.turnHolder);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function getWinnerIndexes () :Array /* of int */
|
||||
{
|
||||
var arr :Array = new Array();
|
||||
if (_ezObj.winners != null) {
|
||||
for (var ii :int = 0; ii < _ezObj.winners.length; ii++) {
|
||||
if (_ezObj.winners[ii]) {
|
||||
arr.push(ii);
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function isMyTurn () :Boolean
|
||||
{
|
||||
return getUsername().equals(_ezObj.turnHolder);
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function isInPlay () :Boolean
|
||||
{
|
||||
return _ezObj.isInPlay();
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function endTurn (nextPlayerIndex :int = -1) :void
|
||||
{
|
||||
_ezObj.ezGameService.endTurn(_ctx.getClient(), nextPlayerIndex,
|
||||
createLoggingListener("endTurn"));
|
||||
}
|
||||
|
||||
// from GameObject
|
||||
public function endGame (winnerIndex :int, ... rest) :void
|
||||
{
|
||||
var winners :TypedArray = TypedArray.create(int);
|
||||
winners.push(winnerIndex);
|
||||
while (rest.length > 0) {
|
||||
winners.push(int(rest.shift()));
|
||||
}
|
||||
_ezObj.ezGameService.endGame(_ctx.getClient(), winners,
|
||||
createLoggingListener("endGame"));
|
||||
}
|
||||
|
||||
override public function willTrigger (type :String) :Boolean
|
||||
{
|
||||
throw new IllegalOperationError();
|
||||
}
|
||||
|
||||
override public function dispatchEvent (event :Event) :Boolean
|
||||
{
|
||||
// Ideally we want to not be an IEventDispatcher so that people
|
||||
// won't try to do this on us, but if we do that, then some other
|
||||
// object will be the target during dispatch, and that's confusing.
|
||||
// It's really nice to be able to
|
||||
throw new IllegalOperationError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Secret function to dispatch property changed events.
|
||||
*/
|
||||
internal function dispatch (event :Event) :void
|
||||
{
|
||||
try {
|
||||
super.dispatchEvent(event);
|
||||
} catch (err :Error) {
|
||||
var log :Log = Log.getLog(this);
|
||||
log.warning("Error dispatching event to user game.");
|
||||
log.logStackTrace(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to get our name.
|
||||
*/
|
||||
private function getUsername () :Name
|
||||
{
|
||||
var body :BodyObject =
|
||||
(_ctx.getClient().getClientObject() as BodyObject);
|
||||
return body.getVisibleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a listener for service requests.
|
||||
*/
|
||||
private function createLoggingListener (
|
||||
service :String) :InvocationService_ConfirmListener
|
||||
{
|
||||
return new ConfirmAdapter(function (cause :String) :void {
|
||||
Log.getLog(GameObject).warning("Service failure " +
|
||||
"[service=" + service + ", cause=" + cause + "].");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for setCollection and addToCollection.
|
||||
*/
|
||||
private function populateCollection (
|
||||
collName :String, values :Array, clearExisting :Boolean) :void
|
||||
{
|
||||
validateName(collName);
|
||||
if (values == null) {
|
||||
throw new ArgumentError("Collection values may not be null.");
|
||||
}
|
||||
validateValue(values);
|
||||
|
||||
var encodedValues :TypedArray =
|
||||
(EZObjectMarshaller.encode(values) as TypedArray);
|
||||
|
||||
_ezObj.ezGameService.addToCollection(
|
||||
_ctx.getClient(), collName, encodedValues, clearExisting,
|
||||
createLoggingListener("populateCollection"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for pickFromCollection and dealFromCollection.
|
||||
*/
|
||||
private function getFromCollection(
|
||||
collName :String, count :int, msgOrPropName :String, playerIndex :int,
|
||||
consume :Boolean, callback :Function) :void
|
||||
{
|
||||
validateName(collName);
|
||||
validateName(msgOrPropName);
|
||||
if (count < 1) {
|
||||
throw new ArgumentError("Must retrieve at least one element!");
|
||||
}
|
||||
|
||||
var listener :InvocationService_ConfirmListener;
|
||||
if (callback != null) {
|
||||
// TODO: Figure out the method sig of the callback, and what it
|
||||
// means
|
||||
var fn :Function = function (cause :String = null) :void {
|
||||
if (cause == null) {
|
||||
callback(count);
|
||||
} else {
|
||||
callback(parseInt(cause));
|
||||
}
|
||||
};
|
||||
listener = new ConfirmAdapter(fn, fn);
|
||||
|
||||
} else {
|
||||
listener = createLoggingListener("getFromCollection");
|
||||
}
|
||||
|
||||
_ezObj.ezGameService.getFromCollection(
|
||||
_ctx.getClient(), collName, consume, count, msgOrPropName,
|
||||
playerIndex, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the property name / value are valid.
|
||||
*/
|
||||
private function validatePropertyChange (
|
||||
propName :String, value :Object, index :int) :void
|
||||
{
|
||||
validateName(propName);
|
||||
|
||||
// check that we're setting an array element on an array
|
||||
if (index >= 0) {
|
||||
if (!(_gameData[propName] is Array)) {
|
||||
throw new ArgumentError("Property " + propName +
|
||||
" is not an Array.");
|
||||
}
|
||||
}
|
||||
|
||||
// validate the value too
|
||||
validateValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the specified name is valid.
|
||||
*/
|
||||
private function validateName (name :String) :void
|
||||
{
|
||||
if (name == null) {
|
||||
throw new ArgumentError(
|
||||
"Property, message, and collection names must not be null.");
|
||||
}
|
||||
}
|
||||
|
||||
private function validateChat (msg :String) :void
|
||||
{
|
||||
if (StringUtil.isBlank(msg)) {
|
||||
throw new ArgumentError(
|
||||
"Empty chat may not be displayed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the value is legal to be streamed to other clients.
|
||||
*/
|
||||
private function validateValue (value :Object) :void
|
||||
{
|
||||
if (value == null) {
|
||||
return;
|
||||
|
||||
} else if (value is IExternalizable) {
|
||||
throw new ArgumentError(
|
||||
"IExternalizable is not yet supported");
|
||||
|
||||
} else if (value is Array) {
|
||||
if (ClassUtil.getClass(value) != Array) {
|
||||
// We can't allow arrays to be serialized as IExternalizables
|
||||
// because we need to know element values (opaquely) on the
|
||||
// server. Also, we don't allow other types because we wouldn't
|
||||
// create the right class on the other side.
|
||||
throw new ArgumentError(
|
||||
"Custom array subclasses are not supported");
|
||||
}
|
||||
// then, continue on with the sub-properties check (below)
|
||||
|
||||
} else {
|
||||
var type :String = typeof(value);
|
||||
if (type == "number" || type == "string" || type == "boolean" ) {
|
||||
// kosher!
|
||||
return;
|
||||
}
|
||||
if (ClassUtil.getClass(value) != Object) {
|
||||
throw new ArgumentError(
|
||||
"Non-simple properties may not be set.");
|
||||
}
|
||||
// fall through and verify the object's sub-properties
|
||||
}
|
||||
|
||||
// check sub-properties (of arrays and objects)
|
||||
for each (var arrValue :Object in (value as Array)) {
|
||||
validateValue(arrValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected var _ctx :CrowdContext;
|
||||
|
||||
protected var _ezObj :EZGameObject;
|
||||
|
||||
protected var _gameData :GameData;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user