[ 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)
{
roomList_lb.removeAll()
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
this.autoJoin()
}
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()
resetRoomSelected(roomId)
_global.currentRoom = roomObj
// Clear text area
chat_txt.htmlText = ""
// Clear current list
userList_lb.removeAll()
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
smartfox.loadBuddyList()
}
}
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)
{
buddyList_lb.removeAll()
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:
smartFox.addBuddy("Lapo")
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)
break
}
}
}
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)
{
smartfox.removeBuddy(item.data.name)
}
}
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
showWindow("pmWindow")
}
}
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)
{
hideWindow("pmWindow")
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)
{
smartfox.getBuddyRoom(item.data)
}
}
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
showWindow("passwordWindow")
}
else
{
// Pass the room id
smartfox.joinRoom(roomId)
}
}
}
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...
|