public abstract class ChunkManager : MonoBehaviour
Provides a base implementation for Chunk Managers. These managers perform two tasks:
1) They provide implementations for Asset Chunk Type specific logic, like getting/setting
chunk positions and activating/deactivated asset chunks.
2) They interface between the
World and Chunk Streamers. When the World needs chunks for
one or more World Cells, it requests them from the Chunk Manager assigned to a particular LOD. The manager
may have the needed chunks already (if using a
pooling manager), however if it does not, it requests new chunks be streamed in via
the Chunk Streamer assigned to the same LOD. In addition, when
the World no longer needs a World Cell, the World Cell is sent to the manager so that
its chunks can be processed. The manager may choose to pool
the chunks, or unload them from the scene (via the Chunk Streamer). This strategy
allows for different chunk life cycle management strategies to be employed, including
custom ones you write yourself.
The provided default managers are the
NonPoolingChunkManager
,
PoolingChunkManager, and
DistancePoolingChunkManager
.
The actual method of loading new chunks into the scene and unloading uneeded chunks
from the scene is left up
to the Chunk Streamer you are using. Think of the
Chunk Manager not as a creator/destroyer, but as a manager that determines whether
uneeded objects
should be kept in the scene, and if so, managing the lifetime of them so that they
can be reused in the future. You can also
think of it as specific logic that targets the exact type of objects you are using.
All Chunk Managers are configured to work with any chunk (both game object based and
non game object based),
however there are certain methods of the Chunk Manager class
that are by default, configured to work with Game Objects. Those methods include:
GetChunkPosition - For retrieving the Vector3Double position of a chunk. Only called
if the LOD using this manager has 'Chunks Use
Positional Data' enabled (this setting can be found on your Streamable Grid asset).
SetChunkPosition - For setting the chunk position to a Vector3Double value. Only called
if the LOD using this manager has 'Chunks Use
Positional Data' enabled (this setting can be found on your Streamable Grid asset).
SetChunkActiveState - For setting the state of the chunk to active or deactive. This
method is called only if Auto Activate/Deactivate
Cell Chunks is enabled in your World inspector, for any LODs that use this manager.
If you anticipate any of these methods being called, you will need to create a custom
class deriving from this one or one of the existing Chunk Managers,
and in that class override the methods that will be called, so that they function
correctly with your custom chunks.
Additional Note: This component contains its own special class (ChunkManagerUser)
which enables multiple
users to use the manager at the same time. The data associated with each user is stored
in this user object and retrieved
using the userID passed into each method.
This user object does not contain any data by default other than the
ILODGroup object associated with the user and the chunkStreamerUserID of
the user (in reference to the Chunk Streamer it uses). You can access the user object
via the
RegisteredUsers property and userID,
like so: RegisteredUsers[userID].
You may also create your own custom user object class which
derives from ChunkManagerUser, in order to store custom data or add custom methods.
In fact, this strategy is utilized by some of the other Chunk Managers in the kit.
Simply override the
CreateNewUser method and return your custom user object.
The properties, methods, and constructors of this ChunkManagerUser class have been
included on this webpage along side
the other members of the ChunkManager class. You can easily identify them as their
member names include a ChunkManagerUser prefix. You can
use these as a reference when creating custom ChunkManagerUser classes.
You should never have to interact directly with the Chunk Manager unless deriving
from it,
as its methods/properties are called/used as needed by the Streamable Assets Manager
automatically.
Name | Type | Description |
---|---|---|
AttachmentProgress | float |
Tracks the progress of this Chunk Manager's current AttachChunksToCells method call as a value between 0 (no chunks attached) and 1 (all chunks attached). The progress is calculated automatically by the base Chunk Manager class. It does so by calculating the total number of Asset Chunks that need to be attached. After AttachChunksAlreadyInSceneToCells is called, it increments the progress by a value equal to total reused chunks / total chunks to attach. The remaining Cell's that still need Chunks are passed to the LOD Group's Chunk Streamer. The progress from the Chunk Streamer is then used to increment the AttachmentProgress the rest of the way to 1. |
ChunkManagerUser.ChunkManager | ChunkManager |
Gets the Chunk Manager instance that created this user object. |
ChunkManagerUser.ChunkStreamerUserID | int |
Gets the User ID of the LOD Group that was assigned to it by the Chunk Streamer when it was registered with it. |
ChunkManagerUser.LODGroup | ILODGroup |
Gets the LOD Group this user object is associated with. |
ChunkManagerUser.StreamableGrid | StreamableGrid |
Get the Streamable Grid associated with the LOD Group. |
ChunkReusePossible | bool |
Gets a value indicating whether chunk reuse is possible on this manager. Reuse allows
chunks from one World Cell to be used by another. This just returns the value as set
in the inspector of your manager, which is by default set to true, as reuse is an
invaluable means of removing some unecessary loading and unloading.
|
RegisteredUsers | RegistrationHandler<ChunkManagerUser> |
Gets the users registered with the manager. |
public ChunkManagerUser(ChunkManager chunkManager, ILODGroup LODGroup, int chunkStreamerUserID)
Create an instance of the Chunk Manager User object. If you are overriding the ChunkManager
class and
not overriding the ChunkManagerUser, you can create a new instance of this user object
via this
constructor, which can be returned in the ChunkManager's CreateNewUser method.
If you are overriding ChunkManagerUser, your custom user class will need constructors
with at least these parameters
(but can also have more), and they must also call the base constructor, which is accomplished
by placing
: (chunkManager, LODGroup, chunkStreamerUserID) after your constructor declaration.
Note, this construct can only be used from a class deriving from ChunkManager or ChunkManagerUser.
Name | Type | Description |
---|---|---|
chunkManager | ChunkManager |
The parent Chunk Manager instance creating the user object. |
LODGroup | ILODGroup |
The LOD Group the user object is being created for. |
chunkStreamerUserID | int |
The User ID of the LOD Group that was assigned to it by the Chunk Streamer when it was registered with it. |
protected virtual IEnumerator<YieldInstruction> AttachChunksAlreadyInSceneToCells(List<WorldCell> cells, ChunkManagerUser user)
When overridden in a derived class, attaches any chunks already in the scene to the
appropriate cells over multiple frames.
Overriding this method is optional. If you don't, all cells will be sent to the Chunk
Streamer for it to stream new chunks
into the scene.
If you do have chunks to attach, you must attach all chunks needed by the cell using
the
WorldCell.AttachChunkToCell method, and then remove the cell from the list so that
it is not sent to the
Chunk Streamer (otherwise, uneeded objects will be loaded into the scene!).
Never store the World Cells themselves for later use; only store non reference data
associated with the World Cells (although,
for this method, that should not be needed).
Name | Type | Description |
---|---|---|
cells | List<WorldCell> |
The cells that need chunks attached. |
user | ChunkManagerUser |
The user requesting the attachment. |
IEnumerator<YieldInstruction>
An IEnumerator<YieldInstruction> that can be iterated over or used as a coroutine.
See the
YieldInstruction page for more info.
protected virtual void AttachChunksAlreadyInSceneToCellsInSingleFrame(List<WorldCell> cells, ChunkManagerUser user)
When overridden in a derived class, attaches any chunks already in the scene to the
appropriate cells in a single frame.
Overriding this method is optional. If you don't, all cells will be sent to the Chunk
Streamer for it to load new chunks
into the scene.
If you do have chunks to attach, you must attach all chunks needed by the cell using
the
WorldCell.AttachChunkToCell method, and then remove the cell from the list so that
it is not sent to the
Chunk Streamer (otherwise, uneeded chunks will be loaded into the scene!).
Name | Type | Description |
---|---|---|
cells | List<WorldCell> |
The cells that need chunks attached. |
user | ChunkManagerUser |
The user requesting the attachment. |
public IEnumerator<YieldInstruction> AttachChunksToCells(List<WorldCell> cells, int userID)
Attaches chunks to the list of passed in cells. This is done by first calling the AttachChunksAlreadyInSceneToCells method. If any cells still need objects after calling this method, they are passed to the attached Chunk Streamer, which carries out this function.
Name | Type | Description |
---|---|---|
cells | List<WorldCell> |
The cells whose objects need to be attached. |
userID | int |
The ID of the user requesting the attachment. |
IEnumerator<YieldInstruction>
An IEnumerator<YieldInstruction> that can be iterated over or used as a coroutine.
See the
YieldInstruction page for more info.
public abstract void AttachChunksToCellsInSingleFrame(List<WorldCell> cells, int userID)
Attaches chunks to the list of passed in cells in a single frame. This is done by first calling the AttachChunksAlreadyInSceneToCellsInSingleFrame method. If any cells still need chunks after calling this method, they are passed to the Chunk Streamer associated with the user, which carries out this function.
Name | Type | Description |
---|---|---|
cells | List<WorldCell> |
The cells that need chunks attached. |
userID | int |
The ID of the user requesting the attachment. |
protected void Awake()
The Chunk Manager's Awake method, called by Unity. You cannot utilize Awake in your derived class. If you need to perform some sort of Awake related logic, override the AwakeExtended method, which will be called by this classes Awake method. Also note that you do not need to call base.AwakeExtended(); from your AwakeExtended method, as this is a virtual empty method that does nothing unless you override it. Also note that this method is protected simply so that if you derive from this class, you will see an error when trying to add the Awake method.
protected virtual void AwakeExtended()
Can be overriden to perform logic that would normally go in Awake (which is used by the base class). Use this instead of implementing Awake! You do not need to call base.AwakeExtended if you override this, as the base method is empty.
protected virtual ChunkManagerUser CreateNewUser(ILODGroup LODGroup, int chunkStreamerUserID)
Method used to create a new user object during user registration. This can be overridden to return a custom user object. User objects store pertitent information about a particular LODGroup. They allow the Chunk Manager to be used with multiple LOD's.
Name | Type | Description |
---|---|---|
LODGroup | ILODGroup |
The lod group that the user object is being created for. |
chunkStreamerUserID | int |
When the LODGroup registered with the manager, the manager automatically registered the LODGroup with the Chunk Streamer associated with it. This is the user ID assigned to the LODGroup by that Chunk Streamer, and can be used if you need to interface with the Chunk Streamer for some reason. |
ChunkManagerUser
The new user created, which may be a basic ChunkManagerUser or may be a custom user
object as returned by the derived Chunk Manager.
public void DeRegister(int userID)
A user can call this method to de register with the Chunk Manager. The Chunk Manager will also automatically de-register the LOD Group with its assigned Chunk Streamer.
Name | Type | Description |
---|---|---|
userID | int |
The ID of the user to de register. |
public abstract IEnumerator<YieldInstruction> DetachAndProcessChunksFromDeactivatedCells(List<WorldCell> cells, int userID)
Detaches and processes the chunks associated with the input cells over a period of
frames.
This method first calls the DetachAndProcessChunksToKeepInScene method, which is implemented
by
derived classes. This method loops through the list of cells and determines if any
of them can be reused or otherwise
do not need to be unloaded from the scene. It removes those cells from the list and
stores or does whatever with the
chunks (chunks).
If there are any cells remaining, they are sent to the Chunk Streamer via its
DetachAndUnloadChunksFromCells method so that the objects associated with the cells
can be unloaded.
Please note, previously this method was abstract and had to be implemented by derived
classes. The new method to implement is
DetachAndProcessChunksFromDeactivatedCells, which should do pretty much the same thing,
except cells from the list
need to be removed if you don't want their objects to be unloaded, and you must not
do any sort of object unloading yourself.
Name | Type | Description |
---|---|---|
deactivatedCells | List<WorldCell> |
The cells whose objects need to be detached and processed. |
userID | int |
The ID of the user requesting the detachment and processing. |
IEnumerator<YieldInstruction>
An IEnumerator<YieldInstruction> that can be iterated over or used as a coroutine.
See the
YieldInstruction page for more info.
protected virtual IEnumerator<YieldInstruction> DetachAndProcessChunksToKeepInScene(List<WorldCell> cells, ChunkManagerUser user)
Optionally overridable method that should detach and processes the objects associated
with the input cells over a period of frames, but
only for cells with objects that should be kept in the scene. For example, if using
a pooling system, this method would
store the objects for any cells determined to be reusable. When such reusable cells
are found,
you must remove the World Cell from the list,
and you must remove all chunks belonging to the cell. As such,
it is best to process the list of cell in descending order so that you can remove
them as you go.
Once this processing is complete, any remaining cells are passed along to the Chunk
Streamer to be unloaded from
the scene.
If you are NOT using a pooling solution or otherwise don't want to keep any objects
in the scene,
you can choose to NOT override this method, however consider that there is very little
point in creating a custom
Chunk Manager if you are not retaining objects in the scene.
It's also important to note that you SHOULD not store the World Cells themselves for
later use, for example for the purpose
of determining if specific objects can be reused by another World Cell down the line.
Instead, store non reference data
of the World Cell, such as its CellOnStreamableGrid or CellOnEndlessGrid, and use
that data instead to make those determinations.
The reason is, internally SAM keeps track of these World Cells and once this method
is finished executing, it clears the World
Cell's data and returns them to an internal pool to be reused, thus conserving memory.
The input list is a duplicated list, therefore
removing a World Cell from the list does not effect this process.
Name | Type | Description |
---|---|---|
deactivatedCells | List<WorldCell> |
The cells whose objects need to be detached and processed. |
user | ChunkManagerUser |
The user requesting the detachment and processing. |
IEnumerator<YieldInstruction>
An IEnumerator<YieldInstruction> that can be iterated over or used as a coroutine.
See the
YieldInstruction page for more info.
public virtual bool GetChunkActiveState(object chunk)
Gets the active state of the chunk. This is not necessarily whether the chunk is active in the scene view, but should be instead the active state of the chunk itself (such as activeSelf).
Name | Type | Description |
---|---|---|
chunk | System.Object |
The chunk whose position should be set. |
bool
True if the chunk is active, false otherwise. For Game Objects (which the
default implementation assumes the chunk is) this returns the activeSelf property,
meaning the chunk
may not actually be active in the scene.
public virtual Vector3Double GetChunkPosition(object chunk)
Default implementation to get the position of a single asset chunk associated with
a World Cell.
The default behaviour is to simply get the transform position of the chunk, which
assumes the chunk is a GameObject.
You can override this using a custom manager if your objects are not traditional game
objects (and thus do
not have transform components), however you only need to do so if you have indicated
on your Streamable Grid LOD that
the objects use positional data, or if the objects are Terrain.
Name | Type | Description |
---|---|---|
chunk | System.Object |
The chunk whose position to get. |
Vector3Double.html
The Chunk's position as a Vector3Double.
public int GetChunkStreamerIDOfUser(int userID)
Can be used to retrieve the chunk streamer ID of a given Chunk Manager user.
Name | Type | Description |
---|---|---|
userID | int |
the ID of the chunk manager user. |
int
The chunk streamer user ID.
protected void OnDestroy()
The Chunk Manager's OnDestroy method, called by Unity. You cannot utilize OnDestroy in your derived class, if you need to perform some sort of OnDestroy related logic, override the OnDestroyExtended method, which will be called by this classes OnDestroy method. Also note that you do not need to call base.OnDestroyExtended(); from your OnDestroyExtended method, as this is a virtual empty method that does nothing unless you override it. Also note that this method is protected simply so that if you derive from this class, you will see an error when trying to add the OnDestroy method.
protected virtual void OnDestroyExtended()
Can be overriden to perform logic that would normally go in OnDestroy (which is used by the base class). Use this instead of implementing OnDestroy! You do not need to call base.OnDestroyExtended if you override this, as the base method is empty.
public virtual void OnUserDeRegistered((ChunkManagerUser user)
Called just after a user has been deregistered by the Chunk Manager. You can override this in a custom manager to perform additional post-deregistration logic on a per user basis.
Name | Type | Description |
---|---|---|
user | ChunkManagerUser |
The user that has just beeen deregistered. |
public virtual void OnUserDeRegistering((ChunkManagerUser user)
Called just before a user is deregistered by the Chunk Manager. You can override this in a custom manager to perform additional pre-deregistration logic on a per user basis.
Name | Type | Description |
---|---|---|
user | ChunkManagerUser |
The user that is about to be deregistered. |
public virtual void OnUserRegistered((ChunkManagerUser user)
Called just after a user has been registered by the Chunk Manager. You can override this in a custom manager to perform additional post-registration logic on a per user basis.
Name | Type | Description |
---|---|---|
user | ChunkManagerUser |
The user that has just beeen registered. |
public void Register(ILODGroup LODGroup, out int userID)
A user can call this method to register with the Chunk Manager.
The userID must be stored by the user
and passed in when calling the methods of the Chunk Manager.
The Chunk Manager automatically registers the LOD Group with its assigned
Chunk Streamer as well.
Name | Type | Description |
---|---|---|
LODGroup | ILODGroup |
The lod group being registered. |
userID | int |
An ID that is assigned to the user when this method is called. Each user has its own ChunkManagerUser object created for it. |
public virtual void SetChunkActiveState(object chunk, bool isActive)
Default implementation to set the chunk for a World Cell as active or deactive. The
default behaviour, which
calls GameObject.SetActive, should be sufficient if your chunks are normal Unity Game
Objects.
Typically, you would only override this method if using non game objects.
Also note that this method is only called if
either 'Auto Activate Chunks When Adding Cells' or 'Auto Deactivate Chunks When
Removing Cells' are enabled for the LOD using your Chunk Manager, so if these options
would always be disabled, there is no need to override this method.
Name | Type | Description |
---|---|---|
chunk | System.Object |
The chunk to set to active or deactive. |
isActive | bool |
True if the chunk should be set to active, false if it should be set to deactive. |
public virtual void SetChunkPosition(object chunk, Vector3Double position)
Default implementation to set the position of a single chunk associated with a World
Cell.
The default behaviour is to simply set the transform position of the object to the
passed in position.
You can override this using a custom manager, which would typically be done for one
of two reasons.
1) If you do not need your chunks to be positioned (i.e., the position of the chunks
does not matter,
in which case setting the position is an uneccesary performance hit).
2) If your chunks are not traditional GameObjects and thus cannot be positioned using
a transform component.
Note, you only need to do so if you have indicated on your Streamable Grid LOD that
the objects use positional data, or if the objects are Terrain.
Name | Type | Description |
---|---|---|
chunk | System.Object |
The chunk whose position should be set. |
position | Vector3Double |
The position to set the chunk to. |