Game.Notifications.IconClusterSystem
Assembly: Game (Assembly-CSharp)
Namespace: Game.Notifications
Type: class
Base: GameSystemBase, IPreDeserialize
Summary: IconClusterSystem gathers notification icons (Icon components) and groups them into spatial clusters for efficient rendering/processing. It maintains a quadtree of clusters, allocates storage for cluster icons, merges nearby icons into clusters (including special handling for temporary icons and moving groups), and exposes a read-only ClusterData view for other systems via job dependencies. The system is Burst-compatible for core clustering jobs and uses Unity.Collections native containers and Jobs to run most work off the main thread. It also supports pre-deserialization (loading) so clusters are recomputed after load.
Fields
-
private Unity.Entities.EntityQuery m_IconQuery
Holds a query that selects non-temporary, non-deleted, cluster-eligible Icon entities. Used to enumerate all icons when fully rebuilding clusters. -
private Unity.Entities.EntityQuery m_ModifiedQuery
Query selecting Icon entities that have been modified (Updated or Deleted). Used to drive incremental updates. -
private Unity.Entities.EntityQuery m_ModifiedAndTempQuery
Query selecting Icon entities that are temporary or modified. Used during incremental processing where temporary icons must be handled. -
private NativeQuadTree<int, TreeBounds> m_ClusterTree
Quadtree storing cluster bounds indexed by cluster index. Used for spatial searches when pairing/merging clusters. -
private NativeHeapAllocator m_IconAllocator
Heap-style allocator used for cluster icon storage. Allocations return NativeHeapBlock describing where cluster icons are stored in m_ClusterIcons. -
private NativeList<IconCluster> m_IconClusters
List of IconCluster structures representing all clusters (root + internal clusters). index 0 is reserved/empty. -
private NativeList<ClusterIcon> m_ClusterIcons
Flat array of ClusterIcon entries. IconCluster stores a NativeHeapBlock with Begin/Size to reference a contiguous range in this list. -
private NativeList<int> m_RootClusters
List of cluster indices considered roots for the current frame / tree levels. -
private NativeList<int> m_FreeClusterIndices
Pool of free cluster indices for reuse when clusters are removed. -
private Unity.Jobs.JobHandle m_ClusterReadDeps
Combined JobHandle representing readers that depend on cluster data. Used to chain job dependencies for safe concurrent reads. -
private Unity.Jobs.JobHandle m_ClusterWriteDeps
JobHandle representing the job writing/updating cluster data. Readers get combined dependency with this to ensure correctness. -
private bool m_Loaded
Flag set during PreDeserialize to force a full rebuild on the next update (used when loading save data). -
private TypeHandle __TypeHandle
Internal generated struct containing Entity/Component type handles used to build job data (assigned in OnCreate/OnCreateForCompiler).
Properties
- None (this system exposes cluster data through GetIconClusterData rather than public properties).
Constructors
public IconClusterSystem()
Default constructor. The system performs native allocations in OnCreate; constructor itself is preserved/empty.
Methods
-
protected override void OnCreate()
Initializes entity queries and allocates persistent native containers: quadtree, heap allocator, and lists. Adds a placeholder IconCluster at index 0 and resizes m_ClusterIcons to match the initial allocator size. -
protected override void OnDestroy()
Disposes/cleans up all created native containers. Completes outstanding read/write job dependencies before disposal to avoid race conditions. Calls base.OnDestroy(). -
protected override void OnUpdate()
Core update loop. If there are new/modified icons (based on queries), schedules two jobs: - IconChunkJob: iterates icon archetype chunks, collects temp icons and orphans, and prepares per-chunk updates.
-
IconClusterJob: processes orphaned clusters and temporary clusters to add/merge clusters and update the quadtree. Manages job dependency wiring, disposes temporary lists using job handles, and updates internal job dependency fields.
-
public void PreDeserialize(Context context)
Called before deserialization (e.g., loading). Clears existing cluster data and sets m_Loaded = true so OnUpdate will perform a full rebuild. -
public ClusterData GetIconClusterData(bool readOnly, out JobHandle dependencies)
Returns a ClusterData view (struct with references to m_IconClusters, m_ClusterIcons, and m_RootClusters) along with a JobHandle representing the required dependency callers must respect. If readOnly == true the returned dependencies are the writer handle; otherwise it combines read and write dependencies. Consumers must Complete the handle (or include in their job dependency) before reading/writing. -
public void AddIconClusterReader(JobHandle jobHandle)
Adds a reader dependency so the system waits for that job in subsequent writes. Combines the provided jobHandle into m_ClusterReadDeps. -
public void AddIconClusterWriter(JobHandle jobHandle)
Sets m_ClusterWriteDeps to the provided jobHandle (the external writer). Used to chain external writers into the system's scheduling. -
public void RecalculateClusters()
Marks the system to fully rebuild clusters on the next update (sets m_Loaded = true). -
private void ClearData()
Internal helper to reset cluster structures. Completes read/write job dependencies, clears the quadtree and allocator, and resets lists to the empty initial state (keeps a placeholder index 0). -
private bool GetLoaded()
Helper that returns true once if m_Loaded is set; after calling it clears the flag. Used to detect when a full rebuild is required. -
protected override void OnCreateForCompiler()
Generated method used by the compiled codepath to assign query/type handle boilerplate. Calls __AssignQueries and assigns handles from __TypeHandle. -
private void __AssignQueries(ref SystemState state)
Generated stub for query assignment; currently empty aside from a temp builder call (kept to satisfy compiler generation). -
Additional nested types and job structs:
- ClusterData (struct): view returned by GetIconClusterData. Provides helpers GetRoot, GetCluster, GetIcons.
- IconCluster (struct): represents a cluster, contains center/size/level/prefabIndex/layer/flags, icon allocation metadata, helpers to compute radius/bounds and to check whether to keep cluster at a given distance.
- ClusterIcon (struct): single icon entry stored in m_ClusterIcons (entity, prefab, order, priority, flags).
- TempIconCluster (struct): temporary cluster used during clustering step; comparable for sorting.
- TreeBounds (struct): quadtree item bounds + level/layer masks; implements necessary interface for quadtree.
- IconChunkJob (Burst-compiled IJob): collects icons from archetype chunks into temp buffers and marks orphans; runs concurrently with minimal main-thread interaction.
- IconClusterJob (Burst-compiled IJob): consumes orphans and temp icon buffers to form/merge clusters and update quadtree.
- IconData (struct): encapsulates cluster data and the logic to allocate icons, merge clusters, handle orphans and temp clusters. Many private helpers sit here (AllocateIcons, AddIcon, GetNewClusterIndex, Remove, HandleOrphans, HandleTemps, etc.).
- TypeHandle (struct): generated container for ComponentTypeHandle and ComponentLookup instances used by jobs.
Notes about threading and safety: - Consumers must respect the returned JobHandle from GetIconClusterData before reading the returned ClusterData (or add their jobs using AddIconClusterReader/Writer). - All heavy clustering work is done in jobs (Burst) and uses NativeCollections; the system manages job handles to coordinate reads/writes to cluster data.
Usage Example
// Example: safely read cluster data from another system/job
void SomeMethod(IconClusterSystem iconSystem)
{
// Request read-only access and get the dependency handle
Unity.Jobs.JobHandle deps;
var clusterData = iconSystem.GetIconClusterData(readOnly: true, out deps);
// If you want to read immediately on main thread:
deps.Complete();
// Iterate root clusters
int idx = 0;
IconCluster cluster;
while (clusterData.GetRoot(ref idx, out cluster))
{
// Use cluster.center, cluster.GetBounds(distance, cameraUp), etc.
UnityEngine.Vector3 center = new UnityEngine.Vector3(cluster.center.x, cluster.center.y, cluster.center.z);
// To access icons of that cluster:
int firstIcon, iconCount;
var allocation = cluster.GetIcons(out firstIcon, out iconCount);
var icons = allocation.GetIcons(clusterData); // or cluster.GetIcons(clusterData)
for (int i = 0; i < iconCount; i++)
{
var ci = icons[i];
// ci.icon, ci.prefab, ci.priority, ci.flags
}
}
// Alternatively, schedule a job that depends on 'deps' and call
// iconSystem.AddIconClusterReader(yourJobHandle) so the system tracks the new dependency.
}
If you need examples for writing/modifying cluster data from jobs, ensure you: - Request non-readOnly cluster data (GetIconClusterData(readOnly: false, out deps)) and include the returned dependency in your job dependency chain. - Use AddIconClusterReader / AddIconClusterWriter to register your job handles with IconClusterSystem so it can combine them with its internal scheduling.