Finding entities by ComonentData

Pre-ECS, I frequently use singletons to maintain a Dict<int, MyObj> of loaded objects.

When converting this to ECS and making it available in a job, I see three approaches

  • In job, call ComponentDataFromEntity and loop over entities testing componentdata
  • In job, inject SharedComponentData and use GetFilter
  • Replace Dict with NativeHashMap<int, Entity> and pass (readonly) to the job

Appreciate any feedback on these.
Jaochim advises against (2) in this post.
Think I’m missing a trick with SharedComponentData… Dict in SharedCompData?

I think I am missing the point, what do you want to do in the job? What do you want to filter? Could you describe the desired result with an example…

I’m not sure if that would do the trick for you, but I would try to create a ComponentGroup with a
ComponentArray Component and the EntityArray. If I understand correctly, the would give you all entities which have the Loaded component attached, so you would need to add that component to all your entities, but then you could easily iterate through them.

This is why I asked for clarification - I think @andywatts want’s something more than a simple tag.

I want to reference entities by an id, both in mono-land and in ECS jobs.
This id is assigned by me. I’m pulling from a database.

The below seems to work.
It provides Dictionary<int, Entity> in both Mono and ECS using SharedComponentData.

    // BlocksController(Entity) => Blocks(SharedDataComponent) => Value(attr)
    public void Start(){
        EntityManager entityManager = World.Active.GetOrCreateManager<EntityManager>();

        // Dictionary of entities
        Dictionary<int, Entity> dict = new Dictionary<int, Entity>();

        // Controller entity
        Entity BlocksController = entityManager.CreateEntity(typeof(MyController));

        // Add dictionary to SharedCompData
        Blocks entities = new Blocks{ Value = dict };

        // Add sharedCompData to controller
        entityManager.AddSharedComponentData(BlocksController, entities);

        // Prepare job
        var job = new Mesher{ 
            BlocksController = BlocksController
        };



        // Add some entities
        Entity e1 = entityManager.CreateEntity();
        dict[0] = e1;

        job.Schedule();
        //job.Complete();
    }

The sharedComp dictionary is available from jobs.

struct Mesher : IJob{
    public Entity BlocksController;

    public void Execute() {
        EntityManager entityManager = World.Active.GetOrCreateManager<EntityManager>();
        Blocks Blocks = entityManager.GetSharedComponentData<Blocks>(BlocksController);
        Debug.Log(Blocks.Value.Count);
    }

}

ComponentData looks like this.

[System.Serializable]

public struct Blocks : ISharedComponentData{

    public Dictionary<int, Entity> Value;

}

don’t access World.Active from inside the job. accessing a static variable throws up all the safety system and will break when Unity implements proper checks to prevent that (they will)

you can add a ComponentDataArray or ComponentDataFromEntity to the job if you need to access it.
or you can use IJobProcessComponentData that takes care of everything (and is parallel)

you can add an id component to each entity:

public struct DatabaseId : IComponentData { public int value; }

the global Dictionary should not be accessed from jobs anyway, you can keep it “outside ECS” i.e. in your DB interface layer (you use it for DB → ECS operations, and you use the DatabaseID component on the entities for your ECS → DB operations)

3 Likes