Table of Contents
As a functional example, a PHP module is provided to interface with a BigWorld server through script. PHP is a very popular open-source scripting language for web development.
This sample module is designed to be used under Linux with Apache and mod_php (the PHP module for Apache). The module also works with the PHP Linux command-line interpreter. While the BigWorld sample implementations use PHP, it is possible to implement a web integration system using any such scripting language or web server. As the TwistedWeb service services HTTP requests, any mechanism that can perform HTTP requests can integrate with the TwistedWeb sample.
You will need to be able to run PHP. It is possible to install it using yum:
# yum install php
You will also need to download and install PHP's libcurl module, which you can also do using yum:
# yum install curl
To implement a website that can access the game server, the PHP
script needs to make HTTP requests to the TwistedWeb service. To help
achieve this, BigWorld.php
implements a PHP class,
called RemoteEntity
, that represents a game entity
on which you can call methods. This is analogous to a BigWorld server
Entity mailbox.
A RemoteEntity
is created using the start of
the URL path as the argument to its constructor. The path does not include
the machine name and port or the method to call and method arguments. For
more information about Twisted.Web and instructions on how to request
entity mailboxes using the TwistedWeb service, see The TwistedWeb Service. For example, to obtain a
RemoteEntity
to FantasyDemo's
AuctionHouse global base entity, you would call:
$this->auctionHouse = new RemoteEntity( "global_entities/AuctionHouse" );
The variable to which the RemoteEntity
was
assigned can subsequently be used like an Entity mailbox for the target
entity.
When calling an entity's methods through a
RemoteEntity
, arguments are provided in the form of
an array. In PHP, an array is an associated map of key/value pairs. The
keys are argument names, and the values are the corresponding argument
values. For example, consider the AuctionHouse entity's
webCreateBidRangeCriteria()
method, which takes
two arguments, representing the minimum and maximum bids for an item, and
returns a criteria object. This method has the following definition in
AuctionHouse.def
:
<webCreateBidRangeCriteria> <Args> <minBid> GOLDPIECES </minBid> <maxBid> GOLDPIECES </maxBid> </Args> <ReturnValues> <criteria> STRING </criteria> <!-- Search criteria object, pickled --> </ReturnValues> </webCreateBidRangeCriteria>
To invoke this method from the RemoteEntity
for the AuctionHouse entity, you will need to create a
PHP array of the arguments. The following code illustrates how this would
be performed:
$res = $this->auctionHouse->webCreateBidRangeCriteria( array( "minBid" => $searchMinBid, "maxBid" => $searchMaxBid ) );
where the values of $searchMinBid
and
$searchMaxBid
are defined before the call. The return
values will be stored in $res
. In this example,
$res[ "criteria" ]
will contain the string describing
the criteria.
The RemoteEntity
instance converts this call
into a HTTP request on an appropriate TwistedWeb
service fragment. It adds the method name and any arguments. It then
blocks waiting for the JSON response. On success, this response is
converted into a PHP object.
In addition to calling entity methods on a
RemoteEntity
in order to access the entity on the
game server, it is possible to access the same entities directly, by
instead using a RemoteEntity
to access the
database, using the TwistedWeb service's db URL option,
for example:
$db = new RemoteEntity( "db" );
Using this RemoteEntity
, it is possible to
invoke commands directly on the game server. For example, to directly log
an account on to the game server, you could make the following
call:
$result = $db->logOn( array( "username" => $username, "password" => $pass ) );
It is possible for remote method calls to fail for a number of reasons, including invalid arguments or methods, or the requested entity not existing. When a call on a RemoteEntity instance fails, the TwistedWeb service will return a specially-formatted error object instead of the expected JSON object. As described in TwistedWeb Error handling, this JSON error object will have the format:
{ "excType": "ErrorType
", "args": [ "Arg1
", "Arg2
" ... ] }
If such an error object is encountered,
BigWorld.php
will raise it as a PHP exception. This
exception type will use the excType
field as the type
name, and the first item in the args
list as the
exception's message:
throw new $excType( $args );
For example, a JSON object representing a BWInvalidArgsError object will be raised as a BWInvalidArgsError exception, whose message will be the first argument contained in the original JSON object.
Any error object encountered by BigWorld.php will have originated as one of two categories of exception objects:
-
Built-in BigWorld errors -
BWStandardError
These are defined in
bigworld/res/scripts/server_common/BWTwoWay.py
, and are explained in the Server Programming Guide's sectionBWStandardError. They originate in the server binaries, and are propagated to the TwistedWeb service.In order for them to be raised as exceptions, they are declared as PHP exception objects in
BWError.php
, sharing the class name of their python counterparts. -
Custom errors -
BWCustomError
These are the error types specific to the game scripts, and are described in detail in PHP Error handling. Like the classes derived from
BWStandardError
, these must be declared as php exception objects in order for them to be handled by normal exception-handling procedures. This is to be done inCustomErrors.php
. For example, if there is a custom error calledMyCustomError
declared in
, there should be a matching php object declared in<res>
/scripts/server_common/CustomErrors.pyCustomErrors.php
://CustomErrors.php <?php require_once( "BWError.php" ); class BWCustomError extends BWFirstArgError {} class MyCustomError extends BWCustomError {} ?>
If an error object is encountered by
BigWorld.php
that has not been declared as its own PHP exception type, it will be thrown instead as aBWGenericError
, maintaining theexcType
field as part of its exception message:throw new BWGenericError( $excType, $args );
For details on handling these errors, refer to PHP Error handling.
The Service
Singleton class in
BigWorld.php
contains a hard-coded list of possible
ServiceApp locations. When a web client starts a new session, the
RemoteEntity
associated with the session is given
the mailbox of a random ServiceApp that is currently online and
providing a fragment of the desired service. You will need to modify
this list to reflect the addresses of your ServiceApp machines:
class Service { private function __construct() { // *** EDIT THIS WITH YOUR ServiceApp ADDRESSES *** $this->urlList = array( "http://someMachine:8000", "http://localHost:8000", "http://someOtherMachine:8000" ); } ... }
A web client will access a Service through the same ServiceApp for
the duration of their session. If this ServiceApp fails during that
time, the RemoteEntity
will find a different
ServiceApp providing the same service, and store its address for the
remainder of the session.
It is possible to store a mailbox to an entity for the duration of a
HTTP session. For example, the BWAuthenticator
class' authenticateUserPass()
method, mentioned
in the previous section, is used not only to invoke the
logOn
command on the game server, but also to
hold onto the resulting entity for the duration of the session. By storing
the URL of this entity in PHP session variables, whose values are
persistent for the entirety of a HTTP session, this allows the web server
to require authentication from a web client only once per session.
To store an entity reference:
$_SESSION['mailbox'] = "entities_by_id/Avatar/37"; // store details to create mailbox later.
To later retrieve it:
$mailbox = new RemoteEntity( $_SESSION['mailbox'] );
For example, to log on and store the result:
$db = new RemoteEntity( "db" ); try { $result = $db->logOn( array( "username" => $username, "password" => $pass ) ); } catch( BWAuthenticateError $e ) { // Handle error ... return; } $_SESSION[ "mailbox" ] = "entities_by_id/" . $result[ "type" ] . '/' . $result[ "id" ];