Game.Net.RaycastJobs
Assembly:
Namespace: Game.Net
Type: public static class
Base: System.Object
Summary:
A collection of Burst-compiled jobs and helpers used by the raycast system for net-related hit testing in Cities: Skylines 2. This class groups three primary jobs:
- RaycastEdgesJob — tests edges and nodes (net geometry) against ray inputs, accounts for composition, elevation, markers, upgrades and placeholders, and accumulates RaycastResult entries.
- RaycastLabelsJob — tests label aggregates (text/label quads) against ray inputs and accumulates results with element indices.
- RaycastLanesJob — performs simplified lane-level tests (utility lanes / net lanes) using prefab lane geometry and utility masks.
These jobs rely on Unity ECS ComponentLookup/BufferLookup accessors, various geometry helpers (MathUtils, Bezier, Triangle/Quad/Line intersection routines), and a NativeAccumulator
Fields
- This static class does not declare top-level fields. Instead it defines three public nested Burst-compiled job structs and one utility method.
{{ YOUR_INFO }} - The nested jobs capture all required data via public fields (NativeArray / ComponentLookup / BufferLookup / NativeAccumulator) so they can be scheduled by Unity's Job System and run with Burst. Make sure lookups and buffers passed in are created/queried in the calling system and are valid for the job's execution.
Properties
- This static class defines no properties.
{{ YOUR_INFO }} - The nested job structs use public fields (not properties) to accept inputs; when creating job instances you must assign those fields directly.
Constructors
- This static class has no constructors (static classes are not instantiable).
{{ YOUR_INFO }} - The nested job structs are value types. Initialize them by setting their public fields before scheduling.
Methods
- public struct RaycastEdgesJob : IJobParallelForDefer {{ YOUR_INFO }}
- Summary: Burst-compiled job that iterates over candidate edge/node entities and runs precise geometry intersection tests to produce RaycastResult entries. It supports:
- Per-entity checks for Node geometry and Edge geometry (EdgeGeometry, EdgeNodeGeometry, Start/End node geometries).
- Marker handling (composition markers vs collision mask).
- Elevation offsets (several SetElevationOffset overloads) to account for terrain and elevated sections when RaycastFlags.ElevateOffset is used.
- Upgrades and sub-building resolution via Owner component traversal and InstalledUpgrade buffers.
- Placeholder/attachment resolution.
- Fine-grained triangle-based segment intersection (CheckSegment) for accurate mesh hit detection.
- Important fields (high level):
- m_FovTan : float — camera FOV tangent for radius calculations.
- m_Input : NativeArray
— per-ray inputs. - m_Edges : NativeArray
— deferred list of candidate entities for each ray. - Many ComponentLookup
fields: Owner, Edge, Node, Curve, Elevation, Composition, Orphan, NodeGeometry, EdgeGeometry, StartNodeGeometry, EndNodeGeometry, Placeholder, Attachment, Building, ServiceUpgrade, PrefabRef, NetData, NetCompositionData. - m_InstalledUpgrades : BufferLookup
— for upgrade resolution. - m_Results : NativeAccumulator
.ParallelWriter — parallel accumulator for results.
- Key methods inside the job:
- Execute(int index) — entry point called per candidate index; resolves whether candidate is Edge or Node and delegates to CheckEdge / CheckNode.
- CheckNode(Entity entity, int raycastIndex, RaycastInput input) — tests node geometry or marker nodes; handles composition width, elevation offsets, and normalized distance calculation.
- CheckEdge(Entity entity, int raycastIndex, RaycastInput input) — tests edge geometry, start/end node geometries, handles middle radius and splits segments where needed; if no geometry present falls back to curve distance test.
- CheckSegment(...) — performs triangle-based intersection over a segment (subdivided into 8 slices) and accumulates results with curve position.
- SetElevationOffset(...) (multiple overloads) — apply elevation-derived vertical offsets to geometry/curves/positions to correctly raycast over elevated terrain/structures.
- ValidateResult(RaycastInput input, ref RaycastResult result) — post-process a raw hit: resolves owner chain (service upgrades / installed upgrades / attachments), respects RaycastFlags (SubElements, NoMainElements, UpgradeIsMain, SubBuildings), checks type masks (Net vs StaticObjects), and finally verifies prefab net connect layers or placeholder acceptance.
- CheckPlaceholder(RaycastInput input, ref Entity entity) — handles placeholders and attachments when deciding whether to accept a hit on a static placeholder object.
-
Remarks:
- This job is complex: it needs correct ComponentLookup / BufferLookup contexts (read-only where appropriate) and the NativeAccumulator writer. Pay attention to RaycastInput flags (Markers, ElevateOffset, Placeholders, UpgradeIsMain, SubElements, etc.) when preparing inputs.
- The job expects entity lists of candidate edges/nodes, typically produced by a spatial index/partitioning query earlier in the raycast pipeline.
-
public struct RaycastLabelsJob : IJobParallelForDefer {{ YOUR_INFO }}
- Summary: Burst-compiled job that tests aggregated label entities (text/label aggregates) against ray inputs. Uses label extents and per-label LabelPosition buffers to build quads along label curves and intersects them with ray lines to produce RaycastResult entries (with cell indices for the label element hit).
- Important fields:
- m_Input : NativeArray
— per-ray inputs. - m_CameraRight : float3 — camera right vector to determine label quad orientation.
- m_Edges : NativeArray
— candidate aggregate entities for each ray. - m_AggregatedData : ComponentLookup
— mapping from candidate entity to aggregate root. - m_LabelExtentsData : ComponentLookup
— label bounds for scaling/orientation. - m_LabelPositions : BufferLookup
— per-aggregate label element buffer. - m_Results : NativeAccumulator
.ParallelWriter
- m_Input : NativeArray
- Key methods:
- Execute(int index) — gets aggregate from candidate, then calls CheckAggregate.
- CheckAggregate(int raycastIndex, RaycastInput input, Entity aggregate) — iterates all LabelPosition entries and:
- filters by collision mask,
- computes per-label scale from camera distance,
- computes bounds/quads along the label curve (start/middle/end sections subdivided),
- intersects quads with ray line and accumulates hits (sets m_Hit.m_CellIndex to [elementIndex, -1]).
-
Remarks:
- Label hit testing uses per-label curve geometry and tangent vectors. The job accounts for camera-facing orientation and scaling to avoid false hits on tiny labels.
-
public struct RaycastLanesJob : IJobParallelForDefer {{ YOUR_INFO }}
- Summary: Burst-compiled job for lane-level hit testing. It performs a simplified distance test between a lane's Bezier curve and the ray, then compares that distance to a minimum radius computed from camera parameters and optionally the prefab lane geometry size to decide a hit.
- Important fields:
- m_FovTan : float — camera FOV tangent.
- m_Input : NativeArray
- m_Lanes : NativeArray
— candidate lane entities. - m_CurveData : ComponentLookup
- m_PrefabRefData : ComponentLookup
- m_PrefabUtilityLaneData : ComponentLookup
— used to filter by UtilityTypes. - m_PrefabLaneGeometryData : ComponentLookup
— optional lane geometry sizes. - m_Results : NativeAccumulator
.ParallelWriter
- Key method:
- Execute(int index) — checks utility type mask vs requested mask, computes distance from Bezier to line with MathUtils.Distance, computes camera distance and min radius (GetMinLaneRadius), uses prefab lane size if available, and accumulates a hit when distance < radius (sets curve position and normalized distance).
-
Remarks:
- This job is an optimization for lane picking; it trades geometric detail for performance.
-
public static float GetMinLaneRadius(float fovTan, float cameraDistance) {{ YOUR_INFO }}
- Summary: Utility method that returns a minimum lane hit radius based on camera parameters. It computes cameraDistance * fovTan * 0.01f.
- Usage: RaycastLanesJob uses this to compute a distance threshold that scales with camera distance and field-of-view, ensuring lane hit tests remain usable at different zoom levels.
Usage Example
// Example (simplified): prepare and schedule a RaycastEdgesJob.
// Note: real usage requires valid ComponentLookup/BufferLookup and a NativeAccumulator created by the calling system.
var edgesJob = new RaycastJobs.RaycastEdgesJob
{
m_FovTan = cameraFovTan,
m_Input = raycastInputs, // NativeArray<RaycastInput>
m_Edges = candidateEdges, // NativeArray<RaycastSystem.EntityResult> (deferred)
m_OwnerData = lookupOwner, // ComponentLookup<Owner>
m_EdgeData = lookupEdge, // ComponentLookup<Edge>
m_NodeData = lookupNode, // ComponentLookup<Node>
m_CurveData = lookupCurve, // ComponentLookup<Curve>
m_ElevationData = lookupElevation, // ComponentLookup<Elevation>
m_CompositionData = lookupComposition, // ComponentLookup<Composition>
m_OrphanData = lookupOrphan, // ComponentLookup<Orphan>
m_NodeGeometryData = lookupNodeGeometry, // ComponentLookup<NodeGeometry>
m_EdgeGeometryData = lookupEdgeGeometry, // ComponentLookup<EdgeGeometry>
m_StartNodeGeometryData = lookupStartNodeGeometry,
m_EndNodeGeometryData = lookupEndNodeGeometry,
m_PlaceholderData = lookupPlaceholder,
m_AttachmentData = lookupAttachment,
m_BuildingData = lookupBuilding,
m_ServiceUpgradeData = lookupServiceUpgrade,
m_PrefabRefData = lookupPrefabRef,
m_PrefabNetData = lookupNetData,
m_PrefabCompositionData = lookupPrefabComposition,
m_InstalledUpgrades = bufferLookupInstalledUpgrades,
m_Results = resultsParallelWriter // NativeAccumulator<RaycastResult>.ParallelWriter
};
// Schedule the job (example): use the candidate list as the deferred length source.
// batchSize and dependency must be provided by the calling system.
JobHandle handle = edgesJob.Schedule(deferredCount, batchSize, dependency);
{{ YOUR_INFO }}
- When using these jobs in your own system:
- Ensure ComponentLookup