Proxied node

Revision as of 18:33, 23 July 2012 by ScottZarnke (Talk | contribs)
Jump to: navigation, search



Proxy Nodes are primarily used to support Seamless World.

A Proxied node is a Node that is created as a surrogate for another node. The proxy represents the Node it is a surrogate of, but in another GOM; more specifically in another Area Instance than the actual Node it represents. For example a Node can exist in Area 1 and have proxy nodes in Area 2, and 3. In this way, scripts in areas 2 and 3 can interact with the proxy of the node in 1 through it's surrogate proxy nodes in their GOM. As illustrated by this example, a node can have multiple proxies.

The most common types of nodes that have proxies are related to player characters. And, in fact, there is special handling for these so that their replication groups can stay intact as they move between areas. Creatures and NPCs are also commonly replicated, but you can script any sort of other node to also take advantage of proxies. By far the most common reason to do this is to provide a Seamless World experience for the player.



Proxied Class Design

There are two basic options to consider when designing the way your game data is proxied. You may choose to have proxies instantiated from the same class as the source node or you can design a lighter weight class that contains only the fields that you want the proxied node to have. As a general rule, it is more efficient to proxy to a lightweight class that contains only the member fields that belong on the proxy.

The diagram depicts the creation of a lightweight class that is intended to be used when proxying the class Foo. Lightweight Foo would include all of the fields that are intended to be replicated to the proxied node as well as any fields that are intended for use locally whether source or proxied node. Foo's class definition would then have the Destination Class (Server) set to be Lightweight Foo. Foo inherits Lightweight Foo so we can write code that is agnostic to whether it is working with a proxy or the source by casting the node to be Lightweight Foo.

Specify the Instantiation Class for a Proxy Node


The class used when instantiating a proxied node is determined by the base class of the source node as specified in its DOM definition. The DOM Editor is used to set the Destination Class(Server) property for your class.

For classes that are GLOMmed onto the original node, their destination class is GLOMmed onto the proxied node just as they are GLOMmed on the source.

Initiating Proxying

The initiation of proxying for a source node (and/or its hierarchy) to one or more destinations is tied to the underlying mechanics of server-to-server replication.

Mechanically the following conditions must exist for server-to-server replication to function:

Controlling what is proxied and when the proxying is initiated is fully under the control of HSL systems. The MMO Foundation Framework implementation of Seamless world 1.0 initiates proxied based on the awareness of an entity placed in the default Spatial Awareness System by a Seamless area link.


The MMO Foundation Framework's implementation of the account node includes a method to retrieve the default replication group used for introduction of the account hierarchy to observing clients and areas. By default, the replication group includes the nodes: _playerAccount (primary), _playerCharacter, _characterAppearance and the _ACCController. The following code snippet results in the proxying of those nodes to the specified destination area.

var repGroup = account._getReplicationGroup( false )
repGroup._addServerDestination( areaID, instanceID )

Method modifiers

See also: Function/method modifiers

Methods called on a proxied mode must have a specific keyword modifier, to indicate whether the method is to be run on the target area instance server process (where the actual proxied node is located), or on the source area server process (where the original node is still located). Relevant modifiers are:

Asynchronous Considerations for Proxied Nodes

The decision to use proxied nodes in your game design imposes certain implementation decisions upon your game systems. Specifically, for anything operation that should work with both real nodes and proxied nodes, the interface you script must be asynchronous. This is because a methods called on the proxy will forward to the real node in its GOM. The results of that method call will not be reflected on the proxy immediately as there is a round-trip for any field updates, and so forth.

You can change fields on a proxied node, however these changes do not reflect to the real node or any other associated proxies. In fact, if the field is replicated from the source node, and it updates, then any change you made on the proxy would get clobbered by the replication update. Sometimes it might make sense to change a field on a proxy node and then use proxyForward method call to change it on the real node too. This technique can be useful in some situations.

No changes to fields on the proxy node are persisted, regardless of the write strategy on the field. Only the source node persists.

Asynchronous vs Synchronous: setHealth()

Your game may have a method setHealth() that is used by combat to apply the result of changes to health based on attacks or healing received. When an attack occurs, you might set the character's health the current value - X.

setHealth() the Wrong Way

method setHealth( newHealth as float )
  me.currentHealth = newHealth

This is not the correct way to implement this method for a game that uses proxies.

All of these issues demonstrate why we need to perform the adjustment in an asynchronous matter that is communicated to the authoritative GOM containing the source node.

setHealth() the Right Way

proxyForward method adjustHealth( value as float )
  me.currentHealth = me.currentHealth + value

First you may notice that we have renamed the method, instead of setting absolute health we are now adjusting health by a value and consequently have named the method adjustHealth(). The proxyForward modifier tells the engine to package up the call and forward it (asynchronously) to the source node when called on a proxy. Once forwarded, we are now adjusting the node in the GOM that is authoritative and we can add the specified value to the source node's currentHealth field.

Once currentHealth is modified, we depend on replication to send out notification to all of the proxies to change their locally cached value.

Send a Remote Procedure Call to All Proxies

The HeroScript call statement provides a way to send a remote call to every proxy instance of a given source node. This is a handy way to share events with nearby seamlessly connected areas.

function sample(n as NodeRef, sampleParam as Boolean)
  call serverReplicas n.SampleMethod(sampleParam)

The class methods script for the class from which the proxy was instantiated would need to have implemented a method marked as both remote and proxyLocal.

remote proxyLocal method SampleMethod( sampleParameter as string )

Player Reference Tokens

Player Reference Tokens enable communication to clients other than ones in the current area. This is used extensively for seamless operation, and has been automated for the common case of replicated account nodes. So, as long as a player's account node is being replicated to an area, that area can send chat, remote calls, and replicate information to that player. Script systems that maintain Player Reference Tokens should continue to work independent of this.


External Functions

external function IsProxyNode( node as NodeRef ) as Boolean
// Returns a list of arrays of ids.  first element in array is the area number, second element is the instance id
// Non replicated nodes will return an empty list
external function SourceAreasOfNode(node as NodeRef) as List of Array[2] of ID

See also

Personal tools