Example #1
0
        protected override void OnUpdate()
        {
            // Make sure last frame's physics jobs are complete before any new ones start
            m_InputDependencyToComplete.Complete();

            // Combine implicit input dependency with the user one
            Dependency = JobHandle.CombineDependencies(Dependency, m_InputDependency);

            int numDynamicBodies = DynamicEntityGroup.CalculateEntityCount();
            int numStaticBodies  = StaticEntityGroup.CalculateEntityCount();
            int numJoints        = JointEntityGroup.CalculateEntityCount();

            int previousStaticBodyCount = PhysicsWorld.NumStaticBodies;

            // Resize the world's native arrays
            PhysicsWorld.Reset(
                numStaticBodies + 1, // +1 for the default static body
                numDynamicBodies,
                numJoints);

            if (PhysicsWorld.NumBodies == 0)
            {
                // If the static body count has changed, make sure to set the correct value to HaveStaticBodiesChanged
                if (PhysicsWorld.NumStaticBodies != previousStaticBodyCount)
                {
                    HaveStaticBodiesChanged[0] = 1;
                }
                else
                {
                    HaveStaticBodiesChanged[0] = 0;
                }

                m_OutputDependency = Dependency;

                ChainDependencies();

                // No bodies in the scene, no need to do anything else
                return;
            }

            // Extract types used by initialize jobs
            var entityType                     = GetEntityTypeHandle();
            var localToWorldType               = GetComponentTypeHandle <LocalToWorld>(true);
            var parentType                     = GetComponentTypeHandle <Parent>(true);
            var positionType                   = GetComponentTypeHandle <Translation>(true);
            var rotationType                   = GetComponentTypeHandle <Rotation>(true);
            var physicsColliderType            = GetComponentTypeHandle <PhysicsCollider>(true);
            var physicsVelocityType            = GetComponentTypeHandle <PhysicsVelocity>(true);
            var physicsMassType                = GetComponentTypeHandle <PhysicsMass>(true);
            var physicsMassOverrideType        = GetComponentTypeHandle <PhysicsMassOverride>(true);
            var physicsDampingType             = GetComponentTypeHandle <PhysicsDamping>(true);
            var physicsGravityFactorType       = GetComponentTypeHandle <PhysicsGravityFactor>(true);
            var physicsCustomTagsType          = GetComponentTypeHandle <PhysicsCustomTags>(true);
            var physicsConstrainedBodyPairType = GetComponentTypeHandle <PhysicsConstrainedBodyPair>(true);
            var physicsJointType               = GetComponentTypeHandle <PhysicsJoint>(true);

            // Determine if the static bodies have changed in any way that will require the static broadphase tree to be rebuilt
            JobHandle staticBodiesCheckHandle = default;

            HaveStaticBodiesChanged[0] = 0;
            {
                if (PhysicsWorld.NumStaticBodies != previousStaticBodyCount)
                {
                    HaveStaticBodiesChanged[0] = 1;
                }
                else
                {
                    staticBodiesCheckHandle = new Jobs.CheckStaticBodyChangesJob
                    {
                        LocalToWorldType    = localToWorldType,
                        ParentType          = parentType,
                        PositionType        = positionType,
                        RotationType        = rotationType,
                        PhysicsColliderType = physicsColliderType,
                        m_LastSystemVersion = LastSystemVersion,
                        Result = HaveStaticBodiesChanged
                    }.ScheduleParallel(StaticEntityGroup, 1, Dependency);
                }
            }

            using (var jobHandles = new NativeList <JobHandle>(4, Allocator.Temp))
            {
                // Static body changes check jobs
                jobHandles.Add(staticBodiesCheckHandle);

                // Create the default static body at the end of the body list
                // TODO: could skip this if no joints present
                jobHandles.Add(new Jobs.CreateDefaultStaticRigidBody
                {
                    NativeBodies       = PhysicsWorld.Bodies,
                    BodyIndex          = PhysicsWorld.Bodies.Length - 1,
                    EntityBodyIndexMap = PhysicsWorld.CollisionWorld.EntityBodyIndexMap.AsParallelWriter(),
                }.Schedule(Dependency));

                // Dynamic bodies.
                // Create these separately from static bodies to maintain a 1:1 mapping
                // between dynamic bodies and their motions.
                if (numDynamicBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType            = entityType,
                        LocalToWorldType      = localToWorldType,
                        ParentType            = parentType,
                        PositionType          = positionType,
                        RotationType          = rotationType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex     = 0,
                        RigidBodies        = PhysicsWorld.Bodies,
                        EntityBodyIndexMap = PhysicsWorld.CollisionWorld.EntityBodyIndexMap.AsParallelWriter(),
                    }.ScheduleParallel(DynamicEntityGroup, 1, Dependency));

                    jobHandles.Add(new Jobs.CreateMotions
                    {
                        PositionType             = positionType,
                        RotationType             = rotationType,
                        PhysicsVelocityType      = physicsVelocityType,
                        PhysicsMassType          = physicsMassType,
                        PhysicsMassOverrideType  = physicsMassOverrideType,
                        PhysicsDampingType       = physicsDampingType,
                        PhysicsGravityFactorType = physicsGravityFactorType,

                        MotionDatas      = PhysicsWorld.MotionDatas,
                        MotionVelocities = PhysicsWorld.MotionVelocities
                    }.ScheduleParallel(DynamicEntityGroup, 1, Dependency));
                }

                // Now, schedule creation of static bodies, with FirstBodyIndex pointing after
                // the dynamic and kinematic bodies
                if (numStaticBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType            = entityType,
                        LocalToWorldType      = localToWorldType,
                        ParentType            = parentType,
                        PositionType          = positionType,
                        RotationType          = rotationType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex     = numDynamicBodies,
                        RigidBodies        = PhysicsWorld.Bodies,
                        EntityBodyIndexMap = PhysicsWorld.CollisionWorld.EntityBodyIndexMap.AsParallelWriter(),
                    }.ScheduleParallel(StaticEntityGroup, 1, Dependency));
                }

                var handle = JobHandle.CombineDependencies(jobHandles);
                jobHandles.Clear();

                // Build joints
                if (numJoints > 0)
                {
                    jobHandles.Add(new Jobs.CreateJoints
                    {
                        ConstrainedBodyPairComponentType = physicsConstrainedBodyPairType,
                        JointComponentType     = physicsJointType,
                        EntityType             = entityType,
                        RigidBodies            = PhysicsWorld.Bodies,
                        Joints                 = PhysicsWorld.Joints,
                        DefaultStaticBodyIndex = PhysicsWorld.Bodies.Length - 1,
                        NumDynamicBodies       = numDynamicBodies,
                        EntityBodyIndexMap     = PhysicsWorld.CollisionWorld.EntityBodyIndexMap,
                        EntityJointIndexMap    = PhysicsWorld.DynamicsWorld.EntityJointIndexMap.AsParallelWriter(),
                    }.ScheduleParallel(JointEntityGroup, 1, handle));
                }

                // Build the broadphase
                // TODO: could optimize this by gathering the AABBs and filters at the same time as building the bodies above
                sfloat timeStep = (sfloat)Time.DeltaTime;

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

                JobHandle buildBroadphaseHandle = PhysicsWorld.CollisionWorld.ScheduleBuildBroadphaseJobs(
                    ref PhysicsWorld, timeStep, stepComponent.Gravity,
                    HaveStaticBodiesChanged, handle, stepComponent.MultiThreaded > 0);
                jobHandles.Add(buildBroadphaseHandle);

                m_OutputDependency = JobHandle.CombineDependencies(jobHandles);
            }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            RecordIntegrity(IntegrityCheckMap);
#endif

            ChainDependencies();
        }
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            // Make sure last frame's physics jobs are complete
            m_EndFramePhysicsSystem.FinalJobHandle.Complete();

            // Extract types used by initialize jobs
            var entityType               = GetArchetypeChunkEntityType();
            var positionType             = GetArchetypeChunkComponentType <Translation>(true);
            var rotationType             = GetArchetypeChunkComponentType <Rotation>(true);
            var physicsColliderType      = GetArchetypeChunkComponentType <PhysicsCollider>(true);
            var physicsVelocityType      = GetArchetypeChunkComponentType <PhysicsVelocity>(true);
            var physicsMassType          = GetArchetypeChunkComponentType <PhysicsMass>(true);
            var physicsDampingType       = GetArchetypeChunkComponentType <PhysicsDamping>(true);
            var physicsGravityFactorType = GetArchetypeChunkComponentType <PhysicsGravityFactor>(true);
            var physicsCustomTagsType    = GetArchetypeChunkComponentType <PhysicsCustomTags>(true);
            var physicsJointType         = GetArchetypeChunkComponentType <PhysicsJoint>(true);

            int numDynamicBodies = DynamicEntityGroup.CalculateEntityCount();
            int numStaticBodies  = StaticEntityGroup.CalculateEntityCount();
            int numJoints        = JointEntityGroup.CalculateEntityCount();

            m_StaticLayerChangeInfo.NumStaticBodies         = numStaticBodies + 1;
            m_StaticLayerChangeInfo.HaveStaticBodiesChanged = 0;

            if (numStaticBodies != (PhysicsWorld.StaticBodies.Length - 1)) //-1 for fake static body we add
            {
                // Quick test if number of bodies changed
                m_StaticLayerChangeInfo.HaveStaticBodiesChanged = 1;
            }
            else
            {
                // Make a job to test for changes
                int numChunks; // There has to be a better way of doing this...
                using (NativeArray <ArchetypeChunk> chunks = StaticEntityGroup.CreateArchetypeChunkArray(Allocator.TempJob))
                {
                    numChunks = chunks.Length;
                }

                var chunksHaveChanges = new NativeArray <int>(numChunks, Allocator.TempJob);

                inputDeps = new Jobs.CheckStaticBodyChangesJob
                {
                    PositionType          = positionType,
                    RotationType          = rotationType,
                    PhysicsColliderType   = physicsColliderType,
                    ChunkHasChangesOutput = chunksHaveChanges,
                    m_LastSystemVersion   = LastSystemVersion
                }.Schedule(StaticEntityGroup, inputDeps);

                inputDeps = new Jobs.CheckStaticBodyChangesReduceJob
                {
                    ChunkHasChangesOutput   = chunksHaveChanges,
                    HaveStaticBodiesChanged = m_StaticLayerChangeInfo.HaveStaticBodiesChangedArray,
                    NumStaticBodies         = m_StaticLayerChangeInfo.NumStaticBodiesArray
                }.Schedule(inputDeps);
            }

            // Resize the world's native arrays
            PhysicsWorld.Reset(
                numStaticBodies: numStaticBodies + 1,   // +1 for the default static body
                numDynamicBodies: numDynamicBodies,
                numJoints: numJoints);

            using (var jobHandles = new NativeList <JobHandle>(4, Allocator.Temp))
            {
                // Create the default static body at the end of the body list
                // TODO: could skip this if no joints present
                jobHandles.Add(new Jobs.CreateDefaultStaticRigidBody
                {
                    NativeBodies = PhysicsWorld.Bodies,
                    BodyIndex    = PhysicsWorld.Bodies.Length - 1
                }.Schedule(inputDeps));

                // Dynamic bodies.
                // Create these separately from static bodies to maintain a 1:1 mapping
                // between dynamic bodies and their motions.
                if (numDynamicBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType            = entityType,
                        PositionType          = positionType,
                        RotationType          = rotationType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex = 0,
                        RigidBodies    = PhysicsWorld.Bodies
                    }.Schedule(DynamicEntityGroup, inputDeps));

                    jobHandles.Add(new Jobs.CreateMotions
                    {
                        PositionType             = positionType,
                        RotationType             = rotationType,
                        PhysicsVelocityType      = physicsVelocityType,
                        PhysicsMassType          = physicsMassType,
                        PhysicsDampingType       = physicsDampingType,
                        PhysicsGravityFactorType = physicsGravityFactorType,

                        MotionDatas      = PhysicsWorld.MotionDatas,
                        MotionVelocities = PhysicsWorld.MotionVelocities
                    }.Schedule(DynamicEntityGroup, inputDeps));
                }

                // Now, schedule creation of static bodies, with FirstBodyIndex pointing after
                // the dynamic and kinematic bodies
                if (numStaticBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType            = entityType,
                        PositionType          = positionType,
                        RotationType          = rotationType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex = numDynamicBodies,
                        RigidBodies    = PhysicsWorld.Bodies
                    }.Schedule(StaticEntityGroup, inputDeps));
                }

                var handle = JobHandle.CombineDependencies(jobHandles);
                jobHandles.Clear();

                // Build joints
                if (numJoints > 0)
                {
                    jobHandles.Add(new Jobs.CreateJoints
                    {
                        JointComponentType     = physicsJointType,
                        EntityType             = entityType,
                        RigidBodies            = PhysicsWorld.Bodies,
                        Joints                 = PhysicsWorld.Joints,
                        DefaultStaticBodyIndex = PhysicsWorld.Bodies.Length - 1,
                        NumDynamicBodies       = numDynamicBodies
                    }.Schedule(JointEntityGroup, handle));
                }

                // Build the broadphase
                // TODO: could optimize this by gathering the AABBs and filters at the same time as building the bodies above
#if !UNITY_DOTSPLAYER
                float timeStep = UnityEngine.Time.fixedDeltaTime;
#else
                float timeStep = Time.DeltaTime;
#endif

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

                jobHandles.Add(PhysicsWorld.CollisionWorld.Broadphase.ScheduleBuildJobs(ref PhysicsWorld, timeStep, stepComponent.Gravity,
                                                                                        stepComponent.ThreadCountHint, ref m_StaticLayerChangeInfo, handle));

                FinalJobHandle = JobHandle.CombineDependencies(jobHandles);
            }

            return(JobHandle.CombineDependencies(FinalJobHandle, inputDeps));
        }
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            // Make sure last frame's physics jobs are complete
            m_EndFramePhysicsSystem.FinalJobHandle.Complete();

            // Extract types used by initialize jobs
            var entityType       = GetArchetypeChunkEntityType();
            var localToWorldType = GetArchetypeChunkComponentType <LocalToWorld>(true);
            var parentType       = GetArchetypeChunkComponentType <Parent>(true);
            //    var positionType = GetArchetypeChunkComponentType<Translation>(true);
            //   var rotationType = GetArchetypeChunkComponentType<Rotation>(true);
            var transformType            = GetArchetypeChunkComponentType <TransformPredictedState>(true);
            var physicsColliderType      = GetArchetypeChunkComponentType <PhysicsCollider>(true);
            var physicsVelocityType      = GetArchetypeChunkComponentType <PhysicsVelocity>(true);
            var physicsMassType          = GetArchetypeChunkComponentType <PhysicsMass>(true);
            var physicsDampingType       = GetArchetypeChunkComponentType <PhysicsDamping>(true);
            var physicsGravityFactorType = GetArchetypeChunkComponentType <PhysicsGravityFactor>(true);
            var physicsCustomTagsType    = GetArchetypeChunkComponentType <PhysicsCustomTags>(true);
            //  var physicsJointType = GetArchetypeChunkComponentType<PhysicsJoint>(true);

            int numDynamicBodies = DynamicEntityGroup.CalculateEntityCount();
            int numStaticBodies  = StaticEntityGroup.CalculateEntityCount();
            //  int numJoints = JointEntityGroup.CalculateEntityCount();

            int previousStaticBodyCount = PhysicsWorld.NumStaticBodies;

            // Resize the world's native arrays
            PhysicsWorld.Reset(
                numStaticBodies + 1, // +1 for the default static body
                numDynamicBodies,
                0);

            // Determine if the static bodies have changed in any way that will require the static broadphase tree to be rebuilt
            JobHandle staticBodiesCheckHandle = default;
            var       haveStaticBodiesChanged = new NativeArray <int>(1, Allocator.TempJob);

            haveStaticBodiesChanged[0] = 0;
            {
                if (PhysicsWorld.NumStaticBodies != previousStaticBodyCount)
                {
                    haveStaticBodiesChanged[0] = 1;
                }
                else
                {
                    // Make a job to test for changes
                    int numChunks;
                    using (NativeArray <ArchetypeChunk> chunks = StaticEntityGroup.CreateArchetypeChunkArray(Allocator.TempJob))
                    {
                        numChunks = chunks.Length;
                    }
                    var chunksHaveChanges = new NativeArray <int>(numChunks, Allocator.TempJob);

                    staticBodiesCheckHandle = new Jobs.CheckStaticBodyChangesJob
                    {
                        //   LocalToWorldType = localToWorldType,
                        //   ParentType = parentType,
                        // PositionType = positionType,
                        //  RotationType = rotationType,
                        TransformType         = transformType,
                        PhysicsColliderType   = physicsColliderType,
                        ChunkHasChangesOutput = chunksHaveChanges,
                        m_LastSystemVersion   = LastSystemVersion
                    }.Schedule(StaticEntityGroup, inputDeps);

                    staticBodiesCheckHandle = new Jobs.CheckStaticBodyChangesReduceJob
                    {
                        ChunkHasChangesOutput = chunksHaveChanges,
                        Result = haveStaticBodiesChanged
                    }.Schedule(staticBodiesCheckHandle);
                }
            }

            using (var jobHandles = new NativeList <JobHandle>(4, Allocator.Temp))
            {
                // Static body changes check jobs
                jobHandles.Add(staticBodiesCheckHandle);

                // Create the default static body at the end of the body list
                // TODO: could skip this if no joints present
                // if (numJoints > 0)
                {
                    jobHandles.Add(new Jobs.CreateDefaultStaticRigidBody
                    {
                        NativeBodies = PhysicsWorld.Bodies,
                        BodyIndex    = PhysicsWorld.Bodies.Length - 1
                    }.Schedule(inputDeps));
                }

                // Dynamic bodies.
                // Create these separately from static bodies to maintain a 1:1 mapping
                // between dynamic bodies and their motions.
                if (numDynamicBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType       = entityType,
                        LocalToWorldType = localToWorldType,
                        ParentType       = parentType,
                        //    PositionType = positionType,
                        //    RotationType = rotationType,
                        TransformType         = transformType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex = 0,
                        RigidBodies    = PhysicsWorld.Bodies
                    }.Schedule(DynamicEntityGroup, inputDeps));

                    jobHandles.Add(new Jobs.CreateMotions
                    {
                        // PositionType = positionType,
                        // RotationType = rotationType,
                        TransformType            = transformType,
                        PhysicsVelocityType      = physicsVelocityType,
                        PhysicsMassType          = physicsMassType,
                        PhysicsDampingType       = physicsDampingType,
                        PhysicsGravityFactorType = physicsGravityFactorType,

                        MotionDatas      = PhysicsWorld.MotionDatas,
                        MotionVelocities = PhysicsWorld.MotionVelocities
                    }.Schedule(DynamicEntityGroup, inputDeps));
                }

                // Now, schedule creation of static bodies, with FirstBodyIndex pointing after
                // the dynamic and kinematic bodies
                if (numStaticBodies > 0)
                {
                    jobHandles.Add(new Jobs.CreateRigidBodies
                    {
                        EntityType       = entityType,
                        LocalToWorldType = localToWorldType,
                        ParentType       = parentType,
                        //  PositionType = positionType,
                        //  RotationType = rotationType,
                        TransformType         = transformType,
                        PhysicsColliderType   = physicsColliderType,
                        PhysicsCustomTagsType = physicsCustomTagsType,

                        FirstBodyIndex = numDynamicBodies,
                        RigidBodies    = PhysicsWorld.Bodies
                    }.Schedule(StaticEntityGroup, inputDeps));
                }

                var handle = JobHandle.CombineDependencies(jobHandles);
                jobHandles.Clear();

                // Build joints
                //if (numJoints > 0)
                //{
                //    jobHandles.Add(new Jobs.CreateJoints
                //    {
                //        JointComponentType = physicsJointType,
                //        EntityType = entityType,
                //        RigidBodies = PhysicsWorld.Bodies,
                //        Joints = PhysicsWorld.Joints,
                //        DefaultStaticBodyIndex = PhysicsWorld.Bodies.Length - 1,
                //        NumDynamicBodies = numDynamicBodies
                //    }.Schedule(JointEntityGroup, handle));
                //}

                // Build the broadphase
                // TODO: could optimize this by gathering the AABBs and filters at the same time as building the bodies above
#if !UNITY_DOTSPLAYER
                float timeStep = UnityEngine.Time.fixedDeltaTime;
#else
                float timeStep = Time.DeltaTime;
#endif

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

                JobHandle buildBroadphaseHandle = PhysicsWorld.CollisionWorld.ScheduleBuildBroadphaseJobs(
                    ref PhysicsWorld, timeStep, stepComponent.Gravity,
                    haveStaticBodiesChanged, handle, stepComponent.ThreadCountHint);
                jobHandles.Add(haveStaticBodiesChanged.Dispose(buildBroadphaseHandle));

                FinalJobHandle = JobHandle.CombineDependencies(jobHandles);
                FinalJobHandle.Complete();
            }

            return(JobHandle.CombineDependencies(FinalJobHandle, inputDeps));
        }
        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            // Extract types used by initialize jobs
            var entityType               = GetArchetypeChunkEntityType();
            var positionType             = GetArchetypeChunkComponentType <Translation>(true);
            var rotationType             = GetArchetypeChunkComponentType <Rotation>(true);
            var physicsColliderType      = GetArchetypeChunkComponentType <PhysicsCollider>(true);
            var physicsVelocityType      = GetArchetypeChunkComponentType <PhysicsVelocity>(true);
            var physicsMassType          = GetArchetypeChunkComponentType <PhysicsMass>(true);
            var physicsDampingType       = GetArchetypeChunkComponentType <PhysicsDamping>(true);
            var physicsGravityFactorType = GetArchetypeChunkComponentType <PhysicsGravityFactor>(true);
            var physicsCustomDataType    = GetArchetypeChunkComponentType <PhysicsCustomData>(true);
            var physicsJointType         = GetArchetypeChunkComponentType <PhysicsJoint>(true);

            int numDynamicBodies = DynamicEntityGroup.CalculateLength();
            int numStaticBodies  = StaticEntityGroup.CalculateLength();
            int numJoints        = JointEntityGroup.CalculateLength();

            // Check for static body changes before the reset()
            bool haveStaticBodiesChanged = false;

            {
                // For now, do this before the reset() - otherwise, we need the BuildRigidBodies jobs to finish
                if (numStaticBodies != (PhysicsWorld.StaticBodies.Length - 1)) //-1 for fake static body we add
                {
                    // Quick test if number of bodies changed
                    haveStaticBodiesChanged = true;
                }
                else
                {
                    // Make a job to test for changes

                    int numChunks; // There has to be a better way of doing this...
                    {
                        var chunks = StaticEntityGroup.CreateArchetypeChunkArray(Allocator.TempJob);
                        numChunks = chunks.Length;
                        chunks.Dispose();
                    }

                    var chunksHaveChanges  = new NativeArray <int>(numChunks, Allocator.TempJob);
                    var checkStaticChanges = new Jobs.CheckStaticBodyChangesJob
                    {
                        PositionType          = positionType,
                        RotationType          = rotationType,
                        PhysicsColliderType   = physicsColliderType,
                        StaticRigidBodies     = PhysicsWorld.StaticBodies,
                        ChunkHasChangesOutput = chunksHaveChanges
                    };

                    checkStaticChanges.Schedule(StaticEntityGroup, inputDeps).Complete();
                    for (int i = 0; i < numChunks; i++)
                    {
                        haveStaticBodiesChanged |= chunksHaveChanges[i] != 0;
                    }
                    chunksHaveChanges.Dispose();
                }
            }

            // Resize the world's native arrays
            PhysicsWorld.Reset(
                numStaticBodies: numStaticBodies + 1,   // +1 for the default static body
                numDynamicBodies: numDynamicBodies,
                numJoints: numJoints);

            var jobHandles = new NativeList <JobHandle>(4, Allocator.Temp);

            // Create the default static body at the end of the body list
            // TODO: could skip this if no joints present
            jobHandles.Add(new Jobs.CreateDefaultStaticRigidBody
            {
                NativeBodies = PhysicsWorld.Bodies,
                BodyIndex    = PhysicsWorld.Bodies.Length - 1
            }.Schedule(inputDeps));

            // Dynamic bodies. Create these separately from static bodies to maintain a 1:1 mapping
            // between dynamic bodies and their motions.
            if (numDynamicBodies > 0)
            {
                jobHandles.Add(new Jobs.CreateRigidBodies
                {
                    EntityType            = entityType,
                    PositionType          = positionType,
                    RotationType          = rotationType,
                    PhysicsColliderType   = physicsColliderType,
                    PhysicsCustomDataType = physicsCustomDataType,

                    FirstBodyIndex = 0,
                    RigidBodies    = PhysicsWorld.Bodies
                }.Schedule(DynamicEntityGroup, inputDeps));

                jobHandles.Add(new Jobs.CreateMotions
                {
                    PositionType             = positionType,
                    RotationType             = rotationType,
                    PhysicsVelocityType      = physicsVelocityType,
                    PhysicsMassType          = physicsMassType,
                    PhysicsDampingType       = physicsDampingType,
                    PhysicsGravityFactorType = physicsGravityFactorType,

                    MotionDatas      = PhysicsWorld.MotionDatas,
                    MotionVelocities = PhysicsWorld.MotionVelocities
                }.Schedule(DynamicEntityGroup, inputDeps));
            }

            // Now, schedule creation of static bodies, with FirstBodyIndex pointing after the dynamic bodies
            if (numStaticBodies > 0)
            {
                jobHandles.Add(new Jobs.CreateRigidBodies
                {
                    EntityType            = entityType,
                    PositionType          = positionType,
                    RotationType          = rotationType,
                    PhysicsColliderType   = physicsColliderType,
                    PhysicsCustomDataType = physicsCustomDataType,

                    FirstBodyIndex = numDynamicBodies,
                    RigidBodies    = PhysicsWorld.Bodies
                }.Schedule(StaticEntityGroup, inputDeps));
            }

            var handle = JobHandle.CombineDependencies(jobHandles);

            jobHandles.Clear();

            // Build joints
            if (numJoints > 0)
            {
                jobHandles.Add(new Jobs.CreateJoints
                {
                    JointComponentType     = physicsJointType,
                    EntityType             = entityType,
                    RigidBodies            = PhysicsWorld.Bodies,
                    Joints                 = PhysicsWorld.Joints,
                    DefaultStaticBodyIndex = PhysicsWorld.Bodies.Length - 1
                }.Schedule(JointEntityGroup, handle));
            }

            // Build the broadphase
            // TODO: could optimize this by gathering the AABBs and filters at the same time as building the bodies above

            float timeStep = UnityEngine.Time.fixedDeltaTime;

            PhysicsStep stepComponent = PhysicsStep.Default;

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

            jobHandles.Add(PhysicsWorld.CollisionWorld.Broadphase.ScheduleBuildJobs(ref PhysicsWorld, timeStep, stepComponent.ThreadCountHint, haveStaticBodiesChanged, handle));

            FinalJobHandle = JobHandle.CombineDependencies(jobHandles);
            jobHandles.Dispose();

            return(JobHandle.CombineDependencies(FinalJobHandle, inputDeps));
        }