DynamicBuffer in EntityQuery (non-Job)?

Hi all,

I’m trying to run a specific type of ForEach loop that doesn’t seem to be implemented in the default ECS implementation (1 Entity, 2x ref IComponentData, and 2x DynamicBuffer) in a main thread ComponentSystem, therefore I’ve been trying to use EntityQuery for that.

I have been able to get my entities (EntityQuery.ToEntityArray) and my two sets of data components (EntityQuery.ToComponentDataArray) pretty fine, but I can’t find how to get the dynamic buffers (the only thing I found was GetBufferFromEntity, which seem to be limited to jobs).

Is there a way to do that? or do I need to use something else (job system, other type of query…) ?

Thanks

There is no overload for what you want to do in a ComponentSystem.
But why don’t you do that in a job IJobForEachWithEntity_EBBCC<> which is exactly the overload you want. Then instead of scheduling you can just run it in the main thread with .Run() ?

1 Like

I didn’t realize that was a possibility, I’ll try that, thanks!

ps: what’s the difference between D and C btw? I thought I was trying to do a EDDBB (or EBBDD)…

In Entities.ForEach D is ComponentData and C UnityEngine.Component. Unfortunately in IJobForEach_X, C is for ComponentData.

[ ]'s

1 Like

I’m running into another issue with this approach: despite running from the main thread (afaik) with Run(), I still get the following errors as if I was scheduling the job:

UnityException: get_frameCount can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

What do you think?

note: the Profiler shows the job being executed on the main thread as intended

You can’t use Unity APIs that are restricted to main thread in jobs even if you use Run. You’ll need to pass the data at scheduling time.

[ ]'s

1 Like

Are you calling Time.frameCount from within that job? If so you can’t do that.
But can you show the code for that job?

@GilCat pretty intricate structure with multiple layers of dependencies + NDA stuff so it would take some time to show :). I’m not calling frameCount directly, but some managed Unity code must be doing that (part of that “job” is to call some Unity UI code)

@elcionap note I’m not originally trying to run a job specifically, but using one was mentioned as the only way to simulate an EBBCC/EBBDD component system. Back to the drawing board? ^_^;

Then your solution is to do manual chunk iteration on the main thread. which is basically what Entities.ForEach does in ComponentSystem behind the scenes.

1 Like

You can do something like this or create your own extension with lambda expressions from this.

var entityType = GetArchetypeChunkEntityType();
    var chunkComponentType0 = GetArchetypeChunkComponentType<YourComponentType01>();
    var chunkComponentType1 = GetArchetypeChunkComponentType<YourComponentType02>();
    var chunkBufferComponentType1 = GetArchetypeChunkBufferType<YourBufferType01>();
    var chunkBufferComponentType2 = GetArchetypeChunkBufferType<YourBufferType02>();

    using (var chunks = m_query.CreateArchetypeChunkArray(Allocator.TempJob)) {
      for (var chunkIndex = 0; chunkIndex < chunks.Length; ++chunkIndex) {
        var chunk = chunks[chunkIndex];
        var array0 = chunk.GetNativeArray(chunkComponentType0);
        var array1 = chunk.GetNativeArray(chunkComponentType1);
        var array2 = chunk.GetBufferAccessor(chunkBufferComponentType1);
        var array3 = chunk.GetBufferAccessor(chunkBufferComponentType2);
        var entityArray = chunk.GetNativeArray(entityType);

        for (var i = 0; i < chunk.Count; ++i) {
          var c0 = array0[i];
          var c1 = array1[i];
          var b0 = array2[i];
          var b1 = array3[i];

          // Do your stuff here

        }
      }
    }
1 Like

Thanks for the heads up! All my iterations are in generic classes, I’ll have a look at cooking something with that :slight_smile:

Seems like you can also do:

    Entities
      .WithoutBurst()
      .WithName("MyJob")
      .ForEach((Entity entity, int entityInQueryIndex, DynamicBuffer<Buffer01> b1, DynamicBuffer<Buffer02> b2, ref Component1 c1, ref Component2 c2) =>
    {
      // Now you can call Unity API here
    }).Run();