Search Unity

The NativeArray has been deallocated - Hybrid ECS

Discussion in 'Data Oriented Technology Stack' started by Bhakti_GL1, Dec 18, 2018.

  1. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    So today I got an "InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it" error in one of my componentsystem.

    I have GameManager.cs that instantiates player and enemies when the game starts. There's nothing wrong when there's only 1 enemy, but after I set max enemy to more than one, "that" error occurs. I have been gathering some information from other posts in this forum and I think that the "Enemy's Instantiate step" on the GameManager is the source of this problem (and yes, please correct me if I am wrong, I'm just a new guy here).

    I am using Hybrid ECS. All of my entities have Parent component (for Pure ECS & Job system) and Child component (for physics and animation using Hybrid ECS & Component System). So when I instantiate new Entity, I always add the Entity component into List (for syncing Parent and Child), yes I know it's complicated but I think that is my "simplest way" to made Job system, Unity physics, and animation in one place. Btw I would be very thankful if u give me any other "simplest ways".

    Here is the "Enemy's Instantiate step" on the GameManager
    Code (CSharp):
    1. static void AddBee (int maxEnemy)
    2.         {
    3.             EntityManager manager = World.Active.GetOrCreateManager<EntityManager>();
    4.  
    5.             GameObject beePrefab = settings.beeEnemyPrefab;
    6.             float horBound = settings.horizontalBound;
    7.             float verBound = settings.verticalBound;
    8.  
    9.             for (int i=0; i<maxEnemy; i++)
    10.             {
    11.                 float xVal = Random.Range(-horBound, horBound);
    12.                 float zVal = Random.Range(-verBound, verBound);
    13.  
    14.                 // PARENT
    15.                 GameObject beeGO = GameObject.Instantiate(beePrefab, new Vector3(xVal, 0f, zVal), Quaternion.identity);
    16.                 GameObjectEntity beeGOEntity = beeGO.GetComponent<GameObjectEntity>();
    17.                 beeGOEntity.enabled = true;
    18.                 Entity beeEntity = beeGOEntity.Entity;
    19.  
    20.                 parentEntitiesInGame.Add(beeEntity);
    21.                 int currentParentEntityIndex = parentEntitiesInGame.Count-1;
    22.  
    23.                 manager.SetComponentData(beeEntity, new Parent { EntityIndex = currentParentEntityIndex });
    24.  
    25.                 // CHILD
    26.                 ChildComponent childComponent = beeGO.GetComponentInChildren<ChildComponent>();
    27.                 GameObjectEntity beeChildGOEntity = childComponent.GetComponent<GameObjectEntity>();
    28.  
    29.                 childEntitiesInGame.Add(beeChildGOEntity);
    30.                 int currentChildEntityIndex = childEntitiesInGame.Count-1;
    31.  
    32.                 childComponent.EntityIndex = currentChildEntityIndex;
    33.  
    34.                 entitiesAnimationToggle.Add(0);
    35.                 entitiesIdleLoopAnimationChecker.Add(0);
    36.  
    37.                 beeChildGOEntity.enabled = true;
    38.             }
    39.         }
    And here is the componentsystem that "doing enemy stuff" ;)
    Error on line 23.

    Code (CSharp):
    1. public struct Data
    2.         {
    3.             public readonly int Length;
    4.             [ReadOnlyAttribute] public EntityArray entity;
    5.             [ReadOnlyAttribute] public ComponentDataArray<Bee> Bee;
    6.             public ComponentDataArray<EnemyAIDirection> EnemyAIDirection;
    7.             [ReadOnlyAttribute] public ComponentDataArray<Position> Position;
    8.             [ReadOnlyAttribute] public ComponentDataArray<Parent> Parent;
    9.         }
    10.         [InjectAttribute] Data data;
    11.  
    12.         float3 float3Zero = float3.zero;
    13.         float deltaTime;
    14.  
    15.         protected override void OnUpdate ()
    16.         {
    17.             EntityCommandBuffer commandBuffer = PostUpdateCommands;
    18.  
    19.             deltaTime = Time.deltaTime;
    20.  
    21.             for (int i=0; i<data.Length; i++)
    22.             {
    23.                 Entity entity = data.entity[i];
    24.                 Bee bee = data.Bee[i];
    25.                 EnemyAIDirection enemyAIDirection = data.EnemyAIDirection[i];
    26.                 Position position = data.Position[i];
    27.                 Parent parent = data.Parent[i];
    28.                 commandBuffer.RemoveComponent<EnemyAIDirection>(entity);
    29.  
    30.                 // Other "Fun" Stuff
    31.             }
    32.         }
    33.  
    I'm stuck and stressed out for a couple of hours already. I would be glad if u help me fix these error, thank u very much! ;)
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,648
    What's the other fun stuff
     
    5argon likes this.
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    Yep I'm interested too, seems you made structural changes in this area
     
  4. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Alrighty then, here is my "fun" stuff :D

    Code (CSharp):
    1.  
    2.                 // Other "Fun" Stuff
    3.  
    4.                 float3 targetPos = float3Zero;
    5.                 int entityIndex = parent.EntityIndex;
    6.                 GameObjectEntity entityGO = childEntitiesInGame[entityIndex];
    7.                 GameObject childGO = entityGO.gameObject;
    8.  
    9. #region Nav Mesh Direction
    10.                 float moveRange = bee.MoveRange;
    11.                 float posX = position.Value.x;
    12.                 float posZ = position.Value.z;
    13.                 float randomX = UnityRandom.Range(posX - moveRange, posX + moveRange);
    14.                 float randomZ = UnityRandom.Range(posZ - moveRange, posZ + moveRange);
    15.                 targetPos = new float3(randomX, 0f, randomZ);
    16.                
    17.                 // enemyNavMeshData.TargetPosition = targetPos;
    18.                 childGO.AddComponent<NavMeshEventComponent>().Destination = targetPos;
    19.                 entityGO.enabled = false;
    20.                 entityGO.enabled = true;
    21. #endregion
    This fun stuff is a Nav Mesh code for enemy AI. It only adds NavMeshEventComponent to enemy's child.
    And yes, I am accepting some nice idea for these AI codes. Thank you very much :)
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,648
    And this is why you need to include all your code, this is your issue

    Code (CSharp):
    1. entityGO.enabled = false;
    2. entityGO.enabled = true;
    This destroys then creates an entity, invalidating all your ComponentDataArrays
     
    Bhakti_GL1 and eizenhorn like this.
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    You're faster :) 5AM by my timezone, I'm slept at tis time, not fair :D
     
    Bhakti_GL1 likes this.
  7. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Thank you very much, now the error is gone, and I have to change my code a bit

    btw that disabling-enabling the GameObjectEntity is my "tricky way" to refresh the "EntityManager" (I don't know what it called) because it's not live updating the GameObjectEntity when you adding or removing a component to them. Do you know the correct way about how to refresh the manager? Thank you :)
     
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    Code (CSharp):
    1.  
    2. protected virtual void OnEnable()
    3. {
    4. EntityManager entityManager;
    5. Entity entity;
    6. if (
    7. World.Active != null
    8. && TryGetEntityAndManager(out entityManager, out entity)
    9. && !entityManager.HasComponent(entity, GetComponentType()) // in case GameObjectEntity already added
    10. )
    11. entityManager.AddComponent(entity, GetComponentType());
    12. }
    13.  
    14. protected virtual void OnDisable()
    15. {
    16. if (!gameObject.activeInHierarchy) // GameObjectEntity will handle removal when Entity is destroyed
    17. return;
    18. EntityManager entityManager;
    19. Entity entity;
    20. if (CanSynchronizeWithEntityManager(out entityManager, out entity))
    21. entityManager.RemoveComponent(entity, GetComponentType());
    22. }
    23.  
    24. internal bool TryGetEntityAndManager(out EntityManager entityManager, out Entity entity)
    25. {
    26. entityManager = null;
    27. entity = Entity.Null;
    28. var gameObjectEntity = GetComponent<GameObjectEntity>();
    29. if (gameObjectEntity == null)
    30. return false;
    31. if (gameObjectEntity.EntityManager == null)
    32. return false;
    33. if (!gameObjectEntity.EntityManager.Exists(gameObjectEntity.Entity))
    34. return false;
    35. entityManager = gameObjectEntity.EntityManager;
    36. entity = gameObjectEntity.Entity;
    37. return true;
    38. }
    39.  
    40. internal bool CanSynchronizeWithEntityManager(out EntityManager entityManager, out Entity entity)
    41. {
    42. return TryGetEntityAndManager(out entityManager, out entity)
    43. && entityManager.HasComponent(entity, GetComponentType());
    44. }
    45.  
     
    Bhakti_GL1 likes this.
  9. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Thank you eizenhorn, you're my hero :D

    btw I have to put those code on every gameobject that has GameObjectEntity component, and let them synchronizing themselves with the EntityManager so I don't have to use "disabling-enabling jutsu" to every destroyed/instantiated GameObjectEntity, right?
     
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    This is what GameObjectEntity does, it's GameObjectEntity source code.
     
  11. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Wait I don't get it, what should I do? I don't understand :(

    Compared with yours GameObjectEntity, here are my default GameObjectEntity source code :
    Code (CSharp):
    1. #region Assembly Unity.Entities.Hybrid, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    2. // <in-memory assembly>
    3. #endregion
    4.  
    5. using UnityEngine;
    6.  
    7. namespace Unity.Entities
    8. {
    9.     [DisallowMultipleComponent]
    10.     [ExecuteInEditMode]
    11.     public class GameObjectEntity : MonoBehaviour
    12.     {
    13.         public GameObjectEntity();
    14.  
    15.         public EntityManager EntityManager { get; }
    16.         public Entity Entity { get; }
    17.  
    18.         public static Entity AddToEntityManager(EntityManager entityManager, GameObject gameObject);
    19.         public void CopyAllComponentsToEntity(EntityManager entityManager, Entity entity);
    20.         protected virtual void OnDisable();
    21.         protected virtual void OnEnable();
    22.     }
    23. }
     
  12. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    Because you not decompile it full. Just check entities package folder and you'll see sources.
     
  13. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Alright I found the GameObjectEntity source code on my entities package folder

    But how to refresh the Entity component in EntityDebugger of any GameObjectEntity when I added or destroyed one of its component? Because the Entities are not updating automatically right now. I just couldn't figure it out, Thank you btw
     
  14. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    Just look what does in OnEnable\Disable and you understand :)
     
  15. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Nope, It's hard for me to understand what GameObjectEntity does when they are on OnEnable and OnDisable "state". I tried adding the modified component of GameObjectEntity's Entity on the EntityManager using:
    manager.AddComponent(GameObjectEntity.Entity, typeof (ComponentType));

    But then "NullReferenceException" error occurs. I have to get the ComponentType on its Entity to fix that error. (doing "GetComponent" on loop, It's much worse I think)
    And btw adding the modified GameObjectEntity component to EntityManager still cause deallocated NativeArray as same as "disabling-enabling jutsu".

    If I add the GameObjectEntity to EntityManager using:
    GameObjectEntity.AddToEntityManager(EntityManager, GameObject);

    It adds new Entity on EntityManager everytime I modified the Component of GameObjectEntity, (yes I know because it's "AddToEntityManager", but I have to prove it by myself :D )

    And then I'm stuck,

    But Thank you btw for your help @eizenhorn , now I'm quite understand about ECS a little bit
     
  16. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    After a couple of some trial and error implementation, I have come with this :
    Code (CSharp):
    1.  
    2.  
    3.                 entityGO.enabled = false;
    4.                 entityGO.enabled = true;
    5.  
    6.                 // data = new Data(); //1. Reset the loop (I think)
    7.                 // break; //2. Break the loop
    8.                 // return; //3. Break out from the entire function
    9.  
    I just "reset" the Struct that used in ComponentSystem.
    Those three lines of code currently fix my problem, but I know it's only for now. (and yes I still using "disabling-enabling jutsu")
     
  17. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    It will in any case with EntityManager, because it's structural chages )
     
  18. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,408
    You can use UpdateInjectedComponentGroups(), but remember it's slow, but fine on small data amount.
     
    Bhakti_GL1 likes this.
  19. Bhakti_GL1

    Bhakti_GL1

    Joined:
    Jul 4, 2018
    Posts:
    17
    Thank you very much, maybe it's much better than break out from the loop ( I have no idea :D )