From fa7bf73ddc9a77544670b96d7c8ed5ffec017974 Mon Sep 17 00:00:00 2001 From: Robert Zubeck Date: Mon, 19 Feb 2007 23:21:28 +0000 Subject: [PATCH] Moving host coordinator into vilya. git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@198 c613c5cb-e716-0410-b11b-feb51c14d237 --- .../com/threerings/ezgame/HostCoordinator.as | 205 ++++++++++++++++++ src/as/com/threerings/ezgame/HostEvent.as | 33 +++ 2 files changed, 238 insertions(+) create mode 100644 src/as/com/threerings/ezgame/HostCoordinator.as create mode 100644 src/as/com/threerings/ezgame/HostEvent.as diff --git a/src/as/com/threerings/ezgame/HostCoordinator.as b/src/as/com/threerings/ezgame/HostCoordinator.as new file mode 100644 index 00000000..d2f5132e --- /dev/null +++ b/src/as/com/threerings/ezgame/HostCoordinator.as @@ -0,0 +1,205 @@ +package com.threerings.ezgame { + +import flash.events.EventDispatcher; + +/** + HostCoordinator provides methods for determining whether the current + client should consider itself the authority in dealing with game state + (for example, when dealing out cards, or setting up the game board). + + Current hosting state can be retrieved from the /status/ property. + Please note that hosting authority can be transferred between clients + at any moment, so all clients should be prepared to suddenly take + over host responsibilities. + + Additionally, the client can register itself for notifications + about changes to the /status/ property - see HostEvent. + + Usage example: + +
+   _coord = new HostCoordinator (_gameCtrl);
+   _coord.addEventListener (HostEvent.CLAIMED, firstHostHandler);
+   _coord.addEventListener (HostEvent.CHANGED, hostChangeHandler);
+
+   ...
+
+   function firstHostHandler (event : HostEvent)
+   {
+     if (_coord.status == HostCoordinator.STATUS_HOST)
+     {
+       // I'm the first host in the game - I should set up the initial board, etc.
+     }
+   }
+   
+   function hostChangeHandler (event : HostEvent)
+   {
+     if (_coord.status == HostCoordinator.STATUS_HOST)
+     {
+       // I just became the host - do whatever is needed.
+     } 
+   }
+   
+ +*/ +public class HostCoordinator + extends EventDispatcher + implements OccupantChangedListener, PropertyChangedListener +{ + // CONSTANTS + + /** Status constant, means that the current status is unknown, either because + the data had not yet arrived from the server, or because nobody claims + to be host for this game. */ + public static const STATUS_UNKNOWN : String = "STATUS_UNKNOWN"; + + /** Status constant, means that this client is the current host. */ + public static const STATUS_HOST : String = "STATUS_HOST"; + + /** Status constant, means that some other client is the current host. */ + public static const STATUS_NOT_HOST : String = "STATUS_NOT_HOST"; + + + + // PUBLIC INTERFACE + + /** + Constructor, expects an initialized instance of EZGameControl. + + If the optional showDebug flag is set, it will display host info + as chat messages (only useful for debugging). + */ + public function HostCoordinator (control : EZGameControl, showDebug : Boolean = false) + { + _control = control; + _control.registerListener (this); + + _showDebug = showDebug; + + // Try set host role if it's not already claimed (i.e. null) + debugLog ("Trying to claim host role."); + debugLog ("Current status: " + status); + tryReplaceHost (null); + } + + /** + Retrieves current host coordination status, as one of the STATUS_* + constants. + + Note: do not save the value of this property. Hosting status + can change at any moment: when the current host quits the game, + any client can suddenly become the new host. +l */ + public function get status () : String + { + var hostId : Number = getHostId (); + if (hostId == _control.getMyId ()) { return STATUS_HOST; } + if (hostId > 0) { return STATUS_NOT_HOST; } + return STATUS_UNKNOWN; + } + + + + + // EVENT HANDLERS + + /** From OccupantChangedListener: keep track of people coming in */ + public function occupantEntered (event : OccupantChangedEvent) : void + { + debugHostStatus (); + } + + /** From OccupantChangedListener: keep track of people leaving */ + public function occupantLeft (event : OccupantChangedEvent) : void + { + // If the occupant who just left was the host, every client will + // get a shot at trying to claim their role. + debugLog ("My ID: " + _control.getMyId ()); + debugLog ("Occupant left: " + event.occupantId); + debugLog ("Current host: " + getHostId()); + + if (getHostId () == event.occupantId) // Elvis has left the building + { + debugLog ("Removing the old host..."); + // Clear the old host value, and put myself in their place. + // Only the first client will succeed in doing this. + tryReplaceHost (event.occupantId); + } + } + + /** From PropertyChangedListener: keep track of changing host values */ + public function propertyChanged (event : PropertyChangedEvent) : void + { + if (event.name == HOST_NAME) + { + debugLog ("Host variable changed to: " + event.newValue); + + // if the host was not known before, dispatch the claimed event + if (event.oldValue == null && + event.newValue != null) + { + var claimed : HostEvent = new HostEvent (HostEvent.CLAIMED, _control); + this.dispatchEvent (claimed); + } + + // always dispatch the changed event + var changed : HostEvent = new HostEvent (HostEvent.CHANGED, _control); + this.dispatchEvent (changed); + } + } + + + // PRIVATE FUNCTIONS + + /** Get the current host ID (will be 0 if there is no authoritative host) */ + private function getHostId () : Number + { + var hostvalue : Object = _control.get (HOST_NAME); + if (hostvalue != null && hostvalue is Number) + { + return hostvalue as Number; + } + return 0; + } + + /** Helper function: tries to set the host variable to the client's id, + if the current value is equal to /hostId/. If the value of null for + hostId has the meaning of "set me as host only if the role has not + been claimed yet". */ + private function tryReplaceHost (hostId : Object) : void + { + _control.testAndSet (HOST_NAME, _control.getMyId (), hostId); + debugHostStatus (); + } + + /** Debug only */ + private function debugLog (message : String) : void + { + if (_showDebug) { _control.localChat (message); } + } + + /** Debug only */ + private function debugHostStatus () : void + { + debugLog ( + (status == STATUS_HOST ? "I am" : "I'm not") + + " the host (id " + getHostId() + ", mine is " + _control.getMyId() + ")"); + } + + + // PRIVATE VALUES + + /** Magic key that stores current authoritative host */ + private var HOST_NAME : String = "HOST_COORDINATOR_AUTHORITATIVE_HOST"; + + /** Controller storage */ + private var _control : EZGameControl = null; + + /** Debug flag */ + private var _showDebug : Boolean; + +} + +} + + diff --git a/src/as/com/threerings/ezgame/HostEvent.as b/src/as/com/threerings/ezgame/HostEvent.as new file mode 100644 index 00000000..c26331c0 --- /dev/null +++ b/src/as/com/threerings/ezgame/HostEvent.as @@ -0,0 +1,33 @@ +package com.threerings.ezgame { + +import flash.events.Event; + +/** + * Dispatched by the host coordinator, to signal a change + * in host status. + */ +public class HostEvent extends EZEvent +{ + /** Indicates that the current host changed. */ + public static const CHANGED :String = "Host Changed"; + + /** Indicates that the host used to be unknown, but it became claimed + by one of the clients. */ + public static const CLAIMED :String = "Host Claimed"; + + public function HostEvent (type :String, ezgame :EZGameControl) + { + super (type, ezgame); + } + + override public function toString () :String + { + return "[HostEvent type=" + type + "]"; + } + + override public function clone () :Event + { + return new HostEvent (type, _ezgame); + } +} +}