diff --git a/src/as/com/threerings/ezgame/EZEvent.as b/src/as/com/threerings/ezgame/EZEvent.as new file mode 100644 index 00000000..aac3e757 --- /dev/null +++ b/src/as/com/threerings/ezgame/EZEvent.as @@ -0,0 +1,27 @@ +package com.threerings.ezgame { + +import flash.events.Event; + +// TODO: there may not be much point in using the standard flash event +// architecture. I'm about thiiiiiiis close to not. +// +public /*abstract*/ class EZEvent extends Event +{ + /** + * Access the game object to which this event applies. + */ + public function get gameObject () :EZGame + { + return _ezgame; + } + + public function EZEvent (type :String, ezgame :EZGame) + { + super(type); + _ezgame = ezgame; + } + + /** The game object for this event. */ + protected var _ezgame :EZGame; +} +} diff --git a/src/as/com/threerings/ezgame/EZGame.as b/src/as/com/threerings/ezgame/EZGame.as index fc6cac08..1afa3f80 100644 --- a/src/as/com/threerings/ezgame/EZGame.as +++ b/src/as/com/threerings/ezgame/EZGame.as @@ -23,6 +23,19 @@ public interface EZGame */ function set (propName :String, value :Object, index :int = -1) :void; + /** + * Register an object to receive whatever events it should receive, + * based on which event listeners it implements. Note that it is not + * necessary to register any objects which appear on the display list, + * as they'll be registered automatically. + */ + function registerListener (obj :Object) :void; + + /** + * Unregister the specified object from receiving events. + */ + function unregisterListener (obj :Object) :void; + /** * Set the specified collection to contain the specified values, * clearing any previous values. diff --git a/src/as/com/threerings/ezgame/MessageReceivedEvent.as b/src/as/com/threerings/ezgame/MessageReceivedEvent.as index cea56a9c..5736565d 100644 --- a/src/as/com/threerings/ezgame/MessageReceivedEvent.as +++ b/src/as/com/threerings/ezgame/MessageReceivedEvent.as @@ -2,7 +2,7 @@ package com.threerings.ezgame { import flash.events.Event; -public class MessageReceivedEvent extends Event +public class MessageReceivedEvent extends EZEvent { /** The type of all MessageReceivedEvents. */ public static const TYPE :String = "msgReceived"; @@ -23,9 +23,10 @@ public class MessageReceivedEvent extends Event return _value; } - public function MessageReceivedEvent (messageName :String, value :Object) + public function MessageReceivedEvent ( + ezgame :EZGame, messageName :String, value :Object) { - super(TYPE); + super(TYPE, ezgame); _name = messageName; _value = value; } @@ -38,7 +39,7 @@ public class MessageReceivedEvent extends Event override public function clone () :Event { - return new MessageReceivedEvent(_name, _value); + return new MessageReceivedEvent(_ezgame, _name, _value); } protected var _name :String; diff --git a/src/as/com/threerings/ezgame/MessageReceivedListener.as b/src/as/com/threerings/ezgame/MessageReceivedListener.as new file mode 100644 index 00000000..f355d6ac --- /dev/null +++ b/src/as/com/threerings/ezgame/MessageReceivedListener.as @@ -0,0 +1,14 @@ +package com.threerings.ezgame { + +/** + * Implement this interface to automagically be registered to received + * MessageReceivedEvents. + */ +public interface MessageReceivedListener +{ + /** + * Handle a MessageReceivedEvent. + */ + function messageReceived (event :MessageReceivedEvent) :void; +} +} diff --git a/src/as/com/threerings/ezgame/PropertyChangedEvent.as b/src/as/com/threerings/ezgame/PropertyChangedEvent.as index dfb0ddd6..dab9d6ee 100644 --- a/src/as/com/threerings/ezgame/PropertyChangedEvent.as +++ b/src/as/com/threerings/ezgame/PropertyChangedEvent.as @@ -6,7 +6,7 @@ import flash.events.Event; * Property change events are dispatched after the property change was * validated on the server. */ -public class PropertyChangedEvent extends Event +public class PropertyChangedEvent extends EZEvent { /** The type of a property change event. */ public static const TYPE :String = "PropChanged"; @@ -47,9 +47,10 @@ public class PropertyChangedEvent extends Event * Constructor. */ public function PropertyChangedEvent ( - propName :String, newValue :Object, oldValue :Object, index :int = -1) + ezgame :EZGame, propName :String, newValue :Object, + oldValue :Object, index :int = -1) { - super(TYPE); + super(TYPE, ezgame); _name = propName; _newValue = newValue; _oldValue = oldValue; @@ -64,7 +65,8 @@ public class PropertyChangedEvent extends Event override public function clone () :Event { - return new PropertyChangedEvent(_name, _newValue, _oldValue, _index); + return new PropertyChangedEvent( + _ezgame, _name, _newValue, _oldValue, _index); } /** Our implementation details. */ diff --git a/src/as/com/threerings/ezgame/PropertyChangedListener.as b/src/as/com/threerings/ezgame/PropertyChangedListener.as new file mode 100644 index 00000000..d65020da --- /dev/null +++ b/src/as/com/threerings/ezgame/PropertyChangedListener.as @@ -0,0 +1,14 @@ +package com.threerings.ezgame { + +/** + * Implement this interface to automagically be registered to received + * PropertyChangedEvents. + */ +public interface PropertyChangedListener +{ + /** + * Handle a PropertyChangedEvent. + */ + function propertyChanged (event :PropertyChangedEvent) :void; +} +} diff --git a/src/as/com/threerings/ezgame/StateChangedEvent.as b/src/as/com/threerings/ezgame/StateChangedEvent.as index 123618f1..241d026b 100644 --- a/src/as/com/threerings/ezgame/StateChangedEvent.as +++ b/src/as/com/threerings/ezgame/StateChangedEvent.as @@ -5,7 +5,7 @@ import flash.events.Event; /** * Dispatched when the state of the game has changed. */ -public class StateChangedEvent extends Event +public class StateChangedEvent extends EZEvent { /** Indicates that the game has transitioned to a started state. */ public static const GAME_STARTED :String = "GameStarted"; @@ -17,9 +17,9 @@ public class StateChangedEvent extends Event // TODO: move to own event? public static const TURN_CHANGED :String = "TurnChanged"; - public function StateChangedEvent (type :String) + public function StateChangedEvent (type :String, ezgame :EZGame) { - super(type); + super(type, ezgame); } override public function toString () :String @@ -29,7 +29,7 @@ public class StateChangedEvent extends Event override public function clone () :Event { - return new StateChangedEvent(type); + return new StateChangedEvent(type, _ezgame); } } } diff --git a/src/as/com/threerings/ezgame/StateChangedListener.as b/src/as/com/threerings/ezgame/StateChangedListener.as new file mode 100644 index 00000000..91a13148 --- /dev/null +++ b/src/as/com/threerings/ezgame/StateChangedListener.as @@ -0,0 +1,14 @@ +package com.threerings.ezgame { + +/** + * Implement this interface to automagically be registered to received + * StateChangedEvents. + */ +public interface StateChangedListener +{ + /** + * Handle a StateChangedEvent. + */ + function stateChanged (event :StateChangedEvent) :void; +} +} diff --git a/src/as/com/threerings/ezgame/client/EZGameController.as b/src/as/com/threerings/ezgame/client/EZGameController.as index 8176d3e2..3aef627b 100644 --- a/src/as/com/threerings/ezgame/client/EZGameController.as +++ b/src/as/com/threerings/ezgame/client/EZGameController.as @@ -68,7 +68,7 @@ public class EZGameController extends GameController public function turnDidChange (turnHolder :Name) :void { dispatchUserEvent( - new StateChangedEvent(StateChangedEvent.TURN_CHANGED)); + new StateChangedEvent(StateChangedEvent.TURN_CHANGED, gameObjImpl)); } // from PropertySetListener @@ -76,8 +76,8 @@ public class EZGameController extends GameController { // notify the user game dispatchUserEvent(new PropertyChangedEvent( - event.getName(), event.getValue(), event.getOldValue(), - event.getIndex())); + gameObjImpl, event.getName(), event.getValue(), + event.getOldValue(), event.getIndex())); } // from MessageListener @@ -114,7 +114,7 @@ public class EZGameController extends GameController protected function dispatchUserMessage (args :Array) :void { dispatchUserEvent(new MessageReceivedEvent( - (args[0] as String), + gameObjImpl, (args[0] as String), EZObjectMarshaller.decode(args[1]))); } @@ -127,14 +127,14 @@ public class EZGameController extends GameController { super.gameDidStart(); dispatchUserEvent( - new StateChangedEvent(StateChangedEvent.GAME_STARTED)); + new StateChangedEvent(StateChangedEvent.GAME_STARTED, gameObjImpl)); } override protected function gameDidEnd () :void { super.gameDidEnd(); dispatchUserEvent( - new StateChangedEvent(StateChangedEvent.GAME_ENDED)); + new StateChangedEvent(StateChangedEvent.GAME_ENDED, gameObjImpl)); } protected function dispatchUserEvent (event :Event) :void diff --git a/src/as/com/threerings/ezgame/client/EZGamePanel.as b/src/as/com/threerings/ezgame/client/EZGamePanel.as index 4a35a77f..3f8d8f98 100644 --- a/src/as/com/threerings/ezgame/client/EZGamePanel.as +++ b/src/as/com/threerings/ezgame/client/EZGamePanel.as @@ -38,6 +38,7 @@ public class EZGamePanel extends VBox // add a listener so that we hear about all new children addEventListener(Event.ADDED, childAdded); + addEventListener(Event.REMOVED, childRemoved); var cfg :EZGameConfig = (ctrl.getPlaceConfig() as EZGameConfig); _gameView = new MediaContainer(cfg.configData); // TODO @@ -64,6 +65,7 @@ public class EZGamePanel extends VBox // from PlaceView public function didLeavePlace (plobj :PlaceObject) :void { + removeListeners(_gameView); _ezObj = null; } @@ -77,6 +79,17 @@ public class EZGamePanel extends VBox } } + /** + * Handle REMOVED events. + */ + protected function childRemoved (event :Event) :void + { + trace("Child removed: " + event.target); + if (_ezObj != null) { + removeListeners(event.target as DisplayObject); + } + } + /** * Find any children of the specified object that implement * com.metasoy.game.Game and provide them with the GameObject. @@ -93,6 +106,17 @@ public class EZGamePanel extends VBox _seenGames[disp] = true; } } + // always check to see if it's a listener + _ctrl.gameObjImpl.registerListener(disp); + }); + } + + protected function removeListeners (root :DisplayObject) :void + { + DisplayUtil.walkDisplayObjects(root, + function (disp :DisplayObject) :void + { + _ctrl.gameObjImpl.unregisterListener(disp); }); } diff --git a/src/as/com/threerings/ezgame/client/GameObjectImpl.as b/src/as/com/threerings/ezgame/client/GameObjectImpl.as index 5e0f67f4..a2ef7fcd 100644 --- a/src/as/com/threerings/ezgame/client/GameObjectImpl.as +++ b/src/as/com/threerings/ezgame/client/GameObjectImpl.as @@ -26,7 +26,12 @@ import com.threerings.ezgame.data.PropertySetEvent; import com.threerings.ezgame.util.EZObjectMarshaller; import com.threerings.ezgame.EZGame; +import com.threerings.ezgame.MessageReceivedEvent; +import com.threerings.ezgame.MessageReceivedListener; import com.threerings.ezgame.PropertyChangedEvent; +import com.threerings.ezgame.PropertyChangedListener; +import com.threerings.ezgame.StateChangedEvent; +import com.threerings.ezgame.StateChangedListener; public class GameObjectImpl extends EventDispatcher implements EZGame @@ -74,6 +79,59 @@ public class GameObjectImpl extends EventDispatcher _ezObj.applyPropertySet(propName, value, index); } + // from EZGame + public function registerListener (obj :Object) :void + { + if (obj is MessageReceivedListener) { + var mrl :MessageReceivedListener = (obj as MessageReceivedListener); + addEventListener( + MessageReceivedEvent.TYPE, mrl.messageReceived, + false, 0, true); + } + if (obj is PropertyChangedListener) { + var pcl :PropertyChangedListener = (obj as PropertyChangedListener); + addEventListener( + PropertyChangedEvent.TYPE, pcl.propertyChanged, + false, 0, true); + } + if (obj is StateChangedListener) { + var scl :StateChangedListener = (obj as StateChangedListener); + addEventListener( + StateChangedEvent.GAME_STARTED, scl.stateChanged, + false, 0, true); + addEventListener( + StateChangedEvent.TURN_CHANGED, scl.stateChanged, + false, 0, true); + addEventListener( + StateChangedEvent.GAME_ENDED, scl.stateChanged, + false, 0, true); + } + } + + // from EZGame + public function unregisterListener (obj :Object) :void + { + if (obj is MessageReceivedListener) { + var mrl :MessageReceivedListener = (obj as MessageReceivedListener); + removeEventListener( + MessageReceivedEvent.TYPE, mrl.messageReceived); + } + if (obj is PropertyChangedListener) { + var pcl :PropertyChangedListener = (obj as PropertyChangedListener); + removeEventListener( + PropertyChangedEvent.TYPE, pcl.propertyChanged); + } + if (obj is StateChangedListener) { + var scl :StateChangedListener = (obj as StateChangedListener); + removeEventListener( + StateChangedEvent.GAME_STARTED, scl.stateChanged); + removeEventListener( + StateChangedEvent.TURN_CHANGED, scl.stateChanged); + removeEventListener( + StateChangedEvent.GAME_ENDED, scl.stateChanged); + } + } + // from EZGame public function setCollection (collName :String, values :Array) :void {