HeroEngine Forums
Welcome, Guest. Please login or Register for HeroCloud Account.

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - HE-JAY

Pages: 1 2 [3] 4 5 ... 9
Often-times, it makes sense to implement methods to manage replication groups on classes you intend to use with replication.  For example, the _playerAccount class has a method called _GetReplicationGroup which will - if instructed - create a replication group for the account and add the correct client destination (effectively setting the node up to be replicated).  You could use this as an example of how to neatly wrap replication group management for your own classes.

The procedure for replicating a server-side spec-derived object is:
  • Create the spec-derived object from a spec
  • Create (or otherwise get) a replication group that you want the spec-derived object to be a part of
  • Add the spec-derived object to the replication group either as the primary node or as a secondary node
  • Add a client destination to the replication group so nodes in that group get replicated to the client
  • Watch your spec-derived object appear on the client (and optionally respond to this replication by implementing _OnReplicationGroupAdded or _OnReplicationNodeAdded, respectively)

At this point, you can use your replicated spec-derived object on the client however you want.

If I understand your questions correctly, you're wondering how to ensure complex spec-derived (and decorated) objects can be replicated such that each decorator's fields will also replicate with the spec-derived object.

In truth, this is simple to accomplish (and you were correct in your approach).

In the case of SDOs with decorators, the decorated fields will be replicated for a node if:
  • The decorator's field definitions in the DOM have been set to replicate to a client-side field
  • The decorator class in the DOM has been set to replicate to a client-side class
  • The node is at some point replicated to the client

Boom. That's it.

Whether you glom the class before or after replication begins does not matter (in fact, if ChangeCallbacks is set to true, you'll get a callback in the event of glomming or unglomming a class).

Since the target of replication is individual nodes within a replication group, it stands to reason (and is true) that changing a field that belongs to a decorator class that has been glommed onto a replicated node will only replicate the change to recipients of that node's replication (phew!).  In short, glomming a decorator class which is configured for replication onto a replicated node will only update that node.

A few final notes to cover some other questions that came up:
  • Nothing on the client is persistent; this means hard-associations will only last until you shut down your client, and any nodes created on the client will cease to exist once the client shuts down
  • Since the spec system exists both on the client and the server, it is perfectly possible to use the spec system without touching replication (using a combination of marshaling and independently creating nodes on the client/server); however, replication takes a huge burden off of your shoulders by automatically managing the creation of replicated nodes, the glomming of decorator classes, and the synchronization of field data.
  • Sometimes there are very good reasons to use the spec system 'just' on the client; for example, instantiating a node intended solely for visualization or augmenting input handling for a client-side HBNode.

Hopefully this answered some (and hopefully all) of your questions. Feel free to follow-up if there's any lingering confusion!

From the work I've been doing with specs and spec decorators, here's the way I understand it.

- Spec oracles manage your specs with Base X

- Spec X can have SpecDec XY glommed onto it, or not, based on your choice for any particular spec of type X

- When Spec X is instantiated, it notifies all decorators glommed onto it that it is being created

- SpecDec XY receives notification, and thus gloms its own class Decorator XY onto Base X

- Your end result is a node composed of the composition of Decorator XY and Base X through glomming.

Correct on all counts.

The short and sweet version:
-Spec oracles manage specs
-Specs instantiate spec-derived objects
-Specs may be decorated by spec decorators
-Spec-derived objects may be decorated by decorator helpers
-The process of decorating specs is manual (via the editor), while the process of decorating spec-derived objects is handled via callback to spec decorators ("I (the spec) have instantiated node N; now I'm going to glom these helper classes onto node N as prescribed by my spec decorators")

It is true that base specs may act is parent classes for other spec classes.
It is also true that decorators (both spec and spec-derived) can act as parent classes for other decorators.

Server 20 serving EU West is undergoing emergency maintenance to correct a software issue.  We will update this thread with additional information as it becomes available.

What you propose (passing lookuplists manually back and forth from client to server) is certainly doable and one way of going about it, but I believe replication is a far surer bet.

Replication is - at base - a cleaner, more robust way of making remote calls from client-to-server (or vice-versa) when the intent is to deliver a piece of data or a message.  You 'could' send explicit calls every time something changes (placing the burden of managing that logic on script implementation), or you could set fields up to replicate automatically when they change (leveraging lots of nifty features like 'atomic sets', 'replication priority', etc) and then respond in script at the destination to process logic that results from the update.

Logically speaking, the object which 'owns' the data is also usually the correct object to own a replication group which replicates that data.  If your abilities belong to the player, the player's replication group (probably a private one replicated only to them) may be an appropriate home for such replications. You could also - if you desire - create an skill system anchor (or manager) which would individually replicate ability set nodes (or some-such) to players, but it stands to reason that "wherever the player goes, its skills go with him/her".

Design & World Building / Re: Creating a non-zoned world
« on: Feb 09, 12, 09:56:34 AM »
A comment about your "mirroring between zones"; if you plan to use HeroEngine's seamless world features, understanding the concept of 'proxy nodes' will be useful.  This is - effectively - the 'copying' you're talking about, where both the 'true' location of a player and all observing zones are able to see and interact with a player; after a transition, the local proxy is removed and replaced with the action player.  This can be used with non-account nodes, too, to proxy other objects you want to exist seamlessly.

You can read more about proxied nodes on the wiki:

The easiest way to think about this is to understand that 'parsed[2]' is a token in a string input.  While that input 'could' have included an ID in string form ("1928531983", for example), it could also have simply been a string ("edit", "clean", "new", etc). Since the line "targArea as ID = parsed[2]" casts the value of parsed[2] into an ID, any non-ID token will automatically evaluate to 0.

In short, this is a sneaky way of saying "If the input was not a number, test against these four strings", "otherwise... do other stuff."

Hopefully that makes sense. (:

Scripting & Programming / Re: Help understanding System Areas
« on: Feb 07, 12, 09:35:00 AM »
A simple example of initializing a System Area on spin-up might be that of an 'In-game Mail System Area'.

Such a system might need to load rules for processing mail, load a queue of pending mails for all players currently active in the system, spin up secondary system area instances to load-balance the processing of mail, etc.

Generally, initialization can be handled in a couple of different ways:
  • Overriding the $AREA._OnAreaLoad(...) method, which in turn will perform initialization actions like spinning up additional system area instances, loading arbitrary root nodes, starting timers, etc
  • Using remote calls into the system area from another area to trigger an action (such as initialization) to occur; examples of this could be 'when a player logs in, register them with the $MAIL system'
  • Use event-driven systems like replication or awareness systems to trigger loading/unloading of data or processing of data

With the mail example above, we might choose to override $AREA._OnAreaLoad(...) to load mail processing rules using a method 'LoadMailRules()' that we've defined on our $MAIL system node; we might also choose to spin up additional system area instances based upon some configuration defined in our $MAIL prototype or in script.  Finally, we might choose to respond to player awareness events (which we registered for when setting up our system area using $WORLD._CreatePlayerDataSystemAreaListener) by loading an arbitrary root node belonging to the player which contains all of the player's mail.

As for a more complete tutorial: we're always looking for ways to improve our wiki and documentation.  We have a long list of improvements we'd like to make, and creating better tutorials is high on our list of priorities.  As new resources become available, we'll keep the community informed.

Hopefully this helped!

When an account root node is moved from one area to another, it is unloaded in the old area and re-loaded into the destination area.  As a result, any non-persisted data attached to the account will be 'unloaded' (i.e. destroyed) immediately prior to the move.  Really, any data that needs to persist across area server boundaries should be persisted on the account (or any other arbitrary root node), in a system area, or communicated directly between the two areas.

Resources you might find useful:

Scripting & Programming / Re: Help understanding System Areas
« on: Jan 26, 12, 09:50:47 AM »
You are indeed understanding things correctly.

The basic procedure for setting up a system area is:
  • On world load, request the launch of an area instance (most likely the edit instance so you can modify persisted data)
  • As a response to this area spinning up, initialize your system area (from within the area), if needed; this can include registering for awareness of player and area events (in the case you want to do something when a player moves or logs in/out)
  • Now, perform computation-only operations in your system area, which can include replicating data to players, handling a particular kind of processing (chat, auctions, quests, etc).
  • Profit

There are other factors involved, such as how you want to persist data and whether you want to spin up helper instances to distribute load over large swathes of players, but these will depend heavily upon your game design.

Scripting & Programming / Re: Move a character ACCC
« on: Jan 24, 12, 03:13:52 PM »
As Cooper has mentioned, some of the systems involved in creating custom characters are highly intertwined.  Replacing 'just the controller' or overriding 'just the character creation system node' will lead to aberrant behavior like what you're seeing now.

At first glance, it appears that your character creation system node is not correctly instantiating a character appearance node for your character. This is generally handled in _CCSCreateVisibleCharacterNodeForCharacter in _CharacterCreationSystemClassMethods and is called once shortly after character creation.

If there was an error during the character creation process (which you'll see either in the Chat panel or Console panel), this character appearance node will not have been created and - for the rest of the session - other errors will be generated and likely flood the console.

The solution is to go back to your procedure for creating the character (which probably includes assigning your ShipController to your character) and find what errors - if any - are occurring. Possibilities are: you've got a script error in custom script which as attempting to reference a node that doesn't exist (or is of the wrong type); you're specifying an invalid character specification from which to instantiate a character appearance; or other logic is expecting to find an E_ACCController and is instead finding a ShipController_ACCController.

Finally, keep in mind that the E_ACCC class is the 'system node' $ACCC and is not the actual controller - this system node is what is used to determine which controllers to instantiate for which characters and should not be overridden with an 'actual' character controller. E_ACCController, on the other hand, IS the actual character controller and may be replaced with your new ShipController_ACCController. Make sure you understand the difference between the system node $ACCC and an individual character's controller.

Once you identify the errors that are occurring earlier in the process, feel free to post them here so I can give additional feedback; or, if you've already figured things out (yay!), feel free to post your solution for the rest of the community to learn from.


This can be accomplished by creating both a 'private replication group' and a 'public replication group'.  The only distinction between the two is which clients are included in the 'client destinations' list. This would be used most frequently to differentiate between - for example - a private inventory being replicated versus a public player position.

Introduction of a player to another player's replication group is - by default - linked to spatial awareness events.  It would be perfectly acceptable and logical to only respond by adding others to a player's public replication group while limiting the private group to a one-time initialization upon entering an area (as a simple example).

Scripting & Programming / Re: Member fields implementation
« on: Jan 24, 12, 01:41:20 PM »
To answer the original post's question:

There are usually two 'types' that are useful when defining a piece of data or functionality within the DOM: "Class" and "NodeRef of Class".  The former is equivalent to a 'struct'; it contains only data but no functionality.  The latter is equivalent to what you would normally think of as a reference to an 'object'; it has data 'and' functionality (functions/methods).

In order to have a meaningful 'NodeRef of Class', you must first have created the node to which you want to point to.  This usually means creating either a persisted node (which will always be around due to its association with other persisted data) or temporarily creating a non-persisted node and then setting the field to reference that node.

The take-away is:
  • Yes, you can have a field with type 'NodeRef of Class ______', and that will indeed allow you to access methods on the node, but you MUST initialize the reference by pointing to a node that currently exists in the GOM, or it will not point to a valid object (and thus not be usable).
  • No, you can not access methods for fields with type 'Class _____', since this is not an object but rather is a collection of data.

  • field 'accountData' on your 'CustomPlayerAccount' class is of type 'NodeRef of Class MyCustomPlayerAccountData'.
  • when you create your CustomPlayerAccount, you create a persisted node from class MyCustomPlayerAccountData and attach it via base_hard_association to - for example - the player account node.
  • you now set your 'accountData' field to point to your newly created 'MyCustomPlayerAccountData' node.  Since that node is of the correct type and does currently exist in the GOM (since it is loaded), you may now reference the object by accessing the field 'accountData'. Calls to 'someAccount.accountData.getCustomAccountName()', for example, will now work!


This work has been completed.

This work has now begun.

Pages: 1 2 [3] 4 5 ... 9