NativeMultiHashmap and BlobAssetReference (Pathfinding)

Hi,

I’m building something where entities need access to a graph for pathfinding that is implemented in a custom struct that contains a NativeMultiHashmap like so:

 public struct Int2Graph : IGraph<Int2Node, Int2Edge>, IDisposable
    {
        private NativeMultiHashMap<Int2Node, Int2Edge> edges;
...

Entities that need a path then spawn an entity containing a PathRequest struct. I have a system that handles these request entities and then stores the result in a DynamicBuffer on the requesting entity. This all works fine.

However, I’m uncertain as to what is the best approach to pass the graph the pathfinding system should use, as entities can have different graphs they should navigate in.

I’ve come up with 2 solutions so far. My preferred solution would be storing the graph as a BlobAssetReference and setting it on a component on the request ‘event’ entity:

    public struct Int2GraphRequest : IComponentData
    {
        public BlobAssetReference<Int2Graph> Graph { get; set; } // graph to perform search on
        public Entity Entity { get; set; } // entity requesting the path
        public Int2Node Start { get; set; }
        public Int2Node Goal { get; set; }
    }

The graph is constructed at startup and doesn’t change after that. A BlobAssetReference is created from it with BlobAssetReference.Create(…)

However, this thread: Hashmap in a blob asset
states that one cannot use NativeHashmap (and I presume also MultiHashmap) in a BlobAssetReference. I’ve tried this approach and it does seem to work. But I keep getting a Native Collection has not been disposed error even though I’m disposing the BlobAssetReference and the original struct when the game stops. My hunch is the BlobAssetReference doesn’t know about the internal NativeMultiHashmap that’s in the struct. (The struct itself implements IDisposable and disposes the hash map)

Can somebody shed light on this approach and if it’s a valid one?

My other approach would be storing the graph struct as persistent directly on the system that handles the requests. Different graphs would then be handled by creating a new system in a different world.
The system handling the requests can pass the graph struct directly to the job and no BlobAssetReference would be required. I’ve read however you should not store data in systems themselves. Any thoughts on this approach would be appreciated too!

Thanks.

The thread you linked already answered your questions. It’s not valid. And will throw you errors which will prevent you from using native collections inside blobs in future.
From Unity tests for blobs.

That’s a shame. So the reason my approach is functional is because Unity’s test aren’t into place yet and I just got ‘lucky’ ?

This example: Getting Started with Blob Asset – COFFEE BRAIN GAMES also does something long these lines… So if I understand you correctly that tutorial is also incorrect?

How about my second option? Basically looking for a way to ‘reference’ a complex struct in a request. But it seems like this is almost impossible to do without generating a new world (and thus a new system containing the struct). Surely I’m not the first person to encounter such a scenario.

For our pathfinding we have singleton entity with class (not struct) IComponentData with our custom Native container (with couple of our other nested custom native containers) and we have mechanism for semiautomatic managing dependency for this container, disposing etc., and all our pathfinding results (flow fields implemented as specific unsafe structs for better usage in job with parallelism) stored in this, with cleanup from time to time, with rebuilding and invalidating regions (on top Hierarchical A* level) etc. Only one system writes to this (pathfinding) and all other only read from this. In OnUpdate we getting container from singleton and just using it inside all our jobs with maximum parallel (where it’s possible and give you gains) processing and Burst.

1 Like

Nice one. I was trying something alike found some strange behaviour when implementing IDisposable on the class. When I try to replace the component, Dispose() get’s called on the new component I’m setting. I was hoping it would only be called on the old component that is being replaced so the native containers can get cleaned up automatically. Is that something you’ve worked around or are you not using IDisposable at all?

We’re using explicit disposing management.