| back to uSimpleChat tutorial home |
unity 2 uSimpleChat tutorial, actionscript 1.0 version
PART 4The fourth version of uSimpleChat will show how to:
- create a new namespace from ActionScript
- display a list of clients in a room
- use a client attribute to store each client's username
- display Unity connection status to the end user
- reconnect to Unity when the connection is lost
- add logging to our application
In the first three versions of uSimpleChat, we created our
chatroom in theudefaultnamespace. In this version, we'll give thechatroom its very own namespace. By providing our application with its own namespace, we ensure that no other application will interfere with our chat room. This allows multiple projects to be developed and deployed on the same Unity server. It also provides a way to group rooms logically, so that they can be manipulated en masse. For example, if a chat application keeps all its sports-related rooms in a namespace called "moockchat.sports", then an administration tool can easily be written to send a message to all rooms related to sports ("ALERT: Wayne Gretzky's chatting in the Hockey room right now!!").The addition of a custom namespace changes our application logic somewhat. In uSimpleChat version 4, the client-side application logic is:
- Connect to server.
- When connection succeeds, create namespace
usimplechat.- When client-side NameSpace object is created for
simplechat:
- Register to listen to its events.
- Create room
simplechat.chat.- When
simplechatNameSpace object reports newchatroom:
- Register to listen to
chatroom's events.- Join
chatroom.- When
chatroom reports that it was joined, display chat interface.In addition to the above revised logic, this version adds new features such as a client list and user names. Those features do not affect the basic logic involved in connecting to the server, creating a room, and joining it. In fact, even very complex Unity applications generally do not deviate much from the basic architecture of uSimpleChat version 4. This version of our chat application makes an excellent boilerplate for many kinds of multiuser apps.
Creating the simplechat Namespace
Unlike the previous two versions of uSimpleChat, version 4's USimpleChat.onClientReady() method does not tell Unity to create thechatroom. Instead, it only tells Unity to create thesimplechatnamespace, and then waits to be notified when the corresponding client-side NameSpace object is created by the RoomManager. We use the RoomManager.createNamespaceOnServer() method to create the namespace. Here's the code for USimpleChat.onClientReady(), version 4:org.moock.unity.simplechat.v4.USimpleChat.prototype.onClientReady = function () { // Make a new namespace, "simplechat", and start observing it. this.getRoomManager().createNamespaceOnServer("simplechat", true); // Tell the user what's happening. this.getTargetMC().status_txt.text = "Connected to Unity. Joining simplechat room..."; }In the call to createNamespaceOnServer(), the second argument (
true) specifies that the client wants to "observe" the namespace. When a namespace is observed by a client, Unity automatically notifies that client of changes to the namespace (i.e., additions or removals of rooms or subnamespaces). For example, later, when we're informed that thesimplechatNameSpace has been created, we'll add thechatroom to it. In response, Unity will notify us that the room was added. The RoomManager will automatically create the corresponding client-side URoom instance, and thesimplechatNameSpace instance will invoke onAddRoom() on all its listeners (in our case, a SimpleChatNamespaceView instance).Notice that we don't bother implementing the RoomManagerListener.onCreateNamespaceResults() method. That method tells us whether the namespace creation was successful or not. However, UClient already implements onCreateNamespaceResults(), and outputs the results to the client log. (We'll learn how to enable the client log later in this tutorial.) For our purposes, logging is all we need. If there's a problem creating the namespace, we can check the log and attempt to debug. Of course, if the namespace could not be created, it would also be nice to display a generic error message to the user, but that's left as an exercise for the reader. Hint: implement USimpleChat.onCreateNamespaceResults(), and move the main timeline to an error frame in the event of a failed namespace creation attempt.
Creating the simplechat.chat Room
When our client-sidesimplechatNameSpace instance is created, USimpleChat.onAddNamespace() executes. From that method, we'll register an event listener for the NameSpace, just like we did version 3. This time, Our listener will be an instance of the SimpleChatNamespaceView class, which bears much in common with version 3's UdefaultNamespaceView class. In addition to registering a NameSpace listener, the version 4 USimpleChat.onAddNamespace() will create ourchatroom in the new namespace.Here's the code for USimpleChat.onAddNamespace():
Notice that the arguments to our createRoomOnServer() method have changed since version 3. This time, the third and fourth arguments areorg.moock.unity.simplechat.v4.USimpleChat.prototype.onAddNamespace = function (e) { // Invoke superclass's version of this method to preserve logging. super.onAddNamespace(e); // Retrieve a reference to the new NameSpace object. var ns = this.getRoomManager().getNamespace(e.getNamespaceID()); if (e.getNamespaceID() == "simplechat") { // Register the "simplechat" NameSpace listener. Nothing new here. ns.addNamespaceListener( new org.moock.unity.simplechat.v4.SimpleChatNamespaceView(ns)); // This is new to version 4: create a room in the new namespace. this.getRoomManager().createRoomOnServer("chat", "simplechat", true, true, 50, null, null); } else { this.log.warn("Unexpected namespace added to chat application."); } }trueinstead offalse, indicating that:
- the room should be removed from the server if it becomes empty (no harm done: it will be recreated by the next client that joins)
- the server should send the room's client list when we join the room, and should notify us when a client enters or leaves the room
We'll respond to clients joining and leaving the room from our ChatRoomView class, which will implement the URoomListener.onAddClient() and URoomListener.onRemoveClient() methods.
Joining the simplechat.chat Room
If the server successfully creates thesimplechat.chatroom, it will notify all clients observing thesimplechatnamespace that the room was added. We respond to that notification from the SimpleChatNamespaceView.onJoin() method (exactly like we did in version 3 with UdefaultNamespaceView.onJoin()). The onJoin() method has three tasks: 1) create a new ChatRoomView instance, 2) registers the ChatRoomView instance to receive events from thechatroom, 3) join thechatroom.Here's the code for SimpleChatNamespaceView:
// CLASS SimpleChatNamespaceView EXTENDS NamespaceView org.moock.unity.simplechat.v4.SimpleChatNamespaceView = function (namespace) { super(namespace); } // EXTEND SUPERCLASS org.moock.unity.simplechat.v4.SimpleChatNamespaceView.prototype = new org.moock.unity.NamespaceView(); // METHODS /** * NamespaceListener event handler */ org.moock.unity.simplechat.v4.SimpleChatNamespaceView.prototype.onAddRoom = function (e) { // When a new room is added to this namespace... // If it's the chat room... if (e.getRoomID() == "chat") { // First get a reference to the room object. var room = this.ns.getRoom(e.getRoomID()); // Then create a view for the room and register it to // receive the room's events. room.addURoomListener( new org.moock.unity.simplechat.v4.ChatRoomView(room)); // Finally, join the room. room.join(); } }Displaying the Chat Interface
We respond to the joining of thesimplechat.chatroom via ChatRoomView.onJoin(). That method has two responsibilities: 1) move the main timeline's playhead to the frame labeled "simpleChatInterface", and 2) create the ListBox component instance that will display the user list for the room. Note that we're forced to create the ListBox programmatically rather than placing it on the Stage manually (with the rest of the chat interface). If we were to place the component on the Stage manually, its methods wouldn't be initialized until a frame had passed, which would prevent us from adding user names to it for the duration of one frame.Here's the code for onJoin():
org.moock.unity.simplechat.v4.ChatRoomView.prototype.onJoin = function (e) { // If the room join attempt was successful... if (e.getStatus() == "ROOM_JOINED") { // Display the interface frame. this.client.getTargetMC().gotoAndStop("simpleChatInterface"); // Attach the users listbox. Have to do this at runtime so the listbox // methods are available immediately. Otherwise, we'd have to wait a // frame for the listbox to initialize itself. this.users_lb = this.client.getTargetMC().attachMovie("FListBoxSymbol", "users_lb", this.client.getNewTargetDepth()); this.users_lb._x = 409; this.users_lb._y = 163; this.users_lb.setSize(117, 156); // Tell the user the application is ready to use. this.client.getTargetMC().status_txt.text = "Chat now active. Send your message."; } else { this.client.getTargetMC().status_txt.text = "Could not join chat room. Status: " + e.getStatus(); } }Displaying the User List
Whenever a client joins thechatroom, ChatRoomView.onAddClient() executes. Whenever a client leaves thechatroom, ChatRoomView.onRemoveClient() executes. Those two methods let us populate the user list for the room. Immediately after we join a room, onAddClient() executes once for each client in the room at the time we joined it.Like all other event methods in the uClientCore API, the onAddClient() and onRemoveClient() methods are passed an event object,
e, that provides information about the event. The event object passed to onAddClient() and onRemoveClient() contains the id of the client that was added or removed. In the simplest case, we could add that ID to, and remove it from our ListBox as follows:// Add. this.users_lb.addItem(e.getClientID()); // Remove. var clientID:String = e.getClientID(); for (var i:Number = this.users_lb.getLength(); --i >= 0;) { if (this.users_lb.getItemAt(i).label == clientID) { this.users_lb.removeItemAt(i); return; } }However, the above code would result in a user list containing only numeric user ids. Not very much fun. Our application allows users to set their name as a "shared client attribute". Client attributes for a particular client are retrieved via the RemoteClient.getAttribute() method. For example, the following code retrieves a global shared client attribute named "username" for a RemoteClient instance (the
nullargument indicates that the scope of the client attribute is global):theRemoteClient.getAttribute(null, "username");RemoteClient instances themselves are retrieved via the RemoteClientManager.getClient() method, which takes the client ID for the RemoteClient to retrieve as its only argument. The RemoteClientManager for an application is accessed via the UClient.getRemoteClientManager() method. Hence, to retrieve a remote client with ID 45, we use:
theClient.getRemoteClientManager().getClient(45);Here, then, is the ChatRoomView.onAddClient() code that retrieves the
usernameattribute for a client that has been added to the room:var remoteuser = this.client.getRemoteClientManager().getClient(e.getClientID()); var username = remoteuser.getAttribute(null, "username");Once the
usernamehas been retrieved, it is displayed in theusers_lbListBox, via theaddItem()method. Thelabelfor the ListBox item is theusername, and thedatafor the ListBox item is the client id. This allows us to operate on items in the list by client id, which is guaranteed to be unique.Here's the complete code for the onAddClient() method:
org.moock.unity.simplechat.v4.ChatRoomView.prototype.onAddClient = function (e) { // Retrieve the username for the client that just joined. var remoteuser = this.client.getRemoteClientManager().getClient(e.getClientID()); var username = remoteuser.getAttribute(null, "username"); // Use the client id as a user name if the user hasn't set a name. if (username == undefined) { username = "User" + e.getClientID(); } // Add the new user to the list box. this.users_lb.addItem(username, e.getClientID()); this.users_lb.sortItemsBy("label", "asc"); }When a client leaves the room, we must remove it from the ListBox. That's a little bit tricker. The ListBox component does not provide a means of removing an item according to a specific data value. Instead, we have to manually find the data value we're looking for, determine its index in the list, and remove it. The onRemoveClient() method, shown next, does just that: it removes an item for a particular client id from the
users_lbListBox.org.moock.unity.simplechat.v4.ChatRoomView.prototype.onRemoveClient = function (e) { var clientID:String = e.getClientID(); for (var i:Number = this.users_lb.getLength(); --i >= 0;) { if (this.users_lb.getItemAt(i).data == clientID) { this.users_lb.removeItemAt(i); return; } } }Setting a User Name
Our application allows each client to set a shared client attribute,username, that stores the client's chosen user name. When the attribute is defined or changed, all clients in room at the time will be notified of the new value. We'll define theusernameattribute as a global attribute, which means that if the client is in multiple rooms, all clients in all those rooms will be notified when the attribute changes. A client attribute can also be scoped to a particular room, so that only clients in that room are notified when it changes. For details, see UClient.setClientAttribute().To allow end-users to set a user name, we'll add a new text field (
nameInput_txt) and a new button (setname_pb) to our uSimpleChat.fla file. We'll use the method UClient.setClientAttribute() to set theusernameattribute, but we'll wrap that method in a USimpleChat method called setName(). To wiresetname_pbbutton clicks to the USimpleChat.setName() method, we'll add the following code to our .fla, at the frame labeled "simpleChatInterface":Here's the setName() method:setname_pb.setClickHandler("setName", sc);The arguments to setClientAttribute() have the following meaning:org.moock.unity.simplechat.v4.USimpleChat.prototype.setName = function () { if (this.getTargetMC().nameInput_txt.text.length > 0) { this.setClientAttribute("username", this.getTargetMC().nameInput_txt.text, null, true, false, false); this.getTargetMC().nameInput_txt.text = ""; } }
- "username", the name of the attribute
- this.getTargetMC().nameInput_txt.text, the value of the attribute
- null, the scope of the attribute (global)
- true, the attribute should be shared with other clients in the room
- false, the attribute is not persistent (saved on the server when the client disconnects)
- false, the supplied attribute value should not be appended to the existing attribute value on the server
When the
usernameattribute is set, ChatRoomView.onUpdateClientAttribute() automatically fires on all clients in thesimplechat.chatroom at the time. That method is responsible for updating the user name displayed in theusers_lblist box.Here's the code for ChatRoomView.onUpdateClientAttribute(). Notice that it subcontracts the work of updating the
users_lblist box to another method, renameUser() (shown following).org.moock.unity.simplechat.v4.ChatRoomView.prototype.onUpdateClientAttribute = function (e) { // URoomEvent.getChangedAttr() returns an object whose properties // specify the changed attribute's name (attrName) and value (attrVal). var attrName = e.getChangedAttr().attrName; var attrVal = e.getChangedAttr().attrVal; // If the username attribute was changed, display it on screen. if (attrName == "username") { this.renameUser(e.getClientID(), attrVal); } } org.moock.unity.simplechat.v4.ChatRoomView.prototype.renameUser = function (clientID, newName) { for (var i = this.users_lb.getLength(); --i >= 0;) { if (this.users_lb.getItemAt(i).data == clientID) { this.users_lb.replaceItemAt(i, newName, clientID); this.users_lb.sortItemsBy("label", "asc"); } } }With the ability to set a user name in place, the uSimpleChat version 4 application is functionally complete. However, as a final bit of polish for our application, we'll add code to handle a connection failure and to enable the application log.
Handling Connection Failure
When a connection failure occurs, the application's SocketManager automatically invokes one of three methods on USimpleChat:
- onConnectFailure(), when attempt to connect cannot be completed
- onServerKillConnect(), when an existing connection is terminated by the server (either the server went down, or the client was kicked off)
- onClientKillConnect(), when an existing connection is terminated by the client (via UClient.disconnect())
Here's the implementation for those methods in USimpleChat, version 4.
org.moock.unity.simplechat.v4.USimpleChat.prototype.onConnectFailure = function (e) { // Invoke superclass's version of this method to preserve logging. super.onConnectFailure(e); this.getTargetMC().status_txt.text = "Connection to Unity failed."; this.getTargetMC().gotoAndStop("disabled"); } org.moock.unity.simplechat.v4.USimpleChat.prototype.onServerKillConnect = function (e) { // Invoke superclass's version of this method to preserve logging. super.onServerKillConnect(e); this.getTargetMC().status_txt.text = "Unity has closed the connection."; this.getTargetMC().gotoAndStop("disabled"); } org.moock.unity.simplechat.v4.USimpleChat.prototype.onClientKillConnect = function (e) { // Invoke superclass's version of this method to preserve logging. super.onClientKillConnect(e); this.getTargetMC().status_txt.text = "Connection to Unity closed."; this.getTargetMC().gotoAndStop("disabled"); }In each of the three disconnection scenarios, we'll display a frame labeled "disabled", which contains a button the user can use to reconnect.
Here's the disabled frame in uSimpleChat.fla:
To make the reconnect_pb button attempt to reconnect to Unity when clicked, we add the following code to the "scripts" layer of the "disabled" frame:
reconnect_pb.setClickHandler("connect", sc);Cleaning Up After the Party
When a connection is lost, all NameSpace and URoom instances are automatically removed from the client. Immediately before each URoom is deleted, it fires onLeave() on its listeners. From that method, each room view object is expected to clean up any resources it may have created. In the case of our ChatRoomView class, we must remove theusers_lbwe created when thechatroom was joined. Here's the ChatRoomView.onLeave() method, which does just that.org.moock.unity.simplechat.v4.ChatRoomView.prototype.onLeave = function () { this.users_lb.removeMovieClip(); }We didn't create any resources in the SimpleChatNamespaceView class, so we don't need to do anything special when the
simplechatnamespace is deleted. If we had needed to clean up after that namespace, we'd have implemented the SimpleChatNamespaceView.onDie() method.Enabling the Client Log
As a final feature in our application, we'll add an application log, which will display lots of information about what's happening internally in the uClientCore classes. The log is enabled in the call to the USimpleChat constructor (on the frame labeled "main"). The last argument of the constructor call is set tofalse, meaning "don't disable the log", as follows:var sc = new org.moock.unity.simplechat.v4.USimpleChat(this, null, null, "uSimpleChatConfig.xml", false);Within the constructor function itself, the log display is customized with the following code:
this.logPanel.setPosition(17, 376); this.logPanel.setSize(511, 250); this.logPanel.minimize();The above code controls the
logPanelmovie clip instance, which is dynamically created automatically by the UClient class when the log is enabled.Mission Complete
Over four stages, we've created a solid, reasonably sophisticated multiuser application. The listings for the final application classes are provided below. This is the end of the tutorial but it should only be the beginning of your own exploration. If you create something interesting with Unity, let us know at unity@moock.org! We may include your project in the Unity Application Showcase.
Code Listing for USimpleChat Class, Version 4
// PACKAGE org.moock.unity.simplechat = new Object(); org.moock.unity.simplechat.v4 = new Object(); // CLASS USimpleChat EXTENDS UClient org.moock.unity.simplechat.v4.USimpleChat = function (target, host, port, configURL, disableLog) { // Invoke UClient constructor. super(target, host, port, configURL, disableLog); // Adjust the display of the log panel. this.logPanel.setPosition(17, 376); this.logPanel.setSize(511, 250); this.logPanel.minimize(); // Listen for key presses so we can submit messages // when the user presses ENTER. Key.addListener(this); // Tell the user we're connecting. this.getTargetMC().status_txt.text = "Connecting to Unity..."; } // EXTEND SUPERCLASS org.moock.unity.simplechat.v4.USimpleChat.prototype = new org.moock.unity.UClient(); // METHODS /** * UClient event handler */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onClientReady = function () { // Make a new namespace, "simplechat", and start observing it. this.getRoomManager().createNamespaceOnServer("simplechat", true); // Tell the user what's happening. this.getTargetMC().status_txt.text = "Connected to Unity. Joining simplechat room..."; } /** * SocketListener event handler */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onConnectFailure = function (e) { // Invoke superclass's version of this method to preserve logging. super.onConnectFailure(e); this.getTargetMC().status_txt.text = "Connection to Unity failed."; this.getTargetMC().gotoAndStop("disabled"); } /** * SocketListener event handler */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onServerKillConnect = function (e) { // Invoke superclass's version of this method to preserve logging. super.onServerKillConnect(e); this.getTargetMC().status_txt.text = "Unity has closed the connection."; this.getTargetMC().gotoAndStop("disabled"); } /** * SocketListener event handler */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onClientKillConnect = function (e) { // Invoke superclass's version of this method to preserve logging. super.onClientKillConnect(e); this.getTargetMC().status_txt.text = "Connection to Unity closed."; this.getTargetMC().gotoAndStop("disabled"); } /** * RoomManager event handler */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onAddNamespace = function (e) { // Invoke superclass's version of this method to preserve logging. super.onAddNamespace(e); // Retrieve a reference to the new NameSpace object. var ns = this.getRoomManager().getNamespace(e.getNamespaceID()); if (e.getNamespaceID() == "simplechat") { ns.addNamespaceListener( new org.moock.unity.simplechat.v4.SimpleChatNamespaceView(ns)); this.getRoomManager().createRoomOnServer("chat", "simplechat", true, true, 50, null, null); } else { this.log.warn("Unexpected namespace added to chat application."); } } /** * Takes user input from outgoing_txt and sends it to all clients * in the room "udefault.chat". */ org.moock.unity.simplechat.v4.USimpleChat.prototype.sendMessage = function () { // Only send the message if there's text // in the outgoing_txt text field. if (this.getTargetMC().outgoing_txt.text.length > 0) { // The message typed by the user. var msg = this.getTargetMC().outgoing_txt.text; // The message we'll send to the server. var safeMsg = '<![CDATA[' + msg + ']]>'; // Send the message to the server. this.invokeOnRoom("displayMessage", "simplechat.chat", true, safeMsg); // Clear the user input text field. this.getTargetMC().outgoing_txt.text = ""; } } /** * Displays text sent by a client. */ org.moock.unity.simplechat.v4.USimpleChat.prototype.displayMessage = function (clientID, msg) { // Retrieve the username for the client that sent the message. var remoteuser = this.getRemoteClientManager().getClient(clientID); var username = remoteuser.getAttribute(null, "username"); // Use the client id as a user name if the user hasn't set a name. if (username == undefined) { username = "User" + clientID; } // Display the message on screen. this.getTargetMC().incoming_txt.text += username + ": " + msg + "\n"; // Scroll the incoming_txt text field to the bottom. this.getTargetMC().incoming_txt.scroll = this.getTargetMC().incoming_txt.maxscroll; } /** * Sets the username attribute for this client. */ org.moock.unity.simplechat.v4.USimpleChat.prototype.setName = function () { if (this.getTargetMC().nameInput_txt.text.length > 0) { this.setClientAttribute("username", this.getTargetMC().nameInput_txt.text, null, true, false, false); this.getTargetMC().nameInput_txt.text = ""; } } /** * Key event handler. * Checks for ENTER key. Sends a message if the outgoing text field is focused. */ org.moock.unity.simplechat.v4.USimpleChat.prototype.onKeyDown = function () { if (Key.getCode() == Key.ENTER) { if (Selection.getFocus() == targetPath(this.getTargetMC().outgoing_txt)) { this.sendMessage(); } else if (Selection.getFocus() == targetPath(this.getTargetMC().nameInput_txt)) { this.setName(); } } }Code Listing for SimpleChatNamespaceView Class, Version 4
// CLASS SimpleChatNamespaceView EXTENDS NamespaceView org.moock.unity.simplechat.v4.SimpleChatNamespaceView = function (namespace) { super(namespace); } // EXTEND SUPERCLASS org.moock.unity.simplechat.v4.SimpleChatNamespaceView.prototype = new org.moock.unity.NamespaceView(); // METHODS /** * NamespaceListener event handler */ org.moock.unity.simplechat.v4.SimpleChatNamespaceView.prototype.onAddRoom = function (e) { // When a new room is added to this namespace... // If it's the chat room... if (e.getRoomID() == "chat") { // First get a reference to the room object. var room = this.ns.getRoom(e.getRoomID()); // Then create a view for the room and register it to // receive the room's events. room.addURoomListener( new org.moock.unity.simplechat.v4.ChatRoomView(room)); // Finally, join the room. room.join(); } }Code Listing for ChatRoomView Class, Version 4
// CLASS ChatRoomView EXTENDS URoomView org.moock.unity.simplechat.v4.ChatRoomView = function (room) { super(room); } // EXTEND SUPERCLASS org.moock.unity.simplechat.v4.ChatRoomView.prototype = new org.moock.unity.URoomView(); // PROPERTIES org.moock.unity.simplechat.v4.ChatRoomView.prototype.users_lb = null; // METHODS /** * URoomListener event handler */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.onJoin = function (e) { // If the room join attempt was successful... if (e.getStatus() == "ROOM_JOINED") { // Display the interface frame. this.client.getTargetMC().gotoAndStop("simpleChatInterface"); // Attach the users listbox. Have to do this at runtime so the listbox // methods are available immediately. Otherwise, we'd have to wait a // frame for the listbox to initialize itself. this.users_lb = this.client.getTargetMC().attachMovie("FListBoxSymbol", "users_lb", this.client.getNewTargetDepth()); this.users_lb._x = 409; this.users_lb._y = 163; this.users_lb.setSize(117, 156); // Tell the user the application is ready to use. this.client.getTargetMC().status_txt.text = "Chat now active. Send your message."; } else { this.client.getTargetMC().status_txt.text = "Could not join chat room. Status: " + e.getStatus(); } } /** * URoomListener event handler */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.onAddClient = function (e) { // Retrieve the username for the client that just joined. var remoteuser = this.client.getRemoteClientManager().getClient(e.getClientID()); var username = remoteuser.getAttribute(null, "username"); // Use the client id as a user name if the user hasn't set a name. if (username == undefined) { username = "User" + e.getClientID(); } // Add the new user to the list box. this.users_lb.addItem(username, e.getClientID()); this.users_lb.sortItemsBy("label", "asc"); } /** * URoomListener event handler */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.onRemoveClient = function (e) { var clientID:String = e.getClientID(); for (var i:Number = this.users_lb.getLength(); --i >= 0;) { if (this.users_lb.getItemAt(i).data == clientID) { this.users_lb.removeItemAt(i); return; } } } /** * URoomListener event handler */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.onUpdateClientAttribute = function (e) { var attrName = e.getChangedAttr().attrName; var attrVal = e.getChangedAttr().attrVal; // If the username attribute was changed, display it on screen. if (attrName == "username") { this.renameUser(e.getClientID(), attrVal); } } /** * Clean up UI when the client leaves the room or the server * connection is lost. (When the server connection is lost, * all rooms and namespaces are removed, and onLeave() fires * for every removed room.) */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.onLeave = function () { this.users_lb.removeMovieClip(); } /** * Changes a user's name in the user list. */ org.moock.unity.simplechat.v4.ChatRoomView.prototype.renameUser = function (clientID, newName) { for (var i = this.users_lb.getLength(); --i >= 0;) { if (this.users_lb.getItemAt(i).data == clientID) { this.users_lb.replaceItemAt(i, newName, clientID); this.users_lb.sortItemsBy("label", "asc"); } } }
Documentation Version
1.0.3