Skip to content

Game.EndFrameBarrier

Assembly:
Assembly-CSharp

Namespace:
Game.Pathfind

Type:
static class (AvailabilityJobs)

Base:

Summary:
This file implements AvailabilityJobs — a set of jobs and helper types used to calculate "availability" of service providers along path edges for pathfinding in Cities: Skylines 2. The algorithm performs a multi-source search from provider targets, combines provider capacities and costs, propagates availability along edges (using path cost calculations), and emits AvailabilityResult items that are then reduced into AvailabilityElement buffers on owner entities. Main entry points are AvailabilityJob (IJob) which runs the availability graph search and ProcessResultsJob (IJobParallelFor) which aggregates results into ECS buffers. The implementation is optimized for Burst, uses Unsafe collections and a custom min-heap to prioritize nodes by availability, and merges providers when their search frontiers meet.


Fields

  • private System.Diagnostics.Stopwatch m_Stopwatch
    This field is not present in AvailabilityJobs.cs. Instead, the file contains several internal/private structures and fields inside the AvailabilityExecutor that manage state for the search. Important state items include:
  • m_PathfindData: read-only UnsafePathfindData used to access nodes/edges/connections.
  • m_Allocator: Allocator used for allocating temporary unsafe containers.
  • m_Parameters: AvailabilityParameters used for cost/normalization factors.
  • m_ProviderTargets: UnsafeParallelMultiHashMap mapping providers to PathTarget entries.
  • m_Providers: UnsafeList storing per-provider capacity and adjusted cost.
  • m_ProviderIndex: UnsafeList disjoint-set-like index mapping to merge provider indices.
  • m_NodeIndex / m_NodeIndexBits: UnsafeList bit-indexed table for deduplicating FullNode entries.
  • m_Heap: UnsafeMinHeap priority heap for processing candidate nodes by availability.
  • m_NodeData: UnsafeList list storing discovered nodes, their best availability, link to next chain item, processed flag, and chosen next edge.

  • private Unity.Jobs.JobHandle <producerHandle>k__BackingField
    This property/backing-field is not present in this file. The file exposes two Jobs instead:

  • AvailabilityJob : IJob — schedules the graph search operation (Burst-compiled).
  • ProcessResultsJob : IJobParallelFor — aggregates the produced AvailabilityResult lists into ECS buffers.

Properties

  • public Unity.Jobs.JobHandle producerHandle { get; private set }
    This specific property is not part of AvailabilityJobs. Relevant public/internal data are the job structs and their public fields:
  • AvailabilityJob.m_PathfindData (ReadOnly NativePathfindData) and m_Action (AvailabilityAction) — the job reads path data and an action payload containing sources, providers and parameters.
  • ProcessResultsJob members: m_ResultItems (NativeList), m_OwnerData and m_EdgeLaneData (ComponentLookup<>), and m_AvailabilityElements (BufferLookup) used to write aggregated results.

Constructors

  • public EndFrameBarrier()
    There is no EndFrameBarrier constructor in this file. AvailabilityJobs is a static container type; key structs (AvailabilityExecutor, ProviderItem, NodeData, etc.) are value types with default constructors, and jobs are plain value types as well. The AvailabilityExecutor has an Initialize method used to set up internal containers rather than a public constructor.

Methods

  • protected virtual OnCreate() : System.Void
    There is no OnCreate in this file. Instead, main methods and important internal routines include:

  • AvailabilityJob.Execute() : void

    • Burst compiled. Entry point invoked by the job system. Calls static Execute(pathfindData, Allocator.Temp, ref actionData).
    • Behavior: if actionData contains providers, it constructs an AvailabilityExecutor, initializes it, adds sources and providers, runs the availability search, fills results, and releases temporary resources.
  • AvailabilityJob.Execute(NativePathfindData pathfindData, Allocator allocator, ref AvailabilityActionData actionData) : static void

    • Core orchestration static routine used by the job. Performs the full flow for one AvailabilityActionData.
  • AvailabilityExecutor.Initialize(NativePathfindData pathfindData, Allocator allocator, AvailabilityParameters parameters) : void

    • Allocates and initializes all internal unsafe lists, bitmaps and heap. Computes sizing based on node/edge counts and prepares containers for the search.
  • AvailabilityExecutor.Release() : void

    • Disposes all created Unsafe containers (lists, heap, maps). Ensures no leak of native allocations.
  • AvailabilityExecutor.AddSources(ref UnsafeQueue pathTargets) : void

    • Moves PathTarget items out of the provided queue into an internal UnsafeParallelMultiHashMap keyed by provider Entity for quick lookup when adding provider influence.
  • AvailabilityExecutor.AddProviders(ref UnsafeQueue availabilityProviders) : void

    • Pulls providers from the queue, creates ProviderItem entries (capacity, scaled cost), and iterates PathTargets for each provider to add initial connections into the node heap while accumulating a per-provider initial cost adjustment.
  • AvailabilityExecutor.FindAvailabilityNodes() : bool

    • Main processing loop: repeatedly extracts the highest-availability candidate from the heap, marks node as processed, inspects adjacent edges/connections (or the next edge if present), enqueues new candidate nodes, merges providers when different provider frontiers meet, and increments provider costs by traversed segments. Returns true if any nodes were added (i.e., results exist).
  • AvailabilityExecutor.FillResults(ref UnsafeList results) : void

    • After processing, iterates processed NodeData entries and creates AvailabilityResult entries for edges where both directions have been reached (i.e., forms a usable connection), normalizing availability using AvailabilityParameters.m_ResultFactor.
  • AvailabilityExecutor.AddHeapData(...) overloads : void

    • Helpers to get-or-create a NodeData entry for a FullNode, possibly merge providers, update best availability for that node, and insert HeapData to the heap.
  • AvailabilityExecutor.MergeProviders(int providerIndex1, int providerIndex2) : void

    • Merges two provider entries when their search fronts meet by combining capacities and costs and updating provider index mapping.
  • AvailabilityExecutor.GetAvailability(ProviderItem providerItem, float cost) : float

    • Computes availability value = capacity / (1 + cost + providerCost), used as heap priority (higher availability is better).
  • AvailabilityExecutor.GetOrAddNodeIndex / TryGetNodeIndex : bool

    • Internal deduplication / hash-bucketing to map FullNode values to NodeData indices using m_NodeIndex and m_NodeIndexBits arrays.
  • ProcessResultsJob.Execute(int index) : void

    • For each ResultItem:
    • Ensures owner has an AvailabilityElement buffer.
    • Merges multiple AvailabilityResult entries by owner (Entity) taking component-specific availability adjusted by edge lane deltas.
    • Writes aggregated AvailabilityElement entries into the owner entity's dynamic buffer.
    • Uses a temporary NativeParallelHashMap to reduce results per owner.
  • ProcessResultsJob.GetAvailability(float2 availability, float2 edgeDelta) : float2 (private static)

    • Helper logic to select availability based on edge lane delta flags and availability component ordering; used when reducing results to owners.

Notes on algorithmic behavior: - The search is not a straightforward Dijkstra on distances; it uses a custom "availability" metric combining provider capacity, provider cost (scaled by parameters), and path cost segments computed by PathUtils.CalculateCost. Availability is higher for more capacity and lower cumulative cost. - When multiple providers meet at a node, their capacities and costs are merged to represent a combined provider supply. - The code avoids allocations in the job-run path by using unsafe collections and a supplied Allocator for temporary work memory.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    m_Stopwatch = new Stopwatch();
}

{{ YOUR_INFO }} - How to schedule the availability search in a typical system: - Prepare an AvailabilityActionData instance containing: - m_Sources: queue of PathTarget entries (entity + delta info). - m_Providers: queue of AvailabilityProvider items (provider Entity, capacity, cost). - m_Parameters: AvailabilityParameters controlling cost factor and result normalization. - m_Results: an UnsafeList (empty) where results will be appended. - Create and populate a NativePathfindData (read-only) referencing the path graph (nodes/edges). - Schedule AvailabilityJob (Burst) and wait/complete (or chain via JobHandle) — the job will allocate temporary memory with Allocator.Temp by default when using the convenience Execute wrapper. - After AvailabilityJob completes, collect ResultItem objects referencing result lists per owner and execute ProcessResultsJob (IJobParallelFor) to write AvailabilityElement buffers on owner entities. Provide ComponentLookup/BufferLookup instances on the job and mark the buffer lookup with [NativeDisableParallelForRestriction] if necessary (as in the implementation). - Performance tips: - The implementation assumes Burst and low-level unsafe containers; use correct Allocator and ensure we run on worker threads where allowed. - Reuse allocations where possible across frames (not implemented here) to reduce GC/native allocation churn. - The size hints in Initialize (heap initial size, node list initial capacity) can be tuned according to map complexity and expected provider/sources count. - Important types referenced (extern / provided by engine/mod): - NativePathfindData, Edge, EdgeID, NodeID, PathTarget, AvailabilityProvider, AvailabilityActionData, AvailabilityParameters, AvailabilityResult, AvailabilityElement, EdgeLane, Owner, PathUtils, PathSpecification, EdgeFlags, PathMethod. - Safety and correctness: - This code relies on internal engine layout and accessors (GetEdge, GetConnection, etc.). When modding, make sure the pathfind data layout is compatible and that Burst compilation and unsafe containers are allowed for your mod environment.