bw logo

Chapter 12. Integrating With BigWorld Server

12.1. Overview

This chapter describes how to integrate arbitrary clients with the BigWorld Server.

A tool called ProcessDefs parses the entity definitions and generates C++ code for interacting with a BigWorld server that uses those same entity definitions. The entity behaviour can then be implemented in C++, or glue code can be written to allow the entity behaviour to be implemented in another language, for example, Lua, or Objective-C. This allows for client applications that do not use Python as their game scripting language by generating code that contains all the entity type data (method calls and properties) that is normally read from the entity definitions files.

To implement entity-specific behaviours, the generated stub classes for each entity type can be extended to provide the specific behaviours in response to method call requests or property updates from the server. More general behaviours common to all entity types can be implemented in the user-defined superclass that derives from BWEntity.

For example, the above class diagram shows an entity type called Avatar from a set of entity definitions. The code generator will generate stub files for the Avatar_Stub, CellMB::Avatar and BaseMB::Avatar classes, which encapsulate all the accessors and members for accessing properties and calling remote methods. Concrete implementations of the Avatar entity type on the client are implemented in the user-defined Avatar class (a template that can be used as a basis for this is also generated).

All entity classes must have BWEntity as one of their inherited ancestor superclasses, but they can also inherit from a user-defined custom class that provides general game-specific functionality that is common to all entity classes. For example, Avatar_Stub derives from MyEntity instead of BWEntity in the above example, allowing for the Avatar class to use inherited member methods and data from MyEntity as well.

The connection library provides C++ classes that can be used to connect and authenticate to the BigWorld Server. Once connected, volatile data, property updates, method calls can be sent and received between the client and server.

12.2. Generating Code With the ProcessDefs tool

At the most basic level, the ProcessDefs command line tool parses a set of entity definition files and calls through to a processing function defined in a Python module with a data structure that represents the parsed entity definitions.

By default, it will use the ProcessDefs Python module located in the same directory as the process_defs executable, which simply outputs the entity definitions to the standard output stream and exits.

For generating C++ source files, the supplied GenerateCPlusPlus module is used.

The desired Python module can be specifying the module name with the -m / --module switch. For example, for selecting the GenerateCPlusPlus module:

$ ./process_defs -m GenerateCPlusPlus ...

12.2.1. ProcessDefs/GenerateCPlusPlus Operation

Running the process_defs executable with the --help switch will give you general options as well as a list of module-specific options supported by the selected Python module.

$ ./process_defs -m GenerateCPlusPlus --help
usage: process_defs [OPTION] scriptArgs

This program parses the BigWorld entity definition files. A Python object is
then created representing the entity descriptions. This is passed to a Python
callback moduleName.functionName. By default, this is ProcessDefs.process.

This module (ProcessDefs.py) should be placed in modulePath. This is the
current working directory by default.

Options:
  -r             directory     Specifies a resource path. Can be used
                               multiple times, in order of deccreasing
                               priority.
  -f, --function funcName      The Python function to call. "process" by
                               default.
  -m, --module   moduleName    The Python module to load. "ProcessDefs"
                               by default.
  -p, --path     directory     The directory to find the module. Current 
                               working directory by default.
  -v, --verbose                Displays more verbose output.
  -h, --help                   Displays this message.

Script Options:
  -h, --help            show this help message and exit
  -o FILE, --output=FILE
                        Directory to output generated files. Defaults to
                        "GeneratedCPlusPlus".
  --base-class-header=CLASS_NAME_INCLUDE_PATH
                        Path to a header file containing the declaration for
                        the base class for generated entity classes. Defaults
                        to "connection/bw_entity.hpp".
  -b CLASS_NAME, --base-class=CLASS_NAME
                        The base class for generated entity classes. Defaults
                        to "BWEntity".
  --generated-header-path=HEADERPATH
                        This indicates the directory of where to find the
                        generated sources, and is used for generating the
                        #include lines for generated headers. Defaults to
                        "GeneratedEntities".
  --entity-header-path=HEADERPATH
                        This indicates the directory of where to find your
                        entity class header files, and is used for generating
                        the #include lines for entity header files. Defaults
                        to "Entities"
  --entity-template-source-extension=EXT
                        Specifies the extension suffix given to generated
                        entity stub and template C++ source files. Defaults to
                        "cpp".

ProcessDefs requires the location of the resource directories be specified as command line options, so it can find the relevant entity definition files to parse. The resource directories can be specified by using the -r option, followed by the path to the resource directory. To specify multiple directories, the option can be used multiple times, specifying resource paths in descending order of priority. Typically, the bigworld/res directory is specified as the last resource path.

Typically, the generated sources are compiled as part of a larger project, and are placed in their own directory within the project directory structure. You can use the ProcessDefs tool to compile straight to their target directory by using the -o / --output command line option.

Once the sources are in place, you will also need to include them into your project using a common include line path prefix. The generated source files will also include other generated header files, and so it is necessary to also add this common include line path prefix in the generated source files themselves. This prefix is specified using the --generated-header-path option, and is usually determined by where the output directory is in relation to your project source directories.

Concrete entity implementations will typically be in their own directory. Since the generated source files require the inclusion of those entity class header files in order to construct them in the entity factory, the location of the entity class header files needs to be specified using the --entity-header-path option.

It can be useful to also modify the file extension of the entity class template source files that are generated. For example, Objective-C++ requires its source files to have a .mm extension.This can be specified using the --entity-template-source-extension option.

As an example, the ios client project directory (located at bigworld/src/examples/client_integration/c_plus_plus/ios) contains a Classes directory, which in turn contains an Entities directory, which in turn contains a GeneratedSource directory. The Classes directory contains source files for general game Objective-C and Objective-C++ classes, including the general FDEntity class which is used as the entity super-class, which implements functionality common to all entity classes. FDEntity itself derives from BWEntity.

The Entities directory contains the implementation source files of the concrete entity classes. These classes derive directly from their corresponding stub classes, so for example, Avatar derives from Avatar_Stub.

The GeneratedSource directory contains all the generated sources output from ProcessDefs. It contains the non-entity-specific source files, for example, the sources for generated FIXED_DICT types, as well as each entity type's stub class and the server-side entity classes.

With these requirements in mind, we use the following command as part of the build process in XCode:

./process_defs.macosx \
        -r "${SRCROOT}/../../../../fantasydemo/res" \
        -r "${SRCROOT}/../../../res" \
        --module "GenerateCPlusPlus" \
        --output "${SRCROOT}/Classes/Entities/GeneratedSource" \
        --base-class "FDEntity" \
        --base-class-header "FDEntity.h" \
        --entity-header-path "Classes/Entities" \
        --generated-header-path "Classes/Entities/GeneratedSource" \
        --entity-template-source-extension "mm"

12.2.2. Generating C++ Code

The GenerateCPlusPlus module takes the entity definitions descriptor object and writes out several generated files that can be used for connecting to a server that runs those same entity definitions.

For each entity type, the GenerateCPlusPlus module will generate a stub class which incorporates the entity type name in the class name. This stub class implements the entity property streaming and client-side method dispatch.

The GenerateCPlusPlus module will also generate, if needed, remote entity classes used for calling remote methods on the server side, if they are defined in that entity type's definition file.

The files generated are:

  • Entity_Stub.hpp and Entity_Stub.cpp

    The Avatar_Stub class derives indirectly from BWEntity, and contains property member variables and accessors, as well as implementing the streaming operators for each of its property members that are populated from the server-side.

    It contains accessors to the cell and base (if applicable) via a ServerEntityMailBox subclass, which contains methods to call remote base and cell methods declared in the entity definitions.

    It contains pure virtual method declarations of client-side methods that can be remotely called from the server-side.

    The concrete Avatar class derives directly from Avatar_Stub, and implements the pure virtual methods and inherits the property accessors and the base and cell remote entity handles.

  • Entity_CellMB.hpp and Entity_CellMB.cpp

    The CellMB::Avatar class implements the remote method calls from the client-side to the cell entity on the server-side. This may not be available if the entity definitions for the Avatar entity type do not declare any exposed CellMethods.

  • Entity_BaseMB.hpp and Entity_BaseMB.cpp

    The BaseMB::Avatar class implements the remote method calls from the client-side to the base entity on the server-side. This may not be available if the entity definitions for the Avatar entity type do not declare any exposed BaseMethods.

  • Entity.hpp and Entity.cpp

    A template for the concrete Avatar entity class will also be generated that can be used as a basis for the actual concrete Avatar entity class implementation. It provides empty implementations of required client-side methods and property setter callbacks. These concrete entity template sources are located in a sub-directory of the output directory called templates.

The GenerateCPlusPlus module will also output several general source files as listed below:

  • DefsDigest.hpp and DefsDigest.cpp

    The DefsDigest namespace holds a single method that returns the string value of the digest of the entity definitions. This digest value is used when logging into the server to verify that the server entity definitions match the client's entity definitions.

  • EntityFactory.hpp and EntityFactory.cpp

    The EntityFactory class implements the BWEntityFactory interface, and creates a new instance of BWEntity that is named the same as the entity type that the given entity type ID refers to (for example, the Account class for the Account entity type).

  • GeneratedTypes.hpp and GeneratedTypes.cpp

    This header and source file describe generated types that were derived from FIXED_DICT data types. These are labelled in the definition of the FIXED_DICT data type where they appear in either the scripts/entity_defs/alias.xml file or in the <EntityType>.def file using the <Label> tag in order to name the generated class for that FIXED_DICT type. For example:

    <root>
    ...
        <InventoryEntry> FIXED_DICT
            <TypeName> InventoryEntry </TypeName>
            <Properties>
                <itemType>
                    <Type> ITEMTYPE </Type>
                </itemType>
               <serial>
                    <Type> ITEMSERIAL </Type>
               </serial>
               <lockHandle>
                    <Type> LOCKHANDLE </Type>
               </lockHandle>
            </Properties>
        </InventoryEntry>
    ...

    The above example will result in a class called InventoryEntry to be generated and used as the type for member data in stub classes for entity types that have the InventoryEntry type as a type for one of their client-visible properties.

    It is important to label all FIXED_DICT types, as failure to do so will cause issues due to the arbitrary numeric label that is assigned to unlabelled FIXED_DICT types (for example, FixedDict0, FixedDict1, and so on). If the parse order changes at all, entity source files that refer to those unlablled FIXED_DICT types may be referring to incorrect types in the new parse order, causing compile errors when using sub-property accessors.

12.3. Customising ProcessDefs Output

It may be necessary to change the generated code output to customise it for specific game development needs. This can be done by modifying the templates that the GenerateCPlusPlus module uses for generating source, or implementing a whole new processing module for the ProcessDefs tool.

12.3.1. Modifying the Generated Code Templates

The GenerateCPlusPlus module uses the supplied jinja2 Python templating library to generate the code. The jinja templates are located inside the module directory under the directory called templates. The templates used are:

  • DefsDigest.hpp and DefsDigest.cpp

    Template used for generating the definitions digest accessor function.

  • EntityFactory.hpp and EntityFactory.cpp

    Template used for generating the entity factory class.

  • EntityMailBoxTemplate.hpp and EntityMailBoxTemplate.cpp

    Template used for generating the base and cell mailbox objects, for calling remote methods on the server-side.

  • EntityStubTemplate.hpp and EntityStubTemplate.cpp

    Template used for generating the entity stub classes that implement the functionality for client-side entity method dispatch and client-side entity property streaming.

  • EntityTemplate.hpp and EntityTemplate.cpp

    Template used for generating the empty entity class templates.

  • GeneratedTypes.hpp and GeneratedTypes.cpp

    Template used for generating the FIXED_DICT equivalent types.

12.3.2. Implementing a New Processing Module

For ultimate control over the code generation process, a new processing module can be used with ProcessDefs.

Each ProcessDefs processing module implements a function that is passed a data structure that describes the entity definitions that are parsed by ProcessDefs. The function is called process() by default; a command line option on ProcessDefs can change which module function is called.

The data structure passed to the processing function is a Python dictionary with the following keys:

  • constants

    This is a dictionary of constants used for connection to the server. In particular, it contains:

    • digest

      This value is a string of the entity definitions digest, used to verify the client-side resources are consistent with those resources on the server.

    • maxClientServerPropertyCount

      This value is the maximum count of client-server properties across all entity types.

    • maxExposedBaseMethodCount

      This value is the maximum count of exposed base methods across all entity types.

    • maxExposedCellMethodCount

      This value is the maximum count of exposed cell methods across all entity types.

    • maxExposedClientMethodCount

      This value is the maximum count of client methods across all entity types.

  • entityTypes

    This value is a sequence of dictionary objects, each of which describes an entity type. Each entity type dictionary has the following keys:

    • clientMethods

      This value contains a sequence of dictionaries describing each of the client methods for this entity type.

    • baseMethods

      This value contains a sequence of dictionaries describing each of the base methods for this entity type.

    • cellMethods

      This value contains a sequence of dictionaries describing each of the cell methods for this entity type.

    • allProperties

      This value contains a sequence of property description dictionaries for all properties.

    • clientProperties

      This value contains a sequence of property description dictionaries for all client-side properties propagated from the server.

    • baseToClientProperties

      This value contains a sequence of property description dictionaries for BASE_AND_CLIENT properties.

    • cellToClientProperties

      This value contains a sequence of property description dictionaries for OWN_CLIENT, OTHER_CLIENT and ALL_CLIENT properties.

Each method description dictionary object contains the following keys:

  • name

    The name of the method.

  • isExposed

    Whether the method is exposed for client-side initiated remote calls.

  • internalIndex

    The internal index of the method - only important for debugging.

  • exposedIndex

    If this is an exposed method, this is the index used to identify this method in communications between the server and client. This value is set to -1 for non-exposed methods.

Each property description dictionary object contains the following keys:

  • name

    The name of the property.

  • index

    The index of the property - only important for debugging.

  • clientServerFullIndex

    The index of the property used to identify this property in communications between the server and client.

  • isGhostedData

    ALL_CLIENTS, OTHER_CLIENTS or CELL_PUBLIC properties have this value set to True, otherwise False.

  • isOtherClientData

    ALL_CLIENTS and OTHER_CLIENTS properties have this value set to True, otherwise False.

  • isOwnClientData

    OWN_CLIENT properties have this value set to True, otherwise False.

  • isCellData

    ALL_CLIENT, OWN_CLIENTS, OTHER_CLIENTS, CELL_PRIVATE and CELL_PUBLIC properties have this value set to True, otherwise False.

  • isBaseData

    BASE and BASE_AND_CLIENT properties have this value set to True, otherwise False.

  • isClientServerData

    BASE_AND_CLIENT, ALL_CLIENTS, OTHER_CLIENTS, OWN_CLIENT properties have this value set to True, otherwise False.

  • isPersistent

    If this is a persistent property, this value is set to True, otherwise False.

  • isIdentifier

    If this property is the identifier property for its entity type, this value is set to True, otherwise False.

  • isIndexed

    If this property is indexed in the database, this value is set to True, otherwise False.

  • isUnique

    If this property is marked as unique in the database, this value is set to True, otherwise False.

12.4. The connection_model Library

The connection_model library contains classes for connecting to the BigWorld Server. It makes use of the lower-level connection library.

The BWConnection class contains most of the functionality for connecting to a BigWorld server, and provides a simple API for connecting. Connections are performed asynchronously, and require that the connection object is ticked frequently (typically once per game tick), to process events from the network.

The BWEntity class is the base class for entity types. Typically, a particular game will have its own base class that extends the BWEntity class, and each entity type will then further derive from the BWEntity-derived base class to implement entity-type-specific behaviours.

For example, the example sdl client (located at bigworld/src/examples/c_plus_plus/sdl) contains a MyEntity class which derives from BWEntity. The Account entity class derives from MyEntity.

A class implementing the BWEntityFactory interface is required when constructing a BWConnection instance. This factory is responsible for creating a new instance of BWEntity based on an entity type ID sent down from the server. The entity type ID reflects the order in which a particular entity type appears in the entities.xml file.

When using code generation, a subclass of BWEntityFactory will be generated which contains the logic to instantiate the particular BWEntity class that is named after the entity type identified by the entity type ID.

12.4.1. Dependencies

The connection_model library depends on:

  • The connection library, low-level classes and interfaces for connecting to the server.

  • The cstdmf library, a general utility library used in BigWorld.

  • The network library, a networking library used to implement the Mercury protocol.

  • The math library, a general math library.

  • The OpenSSL library

12.4.2. BWConnection

This class represents a connection to the server. The BWConnection class's simple interface allows applications to connect to a server and populate BWEntity objects with position and direction data, property updates and handling of remote method calls.

12.4.2.1. LoginApp Public Key

In order to communicate with the server, the public key used to encrypt login details for a server must be configured and set on the connection object. This is done via a call to either setLoginAppPublicKeyString() or the setLoginAppPublicKeyPath() method.

The setLoginAppPublicKeyString() method sets the LoginApp public key based on a string containing the public key. For example:

static const char g_publicKeyString[] = "-----BEGIN PUBLIC KEY-----\n" \
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7/MNyWDdFpXhpFTO9LHz\n" \
"CUQPYv2YP5rqJjUoxAFa3uKiPKbRvVFjUQ9lGHyjCmtixBbBqCTvDWu6Zh9Imu3x\n" \
"KgCJh6NPSkddH3l+C+51FNtu3dGntbSLWuwi6Au1ErNpySpdx+Le7YEcFviY/ClZ\n" \
"ayvVdA0tcb5NVJ4Axu13NvsuOUMqHxzCZRXCe6nyp6phFP2dQQZj8QZp0VsMFvhh\n" \
"MsZ4srdFLG0sd8qliYzSqIyEQkwO8TQleHzfYYZ90wPTCOvMnMe5+zCH0iPJMisP\n" \
"YB60u6lK9cvDEeuhPH95TPpzLNUFgmQIu9FU8PkcKA53bj0LWZR7v86Oco6vFg6V\n" \
"sQIDAQAB\n"
"-----END PUBLIC KEY-----\n"

BWConnection connection( ... );

connection.setLoginAppPublicKeyString( g_publicKeyString );

The setLoginAppPublicKeyPath() method sets the LoginApp public key based on a file located at the given path. The path itself is a normal file-system path; it is not resolved through the resource file system.

Please refer to the Encrypting Client-Server Traffic for more information about the encryption used between the client and the server.

12.4.2.2. Entity Definitions Digest

The entity definitions is required to be identical between the client and the server for methods and properties to be able to be streamed over the network. In order to guard against inconsistent entity definitions, the server and the client take a digest of the entity definitions, and the client sends its digest when logging in for the server to compare against.

The BWConnection object requires that the digest be set using the setDigest() method.

When using ProcessDefs/GenerateCPlusPlus to generate code, the function DefsDigest::constants()is generated, which returns a constants object that contains the definitions digest string, along with other constants important for streaming properties and methods.

For example:

#include "GeneratedSource/DefsDigest.hpp"

#include "connection/bw_connection.hpp"

...

    BWConnection * pConnection = new Connection( *pEntityFactory, DefsDigest::constants() );

12.4.2.3. Ticking the Connection Instance

Clients will generally have a render loop in which rendering occurs each frame. As part of each frame, the BWConnection instance should be ticked regularly, by calling the BWConnection::update() method periodically.

The update() method requires that the amount of time elapsed since the last update be passed in.

Under certain frameworks, timers may be set up to call update(). For example, under Apple Objective-C under iOS, NSTimer can be used to tick the connection instance periodically. Cocos2D also has a similar timer.

12.4.2.4. Logging Into a Server

After setting up the LoginApp public key, the entity definitions digest and ticking the connection instance, the connection can be started by logging into the server using the logOnTo() method.

std::string serverAddress = "10.1.1.1";
std::sttring username = "MyUser";
std::string password = "pass";

pConnection->logOnTo( serverAddress, username, password );

The serverAddress string parameter specifies the address and port to connect to. If no port is specified, the default port of 20013 is assumed. To specify a port, use the <ip_address>:<port> format.

Log-on success, failures and disconnection events can be handled by setting a ServerConnectionHandler object on the connection. The ServerConnectionHandler interface in the connection library allows you to catch the following events:

  • onLoggedOn()

    Called when a connection attempt succeeds.

  • onLoggedOff()

    Called when a connection has been disconnected.

  • onLogOnFailure()

    Called when a connection attempt fails. A string error message is supplied as a parameter.

The handler can be set on a connection object before calling logOnTo():

MyConnectionHandler handler;
pConnection->setHandler( &handler );

12.4.3. BWEntity

The BWEntity class is the superclass of all entity classes. Instances of the BWEntity class are created using the BWEntityFactory instance registered with the BWConnection at construction time.

12.4.3.1. Avatar Filtering

Each BWEntity instance can have an associated filter object that is used whenever position and direction data is received from the server. This filter object is then used to output positions and directions each frame based on the received inputs from the server.

There are pre-defined filters that can be used, for example the AvatarFilter class, which is the generic filter used for most entities in the Windows-based BWClient. You can simply initialise the entity's filter object by calling the pFilter() method.

MyEntity::MyEntity() :
...
{
    ...
    this->pFilter( new AvatarFilter( environment ) );

A filter environment object (deriving from the FilterEnvironment interface class) is required when constructing a FilterBase subclass. This is often engine-specific, and so a particular FilterEnvironment is required for each particular game engine.

A FilterEnvironment (found in the connection library) implements these virtual methods:

  • void updateCoordinateSystem( EntityBase * pEntity, SpaceID spaceID, EntityID vehicleID )

    This method is called whenever an entity has changed its coordinate system, typically by boarding or alighting a vehicle. It is also called when a player entity teleports and changes space. This method is used to perform any bookkeeping on the passed in entity in order to support the new updated coordinate space, as well as handling the vehicle change.

  • void transformIntoCommon( SpaceID spaceID, EntityID vehicleID, Position3D & position, Vector3 & direction )

    void transformFromCommon( SpaceID spaceID, EntityID vehicleID, Position3D & position, Vector3 & direction )

    These two methods are used to transform coordinates from vehicle-space coordinates to the common world-space coordinates.

  • bool filterDropPoint( EntityBase * pEntity, const Position3D & fall, Position3D & land, Vector3 * pGroundNormal )

    This method is used to getting the drop position onto the closest terrain or other obstacle in the scene. The ground normal should also be supplied in the pGroundNormal parameter if it is non-NULL.

  • bool resolveOnGroundPosition( Position3D & position, bool & isOnGround )

    This method is used to determine whether a particular point can be considered to be "on-ground". This is used to optimise the network communication between the client and server if both sides agree that a player entity is on the ground, as this allows for the y-position to be omitted from sending.

For creating new filters, new sub-classes of the FilterBase interface class can be implemented. Each filter object is required to implement the following methods:

  • void input( double time, SpaceID spaceID, EntityID vehicleID, const Position3D & position, const Vector3 & positionError, float * auxFiltered )

    This method is called to receive a position and direction update from the server, specific to a particular time. The auxFiltered parameter points to a 3-element array containing the yaw, pitch and roll respectively.

  • void output( double time )

    This method is called to set the filter's best estimate for the position and direction of an entity for the given time. This is typically called each frame to set the entity position before it is visually rendered.

  • void reset()

    This method is called when a filter state needs to be reset. This is typically when an entity first comes into the area of interest, or when it has teleported.

  • void getLastInput()

    This method is called to retrieve the last input that was received from the server.

12.4.4. BWEntityFactory

Subclasses of the BWEntityFactory interface class are responsible for creating instances of BWEntity that are appropriate to the entity type ID given to the creation method.

Generated code will include a concrete class that implements BWEntityFactory, called EntityFactory, which creates the appropriate concrete BWEntity class that has the same name as the entity type name.

A BWEntityFactory instance is required to construct a BWConnection instance.

12.4.5. BWEntitiesListener

When the player is inside a space, entities in that space will enter and leave the client's area of interest, and the server will inform the client when this occurs. It is useful to catch when this happens, and so BWConnection allows for a BWEntitiesListener object to be registered which receives entity enter and leave events.

A BWEntitiesListener subclass implements the following methods:

  • void onEntityEnter( BWEntity * pEntity )

    This is called when an entity has entered the client's AoI.

  • void onEntityLeave( BWEntity * pEntity )

    This is called when an entity has left the client's AoI.

12.4.6. Server Discovery

Server discovery is used during development to find a locally running server on the same LAN segment and get details for starting a connection. It is not intended to be used for production clients.

A subclass of the abstract ServerFinder class is used for this purpose. By implementing a new concrete subclasss of ServerFinder, instantiating it and passing it to BWConnection's findServers() method, a search for locally running servers will be performed. The timeout parameter in findServers() can be used to set the time-out duration for searches; it defaults to 10 seconds.

Virtual method callbacks are called when servers are found, when the search is completed or has timed out. ServerFinder subclasses should implement the following methods:

  • onServerFound() is called when a single server has been found. It is passed a ServerInfo object, which contains an address and port for connection, as well as the Unix user ID of the user running the server.

  • onFinished() is called when the search process has completed successfully.

  • onRelease() is called when the search is completed or when it has timed out. This is typically used to clean up the object.

12.4.6.1. Probing a Running Server

The information from ServerFinder only gives you numeric address and port to pass into BWConnection::logOnTo(), and the numeric Unix user ID of the user running the server instance. It is possible to probe the server to provide more information, such as the name of the machine running LoginApp, and the username of the user running the server. This can be done by sending a server probe using the ServerFinder's sendProbe() method.

Server probe results are handled by a subclass of the ServerProbeHandler interface class. The relevant virtual methods to implement are:

  • onKeyValue()

    This is used to get results for a particular key-value result from the probe. Keys are:

    • hostName

      The name of the LoginApp machine.

    • ownerName

      The name of the user running the server instance.

    • usersCount

      The number of successful logins processed by this LoginApp.

    • universeName

      Not used, present for backwards compatibility.

    • spaceName

      Not used, present for backwards compatibility.

    • binaryID

      Not used, present for backwards compatibility.

  • onSuccess()

    This is called when the probe has completed successfully.

  • onFailure()

    This is called when the probe has timed out or otherwise failed.

  • onFinished()

    This method is called after either onSuccess() or onFailure() is called, and should be used to clean up the probe handler object.

12.5. Example Clients

BigWorld provides example source code to illustrate how to integrate with the BigWorld server from other client applications. These example clients are found in the bigworld/src/examples/client_integration directory.

12.5.1. python/simple

This example client is a barebone application that connects to a BigWorld server, and illustrates a minimal amount of effort required to connect to the server and send player movement, and how to apply property updates to Python-based entities.

This example is compilable under Linux and Windows.

12.5.2. c_plus_plus/sdl

The SDL example is a simple client that provides a top-down GUI using the Simple Directmedia Library library (http://www.libsdl.org) to connect to a FantasyDemo server.

It uses the ProcessDefs tool to generate entity code.

This example is compilable under Linux and Mac OS X. It requires the SDL and SDL_image libraries.

Under CentOS Linux, these libraries can be installed by installing the SDL-devel and SDL_image-devel packages.

Mac OS X framework libraries for SDL and SDL_image and instructions on how to install them can be found at on the SDL site.

In order to run the example, the resource paths for FantasyDemo need to be specified on the command line as well as the server address, for example:

$ ./client_integration -r ../../../../fantasydemo/res -r ../../../res -s localhost

When running under Xcode, you will need to set these command line arguments in the client_integration scheme Run Arguments Arguments Passed On Launch.

12.5.3. c_plus_plus/ios

This example is a simple iOS client that connects to a FantasyDemo server, and offers a top-down GUI to visualise the client-side area of interest.

The project file is located in bigworld/src/examples/client_integration/c_plus_plus/ios/FantasyDemo.xcodeproj. It requires XCode 4.3 and above, and the installation of the optional XCode Command Line Tools. To install, go to Preferences Downloads Components, and install the Command Line Tools component.