Skip to content

Game.Vehicles.ComponentsSystem

Assembly:
Namespace: Game.Vehicles

Type: class

Base: GameSystemBase

Summary:
ComponentsSystem is a Unity ECS system used in Cities: Skylines 2 to ensure newly created vehicle entities receive the appropriate transport marker components (PassengerTransport, EvacuatingTransport, PrisonerTransport) based on their "original" template entity referenced from a Temp component. It schedules a Burst-compiled IJobChunk (VehicleComponentsJob) that iterates vehicle archetype chunks, checks the original template entity for transport components using ComponentLookup.HasComponent, and enqueues AddComponent commands to a ModificationBarrier4's EntityCommandBuffer. The system uses parallel scheduling and writes to a parallel command buffer to perform component additions safely from jobs.


Fields

  • private ModificationBarrier4 m_ModificationBarrier
    Used to produce an EntityCommandBuffer (as a ParallelWriter) for safely adding components from jobs and to register job dependencies via AddJobHandleForProducer. This ensures structural changes are deferred and executed on the main thread at the appropriate time.

  • private EntityQuery m_VehicleQuery
    Query selecting entities that are newly Created and have Vehicle and Temp components. Used with RequireForUpdate so the system only runs when relevant entities exist.

  • private TypeHandle __TypeHandle
    Container for the various EntityTypeHandle, ComponentTypeHandle and ComponentLookup handles used when scheduling the chunk job. Populated via the __AssignHandles method (called from OnCreateForCompiler).

  • (nested) private struct VehicleComponentsJob : IJobChunk
    Burst-compiled chunk job that:

  • Reads the Entity and Temp arrays from the chunk.
  • Uses ComponentLookup.HasComponent on Temp.m_Original to determine whether to add transport marker components to the new vehicle entity.
  • Adds components via an EntityCommandBuffer.ParallelWriter (m_CommandBuffer.AddComponent).

  • (nested) private struct TypeHandle
    Holds the EntityTypeHandle, Temp ComponentTypeHandle (read-only), and ComponentLookup instances (read-only) required by the job. Provides __AssignHandles(ref SystemState) to request the handles from the SystemState.

Properties

  • None.

Constructors

  • public ComponentsSystem()
    Default constructor. The system is attributed with [Preserve] on lifecycle methods to avoid stripping. No custom initialization beyond base constructor.

Methods

  • protected override void OnCreate()
    Initializes the system:
  • Retrieves/creates ModificationBarrier4 from the World.
  • Constructs the m_VehicleQuery: entities with Created, Vehicle and Temp (all read-only).
  • Calls RequireForUpdate(m_VehicleQuery) so the system only runs when the query matches.

  • protected override void OnUpdate()
    Main update that:

  • Prepares and schedules VehicleComponentsJob as a parallel job using JobChunkExtensions.ScheduleParallel.
  • Builds job input handles via InternalCompilerInterface.GetEntityTypeHandle / GetComponentTypeHandle / GetComponentLookup using __TypeHandle fields and base.CheckedStateRef.
  • Creates a parallel EntityCommandBuffer via m_ModificationBarrier.CreateCommandBuffer().AsParallelWriter().
  • Registers the scheduled JobHandle with the modification barrier via AddJobHandleForProducer and assigns the handle to base.Dependency.

  • private void __AssignQueries(ref SystemState state)
    Called during compiler-time creation path (OnCreateForCompiler) — in this code it creates and immediately disposes of an EntityQueryBuilder(Allocator.Temp). This method is part of generated/compiled system scaffolding to ensure queries are set up in an ahead-of-time fashion.

  • protected override void OnCreateForCompiler()
    Compiler-time initialization helper that calls __AssignQueries and calls __TypeHandle.__AssignHandles(ref base.CheckedStateRef). This supports the generated Access/Handle wiring used for job scheduling.

  • private struct TypeHandle.__AssignHandles(ref SystemState state)
    Assigns:

  • EntityTypeHandle via state.GetEntityTypeHandle()
  • ComponentTypeHandle (read-only) via state.GetComponentTypeHandle(isReadOnly: true)
  • ComponentLookup (read-only) via state.GetComponentLookup(isReadOnly: true)

  • private struct VehicleComponentsJob.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
    For each entity in the chunk:

  • Retrieves Entity and Temp arrays for the chunk.
  • For each index gets the Temp.m_Original entity and checks if that original has PassengerTransport, EvacuatingTransport, or PrisonerTransport using the respective ComponentLookup.HasComponent.
  • If present on original, enqueues AddComponent(unfilteredChunkIndex, e, default(TTransport)) to the parallel EntityCommandBuffer writer for the new entity.

Notes about implementation details: - The job is marked with [BurstCompile] to enable burst optimizations. - ComponentLookup is used read-only to inspect components on the referenced original entity (Temp.m_Original). - Structural changes are not applied directly in the job; they are deferred via the command buffer produced by ModificationBarrier4. - The job is scheduled in parallel and the command buffer is used as a ParallelWriter — AddComponent calls use the unfilteredChunkIndex to be thread-safe.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    // Create or get the modification barrier that provides an ECB for structural changes.
    m_ModificationBarrier = base.World.GetOrCreateSystemManaged<ModificationBarrier4>();

    // Only run this system when there are newly created vehicles with a Temp component.
    m_VehicleQuery = GetEntityQuery(ComponentType.ReadOnly<Created>(),
                                    ComponentType.ReadOnly<Vehicle>(),
                                    ComponentType.ReadOnly<Temp>());
    RequireForUpdate(m_VehicleQuery);
}

[Preserve]
protected override void OnUpdate()
{
    // Scheduling the VehicleComponentsJob (simplified — actual code builds handles via internal helpers)
    var job = new VehicleComponentsJob
    {
        m_EntityType = /* entity type handle */,
        m_TempType = /* component type handle for Temp */,
        m_PassengerTransportData = /* component lookup for PassengerTransport */,
        m_EvacuatingTransportData = /* component lookup for EvacuatingTransport */,
        m_PrisonerTransportData = /* component lookup for PrisonerTransport */,
        m_CommandBuffer = m_ModificationBarrier.CreateCommandBuffer().AsParallelWriter()
    };

    JobHandle handle = JobChunkExtensions.ScheduleParallel(job, m_VehicleQuery, base.Dependency);
    m_ModificationBarrier.AddJobHandleForProducer(handle);
    base.Dependency = handle;
}

Additional remarks: - This system is part of the vehicle initialization pipeline: when vehicle entities are spawned (Created) they reference a Temp component that points back to the original prefab/template entity. ComponentsSystem inspects that template to copy marker components (by adding them to the spawned entity), enabling other systems to treat vehicles according to their transport role. - If you extend or modify transport marker types, ensure the TypeHandle and the job checks are updated accordingly. - Because this system uses ComponentLookup.HasComponent on referenced entities, the referenced originals must be accessible in the same world and not be structural-changed concurrently in a way that invalidates the lookup during job execution. The read-only ComponentLookup usage and ModificationBarrier pattern help ensure safety.