t1k:unity:dots-core:entity-command-buffer
| Field | Value |
|---|---|
| Module | dots-core |
| Version | 2.3.2 |
| Effort | high |
| Tools | — |
Keywords: deferred, DOTS, ECB, entity command buffer
How to invoke
Section titled “How to invoke”/t1k:unity:dots-core:entity-command-bufferDOTS EntityCommandBuffer (ECB)
Section titled “DOTS EntityCommandBuffer (ECB)”Handles ECB creation, playback, parallel usage, and structural change deferral.
Does NOT handle general ECS patterns (→ dots-ecs-core) or job/Burst patterns (→ dots-jobs-burst).
ECB Creation
Section titled “ECB Creation”// Option 1: from system state (recommended — auto-disposed)var ecb = new EntityCommandBuffer(Allocator.TempJob);
// Option 2: from ECB system singleton (plays back at system group boundary)var ecb = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>() .CreateCommandBuffer(state.WorldUnmanaged);
// Option 3: from EntityManager (manual playback)var ecb = new EntityCommandBuffer(Allocator.Temp);ecb.Playback(state.EntityManager);ecb.Dispose();Use Option 2 for fire-and-forget spawning/destruction across systems.
Common ECB Operations
Section titled “Common ECB Operations”ecb.CreateEntity(); // returns placeholder Entityecb.DestroyEntity(entity);ecb.AddComponent<T>(entity, value);ecb.RemoveComponent<T>(entity);ecb.SetComponent<T>(entity, value);ecb.SetComponentEnabled<T>(entity, false); // → see dots-enableable-componentsecb.SetName(entity, "SpawnedUnit"); // debug onlyPlayback Order
Section titled “Playback Order”- Within one system: commands play back in the order they were recorded — deterministic
- Across systems: determined by system update order in the world’s system group
BeginSimulationEntityCommandBufferSystem— plays at start of SimulationSystemGroup frameEndSimulationEntityCommandBufferSystem— plays at end of SimulationSystemGroup frame
Choose BeginSim when spawned entities must be visible to systems in the SAME frame.
Choose EndSim when destruction must happen AFTER all simulation logic this frame.
Parallel ECB (ParallelWriter)
Section titled “Parallel ECB (ParallelWriter)”// Acquire parallel writervar ecbParallel = ecb.AsParallelWriter();
// In IJobEntity — pass sortKey from [ChunkIndexInQuery][BurstCompile]partial struct SpawnJob : IJobEntity{ public EntityCommandBuffer.ParallelWriter Ecb;
void Execute([ChunkIndexInQuery] int chunkIndex, in SpawnRequest req) { var e = Ecb.CreateEntity(chunkIndex); Ecb.AddComponent(chunkIndex, e, new Health { Value = 100 }); }}sortKey (chunkIndex) ensures deterministic playback across threads. Never use entity index as sort key — not stable across frames.
Deferred Entity Creation
Section titled “Deferred Entity Creation”// Entity returned is a PLACEHOLDER — not valid until after Playbackvar placeholder = ecb.CreateEntity();ecb.AddComponent(placeholder, new MyData { Value = 42 });// Can use placeholder for further ECB commands in same recording — they resolve togetherNever pass a deferred entity to code that runs BEFORE ECB playback — it is invalid outside ECB context.
Gotchas
Section titled “Gotchas”- ECB entity before playback: using a placeholder entity in EntityManager queries or SystemAPI before playback = invalid entity access → exception
- Multiple ECBs in same system: each ECB plays back independently — order between them is not guaranteed unless you control the system order explicitly
- ECB in IJobEntity: must pass ECB (or ParallelWriter) as a job field — cannot capture via closure
- Structural changes in foreach: never call
EntityManager.AddComponentinsideSystemAPI.Queryforeach — use ECB to defer the change - SetComponentEnabled on missing component: silently ignored — always ensure the component exists in the archetype before enabling/disabling via ECB
- SetComponent on ECB-instantiated prefab:
ecb.SetComponent(instantiatedEntity, data)fails at playback if the prefab doesn’t have the component. Useecb.AddComponent(instantiatedEntity, data)instead — idempotent: overwrites if exists, adds if not. Critical for perspective-agnostic systems (e.g.,SpriteColorexists on 2D prefabs but not 3D) - Manual
new ECB(Allocator.Temp) + ecb.Playback()is an anti-pattern — 6 demos use this instead ofEndSimulationEntityCommandBufferSystem.Singleton. The Singleton ECB plays back at the correct frame boundary and avoids manual ordering issues. Canonical pattern:EndSimulationEntityCommandBufferSystem.SystemHandle. Source: review-260520-round1-burst.md §X2
Performance
Section titled “Performance”- Batch destroys: prefer
ecb.DestroyEntity(query)over per-entity loop - Avoid ECB in every-frame hot paths — prefer structural stability, use
IEnableableComponentfor toggles (→dots-enableable-components) - ECB allocation uses
Allocator.TempJob(1-4 frames lifetime) orAllocator.Persistentfor long-lived buffers
Reference Files
Section titled “Reference Files”| Cross-Reference | Content |
|---|---|
→ See dots-ecs-core | General ECS, SystemAPI, IJobEntity |
→ See dots-jobs-burst | Burst-compiled jobs, parallel safety |
→ See dots-enableable-components | IEnableableComponent as ECB alternative |