EntityManager.Exists test not working properly

I use a hybrid approach where gameobjects (used for animations and game controls) follow relative entities on LateUpdate(). Entity destruction is done via command buffers in Systems. In the monobehaviour of follower gameobject, I check for followed entity’s destruction with if (_entityManager.Exists(EntityToFollow)):

public class FollowEntity : MonoBehaviour
{
    public Entity EntityToFollow;
    private EntityManager _entityManager;

    void Start()
    {

        _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;

    }

    void LateUpdate()
    {
        if (_entityManager.Exists(EntityToFollow))
        {
             // get some component X of the entity and sync this
             // gameobject with it, HERE SOMETIMES FAILS NOT FINDING THE COMPONENT
        }
           
        else
        {
            // do the stuff when an entity dies
        }
    }

Example of entity destruction in SystemBase:

EntityCommandBuffer.ParallelWriter _entityCommandBuffer = _commandBufferSystem.CreateCommandBuffer().AsParallelWriter(); //BeginFixedStepSimulationEntityCommandBufferSystem

Dependency = Entities
            .WithBurst()
            .WithAll<EnemyTag>()
            .WithReadOnly(_world)
            .ForEach((
                        int entityInQueryIndex,
                        Entity e,
                        ref LifeData life,
                        in JoinDistanceData joinDist,
                        in LocalToWorld ltw,
                        in IsFollowingData isFollowing
                    ) =>
            {

                ...            
                _entityCommandBuffer.DestroyEntity(entityInQueryIndex, e);
                ...
                           
            })
            .ScheduleParallel(Dependency);
        _commandBufferSystem.AddJobHandleForProducer(Dependency);

This approach works for some systems, not for other systems or when I destroy entities while changing scene. When it fails, it bypasses the Exists test and throws me the “A component with type:Unity.Transforms.Translation has not been added to the entity” exception, obviously as the entity has been destroyed but still trying to access it. It looks apparently random to me when this test is done and when it is bypassed, so I even hypothesized it could be branch prediction i.e. it does the test later and always executes the code, eventually rolling back whether the test is negative, and in this code it gets components of an entity that does not exists. Anyway, the entityManager.Exists test would be pretty useless if branch prediction may occur, I guess…

If you have any hints on this, it would help a lot! Thank you

Do you have system state components? Because an entity will continue to exist after Destroy is called as long as any system state component hasn’t been manually removed.

Hi @tertle , no I actually don’t. As I tested, the entity is actually destroyed but the “Exists” boolean is still true for that frame. In the next frame the Exists become false, as I tested. So I guess it’s a syncronizing problem, but AFAIK the entity command buffer should empty and destroy the entities before any LateUpdate().

No, the monobehaviour update calls are all executed before the whole entities update loop, your late update will execute before your command buffer will even be created. You can easily confirm this by using the timeline view from the profiler.

Well, not exactly. MB player loop calls between entities Initialization and Simulation groups. Which means all the entities and buffers you working on in Initialization group will run before MB calls, and all stuff processing in Simulation - after.
8265075--1082301--upload_2022-7-9_15-28-11.png

But in his case of BeginFixedStepSimulationEntityCommandBufferSystem - yes, MB will run before. But important thing to note - Fixed step sim group has different update rate than MB every frame LateUpdate.

Ok, fixed. thank you anyway for your inputs! it didn’t work because I had another system destroying those entities with BeginInitializationEntityCommandBufferSystem, instead I destroyed them just in BeginFixedStepSimulationEntityCommandBufferSystem