bw logo

Chapter 9. Scripting

The facilities provided to scripts are of extreme importance, as they determine the generality and extensibility of the client. To a script programmer this environment is the client; just as to an ordinary user, the windowing system is the computer.

The scripting environment offers a great temptation to try to write the whole of a program in it. This can quickly make for slow and incomprehensible programs (especially if the same programming discipline is not applied to the scripting language as is to C++). Therefore, we recommend that a functionality should only be written in script when it does not need to be called at every frame. Furthermore, where it is global, it should be implemented in the personality script. So, for example, a global chat console would be implemented in the personality script, whilst a targeting system, which needs to check the collision scene at every frame, is best implemented in C++.

Importantly, the extensive integration of Python throughout BigWorld Technology allows for both rapid development of game code, and enormous flexibility.

Note

Garbage collection is disabled in BigWorld's Python integration, because garbage collection is an expensive operation that can occur at any time, blocking the main thread and causing frame rate spikes for example.

9.1. Functional components

This section describes the contents and services of the (general) C++ entity, from the point of view of a script that uses these facilities. The functional components of an entity, described in the following sections are:

  • Entity Skeleton

  • Python Script Object

  • Model Management

  • Filters

  • Action Queue

  • Action Matcher

  • Trackers (IK)

  • Timers and Traps

9.1.1. Entity skeleton

The Entity class (entity.cpp) is the C++ container that brings together whatever components are in use for a particular entity. It is derived from Python object and intercepts certain accesses, and passes those it does not understand on to the user script. This allows scripts to call C++ functions on themselves (and other entities) transparently, using the 'self' reference. The same technique of integration has been used in the cell and base components of the server.

This class handles any housekeeping or glue required by the component classes — it is the public face of an entity as far as other C++ modules are concerned.

The data members of this class include id, type, and position.

9.1.2. Python script object

This is the instance of the user-supplied script class. The type of the entity selects the class. It stores type-specific data defined in the XML description of the entity type, as well as any other internally used data that the script wishes to store.

When field data is sent from the server, this class has its fields automatically updated (and it is notified of the change). When messages are received from the server (or another script on the client), the message handlers are called automatically. The entity class performs this automation — it appears to be automatic from the script's point of view.

9.1.3. Model management

A model is BigWorld's term for a mesh, plus the animations and actions used on it.

The model management component allows an entity to manage the models that are drawn and animated at its position. Models can be attached to each other at well-defined attachment points (hard points), or they can exist independently. A model is not automatically added to the scene when it is loaded — it must be explicitly put in it.

An entity may use any number of independent (disconnected) models, but most will use zero or one. Those that use more require special filters to behave sensibly. For details, see Filters.

The best way to understand models is t`o be acquainted to their Python interface, which is described in the Client Python API's entry Main Client BigWorld Classes PyModel. For more details, see Models.

9.1.4. Filters

Filters take time-stamped position updates and interpolate them to produce the position for an entity at an arbitrary time.

BigWorld provides only the Filter base class. The game developer would derive game-specific filters from this. Each entity can then select one type of filter for itself from the variations available. It can dynamically change its filter if it so desires.

Whenever a movement update comes from the server, it is handed over to the selected filter, along with the time that the (existing) game time reconstruction logic calculated for that event.

The filter can also be provided with gaps in time and transform, i.e., 'at game-time x there was a forward movement of y metres and a rotation of z radians lasting t seconds'. The filter (if it is smart enough) can then incorporate this into its interpolation.

The filter can also execute script callbacks at a given time in the stream.

Filters are fully accessible from Python.

9.1.5. Navigation

BigWorld provides access to some navigation methods by the client scripts. BigWorld.navigatePathPoints() will return a list of points along the path between the given source and destination points, and BigWorld.findRandomNeighbourPoint() and the related BigWorld.findRandomNeighbourPointWithRange() will return a random point in a connected navmesh, which will be navigable from the given point.

These methods are provided for the client in order to allow some processing to be moved away from the server, and to allow movement to be more responsive, removing the need to wait for the server to provide a path.

For more details about navigation in BigWorld, refer to the Server Programming Guide's section Navigation System.

9.1.5.1. Configuring a Space to Use Navigation

If the client-side navigation methods are not used, loading the navmeshes would cause unnecessary additional memory usage (usually 10-50mb). For this reason, navigation meshes will not be loaded by default. Each space that will use navigation must be configured to do so. Add the following section to the space.settings file of any space that will use client-side navigation:

<clientNavigation>
    <enable>  true  </enable>
</clientNavigation>

This will ensure that the client will load any navigation meshes stored with the chunk data.

For more details about this space.settings option, see the File Grammar Guide's section space.settings.

9.1.5.2. Distributing Navigation Meshes with the Client

Note

If client-side navigation is not enabled for a space, then ResPacker will strip the navigation meshes from the cdata files for the client package. This is to keep the chunk resource files as small as possible for distribution.

9.1.5.3. BigWorld.navigatePathPoints()

BigWorld.navigatePathPoints() will take source and destination points, and return a path of points between them, such that moving to each in turn will result in an entity successfully navigating to the destination.

The method has the following syntax:

navigatePathPoints( src, dst, maxSearchDistance, girth )

The arguments are as follows:

  • src

    Vector3 containing the source point in the current space.

  • dest

    Vector3 containing the destination point in the current space.

  • maxSearchDistance

    float containing the maximum distance that will be searched for a path, from the source point. This deafaults to 500.

  • girth

    float containing the navigation girth grid to use. This defaults to 0.5 if not supplied. The girth is the minimum width of the path, and is used to ensure that large entities can not navigate through areas that are too narrow for them. This value must correspond to one of the girth entries in the girths file, which is located at bigworld/res/helpers/girths.xml by default.

BigWorld.navigatePathPoints() returns a list of Vector3 points containing the path. If a path can not be found it will raise an exception.

For example, the following call will return a list of points along the path between (100,10,200) and (150,20,50) if it exists. The path must be at least 4m wide at all points, and must be less than 300m in total:

BigWorld.navigatePathPoints( (100, 10, 200), (150, 20, 50), 300, 4 )

The path will be returned as a list:

[(100,10,200), (121,3,148), (133,9,87), (144,8,61), (150,20,50)]

9.1.5.4. BigWorld.findRandomNeighbourPoint()

BigWorld.findRandomNeighbourPoint() will take a source point, and return a random point in a connected navmesh. The resulting point is guaranteed to be connected to the source.

The method has the following syntax:

findRandomNeighbourPoint( position, radius, girth )

The arguments are as follows:

  • position

    Vector3 containing the source point in the current space.

  • radius

    float containing the maximum distance that will be searched for a path, from the source point.

  • girth

    float containing the navigation girth grid to use. This defaults to 0.5 if not supplied. The girth is the minimum width of the path, and is used to ensure that large entities can not navigate through areas that are too narrow for them. This value must correspond to one of the girth entries in the girths file, which is located at bigworld/res/helpers/girths.xml by default.

BigWorld.findRandomNeighbourPoint() returns a Vector3 containing the random point. If an appropriate point can not be found it will raise an exception.

For example, the following call will return a random point within 300m of the point (100,10,200). The path to this point must be at least 0.5m wide at all points.

BigWorld.findRandomNeighbourPoint( (100, 10, 200), 300, 0.5 )

9.1.5.5. BigWorld.findRandomNeighbourPointWithRange()

This method performs the same functionality as BigWorld.findRandomNeighbourPoint(), but takes an additional argument specifying a minimum radius. This allows the caller to specify a specific range for the distance to the random point.

The method has the following syntax:

findRandomNeighbourPoint( position, minRadius, maxRadius, girth )

The arguments are as follows:

  • position

    Vector3 containing the source point in the current space.

  • minRadius

    float containing the minimum distance that will be searched for a path, from the source point.

  • maxRadius

    float containing the maximum distance that will be searched for a path, from the source point.

  • girth

    float containing the navigation girth grid to use. This defaults to 0.5 if not supplied. The girth is the minimum width of the path, and is used to ensure that large entities can not navigate through areas that are too narrow for them. This value must correspond to one of the girth entries in the girths file, which is located at bigworld/res/helpers/girths.xml by default.

BigWorld.findRandomNeighbourPoint() returns a Vector3 containing the random point. If an appropriate point can not be found it will raise an exception.

For example, the following call will return a random point further than 200m, but within 400m of the point (150, 20, 50). The path to this point must be at least 4m wide at all points.

BigWorld.findRandomNeighbourPoint( (150, 20, 50), 200, 400, 4 )

9.1.6. Action Queue

The action queue is the structure within the BigWorld Technology framework that controls the queue of actions in effect on a model (actions are wrapped by ActionQueuer objects that are contained by the action queue).

The ActionQueue deals with the combining of layers and also applying the appropriate blend in and blend out times.

The ActionQueue also deals with any scripted callback functions that are linked to the playing of an action, like for example calling sound-playing callbacks at particular frames in an action.

An action is described in XML as illustrated the example .model file below (model files are located in any of the various sub-folders under the resource tree <res> , such as for example, <res>/environments, <res>/flora, <res>/sets/vehicles, etc...):

<action>
   <name>          ACTION_NAME     </name>
  ?<animation>     ANIMATION_NAME  </animation>
  ?<blendInTime>   float           </blendInTime>
  ?<blendOutTime>  float           </blendOutTime>
  ?<filler>        [true|false]    </filler>
  ?<track>         int             </track>
  ?<isMovement>    [true|false]    </isMovement>
  ?<isCoordinated> [true|false]    </isCoordinated>
  ?<isImpacting>   [true|false]    </isImpacting>
  ?<match>
    ?<trigger>
      ?<minEntitySpeed> float  </minEntitySpeed>
      ?<maxEntitySpeed> float  </maxEntitySpeed>
      ?<minEntityAux1>  float  </minEntityAux1>
      ?<maxEntityAux1>  float  </maxEntityAux1>
      ?<minModelYaw>    float  </minModelYaw>
      ?<maxModelYaw>    float  </maxModelYaw>Coor
      ?<capsOn>  capabilities  </capsOn>
      ?<capsOff> capabilities  </capsOff>
     </trigger>
    ?<cancel>
      ?<minEntitySpeed> float  </minEntitySpeed>
      ?<maxEntitySpeed> float  </maxEntitySpeed>
      ?<minEntityAux1>  float  </minEntityAux1>
      ?<maxEntityAux1>  float  </maxEntityAux1>
      ?<minModelYaw>    float  </minModelYaw>
      ?<maxModelYaw>    float  </maxModelYaw>Coor
      ?<capsOn>  capabilities  </capsOn>
      ?<capsOff> capabilities  </capsOff>
     </cancel>
    ?<scalePlaybackSpeed>  [true|false] </scalePlaybackSpeed>
    ?<feetFollowDirection> [true|false] </feetFollowDirection>
    ?<oneShot>             [true|false] </oneShot>En
    ?<promoteMotion>       [true|false] </promoteMotion>
   </match>
</action>

Example .model file describing action

The list below describes some of the tags in the XML file:

  • name

    Name of that action as used by a script.

    These are available as named 'constants' off the model object returned by the Model Manager.

  • animation

    The base animation whence the frame data is sourced.

  • blendInTime

    Time in seconds the action takes to completely blend in.

  • blendOutTime

    Time in seconds the action takes to completely blend out.

  • filler

    Specifies if the action is just padding and can be interrupted if anything else comes on the queue.

  • track

    Track number in which the action should be played.

    If the action has a track, then the animation is blended on top of whatever other animations exist — i.e., it bypasses the queue.

  • isMovement

    Specifies that the action uses a simple movement animation such as walk, run, side-step, etc. The translation must be linear, and is subtracted from the action when played (so a run animation which moves from the origin will now appear to run on the spot). This setting requires the PromoteMotion flag to be set, and doing so means this translation then moves the model accordingly. If the model is owned by a client-controlled Entity, then the server-side entity's position will be updated accordingly. This setting allows the use of scalePlaybackSpeed. This setting cannot be used with isCoordinated and isImpacting.

  • isCoordinated

    Specifies that the action's animation starts from an offset position. Used for actions that require coordination with a non-player character (NPC), which needs to be positioned relative to the player's character for the purpose of matching contact points (e.g. shaking hands). This setting cannot be used with isMovement and isImpacting.

  • isImpacting

    Specifies that the action is a complex (non-linear) movement animation. If the entity is client-controlled, then its position on the server will also be updated. Examples of animations used with isImpacting are jumping, combat and knockdowns, interacting with entities, etc. This setting requires PromoteMotion and cannot be used with isMovement and isCoordinated.

  • match

    If this section is present, it means the Action Matcher can automatically select the action (see below).

  • trigger (section match)

    This section defines criteria used to determine when to start an action.

  • minEntitySpeed (section trigger)

    Determines the minimum velocity of the entity for the action to start.

  • maxEntitySpeed (section trigger)

    Determines the maximum velocity of the entity for the action to start.

  • minEntityAux1 (section trigger)

    Determines the minimum pitch of the entity for the action to start.

  • maxEntityAux1 (section trigger)

    Determines the maximum pitch of the entity for the action to start.

  • minModelYaw (section trigger)

    Determines the minimum yaw of the model for the action to start.

  • maxEntityYaw (section trigger)

    Determines the maximum yaw of the model for the action to start.

  • capsOn (section trigger)

    Determines which special case character states need to be on for the action to start.

  • capsOff (section trigger)

    Determines which special case character states need to be off for the action to start.

  • cancel (section match)

    This section defines the criteria used to determine when to stop an action.

  • minEntitySpeed (section cancel)

    Determines the minimum velocity of the entity for the action to stop.

  • maxEntitySpeed (section cancel)

    Determines the maximum velocity of the entity for the action to stop.

  • minEntityAux1 (section cancel)

    Determines the minimum pitch of the entity for the action to stop.

  • maxEntityAux1 (section cancel)

    Determines the maximum pitch of the entity for the action to stop.

  • minModelYaw (section cancel)

    Determines the minimum yaw of the model for the action to stop.

  • maxEntityYaw (section cancel)

    Determines the maximum yaw of the model for the action to stop.

  • capsOn (section cancel)

    Determines which special case character states need to be on for the action to stop.

  • capsOff (section cancel)

    Determines which special case character states need to be off for the action to stop.

  • scalePlaybackSpeed (section match)

    Specifies that the animation playback speed should be scaled as a function of the entity's speed. This setting requires isMovement.

  • feetFollowDirection (section match)

    Specifies that the model should turn to track the Entity. In practice this means while this action is matched, the model rotates on the spot instead of playing a turning action.

  • oneShot (section match)

    Specifies that the action will only be selected for playing once in a row by the action matcher. Note the distinction between this and filler, where filler is not related to the action matcher.

  • promoteMotion (section match)

    Specifies that the motion of the root node within the animation should affect the model's position (and the owner entity's position, if the entity is client-controlled). This setting must be enabled for isImpacting or isMovement actions to work correctly. This setting cannot be used with filler.

The Python interface to a model's action queue allows actions to be played directly on that model, or a set of actions to be queued and played in sequence. Callback functions can be defined and played when actions are finished.

In Python, a model can be easily created and an action played on it, as illustrated in the example below:

class Jogger( BigWorld.Entity ):
  ....
def __init__( self ):
  self.model = BigWorld.Model( "jogger.model" )

def warmUp( self ):
  self.model.action( "StretchLegs" )()
...

Model creation in Python

9.1.6.1. Debugging animations

If a model is not being animated as it is supposed to, it is useful to display the Action Queue graph in the Python console.

This is can be done by calling BigWorld.debugAQ() method, which can receive two kinds of arguments:

  • PyModel

    Displays the graph for the specified model, with the blend weight of each action. Each action is represented in a different, arbitrarily chosen, colour.

  • None

    Switches off the graph display.

Python console displaying Action Queue's debugging graph

The graph in the picture above displays the execution on the TurnLeft animation (in green) and the Idle one (in red). We can determine the animations that were being played in each labelled point in the graph:

  • A — 100% of the Idle animation is being played.

  • Between A and BIdle animation is being blended in with TurnLeft animation.

  • B — 50% of the Idle animation is being played, and 50% of the TurnLeft animation is being played.

  • C — 100% of the TurnLeft animation is being played.

For more details, see the Client Python API.

Note

Model Editor offers the same functionality for the model. For details, see the document Content Tools Reference Guide's section Model Editor Panel summary Actions panel.

9.1.7. Action Matcher

Given a model, an action queue, and a set of actions, all behaviour of a game object/character can be specified by event-driven calls on the Action Queuer. This ends up with a heavy overhead, as many changes in object state need to directly call the object and solve which animation should be played.

The solution to this problem is to internalise most of the behaviour of a character in a system called the Action Matcher, which automatically updates an object's motion based on the object's state. It is a simple pattern matcher, picking an animation based on model's attributes such as speed, direction, etc.

State parameters such as speed, rotation, or power are exposed to the Action Matcher, which then selects the action that best maps to these parameters. This frees the game from having to handle many aspects of animation, allowing it to only have to update state parameters, such as position.

When there are no (unblended) actions in the Action Queue for a model (within the player's AoI), the Action Matcher takes over and plays an 'idle' action. It triggers these 'idle' animations to give the game world more life, since real living things are not still. It can also be used to automate menial animation tasks.

This class looks at all the actions that have a match section (see XML example in section Action Queue, whose constraints are satisfied for the Action Matcher object controlling the model.

Scriptable constraints are tested against the capabilities bit fields capsOn and capsOff. The Action Matcher for a model has a set of capability bits, which value is controlled by script. An action will only be matched if all the capsOn bits are on and all the capsOff bits are off in the Action Matcher's set.

It then looks at the change in pose (position and orientation — as set by the filter) and selects the first action that matches this change for the time over which the change occurred. The trigger constraints are used to test most actions. The cancel constraints are used if the action that matched last frame is encountered. This feature is intended primarily to reduce action hysteresis.

The update function of an action-matched object takes the previous updated position of the object, chooses the best matched action from its matched action list, then plays the animation back at the correct speed to smoothly link action with speed. As a game character starts moving faster, the Action Matcher may choose a faster running cycle to play back and increase its playback speed to precisely match speed so no foot sliding is seen.

This method allows an AI system to define behaviour with respect to a few variables such as orientation, speed, and aiming direction, and the Action Matcher will convert these updated parameters into a smoothly moving character.

In a client/server architecture where position and orientation are updated over a network, the Action Matcher (combined with a filter) can automatically compensate for position jumps caused by network lag by having characters realistically run faster to the latest updated position.

When an action is loaded, its data is augmented with the effect on pose that performing the action would have on the root node. This information is used for the matching described above.

Now that an action has been selected, it is passed to the Action Queue. If the action supplied is the same as the previous action, it continues to be played in the normal fashion (i.e., frame += fps*deltaTime). Otherwise, it is blended in over a few frames while the other is blended out.

9.1.7.1. Using the Action Matcher

Each action designed to be matched must define a <match> section. These are added via Model Editor using the Actions window. The matching parameters are divided in two:

  • Trigger parameters — Define when an action can be started, and

  • Cancel section — Defines when an action should be stopped.

The minEntitySpeed and minEntitySpeed tags in each section define the velocities in which actions can and cannot be triggered or cancelled.

The auxiliary parameters can be used to define a pitch range that is used to match action. The minModelYaw and maxModelYaw tags define a yaw range. The main matching parameters define speed and orientation ranges that the action applies to, and also a user-defined set of matching flags that are used with special case character states. These flags can be used to set whether a game character is not using the basic action set, such as being injured or being angry.

The BigWorld engine uses the matchCaps parameter to store the bitwise flag set of an action. At any given time, the model itself will have an on/off flag set representing the state of these states, and this is tested against each action's matchCaps per frame.

A set of user-defined action states should be defined (created as a text file or as comment section in model file). A simple example is given in the list below:

  • Capability flag: 1 — State: Angry

  • Capability flag: 2 — State: Happy

  • Capability flag: 3 — State: Sad

A set of angry animation can now be accessed using the action matcher by just adding the angry flag to the current matchCaps.

In Python code, a simple example of a character that should now move and behave in an angry manner is shown below:

class AngryMan( BigWorld.Entity ):
  ....
def onEnterWorld( self, prereqs ):
  self.am = BigWorld.ActionMatcher( self )

def enterAngryMode( self ):
  self.am.matchCaps = self.am.matchCaps + [1]
...

Python implementation of character in angry mode

By using the Action Matcher this way, a character's natural motion can be fleshed out without having to explicitly call any function to play animations. Specific event-based actions should still be called directly via the Action Queue structure, but the background behaviour of the character can be completely defined using the Model Editor tool and setting matching flags appropriately in the code base.

9.1.8. Trackers

A tracker applies inverse kinematics to nodes in the entity's model so that they appear to point to a position defined by a given 'target' entity. An entity may have any number of trackers.

To add a tracker to an entity, use a script call like this:

tracker = BigWorld.Tracker()
tracker.dirProvider = DiffDirProvider( 
  self.focalMatrix, target.focalMatrix )
tracker.nodeInfo = BigWorld.TrackerNodeInfo(
  model,
  primaryNode, 
  secondaryNodeList, 
  pointingNodeName,
  minPitch, maxPitch,
  minYaw, maxYaw,
  angularVelocity )
self.model.tracker = tracker

Adding tracker in Python

The parameters for the BigWorld.TrackerNodeInfo method are described below:

  • model

    PyModel that owns the nodes that the tracker will affect.

  • primaryNode

    Primary node reference.

    Node references are built up from the entity's independent model (the first one if there are multiple) following a path of attachment points and ending in a node name. This allows trackers to transparently work through attached models (i.e., they are treated as if they are welded onto the model's skeleton).

    This is more important for Supermodels (for more details, see SuperModel), where characters are built out of multiple model parts.

  • secondaryNodeList

    List of secondary nodes, containing tuples of the form (node, weight).

    These have the same transform performed on them as on the primary node, in proportion with the weight amount. Actually, all the weights (including the primary node, with a weight of 1.0) are summed, and each node gets their weight proportion of this total applied to them.

  • pointingNodeName

    Name of the node providing the frame of reference used for tracker manipulations.

    If the node specified is not present, then the model's scene root is used.

  • minPitch, maxPitch, minYaw, maxYaw

    Limits on the turn that the tracker is permitted to apply, in degrees.

  • angularVelocity

    Speed at which a tracker will turn the PyModelNode instances that it influences, in degrees per second.

9.1.9. Timers and Traps

These are generic helper services provided to entity scripts.

A script can set timers to have itself called-back at a certain time, as illustrated in the example below:

BigWorld.callback( afterTime, fn )

Traps use a slightly different interface:

trapRef = self.addTrap( radius, function )

A trap goes off if any entity wanders within the given radius of the entity it is created on, and can be cancelled with the self.delTrap method.

There are two other types of trap, optimised for their specific need, as discussed in the following sections.

9.1.9.1. Pot

A Pot is a 'player-only-trap', and is triggered only by the player entity. Due to this, it is a lot cheaper to use than a general trap.

A Pot is added given a matrix provider, a radius, and a script callback for triggering.

potHandle = BigWorld.addPot( trapMatrix, radius, callback )

9.1.9.2. Mat

A Mat is a 'matrix trap', and is triggered when an area is triggered by another. This makes sense only because matrix providers are dynamic. The areas are defined as:

  • Source-matrix translation and a bounding area given by the scale of the x-, y- and z-axes in that matrix.

  • Destination-matrix translation of destination matrix (treated as a point).

A Mat is defined in Python as listed below:

matHandle = BigWorld.addMat( sourceMatrix, callback, destMatrix )

9.2. Personality script

The personality script is a Python script used to handle several callbacks from the BigWorld engine for initialisation, cleanup, input handling, and environment changes. It can also implement client functionality that does not belong to any particular entity in the game, such as the game start screen.

Its name is defined in the file specified by the resources.xml's engineConfigXML tag, in the personality tag — for more details, see File <engine_config>.xml.

The personality script generally declares a class to contain all data to be shared by functions in the script, and declares a global variable using the constructor of that class. For example, a personality script may include the following code:

class SharedData:
  def __init__( self ):
    self.settings = ""

# initialise the shared data object for this personality script
sd = SharedData()

# This callback is called by BigWorld when initialising
def init( configSect ):
  # save the configSect object for later use
  sd.configSect = configSect

Example of personality script

The sections below describe the available personality callbacks.

9.2.1. init

The callback has the following syntax:

init(scriptsConfig, engineConfig, preferences, loadingScreenGUI = None)

The script is called once, when the engine initialises, and receives the arguments below:

  • scriptsConfig

    PyDataSection object containing data from XML file defined in resources.xml's scriptsConfigXML tag (for details, see File <scripts_config>.xml).

  • engineConfig

    PyDataSection object containing data from XML file defined in resources.xml's engineConfigXML tag (for details, see File <scripts_config>.xml).

  • preferences

    PyDataSection object containing data from the scriptsPreference section of the file specified in the preferences tag of the file specified in resources.xml's engineConfigXML tag (for details, see File <preferences>.xml).

  • loadingScreenGUI

    Optional argument representing the loading screen GUI, if one was defined in resources.xml (for details, see File <preferences>.xml).

The available read functions are listed below:

  • readBool

  • readFloat

  • readFloats

  • readInt

  • readInts

  • readMatrix34

  • readString

  • readStrings

  • readVector2

  • readVector2s

  • readVector3

  • readVector3s

  • readVector4

  • readVector4s

  • readWideString

  • readWideStrings

To read data from PyDataSection, call the read function that relates to the data type, passing in the section name as the first argument, and the default value as the second argument. The plural read functions (ending in 's') read the contents of all matching subsections of the specified section, and return the results as tuple of values. You can refer to sub-sections by using the forward slash.

For example:

username = userPreferences.readString("login/username", "guest")

You can also reference to subsections of a PyDataSection by calling the section name prefixed with an underscore.

For example:

username = userPreferences._login._username.asString

9.2.2. fini

The callback has the following syntax:

fini()

This is script is called when the client engine shuts down. It is used to do any cleanup required before the client exits. This is a good place to perform a logout procedure on the player to logout gracefully.

For example:

# note: you must set up a logOff method as a base method in the
# def file of the class that the player is using.
def fini():
  try:
    BigWorld.player().base.logOff()
  except:
    pass

Example of fini() implementation

9.2.3. handleKeyEvent

The callback has the following syntax:

handleKeyEvent( event )

The event argument is a PyKeyEvent which contains information about the key event. See the Python Client API document for details.

Generally, several systems can process keyboard input, so the arguments are passed to a handleKeyEvent method on each system in turn, until one returns a Boolean value of True, indicating that it has processed the key event.

For example:

def handleKeyEvent( event ):
  global rds

  # give the chat console a go first
  if rds.chat.editing:
    if rds.chat.handleKeyEvent( event ):
      return True
  # try the gui
  if GUI.handleKeyEvent( event ):
    return 1
  # now do our custom keys
  if not event.isKeyDown(): return False # we are not interested in key releases
  if event.key == KEY_RETURN and event.modifiers == 0:
    rds.chat.edit( True )  # bring up the chat console
    return True

  # return False because the key event has not been handled
  return False

Example of handleKeyEvent() implementation

Note that the engine also calls the handleKeyEvent method on the entity that the player is controlling. All keys related to player control are handled there.

9.2.4. handleMouseEvent

The callback has the following syntax:

handleMouseEvent( event )

This script is called whenever the mouse moves, and is given an instance of PyMouseEvent. It operates similarly to handleKeyEvent.

For example:

def handleMouseEvent( event ):

  # try the gui
  if GUI.handleMouseEvent( event ):
    return True

  # return False because the mouse event has not been handled
  return False

Example of handleMouseEvent() implementation

9.2.5. handleAxisEvent

The callback has the following syntax:

handleAxisEvent( event )

This script is called whenever a joystick axis event occurs, and is given an instance of PyAxisEvent.

For example:

def handleAxisEvent( event ):

  # try the GUI
  if GUI.handleAxisEvent( event ):
    return True

  # return False because the axis event has not been handled
  return False

Example of handleAxisEvent() implementation

9.2.6. handleIMEEvent

The callback has the following syntax:

handleIMEEvent( event )

This is called when an Input Method Editor (IME) related event occurs and is used to update the GUI respectively, and is given a PyIMEEvent object as it's first parameter. See Input Method Editors (IME) for details on IME support.

9.2.7. handleLangChangeEvent

The callback has the following syntax:

handleLangChangeEvent()

This event occurs whenever the current input language has been changed by the user. It is useful for tasks such as updating language indicators on GUI edit fields.

9.2.8. onChangeEnvironments

The callback has the following syntax:

onChangeEnvironments( inside )

This script is a callback acknowledging the environment type the player is currently in.

Currently there are only inside and outside environment types. The argument is a Boolean value indicating whether the player is inside or not. This may be useful for modifying the behaviour of the camera in third person mode.

For example:

def onChangeEnvironments( inside ):
  global sd
  sd.inside = inside
  sd.updatePivotDist()

9.2.9. onGeometryMapped

The callback has the following syntax:

onGeometryMapped(spaceID, spacePath)

This callback method tells the player entity about changes to the geometry in a space. It is called when geometry is mapped into any of the currently existing spaces on the client. The space ID and the name of the space geometry are passed as parameters.

The first parameter is the ID of the space the geometry is being mapped in to. The second parameter is the name describing the space's geometry.

9.2.10. onRecreateDevice

The callback has the following syntax:

onRecreateDevice ()

This script is a callback alerting the scripts that the Direct3D device has been recreated. This often occurs when the screen resolution is changed.

This callback was introduced primarily so that scripts can re-layout their GUI component scripts, but it is also useful for recreating any static PyModelRenderer textures (since these do not automatically update, unless they are dynamic).

For example:

def onRecreateDevice():
  (width,height) = GUI.screenResolution()
  myGuiController.doLayout( width, height )
  myRenderers.recreateTextures()

9.2.11. onTimeOfDayLocalChange

The callback has the following syntax:

onTimeOfDayLocalChange( gameTime, secondsPerGameHour )

This script is a callback to allow scripts to be notified of changes in the game time.

It is passed two floats as arguments: the first one is the game time in seconds, and the second is the number of real-time seconds per game hour.

9.2.12. start

The callback has the following syntax:

start()

This script is called after the engine has initialised, and used to start the game. It may be used to bring up a start menu, or login screen.