8.10 Tutorials: Pixel Game (advanced room management)

The source FLA of this example is found under the Examples/AS2/19_pro_pixelgame folder.

» Introduction

In this article we will analyze some advanced aspects of server side multiplayer programming with SmartFoxServer. In particular we will create a simple multiuser application that requires a custom logic for handling user login and joining.

The application will allow the clients to share a pixel board where every user can turn on or off each pixel and create simple drawings.
The particularity of this application is the way the rooms are managed.
Instead of using the default system of getting a list of rooms and then let the user decide which room to join, we will implement a custom logic where the server automatically looks for the first available room and join the user inside. If all the rooms are full the server will automatically create a new room and join the client inside.

pixelGame

The main intent of this article is to describe the logic used to create this behaviour. The rest of the application is very simple and uses concepts that we have already exposed in the previous article, so we won't analyze the,

This tutorial requires SmartFoxServer 1.4.0 or later. Also we strongly reccomend that you're familiar with the basics of server side programming with SmartFoxServer PRO before starting with this article.

» The server side extension

You will find the extension source code in the sfsExtensions/ folder with the name "pixelGame.as"

Let's analyze the ActionScript that handles the login event:
function handleInternalEvent(e)
{
        
        if (e.name == "loginRequest")
        {
                var newUser = null
                var error = ""
                
                var nick = e["nick"]
                var pass = e["pass"]
                var chan = e["chan"]
                
                if (nick == "")
                nick = getRandomName(12)
                
                var obj = _server.loginUser(nick, pass, chan)
                
                if (obj.success == false)
                error = obj.error
                
                // Send response to client
                var response = new Object()
                
                if (error == "")
                {
                        newUser = _server.instance.getUserByChannel(chan)
                        
                        response._cmd = "logOK"
                        response.id = newUser.getUserId()
                        response.name = newUser.getName()
                }
                else
                {
                        response._cmd = "logKO"
                        response.err = error
                }
                
                _server.sendResponse(response, -1, null, chan)
        }
}


You will notice that the code is almost identical to the one used in the previous example. We just have added an extra check for empty user names. If a blank nick name is sent, it will be replaced by a 12 char long random name generated by the getRandomName() function.

When the client receivs the "logOK" message it will send a "jme" (join me) command request to the server, which will be handled by the lookforRoom method of the extension:

function lookForRoom(usr)
{
        var rooms = zone.getRooms()
        var found = false
        
        if (usr != null)
        {
                for (var i = 0; i < rooms.length; i++)
                {
                        var rm = rooms[i]
                        
                        if (rm.howManyUsers() < rm.getMaxUsers())
                        {
                                _server.sendRoomList(usr)
                                
                                var j = _server.joinRoom(usr, -1, false, rm.getId(), "", false, true)
                                
                                if (!j)
                                trace("Oops, user: " + usr.getName() + " couldn't join")
                                
                                found = true
                                break
                        }
                }
                
                if (!found)
                {
                        var rName = "AutoRoom_" + roomCounter
                        roomCounter++
                        
                        var r = makeNewRoom(rName, 4, usr)
                        
                        if (r != null)
                        {
                                _server.sendRoomList(usr)
                                createGrid(r)
                                var j = _server.joinRoom(usr, -1, false, r.getId(), "", false, true)
                        }
                        else
                        trace("Failed creating room >> " + rName)
                        
                }
        }
}

In this function we cycle through all the rooms available in the current Zone and we check if there's room for a new user.
If the room is found we will join the user inside and break the loop. Also you can notice that we call a sendRoomList() method. We will analyze this in a moment.

If all the available rooms are full we will execute the second part of the function. A new room is created calling the makeNewRoom() method and passing the name of the new room, the capacity, and the "owner" of the room (the user who created it)

NOTE:
you can set the Server itself as the owner of a Room. To do so, you should pass a null as the owner parameter. By doing so the room will never be destroyed.

This is the code for creating the new room:

function makeNewRoom(rName, maxU, owner)
{
        var rObj 	= {}
        rObj.name 	= rName
        rObj.pwd 	= ""
        rObj.maxU	= maxU
        rObj.maxS 	= 0
        rObj.isGame	= false
        
        var r = _server.createRoom(rObj, owner, true)
        
        return r
}

We build an object and assign the properties of the new room that we'd like to create. Finally we invoke the _server.createRoom() function and return the Room object. You can find more details on this last function by checking the Server Side API docs.

Now that we have a new room available for the client we can join him using the _server.joinRoom()command. As you can see we pass 7 parameters to this function:

-> the user object
-> the id of the previous room where the user was in (-1 means, no previous room)
-> a flag to tell the server if we want to leave the previous room (fals in this case)
-> the id of the new room we want the user to join
-> the password for that room (none in this case)
-> a flag to tell the server if the user wants to join as a spectator (for game rooms only, false in this case)
-> a flag to tell the server if we want to send the default update to all other clients (this is optional, by default is true)

The _server.joinRoom() method will return a boolean indicating if the join was successful and it will fire a onJoinRoom() event on the client side that can be handled in the usual way.

» The room list

One of the most important information that the client receives from the server at the beginning is the room list. The list contains all the properties of each room and it will be populated with the Room Variables and the list of users during the execution of your applications.

Normally this list is received by calling the getRoomList() method from the client side.

In this application we will send the roomList directly from the server extension by calling _server.sendRoomList(), without the need to request it from the client.

» Conclusions

We've seen how to use some of the new commands introduced in the server side framework from version 1.4.0
The ability to create and join rooms on the server side adds more flexibilty and power to SmartFoxServer extensions and allow to create all kind of sophisticated behaviours for challenge systems, automatic room management, etc...


doc index