Search Unity

How to make a list of Entities using DynamicBuffer?

Discussion in 'Entity Component System' started by davenirline, Feb 3, 2019.

  1. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    I want to keep an ordered set of Entities so ComponentDataFromEntity wouldn't do. I'd like to keep them in a DynamicBuffer instead. So I made an IBufferElementData wrapper that can hold an Entity:

    Code (CSharp):
    1.     [InternalBufferCapacity(100)]
    2.     public struct EntityBufferWrapper : IBufferElementData {
    3.         public Entity entity;
    4.  
    5.         public EntityBufferWrapper(Entity entity) {
    6.             this.entity = entity;
    7.         }
    8.     }
    However, when it's time to add elements to the buffer, it gives me this error:

    InvalidOperationException: The NativeArray has been deallocated, it is not allowed to access it
    Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x3d350a10 + 0x00052> in <d616be05755d41a089810b5c14e4dd50>:0
    Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at C:/buildslave/unity/build/Runtime/Export/AtomicSafetyHandle.bindings.cs:158)
    Unity.Entities.DynamicBuffer`1[T].CheckWriteAccess () (at Library/PackageCache/com.unity.entities@0.0.12-preview.23/Unity.Entities/Iterators/DynamicBuffer.cs:89)
    Unity.Entities.DynamicBuffer`1[T].Add (T elem) (at Library/PackageCache/com.unity.entities@0.0.12-preview.23/Unity.Entities/Iterators/DynamicBuffer.cs:157)


    The following is the test code:
    Code (CSharp):
    1. DynamicBuffer<EntityBufferWrapper> buffer = this.entityManager.AddBuffer<EntityBufferWrapper>(entity);
    2. buffer.Add(new EntityBufferWrapper(this.entityManager.CreateEntity()));
    Testing it with another IBufferElementData struct that doesn't have an Entity works, though. It's weird. What could be the problem?
     
    Tony_Max likes this.
  2. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    Yeah that's weird. Looks like a bug.
    I think the problem is actually the call to CreateEntity in the middle.
    Even with a non Entity buffer, it still crashes on mine.

    Code (CSharp):
    1. DynamicBuffer<EntityBufferWrapper> buffer = this.entityManager.AddBuffer<EntityBufferWrapper>(entity);
    2. Entity entity2 = Entity.Null;
    3. entity2 = this.entityManager.CreateEntity(); // <-- comment out this
    4. buffer.Add(new EntityBufferWrapper(entity2));
    AtomicSafetyHandle.CheckWriteAndThrow(m_Safety0); is the very first thing called in DynamicBuffer.Add() and it crashes immediately.

    - Edit -
    If you create the second Entity before you add the buffer, then there's no problem.
    Code (CSharp):
    1. Entity entity2 = this.entityManager.CreateEntity();
    2. DynamicBuffer<EntityBufferWrapper> buffer = this.entityManager.AddBuffer<EntityBufferWrapper>(entity);
    3. buffer.Add(new EntityBufferWrapper(entity2));
     
    Last edited: Feb 3, 2019
    davenirline likes this.
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Yep, create new entities, before add buffer, or add to buffer.
     
  4. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    I see. Thanks!
     
  5. LuisEGV

    LuisEGV

    Joined:
    Jul 21, 2015
    Posts:
    36
    Guys, did you find any solution/explanation/Bug reported for this problem? I'm having exactly the same issue. There are some Entity elements that I need to create after the buffer is added, so what you proposed will not work for me. I need to know if there's is already a bug report, so in case it hasn't been created I could do it
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    There isn't a bug.
    You need create entities before buffer is added. For example if you know that number of entiteis is same, as buffer size. Or mark entities as spare, which are not used / not added to buffer. Then do whatever you want with spares. I.e. remove.

    Or use ECB to create entities, so it does not invalidates buffer.
    If you want add new entities, to prior created buffer for example, you can create entities with ECB, then add some tag, saying it need be added to buffer of such and such entities. Then process adding entities to the buffer in separate job.
     
    LuisEGV likes this.
  7. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    What I did is I created the entities first and maintained them in a separate container. Only then the call to AddBuffer() would be safe.
     
    LuisEGV likes this.
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    LuisEGV likes this.
  9. LuisEGV

    LuisEGV

    Joined:
    Jul 21, 2015
    Posts:
    36
    Thanks, you're right. That's exactly what I was doing wrong.

    Guys, I'm doing this outside a system, in a MonoBehaviour. So, for this case it is recommended to use ECB as Antypodish suggest? or just take care of not invalidating my buffer reference before adding elements?
     
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    You don't have to use ECB, but ECB allows you do things, which otherwise are not possible, do to structural changes.
    Also, you can jobify and even burst things.

    How you approach it, is up to you.
     
  11. LuisEGV

    LuisEGV

    Joined:
    Jul 21, 2015
    Posts:
    36
    Ok, Thanks a lot. :)