Skip to content

Game.NodeReductionSystem

Assembly: Game
Namespace: Game.Tools

Type: class

Base: GameSystemBase

Summary:
NodeReductionSystem is an ECS system that detects and reduces/moves intermediate network nodes (net nodes used by roads/rails/etc.) to simplify and optimize the network geometry. It runs as a two-phase job pipeline:

  • FindCandidatesJob (IJobChunk, Burst compiled): scans candidate node entities (Temp + Node + Updated, excluding Deleted/Fixed) and enqueues ReductionData for nodes that are eligible for reduction/move. It performs extensive checks: connected-edge count, middle-connections, fixed flags, prefab compatibility, elevation/composition flags, upgraded state, ownership and owner definition constraints, and direction/tangent checks depending on height checking.
  • NodeReductionJob (IJob, Burst compiled): dequeues ReductionData and attempts to either join the two connected edges into one (reducing a node) or move endpoints (shortening/lengthening edges) while preserving important flags, build orders, road flags, connection buffers, and connected-node distances. It updates Temp flags, Curve and Edge component data, connected-edge/node buffers and handles special cases like snapping to grid cell sizes or forbidding moves because of elevated geometry.

The system uses ComponentLookup and BufferLookup handles, a NativeQueue for communication between the two job steps, and ToolSystem.actionMode to detect editor mode behavior. It is Burst compiled for performance and uses parallel scheduling for chunk scanning and a single job to apply changes.


Fields

  • private ToolSystem m_ToolSystem
    Used to query current tool/action mode (used to determine editor mode checks and restrictions). Initialized in OnCreate via World.GetOrCreateSystemManaged().

  • private EntityQuery m_TempNodeQuery
    EntityQuery used to select candidate nodes (Temp + Node + Updated, excludes Deleted and Fixed). The query is required for update via RequireForUpdate.

  • private TypeHandle __TypeHandle
    Generated helper struct that holds EntityTypeHandle, ComponentLookup and BufferLookup handles used by jobs. Assigned in OnCreateForCompiler via __AssignHandles.

  • private struct FindCandidatesJob
    Nested Burst-compiled IJobChunk that scans archetype chunks and enqueues ReductionData for nodes that pass eligibility checks.

  • private struct ReductionData
    Small POD struct used to send candidate information from the chunk job to the main reduction job. Fields:

  • Entity m_Node
  • Bounds1 m_EdgeLengthRange
  • bool m_SnapCellSize
  • bool m_ForbidMove
  • bool m_CheckHeight
  • bool m_NoEdgeConnection

  • private struct NodeReductionJob
    Nested Burst-compiled IJob that dequeues ReductionData and performs the actual reduction/move operations: joining curves, updating Temp flags, swapping/merging edge data, updating build orders and road flags, and updating connected-edge and connected-node buffers.

  • private struct TypeHandle
    Nested helper struct (auto-generated) that provides ComponentLookup/BufferLookup handles and a method __AssignHandles to populate them from a SystemState.


Properties

  • (none public)
    All component lookups and job handles are internal/field-level and acquired through the TypeHandle and InternalCompilerInterface at runtime. There are no public properties exposed on this system.

Constructors

  • public NodeReductionSystem()
    Default constructor. The system uses OnCreate to perform initialization (obtain ToolSystem and setup queries). Marked with [Preserve] on OnCreate/OnUpdate for IL2CPP/runtime preservation.

Methods

  • protected override void OnCreate()
    Initializes the system:
  • Calls base.OnCreate().
  • Gets/creates the ToolSystem instance.
  • Builds m_TempNodeQuery for Temp + Node + Updated and excludes Deleted/Fixed.
  • Calls RequireForUpdate(m_TempNodeQuery) so the system only runs when relevant entities exist.

  • protected override void OnUpdate()
    Main runtime logic:

  • Allocates a NativeQueue (TempJob).
  • Constructs FindCandidatesJob with read-only ComponentLookup/BufferLookup handles and enqueues matching nodes in parallel (ScheduleParallel).
  • Constructs NodeReductionJob with write ComponentLookup/BufferLookup handles and the queue; schedules it as a dependent job to apply the reductions/moves.
  • Disposes the queue with the returned job handle and updates base.Dependency.

  • protected override void OnCreateForCompiler()
    Compiler helper method: assigns queries and calls __TypeHandle.__AssignHandles to populate Component/Buffer handles used by generated job descriptors. (Part of generated system plumbing.)

  • private void __AssignQueries(ref SystemState state)
    Small helper used by compiler-generated OnCreateForCompiler; currently creates and disposes an EntityQueryBuilder (present for compiler compatibility).

  • FindCandidatesJob.Execute(...) / CanMove(...)
    FindCandidatesJob scans each node entity in a chunk and runs CanMove which performs:

  • Rejects nodes without original entity or with Temp flags marking for delete/replace/upgrade.
  • Iterates connected edges (via EdgeIterator) and enforces: exactly two edges, no middle connections, both edges have Temp component, no Fixed edge component, same prefab on both edges, prefab geometry constraints (Asymmetric, SnapCellSize, StraightEdges, NoEdgeConnection), composition/elevation compatibility, upgraded flags equality, ownership and ownerDefinition checks (different behavior in editor vs runtime), and tangent/height checks depending on flags.
  • If eligible, packages a ReductionData with flags/ranges and enqueues it.

  • NodeReductionJob.Execute() / TryReduceOrMove(ReductionData)
    Handles actual reduction/move. High-level responsibilities:

  • Reads connected edges for the node and skips if not exactly two non-deleted edges.
  • Loads Temp, Edge, Curve components for both edges and the node.
  • Attempts to join curves (TryJoinCurve) — either full join (node deletion) or partial move (split/join depending on edge lengths and configured max edge length).
  • Updates Temp flags to mark Delete/Hidden/Modify/Combine/RemoveCost appropriately to preserve build-cost semantics.
  • Updates Curve (m_Bezier and m_Length), Edge connections (start/end node), BuildOrder (m_Start/m_End), and Road flags (direction flags).
  • Moves and reconciles connected nodes and connected-edge buffers using MoveConnectedNodes overloads, Add/Remove/SwitchConnectedEdge helpers, and distance calculations (GetDistance / GetClampedDistance).
  • Maintains special cases for LocalConnectFlags.ChooseSides prefabs when deciding which edge a connected node should belong to.
  • Several helper methods: TryJoinCurve (joins Bezier curves and checks tolerance, applies height offsets), FixStartSlope/FixEndSlope, FindHeightOffset, ReplaceEdgeConnection, ReplaceEdgeData, MoveConnectedNodes, RemoveConnectedEdge, AddConnectedEdge, SwitchConnectedEdge, GetClampedDistance, GetDistance.

Notes about math/geometry: The system uses MathUtils helpers and math library (Unity.Mathematics) to handle Bezier operations, tangents, dot products, distances, length clamping/dividing, and tolerance comparisons. Many checks use thresholds (e.g., dot >= 0.9995, distance < 0.1).


Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    // Typical initialization performed by NodeReductionSystem:
    m_ToolSystem = base.World.GetOrCreateSystemManaged<ToolSystem>();
    m_TempNodeQuery = GetEntityQuery(
        ComponentType.ReadOnly<Temp>(),
        ComponentType.ReadOnly<Node>(),
        ComponentType.ReadOnly<Updated>(),
        ComponentType.Exclude<Deleted>(),
        ComponentType.Exclude<Fixed>());
    RequireForUpdate(m_TempNodeQuery);
}

// The system schedules internal jobs in OnUpdate; modders normally don't need to call the jobs directly.
// If extending/customizing, follow the pattern of constructing component lookups and scheduling the chunk job (FindCandidatesJob)
// followed by the IJob (NodeReductionJob) and ensure the NativeQueue is disposed with the scheduled dependency.

Additional notes for modders: - This system is heavily tied to the game's ECS component types (Temp, Node, Edge, Curve, PrefabRef, NetGeometryData, Upgraded, Elevation, Owner, OwnerDefinition, BuildOrder, Road, ConnectedEdge, ConnectedNode, LocalConnectData). Changing those component schemas or names may break behavior. - The jobs are Burst compiled and use only blittable types. Avoid introducing managed references into the job structs unless you remove Burst or adapt code accordingly. - The system respects editor-mode rules (m_EditorMode) and enforces stricter ownership/ownerDefinition constraints in runtime mode; be careful when simulating or testing in editor vs runtime. - The algorithm makes geometry approximations (distance tolerance, dot thresholds). If altering thresholds or geometry math, validate visual and gameplay consequences (connections, mesh generation, and building costs). - Internal methods and generated TypeHandle names (like __AssignHandles and InternalCompilerInterface usage) are compiler-generated; do not rely on or call them directly from mods unless required by advanced ECS integration.