Search Unity

Shutdown ECS/Scene switching

Discussion in 'Entity Component System' started by hardcodednumber, Jul 24, 2020.

  1. hardcodednumber

    hardcodednumber

    Joined:
    May 26, 2014
    Posts:
    88
    I want to switch to a non-ECS scene, i.e Main Menu. Every time I try to clean things up, I get a ton of errors.

    This is what I have so far
    Code (CSharp):
    1.     private void OnDestroy()
    2.     {
    3.         if (_blobStore != null) {
    4.             _blobStore.Dispose();
    5.         }
    6.  
    7.         _entityManager.DestroyEntity(_entityManager.UniversalQuery);
    8.         _world.DestroyAllSystemsAndLogException();
    9.         _world.Dispose();
    10.  
    11.         _gameObjectSettings = null;
    12.         _world = null;
    13.     }
    I've tried various combinations, but I still receive multiple errors:
    ArgumentException: The World has already been Disposed.
    Unity.Entities.World.Dispose () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/World.cs:268)
    Startup.OnDestroy () (at Assets/Source/Startup.cs:58)​

    InvalidOperationException: object is not initialized or has already been destroyed
    Unity.Entities.ComponentSystemBase.CheckedState () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ComponentSystemBase.cs:331)
    Unity.Entities.ComponentSystem.Update () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ComponentSystem.cs:86)
    Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelegateWrapper.TriggerUpdate () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ScriptBehaviourUpdateOrder.cs:196)​

    Before, I only had the blob asset dispose. Everything was fine. Now If I only dispose of the blob asset reference I get this error:

    InvalidOperationException: The BlobAssetReference is not valid. Likely it has already been unloaded or released.
    Unity.Entities.BlobAssetReferenceData.ValidateNonBurst () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/Blobs.cs:212)
    Unity.Entities.BlobAssetReferenceData.ValidateNotNull () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/Blobs.cs:228)
    Unity.Entities.BlobAssetReference`1[T].get_Value () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/Blobs.cs:309)
    Unity.Physics.Broadphase+PrepareDynamicBodyDataJob.ExecuteImpl (System.Int32 index, System.Single aabbMargin, Unity.Mathematics.float3 gravity, System.Single timeStep, Unity.Collections.NativeSlice`1[T] rigidBodies, Unity.Collections.NativeSlice`1[T] motionDatas, Unity.Collections.NativeSlice`1[T] motionVelocities, Unity.Collections.NativeArray`1[T] aabbs, Unity.Collections.NativeArray`1[T] points, Unity.Collections.NativeArray`1[T] filtersOut) (at Library/PackageCache/com.unity.physics@0.3.2-preview/Unity.Physics/Collision/World/Broadphase.cs:810)
    Unity.Physics.Broadphase+PrepareDynamicBodyDataJob.Execute (System.Int32 index) (at Library/PackageCache/com.unity.physics@0.3.2-preview/Unity.Physics/Collision/World/Broadphase.cs:790)
    Unity.Jobs.IJobParallelForExtensions+ParallelForJobStruct`1[T].Execute (T& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at <94c5f4c38cdc42d2b006f8badef04394>:0)​
     
    Mikael-H likes this.
  2. hardcodednumber

    hardcodednumber

    Joined:
    May 26, 2014
    Posts:
    88
    I looked at this post: https://forum.unity.com/threads/ecs-tear-down-and-restart.539722/

    And tried this:
    Code (CSharp):
    1.    
    2. private void OnDestroy()
    3.     {
    4.         _entityManager.DestroyEntity(_entityManager.UniversalQuery);
    5.  
    6.         if (_world.IsCreated) {
    7.             _world.Dispose();
    8.             _world.DestroyAllSystemsAndLogException();
    9.         }
    10.  
    11.         if (_blobStore != null) {
    12.             _blobStore.Dispose();
    13.         }
    14.     }
    I now only have one error:
    InvalidOperationException: object is not initialized or has already been destroyed
    Unity.Entities.ComponentSystemBase.CheckedState () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ComponentSystemBase.cs:331)
    Unity.Entities.ComponentSystem.Update () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ComponentSystem.cs:86)
    Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelegateWrapper.TriggerUpdate () (at Library/PackageCache/com.unity.entities@0.10.0-preview.6/Unity.Entities/ScriptBehaviourUpdateOrder.cs:196)
    I guess I'll try to find a workaround. Maybe just destroying the entities, and never switching the scene. Just add the menu scene on top.
     
  3. hardcodednumber

    hardcodednumber

    Joined:
    May 26, 2014
    Posts:
    88
    I'm going to assuming that no one has had these issues.
     
  4. manpower13

    manpower13

    Joined:
    Dec 22, 2013
    Posts:
    140
    Hi!
    I have the same issues in my unit tests. I haven't found a way to properly dispose a world and recreate one after.

    I assumed it was a bug and didn't have the time to properly debug it. Let me know if you found a workaround!
     
  5. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    260
    Out of curiosity why do you need to destroy the world?

    If you destroy all entities with the universal query, then you shouldn't need to dispose of the world. I know that the systems will still exist, but with no entities to process I doubt they would any kind of noticeable performance impact.

    Now if you need to a different world (i.e. a custom bootstrap) for different levels then I could see the need for disposing a world. I'm also curious to know how to do this for this use case.
     
  6. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Never tried something like that, but shouldn't you need to use
    ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(_world)
    before destroying all systems?

    EDIT: also, I think you need to destroy the systems before disposing the world
    Code (CSharp):
    1. private void OnDestroy()
    2. {
    3.     if (_world.IsCreated) {
    4.         _entityManager.DestroyEntity(_entityManager.UniversalQuery);
    5.         ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(_world);
    6.         _world.DestroyAllSystemsAndLogException();
    7.         _world.Dispose();
    8.     }
    9.     if (_blobStore != null) {
    10.         _blobStore.Dispose();
    11.     }
    12. }
     
  7. Ryunis

    Ryunis

    Joined:
    Dec 23, 2014
    Posts:
    24
    (Disclaimer: Opinion)
    This might not be a solution to your problem, but I agree with the notion that you probably shouldn't need to destroy the whole world. Systems shouldn't contain any state to make that necessary. Spawning a set of entities should not lead to different results depending on wether or not similar archetypes existed previously.
     
    manpower13 likes this.
  8. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Or you can clean the state inside OnStopRunning. If it is a System which always update then it may be needed a different approach, but I still think that destroying the World is unnecessary unless you want to create a totally different one later.
     
    manpower13 likes this.
  9. hardcodednumber

    hardcodednumber

    Joined:
    May 26, 2014
    Posts:
    88
    I was using unity version 2019.3.2f1, and upgraded to 2020.1.0f1 and everything is fine. I think there is a bug with that version.
     
  10. hardcodednumber

    hardcodednumber

    Joined:
    May 26, 2014
    Posts:
    88
    @brunocoimbra I did have try what you had before posting to the forums, and it would still throw exceptions. I think the unity version was the problem.
     
  11. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Oh, right, actually ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop was introduced in Entities 0.13, which is only supported on 2020.1
     
    manpower13 likes this.
  12. cort_of_unity

    cort_of_unity

    Unity Technologies

    Joined:
    Aug 15, 2018
    Posts:
    98
    Nope; World.Dispose() will destroy all its systems, and its EntityManager (which will destroy all the World's Entities). So, you shouldn't need to do any of those things when destroying a World.

    World.Dispose() does not call ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(), because it's actually a fairly expensive function. If you manually Dispose() a World, you should manually remove it from the player loop. Leaving disposed Worlds in the player loop isn't (puts on shades) the end of the world (yeaaaaaaaaaah!), as it will check if the World's systems are null before trying to update them. But it does clutter up the player loop with extra entries, which could have an impact on performance after a while.
     
  13. uknowunity

    uknowunity

    Joined:
    Jul 12, 2018
    Posts:
    15
    Would this be an good approach for using ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop()? Because just deleting entities and disposing world still gives some errors in my project.

    Code (CSharp):
    1. var entitymanager = World.DefaultGameObjectInjectionWorld.EntityManager;
    2. entitymanager.DestroyEntity(entitymanager.UniversalQuery);
    3. ScriptBehaviourUpdateOrder.RemoveWorldFromCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld);
    4. DefaultWorldInitialization.Initialize("Default World", false);
    5. SceneManager.LoadScene("World", LoadSceneMode.Single);
    After applying this code the systems the hierachy is lost in resetted entities created from the conversion.. I can see all child enities in the hierachy non have an parent. but maybe this could be an bug from DOTS editor
     
    Last edited: Aug 14, 2020