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…) ?
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() ?
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
@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.
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
}
}
}
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();