Search Unity

Bug DynamicBuffer broken in context of Entities.WithStructuralChanges

Discussion in 'Entity Component System' started by DreamingImLatios, May 30, 2020.

  1. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    This bug is biting me really hard today.

    When accessing a DynamicBuffer in an Entities.WithStructuralChanges.ForEach, I get the error:
    The NativeArray has been deallocated, it is not allowed to access it, when trying to access the DynamicBuffer.

    Here's a dirt-simple repro:
    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7.  
    8. [GenerateAuthoringComponent]
    9. public struct Spawner : IComponentData
    10. {
    11.     public Entity prefab;
    12. }
    13.  
    14. public struct FactionMember : ISharedComponentData
    15. {
    16.     public Entity entity;
    17. }
    18.  
    19. public class SpawnSystem : SystemBase
    20. {
    21.     protected override void OnUpdate()
    22.     {
    23.         Entities.WithStructuralChanges().ForEach((Entity entity, in Spawner spawner) =>
    24.         {
    25.             var factionMember = new FactionMember { entity = entity };
    26.             var firstInstance                              = EntityManager.Instantiate(spawner.prefab);
    27.             var linkedGroup                                = EntityManager.GetBuffer<LinkedEntityGroup>(firstInstance);
    28.             foreach (var e in linkedGroup)
    29.             {
    30.                 EntityManager.AddSharedComponentData(e.Value, factionMember);
    31.             }
    32.             if (!EntityManager.HasComponent<FactionMember>(firstInstance))
    33.                 EntityManager.AddSharedComponentData(firstInstance, factionMember);
    34.         }).Run();
    35.         EntityManager.RemoveComponent<Spawner>(EntityManager.UniversalQuery);
    36.     }
    37. }
    38.  
    39.  
    Uploading bug report as I create this thread.
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    As far as I'm aware this technically isn't a bug just how it's always worked. Pretty certain it's mentioned in the documentation somewhere.

    Any structural to entity manager will invalidate all dynamic buffers

    The only way around it is to copy your buffer to an array or use a local ECB and just play it back after the job instead of using structural changes
     
    lclemens likes this.
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    rafal_b likes this.
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Yup. I see that behavior now. The actual test case I had made it seem like the buffer was being invalidated before I was even making structural changes, but looking back that wasn't actually the case.

    Unfortunately an ECB doesn't work here because the use case is Instantiate, Add SharedComponent, and then Instantiate many. Copying to array seems like a good workaround though.
     
  5. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    Thanks for this info guys. You would think that in 1.0 specifying the read-only parameter to true in SystemAPI.GetSingletonBuffer<MyData>(true) would avoid this error, but nope - we still need to copy to array or use ECB.