Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Bug Idiomatic foreach throws Entities.ForEach exception.

Discussion in 'Entity Component System' started by WAYNGames, Oct 27, 2022.

  1. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    995
    Hello,

    My understanding is that the idiomatic foreach syntax is main thread only. So it should support structural change.

    However, this code :
    Code (CSharp):
    1. public partial struct SpawnerSystem : ISystem
    2. {
    3.     public void OnCreate(ref SystemState state)
    4.     {
    5.     }
    6.  
    7.     public void OnDestroy(ref SystemState state)
    8.     {
    9.     }
    10.  
    11.     public void OnUpdate(ref SystemState state)
    12.     {
    13.         // For each spawner
    14.         foreach(var (spawner,path) in SystemAPI.Query<RefRW<SpawnerData>,DynamicBuffer<Waypoints>>()){
    15.        
    16.             spawner.ValueRW.TimeUntilNextSpawn -= SystemAPI.Time.DeltaTime;
    17.  
    18.             if(spawner.ValueRO.TimeUntilNextSpawn < 0)
    19.             {
    20.                 spawner.ValueRW.TimeUntilNextSpawn = spawner.ValueRO.Rate;
    21.  
    22.  
    23.                 Entity e = state.EntityManager.Instantiate(spawner.ValueRO.Prefab);
    24.                 DynamicBuffer<Waypoints> buffer = state.EntityManager.AddBuffer<Waypoints>(e);
    25.             }
    26.         }
    27.     }
    28. }

    throws an exception :

    Code (CSharp):
    1. InvalidOperationException: Structural changes are not allowed during Entities.ForEach. Please use EntityCommandBuffer or WithStructuralChanges instead.
    2. Unity.Entities.EntityDataAccess.CheckIsStructuralChange () (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityDataAccess.cs:346)
    3. Unity.Entities.EntityDataAccess.BeforeStructuralChange () (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityDataAccess.cs:418)
    4. Unity.Entities.EntityDataAccess.BeginStructuralChanges () (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityDataAccess.cs:428)
    5. Unity.Entities.EntityManager.AddComponent (Unity.Entities.Entity entity, Unity.Entities.ComponentType componentType) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityManager.cs:1456)
    6. Unity.Entities.EntityManager.AddComponent[T] (Unity.Entities.Entity entity) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityManager.cs:1520)
    7. Unity.Entities.EntityManager.AddBuffer[T] (Unity.Entities.Entity entity) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/EntityManager.cs:2636)
    8. SpawnerSystem.OnUpdate (Unity.Entities.SystemState& state) (at Assets/Scripts/Authoring/Spanwer.cs:101)
    9. SpawnerSystem.__codegen__OnUpdate (System.IntPtr self, System.IntPtr state) (at <45595ca27323447ababe86d6fdda3749>:0)
    10. Unity.Entities.SystemBaseRegistry+<>c__DisplayClass9_0.<SelectBurstFn>b__0 (System.IntPtr system, System.IntPtr state) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/SystemBaseRegistry.cs:228)
    11. UnityEngine.Debug:LogException(Exception)
    12. Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/Stubs/Unity/Debug.cs:19)
    13. Unity.Entities.<>c__DisplayClass9_0:<SelectBurstFn>b__0(IntPtr, IntPtr) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/SystemBaseRegistry.cs:232)
    14. Unity.Entities.UnmanagedUpdate_00001487$BurstDirectCall:wrapper_native_indirect_000001DA39F81448(IntPtr&, Void*)
    15. Unity.Entities.UnmanagedUpdate_00001487$BurstDirectCall:Invoke(Void*)
    16. Unity.Entities.WorldUnmanagedImpl:UnmanagedUpdate(Void*) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/WorldUnmanaged.cs:801)
    17. Unity.Entities.WorldUnmanagedImpl:UpdateSystem(SystemHandle) (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/WorldUnmanaged.cs:866)
    18. Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/ComponentSystemGroup.cs:664)
    19. Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/ComponentSystemGroup.cs:628)
    20. Unity.Entities.SystemBase:Update() (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/SystemBase.cs:406)
    21. Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@1.0.0-exp.8/Unity.Entities/ScriptBehaviourUpdateOrder.cs:526)
    22.  
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,687
    The thing that it's a main thread doesn't mean it automatically allows structural changes, you will see errors if you'll get (for example) lookup for some component (or will have loop where you just using syntax sugar like GetComponent() without EntityManager) and then will do structural change - your lookup will be invalid and you need to care about reinitializing your lookup (because structural changes happens and lookup can be invalid) otherwise you'll get error that lookup deallocated, for preventing that in codegened jobs like Entities.ForEach you see error like that. That's API doesn't support structural changes (as I'm aware off, as I didn't saw anything in that API you can use for enable structural changes) and intended to be used with ECB (can be temp initialized before loop and playedback after loop). Error technically doesn't related to Entities.ForEach itself, just EntityDataAccess safety using for EM method but have one hardcoded name despite the place it's called from.
    upload_2022-10-27_10-35-15.png
     
    WAYNGames likes this.