AGENT SKILL

wave8-ijobchunk-use-enabled-mask-guard

Correctly handle the enableable component bitmask in IJobChunk to avoid processing disabled entities or skipping enabled ones.

License 许可
MIT
最近更新
2026-07-25
Stars
★ 8
Forks
0

01 前言 Front Matter

name
wave8-ijobchunk-use-enabled-mask-guard
tags
[ "jobs", "chunks", "enableable", "antipattern" ]
metadata
{ "tier": 3, "internal-only": true }
description
Correctly handle the enableable component bitmask in IJobChunk to avoid processing disabled entities or skipping enabled ones.

03 SKILL.md 正文

IJobChunk useEnabledMask Guard

Intent

Correctly handle the enableable component bitmask in IJobChunk to avoid processing disabled entities or skipping enabled ones.

Use When

  • An IJobChunk implementation iterates over chunks that contain one or more IEnableableComponent types
  • The query includes any component that implements IEnableableComponent

Avoid When

  • The job uses IJobEntity — IJobEntity handles the enableable mask automatically; this guard is only needed in IJobChunk
  • No IEnableableComponent types are in the query — useEnabledMask will always be false; the fast path handles all entities

Senior Pattern

[BurstCompile]
public struct ProcessActiveEntitiesJob : IJobChunk
{
    public ComponentTypeHandle<Velocity> VelocityHandle;
    [ReadOnly] public ComponentTypeHandle<ActiveTag> ActiveTagHandle;  // IEnableableComponent
    [ReadOnly] public EntityTypeHandle EntityHandle;

    [BurstCompile]
    public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex,
        bool useEnabledMask, in v128 chunkEnabledMask)
    {
        var velocities = chunk.GetNativeArray(ref VelocityHandle);

        if (useEnabledMask)
        {
            // Some entities in chunk may be disabled — iterate only enabled ones:
            var enumerator = new ChunkEntityEnumerator(useEnabledMask, chunkEnabledMask, chunk.Count);
            while (enumerator.NextEntityIndex(out int i))
            {
                velocities[i] = new Velocity { Value = velocities[i].Value * 0.9f };
            }
        }
        else
        {
            // All entities in chunk are enabled — iterate all without mask overhead:
            for (int i = 0; i < chunk.Count; i++)
            {
                velocities[i] = new Velocity { Value = velocities[i].Value * 0.9f };
            }
        }
    }
}

// Schedule — query includes IEnableableComponent type:
EntityQuery query = state.GetEntityQuery(
    ComponentType.ReadWrite<Velocity>(),
    ComponentType.ReadOnly<ActiveTag>());

state.Dependency = new ProcessActiveEntitiesJob
{
    VelocityHandle  = state.GetComponentTypeHandle<Velocity>(),
    ActiveTagHandle = state.GetComponentTypeHandle<ActiveTag>(isReadOnly: true),
    EntityHandle    = state.GetEntityTypeHandle()
}.ScheduleParallel(query, state.Dependency);

Anti-Patterns

  • Ignoring useEnabledMask and iterating all chunk.Count entities — silently processes disabled entities; incorrect simulation results for all state-machine patterns built on IEnableableComponent.
  • Using a manual bitmask check instead of ChunkEntityEnumerator — error-prone; re-invents platform-specific SIMD bitmask iteration logic.
  • Calling ArchetypeChunk.GetEnabledMask() without checking useEnabledMask first — unnecessary work when all entities in the chunk are enabled.
  • Using IJobChunk when IJobEntity would suffice — IJobEntity handles the mask automatically; prefer it unless chunk-level access is required.

Runtime Risks

  • Skipping the useEnabledMask guard silently processes disabled entities — no exception, no warning.
  • For IEnableableComponent-based state machines (dead/alive, sleeping/awake), this means dead or sleeping entities receive updates they should not — correctness bug that manifests as incorrect game behavior.

Performance Notes

  • ChunkEntityEnumerator uses SIMD bitmask iteration internally — faster than a manual branch-per-entity loop.
  • The useEnabledMask == false fast path skips bitmask overhead entirely for fully-enabled chunks, which is the common case in well-organized archetypes.
  • Prefer IJobEntity over IJobChunk for new systems — it eliminates this boilerplate and handles the mask automatically.

Architecture Guidance

  • For new systems, prefer IJobEntity (mask is automatic). Use IJobChunk only when chunk-level access is required (pointer arithmetic, DidChange, per-chunk scratch buffers).
  • When using IJobChunk with any IEnableableComponent in the query, the useEnabledMask guard + ChunkEntityEnumerator pattern is mandatory — treat it as non-negotiable.

Related Skills

[[wave4-ijobchunk-full-anatomy]], [[enableable-component]], [[wave6-with-disabled-query-filter]], [[wave8-enableable-component-query-mismatch]]

04 同仓库更多 Skills

dyCuong03
dyCuong03/unity-agent-team

dots-update-groups

How to choose the right ECS system group and ordering so per-frame and per-fixed-step work is deterministic and never races its own readers. Covers InitializationSystemGroup / SimulationSystemGroup / PresentationSystemGroup / FixedStepSimulationSystemGroup / VariableRateSimulationSystemGroup, UpdateBefore / UpdateAfter peer ordering, OrderFirst / OrderLast group-boundary placement, RateManager, and the cross-group ordering trap. Use when adding an ISystem, fixing "value visible one frame late" bugs, or coupling simulation to a fixed timestep.

★ 8
dyCuong03
dyCuong03/unity-agent-team

dots-transform-patterns

The Entities 1.x transform model — LocalTransform (writable input) vs LocalToWorld (system-owned matrix), Parent/Child hierarchy, reparenting cost, uniform vs non-uniform scale (PostTransformMatrix), and when to opt out with custom transform systems. Use when designing parent/child hierarchies, runtime reparenting (mount/dismount/socket), or choosing transform components at the Baker boundary.

★ 8
dyCuong03
dyCuong03/unity-agent-team

dots-singleton-patterns

Model cross-system shared configuration and game state as a single-entity component with a strict single-writer contract. Covers RequireForUpdate gating, SystemAPI.GetSingleton / GetSingletonRW / HasSingleton / TryGetSingleton, bake-time vs runtime-created vs ECB-system singletons, the "exactly one entity" runtime invariant, and the single-writer rule. Use when designing frame-stable global config, shared mutable state, or any component intended to exist on exactly one entity.

律师与法务
★ 8
dyCuong03
dyCuong03/unity-agent-team

dots-hybrid-bridge

The one-way bridge between DOTS-owned runtime state and Unity-owned presentation. Covers UnityObjectRef for managed asset refs in components, the DOTS-writes / Unity-reads ownership rule, when to use managed IComponentData vs UnityObjectRef vs CompanionComponent, baker-bridge vs runtime-bridge, and SubScene boundary rules. Use when an entity must reference Unity assets (Mesh, Material, AudioClip, ScriptableObject), a MonoBehaviour view must read entity state, or input/UI must trigger ECS work.

★ 8
dyCuong03
dyCuong03/unity-agent-team

dots-event-driven-ecs

Model one-frame events and external requests in ECS without dual ownership, polling, or persistent state leaks. Covers request-tag pattern with ECB, enableable command components (no structural change), event buffers (IBufferElementData), explicit consumer ownership, one-frame latency rules, and the banned C# event / UnityEvent / static bus anti-patterns. Use when input/UI/network must trigger ECS work, when a one-frame signal fans out to N consumers (damage, hit, collision), or when state changes must be processed exactly once.

★ 8
dyCuong03
dyCuong03/unity-agent-team

valid_skill

A complete, well-formed test fixture skill for SkillHub validation testing. Covers basic task routing and code review for Unity projects.

代码审查测试与质量
★ 8