Search Unity

Reading from SharedComponentDataArray throws InvalidOperationException

Discussion in 'Entity Component System' started by Demkeys, Dec 10, 2018.

  1. Demkeys

    Demkeys

    Joined:
    Nov 14, 2014
    Posts:
    32
    Hey everyone. I've very new to ECS so I still don't fully understand what I'm doing. I have a SpawnerComponent and SpawnerSystem.

    SpawnerComponent code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Collections;
    6. using Unity.Mathematics;
    7. using Unity.Transforms;
    8.  
    9. [System.Serializable]
    10. public struct ECS01Spawner : ISharedComponentData {
    11.  
    12.     public GameObject prefab;
    13.     public int count;
    14.     public float minRange;
    15.     public float maxRange;
    16.  
    17. }
    18.  
    19. public class ECS01SpawnerComponent : SharedComponentDataWrapper<ECS01Spawner> { }
    20.  
    SpawnerSystem code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Collections;
    6. using Unity.Mathematics;
    7. using Unity.Transforms;
    8.  
    9. public class ECS01SpawnerSystem : ComponentSystem {
    10.  
    11.     struct DataGroup
    12.     {
    13.         [ReadOnly] public SharedComponentDataArray<ECS01Spawner> spawner;
    14.  
    15.         public ComponentDataArray<Position> positions;
    16.         public EntityArray entities;
    17.     }
    18.     [Inject] private DataGroup m_DataGroup;
    19.  
    20.     protected override void OnUpdate()
    21.     {
    22.         Entity sourceEntity = m_DataGroup.entities[0];
    23.  
    24.         NativeArray<Entity> entities = new NativeArray<Entity>(m_DataGroup.spawner[0].count, Allocator.Temp);
    25.         EntityManager.Instantiate(m_DataGroup.spawner[0].prefab, entities);
    26.  
    27.         for(int i = 0; i < entities.Length; i++)
    28.         {
    29.             /* Method 1 */
    30.             Unity.Mathematics.Random randomNumGenerator = new Unity.Mathematics.Random(i == 0 ? 1 : (uint)i);
    31.             float x = randomNumGenerator.NextFloat(m_DataGroup.spawner[0].minRange,m_DataGroup.spawner[0].maxRange);
    32.             float z = randomNumGenerator.NextFloat(m_DataGroup.spawner[0].minRange,m_DataGroup.spawner[0].maxRange);
    33.             float3 randomFloat3 = new float3(x,0f,z);
    34.  
    35.             /* Method 2 */
    36.             // Unity.Mathematics.Random randomNumGenerator = new Unity.Mathematics.Random(i == 0 ? 1 : (uint)i);
    37.             // float x = randomNumGenerator.NextFloat(0f, 10f);
    38.             // float z = randomNumGenerator.NextFloat(0f, 10f);
    39.             // float3 randomFloat3 = new float3(x,0f,z);
    40.  
    41.             Position pos = new Position { Value = randomFloat3 };
    42.  
    43.             EntityManager.SetComponentData(entities[i], pos);
    44.         }
    45.  
    46.         entities.Dispose();
    47.         EntityManager.RemoveComponent<ECS01Spawner>(sourceEntity);
    48.         UpdateInjectedComponentGroups();
    49.     }
    50.  
    51. }
    52.  
    The SpawnerComponent is attached to a GameObject in the scene. The SpawnerSystem spawns (count) number of entities, and the position for each entity is set randomly. In the SpawnerSystem's OnUpdate method, you can see Method 1 and Method 2. These are two different methods I'm using to calculate the position randomly. Method 2, where I specific the min and max range, works perfectly fine. Method 1, where I'm trying to read minRange and maxRange from the SpawnerComponent, throws the following exception:
    InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it.

    Looking at the details of the exception, I traced it back to the following line in the SpawnerSystem:
    float x = randomNumGenerator.NextFloat(m_DataGroup.spawner[0].minRange,m_DataGroup.spawner[0].maxRange);


    Can anyone tell me what I'm doing wrong here?
    Also I'd like to know if float and float3 need to be disposed the way NativeArray needs to be disposed.
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    At 25 row you are doing structural changes, and it's invalidate chunk, after that you can't access injected data, because it's invalid. You must call UpdateInjectedComponentGroups after instantiate. But better way it's switch to ComponentGroup\Chunk Iteration and get data arrays after instantiate in any case CG\CI faster than Inject.
     
    Demkeys likes this.
  3. Demkeys

    Demkeys

    Joined:
    Nov 14, 2014
    Posts:
    32
    Ah I see. Adding a call to UpdateInjectedComponentGroups after line 25 worked. Thanks!
    I'll do more research on ComponentGroup and Chunk and try and implement that, and also read up on Injection to understand what's going on in my current system as well. Thanks for the info.