Skip to content

Game.Rendering.RouteBufferSystem

Assembly:
Namespace: Game.Rendering

Type: class

Base: GameSystemBase, IPreDeserialize

Summary:
Manages GPU-side route segment buffers and materials used for rendering route paths (e.g. transit/vehicle routes). It tracks Route entities, builds per-route segment data (Bezier segments and nodes) on worker threads (Burst-compiled IJobParallelFor), and exposes ComputeBuffer + Material + bounds/size for rendering. The system uses Unity's DOTS APIs (Entity queries, BufferLookup, ComponentLookup), Burst jobs, and Native containers. It reacts to route updates and (re)allocates/updates managed ComputeBuffers and Materials for each routed prefab.


Fields

  • private RenderingSystem m_RenderingSystem
    Holds reference to the RenderingSystem (used for frame/time values when scheduling the UpdateBufferJob).

  • private PrefabSystem m_PrefabSystem
    Reference to the PrefabSystem used to resolve RoutePrefab instances for route entities.

  • private EntityQuery m_UpdatedRoutesQuery
    Query for routes that need updating (Updated / LivePath / Deleted / PathUpdated events).

  • private EntityQuery m_AllRoutesQuery
    Query that matches all Route entities (used when loading to initialize buffers).

  • private EntityQuery m_RouteConfigQuery
    Query used to get route configuration data (e.g. fallback missing route prefab).

  • private List<ManagedData> m_ManagedData
    Managed (UnityEngine) objects per-route: Material and ComputeBuffer references. Lifetimes must be disposed manually.

  • private NativeList<NativeData> m_NativeData
    Native-side data for each route (UnsafeList of SegmentData, bounds, length, updated flag, entity reference). Used by the worker job.

  • private Stack<int> m_FreeBufferIndices
    Pool of free indices for reusing managed/native buffer slots when routes are deleted.

  • private JobHandle m_BufferDependencies
    JobHandle for the scheduled UpdateBufferJob. Completed before accessing managed data.

  • private bool m_Loaded
    Flag set by PreDeserialize to indicate initial load; used to initialize all routes on next update.

  • private TypeHandle __TypeHandle
    Generated structure holding component/type handles used by the system (internal DOTS boilerplate).

Nested types (brief):

  • ManagedData (private class)
    Holds Material, ComputeBuffer, Vector4 size, original render queue and an "updated" flag. Provides Initialize(RoutePrefab) and Dispose() to create/destroy UnityEngine.Object resources.

  • NativeData (private struct)
    Holds UnsafeList m_SegmentData, Bounds3 m_Bounds, Entity m_Entity, float m_Length, and a bool m_Updated. Has Initialize(Entity) and Dispose().

  • SegmentData (private struct)
    Layout that represents one route segment or node (float4x4 curve encoded, position, size factors, opacity, divided opacity, broken flag). This struct is copied into the ComputeBuffer for rendering.

  • UpdateBufferJob (private Burst-compiled struct)
    IJobParallelFor that computes/updates SegmentData lists for each updated route (reads many ECS lookups and buffers). It creates and manipulates Native containers, combines segment pieces, computes bounds and per-segment attributes, handles shared curve deduplication, and writes into NativeData.m_SegmentData.

Other nested helper structs: CurveKey, CurveValue, SourceKey (used inside the job to dedupe/merge segments).

Properties

  • (none public)
    This system exposes no public properties. Access to per-route buffers/materials is via GetBuffer(int index, out ...).

Constructors

  • public RouteBufferSystem()
    Default constructor (preserved for runtime). Typical initialization is done in OnCreate.

Methods

  • protected override void OnCreate()
    Initializes references to RenderingSystem and PrefabSystem and creates entity queries used by the system (m_UpdatedRoutesQuery, m_AllRoutesQuery, m_RouteConfigQuery). Call base.OnCreate().

  • protected override void OnDestroy()
    Calls Clear(), disposes native lists (m_NativeData) and completes outstanding jobs before destruction.

  • public void PreDeserialize(Context context)
    Implements IPreDeserialize. Called before deserialization/load to clear existing buffers and mark the system as loaded so it initializes buffers for all routes on the next update.

  • private void Clear()
    Disposes/cleans managed Materials and ComputeBuffers, clears free index pool, completes outstanding jobs and disposes native data lists. Safe to call on load/teardown.

  • public unsafe void GetBuffer(int index, out Material material, out ComputeBuffer segmentBuffer, out int originalRenderQueue, out Bounds bounds, out Vector4 size)
    Retrieves the Material and ComputeBuffer for a given buffer index. Completes the scheduled UpdateBufferJob, updates (or creates) the ComputeBuffer from the NativeData.m_SegmentData if needed, and returns bounds and the size vector. Callers must ensure they pass a valid index (RouteBufferIndex.m_Index) and that the system has finished its job dependencies.

  • private bool GetLoaded()
    Internal helper to flip the m_Loaded flag once (returns true the first time after PreDeserialize).

  • protected override void OnUpdate()
    Main update loop. Gathers route entities to initialize or mark for update, allocates or reuses ManagedData/NativeData entries, sets updated flags for routes that changed, and schedules the Burst UpdateBufferJob (IJobParallelFor) to build segment lists. Maintains m_BufferDependencies and base.Dependency accordingly.

  • private void __AssignQueries(ref SystemState state)
    Compiler-generated helper used in OnCreateForCompiler (DOTS boilerplate).

  • protected override void OnCreateForCompiler()
    Compiler helper for DOTS-generated code; sets up type handles.

  • Nested: ManagedData.Initialize(RoutePrefab) / Dispose()
    Create a copy of the prefab Material (so each route material is unique), set m_Size vector from prefab width/segment length, and dispose resources on deletion.

  • Nested: NativeData.Initialize(Entity) / Dispose()
    Initialize entity reference and dispose the UnsafeList when no longer used.

  • Nested (UpdateBufferJob.Execute and helpers):

  • Execute(int index): For each updated NativeData element builds the list of segments (dedupes shared curves, slices curve sources, computes opacities/size factors, computes bounds and total route length).
  • AddSegment(...): Adds or reuses a SegmentData in the UnsafeList, handles shared curve coalescing via internal NativeHashMap.
  • GetSizeFactor(int sharedCount): Heuristic to reduce thickness when multiple routes share the same curve.
  • AddNode(...): Add a node (waypoint) entry as a degenerate SegmentData so the renderer can draw waypoint markers.

Notes about multi-threading & memory: - UpdateBufferJob uses many ReadOnly lookups and Native containers and is Burst-compiled to run in parallel. The system completes the job (m_BufferDependencies.Complete()) before any managed UnityEngine objects (ComputeBuffer / Material) are read or modified. - NativeData.m_SegmentData is created as an UnsafeList with Allocator.Persistent and must be disposed explicitly (Clear/OnDestroy). - ManagedData holds UnityEngine.Object instances; Dispose must be called on the main thread.

Usage Example

// Typical pattern inside a rendering or UI system that wants to draw routes:
// - Each Route entity has a RouteBufferIndex component containing an index to this system's buffers.
// - Call GetBuffer(index, out material, out segmentBuffer, out originalRenderQueue, out bounds, out size)
//   to obtain the data needed to issue a draw call using the provided material and ComputeBuffer.

// Example: retrieving the route buffer for rendering
int index = routeBufferIndexComponent.m_Index;
if (index >= 0)
{
    Material mat;
    ComputeBuffer segBuffer;
    int originalQueue;
    Bounds bounds;
    Vector4 size;
    routeBufferSystem.GetBuffer(index, out mat, out segBuffer, out originalQueue, out bounds, out size);

    if (segBuffer != null && mat != null)
    {
        // Set shader properties and dispatch draw (pseudo-code)
        mat.SetVector("_Size", size);
        mat.SetBuffer("_Segments", segBuffer);
        Graphics.DrawProcedural(mat, bounds, MeshTopology.Triangles, /*vertexCount*/ 6 * segBuffer.count);
    }
}

Additional tips for modders: - If you modify RoutePrefab shader/material parameters or segment struct layout, ensure SegmentData struct and the shader buffer layout remain compatible. - Avoid accessing ManagedData (Material/ComputeBuffer) from jobs — always complete m_BufferDependencies before doing so. - PreDeserialize(Context) will clear existing buffers on load; if you create routes during deserialization, expect the system to reinitialize buffers on the next frame.