1
\$\begingroup\$

I am using Entities v0.8

I am trying to build a Spawner, and this is the system

using UnityEngine;
using Unity.Entities;
using Unity.Transforms;

public class ChunkSpawnerSystem : SystemBase
{
    protected override void OnUpdate()
    {
        Entities.ForEach((ref ChunkSpawnerComponent spawner) =>
        {
            if (!spawner.needsRender) return;

            EntityArchetype chunkArchetype = EntityManager.CreateArchetype(new ComponentType[] { typeof(Translation) });

            for (int id = 0; id < spawner.size; id++)
            {
                Debug.Log("Rendering chunk " + id);
                Entity entity = EntityManager.CreateEntity(chunkArchetype);
                EntityManager.SetName(entity, "Chunk " + id);
            }

            spawner.needsRender = false;

        }).Schedule();

    }
}

But I get the following error

ChunkSpawnerSystem.cs(9,9): error DC0002: Entities.ForEach Lambda expression invokes 'get_EntityManager' on a ChunkSpawnerSystem which is a reference type. This is only allowed with .WithoutBurst() and .Run().

Apparently I cannot seem to be able to use EntityManager inside the lambda function. Why is this?

\$\endgroup\$
0
1
\$\begingroup\$

Check out this example of a system which has entities spawning more entities from Unity Technologies.

This comment explains the problem:

Systems can schedule work to run on worker threads. However, creating and removing Entities can only be done on the main thread to prevent race conditions.

In other words, the EntityManager isn't thread-safe. So you can not safely use it from code which might run in parallel with other code. The same example also provides a solution to this problem:

The system uses an EntityCommandBuffer to defer tasks that can't be done inside the Job.

So what you need to do in your system is to obtain a reference to the CommandBufferSystem. You can do this in OnCreate with

commandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();

in the OnUpdate-method of your system, you then need to

  1. Obtain a commandBuffer from the CommandBufferSystem using var commandBuffer = commandBufferSystem.CreateCommandBuffer().ToConcurrent();
  2. Write the ForEach lambda function to attach commands to the commandBuffer using commandBuffer.Instantiate, commandBuffer.SetComponent etc.
  3. Schedule the ForEach job
  4. Schedule the execution of the command buffer with commandBufferSystem.AddJobHandleForProducer(Dependency);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.