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();
    
    
    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);
        }
    }
    
    

    Deferred entities

    The EntityCommandBuffer methods CreateEntity and Instantiate record commands that create entities. These methods only record commands and don't create entities. As such, they return Entity values with negative indices that represent placeholder entities that don't exist yet. These placeholder Entity values are only meaningful in recorded commands of the same ECB:

    
    // ... in a system
    
    EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
    
    Entity placeholderEntity = ecb.CreateEntity();
    
    // Valid to use placeholderEntity in later commands of same ECB.
    ecb.AddComponent<FooComp>(placeholderEntity);
    
    // The real entity is created, and
    // FooComp is added to the real entity.
    ecb.Playback(state.EntityManager);
    
    // Exception! The placeholderEntity has no meaning outside
    // the ECB which created it, even after playback.
    state.EntityManager.AddComponent<BarComp>(placeholderEntity);
    
    ecb.Dispose();
    
    

    Values recorded in an AddComponent, SetComponent, or SetBuffer command might have Entity fields. In playback, Unity remaps any placeholder Entity values in these components or buffers to the corresponding actual entities:

    
    // ... 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())
    {
        // In playback, an actual entity will be created
        // that corresponds to this placeholder entity.
        Entity placeholderEntity = ecb.CreateEntity();
    
        // (Assume BarComp has an Entity field called TargetEnt.)
        BarComp bar = new BarComp { TargetEnt = placeholderEntity };
    
        // In playback, TargetEnt will be assigned the
        // actual Entity that corresponds to placeholderEntity.
        ecb.AddComponent(e, bar);
    }
    
    // After playback, each entity with FooComp now has a
    // BarComp component whose TargetEnt references a new entity.
    ecb.Playback(state.EntityManager);
    
    ecb.Dispose();
    
    

    Additional resources

    • Playback entity command buffers
    In This Article
    Back to top
    Copyright © 2024 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)