Give Page Feedback | API

Worlds - World Users

A World User is any user that needs to track changes to the World's Origin Cell (including clamping of the Origin Cell), needs to be able to delay Origin Cell Changes, and/or needs to be able to respond to the World being destroyed. Users can register with the World to receive callbacks when certain events happen, or to directly influence certain World behavior.

--Special Note--
Each user object can only be associated with a single World. This is because the IWorldUser methods called by the World do not take in any identifying information (such as the World ID) to differentiate between different Worlds.

Creating A World User

Any existing class can be converted into a World User by implementing the IWorldUser interface. Information about each interface member that needs to be implemented can be found winthin the website API (click the button at the top of this page), or at the bottom of this window (if you scroll down).

Registering Users

Users must register with the World in order for the World to call its methods and query it's properties. To do so, use the World's Register method. This method outputs a registrationID, which is unique for the user and must be stored and returned via the IWorldUser.UserID property.

De-Registering Users

If one of your users is destroyed or otherwise disabled in such a way that they should no longer receive callbacks or influence the World's behavior, you must de-register the user with the World using the World's DeRegister method.

Origin Cell Changes

Tracking and Delaying Origin Cell Changes is one of the most important uses of World Users.

Every time an Origin Cell Change is about to be carried out, all World Users have the IsReadyForOriginCellChange method queried. If at least one user returns false, the World yields for a frame and then queries all users again, repeating the cycle until all users return true (and then, and only then, is the Update containing the change allowed to proceed).

This allows you to delay the change if the change would cause issues with another operation that is being carried out by the user, such as a multi-frame save operation.

Once all users are ready, the OnOriginCellChanging method for all users is invoked. This method allows you to prepare for the change or configure the user so that other operations that would interfere with the change are not allowed to proceed. Such code should always be placed in OnOriginCellChanging and never in IsReadyForOriginCellChange, as the latter may be called several times and the timing of when it is called cannot be guaranteed.

After the World Updating containing the Origin Cell Change has completed, the World notifies users that the change was completed. To do so, it calls either OnOriginCellChanged_Fast or OnOriginCellChanged_Slow, depending on the value returned by the user's UseFastOnOriginCellChangedMethod property (true = fast, false = slow).

Use the fast method if you do not need to execute code when the Origin Cell Change is completed, or the code you need to execute is very simple. Use the slow method if the code needs to be run over multiple frames.

--Special Note--
OnOriginCellChanged_Slow has a return type of IEnumerator. This return type is special as it allows the method to be iterated over, possibly over multiple frames. This allows the execution's performance impact to be spread out over multiple frames, which is awesome! There are two strategies for implementing methods with this return type:

1) Simply include yield return statements within the method's body where the returned object is either null or an instance of a YieldInstruction.

The compiler will auto generate a state machine class, which will be used to iterate the method's logic. The drawback of this technique is every time the method is called, a new instance of the auto generated class is created, resulting in garbage generation throughout the lifetime of the game.

2) Implement one of the reusable enumerator classes found within the API.

This strategy is harder to implement as you will need to implement the state machine logic yourself, as well as perform some other code related task necessary to use the reusable enumerators. It is recommended for experienced coders only!

If you elect to go with option 2, you can find detailed information on how to use the Reusable Enumerator classes in the Yield Enumerator Section within the Secondary Non Components Chapter.

Yield Enumerator Classes

Origin Cell Clamping

If using one or more Endless Axes, it's theoretically possible for one of the Origin Cell values for one or more of these axes to reach a value that cannot be represented by integers. Note that this is incredibly unlikely and you would need to play the game for a long time under most circumstances for this to occur. However because it is a possibility, the Streamable Assets Manager contains a mechanism for resetting the Origin Cell to smaller values. This mechanism is called Clamping.

Clamping resets the Origin Cell (which are always in reference to a Cell on an Endless Grid) for each Grouping to match the equivalent Cell on the Streamable Grid in use by that Grouping.

For example imagine a simple Streamable Grid that has only 2 rows but is being used on a World with endless Rows. When the player reaches the boundary in the positive direction (on the row axis), Row 1 and 2 are repeated to form Endless Rows 3 and 4, then 1 and 2 are repeated again to form Rows 5 and 6, and so on . . .

When clamping is initiated, the World checks the current Origin Row value (let's say it's 6 in this case) and finds which Streamable Grid Row matches it (Row 2 in this case). It then calculates an offset to add to the current Origin Row that would make it equal to the Streamable Grid Row (in this case, that offset would be -4).

It follows the same procedure for the Columns and Layers if they are also endless.

Under the hood all internal systems of the World are updated to take the new Origin Cell values into account. While this works great, any external systems that use Endless Grid Cell indexes will need to update those endless grid cell indexes to account for the clamping operation. This is where the OnOriginCellsClamped method comes in. With it, you gain access to an array of Cell values that tell you how much each World Grouping's origin cell has been offset.

You can then add this offset value to any endless grid cell data that is in use. For example, if you are storing World Cells or World Cell related data using Endless Grid Cell indexes as the keys, you should re-add the World Cells or data by taking the current keys and adding the offset to form new keys.

--Special Note--
The Clamping Operation does not result in any changes to the positions of the World Cells or their Asset Chunks. The only thing that changes is the value of the Origin Cell's, and the endless grid cell indexes for each World Grouping.

World Destruction (And Desyncing)

If you need to perform some special logic when a World is destroyed, you can use the TryDesyncFromWorld method to do so.

This method is called in two scenarios:

1) The World is being destroyed via the Component Manager. In this case failureWillDelayDestruction will be true and the destruction of the World can be delayed by the World User, by returning false in the method body.

This can be used if an operation is being performed that would fail if the World were destroyed, or result in cascading errors. Each user has the method queried and if one of them returns false for this method, a frame is yielded and the users are queried again afterwards. The cycle repeats until all users desync correctly. Please note, however, that once a user desyncs (and returns true), they will not be queried again (this differs from the way IsReadyForOriginCellChange works). Only users that fail to desync are queried again.

2) The World is being destroyed via a Destroy method call or the application quitting (which could be exiting play mode if in the editor). In this scenario the destruction cannot be delayed, so {BoldTagOpen}failureWillDelayDestruction{BoldTagClose} will be false. Your users must perform as much cleanup as they can and should generally return true. If they return false, an error message is printed giving you details about the user that failed to desync and the World that was destroyed.