I’m confused about sharing a NativeArray (or other NativeCollections) between multiple SystemBase systems.
In other threads I read that a common practice is to make a public property for the Native Collection and then access it in other systems with GetOrCreateSystem<>(), and also that I need to keep track of the dependencies manually.
However when I’ve tried to set that up I get this error.
error DC0001: Entities.ForEach Lambda expression uses field '_gridOccupationMap'. Either assign the field to a local outside of the lambda expression and use that instead, or use .WithoutBurst() and .Run()
This seems like a major drawback and I haven’t seen anyone else mention it.
Can someone tell me what I’m doing wrong here? How do I make a public property and also assign it to a local? Am I stuck .WithoutBurst and .Run for all my systems that are the owner of shared NativeCollections?
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
namespace Cynics
{
public class GridOccupationSystem : SystemBase
{
private NativeArray<Entity> _gridOccupationMap;
public NativeArray<Entity> GridOccupationMap => _gridOccupationMap;
private EndSimulationEntityCommandBufferSystem _endSimulationEntityCommandBufferSystem;
private int _width;
private int _gridSize;
protected override void OnCreate()
{
base.OnCreate();
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
var gridDefinition = entityManager.CreateEntityQuery(ComponentType.ReadOnly<GridDefinition>())
.GetSingleton<GridDefinition>();
_width = gridDefinition.width;
_gridSize = gridDefinition.width * gridDefinition.height;
_gridOccupationMap =
new NativeArray<Entity>(_gridSize, Allocator.Persistent);
_endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
}
public JobHandle GetDependency()
{
return Dependency;
}
public void AddDependency(JobHandle inputDependency)
{
Dependency = JobHandle.CombineDependencies(Dependency, inputDependency);
}
public Entity EntityAtIndex(int index)
{
if (index < 0 || index > _gridSize)
return Entity.Null;
return _gridOccupationMap[index];
}
public Entity EntityAtXY(int x, int y)
{
var index = GridMappingHelper.ArrayIndexFromGridLocation(x, y, _width);
if (index < 0 || index > _gridSize)
return Entity.Null;
return _gridOccupationMap[index];
}
public bool IsOccupied(int index)
{
if (index < 0 || index > _gridSize)
return false;
return _gridOccupationMap[index] != Entity.Null;
}
protected override void OnUpdate()
{
var ecb = _endSimulationEntityCommandBufferSystem.CreateCommandBuffer();
var gridDefinition = GetSingleton<GridDefinition>();
var gridSize = gridDefinition.width * gridDefinition.height;
Entities.WithAll<Tag_AddToOccupationGrid>().ForEach((Entity e, int entityInQueryIndex, in GridLocation gridLocation) =>
{
var index = GridMappingHelper.ArrayIndexFromGridLocation(gridLocation.x, gridLocation.y, gridDefinition.width);
if (index < 0 || index > gridSize)
return;
this._gridOccupationMap[index] = e;
ecb.RemoveComponent<Tag_AddToOccupationGrid>(e);
}).Schedule();
Entities.WithAll<Tag_RemoveFromOccupationGrid>().ForEach((Entity e, int entityInQueryIndex, in GridLocation gridLocation) =>
{
var index = GridMappingHelper.ArrayIndexFromGridLocation(gridLocation.x, gridLocation.y, gridDefinition.width);
if (index < 0 || index > gridSize)
return;
this._gridOccupationMap[index] = Entity.Null;
ecb.RemoveComponent<Tag_RemoveFromOccupationGrid>(e);
}).Schedule();
}
}
}