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));
        }