How large is to large for a componentdata, and how to relate disparate components/buffers?

I’ve been messing around with DOTS for a bit and am still struggling to figure out how I should structure things and how I should format the data and access it sometimes. Lots of methods seem to require you have to the entity for instance. Like I have several separate componendatas on an entity including a buffer like below.

public struct CellData : IComponentData
{
    public float3 worldPos;
    public int2 gridIndex;
    public byte cost;
    public ushort bestCost;
    public int2 bestDirection;
}
public struct FlowfieldMemberOf : IComponentData
{
    public CurrentFlowfield myflowfeld;

}
public struct FlowfieldVertPointsBuff : IBufferElementData
{
    public float3 Float3points;

    public static implicit operator float3(FlowfieldVertPointsBuff flowvertelem)
    {
        return flowvertelem.Float3points;
    }

    public static implicit operator FlowfieldVertPointsBuff(float3 e)
    {
        return new FlowfieldVertPointsBuff { Float3points = e };
    }
}
public struct FlowfieldNeigborEntities : IBufferElementData
{
    public int2 Neighbent;

    public static implicit operator int2(FlowfieldNeigborEntities Neigbelem)
    {
        return Neigbelem.Neighbent;
    }

    public static implicit operator FlowfieldNeigborEntities(int2 e)
    {
        return new FlowfieldNeigborEntities { Neighbent = e };
    }

}

That’s all data on a single entity but I find myself having problems when trying to figure out how to then get them and interact with them in systems. Like say I need the flowfieldNeighbourEntities and the CellData components. I have to get them separately because one is a buffer and I have to relate them so when I get them they both correlate on the same entity and I’m not quite sure how to do that. I have to get the Celldata with an EntityQuery, I can’t use an Entities.Foreach, so I would have to get two Entityquerys, one for the

and another for the

. And then correlate them with each other and then use the ToEntityArray, to get the correct DynamicBuffer. I don’t know that just seems a bit messy.

I don’t know if maybe if I’m over complicating things or confusing myself, or maybe its the formatting of my data that is wrong? I’m wondering what you do when you have a bunch of separate componentdata and buffers that you need together, but you can’t use an entities.foreach?

Why can’t you use Entities.ForEach?

eg.

Entities.ForEach ((Entity flowfieldEntity, in DynamicBuffer<FlowfieldCell> flowfield, in TileId tileId)=>

Alternatively, if you need to access multiple flowfields from different entities in the same job then you would need to use a GetBuffer / BufferFromEntity instead.

By the way, if this is for flowfields, eventually you might prefer to store less data per cell, or move the various members into other DynamicBuffers. You can get away with just storing a single byte for a flowfield cell, with 4 bits providing an index for a 16 direction look-up table and the other bits for various flags you might want such as obstacle, or line of sight.

Its because I need access to the entities in a non linear way. I need to calculate them in a specific order which is dependant on the previous calculated entity, I’m not aware of any way I could do that in a job as outlined above. I guess I will just have to have two nativearray’s, I was just hoping for a cleaner/simpler way of doing it.

I’m aware of the byte trick(just not the implementation, will have to look into that), am just trying to get the flowfield to work at all first.

Thanks for the help.

Ok you might have to do as you originally mention then. I often handle these sort of situations by referencing entities from a DynamicBuffer. For example when processing some flowfield entities in order along a hierarchical path:

Entities.ForEach ((Entity portalPathEntity, ref DynamicBuffer<PathFlowField> flowfields, in PortalPath portalPath)=>
{
  for (int flowfieldPathIndex = 0; flowfieldPathIndex < flowfields.Length; ++ flowfieldPathIndex)
  {
    Entity flowfieldEntity = flowfields [flowfieldPathIndex].m_flowfieldEntity;
  }
}

Few suggestions:

  1. Fetching NativeArray from EntityQuery is fine, albeit a bit heavier on main thread.
  2. Use ComponentDataFromEntity, its faster than allocating component arrays.
  3. If you have “reference” to an Entity, you can call GetComponent(entity) / GetBuffer from inside ForEach even when iterating on different set of entities. As long as you’re not reading and writing at the same component. (Under the hood GetComponent / GetBuffer fetches / codegens a CDFE for you)
  4. It may be easier and faster to store entity references / state on system itself or re-evaluate and patch entity references before required logic runs. In other words - prepare your data before processing.

Thanks for the replies. To be honest I wish there was a GetEntity similar to GetComponent that you could use in a job, that might make things a bit simpler. I have used GetBuffer before and I found out that using a separate job to prepackage all those components in the buffers into a single nativearray was a lot faster, but I guess it depends on the case.

With this job I’m creating I would need to use GetBuffer once every loop, I’m sure that wouldn’t be optimal. I guess I could just calculate the neigbours every loop instead of storing them I’m wondering if that would be faster.

Worth a try, that’s what I’ve done. A few math.select calls with zero branching to get the neighbours and it appears to be pretty fast, even if it might not be the fastest possible.

If I were going to store the neighbours I’d probably chuck them all in a single buffer/array (for all cells in a tile/graph) and then offset into it rather than store a buffer/array per cell. In fact that’s what I have done for a non-grid based higher level pathfinding graph.