Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Accessing unknown quantity of NativeHashmaps from within a job

Discussion in 'Entity Component System' started by threedots1, Jun 24, 2020.

  1. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    I'm working on a game where I have hierachical graphs and standard grid graphs in use for pathfinding. There are an undefined number of graphs at runtime, the number is defined in data external to Unity.

    When my pathfinding system runs, it determines what graphs to use based on a byte stored on the entity. With the standard grid graphs, they are just tiles stored in a regular array, which conveniently goes in dynamic buffers on entities, and I use the byte to find an Entity ID to access the buffer, all easy.

    However the hierarchical graphs are composed of two NativeMultiHashmaps. I can't just jam this on an entity and be done, and passing an undefined number of these into a job is difficult.

    An ideal solution for me would be to be able to pass in a list somehow that I can index into to select the correct graph to use. Burst compilation is absolutely required.

    My current solution works, but is ugly, and is fixed in size. I have to pre-create a number of hashmaps, even if they aren't used, pass them in in a single struct and access them with a switch based index.

    Is there anything I haven't thought of that could do a better job of this? Are there any ways to do this using NativeLists of pointers? I've posted my ugly code below.

    Code (CSharp):
    1.  public struct HGraphs : IDisposable
    2.     {
    3.         public HGraphSectorData SectorData;
    4.  
    5.         public HGraph HGraph0;
    6.         public HGraph HGraph1;
    7.         public HGraph HGraph2;
    8.         public HGraph HGraph3;
    9.         public HGraph HGraph4;
    10.         public HGraph HGraph5;
    11.         public HGraph HGraph6;
    12.         public HGraph HGraph7;
    13.  
    14.         public const int Length = 8;
    15.  
    16.         public HGraphs(int2 dimensions)
    17.         {
    18.             SectorData = new HGraphSectorData(dimensions);
    19.  
    20.             HGraph0 = new HGraph(SectorData);
    21.             HGraph1 = new HGraph(SectorData);
    22.             HGraph2 = new HGraph(SectorData);
    23.             HGraph3 = new HGraph(SectorData);
    24.             HGraph4 = new HGraph(SectorData);
    25.             HGraph5 = new HGraph(SectorData);
    26.             HGraph6 = new HGraph(SectorData);
    27.             HGraph7 = new HGraph(SectorData);
    28.         }
    29.  
    30.         public HGraph this[int index]
    31.         {
    32.             get
    33.             {
    34.                 switch (index)
    35.                 {
    36.                     case 0:
    37.                         return HGraph0;
    38.                     case 1:
    39.                         return HGraph1;
    40.                     case 2:
    41.                         return HGraph2;
    42.                     case 3:
    43.                         return HGraph3;
    44.                     case 4:
    45.                         return HGraph4;
    46.                     case 5:
    47.                         return HGraph5;
    48.                     case 6:
    49.                         return HGraph6;
    50.                     case 7:
    51.                         return HGraph7;
    52.                     default:
    53.                         throw new IndexOutOfRangeException("Index out of range when attempting to access HGraphs");
    54.                 }
    55.             }
    56.         }
    57.  
    58.         public void Dispose()
    59.         {
    60.             HGraph0.Dispose();
    61.             HGraph1.Dispose();
    62.             HGraph2.Dispose();
    63.             HGraph3.Dispose();
    64.             HGraph4.Dispose();
    65.             HGraph5.Dispose();
    66.             HGraph6.Dispose();
    67.             HGraph7.Dispose();
    68.         }
    Code (CSharp):
    1. public struct HGraph : IDisposable
    2.     {
    3.         public NativeMultiHashMap<int, int>            SectorNodes;
    4.         public NativeMultiHashMap<int, NodeConnection> NodeConnections;
    5.  
    6.         public HGraph(HGraphSectorData sectorData)
    7.         {
    8.             SectorNodes     = new NativeMultiHashMap<int, int>(8            * sectorData.Count, Allocator.Persistent);
    9.             NodeConnections = new NativeMultiHashMap<int, NodeConnection>(8 * sectorData.Count, Allocator.Persistent);
    10.         }
    11.  
    12.         public void Dispose()
    13.         {
    14.             if (SectorNodes.IsCreated)
    15.                 SectorNodes.Dispose();
    16.             if (NodeConnections.IsCreated)
    17.                 NodeConnections.Dispose();
    18.         }
    19.     }
     
  2. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    988
    I think you data structure is too close to you conceptual structure.

    Based on the HGrpah struct it feel like your are working with something similar to and octree.
    Mabe look at flattened implementation of such strucutre and morton code.

    If once you graph is created it's immutable, and you don't have too much new graph at runtime, I would also look into blob assets maybe. I remember seeing a thread in this forum about making a grpah like strucutre with blob assets.
     
  3. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    The graph is mutable, and changes relatively often.

    For anyone else looking for the solution it looks like it's quite simple. UnsafeMultiHashMap is blittable, therefore can be emedded directly into a native array. Obviously with the drawbacks of managing safe access yourself, but can't believe I hadn't found this out eariler!