Search Unity

ComponentSystem doesn't run when ComponentGroup has no entities but EntityArchetypeQuery has

Discussion in 'Entity Component System' started by pahe, Dec 14, 2018.

  1. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Hi guys.
    I'm transitioning some of my ComponentSystems currently to use chunk iteration. Now I experienced the problem that one of my systems isn't running when the system has a ComponentGroup without entities to process and a EntityArchetypeQuery which has some. I'm wondering now why that is the case, as I'd have expected that either one with entities would be enough to run the system.

    I checked the entity debugger what's going on and it shows that the ComponentGroup hasn't found any entities, but the EntityArchetypeQuery has. Still the system isn't running. Can anyone explain me why this is the case and what I am missing?

    Another note: If I only use only either ComponentGroup or the EntityArchetypeQuery then the system runs fine, but not both ways together.

    system_bug.png

    My code for the system looks like this. I could split this into two different systems (as I said, I am transitioning my systems currently), but I had no need for that when both processes used ComponentGroups:

    Code (CSharp):
    1. using System;
    2. using Assets.Scripts.Battle;
    3. using Battle;
    4. using Components;
    5. using Components.Fields;
    6. using Components.SkillEffects;
    7. using Unity.Collections;
    8. using Unity.Entities;
    9. using UnityEngine;
    10. using Random = UnityEngine.Random;
    11.  
    12. namespace Systems
    13. {
    14.     public sealed class TLTBattleElementUpdatingSystem : ComponentSystem
    15.     {
    16.         private ComponentGroup battleElementBurnComponentGroup;
    17.         private EntityArchetypeQuery battleElementArchetypeQuery;
    18.  
    19.         private EntityManager entityManager;
    20.  
    21.         protected override void OnCreateManager()
    22.         {
    23.             entityManager = World.Active.GetOrCreateManager<EntityManager>();
    24.  
    25.             battleElementBurnComponentGroup = GetComponentGroup(ComponentType.ReadOnly<TLTBattleElementBurnData>());
    26.  
    27.             battleElementArchetypeQuery = new EntityArchetypeQuery
    28.             {
    29.                 All = new ComponentType[] {typeof(TLTBattleElementData), typeof(TLTBattleFieldView)},
    30.                 None = Array.Empty<ComponentType>(),
    31.                 Any = new ComponentType[] {typeof(TLTBattleTurnEndedData), typeof(TLTFieldBurnedData)}
    32.             };
    33.         }
    34.  
    35.         protected override void OnUpdate()
    36.         {
    37.             ProcessElementUpdating();
    38.  
    39.             ProcessElementBurning();
    40.         }
    41.  
    42.         private void ProcessElementUpdating()
    43.         {
    44.             var chunks = entityManager.CreateArchetypeChunkArray(battleElementArchetypeQuery, Allocator.TempJob);
    45.             var battleElementArchetype = GetArchetypeChunkComponentType<TLTBattleElementData>();
    46.             //var fieldArchetype = GetArchetypeChunkComponentType<TLTBattleFieldView>(); // not possible for monobehaviours (atm?)
    47.             var entitiesArchetype = GetArchetypeChunkEntityType();
    48.  
    49.             for (int i = 0; i < chunks.Length; i++)
    50.             {
    51.                 var chunk = chunks[i];
    52.                 var battleElements = chunk.GetNativeArray(battleElementArchetype);
    53.                 var entities = chunk.GetNativeArray(entitiesArchetype);
    54.  
    55.                 for (int j = 0; j < battleElements.Length; j++)
    56.                 {
    57.                     var element = battleElements[j];
    58.                     var entity = entities[j];
    59.                     var fieldView = entityManager.GetComponentObject<TLTBattleFieldView>(entity); // get MB via entity then
    60.  
    61.                     // ... do some stuff
    62.                 }
    63.             }
    64.  
    65.             chunks.Dispose();
    66.         }
    67.  
    68.         private void ProcessElementBurning()
    69.         {
    70.             var burnElementsLength = battleElementBurnComponentGroup.CalculateLength();
    71.             var burnElements = battleElementBurnComponentGroup.GetComponentDataArray<TLTBattleElementBurnData>();
    72.             var burnElementsEntities = battleElementBurnComponentGroup.GetEntityArray();
    73.  
    74.             for (int i = 0; i < burnElementsLength; i++)
    75.             {
    76.                 var burnElement = burnElements[i];
    77.                 var entity = burnElementsEntities[i];
    78.                 var elementData = entityManager.GetComponentData<TLTBattleElementData>(burnElement.AffectedEntity);
    79.                 var elementView = entityManager.GetComponentObject<TLTBattleElementView>(burnElement.AffectedEntity);
    80.  
    81.                 // ... do some other stuff
    82.  
    83.             }
    84.         }
    85.     }
    86. }
    87.  
     
    Last edited: Dec 14, 2018
  2. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    The behaviour seems strange, but my understanding is the recommended way to get ArchetypeChunkArray is via the component anyway. I guess related to this.
     
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Behaviour absolutely correct, this is how systems works. Recommended approach it's use ArchetypeChunkArray directly if you need LLAPI, if you don't, you use IJobRocesComponentData\IJobRocesComponentDataWithEntity, getting ACA from CG is only additional approach.

    @pahe your behaviour works as expected.
    1. If system hasn't any injections\CG - it's runs always, same as with [AlwaysUpdateSystem] attribute.
    2. If your system has Injection\CG, you not use [AlwaysUpdateSystem] and there is no entities - it's not runs.
    Thus if you have CG and EAQ both - here second case, because you have CG request, and systems checks entities, if you use them separateley then systems with CG runs when entities exists (2 case) and system with EAQ runs always and checks entities in OnUpdate (1 case).
     
    pahe and timmehhhhhhh like this.
  4. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    ah right, i forgot system OnUpdate() runs by default like that.