Search for specific entity(s) based on component values

Hello gang,

I am lost, there seems to not be a way to search for specific entities. There is the Entity Query where I can create a list of entities that contain a specific component, but not by the values of said component. Am I wrong?

I started with databases back in the early 90s, so the ability to search for specific items is so common. It exists for databases, arrays, etc. So what dumbass thing am I missing?

Thanks

Nothing really built in. You need to implement it yourself. Why? Well because most of the time you should immediately process each result you discover to save memory bandwidth. However, if the number of unique values is small, you might benefit from shared components.

1 Like

In General System I would agree, but for the editor it would be really useful if we could not just query for entities with specific components, but actual specified values.

It would make the inspection of entities a lot more pleasant/faster.

1 Like

You can write quick job, which looks up through queries entities with specific value.

You can post an example, all I can find is jobs that return components by type, not by content/value.

Thanks, at least I am not insane for not finding an answer that does not exist.

Make yourself a DebugTools.cs MonoBehaviour with this kind of methods :

[ContextMenu("AnalyzeMeshStats")]
        public void AnalyzeMeshStats()
        {
            var em = World.DefaultGameObjectInjectionWorld.EntityManager;
            var entities = em.GetAllEntities(Allocator.Temp);

            int minV = int.MaxValue;
            int maxV = 0;

            bool badOnlyBorders = true;
            bool goodOnlyBorders = true;

            foreach (var e in entities)
            {
                if (em.HasComponent<MeshStats>(e))
                {
                    var stats = em.GetComponentData<MeshStats>(e);
                    minV = min(minV, stats.VertCount);
                    maxV = max(maxV, stats.VertCount);

                    var voxStats = em.GetComponentData<VoxStats>(e);

                    if (em.HasComponent<BadVertices>(e))
                    {
                        badOnlyBorders &= stats.OnlyCrossingBorder;
                    }
                    else
                    {
                        goodOnlyBorders &= stats.OnlyCrossingBorder;
                    }
                }
            }

            Debug.Log($"min vert count{minV} , max {maxV}");
            Debug.Log($"BadMeshes onlyBorders {badOnlyBorders}");
            Debug.Log($"Good Meshes onlyBorders {goodOnlyBorders}");

        }

It’s extremely fast to scan 10,000ds of entities, it’s all small stuff in memory !

Thanks, but that’s not what I am asking for (but REALLY, thank you!) All I need is the ability to filter:

ie:

var entities = em.GetAllEntities(Allocator.Temp);

var subset = entities.Where(x => x.value = 2)

I just cannot believe that ANYONE would build a data store and not have a search function. BLOWS MY MIND!

Anyway, have a wonderful weekend

2 Likes

There’s not a good construct for this in the C# language that is also Burst-friendly. And as I said earlier, you typically wouldn’t want to do things this way if you care about performance.

As mentioned, searching across all entities for specific value in components is inefficient and slow.
If you want it as an editor tooling - you can build it.

If you want it for game logic - forget it.
Define a query you need to search on, and then do a manual search inside specified component.
E.g.

Entities.ForEach((T someComponent) => {
    if (someComponent.Value == X)
         // Result found
}).Schedule();

Its basically the same thing you’re asking for.

Alternatively, think of a different solution based on your specific problem.
It depends on what you’re trying to solve.
From my experience, there’s literally 0 times such search would been required.

There are multiple approaches how to outline specific entity in context of game logic.
You can do any of the following:

  • Enable / Disable it (to use enable mask / filter on the query);
  • Put a flag inside the component, process all component of with that flag;
  • Set a tag to the entity via ECB;
    (identical to enabling / disabling but without thread write, and slower due to structural changes);
  • Add specific entity to the native container to process it later;
  • Read / Write separate entity directly via lookups;
  • Use shared component as a key; (Though its not worth doing in most of the cases)

ECS is not exactly database.
While having similar concepts (due to being DOD in nature) its not 1 to 1 representation.
Its built to process large quantities of data in batches at blazing fast speeds over defined and O(1) queries.

At the same time, you’d want to place constraints in the database query to find specifically what you want anyway, so…

1 Like

It would be good to have an example use case of this, that we can reason about. Maybe the best solution might not even have to involve “querying by value”, but would take a different approach that flips the problem on its head

Ok gang,

I am going to try this again in hopes that someone has an answer:

I have roads, connections (aka Intersections) and autos. The roads have Vector3 points for each lane. Each auto is assigned a Road and therefore it’s points. When an auto reaches the end of a road, the Connection/Intersection has data that shows me which roads are connected to it. I need to gather these other roads, choose one of them at random and then have the Auto move along that new road’s points.

There is a set of entities for Roads and another set of entities for Connections. In my old, pre 1.0 ECS I had two entity queries that gave me all Roads and Connections (one NativeArray for Roads, one for Connections)

When the Auto reached the end of the Road I would look through the Connections to find a match to the identity at the end of the Road (asset: Easy Roads 3D, good asset, AWESOME support!) When I get that Connection I can then find it’s “exit” point Road Identities, those that met that criteria are then put into a list that I can randomly choose from.

I “need” this functionality because there should be random movement of the autos. I’d hate to assign an Auto’s path at startup and then just have it do that “loop”

If anyone has a better idea on how to model this, I am absolutely open to ideas.

I assume this will need further discussion or explanations of details that I’ve missed, but let’s start here:

  • CarSystem makes car entities progress along their current Road.

  • CarSystem also handles detecting when a car has reached the end of a road

  • When that happens, it gets that road’s Intersection entity (presumably stored in a component on the road entity)

  • On the Intersection entity, it gets a DynamicBuffer of connected Roads entities

  • It looks through those connected roads and chooses a random valid match. This is where the car goes next

1 Like

Sounds like you have the idea. Here is my old code: https://github.com/Blissgig/Easy-Road-3D-ECS-Traffic

In that case I don’t think you need any querying by value to solve this (aside from a general car query to update car entities)

  • Cars store the entity for their current road in the Car component
  • Roads store the entity(ies) of their connections in a DynamicBuffer
  • Connections store the entities of connected roads in a DynamicBuffer

So when a car reaches the end of a road, it can go find a random next connected road through these stored entities. Car gets road entity, then finds intersections of that road, then finds other roads. All this just by looking up components or buffers on entities starting from the Car entity

1 Like

huh… interesting. I will absolutely digest this. Thank you very much.

So basically you want to find closest conector(s) to the next road at the end of the path?

You could just store / insert connection points (start / end) in some kind of auxilary structure, like an octree / quadtree.
E.g. https://github.com/marijnz/NativeOctree
(actual tree works fine in recent versions with some changes to the test API)

Then query by car position + radius / distance will return all result connectors.

That will immensely reduce random access.
If your map doesn’t change often, it will be also faster, since no tree rebuilding would be required.

Plus it will reduce headache from keeping all the references and iterating through them.
+
Edit:
Manually connecting roads will also work (by storing refs in DynamicBuffer of the road).
But having to manually change connections [instead of just adjusting road points] is probably be more taxing on the game design side.

I will look into this. Thank you very much

1 Like

I wanted to come back and say I just returned to the traffic on my project, and you were right.

I have Lanes, which have collection of points, and a collection of ref to entities that connect to the end of that lane. When the System gets to the last index of the Points, I select randomly from the list (dynamic array) of Connected Lanes. It was all about setting up the data correctly. Thank you very much for enlightening me. Have a great week