Search Unity

EntityCommandBuffer not working [Solved]

Discussion in 'Entity Component System' started by gilley033, Aug 23, 2018.

  1. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    I'm trying to get this broad phase collision detection code working. There's a legitimate chance there is just a bug in my code, but I have looked at it for hours and can't find it, so please let me know if you guys see anything. But, I stuck a Debug.Log statement inside the Job that doesn't seem to be executing and it is printing (yeah, it throws some errors as you'd expect but it still prints, so the code is being reached). The job in questions is CheckForCollisions. Here's the code:

    Code (CSharp):
    1. using Unity.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Burst;
    6. using Unity.Mathematics;
    7. using Unity.Transforms;
    8. using Unity.Transforms2D;
    9. using UnityEngine.Scripting;
    10. using UnityEngine;
    11.  
    12. public class BroadPhaseBarrierSystem : BarrierSystem
    13. {
    14.  
    15. }
    16.  
    17. public class BroadPhaseCollisionDetectionSystem : JobComponentSystem
    18. {
    19.     [Inject] BroadPhaseBarrierSystem broadPhaseBarrierSystem;
    20.  
    21.     List<PhysicsLayer> physicsLayers = new List<PhysicsLayer>(2);
    22.     PrevExecution previousExecution;
    23.     bool clearPreviousExecution;
    24.  
    25.     struct PrevExecution
    26.     {
    27.         public NativeMultiHashMap<int, int> collisionGrid;
    28.         public NativeArray<Entity> copyEntities;
    29.         public NativeArray<AABB> copyAABBSet;
    30.     }
    31.  
    32.     struct AABBGroup
    33.     {
    34.         public readonly int Length;
    35.         [ReadOnly] public EntityArray entities;
    36.         [ReadOnly] public ComponentDataArray<AABB> aabbSet;
    37.         [ReadOnly] public ComponentDataArray<PhysicsLayerNonShared> physicsLayers;
    38.     }
    39.  
    40.     [Inject] AABBGroup aabbGroup;
    41.  
    42.     [BurstCompile]
    43.     struct BuildCollisionGrid : IJobParallelFor
    44.     {
    45.         public NativeMultiHashMap<int, int>.Concurrent collisionGrid;
    46.  
    47.         [ReadOnly] public ComponentDataArray<AABB> aabbSet;
    48.         [ReadOnly] public ComponentDataArray<PhysicsLayerNonShared> physicsLayers;
    49.         public readonly int cellSize;
    50.  
    51.         public void Execute(int i)
    52.         {
    53.             AABB aabb = aabbSet[i];
    54.             int physicsLayer = physicsLayers[i].Layer;
    55.  
    56.             int bottomRow = aabb.minY.ToInt() / 2;
    57.             int topRow = aabb.maxY.ToInt() / 2;
    58.             int leftColumn = aabb.minX.ToInt() / 2;
    59.             int rightColumn = aabb.maxX.ToInt() / 2;
    60.  
    61.             for(int row = bottomRow; row <= topRow; row++)
    62.             {
    63.                 for(int column = leftColumn; column <= rightColumn; column++)
    64.                 {
    65.                     collisionGrid.Add(GridHash.Hash(new int3(column, row, physicsLayer)), i);
    66.                 }
    67.             }
    68.         }
    69.     }
    70.  
    71.     [BurstCompile]
    72.     struct CheckForCollisions : IJob
    73.     {
    74.         [ReadOnly] public NativeMultiHashMap<int, int> collisionGrid;
    75.         [ReadOnly] public NativeArray<Entity> entities;
    76.         [ReadOnly] public NativeArray<AABB> aabbSet;
    77.      
    78.         public EntityCommandBuffer buffer;
    79.  
    80.         public EntityArchetype potentialCollisionArchetype;
    81.  
    82.         public int hash1, hash2;
    83.         public void Execute()
    84.         {
    85.             //The two do/while loops will ensure that we compare every value at hash1 in the
    86.             //collision grid with every value at hash2 in the collision grid.
    87.             int index1, index2;
    88.             NativeMultiHashMapIterator<int> iterator1, iterator2;
    89.  
    90.             //first make sure there are items in the collision grid belonging to hash 1
    91.             if (!collisionGrid.TryGetFirstValue(hash1, out index1, out iterator1))
    92.                 return;
    93.          
    94.             //now make sure there are items in the collision grid belonging to hash 2
    95.             if (!collisionGrid.TryGetFirstValue(hash2, out index2, out iterator2))
    96.                 return;
    97.          
    98.             do
    99.             {
    100.                 do
    101.                 {
    102.                     AABB a = aabbSet[index1];
    103.                     AABB b = aabbSet[index2];
    104.                  
    105.                     //overlap exist
    106.                     if(a.minX < b.maxX && a.minY < b.maxY && a.maxX > b.minX && a.maxY > b.minY)
    107.                     {
    108.                         //Entity entity1 = entities[index1];
    109.                         //Entity entity2 = entities[index2];
    110.                         //order the entities so en
    111.                         if(index1 > index2)
    112.                         {
    113.                             var temp = index2;
    114.                             index2 = index1;
    115.                             index1 = temp;
    116.                         }
    117.  
    118.                         //int collisionHash = GridHash.Hash(new int2(index1, index2));
    119.  
    120.                         buffer.CreateEntity(potentialCollisionArchetype);
    121.                         buffer.SetComponent(new PotentialCollision() { AABBIndex1 = index1, AABBIndex2 = index2});
    122.                     }
    123.  
    124.                 } while (collisionGrid.TryGetNextValue(out index2, ref iterator2));
    125.             } while (collisionGrid.TryGetNextValue(out index1, ref iterator1) && collisionGrid.TryGetFirstValue(hash2, out index2, out iterator2));
    126.         }
    127.     }
    128.  
    129.     protected override void OnStopRunning()
    130.     {
    131.         if(clearPreviousExecution)
    132.         {
    133.             ClearPreviousExecution();
    134.             clearPreviousExecution = false;
    135.         }
    136.     }
    137.  
    138.     void ClearPreviousExecution()
    139.     {
    140.         previousExecution.collisionGrid.Dispose();
    141.         previousExecution.copyAABBSet.Dispose();
    142.         previousExecution.copyEntities.Dispose();
    143.     }
    144.  
    145.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    146.     {
    147.         if (clearPreviousExecution)
    148.             ClearPreviousExecution();
    149.  
    150.         if (aabbGroup.Length == 0)
    151.             return inputDeps;
    152.         else
    153.             clearPreviousExecution = true;
    154.  
    155.         //* 4 because each aabb can possibly be in 4 cells. Though this is probably not going to happen that much,
    156.         //if we don't prepare for the possibility then we may get into trouble later.
    157.         //If we have objects that are bigger than our cell radius we will need to increase this value.
    158.         var collisionGrid = new NativeMultiHashMap<int, int>(aabbGroup.Length * 4, Allocator.TempJob);
    159.         var copyAABBSet = new NativeArray<AABB>(aabbGroup.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
    160.         var copyEntities = new NativeArray<Entity>(aabbGroup.Length, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
    161.  
    162.         previousExecution = new PrevExecution()
    163.         {
    164.             collisionGrid = collisionGrid,
    165.             copyAABBSet = copyAABBSet,
    166.             copyEntities = copyEntities
    167.         };
    168.  
    169.         //var buffer = broadPhaseBarrierSystem.CreateCommandBuffer();
    170.  
    171.         var buildCollisionGridJobHandle = new BuildCollisionGrid()
    172.         {
    173.             collisionGrid = collisionGrid,
    174.             aabbSet = aabbGroup.aabbSet,
    175.             physicsLayers = aabbGroup.physicsLayers
    176.         }.Schedule(aabbGroup.Length, 64, inputDeps);
    177.  
    178.         var copyAABBJobHandle = new CopyComponentData<AABB>()
    179.         {
    180.             Source = aabbGroup.aabbSet,
    181.             Results = copyAABBSet
    182.         }.Schedule(aabbGroup.Length, 64, inputDeps);
    183.  
    184.         var copyEntitiesJobHandle = new CopyEntities()
    185.         {
    186.             Source = aabbGroup.entities,
    187.             Results = copyEntities
    188.         }.Schedule(aabbGroup.Length, 64, inputDeps);
    189.  
    190.         var runCollisionCheckBarrier = JobHandle.CombineDependencies(buildCollisionGridJobHandle, copyAABBJobHandle, copyEntitiesJobHandle);
    191.  
    192.         EntityManager.GetAllUniqueSharedComponentDatas(physicsLayers);
    193.  
    194.         int countOfHowManyLayersInteract = 0;
    195.      
    196.         for (int i = 1, j = 1; i < physicsLayers.Count; i++)
    197.         {
    198.             var layer1 = physicsLayers[i].Layer;
    199.             for (; j < physicsLayers.Count; j++)
    200.             {
    201.                 var layer2 = physicsLayers[j].Layer;
    202.                 if (!Physics2D.GetIgnoreLayerCollision(layer1, layer2))
    203.                 {
    204.                     countOfHowManyLayersInteract++;
    205.                 }
    206.             }
    207.             j = i + 1;
    208.         }
    209.  
    210.         var jobList = new NativeList<JobHandle>(7 * 13 * countOfHowManyLayersInteract, Allocator.Temp);
    211.  
    212.         for(int row = 0; row < 7; row++)
    213.         {
    214.             for(int column = 0; column < 13; column++)
    215.             {
    216.                 //skip i = 0 (default case) as it's useless
    217.                 for (int i = 1, j = 1; i < physicsLayers.Count; i++)
    218.                 {
    219.                     var layer1 = physicsLayers[i].Layer;
    220.                     int hash1 = GridHash.Hash(new int3(column, row, layer1));
    221.                     //NativeMultiHashMapIterator<int> iterator;
    222.                     //int value;
    223.  
    224.                     //Make sure collision grid cell [Column, Row] at Layer i has objects in it
    225.                     //if (!collisionGrid.TryGetFirstValue(hash1, out value, out iterator))
    226.                     //    continue;
    227.  
    228.                     //Now loop through all physics layers to run the collision check
    229.                     //Note, however, if we were to loop through the physics layers in full, we would run
    230.                     //duplicate comparisons, for instance we'd compare layer 2 and 1 after already comparing
    231.                     //1 and 2. To avoid this, after each inner loop, we set the next start index to
    232.                     //i + 1
    233.                     for (; j < physicsLayers.Count; j++)
    234.                     {
    235.                         var layer2 = physicsLayers[j].Layer;
    236.  
    237.                         //Actually make sure layer1 and layer2 objects can collide with each other.
    238.                         if (Physics2D.GetIgnoreLayerCollision(layer1, layer2))
    239.                             continue;
    240.                      
    241.                         //Make sure collision grid cell [column, row] at layer j has objects in it
    242.                         int hash2 = GridHash.Hash(new int3(column, row, layer2));
    243.  
    244.                         //NativeMultiHashMapIterator<int> iterator2;
    245.                         //int value2;
    246.  
    247.                         ////Make sure collision grid cell [Column, Row] at Layer i has objects in it
    248.                         //if (!collisionGrid.TryGetFirstValue(hash2, out value2, out iterator2))
    249.                         //    continue;
    250.  
    251.                         jobList.Add((new CheckForCollisions()
    252.                         {
    253.                             collisionGrid = collisionGrid,
    254.                             entities = copyEntities,
    255.                             aabbSet = copyAABBSet,
    256.                             buffer = broadPhaseBarrierSystem.CreateCommandBuffer(),
    257.                             potentialCollisionArchetype = potentialCollisionArch,
    258.                             hash1 = hash1,
    259.                             hash2 = hash2
    260.                         }).Schedule(runCollisionCheckBarrier));
    261.                     }
    262.                     j = i + 1;
    263.                 }
    264.             }
    265.         }
    266.  
    267.         var returnHandle = runCollisionCheckBarrier;
    268.         if (jobList.Length > 0)
    269.         {
    270.             NativeArray<JobHandle> jobHandleArray = new NativeArray<JobHandle>(jobList.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
    271.             for (int i = 0; i < jobHandleArray.Length; i++)
    272.                 jobHandleArray[i] = jobList[i];
    273.  
    274.             returnHandle = JobHandle.CombineDependencies(jobHandleArray);
    275.             jobHandleArray.Dispose();
    276.         }
    277.  
    278.         jobList.Dispose();
    279.  
    280.         physicsLayers.Clear();
    281.      
    282.         return returnHandle;
    283.     }
    284.  
    285.     EntityArchetype potentialCollisionArch;
    286.  
    287.     protected override void OnCreateManager(int capacity)
    288.     {
    289.         potentialCollisionArch = EntityManager.CreateArchetype(typeof(PotentialCollision));
    290.         //physicsLayerGroup = GetComponentGroup(
    291.         //    ComponentType.ReadOnly(typeof(PhysicsLayer)),
    292.         //    ComponentType.ReadOnly(typeof(AABB)));
    293.     }
    294. }
    295.  

    Basically, I am building a collision table, using each object's hash (row/column that each physics object is in according to its AABB - yes it can be in multiple cells - and the physics layer the object is on) to serve as the key, and storing the index of the AABB (as it is ordered in the array of all AABB's in the scene) as the value. So each layer has potentially n*m keys in the multi hash map, for a total of n*m*layer keys (of course, it's almost certainly less than this, as physics objects will not be in every cell). Building that collision table is the first job.

    After that job is one (along with some basic copy data jobs), I loop through each collision cell for each layer that has objects in it, and do an AABB overlap test for the physics objects that are in the same cell and that can collide with them. There may be a better way to do this without using a multi hash map, but its' what I came up with. I will test other methods once I've got this one working.

    The collision checking (AABB overlap test) jobs are run in parallel (that is, they are all scheduled to depend on the collision table build job, but not each other - and then their dependencies are combined), however I tried setting them to depend on each other so they run one after another and didn't see any change. I also am using multiple command buffers per job created from the same barrier system, but I also tried using a single buffer when the jobs were not written to run in parallel and there was no change.

    As I've said, I set a Debug.Log statement to only run when an overlap test returns true (overlap exists), and it is being printed to the console. I take this to mean that the jobs are running as expected. I can't find a bug anywhere. New entities should be created after each cycle, but the Entity debugger isn't showing them, and I created a separate system to detect the existing of the new PotentialCollision components and it is not detecting them.

    So I am left to the conclusion that the command buffers are just not running. I am using CreateEntity(EntityArchetype) and SetComponent, but also tried CreateEntity() and AddComponent. Neither has worked.

    Has anyone got any ideas? If I had to guess I'd say I am doing something wrong somewhere that is messing things up.

    Thanks!
     
    Last edited: Aug 23, 2018
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    I don't know if that will be case for you, but I normally assign command buffer as follow

    [Inject] private Barrier myBarrier ;
    Code (CSharp):
    1.  
    2.  
    3. [Inject] private Barrier myBarrier ;
    4. static private EntityCommandBuffer commandsBuffer ;
    5.  
    6. OnCreateManager ()
    7. {
    8.     // this is likely not needed
    9.     commandsBuffer = myBarrier.CreateCommandBuffer () ;
    10. }
    11.  
    12. struct MyJob : IJob
    13. {
    14.     public EntityCommandBuffer commandsBuffer ;
    15.  
    16.     public void Execute ()
    17.     {
    18.         // some for loop
    19.     }
    20. }
    21.  
    22. protected override JobHandle OnUpdate ( JobHandle inputDeps )
    23. {                  
    24.    commandsBuffer = myBarrier.CreateCommandBuffer () ;
    25.  
    26.    return new MyJob
    27.    {          
    28.        commandsBuffer = commandsBuffer
    29.     }.Schedule(inputDeps) ;
    30. }
    Not sure if is 100% right, but this work form me
     
    Last edited: Aug 23, 2018
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    The general approach I'e seen recommended (and how Unity does it in their systems) is the way gilley033 has done it, creating the commandbuffer every update.

    Anyway onto your actual problem. Is this what you're meant to be doing? You create 2 entities

    Code (CSharp):
    1.         public void Execute()
    2.         {
    3.             buffer.CreateEntity(potentialCollisionArchetype);
    You create an entity right at start of job, but then

    Code (CSharp):
    1.                         buffer.CreateEntity();
    2.                         buffer.SetComponent(new PotentialCollision() { AABBIndex1 = index1, AABBIndex2 = index2});
    Create another entity, this time without the archetype. So your achetype entity isn't being assigned, instead you're trying to set the component on an entity without the type. If this is intended behaviour (which I doubt), it should be AddComponent not set.
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    I have seen indeed some examples with command buffer in update.
    But I do wonder then, what are consequences of my approach?
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    As far as I'm aware, it doesn't work. When you create a buffer, it adds it to the pending list

    Code (CSharp):
    1. public EntityCommandBuffer CreateCommandBuffer()
    2. {
    3.     var cmds = new EntityCommandBuffer(Allocator.TempJob);
    4.  
    5.     m_PendingBuffers.Add(cmds);
    6.  
    7.     return cmds;
    8. }
    When update is run the list is cleared

    Code (CSharp):
    1. protected sealed override void OnUpdate()
    2. {
    3.     FlushBuffers(true);
    4.  
    5.     m_PendingBuffers.Clear();
    6. }
    So it's only going to work once.

    It's also disposed of as soon as it's used so it's not even valid

    Code (CSharp):
    1.  private void FlushBuffers(bool playBack)
    2.         {
    3.             m_ProducerHandle.Complete();
    4.             m_ProducerHandle = new JobHandle();
    5.  
    6.             int length;
    7. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    8.             length = m_PendingBuffers.Count;
    9. #else
    10.             length = m_PendingBuffers.Length;
    11. #endif
    12.             for (int i = 0; i < length; ++i)
    13.             {
    14.                 if (playBack)
    15.                 {
    16.                     m_PendingBuffers[i].Playback(EntityManager);
    17.                 }
    18.                 m_PendingBuffers[i].Dispose();
    19.             }
    20.         }
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    My initial octree systems and collisions I have done the way, I have described. So it does work. That is why I am very curious now, while you saying, technically it shouldn't work :confused:
     
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Ok, I need apologize. My bad.

    In fact I had,
    Code (CSharp):
    1. commandsBuffer = myBarrier.CreateCommandBuffer () ; // in OnUpdate (updated script)
    I copied example from wrong reference script.
    So yes, CreateCommandBuffer () need be in OnUpdate.

    Then perhaps it can be removed form OnCreateManager method.
     
  8. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    @tertle

    Whoops! The first CreateEntity call is not really meant to be there, I just added it to check if my AABB overlap test was somehow failing. I wanted to make sure the Execute method was being called. That call wasn't there before and it wasn't working still, so I don't think that's the problem. The second one did have the archetype included, I just forgot to change it back after messing with things.

    Here is what the code should actually be (and no, this does not work still):

    Code (CSharp):
    1. [BurstCompile]
    2.     struct CheckForCollisions : IJob
    3.     {
    4.         [ReadOnly] public NativeMultiHashMap<int, int> collisionGrid;
    5.         [ReadOnly] public NativeArray<Entity> entities;
    6.         [ReadOnly] public NativeArray<AABB> aabbSet;
    7.      
    8.         [WriteOnly]public EntityCommandBuffer buffer;
    9.  
    10.         public EntityArchetype potentialCollisionArchetype;
    11.  
    12.         public int hash1, hash2;
    13.         public void Execute()
    14.         {
    15.             //The two do/while loops will ensure that we compare every value at hash1 in the
    16.             //collision grid with every value at hash2 in the collision grid.
    17.             int index1, index2;
    18.             NativeMultiHashMapIterator<int> iterator1, iterator2;
    19.  
    20.             //first make sure there are items in the collision grid belonging to hash 1
    21.             if (!collisionGrid.TryGetFirstValue(hash1, out index1, out iterator1))
    22.                 return;
    23.          
    24.             //now make sure there are items in the collision grid belonging to hash 2
    25.             if (!collisionGrid.TryGetFirstValue(hash2, out index2, out iterator2))
    26.                 return;
    27.          
    28.             do
    29.             {
    30.                 do
    31.                 {
    32.                     AABB a = aabbSet[index1];
    33.                     AABB b = aabbSet[index2];
    34.                  
    35.                     //overlap exist
    36.                     if(a.minX < b.maxX && a.minY < b.maxY && a.maxX > b.minX && a.maxY > b.minY)
    37.                     {
    38.                         //Entity entity1 = entities[index1];
    39.                         //Entity entity2 = entities[index2];
    40.                         //order the entities so en
    41.                         if(index1 > index2)
    42.                         {
    43.                             var temp = index2;
    44.                             index2 = index1;
    45.                             index1 = temp;
    46.                         }
    47.  
    48.                         //int collisionHash = GridHash.Hash(new int2(index1, index2));
    49.  
    50.                         buffer.CreateEntity(potentialCollisionArchetype);
    51.                         buffer.SetComponent(new PotentialCollision() { AABBIndex1 = index1, AABBIndex2 = index2});
    52.                     }
    53.  
    54.                 } while (collisionGrid.TryGetNextValue(out index2, ref iterator2));
    55.             } while (collisionGrid.TryGetNextValue(out index1, ref iterator1) && collisionGrid.TryGetFirstValue(hash2, out index2, out iterator2));
    56.         }
    57.     }
    Edit: Also, I tried taking the archetype out of the occasion and using an empty CreateEntity call followed by an AddComponent call. Still doesn't work. For reasons I don't understand the command buffer is not being played back.
     
  9. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Okay, so I just realize I have no code anywhere involving EntityCommandBuffers that is actually tested and working properly. And I just tried the simplest possible test I could think of and it is not working:
    Code (CSharp):
    1. public class TestSystem : JobComponentSystem
    2. {
    3.     [Inject] BarrierTestSystem testBarrier;
    4.  
    5.     public struct AddPotentialCollision : IJob
    6.     {
    7.         public EntityCommandBuffer buffer;
    8.  
    9.         public void Execute()
    10.         {
    11.             buffer.CreateEntity();
    12.             buffer.AddComponent(new PotentialCollision() { AABBIndex1 = 0, AABBIndex2 = 1 });
    13.         }
    14.     }
    15.  
    16.  
    17.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    18.     {
    19.         var buffer = testBarrier.CreateCommandBuffer();
    20.         for (int i = 0; i < 5; i++)
    21.         {
    22.             inputDeps = (new AddPotentialCollision() { buffer = buffer }).Schedule(inputDeps);
    23.         }
    24.  
    25.         return inputDeps;
    26.     }
    27. }
    28.  
    29. public class BarrierTestSystem : BarrierSystem
    30. {
    31.  
    32. }

    The only thing about my code that differs from standard approaches is that I am not using the default world initialization stuff, but am adding systems to the world manually and calling each systems Update method manually. Other systems that don't use EntityCommandBuffer are working properly using this approach, so I don't see why there would be an issue. I'm going to dig into the Entities package code to see if I can find a possible issue, but in case you guys find anything wrong with my approach, here is the MonoBehaviour where everything is setup.

    Code (CSharp):
    1. public class TestingDoubleMultiHash : MonoBehaviour
    2. {
    3.     List<ComponentSystemBase> systems = new List<ComponentSystemBase>();
    4.     World world;
    5.  
    6.     public static SharedSprite BubbleLook, WallLook;
    7.  
    8.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    9.     private static void OnBeforeSceneLoad()
    10.     {
    11.         TestingDoubleMultiHash t = FindObjectOfType<TestingDoubleMultiHash>();
    12.         if (t == null)
    13.             return;
    14.         else
    15.             t.Initialize();
    16.     }
    17.  
    18.     private void Initialize()
    19.     {
    20.         world = new World("TestingDoubleMultiHash");
    21.         World.Active = world;
    22.         PlayerLoopManager.RegisterDomainUnload(OnDomainUnloadShutdown, 10000);
    23.         BubbleLook = GetSpriteFromResources("Sprites/BubblePrototype");
    24.         WallLook = GetSpriteFromResources("Sprites/WallPrototype");
    25.         RegisterSystems();
    26.     }
    27.  
    28.     static void OnDomainUnloadShutdown()
    29.     {
    30.         World.DisposeAllWorlds();
    31.         ScriptBehaviourUpdateOrder.UpdatePlayerLoop();
    32.     }
    33.  
    34.     void RegisterSystems()
    35.     {
    36.         systems.Add(RegisterSystem<UpdateAABBSystem>());
    37.         systems.Add(RegisterSystem<BroadPhaseCollisionDetectionSystem>());
    38.         systems.Add(RegisterSystem<BroadPhaseBarrierSystem>());
    39.         systems.Add(RegisterSystem<DetectPotentialCollionsSystem>());
    40.         systems.Add(RegisterSystem<TestSystem>());
    41.         systems.Add(RegisterSystem<BarrierTestSystem>());
    42.         systems.Add(RegisterSystem<UpdateRenderPositionSystem>());
    43.         systems.Add(RegisterSystem<RenderTransform2DSystem>());
    44.         systems.Add(RegisterSystem<SharedSpriteRendererSystem>());
    45.     }
    46.  
    47.     ComponentSystemBase RegisterSystem<T>() where T : ComponentSystemBase
    48.     {
    49.         return (ComponentSystemBase)world.CreateManager(typeof(T));
    50.     }
    51.  
    52.     void Start()
    53.     {
    54.         var em = World.Active.GetExistingManager<EntityManager>();
    55.         var arch = em.CreateArchetype
    56.         (
    57.             ComponentType.Create<RenderPosition2D>(),
    58.             ComponentType.Create<PhysicsPosition2D>(),
    59.             ComponentType.Create<CircleCollider2D>(),
    60.             ComponentType.Create<AABB>(),
    61.             ComponentType.Create<PhysicsLayer>(),
    62.             ComponentType.Create<PhysicsLayerNonShared>(),
    63.             ComponentType.Create<Scale2D>(),
    64.             ComponentType.Create<TransformMatrix>(),
    65.             ComponentType.Create<Coloring>(),
    66.             ComponentType.Create<SharedSprite>(),
    67.             ComponentType.Create<DebugComponent>(),
    68.             ComponentType.Create<CollisionCells>()
    69.         );
    70.  
    71.         var boxArch = em.CreateArchetype
    72.         (
    73.             ComponentType.Create<RenderPosition2D>(),
    74.             ComponentType.Create<PhysicsPosition2D>(),
    75.             ComponentType.Create<BoxCollider2D>(),
    76.             ComponentType.Create<AABB>(),
    77.             ComponentType.Create<PhysicsLayer>(),
    78.             ComponentType.Create<PhysicsLayerNonShared>(),
    79.             ComponentType.Create<TransformMatrix>(),
    80.             ComponentType.Create<Coloring>(),
    81.             ComponentType.Create<SharedSprite>(),
    82.             ComponentType.Create<DebugComponent>(),
    83.             ComponentType.Create<CollisionCells>()
    84.         );
    85.  
    86.         for (int i = 1; i < 11; i++)
    87.         {
    88.             var e = em.CreateEntity(boxArch);
    89.             var x = Random.Range(1f, 20f);
    90.             var y = Random.Range(1f, 10f);
    91.  
    92.             em.SetComponentData(e, new RenderPosition2D(x, y));
    93.             em.SetComponentData(e, new PhysicsPosition2D(FixedMath.Create(x), FixedMath.Create(y)));
    94.             em.SetComponentData(e, new BoxCollider2D(FixedMath.Two));
    95.             em.SetComponentData(e, new PhysicsLayerNonShared((int)PhysicsLayerType.LevelGeometry));
    96.             em.SetSharedComponentData(e, new PhysicsLayer((int)PhysicsLayerType.LevelGeometry));
    97.          
    98.             em.SetComponentData(e, new Coloring(1f, 1f, 1f, 1f));
    99.             em.SetSharedComponentData(e, WallLook);
    100.         }
    101.  
    102.         for (int i = 1; i < 11; i++)
    103.         {
    104.             var e = em.CreateEntity(arch);
    105.             var x = i * 1.5f;
    106.             var y = i * 1f;
    107.             int radiusMultiplier = i % 4;
    108.             var radius = .25f + (.25f * radiusMultiplier);
    109.             em.SetComponentData(e, new RenderPosition2D(x, y));
    110.             em.SetComponentData(e, new PhysicsPosition2D(FixedMath.Create(x), FixedMath.Create(y)));
    111.             em.SetComponentData(e, new CircleCollider2D(FixedMath.Create(radius)));
    112.             em.SetComponentData(e, new PhysicsLayerNonShared((int)PhysicsLayerType.Bubbles));
    113.             em.SetSharedComponentData(e, new PhysicsLayer((int)PhysicsLayerType.Bubbles));
    114.             if (Mathf.Approximately(1f, radius))
    115.                 em.RemoveComponent<Scale2D>(e);
    116.             else
    117.                 em.SetComponentData(e, new Scale2D(radius));
    118.             em.SetComponentData(e, new Coloring(1f, 1f, 1f, 1f));
    119.             em.SetSharedComponentData(e, BubbleLook);
    120.         }
    121.     }
    122.  
    123.     void Update()
    124.     {
    125.         foreach (var system in systems)
    126.             system.Update();
    127.     }
    128.  
    129.     private static SharedSprite GetSpriteFromResources(string resourcePath)
    130.     {
    131.         Sprite sprite = Resources.Load<Sprite>(resourcePath);
    132.         return new SharedSprite { Value = sprite };
    133.     }
    134. }

    The wall and bubble entities created in Start are working fine (displaying properly), so I feel like this should all be working. Any ideas? Thanks!
     
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Thing of top of my head, is to actually remove var from front of buffer variable.
     
    NearAutomata likes this.
  11. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Thanks, but that did not work unfortunately.
     
  12. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
  13. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I'm not sure how that could possibly change anything.

    @gilley033 if you're manually updating the systems are you also manually updating the barrier? If not you'll need to do that.

    -edit- I should add, this sounds like a pretty bad idea as you're manually handling sync points and dependencies
     
    Last edited: Aug 23, 2018
  14. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Trying anything ;)
     
  15. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Yes, the barrier system is included in the list of systems that is updated every frame. I am just calling the Update method on the systems, I am pretty sure there is code behind the scenes still managing all the dependencies, but who knows, that may be an issue.

    But, what I am doing has been posted as the way to go about things if you need to manually update your systems, so I think it should work. As for doing the manual update at all, it's not apparent in this limited use case but for my custom physics system it is a must, because I have certain systems that need to run several times in a loop before other systems are called, and also it's needed for other reasons. And Unity devs have stated it shouldn't be a problem.
     
  16. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    @tertle You were right, it was an issue with manually updating the systems. I tested doing an automatic update and it works fine. There's a lot of stuff that gets setup when you call ScriptBehaviourUpdateOrder.UpdatePlayerLoop, so not using that causes issues. I'm going to have to do more research into the topic of manual updates. Some devs implied in other threads it was as simple as what I'm doing, but I've obviously misunderstood something.

    But for the purpose of this thread, it's clear there is not an issue with the Entity Command Buffer. Thanks for help @tertle and @Antypodish
     
  17. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Well, no much help from me really.
    As usually, I am far behind you guys with ECS expertise :p
    Me thinking, is like ... "Where you guys got that knowledge from. is just MASSIVE" ;)
    But I have learned something here. That is for sure.
     
    FlavioIT likes this.
  18. NearAutomata

    NearAutomata

    Joined:
    May 23, 2018
    Posts:
    51
    I ran into an inexplicable issue and this helped me out after replacing
    var
    with
    EntityCommandBuffer.Concurrent
    . Took me hours to figure this one out.