Started work on the 'crowd' package.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3935 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Ray Greenwell
2006-03-10 03:05:37 +00:00
parent 3f5aed3555
commit ca66f91ac7
31 changed files with 2650 additions and 57 deletions
+10
View File
@@ -1,6 +1,16 @@
This document contains a couple of notes about some design decisions
and some notes about flash that you may find useful.
TODO
----
- Write code that processes a dobj class in java and outputs the
corresponding class in actionscript. This is sorta fucked because
we want to exclude things not applicable to client code, not because
we're trying to save every byte in the class definition, but because
some of those methods involve whole classes we don't need on the as client.
- Write code that generates actionscript service, listener and marshaller
classes from a java Service class definition.
Design decisions
----------------
+36
View File
@@ -0,0 +1,36 @@
package com.threerings.crowd {
import mx.logging.ILogger;
import com.threerings.util.LogDaddy;
public class Log extends LogDaddy
{
/** The Logger for this package. */
public static var log :ILogger = getLogger("crowd");
/** Convenience function. */
public static function debug (message :String, ... rest) :void
{
log.debug(message, rest);
}
/** Convenience function. */
public static function info (message :String, ... rest) :void
{
log.info(message, rest);
}
/** Convenience function. */
public static function warning (message :String, ... rest) :void
{
log.warn(message, rest);
}
/** Convenience function. */
public static function logStackTrace (err :Error) :void
{
log.warn(err.getStackTrace());
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
//
// $Id: ChatDisplay.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.client {
import com.threerings.crowd.chat.data.ChatMessage;
/**
* A chat display provides a means by which chat messages can be
* displayed. The chat display will be notified when chat messages of
* various sorts have been received by the client.
*/
public interface ChatDisplay
{
/**
* Called to clear the chat display.
*/
public function clear () :void;
/**
* Called to display a chat message.
*
* @see ChatMessage
*/
public function displayMessage (msg :ChatMessage) :void;
}
}
@@ -0,0 +1,69 @@
//
// $Id: ChatService.java 3310 2005-01-24 23:08:21Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.client {
import com.threerings.util.Name;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationListener;
import com.threerings.presents.client.InvocationService;
/**
* The chat services provide a mechanism by which the client can broadcast
* chat messages to all clients that are subscribed to a particular place
* object or directly to a particular client. These services should not be
* used directly, but instead should be accessed via the {@link
* ChatDirector}.
*/
public interface ChatService extends InvocationService
{
/**
* Requests that a tell message be delivered to the user with username
* equal to <code>target</code>.
*
* @param client a connected, operational client instance.
* @param target the username of the user to which the tell message
* should be delivered.
* @param message the contents of the message.
* @param listener the reference that will receive the tell response.
*/
function tell (
client :Client, target :Name, message :String, listener :TellListener)
:void;
/**
* Requests that a message be broadcast to all users in the system.
*
* @param client a connected, operational client instance.
* @param message the contents of the message.
* @param listener the reference that will receive a failure response.
*/
function broadcast (
client :Client, message :String, listener :InvocationListener) :void;
/**
* Sets this client's away message. If the message is null or the
* empty string, the away message will be cleared.
*/
function away (client :Client, message :String) :void;
}
}
@@ -0,0 +1,44 @@
package com.threerings.crowd.chat.client {
import com.threerings.crowd.data.BodyObject;
/**
* Used to implement a slash command (e.g. <code>/who</code>).
*/
public /* abstract */ class CommandHandler
{
/**
* Handles the specified chat command.
*
* @param speakSvc an optional SpeakService object representing
* the object to send the chat message on.
* @param command the slash command that was used to invoke this
* handler (e.g. <code>/tell</code>).
* @param args the arguments provided along with the command (e.g.
* <code>Bob hello</code>) or <code>null</code> if no arguments
* were supplied.
* @param history an in/out parameter that allows the command to
* modify the text that will be appended to the chat history. If
* this is set to null, nothing will be appended.
*
* @return an untranslated string that will be reported to the
* chat box to convey an error response to the user, or {@link
* ChatCodes#SUCCESS}.
*/
public function handleCommand (
speakSvc :SpeakService, cmd :String, args :String, history :Array)
:void
{
throw new Error("abstract");
}
/**
* Returns true if this user should have access to this chat
* command.
*/
public function checkAccess (user :BodyObject) :Boolean
{
return true;
}
}
}
@@ -0,0 +1,46 @@
//
// $Id: SpeakService.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.client {
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Provides a means by which "speaking" can be allowed among subscribers
* of a particular distributed object.
*/
public interface SpeakService extends InvocationService
{
/**
* Issues a request to speak "on" the distributed object via which
* this speak service was provided.
*
* @param message the message to be spoken.
* @param mode the "mode" of the message. This is an opaque value that
* will be passed back down via the {@link ChatDirector} to the {@link
* ChatDisplay} implementations which can interpret it in an
* application specific manner. It's useful for differentiating
* between regular speech, emotes, etc.
*/
function speak (client :Client, message :String, mode :int) :void;
}
}
@@ -0,0 +1,11 @@
package com.threerings.crowd.chat.client {
import com.threerings.util.long;
import com.threerings.presents.client.InvocationListener
public interface TellListener extends InvocationListener
{
function tellSucceeded (idleTime :long, awayMessage :String) :void;
}
}
@@ -0,0 +1,91 @@
//
// $Id: ChatCodes.java 3725 2005-10-08 22:21:19Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.data {
import com.threerings.presents.data.InvocationCodes;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.chat.client.ChatDirector;
import com.threerings.crowd.chat.client.SpeakService;
/**
* Contains codes used by the chat invocation services.
*/
public class ChatCodes extends InvocationCodes
{
/** The message identifier for a chat notification message. */
public static const CHAT_NOTIFICATION :String = "chat";
/** The access control identifier for normal chat privileges. See
* {@link BodyObject#checkAccess}. */
public static const CHAT_ACCESS :String = "crowd.chat.chat";
/** The access control identifier for broadcast chat privileges. See
* {@link BodyObject#checkAccess}. */
public static const BROADCAST_ACCESS :String = "crowd.chat.broadcast";
/** The configuration key for idle time. */
public static const IDLE_TIME_KEY :String = "narya.chat.idle_time";
/** The default time after which a player is assumed idle. */
public static const DEFAULT_IDLE_TIME :Number = 3 * 60 * 1000;
/** The chat localtype code for chat messages delivered on the place
* object currently occupied by the client. This is the only type of
* chat message that will be delivered unless the chat director is
* explicitly provided with other chat message sources via {@link
* ChatDirector#addAuxiliarySource}. */
public static const PLACE_CHAT_TYPE :String = "placeChat";
/** The chat localtype for messages received on the user object. */
public static const USER_CHAT_TYPE :String = "userChat";
/** The default mode used by {@link SpeakService#speak} requests. */
public static const DEFAULT_MODE :int = 0;
/** A {@link SpeakService#speak} mode to indicate that the user is
* thinking what they're saying, or is it that they're saying what
* they're thinking? */
public static const THINK_MODE :int = 1;
/** A {@link SpeakService#speak} mode to indicate that a speak is
* actually an emote. */
public static const EMOTE_MODE :int = 2;
/** A {@link SpeakService#speak} mode to indicate that a speak is
* actually a shout. */
public static const SHOUT_MODE :int = 3;
/** A {@link SpeakService#speak} mode to indicate that a speak is
* actually a server-wide broadcast. */
public static const BROADCAST_MODE :int = 4;
/** An error code delivered when the user targeted for a tell
* notification is not online. */
public static const USER_NOT_ONLINE :String = "m.user_not_online";
/** An error code delivered when the user targeted for a tell
* notification is disconnected. */
public static const USER_DISCONNECTED :String = "m.user_disconnected";
}
}
@@ -0,0 +1,81 @@
//
// $Id: ChatMessage.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.data {
import com.samskivert.util.StringUtil;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamable;
/**
* The abstract base class of all the client-side ChatMessage objects.
*/
public /*abstract*/ class ChatMessage
implements Streamable
{
/** The actual text of the message. */
public var message :String;
/** The bundle to use when translating this message. */
public var bundle :String;
/** The client side 'localtype' of this chat, set to the type
* registered with an auxiliary source in the ChatDirector. */
public var localtype :String;
/**
* Once this message reaches the client, the information contained within
* is changed around a bit.
*/
public function setClientInfo (msg :String, localtype :String) :void
{
message = msg;
this.localtype = localtype;
bundle = null;
//timestamp = System.currentTimeMillis();
}
/**
* Generates a string representation of this instance.
*/
public function toString () :String
{
return ClassUtil.shortClassName(this) +
" [message=" + message + ", bundle=" + bundle + "]";
}
// documentation inherited from interface Streamable
public function readObject (ins :ObjectInputStream) :void
{
message = ins.readField(String);
bundle = ins.readField(String);
}
// documentation inherited from interface Streamable
public function writeObject (out :ObjectOutputStream) :void
{
out.writeField(message);
out.writeField(bundle);
}
}
}
@@ -0,0 +1,58 @@
//
// $Id: SystemMessage.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.data {
/**
* A ChatMessage that represents a message that came from the server
* and did not result from direct user action.
*/
public class SystemMessage extends ChatMessage
{
/** Attention level constant to indicate that this message is merely
* providing the user with information. */
public static const INFO :int = 0;
/** Attention level constant to indicate that this message is the
* result of a user action. */
public static const FEEDBACK :int = 1;
/** Attention level constant to indicate that some action is required. */
public static const ATTENTION :int = 2;
//----
/** The attention level of this message. */
public var attentionLevel :int;
public override function readObject (ins :ObjectInputStream) :void
{
super.readObject(ins);
attentionLevel = ins.readByte();
}
public override function writeObject (out :ObjectOutputStream) :void
{
super.writeObject(out);
out.writeByte(attentionLevel);
}
}
}
@@ -0,0 +1,54 @@
//
// $Id: UserMessage.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.chat.data {
import com.threerings.util.Name;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
/**
* A ChatMessage representing a message that came from another user.
*/
public class UserMessage extends ChatMessage
{
/** The user that the message came from. */
public var speaker :Name;
/** The mode of the message. @see ChatCodes.DEFAULT_MODE */
public var mode :int;
public override function readObject (ins :ObjectInputStream) :void
{
super.readObject(ins);
speaker = (ins.readObject() as Name);
mode = ins.readByte();
}
public override function writeObject (out :ObjectOutputStream) :void
{
super.writeObject(out);
out.writeObject(speaker);
out.writeByte(mode);
}
}
}
@@ -0,0 +1,203 @@
//
// $Id: BodyObject.java 3774 2005-12-03 03:05:06Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.data {
import com.threerings.util.Byte;
import com.threerings.util.Name;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationCodes;
import com.threerings.crowd.chat.data.ChatCodes;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
/**
* The basic user object class for Crowd users. Bodies have a username, a
* location and a status.
*/
public class BodyObject extends ClientObject
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>username</code> field. */
public static const USERNAME :String = "username";
/** The field name of the <code>location</code> field. */
public static const LOCATION :String = "location";
/** The field name of the <code>status</code> field. */
public static const STATUS :String = "status";
/** The field name of the <code>awayMessage</code> field. */
public static const AWAY_MESSAGE :String = "awayMessage";
// AUTO-GENERATED: FIELDS END
/**
* The username associated with this body object. This should not be used
* directly; in general {@link #getVisibleName} should be used unless you
* specifically know that you want the username.
*/
public var username :Name;
/**
* The oid of the place currently occupied by this body or -1 if they
* currently occupy no place.
*/
public var location :int = -1;
/**
* The user's current status ({@link OccupantInfo#ACTIVE}, etc.).
*/
public var status :int;
/**
* If non-null, this contains a message to be auto-replied whenever
* another user delivers a tell message to this user.
*/
public var awayMessage :String;
// /**
// * Checks whether or not this user has access to the specified
// * feature. Currently used by the chat system to regulate access to
// * chat broadcasts but also forms the basis of an extensible
// * fine-grained permissions system.
// *
// * @return null if the user has access, a fully-qualified translatable
// * message string indicating the reason for denial of access (or just
// * {@link InvocationCodes#ACCESS_DENIED} if you don't want to be
// * specific).
// */
// public String checkAccess (String feature, Object context)
// {
// // our default access control policy; how quaint
// if (ChatCodes.BROADCAST_ACCESS.equals(feature)) {
// return getTokens().isAdmin() ? null : ChatCodes.ACCESS_DENIED;
// } else if (ChatCodes.CHAT_ACCESS.equals(feature)) {
// return null;
// } else {
// return InvocationCodes.ACCESS_DENIED;
// }
// }
//
// /**
// * Returns this user's access control tokens.
// */
// public TokenRing getTokens ()
// {
// return EMPTY_TOKENS;
// }
/**
* Returns the name that should be displayed to other users and used for
* the chat system. The default is to use {@link #username}.
*/
public function getVisibleName () :Name
{
return username;
}
public override function writeObject (out :ObjectOutputStream) :void
{
super.writeObject(out);
out.writeObject(username);
out.writeInt(location);
out.writeByte(status);
out.writeField(awayMessage);
}
public override function readObject (ins :ObjectInputStream) :void
{
super.readObject(ins);
username = (ins.readObject() as Name);
location = ins.readInt();
status = ins.readByte();
awayMessage = (ins.readField(String) as String);
}
// AUTO-GENERATED: METHODS START
/**
* Requests that the <code>username</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.
*/
public function setUsername (value :Name) :void
{
Name ovalue = this.username;
requestAttributeChange(
USERNAME, value, ovalue);
this.username = value;
}
/**
* Requests that the <code>location</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.
*/
public function setLocation (value :int) :void
{
int ovalue = this.location;
requestAttributeChange(
LOCATION, value, ovalue);
this.location = value;
}
/**
* Requests that the <code>status</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.
*/
public function setStatus (value :int) :void
{
var ovalue :int = this.status;
requestAttributeChange(
STATUS, new Byte(value), new Byte(ovalue));
this.status = value;
}
/**
* Requests that the <code>awayMessage</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.
*/
public function setAwayMessage (value :String) :void
{
var ovalue :String = this.awayMessage;
requestAttributeChange(
AWAY_MESSAGE, value, ovalue);
this.awayMessage = value;
}
// AUTO-GENERATED: METHODS END
}
}
@@ -0,0 +1,44 @@
//
// $Id: LocationCodes.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.data {
import com.threerings.presents.data.InvocationCodes;
/**
* Contains codes used by the location invocation services.
*/
public class LocationCodes extends InvocationCodes
{
/** An error code indicating that a place identified by a particular
* place id does not exist. Usually generated by a failed moveTo
* request. */
public static const NO_SUCH_PLACE :String = "m.no_such_place";
/** An error code sent when a user requests to move to a new place but
* they are in the middle of moving somewhere already. */
public static const MOVE_IN_PROGRESS :String = "m.move_in_progress";
/** An error code sent when a user requests to move to a place, but
* they are already in the requested place. */
public static const ALREADY_THERE :String = "m.already_there";
}
}
@@ -0,0 +1,102 @@
//
// $Id: OccupantInfo.java 3774 2005-12-03 03:05:06Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.data {
import com.threerings.util.Integer;
import com.threerings.util.Name;
import com.threerings.presents.dobj.DSetEntry;
import com.threerings.crowd.data.BodyObject;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
/**
* The occupant info object contains all of the information about an
* occupant of a place that should be shared with other occupants of the
* place. These objects are stored in the place object itself and are
* updated when bodies enter and exit a place.
*
* <p> A system that builds upon the Crowd framework can extend this class to
* include extra information about their occupants. They will need to provide a
* derived {@link BodyObject} that creates and configures their occupant info
* in {@link BodyObject#createOccupantInfo}.
*
* <p> Note also that this class implements {@link Cloneable} which means
* that if derived classes add non-primitive attributes, they are
* responsible for adding the code to clone those attributes when a clone
* is requested.
*/
public class OccupantInfo
implements DSetEntry
{
/** Constant value for {@link #status}. */
public static const ACTIVE :int = 0;
/** Constant value for {@link #status}. */
public static const IDLE :int = 1;
/** Constant value for {@link #status}. */
public static const DISCONNECTED :int = 2;
/** Maps status codes to human readable strings. */
public static const X_STATUS :Array = { "active", "idle", "discon" };
/** The body object id of this occupant (and our entry key). */
public var bodyOid :Integer;
/** The username of this occupant. */
public var username :Name;
/** The status of this occupant. */
public var status :int = ACTIVE;
/** Access to the body object id as an int. */
public function getBodyOid () :int
{
return bodyOid.value;
}
// documentation inherited from interface DSetEntry
public function getKey () :Object
{
return bodyOid;
}
// documentation inherited from superinterface Streamable
public function writeObject (out :ObjectOutputStream) :void
{
out.writeObject(bodyOid);
out.writeObject(username);
out.writeByte(status);
}
// documentation inherited from superinterface Streamable
public function readObject (ins :ObjectInputStream) :void
{
bodyOid = (ins.readObject() as Integer);
username = (ins.readObject() as Name);
status = ins.readByte();
}
}
}
@@ -0,0 +1,64 @@
//
// $Id: PlaceConfig.java 3726 2005-10-11 19:17:43Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.data {
import com.threerings.io.Streamable;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.crowd.client.PlaceController;
/**
* The place config class encapsulates the configuration information for a
* particular type of place. The hierarchy of place config objects mimics
* the hierarchy of place managers and controllers. Both the place manager
* and place controller are provided with the place config object when the
* place is created.
*
* <p> The place config object is also the mechanism used to instantiate
* the appropriate place manager and controller. Every place must have an
* associated place config derived class that overrides {@link
* #getControllerClass} and {@link #getManagerClassName}, returning the
* appropriate place controller and manager class for that place.
*/
public interface PlaceConfig extends Streamable
{
/**
* Returns the class that should be used to create a controller for
* this place. The controller class must derive from {@link
* PlaceController}.
*/
public function getControllerClass () :Class;
/**
* Returns the name of the class that should be used to create a
* manager for this place. The manager class must derive from {@link
* com.threerings.crowd.server.PlaceManager}. <em>Note:</em> this
* method differs from {@link #getControllerClass} because we want to
* avoid compile time linkage of the place config object (which is
* used on the client) to server code. This allows a code optimizer
* (DashO Pro, for example) to remove the server code from the client,
* knowing that it is never used.
*/
// public function getManagerClassName () :String;
}
}
@@ -0,0 +1,179 @@
//
// $Id: PlaceObject.java 3406 2005-03-15 02:12:03Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// 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.crowd.data {
import com.threerings.util.Iterator;
import com.threerings.util.Name;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet;
import com.threerings.presents.dobj.DSetEntry;
import com.threerings.presents.dobj.OidList;
import com.threerings.crowd.Log;
import com.threerings.crowd.chat.data.SpeakMarshaller;
import com.threerings.crowd.chat.data.SpeakObject;
/**
* A distributed object that contains information on a place that is
* occupied by bodies. This place might be a chat room, a game room, an
* island in a massively multiplayer piratical universe, anything that has
* occupants that might want to chat with one another.
*/
public class PlaceObject extends DObject
{
// AUTO-GENERATED: FIELDS START
/** The field name of the <code>occupants</code> field. */
public static const OCCUPANTS :String = "occupants";
/** The field name of the <code>occupantInfo</code> field. */
public static const OCCUPANT_INFO :String = "occupantInfo";
/** The field name of the <code>speakService</code> field. */
public static const SPEAK_SERVICE :String = "speakService";
// AUTO-GENERATED: FIELDS END
/**
* Tracks the oid of the body objects of all of the occupants of this
* place.
*/
public var occupants :OidList = new OidList();
/**
* Contains an info record (of type {@link OccupantInfo}) for each
* occupant that contains information about that occupant that needs
* to be known by everyone in the place. <em>Note:</em> Don't obtain
* occupant info records directly from this set when on the server,
* use <code>PlaceManager.getOccupantInfo()</code> instead (along with
* <code>PlaceManager.updateOccupantInfo()</code>) because it does
* some special processing to ensure that readers and updaters don't
* step on one another even if they make rapid fire changes to a
* user's occupant info.
*/
public var occupantInfo :DSet = new DSet();
/** Used to generate speak requests on this place object. */
public var speakService :SpeakMarshaller;
/**
* Looks up a user's occupant info by name.
*
* @return the occupant info record for the named user or null if no
* user in the room has that username.
*/
public function getOccupantInfo (username :Name) :OccupantInfo
{
var itr :Iterator = occupantInfo.iterator();
while (itr.hasNext()) {
var info :OccupantInfo = (itr.next() as OccupantInfo);
if (info.username.equals(username)) {
return info;
}
}
return null;
}
// AUTO-GENERATED: METHODS START
/**
* Requests that <code>oid</code> be added to the <code>occupants</code>
* oid list. The list will not change until the event is actually
* propagated through the system.
*/
public function addToOccupants (oid :int) :void
{
requestOidAdd(OCCUPANTS, oid);
}
/**
* Requests that <code>oid</code> be removed from the
* <code>occupants</code> oid list. The list will not change until the
* event is actually propagated through the system.
*/
public function removeFromOccupants (oid :int) :void
{
requestOidRemove(OCCUPANTS, oid);
}
/**
* Requests that the specified entry be added to the
* <code>occupantInfo</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public function addToOccupantInfo (elem :DSetEntry) :void
{
requestEntryAdd(OCCUPANT_INFO, occupantInfo, elem);
}
/**
* Requests that the entry matching the supplied key be removed from
* the <code>occupantInfo</code> set. The set will not change until the
* event is actually propagated through the system.
*/
public function removeFromOccupantInfo (key :Object) :void
{
requestEntryRemove(OCCUPANT_INFO, occupantInfo, key);
}
/**
* Requests that the specified entry be updated in the
* <code>occupantInfo</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public function updateOccupantInfo (elem :DSetEntry) :void
{
requestEntryUpdate(OCCUPANT_INFO, occupantInfo, elem);
}
/**
* Requests that the <code>occupantInfo</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.
*/
public function setOccupantInfo (value :DSet) :void
{
requestAttributeChange(OCCUPANT_INFO, value, this.occupantInfo);
this.occupantInfo = (value == null) ? null : (DSet)value.clone();
}
/**
* Requests that the <code>speakService</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.
*/
public function setSpeakService (value :SpeakMarshaller) :void
{
var ovalue :SpeakMarshaller = this.speakService;
requestAttributeChange(
SPEAK_SERVICE, value, ovalue);
this.speakService = value;
}
// AUTO-GENERATED: METHODS END
}
}
+9 -3
View File
@@ -7,10 +7,13 @@ import flash.util.ByteArray;
import com.threerings.util.SimpleMap;
import com.threerings.io.streamers.ArrayStreamer;
import com.threerings.io.streamers.ByteyStreamer;
import com.threerings.io.streamers.ByteArrayStreamer;
import com.threerings.io.streamers.IntStreamer;
import com.threerings.io.streamers.FloatStreamer;
import com.threerings.io.streamers.IntegerStreamer;
import com.threerings.io.streamers.NumberStreamer;
import com.threerings.io.streamers.ObjectArrayStreamer;
import com.threerings.io.streamers.ShortStreamer;
import com.threerings.io.streamers.StringStreamer;
public class Streamer
@@ -125,10 +128,13 @@ public class Streamer
if (_streamers == null) {
_streamers = [
new StringStreamer(),
new IntStreamer(),
new NumberStreamer(),
new ObjectArrayStreamer(),
new ByteArrayStreamer()
new ByteArrayStreamer(),
new ByteStreamer(),
new ShortStreamer(),
new IntegerStreamer(),
new FloatStreamer()
];
}
}
@@ -1,35 +1,37 @@
package com.threerings.io.streamers {
import com.threerings.util.Byte;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamer;
/**
* A Streamer for int objects.
* A Streamer for Byte objects.
*/
public class IntStreamer extends Streamer
public class ByteStreamer extends Streamer
{
public function IntStreamer ()
public function ByteStreamer ()
{
super(int, "java.lang.Integer");
super(Byte, "java.lang.Byte");
}
public override function createObject (ins :ObjectInputStream) :Object
{
return ins.readInt();
return new Byte(ins.readByte());
}
public override function writeObject (obj :Object, out :ObjectOutputStream)
:void
{
var i :int = (obj as int);
out.writeInt(i);
var byte :Byte = (obj as Byte);
out.writeByte(byte.value);
}
public override function readObject (obj :Object, ins :ObjectInputStream)
:void
{
// nothing here, the int is fully read in createObject()
// unneeded, done in createObject
}
}
}
@@ -0,0 +1,37 @@
package com.threerings.io.streamers {
import com.threerings.util.Float;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamer;
/**
* A Streamer for Float objects.
*/
public class FloatStreamer extends Streamer
{
public function FloatStreamer ()
{
super(Float, "java.lang.Float");
}
public override function createObject (ins :ObjectInputStream) :Object
{
return new Float(ins.readFloat());
}
public override function writeObject (obj :Object, out :ObjectOutputStream)
:void
{
var float :Float = (obj as Float);
out.writeFloat(float.value);
}
public override function readObject (obj :Object, ins :ObjectInputStream)
:void
{
// unneeded, done in createObject
}
}
}
@@ -0,0 +1,37 @@
package com.threerings.io.streamers {
import com.threerings.util.Integer;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamer;
/**
* A Streamer for Integer objects.
*/
public class IntegerStreamer extends Streamer
{
public function IntegerStreamer ()
{
super(Integer, "java.lang.Integer");
}
public override function createObject (ins :ObjectInputStream) :Object
{
return new Integer(ins.readInt());
}
public override function writeObject (obj :Object, out :ObjectOutputStream)
:void
{
var inty :Integer = (obj as Integer);
out.writeInt(inty.value);
}
public override function readObject (obj :Object, ins :ObjectInputStream)
:void
{
// unneeded, done in createObject
}
}
}
@@ -0,0 +1,37 @@
package com.threerings.io.streamers {
import com.threerings.util.Short;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamer;
/**
* A Streamer for Short objects.
*/
public class ShortStreamer extends Streamer
{
public function ShortStreamer ()
{
super(Short, "java.lang.Short");
}
public override function createObject (ins :ObjectInputStream) :Object
{
return new Short(ins.readShort());
}
public override function writeObject (obj :Object, out :ObjectOutputStream)
:void
{
var short :Short = (obj as Short);
out.writeShort(short.value);
}
public override function readObject (obj :Object, ins :ObjectInputStream)
:void
{
// unneeded, done in createObject
}
}
}
@@ -5,6 +5,8 @@ import flash.util.describeType;
import com.threerings.util.Name;
import com.threerings.presents.Log;
import com.threerings.presents.data.TimeBaseMarshaller;
import com.threerings.presents.dobj.DSet;
import com.threerings.presents.dobj.QSet;
import com.threerings.presents.net.UsernamePasswordCreds;
public class TestClient extends Client
@@ -16,11 +18,11 @@ public class TestClient extends Client
logon();
var g1 :String = null;
var g2 :String = String(g1);
Log.debug("foo: " + (g1 === g2) + ", *" + g2 + "*, " + g2.length);
var g2 :String = (com.threerings.util.Util.cast(g1, String) as String);
Log.debug("foo: " + (g1 === g2) + ", *" + g2 + "*, "); // + g2.length);
var duckie :Duck = new Goose();
duckie.screw();
var ob :Object = "this is a string";
Log.debug("part of an object: " + ob.substring(1));
var arr :Array = new Array();
arr[0] = "Florp";
+4 -42
View File
@@ -2,11 +2,11 @@ package com.threerings.presents.dobj {
import flash.util.StringBuilder;
import mx.collections.IViewCursor;
import mx.utils.ObjectUtil;
import com.threerings.util.Equalable;
import com.threerings.util.Iterator;
import com.threerings.util.ArrayIterator;
import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream;
@@ -86,47 +86,9 @@ public class DSet
* made to the set). It should not be kept around as it can quickly
* become out of date.
*/
public function getCursor () :IViewCursor
public function iterator () :Iterator
{
return null; // jesus, what a pain in the ass to make our
// own IViewCursor since we can't have inner classes
// // the crazy sanity checks
// if (_size < 0 ||_size > _entries.length ||
// (_size > 0 && _entries[_size-1] == null)) {
// Log.warning("DSet in a bad way [size=" + _size +
// ", entries=" + StringUtil.toString(_entries) + "].");
// Thread.dumpStack();
// }
//
// return new Iterator() {
// public boolean hasNext () {
// checkComodification();
// return (_index < _size);
// }
// public Object next () {
// checkComodification();
// return _entries[_index++];
// }
// public void remove () {
// throw new UnsupportedOperationException();
// }
// protected void checkComodification () {
// if (_modCount != _expectedModCount) {
// throw new ConcurrentModificationException();
// }
// if (_ssize != _size) {
// Log.warning("Size changed during iteration " +
// "[ssize=" + _ssize + ", nsize=" + _size +
// ", entsries=" + StringUtil.toString(_entries) +
// "].");
// Thread.dumpStack();
// }
// }
// protected int _index = 0;
// protected int _ssize = _size;
// protected int _expectedModCount = _modCount;
// };
return new ArrayIterator(_entries);
}
/**
@@ -0,0 +1,37 @@
package com.threerings.util {
/**
* Provides a generic iterator for an Array.
* No co-modification checking is done.
*/
public class ArrayIterator
implements Iterator
{
/**
* Create an ArrayIterator.
*/
public function ArrayIterator (arr :Array)
{
_arr = arr;
_index = 0;
}
// documentation inherited from interface Iterator
public function hasNext () :Boolean
{
return (_index < _arr.length);
}
// documentation inherited from interface Iterator
public function next () :Object
{
return _arr[_index++];
}
/** The array we're iterating over. */
protected var _arr :Array;
/** The current index. */
protected var _index :int;
}
}
+22
View File
@@ -0,0 +1,22 @@
package com.threerings.util {
/**
* Equivalent to java.lang.Byte.
*/
public class Byte
implements Equalable
{
public var value :int;
public function Byte (value :int)
{
this.value = value;
}
// documentation inherited from interface Equalable
public function equals (other :Object) :Boolean
{
return (other is Byte) && (value === (other as Byte).value);
}
}
}
+22
View File
@@ -0,0 +1,22 @@
package com.threerings.util {
/**
* Equivalent to java.lang.Float.
*/
public class Float
implements Equalable
{
public var value :Number;
public function Float (value :Number)
{
this.value = value;
}
// documentation inherited from interface Equalable
public function equals (other :Object) :Boolean
{
return (other is Float) && (value === (other as Float).value);
}
}
}
+22
View File
@@ -0,0 +1,22 @@
package com.threerings.util {
/**
* Equivalent to java.lang.Integer.
*/
public class Integer
implements Equalable
{
public var value :int;
public function Integer (value :int)
{
this.value = value;
}
// documentation inherited from interface Equalable
public function equals (other :Object) :Boolean
{
return (other is Integer) && (value === (other as Integer).value);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
package com.threerings.util {
/**
* Java has Iterator, ActionScript has IViewCursor.
* The problem is, IViewCursor defines 14 methods and 5 read-only properties.
* That is a serious PITA to write for every collection that might desire
* iteration. This provides a simpler alternative.
*/
public interface Iterator
{
/**
* Is there another element available?
*/
function hasNext () :Boolean;
/**
* Returns the next element.
*/
function next () :Object;
// TODO: remove() ?
}
}
+22
View File
@@ -0,0 +1,22 @@
package com.threerings.util {
/**
* Equivalent to java.lang.Short.
*/
public class Short
implements Equalable
{
public var value :int;
public function Short (value :int)
{
this.value = value;
}
// documentation inherited from interface Equalable
public function equals (other :Object) :Boolean
{
return (other is Short) && (value === (other as Short).value);
}
}
}
+9
View File
@@ -15,6 +15,15 @@ public class Util
return buf.toString();
}
public static function cast (obj :Object, clazz :Class) :Object
{
if (obj == null || obj is clazz) {
return obj;
} else {
throw new Error("wah");
}
}
private static const HEX :Array = new Array("0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
}