1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 11:09:43 +00:00

Merge branch 'smarterunstuck' into 'master'

Improve 'unstuck'ing code

See merge request OpenMW/openmw!675
This commit is contained in:
psi29a 2021-03-21 09:47:59 +00:00
commit 78894b6129
2 changed files with 46 additions and 1 deletions

View file

@ -159,6 +159,24 @@ namespace MWPhysics
MWWorld::Ptr getStandingOnPtr() const;
void setStandingOnPtr(const MWWorld::Ptr& ptr);
unsigned int getStuckFrames() const
{
return mStuckFrames;
}
void setStuckFrames(unsigned int frames)
{
mStuckFrames = frames;
}
const osg::Vec3f &getLastStuckPosition() const
{
return mLastStuckPosition;
}
void setLastStuckPosition(osg::Vec3f position)
{
mLastStuckPosition = position;
}
private:
MWWorld::Ptr mStandingOnPtr;
/// Removes then re-adds the collision object to the dynamics world
@ -192,6 +210,9 @@ namespace MWPhysics
btTransform mLocalTransform;
mutable std::mutex mPositionMutex;
unsigned int mStuckFrames;
osg::Vec3f mLastStuckPosition;
osg::Vec3f mForce;
std::atomic<bool> mOnGround;
std::atomic<bool> mOnSlope;

View file

@ -204,7 +204,7 @@ namespace MWPhysics
osg::Vec3f lastSlideNormalFallback(0,0,1);
bool forceGroundTest = false;
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f; ++iterations)
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.0001f; ++iterations)
{
osg::Vec3f nextpos = newPosition + velocity * remainingTime;
@ -394,6 +394,12 @@ namespace MWPhysics
isOnGround = false;
}
}
// forcibly treat stuck actors as if they're on flat ground because buggy collisions when inside of things can/will break ground detection
if(physicActor->getStuckFrames() > 0)
{
isOnGround = true;
isOnSlope = false;
}
}
if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || actor.mFlying)
@ -437,6 +443,17 @@ namespace MWPhysics
auto* collisionObject = physicActor->getCollisionObject();
auto tempPosition = actor.mPosition;
if(physicActor->getStuckFrames() >= 10)
{
if((physicActor->getLastStuckPosition() - actor.mPosition).length2() < 100)
return;
else
{
physicActor->setStuckFrames(0);
physicActor->setLastStuckPosition({0, 0, 0});
}
}
// use vanilla-accurate collision hull position hack (do same hitbox offset hack as movement solver)
// if vanilla compatibility didn't matter, the "correct" collision hull position would be physicActor->getScaledMeshTranslation()
const auto verticalHalfExtent = osg::Vec3f(0.0, 0.0, physicActor->getHalfExtents().z());
@ -470,6 +487,8 @@ namespace MWPhysics
auto contactCallback = gatherContacts({0.0, 0.0, 0.0});
if(contactCallback.mDistance < -sAllowedPenetration)
{
physicActor->setStuckFrames(physicActor->getStuckFrames() + 1);
physicActor->setLastStuckPosition(actor.mPosition);
// we are; try moving it out of the world
auto positionDelta = contactCallback.mContactSum;
// limit rejection delta to the largest known individual rejections
@ -502,6 +521,11 @@ namespace MWPhysics
}
}
}
else
{
physicActor->setStuckFrames(0);
physicActor->setLastStuckPosition({0, 0, 0});
}
collisionObject->setWorldTransform(oldTransform);
actor.mPosition = tempPosition;