AGENT SKILL

direct-entity-manager-structural-changes

Use EntityManager directly for structural changes outside of any active query iteration — appropriate for one-shot initialisation, infrequent config-driven respawns, and batch operations on the mai...

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

01 前言 Front Matter

name
direct-entity-manager-structural-changes
tags
[ "structural-change" ]
metadata
{ "tier": 3, "internal-only": true }
description
Use EntityManager directly for structural changes outside of any active query iteration — appropriate for one-shot initialisation, infrequent config-driven respawns, and batch operations on the mai...

03 SKILL.md 正文

Direct EntityManager Structural Changes

Intent

Use EntityManager directly for structural changes outside of any active query iteration — appropriate for one-shot initialisation, infrequent config-driven respawns, and batch operations on the main thread.

Use When

One-shot init systems (state.Enabled = false after first run). Mass respawn triggered by config change. Any structural change that happens once at startup or once on a significant event, not per-frame.

Avoid When

Inside a SystemAPI.Query foreach — iterator is invalidated. Inside a scheduled job — EntityManager is not accessible from jobs. In per-frame simulation hot paths — use ECB for deferred execution.

Senior Pattern

  • Disable the system after first run: state.Enabled = false; at the start of OnUpdate (set before any work so even exceptions during work don't leave the system enabled for next frame).
  • Use batch overloads exclusively:
    • state.EntityManager.Instantiate(prefab, count, Allocator.Temp) — spawns N entities in one archetype operation.
    • state.EntityManager.AddComponent<T>(query) — adds T to all matching entities in one pass.
    • state.EntityManager.RemoveComponent<T>(query) — removes T from all matching in one pass.
    • state.EntityManager.DestroyEntity(query) — destroys all matching in one pass.
  • Use state.EntityManager.AddBuffer<T>(entity) for per-entity buffer initialisation after batch spawn.

Code Template

[BurstCompile]
public partial struct WorldSetupSystem : ISystem
{
    public void OnCreate(ref SystemState state)
        => state.RequireForUpdate<WorldConfig>();

    public void OnUpdate(ref SystemState state)
    {
        state.Enabled = false;  // one-shot — set before work begins

        var config = SystemAPI.GetSingleton<WorldConfig>();

        // Batch spawn — single archetype operation for all N entities
        var enemies = state.EntityManager.Instantiate(
            config.EnemyPrefab, config.EnemyCount, Allocator.Temp);

        // Per-entity init using the spawned array
        for (int i = 0; i < enemies.Length; i++)
        {
            state.EntityManager.SetComponentData(enemies[i],
                LocalTransform.FromPosition(new float3(i * 2f, 0, 0)));
        }

        // Batch tag all spawned enemies
        var enemyQuery = SystemAPI.QueryBuilder()
            .WithAll<EnemyData>().WithNone<EnemyReady>().Build();
        state.EntityManager.AddComponent<EnemyReady>(enemyQuery);
    }
}

Anti-Patterns

  • Calling state.EntityManager.Instantiate(prefab) (single-entity overload) in a loop — N archetype operations instead of 1.
  • Calling structural changes inside SystemAPI.Query foreach — iterator invalidation, safety exception.
  • Forgetting state.Enabled = false on a one-shot init system — repeated spawning every frame.
  • Calling state.EntityManager.CompleteAllTrackedJobs() to "enable" structural changes instead of properly scheduling them — blocks all worker threads.

Runtime Risks

  • Structural change inside foreach: access exception or silent data corruption.
  • Missing state.Enabled = false: duplicate entity spawning every frame.
  • Loop of single Instantiate: O(N) archetype operations cause visible frame spikes at large N.

Performance Notes

  • Instantiate(prefab, count, Alloc): O(1) archetype operations + O(count) data copies. Dominates single-entity loop by orders of magnitude at count > 100.
  • AddComponent(query): single structural change pass over all matching chunks. Same cost regardless of entity count.
  • DestroyEntity(query): single pass, optimal for mass destruction.

Architecture Guidance

Direct EntityManager = privileged main-thread batch API. Reserve for world setup and explicit event-driven mass operations. For all simulation-phase structural changes, ECB is the correct tool.

Related Skills

[[entity-command-buffer]], [[batch-structural-change-on-query]]

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