Skip to content

Game.Zones.SearchSystem

Assembly: Assembly-CSharp (game assembly)
Namespace: Game.Zones

Type: class SearchSystem

Base: GameSystemBase, IPreDeserialize

Summary:
SearchSystem maintains a spatial search index (NativeQuadTree) of zone Block entities. It keeps the tree up to date by scheduling a job (UpdateSearchTreeJob) that adds, updates or removes entities from the NativeQuadTree based on Block bounds and component state (Created/Updated/Deleted). The system supports full rebuilds after deserialization (via IPreDeserialize.PreDeserialize), handles job dependency tracking for concurrent read/write access, and exposes a method to obtain the search tree together with its current JobHandle dependencies.


Fields

  • private EntityQuery m_UpdatedBlocksQuery
    This query matches Block entities that are either Updated or Deleted (and not marked Temp). Used to schedule incremental updates to the search tree.

  • private EntityQuery m_AllBlocksQuery
    Query that matches all Block entities (excluding Temp). Used to do a full rebuild of the search tree (when the system is flagged as loaded).

  • private NativeQuadTree<Entity, Bounds2> m_SearchTree
    The spatial index used by the system. Created in OnCreate with cell size 1f and Allocator.Persistent. Contains Entities keyed by their 2D bounds (Bounds2). Disposed in OnDestroy.

  • private JobHandle m_ReadDependencies
    Accumulated JobHandle combining jobs that read from m_SearchTree. Used to ensure writers wait for readers as needed.

  • private JobHandle m_WriteDependencies
    JobHandle for the most recent writer job that mutated m_SearchTree. Readers are combined with this to produce safe dependency results.

  • private bool m_Loaded
    Flag set when PreDeserialize clears the tree to indicate the next update should perform a full rebuild (use m_AllBlocksQuery). It is reset when consumed by GetLoaded().

  • private TypeHandle __TypeHandle
    Internal struct that caches EntityTypeHandle and ComponentTypeHandle references required by jobs. Populated during system creation for performance.

Nested types (brief): - UpdateSearchTreeJob (private struct, IJobChunk)
Job that iterates matching archetype chunks and either Adds, Updates, or Removes Entities in the NativeQuadTree based on block bounds, and depending on whether the chunk has Created/Deleted components or whether the system is performing a full rebuild (m_Loaded).

  • TypeHandle (private struct)
    Helper to assign and store the type handles used by the job.

Properties

  • None (the system exposes methods rather than public properties)

Constructors

  • public SearchSystem()
    Default constructor (preserved). The system performs its actual initialization in OnCreate.

Methods

  • protected override void OnCreate()
    Initializes EntityQueries and constructs the NativeQuadTree:
  • m_UpdatedBlocksQuery: Blocks with (Updated or Deleted) and not Temp.
  • m_AllBlocksQuery: all Blocks excluding Temp.
  • m_SearchTree = new NativeQuadTree(1f, Allocator.Persistent); This method is annotated with Preserve to prevent stripping.

  • protected override void OnDestroy()
    Disposes m_SearchTree and calls base.OnDestroy.

  • private bool GetLoaded()
    Atomically consumes the m_Loaded flag: if set, clears it and returns true. Used to decide whether the next update should rebuild the whole tree.

  • protected override void OnUpdate()
    Main update loop:

  • Uses GetLoaded() to pick between m_AllBlocksQuery (full rebuild) and m_UpdatedBlocksQuery (incremental updates).
  • If the chosen query is not empty, constructs an UpdateSearchTreeJob with the current type handles, the loaded flag, and the search tree returned by GetSearchTree(..., out dependencies).
  • Schedules the job and sets base.Dependency accordingly.
  • Calls AddSearchTreeWriter(base.Dependency) to register the scheduled writer job.

The scheduled UpdateSearchTreeJob: - For each chunk, gets the entity array and block array. - If the chunk has Deleted, calls m_SearchTree.TryRemove(entity) for each entity. - Else if m_Loaded or chunk has Created, computes bounds and calls m_SearchTree.Add(entity, bounds). - Else computes bounds and calls m_SearchTree.Update(entity, bounds).

  • public NativeQuadTree<Entity, Bounds2> GetSearchTree(bool readOnly, out JobHandle dependencies)
    Returns a reference to the internal NativeQuadTree and outputs the JobHandle that callers must respect to safely interact with it:
  • If readOnly == true: dependencies = m_WriteDependencies (writers must finish before readers).
  • Else: dependencies = JobHandle.CombineDependencies(m_ReadDependencies, m_WriteDependencies) (writers will wait for readers and previous writers).
  • Note: the method does not schedule or complete any jobs — callers must Complete() the returned dependencies when required.

  • public void AddSearchTreeReader(JobHandle jobHandle)
    Combine a reader jobHandle into m_ReadDependencies. Use this to register that a background job will read from the tree.

  • public void AddSearchTreeWriter(JobHandle jobHandle)
    Sets m_WriteDependencies to the writer jobHandle. Use this to register that a background job will write to the tree.

  • public void PreDeserialize(Context context)
    Called before deserialization to prepare the search tree:

  • Obtains the search tree with readOnly:false and retrieves dependencies.
  • Calls dependencies.Complete() to ensure all outstanding jobs finish.
  • Clears the searchTree (searchTree.Clear()).
  • Sets m_Loaded = true to indicate that the next OnUpdate should do a full rebuild from m_AllBlocksQuery.

  • private void __AssignQueries(ref SystemState state)
    Internal helper used by OnCreateForCompiler. (In this code it simply constructs and disposes an EntityQueryBuilder. Type handles are assigned elsewhere.)

  • protected override void OnCreateForCompiler()
    Compiler-time initialization: calls __AssignQueries and assigns type handles via __TypeHandle.__AssignHandles.

  • Nested struct: UpdateSearchTreeJob (IJobChunk)

  • Fields: EntityTypeHandle m_EntityType; ComponentTypeHandle m_BlockType; ComponentTypeHandle m_CreatedType; ComponentTypeHandle m_DeletedType; bool m_Loaded; NativeQuadTree m_SearchTree.
  • Execute: described above (Remove/Add/Update behavior per chunk). This job is Burst-compiled.

  • Nested struct: TypeHandle

  • Stores cached type handles and has __AssignHandles(ref SystemState state) to populate them (used during OnCreateForCompiler).

Usage Example

// Example: reading the search tree safely from another system or mod code.
var searchSystem = World.DefaultGameObjectInjectionWorld?.GetExistingSystem<SearchSystem>();
if (searchSystem != null)
{
    JobHandle deps;
    var tree = searchSystem.GetSearchTree(readOnly: true, out deps);

    // Ensure writers have finished before accessing the tree on this thread:
    deps.Complete();

    // Use the tree (example methods: TryGet, TryRemove, etc. depending on NativeQuadTree API)
    // For illustration:
    // if (tree.TryQuery(point, out var results)) { ... }

    // If you schedule a background job that reads the tree, register it:
    // var readerJobHandle = myReaderJob.Schedule();
    // searchSystem.AddSearchTreeReader(readerJobHandle);
}

Notes and tips - The NativeQuadTree is allocated with Allocator.Persistent and must be disposed by the system; the system handles this in OnDestroy. - After deserialization, PreDeserialize clears the tree and sets the system to rebuild on the next update (m_Loaded = true). - Always respect the JobHandle returned by GetSearchTree before reading or mutating the tree. Use AddSearchTreeReader/AddSearchTreeWriter to register scheduled jobs that access the tree so the system can enforce proper dependencies. - The update job (UpdateSearchTreeJob) is Burst compiled and manipulates the tree from worker threads; ensure any external code interacting with the tree follows the dependency protocol to avoid race conditions.