Skip to content

Game.Zones.BlockSystem

Assembly: Assembly-CSharp
Namespace: Game.Zones

Type: class

Base: GameSystemBase

Summary:
BlockSystem is a Unity DOTS system responsible for keeping zone "blocks" (zoning cells placed along roads) in sync with the road network. It listens for updates to edges (roads) and their SubBlock buffers and runs a parallel IJobChunk (UpdateBlocksJob) that: - Removes deleted sub-block entities, - Recomputes and creates ZoneBlock entities along road edges and at nodes where zoning is enabled, - Reuses existing block entities where possible (matching Block structs) and updates their BuildOrder / CurvePosition, - Creates new zone block entities (with cell buffers and Owner) when needed, - Uses geometry (Bezier curves, tangents), net/prefab composition flags and road flags to determine placement, width, splits and continuity across connected edges, - Avoids zoning on elevated/tunnel segments and respects various alignment and side flags.

It uses a ModificationBarrier4 for thread-safe entity commands and schedules UpdateBlocksJob as a parallel JobChunk on m_UpdatedEdgesQuery.


Fields

  • private Unity.Entities.EntityQuery m_UpdatedEdgesQuery
    Holds the query that triggers this system. It matches edge entities with a SubBlock buffer and either Updated or Deleted components (excluding Temp). The system is required to update only when this query has matching entities.

  • private ModificationBarrier4 m_ModificationBarrier
    A barrier system used to create an EntityCommandBuffer. The job uses the command buffer (AsParallelWriter) to create/set/delete entities/components safely from multiple threads.

  • private TypeHandle __TypeHandle
    A compiler-generated container holding the ComponentTypeHandle / BufferTypeHandle / ComponentLookup / BufferLookup instances used by the UpdateBlocksJob. It's set up in OnCreateForCompiler and used in OnUpdate to populate the job's handle fields.

Properties

  • None (no public properties on BlockSystem)

Constructors

  • public BlockSystem()
    Default constructor. The system is [Preserve] attributed (via methods) and relies on OnCreate / OnUpdate overrides for initialization and execution. No special construction logic beyond base initialization.

Methods

  • protected override void OnCreate()
    Initializes system state:
  • Acquires or creates the ModificationBarrier4 from the World,
  • Builds the EntityQuery m_UpdatedEdgesQuery to select Edge entities that have SubBlock buffers and either Updated or Deleted components (excluding Temp),
  • Calls RequireForUpdate(m_UpdatedEdgesQuery) so the system only runs when there are matching entities.

  • protected override void OnUpdate()
    Creates and schedules the UpdateBlocksJob (IJobChunk) in parallel:

  • Populates the job struct with EntityTypeHandle, ComponentTypeHandles, BufferTypeHandles and ComponentLookup/BufferLookup instances taken from __TypeHandle (via InternalCompilerInterface wrappers),
  • Passes an EntityCommandBuffer.ParallelWriter from m_ModificationBarrier,
  • Schedules JobChunkExtensions.ScheduleParallel with m_UpdatedEdgesQuery and current dependency,
  • Adds the JobHandle to the modification barrier (m_ModificationBarrier.AddJobHandleForProducer) and stores the returned job handle on base.Dependency.

  • protected override void OnCreateForCompiler()
    Compiler helper used to assign queries and type handles at compile time:

  • Calls __AssignQueries and __TypeHandle.__AssignHandles to initialize handles used by the generated job.

  • private void __AssignQueries(ref SystemState state)
    Internal method used by the compiler-time setup. In this implementation it creates and immediately disposes an EntityQueryBuilder (placeholder/compile-time behavior).

  • (Nested) UpdateBlocksJob : IJobChunk (private struct)
    The main worker job containing many helpers. Key behaviors:

  • If the chunk has Deleted component, marks all SubBlock entities referenced in the SubBlock buffer with Deleted (and returns).
  • For each edge entity in the chunk, collects owner/edge/curve/composition/buildOrder/road and SubBlock buffer, then:
    • Fills a temporary NativeParallelHashMap of existing Block -> Entity (oldBlockBuffer),
    • Calls CreateBlocks(...) to generate new blocks for both left/right sides and for roundabouts/ends if applicable,
    • Calls RemoveUnusedOldBlocks(...) to delete old blocks that weren't reused,
    • Disposes the temporary map.
  • CreateBlocks contains heavy geometry algorithms:
    • Uses NetCompositionData and RoadComposition flags to check if zoning is enabled for that side,
    • Skips zoning for elevated/tunnel segments,
    • Determines cell widths via ZoneUtils.GetCellWidth, computes offsets and tangents via MathUtils and NetUtils,
    • Splits long continuous curves into multiple blocks, computes block placement, size and direction,
    • Tries to reuse existing blocks via oldBlockBuffer.TryGetValue(matchBlock) and, if found, updates prefab reference / curve position / build order and marks Updated; otherwise creates a new ZoneBlock entity using ZoneBlockData.m_Archetype, creates the Cell buffer with proper length, and sets Owner, BuildOrder, CurvePosition and PrefabRef.
  • Geometry helper methods inside job include:
    • FillOldBlockBuffer / RemoveUnusedOldBlocks,
    • CreateBlocks overloads for node and segment cases,
    • TryOption: heuristic to pick baseWidth/middleWidth/splitCount for splitting widths,
    • CutStart / FindCutPos / CutCurves: for trimming bezier curves and splitting them according to distances and intersections,
    • FindContinuousEdge: checks connected edges to maintain continuous zoning across intersections,
    • Many calls to MathUtils, NetUtils and composition lookups to determine valid placements and continuity.

Because UpdateBlocksJob is lengthy and performs complex geometry and entity creation logic, it is the main implementation detail to read if you want to modify how block placement/splitting/reuse works.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    // Typical initialization performed by BlockSystem:
    m_ModificationBarrier = base.World.GetOrCreateSystemManaged<ModificationBarrier4>();
    m_UpdatedEdgesQuery = GetEntityQuery(new EntityQueryDesc {
        All = new ComponentType[] {
            ComponentType.ReadOnly<Edge>(),
            ComponentType.ReadOnly<SubBlock>()
        },
        Any = new ComponentType[] {
            ComponentType.ReadOnly<Updated>(),
            ComponentType.ReadOnly<Deleted>()
        },
        None = new ComponentType[] { ComponentType.ReadOnly<Temp>() }
    });
    RequireForUpdate(m_UpdatedEdgesQuery);
}

Notes for modders: - If you want to change how zoning blocks are generated along roads, inspect and modify the logic inside UpdateBlocksJob.CreateBlocks and its helpers (TryOption, CutCurves, FindContinuousEdge, etc.). These functions handle curve cutting, block splitting, sizing, and reuse. - Be careful with thread-safety: UpdateBlocksJob runs as a parallel IJobChunk and uses an EntityCommandBuffer.ParallelWriter (m_ModificationBarrier). Any changes to what the job writes must preserve parallel-friendly patterns and not capture managed state. - Avoid changing data layouts of Block, ZoneBlockData or SubBlock without ensuring compatibility with other systems that consume or produce these components.