Search Unity

Dependencies on NativeContainers not shared between systems

Discussion in 'Entity Component System' started by threedots1, Jun 28, 2019.

  1. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    For the current project I'm working on I'm using NativeArrays on systems to store information about the games map. Sometimes other systems need access to these NativeArrays so I am using this to retrieve the native arrays:
    Code (CSharp):
    1. World.Active.GetExistingSystem<GridGraphSystem>().PathTiles
    All works well but unfortunately using this method to access a nativearray and using that nativearray inside a job does not update the job dependencies automatically, leading to x is attempting to write to y etc etc.

    My current solution is to manually store the jobhandle of each system that accesses that nativearray, combining the jobhandles together and using that as an inputdep for scheduling. This obviously ends up in having to write a lot of pain the ass boilerplate code and ends up with very messy looking systems.

    I currently feel like I have two options:
    1. Write a custom system that holds all nativearrays used in other systems, which has functions to register usage of a nativearray and combines dependencies automatically.
    2. Switch back to using dynamic buffers, which I used originally and shifted away from as I found the nativearrays easier and simpler to work with.

    Anyone have any thoughts as to how they've dealt with this?
    Are unity planning to change how this works at all?
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Thoughts?

    Don't do it if you can avoid it. Leads to a lot of surprise issues.

    If you must (for example the collision world in unity physics), only write to the native container in the owner system then expose the job handle for writing so other systems can depend on it.
     
  3. jdtec

    jdtec

    Joined:
    Oct 25, 2017
    Posts:
    302
    This is interesting because there was a thread recently were people were discussing whether to use native containers vs dynamic buffers for this sort of usage.

    I mentioned that I wasn't sure if Unity handles all the dependency management for sharing containers around and if your experience is accurate then it appears they don't.

    I've dealt with this by using DynamicBuffers, like it sounds you used too. I thought that DynamicBuffers were better suited and more explicit in usage terms for data that is a shared resource across multiple systems.

    I generally only use native containers for data encapsulated to a single system.
     
  4. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    346
    wouldn't it work better with NativeHashmap ? Because of toConcurrent() you have a way to isolate writes from reads.

    It works for me but the way I use my hashmap is "read mostly"
     
  5. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    Thanks tertle and jdtec. I've started on converting back to dynamic buffers and I've found a way which is much neater than previous and just as fast.

    In the OnCreate of a system I do this:
    Code (CSharp):
    1. _mapQuery = GetEntityQuery(new ComponentType(typeof(MapTile), ComponentType.AccessMode.ReadOnly));
    In the OnUpdate:
    Code (CSharp):
    1. var mapEntity = _mapQuery.GetSingletonEntity();
    2. var mapTiles  = EntityManager.GetBuffer<MapTile>(mapEntity);
    In the job setup:
    Code (CSharp):
    1. var exampleJob = new ExampleJob
    2. {
    3.     MapTiles = mapTiles.AsNativeArray()
    4. };
    Seems to work as expected, the dependencies shown in the entity debugger look good and I don't have to pass InputDeps around systems any more.

    If you can see something wrong in how I'm doing this let me know!

    Cheers
     
    Razmot likes this.
  6. threedots1

    threedots1

    Joined:
    Oct 9, 2014
    Posts:
    88
    This is being used for a very large game world and I'm after the performance of arrays vs hash maps. Changing values in arrays is much easier and quicker than hashmaps and given a grid dimension on a map it is very easy to get an array index. Also as far as I understand I'd still need to pass around inputdeps for hashmaps as they aren't handled automatically in the component systems.

    The dynamic buffer solution seems to be the correct way to go about this for me.