System Areas

From HEWIKI
Jump to: navigation, search

Contents

System areas are discrete area processes dedicated to a specific type of game processing (you can think of these as providing "services"). Many such areas need access to information about players and/or areas that is typically only available from the world area/instance. For example your game may implement a system area that is responsible for tracking all of the character groups that players have formed. Such a system needs to track where characters are and then notify group members when others move between areas or log off. Registering that area as a system area through the $WORLD system node greatly simplifies the process of implementing those mechanics.

Overview

This mechanism assists implementors of system areas by providing them with access to information that would normally only be available through remote calls to the world server. This has secondary benefit of reducing the need for scripters to write potentially dangerous code that runs on the world server, which obviously increases the stability of that server.

It should be noted that this mechanism still uses asynchronous remote calls to transmit data, so can not guaratee the veracity of that data. This means that system areas still need to be built with the expectation that their information is out of date, and that they may need to recover from failed actions. More detailed information on this is provided in the section below called The Fine Print.

Quick setup

To set an area up to receive area change notifications from the world, execute the following code in that area:

$WORLD._RegisterSystemArea( AREA )

This will cause the $WORLD system node to be updated with changes to area/instances as they are launched, as they successfully spin up, and as they spin down. To get updates about player data, execute the following:

$WORLD._RegisterSystemArea( PLAYER )

This will cause the $WORLD system node to be updated with changes to players as they log on, move between areas, log off, or are unexpectedly disconnected. Additionally, this will allow the system area to message a player via $CHAT.ChatPlayer() or MsgPlayer(), or to remote call to a player's client without having that player loaded in the local GOM.

Updates received as a result of the above calls enable a variety of informational methods that are described below.

It is important to note that registration as a system area is not persisted, so must be done whenever an area spins up for the first time after the world has spun up. The best place to do this is in the HE_PostOnAreaLoad() callback (see Connection Logic).

Advanced setup

Registered system areas can also receive explicit notification of change events (see Observer Pattern). While some system areas simply need to know how to find a player who is online, or be able to identify what areas are currently spun up, some systems need to react to changes in that information. The example "groups" system area mentioned in the opening paragraph is such a system. Whenever a character who is part of a group arrives in a new area, the system area wants to react by sending that information to the other members of the character's group. To do this, the system's implementer needs to create an appropriate listener and implement the necessary shared function that will be called when an event occurs. Creating an event is a single line of code:

var myListener = $WORLD._CreatePlayerDataSystemAreaListener( 0, SYSTEM.EXEC.THISSCRIPT )

Specifying 0 indicates that our listener cares about all players. If for some reason the system only cared about a specific character, it could specify an account ID, and only those events involving that account would trigger the shared function call.

In the script that you specify when creating a listener, you must implement the following shared function:

shared function EventRaisedNotify( world as NodeRef of Class ObsSubject, listener as NodeRef of Class ObsListener, data as NodeRef )
  where data
    is kindof _PlayerDataSystemAreaEvent
 
    .
    is kindof _AreaDataSystemAreaEvent
 
    .
    default
      // handle unknown data type
    .
  .
.

This function will be called in your system area whenever an event occurs that matches one of your listeners.

To receive notification of all area change events, create the following listener:

var myListener = $WORLD._CreateAreaDataSystemAreaListener( 0, 0, SYSTEM.EXEC.THISSCRIPT )

When the specified area id is 0, then the instance id is ignored. The script will receive all events for all instances of all areas.

As with player data you can create a listener for a specific area/instance to receive notification about, like so:

var myListener = $WORLD._CreateAreaDataSystemAreaListener( myAreaID, myInstanceID, SYSTEM.EXEC.THISSCRIPT )

The script will only receive events pertaining to that instance of that area. You could create a child class of _AreaDataSystemAreaEventListener which overrides the IsListenerInterested() and IsAlreadyListening() methods to allow for specifying that the script should receive all events of all instances of that one area. In that case, you would need to replace _CreateAreaDataSystemAreaListener() with a method which uses that new class.

When a listener is created, a reference to is it passed back to allow the system implementer to glom additional data to it for future use, presumably during the event notification. Note that creating listeners automatically adds them to the $WORLD system node, which is their subject. You do not need to add them yourself, as you might with other systems that use the event notification system.

The Event Data

When EventRaisedNotify() is called, the following information will contain information that is relevant to the event type, as described here.

_PlayerDataSystemAreaEvent Data

There are four pieces of data available for player change events:

_AreaDataSystemAreaEvent

There are three pieces of data available for area change events:

$WORLD Fields and Methods

Registering a system area enables a variety of information on the $WORLD system node that would otherwise only be available by making remote calls to the world server.

Area

Field: _knownAreaInstances

This is a LookupList indexed by ID of List of ID that maps area IDs to a list of spun up area/instance IDs.

Field: _knownLaunchingAreaInstances

This is a LookupList indexed by ID of List of ID that maps area IDs to a list of launching area/instance IDs.

Field: _knownAreaNames

This is a LookupList indexed by ID of String that maps known area IDs to their area names. A "known" area ID is one that can be found in either the _knownAreaInstances or _knownLaunchingAreaInstances field.

Method: _SpinUpState()

_SpinUpState( areaID as ID, instanceID as ID ) as Enum _AreaSpinUpStates

This method will tell you the current state of a given area/instance. The valid states are: UP, LAUNCHING, and DOWN. UP This means that the area/instance is currently running. LAUNCHING This means that a request to launch the area/instance has started, but that the area has not yet finished the spin up process. DOWN This means that the area/instance is not currently running.

Method: _GetAreaName()

_GetAreaName( areaID as ID ) as String

This method returns the name of the specified area, if at least one instance of that area is running.

Player fields and methods

Field: _knownPlayers

This is a LookupList indexed by ID of Class _KnownPlayerData that maps online account IDs to a class variable containing a variety of information about the account and character attached to that account. The fields available on the class variable are:

Field: _knownNames

This is a LookupList indexed by String of ID that maps character names to their account IDs.

Field: _onlinePlayers

This is a List of ID that holds the raw list of all players who are currently online.

Method: _IsPlayerOnline()

_IsPlayerOnline( accountID as ID ) as Boolean

This method returns true if the specified account is currently online.

Method: _WhereIsPlayer()

_WhereIsPlayer( accountID as ID ) as Class _AreaInstance

This method returns a class variable of type _AreaInstance where the specified account's character is currently active. The fields available on this class variable are:

Method: _GetCharacterName()

_GetCharacterName( accountID as ID ) as String

This method returns the name of an online account's currently active character.

Method: _GetAccountName()

_GetAccountName( accountID as ID ) as String

This method returns the unique logon identifier of an online account.

Method: _FindPlayerByName()

_FindPlayerByName( characterName as String ) as ID

This method returns the account ID for the specified character.

The Fine Print

System Area Status

Any area that is to be registered as a system area should be one that is always up (done via the KeepAreaUp() external function.) Barring that, when your system area spins down you must unregister itself as a system area using the following:

$WORLD._UnregisterSystemArea( AREA )

and/or

$WORLD._UnregisterSystemArea( PLAYER )

Unregistering a system area causes all data on the $WORLD system node to be cleared, and automatically cleans up any event listeners that you have created.

System areas with multiple instances

It is important to note that areas are registered as system areas, not specific area/instances. If your system area maintains multiple instances of itself in order to distribute processing load, all instances of the area will independently receive data updates and have appropriate events raised.

Information May Be Out of Date

As mentioned earlier, this mechanism uses asynchronous remote calls to transmit data, so can not guaratee the veracity of that data. This means that system areas need to be built with the expectation that their information is out of date, and that they may need to recover from failed actions. For example, a system area that makes a remote call to the location of a character may find that the character is no longer present in the area by the time remote call arrives. In such cases the system in question needs to notify its system area that the action failed, and needs to be reattempted. When it does this, it should transmit the original information back to the system area, so that the area can check whether or not it still thinks that information is correct. If the original information and the current information do not match, then the system area can expect that the current information is correct, and it can re-attempt the original action using it.

If the original information and the current information match, there is a strong likelihood that the system area's data has somehow been corrupted or gotten out of synch, and therefore needs to refresh itself from the world. To do this the system can simply re-register as a system area.

$WORLD._RegisterSystemArea( AREA )
$WORLD._RegisterSystemArea( PlAYER )
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox