Search Unity

ECS preview 10 - GetFixedArray

Discussion in 'Entity Component System' started by Spy-Shifty, Aug 17, 2018.

  1. Spy-Shifty

    Spy-Shifty

    Joined:
    May 5, 2011
    Posts:
    546
    Hi,

    I've just updated to preview 10 and now I'm missing the EntityManager.GetFixedArray<?>(entity) method.

    Was the EntityManager.GetFixedArray<?>(entity) replaced by EntityManager.GetBuffer<?>(entity)?

    How to use this new Buffer? Can do I need to wrap my native type in a IBufferElementData?
     
    Deleted User likes this.
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    According to
    For now, I stay away from 10, since I have unfinished current part of code. Hence, I don't know the answer to last question.
     
  3. dthurn

    dthurn

    Joined:
    Feb 17, 2015
    Posts:
    77
    how are you folks getting these updates? 0.8 still shows up as the latest one for me in package manager...
     
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
  5. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    include stagging packages in to manifest and you can see that
     
  6. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    I ve been able to update my project to preview 10.
    Yes, buffers replace fixedarray, and your type needs to implement IBufferElementData (just a marker interface)
    here are a few pointers from my code :
    Code (CSharp):
    1.  
    2.     [InternalBufferCapacity(16* 16)]
    3.     public struct HeightmapData : IBufferElementData
    4.     {
    5.         public half height;
    6.     }
    7.  
    Code (CSharp):
    1.  
    2.  _nodeArchetype = EntityManager.CreateArchetype(typeof(Node), ComponentType.Create<HeightmapData>(), typeof(LocalToWorld), typeof(MeshCullingComponent));
    3.  
    btw in this new version, localtoworld replaces transformatrix , see the meshcullingsystem sources

    Code (CSharp):
    1.  
    2.  
    3.  Entity entity = EntityManager.CreateEntity(_nodeArchetype);
    4. DynamicBuffer<HeightmapData> heights = EntityManager.GetBuffer<HeightmapData>(entity);
    5.   HeightmapData[] tmp = new HeightmapData[heightsBuf.Capacity]; // so it's not dynamic in my case, but it could be
    6.  
    then write into tmp and in the end do :

    Code (CSharp):
    1.  
    2. heightsBuf.CopyFrom(tmp);
    3.  
    in another system you can inject the buffer array , it replaces the old ill named "fixedArrayArray" :)

    Code (CSharp):
    1.  
    2.   public struct Group
    3.     {      
    4.         [ReadOnly]
    5.         public BufferArray<HeightmapData> Heights;
    6.  
    Cheers !
     
    andywatts, Seb-1814, Fido789 and 4 others like this.
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Well done. Thx for sharing.
     
  8. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    Oh and BufferTest.cs was very useful to understand the new API, here's the whole class for your convenience
    Code (CSharp):
    1. using NUnit.Framework;
    2. using Unity.Collections;
    3. using System;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using UnityEditor.Experimental.UIElements;
    7.  
    8. namespace Unity.Entities.Tests
    9. {
    10.     public class BufferTests : ECSTestsFixture
    11.     {
    12.         [InternalBufferCapacity(1024*1024)]
    13.         public struct OverSizedCapacity : IBufferElementData
    14.         {
    15.             public int Value;
    16.         }
    17.  
    18.         [Test]
    19.         public void BufferTypeClassificationWorks()
    20.         {
    21.             var t  = TypeManager.GetComponentType<EcsIntElement>();
    22.             Assert.AreEqual(TypeManager.TypeCategory.BufferData, t.Category);
    23.             Assert.AreEqual(8, t.BufferCapacity);
    24.         }
    25.  
    26.         [Test]
    27.         public void BufferComponentTypeCreationWorks()
    28.         {
    29.             var bt = ComponentType.Create<EcsIntElement>();
    30.             Assert.AreEqual(ComponentType.AccessMode.ReadWrite, bt.AccessModeType);
    31.             Assert.AreEqual(8, bt.BufferCapacity);
    32.         }
    33.      
    34.         [Test]
    35.         public void CreateEntityWithIntThrows()
    36.         {
    37.             Assert.Throws<System.ArgumentException>(() => { m_Manager.CreateEntity(typeof(int));});
    38.         }
    39.  
    40.         [Test]
    41.         public void AddComponentWithIntThrows()
    42.         {
    43.             var entity = m_Manager.CreateEntity();
    44.             Assert.Throws<System.ArgumentException>(() => { m_Manager.AddComponent(entity, ComponentType.Create<int>()); });
    45.         }
    46.      
    47.         [Test]
    48.         // Invalid because chunk size is too small to hold a single entity
    49.         public void CreateEntityWithInvalidInternalCapacity()
    50.         {
    51.             var arrayType = ComponentType.Create<OverSizedCapacity>();
    52.             Assert.Throws<ArgumentException>(() => m_Manager.CreateEntity(arrayType));
    53.         }
    54.      
    55.         [Test]
    56.         public void HasComponent()
    57.         {
    58.             var arrayType = ComponentType.Create<EcsIntElement>();
    59.             var entity = m_Manager.CreateEntity(arrayType);
    60.             Assert.IsTrue(m_Manager.HasComponent(entity, arrayType));
    61.         }
    62.  
    63.         [Test]
    64.         public void InitialCapacityWorks()
    65.         {
    66.             var arrayType = ComponentType.Create<EcsIntElement>();
    67.             var entity = m_Manager.CreateEntity(arrayType);
    68.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    69.             Assert.AreEqual(8, buffer.Capacity);
    70.         }
    71.  
    72.         [Test]
    73.         public void InitialCapacityWorks2()
    74.         {
    75.             var entity = m_Manager.CreateEntity(typeof(EcsIntElement));
    76.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    77.             Assert.AreEqual(8, buffer.Capacity);
    78.         }
    79.  
    80.         [Test]
    81.         public void AddWorks()
    82.         {
    83.             var arrayType = ComponentType.Create<EcsIntElement>();
    84.             var entity = m_Manager.CreateEntity(arrayType);
    85.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    86.             for (int i = 0; i < 189; ++i)
    87.                 buffer.Add(i);
    88.  
    89.             Assert.AreEqual(189, buffer.Length);
    90.             for (int i = 0; i < 189; ++i)
    91.             {
    92.                 Assert.AreEqual(i, buffer[i].Value);
    93.             }
    94.         }
    95.  
    96.         [Test]
    97.         public void AddRangeWorks()
    98.         {
    99.             var arrayType = ComponentType.Create<EcsIntElement>();
    100.             var entity = m_Manager.CreateEntity(arrayType);
    101.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    102.             for (int i = 0; i < 7; ++i)
    103.                 buffer.Add(i);
    104.  
    105.             Assert.AreEqual(7, buffer.Length);
    106.  
    107.             var blah = new NativeArray<EcsIntElement>(1024, Allocator.Temp);
    108.  
    109.             for (int i = 0; i < blah.Length; ++i)
    110.             {
    111.                 blah[i] = i;
    112.             }
    113.  
    114.             buffer.AddRange(blah);
    115.             blah.Dispose();
    116.  
    117.             Assert.AreEqual(1024 + 7, buffer.Length);
    118.  
    119.             for (int i = 0; i < 7; ++i)
    120.                 Assert.AreEqual(i, buffer[i].Value);
    121.             for (int i = 0; i < 1024; ++i)
    122.                 Assert.AreEqual(i, buffer[7 + i].Value);
    123.         }
    124.  
    125.         [Test]
    126.         public void RemoveAtWorks()
    127.         {
    128.             var entity = m_Manager.CreateEntity(typeof(EcsIntElement));
    129.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    130.             for (int i = 0; i < 9; ++i)
    131.                 buffer.Add(i);
    132.  
    133.             buffer.RemoveAt(7);
    134.  
    135.             CheckBufferContents(buffer, new int[] { 0, 1, 2, 3, 4, 5, 6, 8 });
    136.         }
    137.  
    138.         private static void CheckBufferContents(DynamicBuffer<EcsIntElement> buffer, int[] refs)
    139.         {
    140.             Assert.AreEqual(refs.Length, buffer.Length);
    141.  
    142.             for (int i = 0; i < refs.Length; ++i)
    143.             {
    144.                 Assert.AreEqual(refs[i], buffer[i].Value);
    145.             }
    146.         }
    147.  
    148.         [Test]
    149.         public void RemoveAtWorksFromStart()
    150.         {
    151.             var entity = m_Manager.CreateEntity(typeof(EcsIntElement));
    152.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    153.             for (int i = 0; i < 9; ++i)
    154.                 buffer.Add(i);
    155.  
    156.             buffer.RemoveAt(0);
    157.  
    158.             CheckBufferContents(buffer, new int[] { 1, 2, 3, 4, 5, 6, 7, 8 });
    159.         }
    160.  
    161.         [Test]
    162.         public void RemoveAtWorksFromEnd()
    163.         {
    164.             var entity = m_Manager.CreateEntity(typeof(EcsIntElement));
    165.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    166.             for (int i = 0; i < 9; ++i)
    167.                 buffer.Add(i);
    168.  
    169.             buffer.RemoveAt(8);
    170.             buffer.RemoveAt(7);
    171.  
    172.             CheckBufferContents(buffer, new int[] { 0, 1, 2, 3, 4, 5, 6 });
    173.         }
    174.  
    175.         [Test]
    176.         public void RemoveRangeWorksFromEnd()
    177.         {
    178.             var entity = m_Manager.CreateEntity(typeof(EcsIntElement));
    179.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    180.             for (int i = 0; i < 9; ++i)
    181.                 buffer.Add(i);
    182.  
    183.             buffer.RemoveRange(5, 4);
    184.  
    185.             CheckBufferContents(buffer, new int[] { 0, 1, 2, 3, 4 });
    186.         }
    187.  
    188.         [Test]
    189.         public void InitialCapacityWorksWithAddComponment()
    190.         {
    191.             var entity = m_Manager.CreateEntity();
    192.             m_Manager.AddComponent(entity, ComponentType.Create<EcsIntElement>());
    193.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entity);
    194.             Assert.AreEqual(8, buffer.Capacity);
    195.         }
    196.      
    197.         [Test]
    198.         public void RemoveComponent()
    199.         {
    200.             var arrayType = ComponentType.Create<EcsIntElement>();
    201.             var entity = m_Manager.CreateEntity(arrayType);
    202.             Assert.IsTrue(m_Manager.HasComponent(entity, arrayType));
    203.             m_Manager.RemoveComponent(entity, arrayType);
    204.             Assert.IsFalse(m_Manager.HasComponent(entity, arrayType));
    205.         }
    206.      
    207.         [Test]
    208.         public void MutateBufferData()
    209.         {
    210.             var entity = m_Manager.CreateEntity();
    211.             m_Manager.AddBuffer<EcsIntElement>(entity);
    212.  
    213.             var array = m_Manager.GetBuffer<EcsIntElement>(entity);
    214.             Assert.AreEqual(0, array.Length);
    215.  
    216.             using (var array2 = new NativeArray<EcsIntElement>(6, Allocator.Temp))
    217.             {
    218.                 array.CopyFrom(array2);
    219.  
    220.                 Assert.AreEqual(6, array.Length);
    221.  
    222.                 array[3] = 5;
    223.                 Assert.AreEqual(5, array[3].Value);
    224.                 Assert.AreNotEqual(5, array2[3].Value); // no aliasing
    225.             }
    226.         }
    227.  
    228.         [Test]
    229.         public void BufferComponentGroupIteration()
    230.         {
    231.             /*var entity64 =*/
    232.             m_Manager.CreateEntity(typeof(EcsIntElement));
    233.             /*var entity10 =*/
    234.             m_Manager.CreateEntity(typeof(EcsIntElement));
    235.  
    236.             var group = m_Manager.CreateComponentGroup(typeof(EcsIntElement));
    237.  
    238.             var buffers = group.GetBufferArray<EcsIntElement>();
    239.  
    240.             Assert.AreEqual(2, buffers.Length);
    241.             Assert.AreEqual(0, buffers[0].Length);
    242.             Assert.AreEqual(8, buffers[0].Capacity);
    243.             Assert.AreEqual(0, buffers[1].Length);
    244.             Assert.AreEqual(8, buffers[1].Capacity);
    245.  
    246.             buffers[0].Add(12);
    247.             buffers[0].Add(13);
    248.  
    249.             Assert.AreEqual(2, buffers[0].Length);
    250.             Assert.AreEqual(12, buffers[0][0].Value);
    251.             Assert.AreEqual(13, buffers[0][1].Value);
    252.  
    253.             Assert.AreEqual(0, buffers[1].Length);
    254.         }
    255.  
    256.         [Test]
    257.         public void BufferFromEntityWorks()
    258.         {
    259.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    260.             m_Manager.GetBuffer<EcsIntElement>(entityInt).CopyFrom(new EcsIntElement[] { 1, 2, 3 });
    261.                      
    262.             var intLookup = EmptySystem.GetBufferArrayFromEntity<EcsIntElement>();
    263.             Assert.IsTrue(intLookup.Exists(entityInt));
    264.             Assert.IsFalse(intLookup.Exists(new Entity()));
    265.          
    266.             Assert.AreEqual(2, intLookup[entityInt][1].Value);
    267.         }
    268.  
    269.         [Test]
    270.         public void OutOfBoundsAccessThrows()
    271.         {
    272.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    273.             var intArray = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    274.             intArray.Add(12);
    275.             m_Manager.DestroyEntity(entityInt);
    276.  
    277.             Assert.Throws<InvalidOperationException>(() =>
    278.             {
    279.                 intArray.Add(123);
    280.             });
    281.         }
    282.  
    283.         [Test]
    284.         public void UseAfterStructuralChangeThrows()
    285.         {
    286.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    287.             var intArray = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    288.             m_Manager.DestroyEntity(entityInt);
    289.  
    290.             Assert.Throws<InvalidOperationException>(() =>
    291.             {
    292.                 intArray.Add(123);
    293.             });
    294.         }
    295.  
    296.         [Test]
    297.         public void UseAfterStructuralChangeThrows2()
    298.         {
    299.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    300.             var buffer = m_Manager.GetBufferDataFromEntity<EcsIntElement>();
    301.             var array = buffer[entityInt];
    302.             m_Manager.DestroyEntity(entityInt);
    303.  
    304.             Assert.Throws<InvalidOperationException>(() =>
    305.             {
    306.                 array.Add(123);
    307.             });
    308.         }
    309.  
    310.         [Test]
    311.         public void UseAfterStructuralChangeThrows3()
    312.         {
    313.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    314.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    315.             buffer.CopyFrom(new EcsIntElement[] { 1, 2, 3 });
    316.             m_Manager.AddComponentData(entityInt, new EcsTestData() { value = 20 });
    317.             Assert.Throws<InvalidOperationException>(() => { buffer.Add(4); });
    318.         }
    319.  
    320.  
    321.         [Test]
    322.         public void WritingReadOnlyThrows()
    323.         {
    324.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    325.             var buffer = m_Manager.GetBufferDataFromEntity<EcsIntElement>(true);
    326.             var array = buffer[entityInt];
    327.             Assert.Throws<InvalidOperationException>(() =>
    328.             {
    329.                 array.Add(123);
    330.             });
    331.         }
    332.  
    333.         [Test]
    334.         public void ReinterpretWorks()
    335.         {
    336.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    337.             var intBuffer = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    338.             var floatBuffer = intBuffer.Reinterpret<float>();
    339.  
    340.             intBuffer.Add(0x3f800000);
    341.             floatBuffer.Add(-1.0f);
    342.  
    343.             Assert.AreEqual(2, intBuffer.Length);
    344.             Assert.AreEqual(2, floatBuffer.Length);
    345.  
    346.             Assert.AreEqual(0x3f800000, intBuffer[0].Value);
    347.             Assert.AreEqual(1.0f, floatBuffer[0]);
    348.             Assert.AreEqual(0xbf800000u, (uint)intBuffer[1].Value);
    349.             Assert.AreEqual(-1.0f, floatBuffer[1]);
    350.         }
    351.  
    352.         [Test]
    353.         public void ReinterpretWrongSizeThrows()
    354.         {
    355.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    356.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    357.             Assert.Throws<InvalidOperationException>(() =>
    358.             {
    359.                 buffer.Reinterpret<ushort>();
    360.             });
    361.         }
    362.  
    363.         [DisableAutoCreation]
    364.         public class InjectionTestSystem : JobComponentSystem
    365.         {
    366.             public struct Data
    367.             {
    368.                 public readonly int Length;
    369.                 public BufferArray<EcsIntElement> Buffers;
    370.             }
    371.  
    372.             [Inject] Data m_Data;
    373.  
    374.             public struct MyJob : IJobParallelFor
    375.             {
    376.                 public BufferArray<EcsIntElement> Buffers;
    377.  
    378.                 public void Execute(int i)
    379.                 {
    380.                     Buffers[i].Add(i * 3);
    381.                 }
    382.             }
    383.  
    384.             protected override JobHandle OnUpdate(JobHandle inputDeps)
    385.             {
    386.                 new MyJob { Buffers = m_Data.Buffers }.Schedule(m_Data.Length, 32, inputDeps).Complete();
    387.                 return default(JobHandle);
    388.             }
    389.         }
    390.  
    391.         [Test]
    392.         public void Injection()
    393.         {
    394.             var system = World.Active.GetOrCreateManager<InjectionTestSystem>();
    395.  
    396.             using (var entities = new NativeArray<Entity>(320, Allocator.Temp))
    397.             {
    398.                 var arch = m_Manager.CreateArchetype(typeof(EcsIntElement));
    399.                 m_Manager.CreateEntity(arch, entities);
    400.  
    401.                 system.Update();
    402.                 system.Update();
    403.  
    404.                 for (var i = 0; i < entities.Length; ++i)
    405.                 {
    406.                     var buf = m_Manager.GetBuffer<EcsIntElement>(entities[i]);
    407.                     Assert.AreEqual(2, buf.Length);
    408.                 }
    409.             }
    410.         }
    411.  
    412.         [Test]
    413.         public void TrimExcessWorks()
    414.         {
    415.  
    416.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    417.             var intBuffer = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    418.  
    419.             Assert.AreEqual(0, intBuffer.Length);
    420.             Assert.AreEqual(8, intBuffer.Capacity);
    421.  
    422.             intBuffer.CopyFrom(new EcsIntElement[] { 0, 1, 2, 3 });
    423.  
    424.             intBuffer.TrimExcess();
    425.  
    426.             Assert.AreEqual(4, intBuffer.Length);
    427.             Assert.AreEqual(8, intBuffer.Capacity);
    428.  
    429.             for (int i = 4; i < 10; ++i)
    430.             {
    431.                 intBuffer.Add(i);
    432.             }
    433.  
    434.             Assert.AreEqual(10, intBuffer.Length);
    435.             Assert.AreEqual(16, intBuffer.Capacity);
    436.  
    437.             intBuffer.TrimExcess();
    438.  
    439.             Assert.AreEqual(10, intBuffer.Length);
    440.             Assert.AreEqual(10, intBuffer.Capacity);
    441.  
    442.             for (int i = 0; i < 10; ++i)
    443.             {
    444.                 Assert.AreEqual(i, intBuffer[i].Value);
    445.             }
    446.         }
    447.  
    448.         [Test]
    449.         public void BufferSurvivesArchetypeChange()
    450.         {
    451.             var entityInt = m_Manager.CreateEntity(typeof(EcsIntElement));
    452.             var buffer = m_Manager.GetBuffer<EcsIntElement>(entityInt);
    453.             buffer.CopyFrom(new EcsIntElement[] { 1, 2, 3 });
    454.  
    455.             m_Manager.AddComponentData(entityInt, new EcsTestData() { value = 20 });
    456.  
    457.             CheckBufferContents(m_Manager.GetBuffer<EcsIntElement>(entityInt), new int[] { 1, 2, 3 });
    458.         }
    459.  
    460.         [Test]
    461.         public unsafe void InstantiateCreatesCopyOverflow()
    462.         {
    463.             var original = m_Manager.CreateEntity(typeof(EcsIntElement));
    464.             var buffer = m_Manager.GetBuffer<EcsIntElement>(original);
    465.             buffer.CopyFrom(new EcsIntElement[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); // greater than 8
    466.  
    467.             var clone = m_Manager.Instantiate(original);
    468.  
    469.             buffer = m_Manager.GetBuffer<EcsIntElement>(original);
    470.             var buffer2 = m_Manager.GetBuffer<EcsIntElement>(clone);
    471.  
    472.             Assert.AreNotEqual((UIntPtr)buffer.GetBasePointer(), (UIntPtr)buffer2.GetBasePointer());
    473.             Assert.AreEqual(buffer.Length, buffer2.Length);
    474.             for (int i = 0; i < buffer.Length; ++i)
    475.             {
    476.                 Assert.AreEqual(buffer[i].Value, buffer2[i].Value);
    477.             }
    478.         }
    479.  
    480.         [Test]
    481.         public unsafe void InstantiateCreatesCopyInternal()
    482.         {
    483.             var original = m_Manager.CreateEntity(typeof(EcsIntElement));
    484.             var buffer = m_Manager.GetBuffer<EcsIntElement>(original);
    485.             buffer.CopyFrom(new EcsIntElement[] { 1, 2, 3 }); // smaller than 8
    486.  
    487.             var clone = m_Manager.Instantiate(original);
    488.  
    489.             buffer = m_Manager.GetBuffer<EcsIntElement>(original);
    490.             var buffer2 = m_Manager.GetBuffer<EcsIntElement>(clone);
    491.  
    492.             Assert.AreNotEqual((UIntPtr)buffer.GetBasePointer(), (UIntPtr)buffer2.GetBasePointer());
    493.             Assert.AreEqual(buffer.Length, buffer2.Length);
    494.             for (int i = 0; i < buffer.Length; ++i)
    495.             {
    496.                 Assert.AreEqual(buffer[i].Value, buffer2[i].Value);
    497.             }
    498.         }
    499.  
    500.         internal struct ElementWithoutCapacity : IBufferElementData
    501.         {
    502.             public float Value;
    503.         }
    504.  
    505.         [Test]
    506.         public void NoCapacitySpecifiedWorks()
    507.         {
    508.             var original = m_Manager.CreateEntity(typeof(ElementWithoutCapacity));
    509.             var buffer = m_Manager.GetBuffer<ElementWithoutCapacity>(original);
    510.             Assert.AreEqual(buffer.Capacity, 32);
    511.         }
    512.     }
    513. }
    514.  
     
  9. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Actually is not fully correct. LocalToWorld is not replacement, it is rather an upgrade, it comes with new hierarchy logic in ECS (Attach\Attached components), TransforMatrix deprecated, and for basic things now not needed (also as LocalToWorld), if before for correct rendering with MeshInstanceRenderer and manipulating with Rotation\Position (and now, finally, Scale) you should use TransformMatrix, now enough just Position\Rotation\Scale
     
    Razmot likes this.
  10. dstilwagen

    dstilwagen

    Joined:
    Mar 14, 2018
    Posts:
    36
    Since Buffers are new and there isn't any official documentation yet I made a short(ish) write up on how to make and use the new buffers to help anyone who is having trouble.

    The new attribute InternalBufferCapacity(int) is used to tell the EntityManager the starting capacity of a buffer. Previously a FixedArray had to declare the capacity on initialization using ComponentType.FixedArray(type, capacity). This attribute does not seem to be required when declaring a struct to use as a buffer type. If no attribute is used the default capacity is 128 / Size of Struct. Example struct with only an int is 4 bytes so it would have a default capacity of 32.

    In order to use a struct as a buffer it must implement the IBufferElementData interface and has the same blittable restrictions that IComponentData does. It does look as if a struct can not be both an IComponentData and IBufferElementData (Tested and you do get and Error).

    Example buffer struct that simply wraps an int to be used as a buffer.
    Code (csharp):
    1. [InternalBufferCapacity(4)] //Initial buffer capacity default is 32 or (128 / type size) without attribute
    2. struct IntBufferType : IBufferElementData
    3. {
    4.     public int Value;
    5. }
    6.  
    There are multiple different ways to create and attach buffers to entities, I don't know if one method is better than another.
    Code (csharp):
    1.  
    2.  //Creates entity with a buffer that has a capacity of 4 using ComponentType.Create<IntBufferType>()
    3. var arrayType = ComponentType.Create<IntBufferType>();
    4. var entity    = EntityManager.CreateEntity(arrayType);
    5.  
    6. //Creates entity with a buffer that has a capacity of 4 using CreateArchetype(Type)
    7. var arch   = EntityManager.CreateArchetype(typeof(IntBufferType));
    8. var entity = EntityManager.CreateEntity(arch);
    9.  
    10. //Add a buffer that has a capacity of 4 to existing entity using AddComponent(entity, Type)
    11. EntityManager.AddComponent(entity, ComponentType.Create<IntBufferType>());
    12. //or
    13. EntityManager.AddComponent(entity, typeof(IntBufferType));
    14.  
    15. //Add a buffer that has a capacity of 4 to existing entity using AddBuffer<Type>(entity)
    16. EntityManager.AddBuffer<IntBufferType>(entity);
    17.  
    18. //Add a buffer that has a capacity of 4 to existing entity using EntityCommandBuffer and AddBuffer<Type>(entity)
    19. commandBuffer.AddBuffer<IntBufferType>(entity);
    20.          
    21. //Create entity and add a buffer that has a capacity of 4 to entity using EntityCommandBuffer and AddBuffer<Type>(entity)
    22. commandBuffer.CreateEntity();
    23. commandBuffer.AddBuffer<IntBufferType>();
    24.  
    Once you create and attach the buffer to an entity it can be retrieved using EntityManager.GetBuffer<Type>(entity) and assigned to a variable and used.

    There are some things to keep in mind when using the new Buffers.
    • A buffers length is the number of initialized elements in the buffer, while capacity is the total number of elements available to be used.
    • The size (capacity) of a buffer can be changed, it is similar to a list in this way and has an Add() and AddRange() function.
    • The capacity is determined by the InternalBufferCapacity attribute or defaults to 128 / type size in bytes.
    • In order to access and use it must be added to an entity first and then retrieved using GetBuffer<Type>().
    • A struct can only implement IBufferElementData or IComponentData not both.

    What is Reinterpret<U>()?
    This function converts the buffer its called on to another type but only if the two types are the same size in byte. (sizeof(int) == sizeof(float))
    Example:
    Code (CSharp):
    1. //Get BufferArray (DynamicBuffer<Type>) of IntBufferType which should be the same size as int
    2. var bufferInt = EntityManager.GetBuffer<IntBufferType>(entity);
    3. //Reinterpret buffer as float which should be the same size as int
    4. var bufferUInt = bufferInt.Reinterpret<float>();

    I think Reinterpret could be used to convert single type wrapper structs like the IntBufferType at the top to the type it is wrapping. This way you can wrap say Entity in a struct like you had to with FixedArray and then call Reinterpret<Entity>() and use the entity instead. I doubt this is the correct usage for Reinterpret. Since you could also use implicit and explicit operators to do this.

    I haven't had a chance to test Reinterpret yet but I plan to later this evening. If I am wrong in how Reinterpret works I will come back and correct this post. That also goes for anything else above, if I'm wrong in how something works or made mistake please let me know.

    Edit: Fixed errors that after testing work differently than I thought. See post below for more info.
     
    Last edited: Aug 18, 2018
    pahe, Vacummus, Guerro323 and 8 others like this.
  11. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    This is a godsend.

    Been able to remove multiple SharedComponentDatas that just held a single unique collection, letting me convert ComponentSystems to JobComponentSystems while not worrying about dependency issues.

    Thanks for the writeup @Razmot and @dstilwagen , saved me a lot of time researching it myself.
     
    Razmot likes this.
  12. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Something I've just noticed is, while the maximum component (or buffer) size is 16292 when creating an entity, it seems you can initialize a smaller buffer onto an entity then resize it above the maximum size.
     
    Last edited: Aug 18, 2018
    Razmot likes this.
  13. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    I find it surprising that DynamicBuffer only has CopyFrom(T[]) and CopyFrom(NativeArray<T>) and no CopyTo methods, and that AddRange() only accepts NativeArray. Maybe it will come later, it seems quite doable to implement all that in unsafe code.
     
  14. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    Thank you so much for this thread.
     
    Razmot likes this.
  15. dstilwagen

    dstilwagen

    Joined:
    Mar 14, 2018
    Posts:
    36
    Had a chance to test some of the things I wasn't 100% sure about. I've edited my post above to reflect this.

    I tested default capacity since I thought 128 seemed to high. I read the function wrong so it is really 128 / size of the struct in bytes. So a struct that is 8 bytes has a default capacity of 16.

    I have tested it and a struct can only implement IBufferElementData or IComponentData not both. This changes what I think Reinterpret<U>() is for. I originally thought it was this way but changed my mind while typing my first post.

    What I originally thought Reinterpret was for is to convert IBufferElementData struct to an IComponentData equivalent but this only made sense if a struct can't be both IBufferElementData and IComponentData. Which only after testing I found was true.
    Example:
    Code (csharp):
    1.  //Cell Struct to use with AddBuffer
    2. public struct CellBuffer : IBufferElementData
    3. {
    4.     public float3 CubeCoords;
    5.     public float2 OffsetCoords;
    6. }
    7.  
    8. public struct Cell : IComponentData
    9. {
    10.     public float3 CubeCoords;
    11.     public float2 OffsetCoords;
    12. }
    13.  
    14. //Get BufferArray (DynamicBuffer<Type>) of CellBuffer which should be the same size as Cell
    15. var cellBuffer = EntityManager.GetBuffer<CellBuffer>(entity);
    16. //Reinterpret buffer as Cell to use in system which should be the same size as CellBuffer
    17. var cells = bufferInt.Reinterpret<Cell>();
    18.  
    19. //Attach CellBuffer to entity as Cell
    20. EntityManager.AddComponentData(entity, cells[0]);
    21.  
    This could be really useful for say building a list of all the Cells and sticking it on an entity to store it and retrieve it later and convert it back to Cells to put them individually on entities at a much later time (shown in last line above). That really isn't the best example but hopefully it's enough to give people ideas on what to use it for.
     
    eizenhorn likes this.
  16. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Reinterpret is a pretty nice convenience thing, at least that's how I'm using it.

    So my buffer is

    Code (CSharp):
    1. public struct Block : IBufferElementData
    2. {
    3.     public ushort Value;
    4. }
    setup like this

    Blocks = _data.Blocks[index].Reinterpret<ushort>()


    And then in a job you can use and write like

    Code (CSharp):
    1. public DynamicBuffer<ushort> Blocks;
    2. Blocks[index] = value;
    instead of

    Code (CSharp):
    1. public DynamicBuffer<Block> Blocks;
    2. Blocks[index] = new Block {Value = value};
    I'm sure there are other advantages you can do that aren't just syntax sugar.
     
    recursive likes this.
  17. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    I m thinking of one :

    Let's say you have a 2d array of Voxel in a chunk, and you want to pad the array to have easy access to the border values of neighbour chunks :

    You can take the part of DynamicBuffer<Voxel> where X==0 || X==Max and reinterpret it into a buffer of <XBorder> and Inject it in the next system !

    More generally, it can be an efficient way to split buffer data into various strongly typed components
     
  18. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    987
    Wow. DynamicBuffer is great! It's like a list.
     
  19. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    Finally something able to pass collections to job. For now I am using this wrapper to initialize DynamicBuffer from the inspector, but I am sure there will be some official wrapper soon.

    Code (CSharp):
    1. [RequireComponent(typeof(GameObjectEntity))]
    2. public abstract class BufferElementDataWrapper<T> : MonoBehaviour where T : struct, IBufferElementData
    3. {
    4.     public T[] Items;
    5.  
    6.     private void Awake()
    7.     {
    8.         var goe = GetComponent<GameObjectEntity>();
    9.         goe.EntityManager.AddBuffer<T>(goe.Entity);
    10.         var buffer = goe.EntityManager.GetBuffer<T>(goe.Entity);
    11.         buffer.CopyFrom(Items);
    12.     }
    13. }
     
  20. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Simple CopyTo<T>(NativeArray<T> array) extensions if anyone needs

    Code (CSharp):
    1.         public static unsafe void CopyTo<T>(this DynamicBuffer<T> buffer, NativeArray<T> nativeArray) where T : struct
    2.         {
    3.             if (buffer.Length != nativeArray.Length)
    4.                 throw new ArgumentException("nativeArray.Length does not match the length of this instance");
    5.        
    6.             UnsafeUtility.MemCpy(nativeArray.GetUnsafePtr(), buffer.GetBasePointer(),
    7.                 buffer.Length * (long) UnsafeUtility.SizeOf<T>());
    8.         }
    Note, as there is currently no GetBasePointerReadOnly method, this CopyTo requires write permission even though it reads only.
     
    Last edited: Aug 20, 2018
    Razmot and davenirline like this.
  21. Andreas88

    Andreas88

    Joined:
    Dec 22, 2015
    Posts:
    67
    Hi there. i´m very new to the whole ECS world.
    i have been trying to declare my IBufferElementData, but it get this error :
    " error CS0246: The type or namespace name 'InternalBufferCapacity' could not be found (are you missing a using directive or an assembly reference?)" so far i understand i don´t have to declare my icomponent data inside a class.

    i got all the necessary directives:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Transforms2D;
    6. using Unity.Mathematics;
    7. using Unity.Rendering;
    8. using Unity.Transforms;
    9. using Unity.Jobs;
    hope someone can help me out :)
    oh and i have recently upgraded all the ECS stuff to newest version via package manager
     
  22. Attatekjir

    Attatekjir

    Joined:
    Sep 17, 2018
    Posts:
    23
    Did you add [InternalBufferCapacity(x)] when declaring your IBufferElementData?
    Like so:

    Code (CSharp):
    1. // This describes the number of buffer elements that should be reserved
    2. // in chunk data for each instance of a buffer. In this case, 8 integers
    3. // will be reserved (32 bytes) along with the size of the buffer header
    4. // (currently 16 bytes on 64-bit targets)
    5. [InternalBufferCapacity(8)]
    6. public struct MyBufferElement : IBufferElementData
    7. {
    8.     // These implicit conversions are optional, but can help reduce typing.
    9.     public static implicit operator int(MyBufferElement e) { return e.Value; }
    10.     public static implicit operator MyBufferElement(int e) { return new MyBufferElement { Value = e }; }
    11.    
    12.     // Actual value each buffer element will store.
    13.     public int Value;
    14. }
    From: https://github.com/Unity-Technologi...er/Documentation/reference/dynamic_buffers.md
     
  23. Andreas88

    Andreas88

    Joined:
    Dec 22, 2015
    Posts:
    67
    hi, yeah i did add the internalbuffercapacity. i actually just figured out that i had to upgrade to unity 2018.2 to be able to use the new feature. however this has caused me a new problem. for some reason it won´t allow me to use the namespace Transforms2d. has it been removed in entities preview 19?

     

    Attached Files:

  24. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    157
    I think the transforms2D has been removed, along with its contents (Position2D, Heading2D, etc).
     
  25. Andreas88

    Andreas88

    Joined:
    Dec 22, 2015
    Posts:
    67
    well that´s a bummer. all my code relies on the transforms2d
    if i use the Position and Heading, will i still be able to use the buildt in movement systems ?
    or do i have to make my own systems now ?
     
  26. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
  27. Andreas88

    Andreas88

    Joined:
    Dec 22, 2015
    Posts:
    67
    ok thanks a lot :)