Skip to content

Game.OverrideSystem

Assembly: Assembly-CSharp (game)
Namespace: Game.Net

Type: class

Base: GameSystemBase

Summary: OverrideSystem is an ECS system used by Cities: Skylines 2 to detect and manage "overrides" between utility/fence lanes and other network lanes. It scans lanes that were updated, finds nearby utility/fence lanes that may visually or physically override portions of other lanes, computes CutRange buffers or full Overridden state for the affected lanes, and updates the lane search quadtree layer masks accordingly. The implementation is highly parallel: it uses multiple Burst-compiled jobs (FindUpdatedLanesJob, CheckLaneOverrideJob, CollectObjectsJob, UpdateOverriddenLayersJob) and native containers to keep the work off the main thread and to minimize GC. It coordinates with UpdateCollectSystem, SearchSystem, ModificationBarrier5 and ToolSystem for input data, spatial queries, safe structural changes and editor/game mode info.

Notes: - Works with Prefab/geometry data (UtilityLaneData, NetLaneData, NetLaneGeometryData, NetData, NetGeometryData) and per-lane Component data (Curve, PrefabRef, UtilityLane, etc.). - Adds/Removes components: Updated, Overridden and buffer CutRange via an EntityCommandBuffer supplied by ModificationBarrier5. - Updates the lane search quadtree mask so the search system knows which lanes are overridden (and which layers remain searchable). - Uses a MIN_PARALLEL_FENCE_DISTANCE threshold (1.6f) when expanding bounds and merging cut ranges. - Jobs are Burst-compiled and use NativeQuadTree iterators to efficiently locate nearby lanes; care is taken to avoid false positives by subdividing Bezier curves until a size limit.


Fields

  • private const float MIN_PARALLEL_FENCE_DISTANCE = 1.6f
    This constant is used as the minimum range when expanding lane curve bounds and to determine when to merge cut ranges. It matches the hard-coded threshold used throughout the iterator logic.

  • private UpdateCollectSystem m_NetUpdateCollectSystem
    Reference to the UpdateCollectSystem used to obtain which lanes were updated and their bounds. The system checks m_NetUpdateCollectSystem.lanesUpdated to decide whether to run and uses its updated bounds as inputs to FindUpdatedLanesJob.

  • private SearchSystem m_NetSearchSystem
    Reference to the SearchSystem that provides lane search quadtrees. Used for both read-only and writable access to the lane search tree when collecting nearby lanes and when updating layer masks.

  • private ModificationBarrier5 m_ModificationBarrier
    Used to create an EntityCommandBuffer.ParallelWriter to safely add/remove components (Updated, Overridden, CutRange buffer) from jobs, and to register job handles as producers so structural changes are synchronized.

  • private ToolSystem m_ToolSystem
    Used to determine whether the current actionMode is editor mode (m_EditorMode) to pick editor layers vs game layers for searches.

  • private TypeHandle __TypeHandle
    A small helper struct that holds ComponentLookup/BufferLookup fields for all component types that jobs need. It exposes an __AssignHandles(ref SystemState) method that is called at system creation to initialize the lookups.

  • private struct TreeAction (nested struct)
    Internal helper struct used to carry a pair (Entity, BoundsMask) from worker jobs into UpdateOverriddenLayersJob. The mask encodes flags like NotOverridden plus layer bits computed by CommonUtils.GetBoundsMask.

  • private struct UpdateOverriddenLayersJob (nested job type)
    Burst IJob that dequeues TreeAction items and updates the corresponding entity entry in the lane NativeQuadTree to set or clear layer mask bits (m_Mask). Runs after tree read/write dependencies are combined.

  • private struct FindUpdatedLanesJob (nested job type)
    Burst IJobParallelForDefer that iterates over a deferred array of updated Bounds2 and uses a NativeQuadTree iterator to enqueue candidate Entities into a result NativeQueue (parallel writer). It expands bounds slightly (1.6f) to account for proximity.

  • private struct CollectObjectsJob (nested job type)
    Burst IJob that drains a NativeQueue into a NativeList, sorts and deduplicates them, producing the final list of lanes to be processed by CheckLaneOverrideJob.

  • private struct CheckLaneOverrideJob (nested job type)
    The main Burst IJobParallelForDefer worker that for each candidate lane:

  • skips non-utility/fence prefabs
  • constructs a LaneIterator which searches nearby lanes using the lane search tree
  • computes CutRange lists or full Overridden state
  • enqueues tree update actions via a NativeQueue.ParallelWriter
  • adds Updated, Overridden components and CutRange buffers using the EntityCommandBuffer.ParallelWriter as required This job uses many ComponentLookup/BufferLookup fields and references to prefab data tables.

(Each nested job/iterator type also contains internal helper types and logic described in the source: e.g. LaneIterator.AddCutRange, IsParallel, ShouldMerge.)

Properties

  • None (this system does not expose public properties).
    Most access happens via the ECS ComponentLookup/BufferLookup fields propagated into jobs through TypeHandle.

Constructors

  • public OverrideSystem()
    Default preserved constructor. The system is created/owned by the World; initialization is performed in OnCreate.

Methods

  • protected override void OnCreate() : System.Void
    Initializes references to other systems that OverrideSystem depends on:
  • m_NetUpdateCollectSystem = World.GetOrCreateSystemManaged()
  • m_NetSearchSystem = World.GetOrCreateSystemManaged()
  • m_ModificationBarrier = World.GetOrCreateSystemManaged()
  • m_ToolSystem = World.GetOrCreateSystemManaged() This setups up the system to query update bounds, use the lane quadtree, get safe command buffers and know editor/game mode.

  • protected override void OnUpdate() : System.Void
    Main system update:

  • Checks m_NetUpdateCollectSystem.lanesUpdated; if false the system does nothing.
  • Prepares NativeList and NativeQueue for job inputs/outputs.
  • Calls CollectUpdatedLanes(...) to produce the list of lane entities that need to be processed; this schedules FindUpdatedLanesJob and CollectObjectsJob and returns a dependency handle.
  • Creates and schedules CheckLaneOverrideJob (IJobParallelForDefer) to compute overrides for each lane in the deferred list. The job obtains component lookups from the __TypeHandle via InternalCompilerInterface.GetComponentLookup and the lane search tree from m_NetSearchSystem.GetLaneSearchTree (read-only) and gets an EntityCommandBuffer from m_ModificationBarrier.
  • Creates and schedules UpdateOverriddenLayersJob to apply TreeAction items to the lane search tree (writable access).
  • Disposes the native containers with proper job dependencies.
  • Registers writers/readers with m_NetSearchSystem and records job handles with m_ModificationBarrier to synchronize structural changes.

  • private JobHandle CollectUpdatedLanes(NativeList<Entity> updateLanesList) : JobHandle
    Helper that:

  • Creates a temporary NativeQueue and, if lanes were updated, schedules FindUpdatedLanesJob (deferred) using updated lane bounds gathered from m_NetUpdateCollectSystem.GetUpdatedLaneBounds().
  • Schedules CollectObjectsJob (single-threaded) to pull queue contents into updateLanesList, sort and deduplicate.
  • Disposes the queue with the returned handle and registers lane search tree readers.
  • Returns the JobHandle that must be combined into the system dependency chain.

  • private void __AssignQueries(ref SystemState state)
    Compiler helper invoked from OnCreateForCompiler; here it is an empty registration call (new EntityQueryBuilder(Allocator.Temp).Dispose()) to ensure queries are set up for the generated system.

  • protected override void OnCreateForCompiler() : System.Void
    Compiler-generated hook that calls __AssignQueries(ref base.CheckedStateRef) and __TypeHandle.__AssignHandles(ref base.CheckedStateRef) to initialize component/ buffer lookups used by jobs.

  • TypeHandle.__AssignHandles(ref SystemState state) : void
    Initializes the ComponentLookup<...> and BufferLookup<...> fields inside the TypeHandle struct by calling state.GetComponentLookup(isReadOnly: ...) or state.GetBufferLookup() as appropriate. This must be called before scheduling jobs that access those lookups.

Important implementation details: - The lane collision/overlap detection is conservative: when checking intersection between Bezier curves it may subdivide curves until the segment size is below m_SizeLimit to avoid missing near-parallel or partially overlapping sections. - CutRange merging logic ensures small gaps less than MIN_PARALLEL_FENCE_DISTANCE are merged. - Overridden state is set/cleared via components; when a lane becomes Overridden the system removes any CutRange buffer (full override) and sets the quadtree mask so that search layers for that lane are updated to reflect not being available for certain search layers. - The CheckLaneOverrideJob may add an Updated tag component when it changes a lane's CutRange/Overridden state so downstream systems can respond.

Usage Example

// This system runs in the game's ECS world automatically. As a modder, you can
// observe its results by reading the Overridden component or CutRange buffers
// on network lanes, or by listening for Updated tags. Example: a small system
// that prints lanes currently marked Overridden.

public partial class DumpOverriddenLanesSystem : SystemBase
{
    protected override void OnCreate()
    {
        base.OnCreate();
    }

    protected override void OnUpdate()
    {
        var overriddenLookup = SystemAPI.GetComponentLookup<Overridden>(true);
        Entities
            .WithName("DumpOverriddenLanes")
            .WithAll<Overridden>()
            .ForEach((Entity e) =>
            {
                // Do something with e; here we would log or inspect it.
                // Avoid heavy work on main thread; use this pattern for debug only.
            }).WithoutBurst().Run();
    }
}

Further tips for modders: - If you need to influence override decisions, modify the prefab data (UtilityLaneData / NetLaneData) or Component data (UtilityLane flags) that CheckLaneOverrideJob reads; changes must be safe for jobs and synchronized with ModificationBarrier. - Avoid changing the lane search quadtree directly from mod code — use SearchSystem APIs and respect the read/write registration (AddLaneSearchTreeReader/AddLaneSearchTreeWriter) to prevent race conditions. - When debugging geometry/curve intersection issues, remember the job subdivides Bezier segments up to a size limit (m_SizeLimit) before deciding intersection/overlap — this affects performance vs precision.