From 3cc2a3ad509b8a6ef78e874b79588a2ca6f197b4 Mon Sep 17 00:00:00 2001 From: Sam Hellawell Date: Thu, 16 May 2024 04:25:28 +0100 Subject: [PATCH 1/2] Fix actor simulation running when completely idle --- apps/openmw/mwphysics/movementsolver.cpp | 32 +++++++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 14 ++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 05b9f44654..f4509b604c 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -139,17 +139,43 @@ namespace MWPhysics return; } + // Physics simulation can be potentially skipped if all conditions match: + // - Actor is on ground + // - Actor is not flying + // - mIsAquatic is false + // - mMovement is not zero vector + // - mInertia is not a zero vector + // This is important to fix #3803 and others + ActorTracer tracer; + if (!actor.mFlying && actor.mIsOnGround && !actor.mIsAquatic && actor.mMovement.length2() == 0 + && actor.mInertia.length2() == 0) + { + // We think we can skip the simulation, but we must double check to cover edge cases + // trace the actor's collision object down to try and find valid ground to stand on + // the ground could be removed from the actor, so we cant just remember the last ground value + // we must also check if walking on water even if we skip this movement simulation + // the simulation can also only be skipped if it finds solid ground, not an actor or unwalkable slope + const osg::Vec3f from = actor.mPosition + osg::Vec3f(0.0f, 0.0f, actor.mHalfExtentsZ); + const auto dropDistance = 2 * sGroundOffset + (actor.mIsOnGround ? sStepSizeDown : 0); + const osg::Vec3f to = from - osg::Vec3f(0, 0, dropDistance); + tracer.doTrace(actor.mCollisionObject, from, to, collisionWorld, actor.mIsOnGround); + if (tracer.mFraction < 1.0f && !isActor(tracer.mHitObject) && isWalkableSlope(tracer.mPlaneNormal)) + { + actor.mStandingOn = tracer.mHitObject; + actor.mWalkingOnWater + = actor.mStandingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water; + return; + } + } + // Adjust for collision mesh offset relative to actor's "location" // (doTrace doesn't take local/interior collision shape translation into account, so we have to do it on our // own) for compatibility with vanilla assets, we have to derive this from the vertical half extent instead of // from internal hull translation if not for this hack, the "correct" collision hull position would be // physicActor->getScaledMeshTranslation() actor.mPosition.z() += actor.mHalfExtentsZ; // vanilla-accurate - float swimlevel = actor.mSwimLevel + actor.mHalfExtentsZ; - ActorTracer tracer; - osg::Vec3f velocity; // Dead and paralyzed actors underwater will float to the surface, diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a4464d70ad..3d9615caa4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1330,19 +1330,21 @@ namespace MWWorld return; } + const bool isActor = ptr.getClass().isActor(); const float terrainHeight = ptr.getCell()->isExterior() ? getTerrainHeightAt(pos, ptr.getCell()->getCell()->getWorldSpace()) : -std::numeric_limits::max(); - pos.z() = std::max(pos.z(), terrainHeight) - + 20; // place slightly above terrain. will snap down to ground with code below + pos.z() = std::max(pos.z(), terrainHeight); // We still should trace down dead persistent actors - they do not use the "swimdeath" animation. - bool swims = ptr.getClass().isActor() && isSwimming(ptr) + bool swims = isActor && isSwimming(ptr) && !(ptr.getClass().isPersistent(ptr) && ptr.getClass().getCreatureStats(ptr).isDeathAnimationFinished()); - if (force || !ptr.getClass().isActor() || (!isFlying(ptr) && !swims && isActorCollisionEnabled(ptr))) + if (force || !isActor || (!isFlying(ptr) && !swims && isActorCollisionEnabled(ptr))) { - osg::Vec3f traced - = mPhysics->traceDown(ptr, pos, ESM::getCellSize(ptr.getCell()->getCell()->getWorldSpace())); + // place slightly above terrain. will snap down to ground with code below + const osg::Vec3f posAdjusted = pos + osg::Vec3f(0.0f, 0.0f, 20.0f); + const osg::Vec3f traced + = mPhysics->traceDown(ptr, posAdjusted, ESM::getCellSize(ptr.getCell()->getCell()->getWorldSpace())); pos.z() = std::min(pos.z(), traced.z()); } From 302a64e6e36072b11d6094b1733cf5e901900a29 Mon Sep 17 00:00:00 2001 From: Sam Hellawell Date: Sat, 18 May 2024 07:55:11 +0100 Subject: [PATCH 2/2] Fix comments --- apps/openmw/mwphysics/movementsolver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index f4509b604c..878d7a319a 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -143,8 +143,8 @@ namespace MWPhysics // - Actor is on ground // - Actor is not flying // - mIsAquatic is false - // - mMovement is not zero vector - // - mInertia is not a zero vector + // - mMovement is a zero vector + // - mInertia is a zero vector // This is important to fix #3803 and others ActorTracer tracer; if (!actor.mFlying && actor.mIsOnGround && !actor.mIsAquatic && actor.mMovement.length2() == 0