The Allegro Wiki is migrating to github at https://github.com/liballeg/allegro_wiki/wiki

Using XML RPC for your MMORPG

From Allegro Wiki
Jump to: navigation, search
This article is a stub. Please help Allegro by expanding it.


Introduction

In this article I'll be showing you how you can use XML RPC to not only clean up the source code for your MMORPG, but also create a more coherent base for your game. XML RPC is a very powerful technology, yet it is still surprisingly underused. In this article we'll be using xmlrpc++, an amazingly nice wrapper for creating simple XML RPC applications, and perfect for utilizing this protocol for both the client and server in an MMORPG.

What Is XML RPC?

XML RPC stands for eXtensible Markup Language Remote Procedure Call. Basically it is an XML-based protocol for calling functions on a remote host (i.e. having a client call a Login(char* username, char* password) function stored on a remote server). This is perfect for an MMORPG as it provides a solid base for constructing a client and server system, and it's also surprisingly easy to work with.

Creating A Simple Login System

Ok, so just how simple is XML RPC, well allow me to show. We'll start by creating a simple login system, where on one side the user submits a password, and on the server the password is verified and a result is sent back to the client.

Writing The Login Server

Firstly, let's write the servers' login function, XML RPC makes this very easy to do, and also allows us to use C++ classes to do it:

#include <string>
#include <iostream>
#include "XmlRpc.h"
using namespace std;
using namespace XmlRpc;

const int         PORT = 8080;
const XmlRpcValue USERNAME( "bob" );
const XmlRpcValue PASSWORD( "donttell" );

XmlRpcServer server;

class Login : public XmlRpcServerMethod
{
public:
    Login(XmlRpcServer * server);

    void execute(XmlRpcValue& params, XmlRpcValue& result);
} Login( &server ); // This initializes our class


int main(int argc, char* argv[])
{
  // Run our server on port 8080
  server.bindAndListen( PORT );

  // Tell our server to wait indefinately for messages
  server.work(-1.0f);

  return EXIT_SUCCESS;
}

This is are server login class, basically all we do is inherit from the XmlRpcServerMethod class, and define the XmlRpcServerMethod function execute which takes our parameters and returns a result through a c++ reference to an XmlRpcValue object. Also we've defined the constants USERNAME and PASSWORD as XmlRpcValue strings. Now let's write these functions

// We initialize this class, and name the method Login
Login::Login(XmlRpcServer * server) : XmlRpcServerMethod("Login", server)
{
}

void Login::execute(XmlRpcValue& params, XmlRpcValue& result)
{
    if ( params.getType() != Type::TYPE_STRUCT )
    {
        return;
    }

    XmlRpcValue::bool& ret = result;

    if ( params["username"] == USERNAME &&
         params["password"] == PASSWORD )
    {
        ret = true;
    }

    ret = false;
}

Wow! Now isn't that nice? We've got our very simple login function, all it does is ensure that we received a struct, then we compare the struct values username and password against our constants USERNAME and PASSWORD, and if they match the client is logged in and we return true, otherwise we return false. This should do it for our simple login server, so now for the complete code listing:

#include <string>
#include <iostream>
#include "XmlRpc.h"
using namespace std;
using namespace XmlRpc;

const int         PORT = 8080;
const XmlRpcValue USERNAME( "bob" );
const XmlRpcValue PASSWORD( "donttell" );

XmlRpcServer server;

class Login : public XmlRpcServerMethod
{
public:
    Login(XmlRpcServer * server) : XmlRpcServerMethod("Login", server)
    {
    }

    void execute(XmlRpcValue& params, XmlRpcValue& result)
    {
        if ( params.getType() != Type::TYPE_STRUCT )
        {
            return;
        }

        XmlRpcValue::bool& ret = result;

        if ( params["username"] == USERNAME &&
             params["password"] == PASSWORD )
        {
            ret = true;
        }

        ret = false;
    }
} Login( &server ); // This initializes our class

int main(int argc, char* argv[])
{
  // Run our server on port 8080
  server.bindAndListen( PORT );

  // Tell our server to wait indefinately for messages
  server.work(-1.0f);

  return EXIT_SUCCESS;
}

Writing The Login Client

Now on the client side, we'll use the C++ standard iostreams to retrieve the username and password which will be sent to the server.

#include <string>
#include <iostream>
#include "XmlRpc.h"
using namespace XmlRpc;

const char * HOST = "127.0.0.1"; // localhost
const int    PORT = 8080;

int main(int argc, char* argv[])
{
    // Connect our client to the server
    XmlRpcClient client(HOST, PORT);

    std::string username;
    std::string password;

    std::cout << "Username: ";
    std::cin  >> username;

    std::cout << "Password: ";
    std::cin  >> password;

    XmlRpcValue result;
    XmlRpcValue value;
    value["username"] = username;
    value["password"] = password;

    if ( c.execute("Login", value, result) )
    {
        if ( (bool&)result )
        {
            std::cout << "Login Succeeded!" << std::endl;
        }
        else
        {
            std::cout << "Login Failed!" << std::endl;
        }   
    }

    return EXIT_SUCCESS;
}

Again the code is very simple, we grab a username and password pair from the user, and then we check if the login succeeded or not. All very easy to write, and now we have our simple login system!

Conclusion

Well, that's all for this article, but I sincerely hope that this article has shown just how easy and helpful XML RPC can be if you're writing an MMORPG. Please look at the additional link section for more info, and enjoy!

--Zenogais 08:14, 12 February 2006 (PST)

Known issues

XML RPC, in their code, explains that this library is not thread safe. That means the next: if 2 players, simultaneously, tries to connect using the server-client example above, the server simply crashes. For avoid this, you must use or create threads for each user, in the method execute in the server program.

Additional Links