Skip to content

Game.Simulation.PersonalCarOwnerSystem

Assembly: Game (Assembly-CSharp/Game.dll)
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
PersonalCarOwnerSystem is a simulation system that ensures PersonalCar entities (personal cars) are owned by an Owner entity's OwnedVehicle buffer. It iterates over personal car prefabs on a staggered schedule (based on a shared UpdateFrame shared component) and deletes any vehicle entities that are no longer present in their recorded owner's OwnedVehicle buffer. Deletions are issued via an EndFrameBarrier command buffer to run safely at the end of the frame. The system operates in batches using a Burst-compiled IJobChunk (PersonalCarOwnerJob) for parallel execution and uses a TypeHandle struct to cache type handles for efficient access.


Fields

  • public static readonly int kUpdateInterval
    Constant interval used to partition update frames. The system computes a per-frame update index as (simulationFrame / kUpdateInterval) % 16 so that only a subset of vehicles are processed each frame slice. Value from source: 1024.

  • private EndFrameBarrier m_EndFrameBarrier
    Reference to the EndFrameBarrier system used to create an EntityCommandBuffer for delayed structural changes (deletions). The command buffer is created in OnUpdate and its job handle is registered with the barrier.

  • private SimulationSystem m_SimulationSystem
    Reference to the SimulationSystem used to read the global simulation frame index used to compute which UpdateFrame slice to process.

  • private EntityQuery m_VehicleGroup
    EntityQuery selecting PersonalCar prefabs that should be processed. Constructed in OnCreate and used to schedule the job. The query includes PrefabRef and UpdateFrame and excludes trailers, deleted/temp/out-of-control/destroyed entities.

  • private TypeHandle __TypeHandle
    Internal struct instance used to store and assign component/buffer/shared handles (SharedComponentTypeHandle, EntityTypeHandle, BufferTypeHandle, ComponentTypeHandle, BufferLookup).


Properties

This system does not expose additional public properties. Relevant behavior is controlled via overrides (GetUpdateInterval, OnCreate, OnUpdate) and its fields.


Constructors

  • public PersonalCarOwnerSystem()
    Default constructor. Marked [Preserve] in the compiled assembly. Typical Unity ECS system construction — real initialization is done in OnCreate/OnCreateForCompiler.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns kUpdateInterval (1024). This controls how often the system wants to be considered for scheduling relative to a phased update mechanism.

  • [Preserve] protected override void OnCreate()
    Initializes the system: gets references to EndFrameBarrier and SimulationSystem, builds the m_VehicleGroup EntityQuery (matching PrefabRef + UpdateFrame + PersonalCar and excluding CarTrailer, Deleted, Temp, OutOfControl, Destroyed), and calls RequireForUpdate(m_VehicleGroup) so the system runs only if matching entities exist.

  • [Preserve] protected override void OnUpdate()
    Main update logic:

  • Computes updateFrameIndex = (m_SimulationSystem.frameIndex / kUpdateInterval) % 16 to pick which shared UpdateFrame slice to process.
  • Constructs and schedules a Burst-compiled IJobChunk (PersonalCarOwnerJob) over m_VehicleGroup, passing type handles and a parallel EndFrameBarrier command buffer writer.
  • Registers the produced JobHandle with the EndFrameBarrier (AddJobHandleForProducer) and sets the system Dependency to the returned job handle.

  • protected override void OnCreateForCompiler()
    Compiler-time initialization used to assign query handles and populate the __TypeHandle by calling __AssignQueries and __AssignHandles. Present to support the generated code pattern.

  • private void __AssignQueries(ref SystemState state)
    Internal helper used by the compiler-time OnCreateForCompiler. In this compiled code it only constructs and disposes a placeholder EntityQueryBuilder; its purpose in generated contexts is to initialize query-related internal state.

  • private struct PersonalCarOwnerJob : IJobChunk (Burst compiled)
    Implements the worker logic run per-chunk:

  • Reads the chunk's shared UpdateFrame and only processes the chunk if its m_Index matches the provided m_UpdateFrameIndex (staggered processing).
  • Iterates entities in the chunk, retrieves optional LayoutElement buffer for deletion context.
  • For each entity, checks the Owner component: if the Owner exists and that owner's OwnedVehicle buffer exists, scans the OwnedVehicle buffer for an entry where m_Vehicle == entity. If not found (or the Owner buffer is not created), the job calls VehicleUtils.DeleteVehicle via the command buffer, scheduling deletion.
  • Fields passed into the job include SharedComponentTypeHandle, EntityTypeHandle, BufferTypeHandle, ComponentTypeHandle, BufferLookup, the computed m_UpdateFrameIndex, and an EntityCommandBuffer.ParallelWriter.

  • private struct TypeHandle
    Holds typed handles used by the job: SharedComponentTypeHandle, EntityTypeHandle, BufferTypeHandle, ComponentTypeHandle, BufferLookup. It exposes __AssignHandles(ref SystemState) to cache the handles from the system state.

Notes on deletion behavior: - VehicleUtils.DeleteVehicle(...) is invoked to enqueue vehicle deletions. The deletion receives the command buffer writer, the unfilteredChunkIndex (used as the parallel sort key), the vehicle Entity, and the LayoutElement buffer (if present) to allow cleanup that uses layout metadata.


Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    m_EndFrameBarrier = base.World.GetOrCreateSystemManaged<EndFrameBarrier>();
    m_SimulationSystem = base.World.GetOrCreateSystemManaged<SimulationSystem>();
    m_VehicleGroup = GetEntityQuery(
        ComponentType.ReadOnly<PrefabRef>(),
        ComponentType.ReadOnly<UpdateFrame>(),
        ComponentType.ReadWrite<Game.Vehicles.PersonalCar>(),
        ComponentType.Exclude<CarTrailer>(),
        ComponentType.Exclude<Deleted>(),
        ComponentType.Exclude<Temp>(),
        ComponentType.Exclude<OutOfControl>(),
        ComponentType.Exclude<Destroyed>()
    );
    RequireForUpdate(m_VehicleGroup);
}

[Preserve]
protected override void OnUpdate()
{
    // compute which update-frame slice to process
    uint updateFrameIndex = m_SimulationSystem.frameIndex / (uint)kUpdateInterval % 16;

    // schedule the chunk job that deletes personal cars no longer owned
    var job = new PersonalCarOwnerJob
    {
        m_UpdateFrameType = InternalCompilerInterface.GetSharedComponentTypeHandle(ref __TypeHandle.__Game_Simulation_UpdateFrame_SharedComponentTypeHandle, ref base.CheckedStateRef),
        m_EntityType = InternalCompilerInterface.GetEntityTypeHandle(ref __TypeHandle.__Unity_Entities_Entity_TypeHandle, ref base.CheckedStateRef),
        m_LayoutElementType = InternalCompilerInterface.GetBufferTypeHandle(ref __TypeHandle.__Game_Vehicles_LayoutElement_RO_BufferTypeHandle, ref base.CheckedStateRef),
        m_OwnerType = InternalCompilerInterface.GetComponentTypeHandle(ref __TypeHandle.__Game_Common_Owner_RO_ComponentTypeHandle, ref base.CheckedStateRef),
        m_OwnedVehicles = InternalCompilerInterface.GetBufferLookup(ref __TypeHandle.__Game_Vehicles_OwnedVehicle_RO_BufferLookup, ref base.CheckedStateRef),
        m_UpdateFrameIndex = updateFrameIndex,
        m_CommandBuffer = m_EndFrameBarrier.CreateCommandBuffer().AsParallelWriter()
    };

    JobHandle jobHandle = JobChunkExtensions.ScheduleParallel(job, m_VehicleGroup, base.Dependency);
    m_EndFrameBarrier.AddJobHandleForProducer(jobHandle);
    base.Dependency = jobHandle;
}

Additional notes for modders: - The system relies on the Owner component and the OwnedVehicle buffer being kept up-to-date by other systems. If you add or remove entries from OwnedVehicle buffers, ensure proper synchronization to avoid premature deletions. - The system staggers processing using the UpdateFrame shared component and kUpdateInterval to keep performance predictable; altering kUpdateInterval would change the update bucketing behavior if you were to recompile or patch the system. - Vehicle deletions are enqueued to EndFrameBarrier — structural changes are deferred and applied safely at the barrier's flush.