Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

ArchetypeChunkComponentType<T> and ComponentDataFromEntity<T> conflict?

Discussion in 'Entity Component System' started by Lieene-Guo, Feb 26, 2020.

  1. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    I have a problem when I need to read and write to the same ComponentData type, in Parallel.
    Here's the code.
    Code (CSharp):
    1.  
    2. [BurstCompile]
    3. struct ChildTimeChunkJob : IJobChunk
    4. {
    5.     [NativeDisableParallelForRestriction]
    6.     public ArchetypeChunkComponentType<Time> timeTp;
    7.     [ReadOnly]
    8.     public ArchetypeChunkComponentType<TimeScale> timeScaleTp;
    9.  
    10.     //field to access parent delta time
    11.     [ReadOnly]
    12.     public ArchetypeChunkSharedComponentType<ChildTime> childTp;
    13.     [ReadOnly]
    14.     public NativeArray<SCidEid> scid_eid;
    15.     [NativeDisableParallelForRestriction]
    16.     public ComponentDataFromEntity<Time> timeAccess;
    17.  
    18.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    19.     {
    20.         var chunkTime = chunk.GetNativeArray(timeTp);
    21.         var count = chunk.Count;
    22.         var idx = scid_eid.BinarySearch(new SCidEid()
    23.             { scid = chunk.GetSharedComponentIndex(childTp), eid = default });
    24.         var deltaTime = idx < 0 ? 0f : timeAccess[scid_eid[idx].eid].deltaTime;
    25.         if (chunk.Has(timeScaleTp))//has time scale
    26.         {
    27.             var chunkTimeScale = chunk.GetNativeArray(timeScaleTp);
    28.             for (int i = 0; i < count; i++)
    29.                 chunkTime[i] = chunkTimeScale[i].Tick(chunkTime[i], deltaTime);
    30.         }
    31.         else
    32.               for (int i = 0; i < count; i++)
    33.                   chunkTime[i] = chunkTime[i].Tick(deltaTime);//no time scale
    34.     }
    35. }
    36.  
    It is a simple time update IJobChunk, the only thing special is that there's a "parent" time concept that "child" time can update based on "parent" time. I am ranking chunks by depth. So I'm sure no reading while writing is ever going to happen.
    But! I keep getting this exception :
    "The writable NativeArray ChildTimeChunkJob.Data.timeTp is the same NativeArray as ChildTimeChunkJob.Data.timeAccess, two NativeArrays may not be the same (aliasing)."
    Looks like they are using the same internal NativeArray.
    But I need ArchetypeChunkComponentType<Time> for this IJobChunk to work. Meanwhile, I need ComponentDataFromEntity<Time> to get time from other entities.

    What should I do about this? or dose ArchetypeChunkComponentType<Time> work the same way as ComponentDataFromEntity<Time> so I can get <Time> from any Entity by only using ArchetypeChunkComponentType<Time>?
     
  2. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    I figure this out myself.
    ComponentDataFromEntity<Time> can get and set. So I can use only ComponentDataFromEntity<Time> togather with a ArchetypeChunkEntityType to get entity from Chunk then time.
     
  3. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    ComponentDataFromEntity has a slower indexing pattern as it searches over all entitise by entity id and version.
    for better read and write to the same ComponentData type pattern.
    ComponentDataFromEntity should be able to be converted to ArchetypeChunkEntityType. as they are essentially the same. So in an IJobChunk ComponentDataFromEntity can be used to access both chunk data and/or all ComponentData of a certain type.
     
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    It's not searching by all entities it getting chunk by entity index and getting index from this chunk (by
    EntityInChunk*) and returning pointer to data by declared type from type storage by type index just like simple memory offset, and just restoring data by this pointer. It's O(1) lookup.
     
  5. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    Sure, ComponentDataFromEntity is not that slow. but as I'm updating each of the data in a chunk.
    NativeArray indexer is much better than lookup by entity index.
    Code (CSharp):
    1. public ArchetypeChunkComponentType<Time> timeTp;
    2. var chunkTime = chunk.GetNativeArray(timeTp)
    3. for (int i = 0; i < count; i++) { chunkTime[i] = chunkTime[i].Tick(deltaTime);}
    is faster than
    Code (CSharp):
    1.  
    2. [NativeDisableParallelForRestriction] public ComponentDataFromEntity<Time> timeAccess;
    3. var chunkEids = chunk.GetNativeArray(entityTp);
    4. var chunkTime = chunk.GetNativeArray(timeTp);
    5. var count = chunk.Count;
    6. for (int i = 0; i < count; i++)
    7. {
    8.     var eid = chunkEids[i];
    9.     timeAccess[eid] = timeAccess[eid].Tick(deltaTime);
    10. }
    But I still have to use ComponentDataFromEntity<T> as I need to read data from outside of the current chunk.
    Here's the complete IJobChunk.
    Code (CSharp):
    1. [BurstCompile]
    2. struct ChildTimeChunkJob : IJobChunk
    3. {
    4.     [ReadOnly] public ArchetypeChunkEntityType entityTp;
    5.     [ReadOnly] public ArchetypeChunkComponentType<TimeScale> timeScaleTp;
    6.  
    7.     //field to access parent delta time
    8.     [ReadOnly] public ArchetypeChunkSharedComponentType<ChildTime> childTp;
    9.     [ReadOnly] public NativeList<SCidEid> scid_eid;
    10.     [NativeDisableParallelForRestriction] public ComponentDataFromEntity<Time> timeAccess;
    11.  
    12.     public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
    13.     {
    14.         var chunkEids = chunk.GetNativeArray(entityTp);
    15.         //var chunkTime = chunk.GetNativeArray(timeTp);
    16.         var count = chunk.Count;
    17.         var idx = scid_eid.BinarySearch(
    18.              new SCidEid()
    19.             { scid = chunk.GetSharedComponentIndex(childTp), eid = default }
    20.         );
    21.         var deltaTime = idx < 0 ? 0f : timeAccess[scid_eid[idx].eid].deltaTime;//deltaTime
    22.         if (chunk.Has(timeScaleTp))//has time scale
    23.         {
    24.             var chunkTimeScale = chunk.GetNativeArray(timeScaleTp);
    25.             for (int i = 0; i < count; i++)
    26.             {
    27.                 var eid = chunkEids[i];
    28.                 timeAccess[eid] = chunkTimeScale[i].Tick(timeAccess[eid], deltaTime);
    29.             }
    30.         }
    31.         else
    32.         {
    33.             for (int i = 0; i < count; i++)
    34.             {
    35.                 var eid = chunkEids[i];
    36.                 timeAccess[eid] = timeAccess[eid].Tick(deltaTime);
    37.             }
    38.         }
    39.     }
    40. }
     
    Last edited: Feb 27, 2020