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 = falseon 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
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.
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.
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.
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.
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.
valid_skill
A complete, well-formed test fixture skill for SkillHub validation testing. Covers basic task routing and code review for Unity projects.