Game.Routes.SegmentCurveSystem
Assembly: Assembly-CSharp
Namespace: Game.Routes
Type: class
Base: GameSystemBase
Summary:
SegmentCurveSystem is an ECS system responsible for (re)building the per-segment curve representation (CurveElement buffer, and optionally CurveSource buffer) used by routing and movement logic. It detects updated routes (or, on game load, all routes) and schedules a Burst-compiled, multi-threaded job to compose curve segments from underlying lane/path data (car/watercraft/aircraft/train/human/path elements). The system handles special cases such as airways, area-connections, lane masters/slaves, connection segments and splits long curves into target-length pieces for consistent pathing and simulation.
Fields
-
private Unity.Entities.EntityQuery m_UpdatedRoutesQuery
Stores the query used to find segments whose curves must be updated. This query targets Segments that have CurveElement buffers and are either Updated() or have LivePath(), or have PathUpdated events — used for incremental updates. -
private Unity.Entities.EntityQuery m_AllRoutesQuery
Query for all segments that have CurveElement buffers. This is used once on game load to rebuild every route. -
private System.Boolean m_Loaded
Transient flag set by OnGameLoaded to indicate that all routes should be rebuilt on the next update. GetLoaded() consumes this flag so the full rebuild runs only once after loading. -
private TypeHandle __TypeHandle
Internal struct caching Entity/Component/Buffer handles (ComponentTypeHandle, ComponentLookup, BufferLookup, etc.) used by the jobs to efficiently access component and buffer data. Populated in OnCreateForCompiler.
Properties
- (none)
Constructors
public SegmentCurveSystem()
Default constructor. The system relies on OnCreate / OnCreateForCompiler to set up queries and handle caching.
Methods
protected override void OnCreate()
Initializes entity queries:- m_UpdatedRoutesQuery: segments + CurveElement buffer, with Updated or LivePath or PathUpdated event.
-
m_AllRoutesQuery: all segments that have CurveElement buffer. This sets up which segments are candidates for curve updates.
-
protected override void OnGameLoaded(Context serializationContext)
Called when the game has finished loading. Sets m_Loaded = true so that OnUpdate will rebuild all routes once. -
private bool GetLoaded()
Returns true if m_Loaded was set; clears the flag and returns true only once. Used to select between m_AllRoutesQuery (full rebuild) and m_UpdatedRoutesQuery (incremental). -
protected override void OnUpdate()
Main runtime logic. If there are matching segments (either all on load or only updated), it: - Builds an archetype chunk list for the chosen query asynchronously.
- Schedules FindUpdatedSegmentsJob to collect a unique list of segment Entities that need processing.
- Schedules UpdateSegmentCurvesJob (IJobParallelForDefer, Burst-compiled) with a deferred array of found segments and many ComponentLookup/BufferLookup handles.
-
Joins/disposes temporary NativeLists and chunk lists and updates system dependency. The job pipeline builds/clears CurveElement buffers and optional CurveSource buffers.
-
private void __AssignQueries(ref SystemState state)
Compiler helper (currently creates and disposes a temporary EntityQueryBuilder). Present for generated/compiled-system plumbing. -
protected override void OnCreateForCompiler()
Called by compiler-generated code to assign queries and call __TypeHandle.__AssignHandles. Ensures internal handles are populated for job scheduling. -
private struct TypeHandle.__AssignHandles(ref SystemState state)
(Inside TypeHandle) Populates all cached handles (EntityTypeHandle, ComponentTypeHandle, BufferLookup , ComponentLookup<> for many types, BufferLookup<> for many buffers, etc.). Used by the system when producing job data so the jobs can read component/buffer data efficiently.
Nested job types (important behavior summaries):
-
FindUpdatedSegmentsJob : IJob
(BurstCompile)
Scans archetype chunks produced by the entity query. Collects a unique set of segment entities that need updating into a NativeList. Uses PathUpdated component events where present to prefer owners for updates. Uses an internal NativeHashSet to ensure uniqueness. This reduces the work for the parallel job. -
UpdateSegmentCurvesJob : IJobParallelForDefer
(BurstCompile)
The core job that runs per-segment (parallelizable). For each segment entity it: - Fetches Owner, Segment, Position, PrefabRef, RouteData, and the route waypoints.
- Determines nodeDistance (based on route width) and segmentLength (route-defined segment length for splitting).
- If the route has explicit waypoints for the segment, builds curves between waypoint positions and any PathElements.
- Otherwise, reads the PathSource (the path owner entity) and inspects a large set of possible lane/path sources:
- Car/WATERCRAFT/Aircraft/Train/Human current lanes and their navigation lane buffers,
- PathElements buffer for path-following agents,
- Leader/follower group path elements (for group members),
- CurrentVehicle redirections (e.g. controllers, taxis, public transport),
- Prefab route data to get node spacing.
- For each lane/path source it calls TryAddSegments variants specialized per lane type which determine the last relevant sub-lanes, where to cut the curve (IsLast), and choose how to add curve elements.
- Handles special "connection segments" (sequence of airway/area-only curve elements) by processing them into interpolation points between neighboring non-connection curves.
- Cuts Bezier curves using MathUtils.Cut and MoveCurvePosition to trim endpoints based on nodeDistance.
- Uses NetUtils.FitCurve / NetUtils.StraightCurve and MathUtils.Length to compute and potentially split long spans into smaller CurveElement entries according to routeData.m_SegmentLength.
- Writes resulting DynamicBuffer
and, if present, DynamicBuffer (m_Entity + range) for each added curve. - Maintains state across additions: lastPosition, lastTangent, flags like airway/area/isFirst/connectionCount/hasLastPos/hasNextPos.
- Many helper methods are internal to the job:
- TryAddSegments overloads for different lane types (Car, Watercraft, Aircraft, Train, Human, Path buffers).
- TryAddSegments that operates on a Bezier4x3 (adds curve elements, optional curve source).
- TryAddSegments for interpolating between two positions (builds fitted curve or straight segments, splits into approximate lengths).
- IsLast to determine whether a given target is the "last" before the node, using targetDelta and nodeDistance.
- ShouldEndPath, IsPedestrianTarget, ShouldSkipTarget, GetMasterLane to handle lane/type logic.
- ProcessConnectionSegments to convert sequences of connection-only curves into actual connecting segments.
- The job is heavily optimized: uses ReadOnly ComponentLookup/BufferLookup where possible and marks m_CurveElements / m_CurveSources with NativeDisableParallelForRestriction when it writes to buffers.
Notes about special cases handled: - Airway (runway / aircraft lanes) handling changes vertical tangents and may force stayMidAir behavior for certain aircraft. - Area connection lanes and ConnectionLaneFlags are considered and can produce connection-curve handling. - Slave lanes are resolved to their master lane via sub-lane lookup. - When curve parts are shorter than nodeDistance or otherwise degenerate, they may be skipped. - Curve splitting is performed so each CurveElement is not longer than routeData.m_SegmentLength (rounded parts).
Usage Example
// Example: after SegmentCurveSystem has run, read curve elements for a segment entity
Entity segmentEntity = /* obtain segment Entity */;
if (EntityManager.HasBuffer<CurveElement>(segmentEntity))
{
DynamicBuffer<CurveElement> curves = EntityManager.GetBuffer<CurveElement>(segmentEntity);
for (int i = 0; i < curves.Length; i++)
{
Bezier4x3 bez = curves[i].m_Curve;
// Use bez.a, bez.b, bez.c, bez.d for rendering, path visualization, debugging, etc.
}
}
Additional notes for modders: - This system runs in the game simulation world using Unity.Entities jobs and Burst; any changes to component types, buffer layouts or naming must be reflected in the TypeHandle and jobs. - If you need to influence produced curves, consider modifying RouteData (m_Width, m_SegmentLength) or injecting different Curve/ConnectionLane/Navigation lane data on the relevant entities. - The UpdateSegmentCurvesJob is large and performance-sensitive; prefer small, targeted changes and test for race conditions when adjusting component lookups.