docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Automatic play back and disposal of entity command buffers

    To play back and dispose of entity command buffers (ECBs), you can use EntityCommandBufferSystem, rather than manually doing it yourself. To do this:

    1. Get the singleton instance of the EntityCommandBufferSystem which you want to do the playback.
    2. Use the singleton to create an EntityCommandBuffer instance.
    3. Records commands to the EntityCommandBuffer.

    For example:

    
    // ... in a system.
    
    // Assume an EntityCommandBufferSystem exists named FooECBSystem.
    // This call to GetSingleton automatically registers the job so that
    // it gets completed by the ECB system.
    var singleton = SystemAPI.GetSingleton<FooECBSystem.Singleton>();
    
    // Create a command buffer that will be played back
    // and disposed by MyECBSystem.
    EntityCommandBuffer ecb = singleton.CreateCommandBuffer(state.WorldUnmanaged);
    
    // An IJobEntity with no argument to Schedule implicitly
    // assigns its returned JobHandle to this.Dependency
    new MyParallelRecordingJob() { ecbParallel = ecb.AsParallelWriter() }.Schedule();
    
    

    In the case of a SystemBase system, the unmanaged world can be accessed like this: World.Unmanaged.

    Important

    Don't manually play back or dispose of an EntityCommandBuffer that you've created with an EntityCommandBufferSystem. The EntityCommandBufferSystem does both for you when it runs.

    In each update, an EntityCommandBufferSystem:

    1. Completes all registered jobs, plus all jobs scheduled against its singleton component. This ensures that any relevant jobs have finished their recording.
    2. Plays back all ECBs created via the system in the same order they were created.
    3. Disposes of the EntityCommandBuffer instances.

    Default EntityCommandBufferSystem systems

    The default world has the following default EntityCommandBufferSystem systems:

    • BeginInitializationEntityCommandBufferSystem
    • EndInitializationEntityCommandBufferSystem
    • BeginFixedStepSimulationEntityCommandBufferSystem
    • EndFixedStepSimulationEntityCommandBufferSystem
    • BeginVariableRateSimulationEntityCommandBufferSystem
    • EndVariableRateSimulationEntityCommandBufferSystem
    • BeginSimulationEntityCommandBufferSystem
    • EndSimulationEntityCommandBufferSystem
    • BeginPresentationEntityCommandBufferSystem

    Because structural changes can't happen in the frame after Unity gives the rendering data to the renderer, there's no EndPresentationEntityCommandBufferSystem system. You can use BeginInitializationEntityCommandBufferSystem instead: the end of one frame is the beginning of the next frame.

    The EntityCommandBufferSystem systems update at the beginning and end of the standard system groups, and at the beginning and end of the fixed and variable rate simulation groups. For more information, refer to the documentation on System update order.

    If you can't use the default systems for your application, then you can create your own EntityCommandBufferSystem:

    
    // You should specify where exactly in the frame this ECB system should update.
    [UpdateInGroup(typeof(SimulationSystemGroup))]
    [UpdateAfter(typeof(FooSystem))]
    public partial class MyECBSystem : EntityCommandBufferSystem
    {
        // The singleton component data access pattern should be used to safely access
        // the command buffer system. This data will be stored in the derived ECB System's
        // system entity.
    
        public unsafe struct Singleton : IComponentData, IECBSingleton
        {
            internal UnsafeList<EntityCommandBuffer>* pendingBuffers;
            internal AllocatorManager.AllocatorHandle allocator;
    
            public EntityCommandBuffer CreateCommandBuffer(WorldUnmanaged world)
            {
                return EntityCommandBufferSystem
                    .CreateCommandBuffer(ref *pendingBuffers, allocator, world);
            }
    
            // Required by IECBSingleton
            public void SetPendingBufferList(ref UnsafeList<EntityCommandBuffer> buffers)
            {
                var ptr = UnsafeUtility.AddressOf(ref buffers);
                pendingBuffers = (UnsafeList<EntityCommandBuffer>*)ptr;
            }
    
            // Required by IECBSingleton
            public void SetAllocator(Allocator allocatorIn)
            {
                allocator = allocatorIn;
            }
    
            // Required by IECBSingleton
            public void SetAllocator(AllocatorManager.AllocatorHandle allocatorIn)
            {
                allocator = allocatorIn;
            }
        }
    
        protected override void OnCreate()
        {
            base.OnCreate();
    
            this.RegisterSingleton<Singleton>(ref PendingBuffers, World.Unmanaged);
        }
    }
    
    

    Entities created by command buffers

    The EntityCommandBuffer methods CreateEntity and Instantiate return real Entity references at record time. The entity is allocated immediately but is not assigned a chunk until Playback runs, so component access via EntityManager only works after playback:

    
    // ... in a system
    
    EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
    
    // CreateEntity returns a real entity reference immediately.
    // The entity has no chunk yet — that is assigned during Playback.
    Entity newEntity = ecb.CreateEntity();
    
    // Valid to use newEntity in later commands on the same buffer.
    ecb.AddComponent<FooComp>(newEntity);
    
    // Before Playback: EntityManager access throws because the
    // entity has no chunk yet.
    // state.EntityManager.AddComponent<BarComp>(newEntity); // throws
    
    ecb.Playback(state.EntityManager);
    
    // After Playback: the entity has a chunk and the same
    // reference works directly with EntityManager.
    state.EntityManager.AddComponent<BarComp>(newEntity);
    
    ecb.Dispose();
    
    

    Values recorded in an AddComponent, SetComponent, or SetBuffer command can have Entity fields that reference entities created earlier in the same buffer. The references are stored directly; no remap pass is needed at playback:

    
    // ... in a system
    
    EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
    
    // For all entities with a FooComp component...
    foreach (var (f, e) in SystemAPI.Query<FooComp>().WithEntityAccess())
    {
        // CreateEntity returns a real entity reference immediately.
        Entity newEntity = ecb.CreateEntity();
    
        // (Assume BarComp has an Entity field called TargetEnt.)
        // The reference can be stored in component data directly.
        BarComp bar = new BarComp { TargetEnt = newEntity };
        ecb.AddComponent(e, bar);
    }
    
    // After playback, each entity with FooComp has a BarComp
    // whose TargetEnt references the corresponding new entity.
    ecb.Playback(state.EntityManager);
    
    ecb.Dispose();
    
    

    Additional resources

    • Playback entity command buffers
    In This Article
    Back to top
    Copyright © 2026 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)