Search Unity

Where is my mistake in this chunk iteration?

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

  1. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    I am trying to do a simple reactive system but using chunk iteration and am stuck with `InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it`

    I've gone over several recent similar looking posts and the documentation but can't spot where this is going wrong, especially as the behaviour seems different on subsequent recompiles. I could put this into a job but thought sketching it out in update should be simple enough. Any ideas?

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Collections;
    4.  
    5. public class VisualizationSystem : ComponentSystem
    6. {
    7.     class Barrier : BarrierSystem { }
    8.     [Inject] Barrier barrier;
    9.  
    10.     ComponentGroup addedTimeStamps;
    11.     ComponentGroup removedTimeStamps;
    12.  
    13.     protected override void OnCreateManager()
    14.     {
    15.         base.OnCreateManager();
    16.  
    17.         addedTimeStamps = GetComponentGroup(typeof(TimeStamps), ComponentType.Subtractive(typeof(Initialized)));
    18.         removedTimeStamps = GetComponentGroup(typeof(TimeStamps), typeof(Initialized));
    19.     }
    20.  
    21.     struct Initialized : ISystemStateComponentData { }
    22.  
    23.     protected override void OnUpdate()
    24.     {
    25.         var acet = GetArchetypeChunkEntityType();
    26.         var acct = GetArchetypeChunkComponentType<TimeStamps>();
    27.  
    28.         var commandBuffer = barrier.CreateCommandBuffer();
    29.  
    30.         var chunks = addedTimeStamps.CreateArchetypeChunkArray(Allocator.Temp);
    31.         for (var i = 0; i < chunks.Length; i++)
    32.         {
    33.             var chunk = chunks[i];
    34.             var entities = chunk.GetNativeArray(acet);
    35.             var timeStamps = chunk.GetNativeArray(acct);
    36.             for(var j = 0; j < chunk.Count; j++)
    37.             {
    38.                 var go = UnityEngine.GameObject.Instantiate(AppManager.TransactionPrefab);
    39.                 go.transform.position = new UnityEngine.Vector3(timeStamps[j].TimeStamp, 0, 0);
    40.                 commandBuffer.AddComponent(entities[j], new Initialized());
    41.             }
    42.         }
    43.         commandBuffer.Playback(EntityManager);
    44.         chunks.Dispose();
    45.  
    46.         for (var i = 0; i < removedTimeStamps.GetEntityArray().Length; i++)
    47.         {
    48.  
    49.         }
    50.     }
    51. }
    52.  
     
    Last edited: Dec 10, 2018
  2. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    I would have said that it's because you pass a nativearray to the commandbuffer and you dispose it right after that (and the commandbuffer playbacks later trying to use that nativearray).

    But you are forcing playback right after feeding the commandbuffer, which is kinda strange to me. Why would you do that ?
     
  3. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    i'm forcing playback because i figured the same thing, "it's because you pass a nativearray to teh commandbuffer and you dispose it right after that (and the commandbuffer playbacks later)" - i also saw some other similar examples doing the same thing.
     
  4. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    ok I would get rid of the forced playback and chunks.Dispose() and try:

    if(chunks.isCreated)
    {
    chunks.Dispose();
    }
    var chunks = addedThingies.CreateArchetypeChunkArray(Allocator.Temp);

    Make sure to dispose the nativearray when shutting down your system as it won't happen automactically this way
     
  5. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    I assumed we don't want to modify the chunk as we iterate over it (ie, adding a component to an entity) - I seem to still misunderstand some basics with how these systems work.
     
  6. meanmonkey

    meanmonkey

    Joined:
    Nov 13, 2014
    Posts:
    148
    I deleted my last post because I was just wrong.... There are indeed cases where you want to playback right after queueing.
     
    timmehhhhhhh likes this.
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    @tbriley
    1. If you playback ECB immediatley, you don't need to use barriers, you can just create ECB directly
    Code (CSharp):
    1. var commandBuffer = barrier.CreateCommandBuffer();
    2. //must be in your case
    3. var commandBuffer = new EntityCommandBuffer(Allocator.Temp);
    2. Show please this prefab -
    AppManager.TransactionPrefab


    @meanmonkey ohh you removed your message before I pointed you that you wrong about immediatley playback :)
     
    meanmonkey likes this.
  8. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    I am guessing your GO that is being instantiated contains GameObjectEntity? OnEnable of that will use EntityManager and invalidate all your currently requested ECS database references. (had been there)
     
    timmehhhhhhh and eizenhorn like this.
  9. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    Oh @5argon why are you doing this :p I wants than he personally find problem after looking to his prefab, this is why I'm asked him about prefab :) Then he learn and understand that :)
     
    timmehhhhhhh likes this.
  10. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    Tony_Max and meanmonkey like this.
  11. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    @5argon @eizenhorn what's the advice for instantiating "view" entities then? ideally i am using MeshInstanceRenderer component and this system or another reactive system put in charge or keeping the view updating with component data changes (ie, repositioning based on timestamp changes). do i just cache the data i need in some arrays and instantiate later (still in OnUpdate())?
     
  12. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    In my lib I am using what's similar to EntityCommandBuffer, but it is called an ActionCommandBuffer. This just simply queue up lambda functions to be played back later at the end of OnUpdate. Those actions are like SetActive on the GOE, using setter of Value property of GOE, or instantiating GOE GO. They all invalidate. (ps. send to me?)


    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using Unity.Entities;
    5. using UnityEngine;
    6.  
    7. namespace E7.Izumi
    8. {
    9.     public class ActionCommandBuffer
    10.     {
    11.         List<Action> postUpdateActions = new List<Action>();
    12.         public int Count => postUpdateActions.Count;
    13.  
    14.         internal void Playback()
    15.         {
    16.             foreach(Action a in postUpdateActions) a();
    17.  
    18.             //TODO : All the cascade changes should be jobified and apply in parallel?
    19.         }
    20.  
    21.         internal void Clear() => postUpdateActions.Clear();
    22.  
    23.         /// <summary>
    24.         /// Add any `Action` to play back after the iteration.
    25.         /// </summary>
    26.         public void AddPostUpdateAction(Action lambda) => postUpdateActions.Add(lambda);
    27.  
    28.         /// <summary>
    29.         /// Delay `SetActive` to execute after all iterations.
    30.         /// </summary>
    31.         //TODO : Not relying on invoke but storing just the game object and bool
    32.         public void SetActive(GameObject go, bool active) => postUpdateActions.Add(() => go.SetActive(active));
    33.  
    34.         /// <summary>
    35.         /// Delay `StateStore` assignment after all iterations.
    36.         /// </summary>
    37.         //TODO : Not relying on invoke but perform some ECS magic to make it equivalent to `.Value` property. Probably can use jobs?
    38.         //Note that ECS does not sync back automatically to serialized wrapper data, just the other way around.
    39.         //The assignment here get version number equals to the current global, it is just increased before the system's update so I think it is fine.
    40.         public void CascadeChange<STATE>(ComponentDataWrapper<STATE> wrapper, STATE data)
    41.         where STATE : struct, IState
    42.         => AddPostUpdateAction(() => wrapper.Value = data);
    43.     }
    44. }
     
  13. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    If it's just view, why you use GO and not Pure approach?
     
  14. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    i likely will eventually, it's just prefabs still sometimes feel more straightforward (idea of scene or gameobject as configuration, and we don't have nice ecs editor tools yet)
     
  15. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,684
    This way you create your own problems ;)
     
    timmehhhhhhh likes this.