1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-14 01:19:59 +00:00

Merge branch 'fix-actor-sim-when-idle' into 'master'

Fix actor simulation running when completely idle

Closes #5862

See merge request OpenMW/openmw!4105
This commit is contained in:
cykoder 2025-03-11 00:52:08 +00:00
commit 0b6684734c
2 changed files with 37 additions and 9 deletions

View File

@ -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 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
&& 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,

View File

@ -1331,19 +1331,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<float>::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());
}