/// <summary>
        /// Constructor. Do not use in system's OnCreate when simulation is Havok, as it won't pick up HavokConfiguration properly.
        /// </summary>
        public ImmediatePhysicsWorldStepper(SystemBase system, uint physicsWorldIndex)
        {
            SimulationContext = new SimulationContext();
#if HAVOK_PHYSICS_EXISTS
            Havok.Physics.HavokConfiguration config = system.HasSingleton <Havok.Physics.HavokConfiguration>() ?
                                                      system.GetSingleton <Havok.Physics.HavokConfiguration>() : Havok.Physics.HavokConfiguration.Default;

            // We want to show different physics worlds in separate VDBs, so each one needs its own port
            config.VisualDebugger.Port += (int)physicsWorldIndex;
            HavokSimulationContext      = new Havok.Physics.SimulationContext(config);
#endif
        }
        public virtual IEnumerator LoadScenes([ValueSource(nameof(GetScenes))] string scenePath)
        {
            // Log scene name in case Unity crashes and test results aren't written out.
            Debug.Log("Loading " + scenePath);
            LogAssert.Expect(LogType.Log, "Loading " + scenePath);

            // Wait for next frame
            yield return(null);

            // Number of steps to simulate
            const int k_StopAfterStep = 100;

            // Number of worlds to simulate
            const int k_NumWorlds = 4;

            // Number of threads in each of the runs (3rd run is single threaded simulation)
            NativeArray <int> numThreadsPerRun = new NativeArray <int>(k_NumWorlds, Allocator.Persistent);

            numThreadsPerRun[0] = 8;
            numThreadsPerRun[1] = 4;
            numThreadsPerRun[2] = 0;
            numThreadsPerRun[3] = -1;

            // Load the scene and wait 2 frames
            SceneManager.LoadScene(scenePath);

            yield return(null);

            yield return(null);

            var sampler = DefaultWorld.GetOrCreateSystem <BuildPhysicsWorldSampler>();

            sampler.BeginSampling();

            while (!sampler.FinishedSampling)
            {
                yield return(new WaitForSeconds(0.05f));
            }

            var buildPhysicsWorld = DefaultWorld.GetOrCreateSystem <BuildPhysicsWorld>();
            var stepComponent     = PhysicsStep.Default;

            if (buildPhysicsWorld.HasSingleton <PhysicsStep>())
            {
                stepComponent = buildPhysicsWorld.GetSingleton <PhysicsStep>();
            }

            // Extract original world and make copies
            List <PhysicsWorld> physicsWorlds = new List <PhysicsWorld>(k_NumWorlds);

            physicsWorlds.Add(sampler.PhysicsWorld.Clone());

            physicsWorlds.Add(physicsWorlds[0].Clone());
            physicsWorlds.Add(physicsWorlds[1].Clone());
            physicsWorlds.Add(physicsWorlds[2].Clone());

            NativeArray <int> buildStaticTree = new NativeArray <int>(1, Allocator.Persistent);

            buildStaticTree[0] = 1;

            // Simulation step input
            var stepInput = new SimulationStepInput()
            {
                Gravity                   = stepComponent.Gravity,
                NumSolverIterations       = stepComponent.SolverIterationCount,
                SynchronizeCollisionWorld = true,
                TimeStep                  = Time.fixedDeltaTime
            };

            // Step the simulation on all worlds
            for (int i = 0; i < physicsWorlds.Count; i++)
            {
                int threadCountHint = numThreadsPerRun[i];
                if (threadCountHint == -1)
                {
                    stepInput.World = physicsWorlds[i];
                    stepInput.World.CollisionWorld.BuildBroadphase(
                        ref stepInput.World, stepInput.TimeStep, stepInput.Gravity, true);

#if HAVOK_PHYSICS_EXISTS
                    if (SimulateHavok)
                    {
                        var simulationContext = new Havok.Physics.SimulationContext(Havok.Physics.HavokConfiguration.Default);
                        for (int step = 0; step < k_StopAfterStep; step++)
                        {
                            simulationContext.Reset(ref stepInput.World);
                            new StepHavokJob
                            {
                                Input             = stepInput,
                                SimulationContext = simulationContext
                            }.Schedule().Complete();
                        }

                        simulationContext.Dispose();
                    }
                    else
#endif
                    {
                        var simulationContext = new SimulationContext();
                        for (int step = 0; step < k_StopAfterStep; step++)
                        {
                            simulationContext.Reset(ref stepInput.World);
                            new StepJob
                            {
                                Input             = stepInput,
                                SimulationContext = simulationContext
                            }.Schedule().Complete();
                        }

                        simulationContext.Dispose();
                    }
                }
                else
                {
#if HAVOK_PHYSICS_EXISTS
                    if (SimulateHavok)
                    {
                        var simulation = new Havok.Physics.HavokSimulation(Havok.Physics.HavokConfiguration.Default);
                        stepInput.World = physicsWorlds[i];
                        stepInput.World.CollisionWorld.ScheduleBuildBroadphaseJobs(
                            ref stepInput.World, stepInput.TimeStep, stepInput.Gravity, buildStaticTree, default, threadCountHint).Complete();