Skip to content

Game.Rendering.InitializeBonesSystem

Assembly: Assembly-CSharp (Game)
Namespace: Game.Rendering

Type: class

Base: GameSystemBase

Summary:
InitializeBonesSystem is an ECS system used by the rendering pipeline to prepare and maintain procedural skeleton data for entities that use procedural bones (for example, animated sub-meshes). The system queries culling / update information from PreCullingSystem and uses the ProceduralSkeletonSystem's NativeHeapAllocator to allocate contiguous native heap blocks for skeleton bone matrices. Work is performed inside a Burst-compiled IJob (InitializeBonesJob) that runs off the main thread: it creates/resizes DynamicBuffer and DynamicBuffer entries for each entity that is near the camera and requires procedural bones, initializes Bone data from ProceduralBone buffers, zeroes or resizes Momentum buffers when present, and enqueues deallocations for heap blocks when entities leave near-camera culling. The system coordinates with ProceduralSkeletonSystem (for heap allocator / allocation bookkeeping) and PreCullingSystem (for which entities need updating), and uses ComponentLookup / BufferLookup handles for safe access in jobs.


Fields

  • private ProceduralSkeletonSystem m_ProceduralSkeletonSystem
    This is a reference to the world-managed ProceduralSkeletonSystem. It's acquired in OnCreate and is used to get the NativeHeapAllocator, allocation info, allocation removes queue and current time. The InitializeBonesJob gets the allocator and bookkeeping structures from this system so allocations and deallocations can be coordinated.

  • private PreCullingSystem m_PreCullingSystem
    Reference to the PreCullingSystem. The system asks PreCullingSystem for the set of PreCullingData entries that have been updated (and thus which entities need skeleton initialization or removal). The job reads that list to decide which entities to update or deallocate.

  • private TypeHandle __TypeHandle
    A private struct instance that stores ComponentLookup/BufferLookup handles (prefab ref, procedural bones, submeshes, skeleton/bone/momentum buffers). __TypeHandle.__AssignHandles is called from OnCreateForCompiler to initialize those lookup handles for safe job access.

Properties

  • This class does not declare any public properties of its own. It relies on inherited GameSystemBase members (Dependency, World, etc.) and on the Component/Buffer lookups stored in the TypeHandle for job access.

Constructors

  • public InitializeBonesSystem()
    Default public constructor. The system is preserved and created by the ECS world. The constructor itself is empty in source but marked with [Preserve].

Methods

  • protected override void OnCreate()
    Creates/initializes the system-level references: gets or creates the ProceduralSkeletonSystem and PreCullingSystem from the world. This prepares the system so OnUpdate can query heap allocator and culling data. Called once when the system is created.

  • protected override void OnUpdate()
    Main scheduling method. This method:

  • Calls ProceduralSkeletonSystem.GetHeapAllocator(...) to obtain the NativeHeapAllocator, a NativeReference, a NativeQueue, the current time, and a dependency JobHandle related to heap state.
  • Requests updated culling data from PreCullingSystem (as a NativeList and an out JobHandle dependency for the reader).
  • Constructs and schedules the Burst-compiled InitializeBonesJob, passing ComponentLookup/BufferLookup handles (via InternalCompilerInterface using the pre-initialized TypeHandle), the heap allocator and allocation bookkeeping references, and the culling list.
  • Combines dependencies appropriately, registers the job's handle with ProceduralSkeletonSystem (AddHeapWriter) and PreCullingSystem (AddCullingDataReader), then assigns the scheduled job to base.Dependency.

Notes: the job does the heavy lifting of allocating heap blocks, filling skeleton & bone buffers, and enqueuing removes for deallocation. OnUpdate remains responsible for proper dependency chaining and registration so other systems that interact with the heap or culling data remain synchronized.

  • protected override void OnCreateForCompiler()
    Helper used by the source generator/IL-to-ECS compiler. It calls __AssignQueries and initializes the TypeHandle by calling its __AssignHandles with the system state. This prepares ComponentLookup / BufferLookup handles for later use in scheduled jobs.

  • private void __AssignQueries(ref SystemState state)
    A small method compiled by generator — currently creates and disposes a temporary EntityQueryBuilder. Left in place for compatibility with compiler-generated patterns and ensures queries are assigned/registered as expected. It uses Allocator.Temp for the ephemeral query.

Nested / Job types (documented as important implementation details):

  • private struct InitializeBonesJob : IJob (BurstCompile)
    Purpose: perform per-entity initialization and cleanup of procedural skeleton data on worker threads. Main fields passed into the job:
    • ReadOnly ComponentLookup m_PrefabRefData — used to map entity -> prefab entity to fetch SubMesh buffers.
    • ReadOnly BufferLookup m_ProceduralBones — procedural bone definitions per submesh prefab.
    • ReadOnly BufferLookup m_SubMeshes — sub-mesh list per prefab entity.
    • BufferLookup m_Skeletons — dynamic buffer on the target entity storing per-submesh Skeleton descriptors (allocation, offsets).
    • BufferLookup m_Bones — dynamic buffer storing Bone structs for all skeleton bones across submeshes per entity.
    • BufferLookup m_Momentums — optional momentum/history buffer per entity; if present it will be resized/zeroed when bones change.
    • ReadOnly int m_CurrentTime — current frame/time as provided by ProceduralSkeletonSystem.
    • ReadOnly NativeList m_CullingData — list of culling entries to process (entities to update or remove).
    • NativeHeapAllocator m_HeapAllocator — allocator used to allocate NativeHeapBlock blocks that hold per-skeleton matrices/transform data.
    • NativeReference m_AllocationInfo — shared allocation bookkeeping; job increments allocation count when it allocates.
    • NativeQueue m_AllocationRemoves — queue the job enqueues allocation removals into (with remove time) for later deallocation.

Behavior (Execute): - Iterates m_CullingData; for entries with flags indicating an update/near-camera and that they represent skeleton data, chooses to Update or Remove. - Remove(PreCullingData): clears Skeleton and Bone buffers and clears Momentum if present; enqueues allocation removal entries for any non-empty heap allocations stored in Skeleton entries. - Update(PreCullingData, ref AllocationInfo): for entities that remain near-camera and need skeletons: - Looks up the prefab from PrefabRef and fetches SubMesh buffer of that prefab. If no SubMesh buffer exists, falls back to Remove. - Counts total number of procedural bones across all sub-meshes to size Bone/Dynamic buffers. - If sizes match existing buffer sizes, returns early (no change). - Otherwise deallocates existing heap allocations for skeletons (Deallocate), resizes skeleton and bone buffers (ResizeUninitialized), and if momentum buffer exists it is resized and zero-initialized (set to default(Momentum)). - For each submesh that has procedural bones: allocate a NativeHeapBlock from m_HeapAllocator sized for number of bones in that submesh. If allocator runs out, call m_HeapAllocator.Resize(...) to grow the heap and allocate again. Increment AllocationInfo.m_AllocationCount. Fill Skeleton entry with the new allocation handle, bone offset and flags (m_CurrentUpdated, m_HistoryUpdated, m_RequireHistory set depending on procedural bone connection IDs). Copy ProceduralBone definitions into the entity's Bone buffer (position, rotation, scale). - Deallocate(DynamicBuffer): iterates skeleton entries and for any non-empty buffer allocation enqueues an AllocationRemove with the current time so the ProceduralSkeletonSystem can reclaim the heap later.

Notes: - The job is BurstCompile attributed for performance. - The job uses BufferLookup and ComponentLookup to access entity buffers and components safely from jobs. - Allocation growth strategy: on allocation failure, allocator is grown by a fixed amount (1_048_576 floats worth scaled by sizeof(float4x4) in the original code path) and the allocation retried.

  • private struct TypeHandle
    Stores ComponentLookup/BufferLookup handles for:
    • PrefabRef (RO)
    • ProceduralBone buffer (RO)
    • SubMesh buffer (RO)
    • Skeleton buffer (RW)
    • Bone buffer (RW)
    • Momentum buffer (RW)

Method __AssignHandles(ref SystemState) initializes these lookups from the provided state. These handles are then passed into InitializeBonesJob using InternalCompilerInterface helpers so that the job code can access entity data.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    m_ProceduralSkeletonSystem = base.World.GetOrCreateSystemManaged<ProceduralSkeletonSystem>();
    m_PreCullingSystem = base.World.GetOrCreateSystemManaged<PreCullingSystem>();
}

Additional short example (how the job is scheduled inside OnUpdate — simplified):

protected override void OnUpdate()
{
    var heapAllocator = m_ProceduralSkeletonSystem.GetHeapAllocator(out var allocationInfo, out var allocationRemoves, out var currentTime, out var allocatorDep);
    var cullingList = m_PreCullingSystem.GetUpdatedData(readOnly: true, out var cullingDep);

    var job = new InitializeBonesJob {
        m_PrefabRefData = InternalCompilerInterface.GetComponentLookup(ref __TypeHandle.__Game_Prefabs_PrefabRef_RO_ComponentLookup, ref base.CheckedStateRef),
        // ... assign other lookups and fields ...
        m_HeapAllocator = heapAllocator,
        m_AllocationInfo = allocationInfo,
        m_AllocationRemoves = allocationRemoves,
        m_CurrentTime = currentTime,
        m_CullingData = cullingList
    };

    var handle = job.Schedule(JobHandle.CombineDependencies(base.Dependency, cullingDep, allocatorDep));
    m_ProceduralSkeletonSystem.AddHeapWriter(handle);
    m_PreCullingSystem.AddCullingDataReader(handle);
    base.Dependency = handle;
}

Modding notes and tips: - Because allocation/deallocation is deferred and coordinated via ProceduralSkeletonSystem, do not try to manually free NativeHeapBlock allocations — use the provided allocation remove queue or the owning system. - The job relies on SubMesh -> ProceduralBone buffers attached to prefab entities; adding/removing/modifying those buffers requires changes to the prefab entities and possible reinitialization of the skeleton buffers on instances. - Watch out for Burst safety: all BufferLookup/ComponentLookup passed into the job must be initialized via TypeHandle before scheduling. The code uses InternalCompilerInterface helpers and OnCreateForCompiler to ensure that; when porting or modifying, keep the same pattern. - Allocation growth uses a fixed increment; frequent allocation failures indicate the heap size policy may need tuning (or reuse of allocations should be improved). - Because the job writes DynamicBuffers and also enqueues allocation removals, proper dependency registration with ProceduralSkeletonSystem and PreCullingSystem is necessary to avoid race conditions. The system explicitly registers the job using AddHeapWriter/AddCullingDataReader.

If you want, I can produce a shorter quick-reference (fields/methods only) or expand the Usage Example with a full minimal mod-compatible sample showing how to add a procedural bone to a prefab.