Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug AddComponentDuringStructuralChange crash

Discussion in 'Entity Component System' started by Dominique0, Dec 15, 2022.

  1. Dominique0

    Dominique0

    Joined:
    Jun 8, 2015
    Posts:
    26
    We're having some random crashes in a build (at least on PC and PS4) that points to AddComponentDuringStructuralChange or RemoveComponentDuringStructuralChange in a fairly simple system that add and remove components. Usualy, the order in which the add/remove/set component are called can cause a crash in a build and an error in the editor depending of their order if done in a foreach that loops more than once due to the structural change but never give any issues when looping once or without any foreach(). We've had the same crash also occur in another SystemBase without a foreach that was adding and removing components. Does it have anything to do with the order of the add/remove component? The crash happens very rarely.

    Running Unity 2021.3.14f1, ECS package 0.51.1-preview.21 and burst 1.8.1

    I have included a screenshot of the stack trace from the crash.

    Code (CSharp):
    1. [UpdateInGroup(typeof(VehicleSystemGroup))]
    2.     public partial class ActivateVehicleSystem : SystemBase
    3.     {
    4.         protected override void OnUpdate()
    5.         {
    6.             Entities.WithStructuralChanges().WithAll<Vehicle, VehicleInactive>().
    7.                 WithAny<PlayerCharacterActiveControl, PlayerCharacterNextControl>().
    8.                 ForEach((Entity vehicleEntity) =>
    9.             {
    10.                 EntityManager.RemoveComponent<VehicleInactive>(vehicleEntity);
    11.                 EntityManager.AddComponent<VehicleActive>(vehicleEntity);
    12.                 EntityManager.AddComponent<OnVehicleActivated>(vehicleEntity);
    13.                 EntityManager.AddComponent<EquipBlock>(vehicleEntity);
    14.             }).Run();
    15.         }
    16.     }
     

    Attached Files:

  2. Dominique0

    Dominique0

    Joined:
    Jun 8, 2015
    Posts:
    26
    Here is another exemple. It seems to have crashed on the line
    EntityManager.SetComponentData(playerEntity, breathContainer);

    Code (CSharp):
    1. [UpdateInGroup(typeof(SwimSystemGroup))]
    2.     [UpdateAfter(typeof(ActivateSwimSystem))]
    3.     public partial class DeactivateSwimSystem : SystemBase
    4.     {
    5.         private EntityQuery swimControllerQuery;
    6.         private EntityQuery playerQuery;
    7.  
    8.         private EntityQuery swimMoveQuery;
    9.        
    10.         protected override void OnCreate()
    11.         {
    12.             base.OnCreate();
    13.  
    14.             playerQuery = GetEntityQuery(ComponentType.ReadOnly<BreathContainer>());
    15.             swimMoveQuery = GetEntityQuery(ComponentType.ReadOnly<OnSwimMove>());
    16.            
    17.             RequireForUpdate(swimControllerQuery);
    18.             RequireForUpdate(playerQuery);
    19.         }
    20.  
    21.         protected override void OnUpdate()
    22.         {
    23.             Entity playerEntity = playerQuery.GetSingletonEntity();
    24.             bool isAlive = !EntityManager.HasComponent<Dead>(playerEntity);
    25.            
    26.             Entities.WithStructuralChanges().WithStoreEntityQueryInField(ref swimControllerQuery).
    27.                 WithAll<SwimController, SwimActive>().
    28.                 WithNone<OnSwimActivated>().
    29.                 WithNone<PlayerCharacterActiveControl, PlayerCharacterNextControl>().
    30.                 ForEach((Entity swimControllerEntity, ref SwimControllerWaterCurrent swimControllerWaterCurrent, in SwimAudio swimAudio,
    31.                     in SwimControllerComponentObjects swimControllerComponentObjects) =>
    32.                 {
    33.                     Rigidbody rigidbody = swimControllerComponentObjects.Rigidbody;
    34.                     BreathContainer breathContainer = EntityManager.GetComponentData<BreathContainer>(playerEntity);
    35.                    
    36.                     if (isAlive)
    37.                     {
    38.                         breathContainer.Breath = breathContainer.MaxBreath;
    39.                         EntityManager.SetComponentData(playerEntity, breathContainer);
    40.                     }
    41.  
    42.                     EntityManager.RemoveComponent<SwimActive>(swimControllerEntity);
    43.                     EntityManager.RemoveComponent<SwimTouchFloor>(swimControllerEntity);
    44.                     EntityManager.AddComponent<SwimInactive>(swimControllerEntity);
    45.                     EntityManager.AddComponent<OnSwimDeactivated>(swimControllerEntity);
    46.                    
    47.                     EntityManager.RemoveComponent<EquipBlock>(swimControllerEntity);
    48.  
    49.                     EntityManager.RemoveComponent<OnSwimMove>(swimMoveQuery);
    50.                    
    51.                     swimControllerWaterCurrent.CurrentForce = float3.zero;
    52.                    
    53.                     rigidbody.velocity = Vector3.zero;
    54.                     rigidbody.gameObject.SetActive(false);
    55.                     EntityManager.SetEnabled(swimAudio.AboveWaterLoopAudioElement, false);
    56.                     EntityManager.SetEnabled(swimAudio.UnderWaterLoopAudioElement, false);
    57.                    
    58.                     if (swimAudio.GetOutPrefab != Entity.Null)
    59.                     {
    60.                         EntityManager.CreateAudioEvent(swimAudio.GetOutPrefab);
    61.                     }
    62.                     if (isAlive && breathContainer.Ratio < 0.3f && swimAudio.AirGaspPrefab != Entity.Null)
    63.                     {
    64.                         EntityManager.CreateAudioEvent(swimAudio.AirGaspPrefab);
    65.                     }
    66.             }).Run();
    67.         }
    68.     }
     

    Attached Files:

  3. maxxa05

    maxxa05

    Joined:
    Nov 17, 2012
    Posts:
    186
    To be clear, the call stack in the first post was in 0.17.0, in which the same bug happened. In this version, this is the line in EntityComponentStore where the crash happens: upload_2022-12-15_16-6-11.png
     
  4. maxxa05

    maxxa05

    Joined:
    Nov 17, 2012
    Posts:
    186
    We've got several more points where this happens (On PS4 in this example). It seems to happen when it allocates a memory block for a new archetype? Could there a maximum amount of archetypes that can be created in the ECS?

    Capture d’écran 2022-12-19 144922.png

    Capture d’écran 2022-12-19 144632.png
     
  5. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    There is 16MB limit for archetypes. But you can extend that limit for your requirements (of course keep in mind that on your own risk)
    In
    EntityComponentStore.cs on
    line
    493

    Code (CSharp):
    1. entities->m_ArchetypeChunkAllocator = new BlockAllocator(AllocatorManager.Persistent, 16 * 1024 * 1024); // 16MB should be enough
    You can change that 16MB limit.
    And at the same time you should change that value in
    EntityQueryManager.cs
    on line
    25

    Code (CSharp):
    1. queryManager->m_GroupDataChunkAllocator = new BlockAllocator(AllocatorManager.Persistent, 16 * 1024 * 1024); // 16MB should be enough
     
    Dominique0 and maxxa05 like this.