Search Unity

Are there (Multi)Hashmap versions of DynamicBuffer?

Discussion in 'Entity Component System' started by TheGabelle, Jun 4, 2019.

  1. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    Since components can't have collections we use DynamicBuffers, simple enough. From what I can tell buffers are essentially coupled NativeArrays with some fancy allocation footwork. I need more random access to these buffers and I'm trying to avoid multiple search iterations per buffer, per entity, per system, per frame.

    If there aren't other buffer collections and won't be, how could I work around my need for them?
     
    Last edited: Jun 4, 2019
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    What does the data look like here? What's the key and how much are we talking about?

    My initial thoughts would be first is there a way to actually index into it still using a buffer, or maybe partition it into multiple buffers to the point where iteration is no longer a performance issue.

    Then I'd probably think is there a way to put it all into a single NativeHashMap?

    Most of the above is very dependent on the specific data, and might require some lateral thinking in how you structure it. Which is why I was curious about what the data looks like exactly.
     
  3. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    FYI one approach for using a single NativeHashMap is construct a compound key using IEQuatable.

    For example you could take whatever the natural key is, let's assume it's an integer. Then the Entity itself. Your hashcode would look something like math.hash(new int3(naturalKey, entity.Id, entity.Version)). Or instead of the entity if you have some other unique integer id you could use that.
     
  4. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    I'm in the process of designing an ECS version of my goap-like AI architecture and struggling. The planning system isn't a concern, but the architecture for each action's unique stateful data is. An agent has multiple positions, entity references, and so on to remember. Currently thinking of 'typed blackboards' via DynamicBuffers (an entity buffer, a position buffer, etc). Each action's stateful data is simply a collection of blackboard -> index pairs. Perhaps I could use multiple hashmaps in a similar fashion? The key would be the hash value of task id, 'variable' id, entity id, and entity version? Dunno.

    Not sure where these hashmaps would be constructed either. This data would need to be accessed by many systems, so if it's not on the entity or on each system where does it go? Sounds like global collections.

    I might need to scratch this design and start over since I'm likely trying to replicate my object oriented prototypes too much. My prototypes are fairly involved as it is -- Agents with multiple tasks (strips of actions) with concurrency based on priority and action bit-flags.
     
  5. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    What about separating the ai engine itself from the entities that use it? Let the engine do what it wants to maybe entities are not the best fit for the ai itself or maybe you just don't want to refactor the entire thing right now. ComponentDataFromEntity works nicely as a sort of message bus between various component groups.
     
  6. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    I hope to convert the AI system to ECS for performance gains -- especially since complex AI is extremely expensive.

    The object oriented architecture in a nutshell:
    • Agents have a 'blackboard' for stateful action data that can be W/R from considerations, planning, and actions.
    • Considerations determine an Agent's goal assignments and often assign stateful data (targets, positions, etc)
    • Goals are processed into Tasks by a Task Planner (GOAP)
      • Goals are prioritized, therefore Tasks are too.
      • ActionNodes carry information for assigning Actions and respective stateful data
    • A Task Stitcher converts an Agent's assigned Tasks into Atomic Actions
      • An ActionMask bit-flag allows concurrent Actions across multiple Tasks
    • Actions execute (move, animate, turn, inventory/equipment update, etc)

    In ECS terms (roughly):
    • A blackboard is multiple DynamicBuffers, one for each type of data to be stored on a blackboard (entity references, vec3, etc).
    • Consideration Components are flags for Consideration Systems, which monitor Agent's components / blackboards and assign Goal Tags to Agents
    • Task Planner System generates a Task for each Goal Tag, then removes the tag.
      • Agent's tasks are stored in another DynamicBuffer?
      • Tasks are comprised of: task id, goal id, priority score, current action index, array of Actions (a strip)
      • Actions are comprised of: task id, ActionState, ActionMask, action component type, action variable keys (blackboard keys)
    • A Task Stitcher System assigns Action Components to an Agent based on:
      • a task's priority
      • an action's state (start, running, paused, finished)
      • an action's ActionMask (a bit-flag)
    • Action Systems process Action Components

    I guess the main issue is the inability to store collections on structs/components. I suppose each struct that would otherwise contain a collection could hold a single key, which is used along with a MultiNativeHashmap to actually attain the desired collection. This would be a ton of work-around, likely involving a poor memory usage, and may not be Job-able or Burst-able in the end (the entire goal for converting to ECS).

    Perhaps I should focus on working my prototypes into a Job-able form, then consider a full DOTS conversion.