[SmartFox] Buddy List
[ April 14, 2005 ] by Marco Lapi, a.k.a Lapo
Article 13: learn how to implement a buddy list using the SmartFoxServer Client API; the buddy list allows each client to keep a list of friends and know in realtime if they are online

[ Introduction ]

In this tutorial we will learn how to implement a buddy list using the SmartFoxServer Client API. The buddy list allows each client to keep a list of friends and know in realtime if they are online. Also you can add more interesting features like private messaging between buddies across rooms and a function to join the room where the buddy is currently located.

SmartFoxServer stores buddy lists on the server side, allowing each user to save his list and retrieve next time he gets connected.

[ Requirements ]

Before proceeding with this tutorial it is necessary that you're already familiar with the basic SmartFoxServer concepts explained in the previous articles.

[ Objectives ]

The purpose of this example is to show how the different buddylist-related commands work by implementing it in a simple chat application.
The application allows each user to populate their own list of friend which is automatically updated when on of them logs in or out of the server. Also we've added a button for sending private messages to the buddy and another button for instantly joining the friend in the room where he's currently located. Buddies can also be removed and we will not receive any more notices about his status.

[ The Server Side ]

In order to enable a zone to handle buddy lists you will have to specify the buddList = "nn" attribute of a zone definition in the config.xml file.
Here's an example:

<Zone name="buddyChat" buddyList="20">

In the above line we have enabled the buddy list for the zone called "buddyChat" and we have limited it to 20 buddies for each client.
You can specify any number as a limit, usually values between 20 to 50 are optimal. For each user that uses the buddy list a file with extension ".list" is saved in the buddyLists/ folder inside your SFS main folder.
Now that you have enabled this feature we can check the tools that the SmartFoxServer Client API provide for this functionality.

[ The application ]

With the source file open you can safely skip the "load" and "connect" labels in the main timeline and park the playhead in the "chat" label where the main application code is located.

As you will notice in the very first lines of code we have this boolean variable declared:

var buddyListLoaded:Boolean = false

We keep this flag to know if we have already loaded our buddy list or not. At around line 36 you will find the usual onRoomListUpdate handler:

smartfox.onRoomListUpdate = function(roomList:Array)
        for (var i in roomList)
                var room:Room = roomList[i]
                roomList_lb.addItem(room.getName() + " (" + room.getUserCount() + ")", room.getId())
        roomList_lb.sortItemsBy("label", "ASC")
        // Join the default room

As you have noticed the handler is similar to the one we've used in other applications so we can safely skip to the next event handler: onJoinRoom.

smartfox.onJoinRoom = function(roomObj:Room)
        var roomId:Number 		= roomObj.getId()
        var userList:Object	 	= roomObj.getUserList()
        _global.currentRoom = roomObj
        // Clear text area
        chat_txt.htmlText = ""
        // Clear current list
        for (var i in userList)
                var user:User = userList[i]
                userList_lb.addItem(user.getName(), user.getId())
        // Sort names
        userList_lb.sortItemsBy("label", "ASC")
        chat_txt.htmlText += "<font color='#cc0000'>>> Room [ " + roomObj.getName() 
		+ " ] joined</font>";
        if (!buddyListLoaded)
                buddyListLoaded = true

The last four lines of code check the boolean flag we've set on initialization and load the buddy list from the server: in order to handle the buddy data we need to handle a new event called onBuddyList:

// Handles the loading of the buddyList from server
smartfox.onBuddyList = function(bList:Array)
        for (var i in bList)
                var label:String = bList[i].name 
				+ " [ " + (bList[i].isOnline ? "On" : "Off") + " ]"
				buddyList_lb.addItem(label, bList[i])
        buddyList_lb.sortItemsBy("label", "ASC")

The server returns an Array of objects with three properties:

id the user Id of the buddy
name the buddy name
isOnline the online status. (boolean)

The above code just cycles through the array received by the handler and populate the list box in the "buddy list" panel. It's important to note that the "data" object passed to the each item in the list is the buddy object itself. By storing a reference to each buddy in the list box it will be very simple to retrieve or search for buddy data. The list passed as argument in the event handler is simply a reference to a public SmartFoxClient property called buddyList which holds
the current list of friends.

At any time in your code you can access this data by simply using the smartFox.buddyList property.

[ Adding buddies ]

If you have never initalized your list of friends the server will just return an empty array, so in order to populate our buddy list we should use the addBuddy() method.

The usage is trivial:


You just pass the user name that you want to add to your list. Once you have ent the request the server may respond in two ways: if you don't have any more room in your list it will fire a onBuddyListError event otherwise you will receive an onBuddyList event.

In the first case you can handle the error by showing the server message on screen, like this:

smartfox.onBuddyListError = function(errorMsg:String)
        var win:MovieClip = showWindow("errorWindow")
        win.errorMsg.text = errorMsg

In the second case your buddList property gets updated with the status of the new user you have added. We've already seen how to handle a onBuddyList event so we can move on.

[ Handling updates ]

If one of the users in our buddy list changes status (i.e. goes offline) we'll immediately receive a onBuddyListUpdate:

smartfox.onBuddyListUpdate = function(buddy:Object)
        var label = buddy.name + " [ " + (buddy.isOnline ? "On" : "Off") + " ]"
        for (var i:Number = 0; i < buddyList_lb.getLength(); i++)
                var item:Object = buddyList_lb.getItemAt(i)
                if (item.data.name == buddy.name)
                        buddyList_lb.replaceItemAt(i, label, buddy)

The argument passed to the event handler is the object representing the buddy that has changed status: what we have to do here is cycle through the buddy list box until we find the item with same name of the buddy object received, then replace it with a new label and object.

[ Removing buddies ]

In order to remove users from the list you can use the removeBuddy() command:

function removeBuddy()
        var item:Object = buddyList_lb.getSelectedItem()
        if (item != undefined)

Before invoking the method we check if there's a selected item in the list box, then we call the removeBuddy() function passing the buddy name. This will fire a onBuddyList() event which will update the view in the buddy list box. Another way of removing buddies is done by calling the clearBuddyList(). In this case the whole list is cleared and all buddies are removed.

[ Removing buddies ]

In the sample application you can select one buddy and click on the "MSG" button to send him a private message even if he's not in the same room where you are. Actually this isn't something really new and it's not related with the buddy list features.
The private messages can be sent to any user in the same zone so it is possible to chat with your buddies regardless of which room they are currently in. A nice feature that could be easily implemented with SmartFoxServer is a multi-chat applications like ICQ, Messenger and the like, where each private chat has its own movable and resizable window and you can check the status of all your friends in real time.

This is the code used to send the private message:

function sendBuddyPrivateMessage()
        var item:Object = buddyList_lb.getSelectedItem()
        if (item != undefined && item.data.id != -1)
                _global.pmUid = item.data.id

The operation is splitted in two parts: first we store the id of the recipient in a _global variable and then we show the input dialog box on screen. When the user hits the "Send" button this code is executed.

function sendPrivateMessage(m:String, recipient:Number)
        smartfox.sendPrivateMessage(m, _global.pmUid)

[ Joining buddies ]

Another nice option we have added to the application is the ability to instantly join one of the buddies in the list: the client selects one friend from the list, press the "Join" button and he is "teleported" in the buddy room. In order to achieve this we must ask the server to tell us where the user is currently located:

function joinBuddy()
        var item:Object = buddyList_lb.getSelectedItem()
        if (item != undefined)

The above function is very simple: you just pass the the buddy object to the getBuddyRoom method. The server will respond with a onBuddyRoom event:

smartfox.onBuddyRoom = function(list:Array)
        var roomId:Number = list[0]
        if (roomId != smartfox.activeRoomId)
                // Check if new room is password protected
                var priv:Boolean = smartfox.getRoom(roomId).isPrivate()
                if (priv)
                        // Save newroom as _global for later use
                        _global.newRoom = roomId
                        // Pass the room id

If you look at the above event handler you may be surprised that a list is returned by the server... didn't we just expect a roomId number? Well, this is exactly what we should expect but what about if the buddy we want to join is currently present in 2 or 3 rooms at the same time? That's why we're receiving an array, it contains a list of available rooms where the buddy is located.

For the sake of simplicity in this application we don't allow users to join more than one room at the same time, so we can safely get the one and only roomId at position 0 in the array. Also before joining the room we must check if it's private and in case it is we should show the appropriate input dialog box before proceeding. If the room is public we go ahead and join it.

[ Conclusions ]

As you can see the buddy list commands provided with SmartFoxServer introduce quite a few interesting possibilities for advanced chatting features. For example by paring the buddy list functions with the ability to send private messages everywhere in the zone you could easily create Flash based instant messengers, advanced chatting apps etc...

Name: Marco Lapi, a.k.a Lapo
Location: Fossano, Italy
Age: 34
Flash experience: started out with Flash 4 back in 1999
Job: web designer/developer
Website: http://www.gotoandplay.it/
| Homepage | News | Games | Articles | Multiplayer Central | Reviews | Spotlight | Forums | Info | Links | Contact us | Advertise | Credits |

| www.smartfoxserver.com | www.gotoandplay.biz | www.openspace-engine.com |

gotoAndPlay() v 3.0.0 -- (c)2003-2008 gotoAndPlay() Team -- P.IVA 03121770048