How to use ECB in IJobEntityBatch

The goal I want is as follows.

  1. Implement the ‘Attack system’ using IJobEntityBatch.
  2. Create a projectile prefab when inputting the attack.
  3. Bring the projectile’s ‘Projectile’ component(IComponentData).

However, there was a problem with the part where the Projectile component data was imported.

The errors are as follows.
ArgumentException: All entities created using EntityCommandBuffer.CreateEntity must be realized via playback(). One of the entities is still deferred (Index: -1).

  • Importing EntityManager into IJobEntityBatch also results in errors.

By inference, it seems that I lack knowledge of EntityCommandBuffer.

I ask for your help.

This is my Code.

public partial class AttackSystem : SystemBase
{
    private EntityQuery _attackQuery;

    private EndSimulationEntityCommandBufferSystem _endSimulationEntityCommandBufferSystem;

    private partial struct AttackJob : IJobEntityBatch
    {
        public float DeltaTime;

        public EntityCommandBuffer Ecb;

        [ReadOnly]
        public EntityTypeHandle EntityType;
        public ComponentTypeHandle<Attacker> AttackerType;
        [ReadOnly]
        public ComponentTypeHandle<Equipment> EquipmentType;

        public ComponentDataFromEntity<Projectile> ProjectileFromEntity;
        public ComponentDataFromEntity<LocalToWorld> LocalToWorldFromEntity;

        [BurstCompile]
        public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
        {
            var attackers = batchInChunk.GetNativeArray(AttackerType);
            var equipments = batchInChunk.GetNativeArray(EquipmentType);
            var entities = batchInChunk.GetNativeArray(EntityType);

            for (int i = 0; i < batchInChunk.Count; i++)
            {
                var entity = entities[i];
                var attacker = attackers[i];
                var equipment = equipments[i];
                var weapon = equipment.EquippedWeapon;

                if (attacker.AttackRequested && attacker.AttackDelayTimer <= 0)
                {
                    //var handLocalToWorld = EntityManager.GetComponentData<LocalToWorld>(equipment.WeaponSpawnPoint);
                    LocalToWorldFromEntity.TryGetComponent(equipment.WeaponSpawnPoint, out var handLocalToWorld);

                    if (attacker.CurrentClip > 0 || !attacker.IsReloading)
                    {
                        UnityEngine.Debug.Log($"Attacker : {entity}");

                        var projectileEntity = Ecb.Instantiate(weapon.ProjectileEntity);

                        {
                            // Error
                            ProjectileFromEntity.TryGetComponent(projectileEntity, out var projectile);
                            Ecb.SetComponent(projectileEntity, projectile);
                            Ecb.SetComponent(projectileEntity, new Translation { Value = handLocalToWorld.Position });
                        }

                        attacker.CurrentClip--;
                        attacker.AttackDelayTimer = weapon.AttackDelay;

                        if (attacker.CurrentClip == 0)
                        {
                            attacker.ReloadTimer = weapon.ReloadTime;
                            attacker.IsReloading = true;
                        }
                    }
                }

                if (attacker.IsReloading && attacker.ReloadTimer <= 0)
                {
                    attacker.CurrentClip = weapon.ClipSize;
                    attacker.IsReloading = false;
                }

                attacker.ReloadTimer -= DeltaTime;
                attacker.AttackDelayTimer -= DeltaTime;

                attackers[i] = attacker;
            }
        }
    }

    protected override void OnCreate()
    {
        _endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();

        var description = new EntityQueryDesc
        {
            All = new ComponentType[]
            {
                ComponentType.ReadWrite<Attacker>(),
                ComponentType.ReadOnly<Equipment>(),
            },
        };

        _attackQuery = GetEntityQuery(description);
    }

    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        var ecb = _endSimulationEntityCommandBufferSystem.CreateCommandBuffer();

        Dependency = new AttackJob
        {
            EntityType = GetEntityTypeHandle(),
            DeltaTime = deltaTime,
            Ecb = ecb,
            AttackerType = GetComponentTypeHandle<Attacker>(false),
            EquipmentType = GetComponentTypeHandle<Equipment>(true),
            ProjectileFromEntity = GetComponentDataFromEntity<Projectile>(),
            LocalToWorldFromEntity = GetComponentDataFromEntity<LocalToWorld>()

        }.Schedule(_attackQuery, Dependency);

        _endSimulationEntityCommandBufferSystem.AddJobHandleForProducer(Dependency);
    }

Delete lines 49 and 50. You are trying to read the projectile component from the instantiating entity and set it back to itself. That effectively does nothing, and at the same time invokes code that is generating your error. You cannot use ComponentDataFromEntity directly on the Entity struct returned by EntityCommandBuffer.Instantiate(). That Entity doesn’t actually exist yet and can only be used directly or indirectly in other EntityCommandBuffer methods.