Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Confustion with sharing NativeCollection between different SystemBase systems.

Discussion in 'Entity Component System' started by DanSuperGP, Jul 19, 2020.

  1. DanSuperGP

    DanSuperGP

    Joined:
    Apr 7, 2013
    Posts:
    408
    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.

    Code (CSharp):
    1. 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?



    Code (CSharp):
    1.    
    2. using System.Runtime.InteropServices;
    3. using Unity.Collections;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6.  
    7. namespace Cynics
    8. {
    9.  
    10.     public class GridOccupationSystem : SystemBase
    11.     {
    12.         private NativeArray<Entity> _gridOccupationMap;
    13.  
    14.         public NativeArray<Entity> GridOccupationMap => _gridOccupationMap;
    15.  
    16.         private EndSimulationEntityCommandBufferSystem _endSimulationEntityCommandBufferSystem;
    17.        
    18.         private int _width;
    19.  
    20.         private int _gridSize;
    21.        
    22.        
    23.         protected override void OnCreate()
    24.         {
    25.             base.OnCreate();
    26.  
    27.             var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    28.  
    29.             var gridDefinition = entityManager.CreateEntityQuery(ComponentType.ReadOnly<GridDefinition>())
    30.                 .GetSingleton<GridDefinition>();
    31.  
    32.  
    33.             _width = gridDefinition.width;
    34.             _gridSize = gridDefinition.width * gridDefinition.height;
    35.  
    36.             _gridOccupationMap =
    37.                 new NativeArray<Entity>(_gridSize, Allocator.Persistent);
    38.  
    39.             _endSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    40.  
    41.         }
    42.  
    43.         public JobHandle GetDependency()
    44.         {
    45.             return Dependency;
    46.         }
    47.  
    48.         public void AddDependency(JobHandle inputDependency)
    49.         {
    50.             Dependency = JobHandle.CombineDependencies(Dependency, inputDependency);
    51.         }
    52.  
    53.         public Entity EntityAtIndex(int index)
    54.         {
    55.             if (index < 0 || index > _gridSize)
    56.                 return Entity.Null;
    57.  
    58.             return _gridOccupationMap[index];
    59.         }
    60.  
    61.         public Entity EntityAtXY(int x, int y)
    62.         {
    63.             var index = GridMappingHelper.ArrayIndexFromGridLocation(x, y, _width);
    64.            
    65.             if (index < 0 || index > _gridSize)
    66.                 return Entity.Null;
    67.  
    68.             return _gridOccupationMap[index];
    69.         }
    70.        
    71.         public bool IsOccupied(int index)
    72.         {
    73.             if (index < 0 || index > _gridSize)
    74.                 return false;
    75.  
    76.             return _gridOccupationMap[index] != Entity.Null;
    77.         }
    78.        
    79.         protected override void OnUpdate()
    80.         {
    81.             var ecb = _endSimulationEntityCommandBufferSystem.CreateCommandBuffer();
    82.  
    83.             var gridDefinition = GetSingleton<GridDefinition>();
    84.             var gridSize = gridDefinition.width * gridDefinition.height;
    85.            
    86.             Entities.WithAll<Tag_AddToOccupationGrid>().ForEach((Entity e, int entityInQueryIndex, in GridLocation gridLocation) =>
    87.             {
    88.                
    89.                 var index = GridMappingHelper.ArrayIndexFromGridLocation(gridLocation.x, gridLocation.y, gridDefinition.width);
    90.  
    91.                 if (index < 0 || index > gridSize)
    92.                     return;
    93.  
    94.                 this._gridOccupationMap[index] = e;
    95.                
    96.                 ecb.RemoveComponent<Tag_AddToOccupationGrid>(e);
    97.                
    98.             }).Schedule();
    99.            
    100.             Entities.WithAll<Tag_RemoveFromOccupationGrid>().ForEach((Entity e, int entityInQueryIndex, in GridLocation gridLocation) =>
    101.             {
    102.                
    103.                 var index = GridMappingHelper.ArrayIndexFromGridLocation(gridLocation.x, gridLocation.y, gridDefinition.width);
    104.  
    105.                 if (index < 0 || index > gridSize)
    106.                     return;
    107.  
    108.                 this._gridOccupationMap[index] = Entity.Null;
    109.                
    110.                 ecb.RemoveComponent<Tag_RemoveFromOccupationGrid>(e);
    111.  
    112.             }).Schedule();
    113.         }
    114.     }
    115. }
    116.  
     
  2. Mockarutan

    Mockarutan

    Joined:
    May 22, 2011
    Posts:
    158
    If I understand your problem currently, you should just make a local copy of the collection variable straight before the Entities.ForEach(). Just like this:

    Code (CSharp):
    1. var localGridOccupationMap = _gridOccupationMap;
    And then use localGridOccupationMap inside of the Entities.ForEach(). If you want to call functions inside of the Entities.ForEach() where the collection i used, the function needs to be static and you should just include the collection as a parameter.
     
    Egad_McDad likes this.