Search Unity

[SOLVED] The NativeArray has been deallocated for an injected array

Discussion in 'Data Oriented Technology Stack' started by ItsOrcolom, Aug 4, 2018.

  1. ItsOrcolom

    ItsOrcolom

    Joined:
    Jun 28, 2013
    Posts:
    5
    So I have been getting the infamous 'InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it' error.

    I have been reading all the posts I could find to see how to fix it and for now none of the fixes has worked. I always use postUpdateCommands. I'm manually triggering everything to be sure it is not the same frame error of some kind.
    But still, it gives me the error

    Full error code
    Code (CSharp):
    1. InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it
    2. Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x387c4ad0 + 0x00052> in <4fb24868480b4477918a32a0ec6b2374>:0
    3. Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at C:/buildslave/unity/build/Runtime/Export/AtomicSafetyHandle.bindings.cs:143)
    4. Unity.Entities.EntityArray.get_Item (System.Int32 index) (at C:/Users/joram/AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.8/Unity.Entities/Iterators/EntityArray.cs:44)
    5. JointSystem.OnUpdate () (at Assets/Scrips/Orbs/Joints/JointSystem.cs:40)
    6. Unity.Entities.ComponentSystem.InternalUpdate () (at C:/Users/joram/AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.8/Unity.Entities/ComponentSystem.cs:294)
    7. Unity.Entities.ScriptBehaviourManager.Update () (at C:/Users/joram/AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.8/Unity.Entities/ScriptBehaviourManager.cs:82)
    8. Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelagateWrapper.TriggerUpdate () (at C:/Users/joram/AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.8/Unity.Entities/ScriptBehaviourUpdateOrder.cs:734)
    The execute order is in the image below
    Unity_2018-08-04_14-48-25.png

    My control system for now. This is where I trigger everything
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Jobs;
    3. using Unity.Entities;
    4. using UnityEngine;
    5. using Unity.Transforms;
    6. using Unity.Mathematics;
    7.  
    8. public class OrbSystem : ComponentSystem
    9. {
    10.     [Inject] JointSystem _jointSystem;
    11.  
    12.     Entity CreateNewOrb()
    13.     {
    14.         var go = GameObject.Instantiate(Bootstrapper.settings.OrbitPrefab, Bootstrapper.settings.transform.position, Quaternion.identity);
    15.         var e = go.GetComponent<GameObjectEntity>();
    16.         return e.Entity;
    17.     }
    18.  
    19.     protected override void OnUpdate ()
    20.     {
    21.         // init world
    22.         if (Input.GetKeyDown(KeyCode.F1))
    23.         {
    24.             var orb1 = CreateNewOrb();
    25.             var orbit1 = EntityManager.GetComponentData<Orbit>(orb1);
    26.             orbit1.Ellipse = new float2(1, 1);
    27.             PostUpdateCommands.SetComponent(orb1, orbit1);
    28.  
    29.             var orb2 = CreateNewOrb();
    30.             var orbit2 = EntityManager.GetComponentData<Orbit>(orb2);
    31.             orbit2.Ellipse = new float2(1.5f, 1.5f);
    32.             PostUpdateCommands.SetComponent(orb2, orbit2);
    33.  
    34.             var orb3 = CreateNewOrb();
    35.             var orbit3 = EntityManager.GetComponentData<Orbit>(orb3);
    36.             orbit3.Ellipse = new float2(2, 2);
    37.             PostUpdateCommands.SetComponent(orb3, orbit3);
    38.         }
    39.  
    40.         if (Input.GetKeyDown(KeyCode.F12))
    41.         {
    42.             _jointSystem.EnableJoints();
    43.         }
    44.     }
    45. }
    46.  
    Here it modifies the position and rotation every update
    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Jobs;
    3. using Unity.Transforms;
    4. using Unity.Mathematics;
    5. using UnityEngine;
    6. using Unity.Collections;
    7. using UnityEngine.Jobs;
    8.  
    9. public class OrbitSystem : ComponentSystem
    10. {
    11.     // struct
    12.     struct OrbitData
    13.     {
    14.         public readonly int Length;
    15.         public ComponentDataArray<Orbit> Orbits;
    16.         public ComponentDataArray<Position> Positions;
    17.         public ComponentDataArray<Rotation> Rotations;
    18.         public EntityArray Entities;
    19.     }
    20.  
    21.     // Data
    22.     [Inject] OrbitData _orbitData;
    23.  
    24.     protected override void OnUpdate()
    25.     {
    26.         var dt = Time.deltaTime;
    27.         for (int i = 0; i < _orbitData.Length; i++)
    28.         {
    29.             var orbit = _orbitData.Orbits[i];
    30.             var entity = _orbitData.Entities[i];
    31.  
    32.             if (orbit.Time == 0)
    33.                 continue;
    34.            
    35.             orbit.ElapsedTime += dt;
    36.  
    37.             var time = math.degrees((orbit.ElapsedTime + orbit.OffsetTime) / orbit.Time);
    38.             var pos = new float3(orbit.Ellipse.x * math.sin(time), 0 , orbit.Ellipse.y * math.cos(time));
    39.             pos = Matrix4x4.Rotate(Quaternion.Euler(orbit.ParentRotation + orbit.OffsetRotation)).MultiplyPoint(pos);
    40.            
    41.             var center = orbit.OffsetPosition + orbit.ParentPosition;
    42.             pos = center + pos;
    43.  
    44.             PostUpdateCommands.SetComponent(entity, orbit);
    45.             PostUpdateCommands.SetComponent(entity, new Position(pos));
    46.             PostUpdateCommands.SetComponent(entity, new Rotation(Matrix4x4.LookAt(pos, center, Vector3.up).rotation));
    47.         }
    48.     }
    49. }
    50.  
    Here I have joints that will link to the orbits
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Jobs;
    3. using Unity.Entities;
    4. using UnityEngine;
    5. using Unity.Transforms;
    6.  
    7. [UpdateBefore(typeof(OrbitSystem))]
    8. public class JointSystem : ComponentSystem
    9. {
    10.     // struct
    11.     struct OrbitData
    12.     {
    13.         public readonly int Length;
    14.         public ComponentDataArray<Orbit> Orbits;
    15.         [ReadOnly] public EntityArray Entities;
    16.     }
    17.  
    18.     bool triggerEnable;
    19.  
    20.     // job
    21.     // data
    22.     [Inject] OrbitData _orbitData;
    23.  
    24.     public bool JointsEnabled { get; private set; }
    25.     public void EnableJoints()
    26.     {
    27.         if (JointsEnabled)
    28.             return;
    29.         triggerEnable = true;  
    30.     }
    31.  
    32.     protected override void OnUpdate ()
    33.     {
    34.         if (triggerEnable)
    35.         {
    36.             triggerEnable = false;
    37.             for (int i = 0; i < _orbitData.Length; i++)
    38.             {
    39.                 Debug.Log(i); // returns 0 and 1, after that I get the error message on the line below
    40.                 var orbEntity = _orbitData.Entities[i];
    41.  
    42.                 var jointGO = GameObject.Instantiate(Bootstrapper.settings.JointPrefab);
    43.                 var jointEntity = jointGO.GetComponent<GameObjectEntity>().Entity;
    44.                 PostUpdateCommands.SetComponent(jointEntity, new Joint{Target = orbEntity});
    45.             }
    46.         }
    47.     }
    48. }
    49.  
     
  2. dstilwagen

    dstilwagen

    Joined:
    Mar 14, 2018
    Posts:
    36
    The only thing I see that might be a problem is creating a GameObject with GameObjectEntity will cause all injected arrays to become invalidated. I would try calling UpdateInjectedComponentGroups() after GameObject instantiate but before you use any data that was injected.

    I'm not at my computer so the function name might be a little different. It's also worth noting that updating injected groups can be costly.
     
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,650
    I think dstilwagen is spot on, but I'd solve it differently.

    Code (CSharp):
    1. var jointGO = GameObject.Instantiate(Bootstrapper.settings.JointPrefab);
    Causes the _orbitData array to be invalid as you're creating an entity.

    Instead of iterating _orbitData, copy _orbitData entities to an array and iterate that

    Code (CSharp):
    1. var entities = new NativeArray<Entity>(_orbitData.Length, Allocator.TempJob);
    2. var slice = new NativeSlice<Entity>(entities); // for whatever reason, EntityArray can only copy to Slices atm
    3. _orbitData.Entities.CopyTo(slice);
    4.  
    5. for (var index = 0; index < entities.Length; index++)
    6. {
    7.     var orbEntity = entities[index];
    8.     // Instantiate
    9. }
    10.  
    11. entities.Dispose();
     
  4. ItsOrcolom

    ItsOrcolom

    Joined:
    Jun 28, 2013
    Posts:
    5
    Ok so @tertle solution worked.
    I also tried @dstilwagen option but didn't seem to work in my case.

    I'm trying to understand the problem, but because I'm instantiating via gameobjects my _orbitData is invalid but I can copy the data over and use that?

    Also, does this mean that I can't use injected data? (as I can't 'fix' it with the updateInjectedArrays)

    And does this only happen because I'm using gameobjects or would this also happen with normal entities?

    Thanks for the help!
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,650
    Anytime you create, modify or destroy an entity, all component arrays are invalidated.

    Normally you use PostUpdateCommands (EntityCommandBuffers) to create entities after the system runs when you're not using one of these component arrays. But as you're using GameObjectEntity, which creates the entity on Start, as soon as you instantiate it within the loop all your component arrays become invalid therefore the next iteration of the loop is invalid.
     
    5argon likes this.