Finding specific entity data by ComponentData

I’ve got a bunch of entities with associated data (IComponentData and IBufferElementData) hanging out in memory. Technically it’s a graph of connected lanes for a road system, or would be if I could figure out how to get at them. I’ve got another set of entities, vehicles, which have data associated with them:

  • Lane: LaneIdentityComponent, LanePointsComponent, LaneExitIdentityComponent, other lane data
  • Vehicle: LaneIdentityComponent, CurrentLanePointsComponent, NeedsNewLaneTag, other vehicle data

I have a job that operates on the vehicles (identified by a tag), and I’d like to be able to find the matching LanePointsComponent on the matching Lane, identified by the LaneIdentityComponent. What I’d like to be able to do is copy the data from LanePointsComponent into a component on the vehicle. Given there are about 800-900 lanes in memory, what is the best way to go about finding the correct lane to get data from? I envision a system that would operate on all entities with NeedsNewLaneTag, find the correct LaneExitIdentityComponent and copy that data into the CurrentLanePointsComponent and remove the NeedsNewLaneTag.

Does this seem like a reasonable approach? And how do I get the data out of my lane entities that are just kind of hanging around in memory at the moment?

It would be easier if vehicles cold hold a direct reference to their lane’s entity, something like this: (not tested)

[RequireComponentTag(typeof(NeedsNewLaneTag))]
struct LaneJob : IJobForEachWithEntity<LaneIdentityComponent>
{
    [NativeDisableParallelForRestriction] public ComponentDataFromEntity<LanePointsComponent> lanePoints;

    public EntityCommandBuffer.Concurrent commandBuffer;

    public void Execute(Entity entity, int i, [ReadOnly] ref LaneIdentityComponent laneIdentity)
    {
        var points = lanePoints[entity];
        points.data = lanePoints[laneIdentity.entity].data;
        lanePoints[entity] = points;
       
        commandBuffer.RemoveComponent<NeedsNewLaneTag>(i, entity);
    }
}

But perhaps that is not possible in your situation? If not, I guess you could use a NativeHashMap as LaneIdentity → Entity lookup.

That gives me some ideas. Thanks!

There is one thing I’m not sure about. I actually need to get the LanePointsComponent for the entity that has a LaneIdentityComponent that is equal to the LaneExitIdentityComponent of the lane that has the LaneIdentityComponent equal to the current LaneIdentityComponent on the vehicle. Pseudo-code:

points = lanes WHERE lane.identity = vehicle.currentLane.laneExitIdentity

Your NativeHashMap suggestion might be the way to go. The graph is read-only so I should be able to construct that in the OnCreate for the job.

I think that is a good way to do it if you are happy with the performance of that approach (there is much more performant ways to do it, but it would be complicating and challenging to implement).

As for the second question, I would create a CurrentLane component that exists on the vehicle entities which would hold an entity ref to its current lane entity.

public struct CurrentLane: IComponentData
{
    public Entity laneEntity;
}

Then you can use that entity to get its LanePointsComponent by using ComponentDataFromEntity.

Thanks. The entity reference is a good idea. I don’t know why I didn’t think of it, but I suspect it may not have occurred to me that you could store an entity reference like that.

I’ve also realized that I’m storing my points as DynamicBuffers, and I think I might need to convert those to NativeArray or something, but that’s a separate issue.

Glad that was helpful.

I don’t have much experience when it comes NativeArrays, but my understanding is that they can’t be used inside of IComponentData, and that DynamicBuffers were created to solve the problem of being able to work with arrays within the ECS framework (able to tightly back arrays with other components and query them like any other components). I might be wrong here? But if you were to use NativeArrays instead of DynamicBuffers for storying your points, what would that look like?

I have a similar use case, I have a mining ship that has a target. That target is an entity and I need, to mine the target, have a reference to it. I am going to try your solution. Tx.

Yeah, after re-reading the docs on DynamicBuffer, it seems their purpose is to replace arrays :slight_smile: So I accidentally did the right thing.