how to deal with "orphan" entities?

5091137--501623--2019-10-21_203831.png
here is a chunk with entities that have no components
how to query those poor fellows?

While you got valid question, I would ask first, how they happened?

You could create an EntityQuery that explicitly excludes all component types, but that’s brittle and would break if you forgot any component or someone else adds one. Alternatively, you could query the chunks themselves. This should do the trick, but I haven’t had the time to test it:

using(var chunks = EntityManager.GetAllChunks()) {
    var bareEntity = EntityManager.GetEntityOnlyArchetype();
    UnityEngine.Debug.Assert(bareEntity.GetComponentTypes().Length == 0);
    for (int c = 0; c < chunks.Length; c++) {
        if (chunks[c].Archetype == bareEntity) {
            // do your thing here.
        }
    }
}
1 Like

What’s the use of a completely empty entity?

they had components before, but all of them was removed at some point

this is a good question

yes, this is possible with chunk iteration, but is there a simple way?

I don’t know why but this whole conversation chain made me laugh out loud. Oh boy. :smile:

2 Likes

the problem of entities who lost everything isn’t a joke, this is a problem we need to solve together,
if you have nothing to say better to donate a few spare components, or used buffer elements in good condition going to be very helpful as well

2 Likes

@SubPixelPerfect was that component with data, or with tag?

For example, if I would have entity which suppose only to trigger some system, with single tag, or component, after job is done, remove entity, not the component.

I tend to remove tags, but not components with data. Or create short living entities, which will be removed soon after.

I avoid situation as fire, where entity become orphaned. Just thoughts.

1 Like

To tell the truth this is not a real case, I’ve made it just out of curiosity to know if orphan get destroyed automatically. So the answer is they don’t, and it is not that obvious how to cleanup them. So here I totally agree - it is better to avoid situation like this.

@SubPixelPerfect

Don’t know if is best option, but you could do checks, based on components count.
Simply check, if entities are 0 components. Of course you need iterate all entities in this case, or at least already filtered out entities.

EntityManager.GetComponentCount ( entity ) ;

The easiest way of getting rid of entities with no components is:

      Entities.ForEach((Entity e) => {
        if (EntityManager.GetComponentCount(e) == 0)
          PostUpdateCommands.DestroyEntity(e);
      });

Note that this generates garbage.

What if you have 100,000 components :eyes: That’s a lot of iterations.
I feel like sschoener is on the right track and it’s easy to turn into a job.

1 Like

Well. I didn’t say it was performant. But then again there shouldn’t be empty entities wondering around :eyes:

I might be a little ignorant here, but what’re the odds this is a chunk with a SharedComponentData still attached? It could even be some SystemSharedComponentData that isn’t quite cleaned up.

Grabbing on what @sschoener wrote i’ve created a job for destroying empty entities:

  [BurstCompile]
  struct DestroyOnlyEntities : IJobChunk {
    public EntityArchetype EntityOnlyArchetype;
    [ReadOnly]
    public ArchetypeChunkEntityType EntityType;
    [WriteOnly]
    public EntityCommandBuffer.Concurrent CmdBuffer;
    public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex) {
      var entities = chunk.GetNativeArray(EntityType);
      if (chunk.Archetype == EntityOnlyArchetype)     
        for (var i = 0; i < chunk.Count; i++)
          CmdBuffer.DestroyEntity(firstEntityIndex + i, entities[i]);
    }
  }

When scheduling pass EntityManager.UniversalQuery as it’s query.
Note that it’s even burstable because EntityCommandBuffer.DestroyEntity is supported by Burst.

2 Likes

This solution doesn’t work anymore on Entities 0.2.0 because EntityManager.GetEntityOnlyArchetype() was removed.

1 Like

Actually you can use EntityManager.CreateArchetype() which is the same as our old EntityManager.GetEntityOnlyArchetype().
So this works again :slight_smile:

1 Like