Game.Routes.RaycastJobs
Assembly: Game
Namespace: Game.Routes
Type: public static class
Base: System.Object
Summary:
Contains Burst-compiled Unity DOTS jobs used to perform raycasts against route entities (route waypoints and route segments) in Cities: Skylines 2. The class exposes two job types:
- FindRoutesFromTreeJob — a single-threaded IJob that uses a NativeQuadTree to collect candidate route elements that intersect raycast lines and writes them into a NativeList
These jobs are performance-focused (Burst compatible), use Unity.Collections native containers and DOTS Component/Buffer lookups, and implement a broadphase (quad-tree based) + narrowphase (distance checks) pattern to efficiently raycast many lines against many route entities.
Fields
-
FindRoutesFromTreeJob.m_Input : NativeArray<RaycastInput> (ReadOnly)
Input raycast requests. Each entry supplies a line, type masks, filters (transport/route types), and flags used to decide which route elements to test. -
FindRoutesFromTreeJob.m_SearchTree : NativeQuadTree<RouteSearchItem, QuadTreeBoundsXZ> (ReadOnly)
Broadphase spatial index that stores route search items (waypoints/segments) organized by QuadTreeBoundsXZ. Used by the iterator to quickly find candidate route elements whose bounds intersect the raycast line. -
FindRoutesFromTreeJob.m_RouteList : NativeList<RouteItem> (WriteOnly)
Output list populated with RouteItem entries for each candidate route element discovered by the broadphase iteration. Each RouteItem links to an entity, element index and the originating raycast index. -
FindRoutesFromTreeJob.FindRoutesIterator
(private nested iterator)
Internal quad-tree iterator that implements INativeQuadTreeIterator. It stores: m_RaycastIndex
— index of the raycast in m_Inputm_Line
— Line3.Segment being tested-
m_RouteList
— reference to the native list to append candidates to
Implements Intersect(QuadTreeBoundsXZ) and Iterate(...) used by the quad-tree to test and record candidate items. -
RaycastRoutesJob.m_Input : NativeArray<RaycastInput> (ReadOnly)
The same raycast request array used by the narrowphase job to resolve final hits. -
RaycastRoutesJob.m_Routes : NativeArray<RouteItem> (ReadOnly)
Array of candidate RouteItem entries produced by the broadphase (FindRoutesFromTreeJob). The parallel job iterates this array (deferred length) to perform precise checks. -
RaycastRoutesJob
component lookup fields (ReadOnly)
ComponentLookup and BufferLookup references used to fetch data for candidate entities: m_PrefabRefData : ComponentLookup<PrefabRef>
m_PrefabRouteData : ComponentLookup<RouteData>
m_PrefabTransportLineData : ComponentLookup<TransportLineData>
m_WaypointData : ComponentLookup<Waypoint>
m_SegmentData : ComponentLookup<Segment>
m_PositionData : ComponentLookup<Position>
m_HiddenRouteData : ComponentLookup<HiddenRoute>
m_OwnerData : ComponentLookup<Owner>
-
m_CurveElements : BufferLookup<CurveElement>
-
RaycastRoutesJob.m_Results : NativeAccumulator<RaycastResult>.ParallelWriter (NativeDisableContainerSafetyRestriction)
Parallel accumulator used to collect final RaycastResult values for each raycast index. Marked with NativeDisableContainerSafetyRestriction to allow concurrent accumulation from multiple threads.
Properties
- None (this static helper contains only nested types and jobs; the jobs expose fields rather than properties).
Constructors
-
RaycastJobs()
(implicit static class constructor)
No explicit constructor — RaycastJobs is a static container type for the nested job structs. -
FindRoutesFromTreeJob
/RaycastRoutesJob
Both are value types (structs). They use the default implicit constructors generated by the compiler. All configuration is done by assigning the public fields prior to scheduling.
Methods
-
FindRoutesFromTreeJob.Execute() : void
Iterates the input raycasts (m_Input). For each raycast whose TypeMask includes RouteWaypoints or RouteSegments, it constructs a FindRoutesIterator configured with the ray's Line and index, then calls m_SearchTree.Iterate(ref iterator) to collect candidate RouteItem entries into m_RouteList. The quad-tree iterator uses a bounding-box intersection test (MathUtils.Intersect) to prune the search. -
FindRoutesFromTreeJob.FindRoutesIterator.Intersect(QuadTreeBoundsXZ) : bool
Bounding-box intersection test between the quad-tree node bounds and the job's line segment. Returns true if the node should be visited. -
FindRoutesFromTreeJob.FindRoutesIterator.Iterate(QuadTreeBoundsXZ, RouteSearchItem) : void
Called for each item in a visited quad-tree node. If the item’s bounds intersect the line, creates a RouteItem (entity, element index, raycast index) and appends it to m_RouteList. -
RaycastRoutesJob.Execute(int index) : void
The narrowphase per-candidate execution. For the RouteItem at the given index: - Reads the originating RaycastInput (by m_RaycastIndex).
- If the candidate entity is a waypoint and the raycast requested RouteWaypoints:
- Checks prefab/route/transport type filters, hidden route flags, and computes distance from the ray line to the waypoint position (MathUtils.Distance).
- If within routeData.m_SnapDistance, constructs a RaycastResult (owner, hit entity, positions, normalized distance, cell index) and accumulates it into m_Results for the originating raycast index.
- If the candidate entity is a route segment and the raycast requested RouteSegments:
- Retrieves the corresponding CurveElement from the entity's CurveElement buffer using the element index, checks filters and curve length.
- Computes distance between the ray line and the cubic curve (MathUtils.Distance), compares with half the snap distance, and on hit constructs/accumulates a RaycastResult with appropriate hit positions and metadata.
- Several small position/distance adjustments are applied to normalized distances to order hits (subtracting a normalized line-length factor and applying a tiny scale of the overlap distance).
Notes: - Both jobs are Burst-compiled via [BurstCompile]. - RaycastRoutesJob is an IJobParallelForDefer to allow scheduling with the m_Routes array produced at runtime (deferred length). - The jobs use TryGetComponent / HasComponent combinations to avoid errors when components are missing and to early-out for hidden routes.
Usage Example
// Pseudocode showing typical usage flow inside a system:
// 1) Prepare inputs
NativeArray<RaycastInput> inputs = /* prepared raycast inputs */;
NativeList<RouteItem> routeCandidates = new NativeList<RouteItem>(Allocator.TempJob);
// 2) Broadphase: find candidate route entities that intersect the ray lines.
// Feed a NativeQuadTree<RouteSearchItem, QuadTreeBoundsXZ> (m_SearchTree) built elsewhere.
var findJob = new RaycastJobs.FindRoutesFromTreeJob {
m_Input = inputs,
m_SearchTree = searchTree,
m_RouteList = routeCandidates
};
JobHandle findHandle = findJob.Schedule();
// 3) Convert candidate list to array for deferred parallel job
NativeArray<RouteItem> routesArray = routeCandidates.AsDeferredJobArray(ref findHandle);
// 4) Narrowphase: precise tests in parallel and accumulate results
var raycastJob = new RaycastJobs.RaycastRoutesJob {
m_Input = inputs,
m_Routes = routesArray,
m_PrefabRefData = GetComponentLookup<PrefabRef>(true),
m_PrefabRouteData = GetComponentLookup<RouteData>(true),
m_PrefabTransportLineData = GetComponentLookup<TransportLineData>(true),
m_WaypointData = GetComponentLookup<Waypoint>(true),
m_SegmentData = GetComponentLookup<Segment>(true),
m_PositionData = GetComponentLookup<Position>(true),
m_HiddenRouteData = GetComponentLookup<HiddenRoute>(true),
m_OwnerData = GetComponentLookup<Owner>(true),
m_CurveElements = GetBufferLookup<CurveElement>(true),
m_Results = raycastResults.AsParallelWriter()
};
JobHandle raycastHandle = raycastJob.Schedule(routesArray.Length, 64, findHandle);
// 5) Complete and read out results after job completion
raycastHandle.Complete();
// Consume raycastResults accumulator to get final RaycastResult lists per input index.
// Dispose temp containers when done
routeCandidates.Dispose();
inputs.Dispose();
routesArray.Dispose();
Notes and tips: - Ensure ComponentLookup/BufferLookup instances are updated (with system state) and accessed with the correct read-only/write permissions. - Use conservative batch sizes in Schedule to balance overhead and parallel throughput (example uses batchSize = 64). - The code relies on many game-specific types (RaycastInput, RaycastResult, RouteData, CurveElement, etc.). Make sure your mod provides the same component definitions or references the game's assemblies.