Skip to content

Game.ServiceCoverageSystem

Assembly:
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
ServiceCoverageSystem is the ECS system responsible for computing and applying "service coverage" for buildings and network edges in Cities: Skylines 2. It: - Schedules and runs several Burst-compiled jobs to prepare coverage sources, process coverage contributions from pathfind results, and apply coverage to edge buffers. - Enqueues building coverage searches into the PathfindQueueSystem so pathfinding can discover reachable edges/targets for a given service (parks, post, education, etc.). - Clears and writes per-edge Game.Net.ServiceCoverage buffers for a given CoverageService frame slot (the system uses a rotating coverage index derived from the simulation frame). - Honors district boundaries, density modifiers, efficiencies, and temporary building replacements when computing coverage.

The system contains multiple nested job and helper types (ClearCoverageJob, PrepareCoverageJob, ProcessCoverageJob, ApplyCoverageJob, SetupCoverageSearchJob, CoverageElement, BuildingData, QueueItem, BuildingDataComparer, TypeHandle) used to parallelize and organize the work.


Fields

  • public const uint COVERAGE_UPDATE_INTERVAL
    {{ The system defines a constant COVERAGE_UPDATE_INTERVAL = 256 to determine the coverage update cadence and the rotating coverage index derived from simulation frames. }}

  • private SimulationSystem m_SimulationSystem
    {{ Reference to the SimulationSystem used to read the current frameIndex and other simulation timing. }}

  • private PathfindQueueSystem m_PathfindQueueSystem
    {{ Reference to the PathfindQueueSystem used to enqueue coverage pathfind searches and to receive their results. }}

  • private AirwaySystem m_AirwaySystem
    {{ Reference used when configuring pathfinding targets (airway data used by PathfindTargetSeekerData). }}

  • private EntityQuery m_EdgeQuery
    {{ Query selecting network edges (Game.Net.Edge) that also have ServiceCoverage buffers. Used when clearing coverage via a job. }}

  • private EntityQuery m_BuildingQuery
    {{ Query selecting buildings that have CoverageServiceType and CoverageElement buffers (i.e., buildings that can provide coverage). }}

  • private PathfindTargetSeekerData m_TargetSeekerData
    {{ Helper data used to construct PathfindTargetSeeker instances for building coverage searches. }}

  • private NativeQueue<QueueItem> m_PendingCoverages
    {{ Queue of pending building coverage requests. Each entry has the building entity, queue frame and result frame. The queue is persistent and drained/processed each update. }}

  • private CoverageService m_LastCoverageService
    {{ Tracks which CoverageService was processed in the previous update, to avoid reprocessing the same service slot unnecessarily. }}

  • private TypeHandle __TypeHandle
    {{ Internal cached handles for Component/Buffer/SharedComponent lookups used across the jobs. This is populated in OnCreateForCompiler. }}


Properties

  • None (the system exposes no public properties).

Nested types (summary)

{{ The class defines several nested structs used primarily as job/data containers. Important ones: }}

  • ClearCoverageJob (IJobChunk, Burst compiled)
    {{ Clears the per-edge ServiceCoverage buffer for the coverage index being computed (sets that slot to default for all edges). Uses BufferTypeHandle. }}

  • CoverageElement (struct, IComparable)
    {{ Represents a candidate coverage contribution for an edge with fields:

    • unsafe void* m_CoveragePtr: pointer into the edge ServiceCoverage buffer slot to write to.
    • float2 m_Coverage: computed 2D coverage values (e.g., for day/night or two-channel coverage).
    • float m_AverageCoverage: scalar metric used to sort contributions.
    • float m_DensityFactor, m_LengthFactor: modifiers used when applying contributions. Implements CompareTo to order by m_AverageCoverage. }}
  • QueueItem (struct)
    {{ Small POD describing an enqueued coverage search: building entity, queue frame (when it was enqueued) and result frame (when pathfind results should be applied). }}

  • BuildingData (struct)
    {{ Per-building temporary data used across the prepare/process/apply pipeline: entity, element indices/counts, capacity/remaining capacity tracked during applying. }}

  • PrepareCoverageJob (IJob, Burst compiled)
    {{ Scans building chunks matching the building query and fills NativeList and reserves elements array length for CoverageElements. Filters buildings by CoverageService. }}

  • ProcessCoverageJob (IJobParallelForDefer, Burst compiled)
    {{ For each building (from BuildingData) iterates its Game.Pathfind.CoverageElement entries (which are created from pathfind results) and computes CoverageElement entries:

    • computes contribution magnitude from prefab CoverageData, building efficiency, and cost (distance/cost from pathfind),
    • handles district filtering (ServiceDistrict + BorderDistrict) and density modifiers,
    • writes pointers into the elements list that later will be used to write into the actual ServiceCoverage buffers. This job populates the NativeList and updates BuildingData (element counts). }}
  • ApplyCoverageJob (IJob, Burst compiled)
    {{ Takes the lists filled by the previous jobs and applies coverage greedily:

    • sorts buildings by best contribution,
    • attempts to apply contributions to the target edge ServiceCoverage slot (via unsafe pointer),
    • clamps and scales contributions based on density/length factors and building remaining capacity/capacity,
    • updates building remaining capacity and removes finished buildings. Uses UnsafeUtility to write directly into Game.Net.ServiceCoverage buffer elements. }}
  • SetupCoverageSearchJob (IJob, Burst compiled)
    {{ Per-building job executed before enqueuing a pathfinding search. Sets up CoverageAction data (CoverageParameters) based on the prefab's CoverageData (range, methods), and priming the PathfindTargetSeeker to find targets for that building. }}

  • BuildingDataComparer (IComparer)
    {{ Compares buildings by the top element's CoverageElement (used on ApplyCoverageJob sorting). }}

  • TypeHandle (struct)
    {{ Container for all the Component/Buffer/SharedComponent handles used by the system, and a helper __AssignHandles to initialize them from a SystemState. }}


Constructors

  • public ServiceCoverageSystem()
    {{ Default constructor; system initialization mostly happens in OnCreate(). The constructor itself is empty (preserve attribute applied on lifecycle methods). }}

Methods

  • protected override void OnCreate()
    {{ Initializes internal system references and entity queries:
  • fetches SimulationSystem, PathfindQueueSystem, AirwaySystem,
  • creates m_EdgeQuery and m_BuildingQuery with the required component constraints,
  • initializes PathfindTargetSeekerData and a persistent NativeQueue for pending coverages,
  • sets m_LastCoverageService to CoverageService.Count (uninitialized sentinel). This method is marked [Preserve] in the original. }}

  • protected override void OnDestroy()
    {{ Disposes the persistent m_PendingCoverages queue and calls base.OnDestroy. Marked [Preserve]. }}

  • protected override void OnGamePreload(Purpose purpose, GameMode mode)
    {{ Clears the pending queue and resets m_LastCoverageService. Called when preloading a new game or similar states. }}

  • protected override void OnUpdate()
    {{ Main update that runs each frame:

  • computes the CoverageService index for the current frame and the next frame,
  • if both frame services are equal, only attempts to enqueue pending coverages,
  • otherwise it gathers all buildings for the next-frame service and enqueues pending searches,
  • when the previously computed service (m_LastCoverageService) is not the sentinel, schedules this frame's full coverage pipeline:
    • PrepareCoverageJob to gather BuildingData and reserve element array,
    • ClearCoverageJob (parallel over edges) to reset the target ServiceCoverage slot,
    • ProcessCoverageJob (IJobParallelForDefer) to compute coverage contributions (deferred per-building parallel for using building list),
    • ApplyCoverageJob to greedily apply contributions into the buffers,
  • disposes temporary arrays and combines job dependencies into base.Dependency. This method coordinates job scheduling, uses InternalCompilerInterface to obtain handles, and enqueues pathfind actions via PathfindQueueSystem when needed. }}

  • private bool EnqueuePendingCoverages(out JobHandle outputDeps)
    {{ Processes the m_PendingCoverages queue and for each queued building:

  • constructs PathfindParameters and chooses pathfinding methods based on service,
  • constructs a CoverageAction and PathfindTargetSeeker, and schedules a SetupCoverageSearchJob per building to populate action.data and targets,
  • enqueues the action into the PathfindQueueSystem with its target result frame. The method batches processing so it won't starve the main thread and returns whether any entries were processed. It returns combined JobHandle dependencies for scheduled setup jobs. }}

  • public static void SetupPathfindMethods(CoverageService service, ref PathfindParameters pathfindParameters, ref SetupQueueTarget setupQueueTarget)
    {{ Static helper that configures which PathMethod(s), road types and activity masks should be used for pathfinding based on the CoverageService type:

  • Pedestrian-only for posts, education, shelters, welfare and parks (parks also add many activity masks),
  • Road (vehicle) for default services. This is used when enqueuing pathfind searches. }}

  • private static CoverageService GetFrameService(uint frame)
    {{ Computes the rotating CoverageService enum value used for a given simulation frame index. The code maps (frame % 256) * 8 / 256 to a CoverageService value so one of the CoverageService slots is updated per interval. }}

  • private void __AssignQueries(ref SystemState state)
    {{ Internal method used by compiler-generated OnCreateForCompiler. In the original type it is effectively a placeholder but is called to ensure queries/handles are bound in Ahead-Of-Time compiled contexts. }}

  • protected override void OnCreateForCompiler()
    {{ Internal helper called by the ECS compiler to assign queries and populate TypeHandle by calling __AssignQueries and __TypeHandle.__AssignHandles. }}


Usage Example

// Example: configure PathfindParameters for a park service using the static helper:
var pathfindParameters = new PathfindParameters();
var setupQueueTarget = default(SetupQueueTarget);
ServiceCoverageSystem.SetupPathfindMethods(CoverageService.Park, ref pathfindParameters, ref setupQueueTarget);

// Typical usage of the ServiceCoverageSystem is automatic in the ECS world.
// The system enqueues coverage searches and writes into Game.Net.ServiceCoverage buffers
// via its scheduled jobs, so modders generally do not call methods on it directly.
// To enqueue a custom coverage search you would create a CoverageAction and feed it to
// the PathfindQueueSystem similarly to how the system does inside EnqueuePendingCoverages.