Reset ECS world and jobs to start fresh again

I’m trying to develop a physics based destruction mini-game and I’ve been stuck for a couple of days when I’m trying to reload the whole scene to start fresh again.

Here is the video of what happens:

I’m using several system using jobs to detect collision like this:

[System.Serializable]
    public partial class CollisioWallToActorDetectionSystem : SystemBase
    {
        private StepPhysicsWorld stepPhysicsWorld;
        private EndSimulationEntityCommandBufferSystem commandBufferSystem;

        protected override void OnCreate()
        {
            stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
            commandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
        }

        protected override void OnUpdate()
        {
            var jobHandle = Dependency;
            Dependency.Complete();

            var applicationJob = new ApplicationWallToRagdollJob
            {
                actorCollider = GetComponentDataFromEntity<RagdollComponent>(),
                wallCollider = GetComponentDataFromEntity<WallColliderData>()
            };

            Dependency = applicationJob.Schedule(stepPhysicsWorld.Simulation, Dependency);
               commandBufferSystem.AddJobHandleForProducer(Dependency);
        }

        [BurstCompile]
        private struct ApplicationWallToRagdollJob : ICollisionEventsJob
        {
            public ComponentDataFromEntity<RagdollComponent> actorCollider;
            public ComponentDataFromEntity<WallColliderData> wallCollider;           

            public void Execute(CollisionEvent triggerEvent)
            {
                if (wallCollider.HasComponent(triggerEvent.EntityA))
                {
                    if (actorCollider.HasComponent(triggerEvent.EntityB))
                    {
                        WallColliderData wall = wallCollider[triggerEvent.EntityA];
                        wall.Destroy = true;
                        wallCollider[triggerEvent.EntityA] = wall;
                    }
                }

                if (wallCollider.HasComponent(triggerEvent.EntityB))
                {
                    if (actorCollider.HasComponent(triggerEvent.EntityA))
                    {
                        WallColliderData wall = wallCollider[triggerEvent.EntityB];
                        wall.Destroy = true;
                        wallCollider[triggerEvent.EntityB] = wall;
                    }
                }
            }
        }
    }

So, what should I do to start clean? I’ve tried the few things I’ve found on Internet unsuccessfully and I’ve run out of options.

I’ve had issues myself in the past with clearing a world and reusing it. It looked like a use case Unity had not tested properly. I did not find a solution, but here’s the workaround I use:

Create a brand new world and dispose of the previous one. This brings a couple of challenges because you have to rebind the world to the player loop, but at least it works.

If you destroy all entities besides prefabs, and reinstantiate them again, tha should solve the problem.

Thanks a lot!! It worked. The code looks like this to reset. I don’t even need to reload the scene in order to start fresh:

        public void DestroyAllEntities()
        {
            World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(World.DefaultGameObjectInjectionWorld.EntityManager.UniversalQuery);
            World.DisposeAllWorlds();
            DefaultWorldInitialization.Initialize("Base World", false);
            ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld);
        }

World.DefaultGameObjectInjectionWorld.EntityManager.DestroyEntity(World.DefaultGameObjectInjectionWorld.EntityManager.UniversalQuery);

You don’t need this, you’re disposing world so it’ll clean up by itself. This will just slow it down.

For the future programmers who look into reseting the ECS system this is the final solution that work for me at the moment I’m posting:

        public void CleanAndRestartECS()
        {
            var defaultWorld = World.DefaultGameObjectInjectionWorld;
            defaultWorld.EntityManager.CompleteAllJobs();
            foreach (var system in defaultWorld.Systems)
            {
                system.Enabled = false;
            }
            defaultWorld.Dispose();
            DefaultWorldInitialization.Initialize("Default World", false);
            if (!ScriptBehaviourUpdateOrder.IsWorldInCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld))
            {
                ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld);
            }   
            SceneManager.LoadScene("Game", LoadSceneMode.Single);
        }

But how You destroy entities with certain tag? Like I don’t need to destroy some entities after restarting scene

Looks like this is indeed working (script by @Esteban-Gallardo).

I modified script a little so we no longer have this strings around.

        public void CleanAndRestartECS()
        {
            var worldName = World.DefaultGameObjectInjectionWorld.Name;
            var defaultWorld = World.DefaultGameObjectInjectionWorld;
            defaultWorld.EntityManager.CompleteAllTrackedJobs();
            foreach (var system in defaultWorld.Systems)
            {
                system.Enabled = false;
            }
            defaultWorld.Dispose();
            DefaultWorldInitialization.Initialize(worldName, false);
            if (!ScriptBehaviourUpdateOrder.IsWorldInCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld))
            {
                ScriptBehaviourUpdateOrder.AppendWorldToCurrentPlayerLoop(World.DefaultGameObjectInjectionWorld);
            }

            var scene = SceneManager.GetActiveScene();
            var sceneName = scene.name;
            SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
        }