Game.StuckMovingObjectSystem
Assembly:
Namespace: Game.Simulation
Type: class
Base: GameSystemBase
Summary:
System that detects moving objects (vehicles, creatures, ride needers, group members, animals) that are stuck behind slow or blocking entities. It runs as a parallel IJobChunk (StuckCheckJob) over entities that have a Blocker component and an UpdateFrame shared component, and marks path owners or animal lane components as stuck when a blocking chain prevents movement. The system:
- Skips temporary or non-existent blockers and high-speed blockers (m_MaxSpeed >= 6).
- Treats parked trains (and parked cars when not processing cars) as blocking.
- For crossings on cars, sets a RequestSpace flag on the car's current lane.
- Traverses blocker chains (following Controller indirections) up to 100 links to detect cycles or a blocker that is one of the involved entities.
- Marks PathOwner.m_State with PathFlags.Stuck (or AnimalCurrentLane.m_Flags with CreatureLaneFlags.Stuck) when blocked.
Burst-compiled job for performance; uses shared component UpdateFrame to spread work across frames (frameIndex >> 2 % 16). The system updates every 4 simulation frames (GetUpdateInterval returns 4).
Fields
-
private SimulationSystem m_SimulationSystem
Holds a reference to the SimulationSystem used to read the current simulation frame index (used to compute which UpdateFrame filter to use). -
private EntityQuery m_ObjectQuery
Query matching entities that have Blocker and UpdateFrame shared components, and exclude Deleted and Temp. Used to schedule the StuckCheckJob over the relevant objects. -
private TypeHandle __TypeHandle
Internal struct that stores Entity/Component type handles and ComponentLookup handles used by the job. Populated at OnCreateForCompiler and updated before scheduling the job. -
private struct StuckCheckJob
(nested)
Burst-compiled job implementing IJobChunk that performs the per-chunk stuck detection. Contains component type handles and lookups used inside Execute. -
private struct TypeHandle
(nested)
Helper struct that bundles all EntityTypeHandle, ComponentTypeHandle and ComponentLookup instances and provides __AssignHandles to initialize them from a SystemState.
Properties
- (none public)
Constructors
public StuckMovingObjectSystem()
Default constructor. The system initialization logic happens in OnCreate / OnCreateForCompiler.
Methods
-
public override int GetUpdateInterval(SystemUpdatePhase phase)
Returns 4. The system will be scheduled with an update interval of 4 simulation frames (this is likely used by the game framework to throttle system updates). -
[Preserve] protected override void OnCreate()
Initializes the system: - Resolves the SimulationSystem from the World (m_SimulationSystem).
- Builds an EntityQuery matching Blocker + UpdateFrame and excluding Deleted/Temp.
-
Calls RequireForUpdate on the query so the system runs only if matching entities exist.
-
[Preserve] protected override void OnUpdate()
Main scheduling method: - Chooses a shared UpdateFrame index based on the simulation frame index: (m_SimulationSystem.frameIndex >> 2) % 16. This staggers processing over multiple frames.
- Resets and sets a shared component filter on m_ObjectQuery with UpdateFrame(index).
- Constructs a StuckCheckJob populated with all required EntityTypeHandle, ComponentTypeHandle and ComponentLookup references using InternalCompilerInterface helpers and the stored __TypeHandle.
- Schedules the job with JobChunkExtensions.ScheduleParallel against m_ObjectQuery, attaching to base.Dependency.
The job iterates chunk entities and for each Blocker: - Ignores missing/temporary blockers. - If chunk represents cars and blocker is a crossing, sets CarCurrentLane.m_LaneFlags |= CarLaneFlags.RequestSpace on the controller entity (resolving Controller indirection). - Skips blockers with m_MaxSpeed >= 6. - Determines a related vehicle/target entity where appropriate (CurrentVehicle, RideNeeder → Dispatched handler, GroupMember → leader's CurrentVehicle, Target). - Uses IsBlocked(Entity, Blocker) or IsBlocked(Entity, Entity, Blocker) to inspect the blocker chain and decide if the subject is blocked. - If blocked, marks PathOwner.m_State with PathFlags.Stuck (if PathOwner component exists on the entity) else marks AnimalCurrentLane.m_Flags with CreatureLaneFlags.Stuck.
-
private void __AssignQueries(ref SystemState state)
Called by OnCreateForCompiler; present for compiler support. Currently contains an empty EntityQueryBuilder allocation/dispose; the real query is set up in OnCreate. -
protected override void OnCreateForCompiler()
Compiler-time helper that calls __AssignQueries and initializes __TypeHandle by calling __AssignHandles on it. -
private bool IsBlocked(Entity entity, Blocker blocker)
(inside StuckCheckJob)
Follows the chain of blockers starting from blocker.m_Blocker, resolving Controller indirections to controllers where applicable. Traverses up to 100 links. Returns true if: - traversal reaches the original entity (cycle or self-block), or
-
traversal reached 100 iterations (safety limit). Returns false if it reaches a null blocker or encounters temporary blocker, or a blocker with m_MaxSpeed >= 6.
-
private bool IsBlocked(Entity entity1, Entity entity2, Blocker blocker)
(inside StuckCheckJob)
Same as above but considers both entity1 and entity2 as stopping/blocking targets. Returns true if traversal reaches either entity or reaches 100 links; false for null/temporary/high-speed blockers. -
void IJobChunk.Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
(inside StuckCheckJob)
Explicit interface implementation that forwards to the typed Execute method.
Notes about component types referenced (game-specific): - Blocker: represents blocking relations between moving objects; contains m_Blocker (entity), m_Type, m_MaxSpeed. - Controller: used to resolve to the controlling entity (m_Controller) for certain objects. - ParkedCar / ParkedTrain: indicates parked vehicles — parked trains are always considered blockers. - CurrentVehicle / Dispatched: used to find the vehicle entity associated to a creature or ride request. - PathOwner: pathfinding state component with m_State flags (PathFlags.Pending, PathFlags.Stuck, etc). - AnimalCurrentLane / CarCurrentLane: lane state components for animals/cars; lane flags include stuck/request space markers.
Implementation details and behavior: - The system ignores blockers where Blocker.m_Blocker == Entity.Null or Blocker.m_Type == BlockerType.Temporary. - Blockers with m_MaxSpeed >= 6 are considered fast enough and do not count as causing stuck. - When processing car chunks, a crossing blocker will mark the blocked car's current lane with CarLaneFlags.RequestSpace (requests access). - Uses a safety limit of 100 iterations when following blocker chains to avoid infinite loops. - Designed to run in parallel with Burst for performance.
Usage Example
// Example: check if a PathOwner on an entity was marked stuck by StuckMovingObjectSystem
EntityManager em = World.DefaultGameObjectInjectionWorld.EntityManager;
if (em.HasComponent<PathOwner>(someEntity))
{
PathOwner owner = em.GetComponentData<PathOwner>(someEntity);
if ((owner.m_State & PathFlags.Stuck) != 0)
{
// entity has been marked stuck by the StuckMovingObjectSystem
// handle recovery, replanning, or logging here
}
}
Additional notes for modders: - You generally don't instantiate this system manually — it is part of the simulation systems run by the game's world. If you need similar behavior for custom entity types, follow the pattern: - Provide Blocker-like components and Controller indirection as appropriate. - Use a shared UpdateFrame filter to spread processing across frames. - Mark PathOwner or lane flags to indicate stuck state so other systems can respond. - Be careful when altering Blocker chains or Controller indirections — IsBlocked traverses Controller references and other Blocker components and uses a 100-step cap to avoid endless loops.