master-server-sample-walkthrough

Introduction

The Master Server Chat Sample is a basic chat sample developed for HTML5 platform using AppWarp S2 Master Server. The sample shows how to use master server when you have more than one instance of your AppWarp S2 server running. The sample uses the already developed Chat sample developed earlier by us for AppWarp S2.

Prerequisites

This document assumes that the reader is already well versed with development on AppWarp S2 game servers and understands their game’s architecture. The reader should already have read the introduction to Master Server page and have a good understanding of the concepts.

Details

In the sample, the user can select one of the all zones available on all the servers hosting the chat server. The sample also shows how to use custom messages to communicate with the server by implementing a search to find out in which zone a particular user is present. Graph In above image, the y-axis represents the time. First the master makes a connection with all game servers. Then we can connect to master server and query it. We can either use getAllServers() method to get the list of all game servers or use sendCustomMethod to perform a logical search for game servers. For example you can write a logic on master server to return the game server where a particular user is playing. Once we know which game server we want to connect to, we simply connect to it through the WarpClient.

Server Side

The very first step it to run the AppWarp S2 servers. As stated above, we have used our chat server sample. In this sample, we are running 2 chat servers one at port 12340 and other at 12341. You can configure the port by modifying the AppConfig.json file. This is because we are going to be running everything on the same machine (and multiple servers can’t listen on the same port), however in the real world case – you should be deploying to different machines. The next step is to create the MasterConfig.json file. This file is a configuration file required by the master server to run. This is our MasterConfig.json
{
    "ListenPort" : 12345,
    "LogLevel" : "INFO",
    "GameServers" : [
        {
            "Host" : "127.0.0.1",
            "Port" : "12340"
        },
        {
            "Host" : "127.0.0.1",
            "Port" : "12341"
        }
    ]
}
The config is telling the master server to run at port 12345 with log level equal to INFO. The GameServers is JSON Array having the address of all the game servers in form of host and port. Therefore our master server will be listening to two game servers hosted on 127.0.0.1 and ports 12340 and 12341. Master Servers requires two types of listeners : GameClientEventsListener and GameServerEventsListener. GameClientEventsListener is responsible for communicating with clients while GameServerEventsListener is for communicating with game servers. Once you have implemented both the listener classes, you need to add them to master server and start the server with the config file.
MasterServer server = MasterServer.getInstance();
server.getGameClientHandler().addListener(new ClientListener());
server.getGameServerManager().addListener(new GameServerListener());
boolean success = server.start(appconfigPath);
The master server will now run. You will only need to write extra code if you want to extend the server else, it will work straight away. Since our chat sample also has a feature for searching users, we are going to extend the onCustomRequest method of GameClientEventsListener.
    public void onCustomRequest(IGameClient source, byte[] message) {
        String msg = new String(message);
        String response = new String();
        boolean found = false;
            IGameServerManager gameServerManeger = MasterServer.getInstance().getGameServerManager();
            ArrayList<IGameServer> gameServers = gameServerManeger.getServers();
            for(IGameServer s: gameServers){
                ArrayList<IZone> zones = s.getZones();
                for(IZone zone:zones){
                    ArrayList<String> userNames = zone.getUsernames();
                    if(userNames.contains(msg)){
                        response += zone.getAppKey() + "<br>"; 
                        found = true;
                    }
                }
            }

        if(found == false)
        {
            String str = "Not Found";
            source.sendMessage(str.getBytes());
        }
        else
        {
            source.sendMessage(response.getBytes());
        }
    }
Here we are iterating through all the game servers, then through all the zones in each game server and look for the user in usernames list. If we found it, we send the appKey of that zone as response. But if nothing is found we send “Not Found” string. Remember custom messages work on bytes, so you will need to code/decode from bytes to string.

Client Side

The client side code is also an extension of previously developed chat sample for AppWarp S2. To use it along with master server, we are using `AppWarp.MasterClient’. Similar to WarpClient, you need to initialise the Master server with host and port address of master server, define the listeners and connect to the server.
 AppWarp.MasterClient.initialize(masterHost, masterPort);
  _masterclient = AppWarp.MasterClient.getInstance();
  _masterclient.setListener(AppWarp.MasterEvents.onConnectDone, masterOnConnectDone);
  _masterclient.setListener(AppWarp.MasterEvents.onGetAllServerDone, masterOnGetAllServerDone);
  _masterclient.setListener(AppWarp.MasterEvents.onCustomMessageReceived, masterCustomMessageReceived);
  _masterclient.connect();
Once we have successfully connected to Master Server, we call the getAllServer() method. The result of this method is received in onGetAllServersDone Listener.
  function masterOnConnectDone(res)
{
    if(res == AppWarp.ResultCode.Success)
    {
        _masterclient.getAllServers();
    }
}

function masterOnGetAllServerDone(evnt)
{
    if(evnt.getResult() == AppWarp.ResultCode.Success)
    {
        for(var i in evnt.getServers())
        {
            var server = evnt.getServers()[i];
            var host = server.getAddress().getHost();
            var port = server.getAddress().getPort();
            for(var j in evnt.getServers()[i].getAppKeys())
            {
                var appKey = server.getAppKeys()[j];
            }
        }
    }
}
The above method will receive all the zones along with it’s server address’ host and port. To search for the user, we simply need to send the custom message containing the username.
    _masterclient.sendCustomMessage(AppWarp.Utility.string2bin($("#username").val()));
The response of this method will be received in AppWarp.MasterEvents.onCustomMessageReceived listener. In our sample, we have assigned this listener to masterCustomMessageReceived method.
function masterCustomMessageReceived(bytes)
{
    var response = AppWarp.Utility.bin2String(bytes);
}
The sample provides a list of all zones received from the master server. The user selects it by clicking on it. Once, the user clicks on it, the user is provided with textbox to enter his/her username and a connect button to connect to game server. On clicking the button, the AppWarp.WarpClient is initialized with appkey being selected and corresponding host and port. Once connection is successful the sample works the same as it was developed in our previous sample.

API Extensions

Both sides of the interaction can be extended and modified by developers if required.

Conclusion

Games with heavy traffic will require more than one instance of server, to manage those, a master server is need. Master server is very easy to use and can be used with any existing AppWarp S2 game.