Skip to content

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.ParallelWriter to collect hits in parallel. They are intended to be scheduled from systems that perform raycasting for selection, tool interaction, or other hit-testing needs.


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
  • 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 and BufferLookup are created with the correct EntityManager/World and access modes (read-only as shown). - The NativeAccumulator must be created and its ParallelWriter passed to jobs for accumulation. - Provide the candidate entity lists (m_Edges, m_Lanes) from your spatial partitioning or broad-phase query; these are typically deferred lists (IJobParallelForDefer target). - Validate and dispose of Native containers appropriately to avoid leaks and race conditions. - Because these jobs are Burst-compiled and run in parallel, avoid non-threadsafe API calls inside them and prefer ECS data structures and math helpers as shown in the source code.