Skip to content

Game.Simulation.WaitingPassengersSystem

Assembly:
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
WaitingPassengersSystem collects and updates waiting passenger statistics for transport stops and queue areas. It performs three main tasks each update: clear per-stop counters, count waiting humans and groups at transport stops and queues (accumulating counts and ongoing wait estimates into WaitingPassengers components), and tick/update those WaitingPassengers values (decaying/consuming accumulations, adjusting averaged waiting time, and marking stops for pathfinding updates when averages change). The system uses Burst-compiled IJobChunk jobs and an EndFrameBarrier command buffer to safely add components from jobs.


Fields

  • private EndFrameBarrier m_EndFrameBarrier
    Reference to the EndFrameBarrier system used to create an EntityCommandBuffer for marking entities (PathfindUpdated) from a job. The system adds the produced job handle to this barrier so the barrier can wait for completion and flush commands at end of frame.

  • private EntityQuery m_StopQuery
    EntityQuery that matches entities with the WaitingPassengers component and excludes Temp and Deleted. This query is used to schedule jobs operating on transport stops (clear + tick jobs).

  • private EntityQuery m_ResidentQuery
    EntityQuery that matches resident/creature entities with HumanCurrentLane (and excludes Temp, Deleted, and GroupMember). This query is used by the counting job to iterate residents and inspect their path/queue data.

  • private TypeHandle __TypeHandle
    Internal struct instance that caches ComponentTypeHandle, BufferTypeHandle, EntityTypeHandle and ComponentLookup instances used by the jobs. Populated in OnCreateForCompiler / __AssignHandles to avoid recreating handles every frame.

Properties

  • (none)

Constructors

  • public WaitingPassengersSystem()
    Default constructor. The system initialization of handles/queries happens in OnCreate/OnCreateForCompiler rather than the constructor.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns 256. The system requests to update at this interval (i.e., it is intended to run less frequently than every frame — the update scheduler will use this value to throttle updates).

  • protected override void OnCreate()
    Initializes system state:

  • Resolves the EndFrameBarrier system from World and stores it in m_EndFrameBarrier.
  • Creates m_StopQuery to select WaitingPassengers entities (excluding Temp/Deleted).
  • Creates m_ResidentQuery to select resident/creature entities with HumanCurrentLane (excluding Temp/Deleted/GroupMember).
  • Calls RequireForUpdate(m_StopQuery) so the system only runs when there are stops present.

  • protected override void OnUpdate()
    Primary scheduling method. It:

  • Builds job data for ClearWaitingPassengersJob (resets WaitingPassengers counters).
  • Builds job data for CountWaitingPassengersJob (iterates resident entities, determines stops or queue targets and accumulates counts into per-stop WaitingPassengers via a ComponentLookup with Interlocked.Add).
  • Schedules TickWaitingPassengersJob, CountWaitingPassengersJob, and ClearWaitingPassengersJob with appropriate dependencies:
    • ClearWaitingPassengersJob runs on m_StopQuery.
    • CountWaitingPassengersJob runs on m_ResidentQuery and writes into WaitingPassengers via ComponentLookup; it is scheduled to run after Clear.
    • TickWaitingPassengersJob runs on m_StopQuery and depends on the counting job; it uses a RandomSeed and an EndFrameBarrier command buffer (AsParallelWriter) to add PathfindUpdated to a stop when the average waiting time changes.
  • Adds the resulting job handle to the EndFrameBarrier via AddJobHandleForProducer, and stores the dependency.

  • private void __AssignQueries(ref SystemState state)
    Compiler helper used by OnCreateForCompiler; here it creates a temporary EntityQueryBuilder (empty) and disposes it. In generated code this method can set up query caching; in the decompiled snippet it's effectively a placeholder.

  • protected override void OnCreateForCompiler()
    Compiler/authoring-time method that assigns query handles and component type handles by calling __AssignQueries and TypeHandle.__AssignHandles. This ensures the cached handles are initialized for the Burst jobs.

  • private struct TypeHandle.__AssignHandles(ref SystemState state)
    Initializes and caches all ComponentTypeHandle/BufferTypeHandle/EntityTypeHandle/ComponentLookup used by the jobs:

  • WaitingPassengers (read-write)
  • HumanCurrentLane (read-only)
  • Resident (read-only)
  • PathOwner (read-only)
  • PathElement buffer (read-only)
  • GroupCreature buffer (read-only)
  • Queue buffer (read-only)
  • ComponentLookup (for atomic updates from counting job)
  • EntityTypeHandle

  • private struct ClearWaitingPassengersJob : IJobChunk
    Burst job that iterates chunks matched by m_StopQuery and resets WaitingPassengers.m_Count and WaitingPassengers.m_OngoingAccumulation to zero for every matched entity. This ensures counting starts from zero each update.

  • private struct CountWaitingPassengersJob : IJobChunk
    Burst job (ReadOnly for many inputs) that iterates resident/creature entities and:

  • Checks if the creature has reached a transport stop (CreatureUtils.TransportStopReached) and if so inspects its path buffer to find the target stop entity.
  • Otherwise iterates Queue buffer entries for the creature and inspects queue.m_TargetEntity.
  • Accumulates counts per stop in a streaming-fashion: it compares the target to the lastStop, and when changing stop it uses ComponentLookup with Interlocked.Add to apply the previously accumulated counts to the WaitingPassengers component of the lastStop.
  • For each resident it computes an int2: x = number of people (1 + group size), y = ongoing accumulation estimated as resident.m_Timer * x * (2/15). These are added to the running accumulation.
  • The method is careful to skip null target entities and handles group creatures and residents that may not exist on every chunk.

  • private struct TickWaitingPassengersJob : IJobChunk
    Burst job that updates WaitingPassengers values per stop:

  • Uses a RandomSeed to produce per-chunk randomness.
  • For each WaitingPassengers instance:
    • Randomly increments SuccessAccumulation occasionally (1/64 chance) up to ushort.MaxValue.
    • Computes an average waiting time estimate based on ongoing and concluded accumulation vs. counts and success accumulation. It uses integer math with math.max and math.cmax, clamps the result to a maximum of 65535 and normalizes it to the nearest multiple of 5 (num - num % 5).
    • If the newly computed average differs from stored m_AverageWaitingTime, the job adds a PathfindUpdated component to the entity using the EndFrameBarrier command buffer (so pathfinding can react to changed stop wait times).
    • Applies a stochastic decay/consumption of success accumulation and concluded accumulation (random factor using NextInt and bit-shifts).
    • Writes back updated fields (ConcludedAccumulation, SuccessAccumulation, AverageWaitingTime).

Notes about thread-safety and atomics: - CountWaitingPassengersJob uses ComponentLookup.GetRefRW and Interlocked.Add to atomically update counters from multiple threads; this avoids race conditions while summing per-stop accumulations in parallel. - TickWaitingPassengersJob uses an EntityCommandBuffer.ParallelWriter to safely add components from a parallel job.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    m_EndFrameBarrier = base.World.GetExistingSystemManaged<EndFrameBarrier>();
    m_StopQuery = GetEntityQuery(ComponentType.ReadWrite<WaitingPassengers>(),
                                 ComponentType.Exclude<Temp>(),
                                 ComponentType.Exclude<Deleted>());
    m_ResidentQuery = GetEntityQuery(ComponentType.ReadOnly<HumanCurrentLane>(),
                                     ComponentType.Exclude<Temp>(),
                                     ComponentType.Exclude<Deleted>(),
                                     ComponentType.Exclude<GroupMember>());
    RequireForUpdate(m_StopQuery);
}

This example shows how the system initializes its EndFrameBarrier reference and entity queries in OnCreate so the jobs scheduled in OnUpdate have the proper queries and command buffers available.