RemoveComponent with EntityCommandBuffer

I have an entities with 2 components VertexComponent and TileComponent. In my IJobParallelFor i copy some data from VertexComponent to TileComponent. After the copy is done I want to remove VertexComponent from this entity. I was wondering I can do this in a single IJobParallelFor job. How I attempted it below errors with an
IndexOutOfRangeException: Index 0 is out of range of ‘0’ Length. on Entity e = eVertexBuffer*; So clearly I need so sort of post command for remove. Any ideas. Thanks in advance*
```csharp

  •    [RequireComponentTag(typeof(VertexComponent))]
      struct BuildVertexEntitiesJob : IJobParallelFor
      {
          [ReadOnly] public EntityCommandBuffer.Concurrent ecb;
          [DeallocateOnJobCompletion]
          [ReadOnly] public NativeArray<Entity> eVertexBuffer;
          [ReadOnly] public ComponentDataFromEntity<VertexComponent> vertexEntity;
    
    
          public void Execute(int i)
          {
              Entity e = eVertexBuffer[i];
              var vertexData = vertexEntity[e];
    
              ecb.SetComponent<TileComponent>(i, e, new TileComponent
              {
                  position = new float3(vertexData.positionX, vertexData.positionY, vertexData.positionZ),
                  connectedTriA = Entity.Null,
                  connectedTriB = Entity.Null,
                  connectedTriC = Entity.Null,
                  connectedTriD = Entity.Null,
                  connectedTriE = Entity.Null,
                  connectedTriF = Entity.Null
              });
    
             ecb.RemoveComponent<VertexComponent>(i, e);
          }
      }
    
    
    
      protected override JobHandle OnUpdate(JobHandle inputDeps)
      {
         
          var hexSphereBuildComponent = GetSingletonEntity<HexSphereBuildDataComponent>();
          _hexSphereBuildDataSingleton = EntityManager.GetComponentData<HexSphereBuildDataComponent>(hexSphereBuildComponent);
    
    
          //
          // Job
          BuildVertexEntitiesJob jhBuildVertexEntities = new BuildVertexEntitiesJob()
          {
              ecb = ecbs.CreateCommandBuffer().ToConcurrent(),
              eVertexBuffer = eqVertexComp.ToEntityArray(Allocator.TempJob),
              vertexEntity = GetComponentDataFromEntity<VertexComponent>(true)
          };
    
          inputDeps = jhBuildVertexEntities.Schedule(_hexSphereBuildDataSingleton.vertexCount, 12, inputDeps);
          ecbs.AddJobHandleForProducer(inputDeps);
    
    
          inputDeps.Complete();
          return inputDeps;
      }*
    

```

I think the problem might not be execute order. The code seems no problem, may be eqVertexComp.ToEntityArray = 0 ?

You need to use the EntityCommandBuffer.Concurrent adapter struct. Without using that interface, the parallel ECB is nondeterministically played back, and it’ll throw errors.

Here’s the scripting API link: Struct EntityCommandBuffer.Concurrent | Package Manager UI website

Thanks for the reply. Im not sure I understand, is this not what Im doing here ?

[ReadOnly] public EntityCommandBuffer.Concurrent ecb;

I will double check this as well, thanks for the reply

Can you show the entity query?

The RequireComponentTag does nothing in IJobParallelFor.
Also why are you using ComponentDataFromEntity with a IJobParallelFor instead of IJobForEach? IJobForEach will already give the data you need. And will be cleaner in this case.

EntityCommandBuffer, currently doesn’t work with burst. So maybe using two systems, one copying the data and other one removing the component will be faster. In your case you always will remove the VertexComponent component, right? So removing in the main thread using a entity query will be faster.

You’re setting ReadOnly on the EntityCommandBuffer in your job. You will be writing in this EntityCommandBuffer so there is no need for the ReadOnly. Actually, i’m impressed that didn’t rise any error.

Can you try this?

public class BuildVertexEntitiesSystem : JobComponentSystem
{
    struct BuildVertexEntitiesJob : IJobForEachWithEntity<VertexComponent, TileComponent>
    {
        public EntityCommandBuffer.Concurrent CommandBuffer;
     
        public void Execute(Entity entiy, int index, [ReadOnly] ref VertexComponent vertexComponent, ref TileComponent tileComponent) {
            tileComponent.position = new float3(vertexComponent.positionX, vertexComponent.positionY, vertexComponent.positionZ);
            tileComponent.connectedTriA = Entity.Null;
            tileComponent.connectedTriB = Entity.Null;
            tileComponent.connectedTriC = Entity.Null;
            tileComponent.connectedTriD = Entity.Null;
            tileComponent.connectedTriE = Entity.Null;
            tileComponent.connectedTriF = Entity.Null;
         
            CommandBuffer.RemoveComponent<VertexComponent>(index, entity);
        }
    }
 
    EntityCommandBufferSystem commandBufferSystem;
 
    protected override void OnCreate()
    {
        base.OnCreate();
     
        commandBufferSystem = World.GetOrCreateSystem<....>();
    }
 
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        inputDeps = new BuildVertexEntitiesJob
        {
            CommandBuffer = commandBufferSystem.CreateCommandBuffer().ToConcurrent()
        }.Schedule(this, inputDeps);
     
        commandBufferSystem.AddJobHandleForProducer(inputDeps);
    
        return inputDeps;
    }
}

Or, using two systems, this:

public class BuildVertexEntitiesSystem : JobComponentSystem
{
    [BurstCompile]
    struct BuildVertexEntitiesJob : IJobForEach<VertexComponent, TileComponent>
    {
        public void Execute([ReadOnly] ref VertexComponent vertexComponent, ref TileComponent tileComponent) {
            tileComponent.position = new float3(vertexComponent.positionX, vertexComponent.positionY, vertexComponent.positionZ);
            tileComponent.connectedTriA = Entity.Null;
            tileComponent.connectedTriB = Entity.Null;
            tileComponent.connectedTriC = Entity.Null;
            tileComponent.connectedTriD = Entity.Null;
            tileComponent.connectedTriE = Entity.Null;
            tileComponent.connectedTriF = Entity.Null;
        }
    }
 
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        return new BuildVertexEntitiesJob().Schedule(this, inputDeps);
    }
}

[UpdateAfter(typeof(BuildVertexEntitiesSystem))]
public class ClearVertexEntitiesSystem : ComponentSystem
{
    EntityQuery query;
 
    protected override void OnCreate()
    {
        base.OnCreate();
     
        query = GetEntityQuery(typeof(VertexComponent), typeof(TileComponent));
    }
 
    protected override void OnUpdate()
    {
        EntityManager.RemoveComponent(query, typeof(VertexComponent));
    }
}

Didn’t have an opportunity to test both codes above (and you have to fill the correct EntityCommandBufferSystem on the first code, line 23) but you shouldn’t have any big trouble fixing something.

[ ]'s

  • Edit: Formatting
1 Like

Thanks for the relpy this is helpful. I purposely forced the IJobParallelFor because I though it would be faster but maybe I was wrong. Maybe when EntityCommandBufferSystem supports burst