From 40265bf1181167d927f3870b9d5127e310ce49f7 Mon Sep 17 00:00:00 2001 From: wareya Date: Sat, 20 Mar 2021 21:14:56 -0400 Subject: [PATCH] make unstucking slightly smarter (can turn itself off, also acts like flat ground) --- apps/openmw/mwphysics/actor.hpp | 21 +++++++++++++++++++ apps/openmw/mwphysics/movementsolver.cpp | 26 +++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 031125f40d..472a79bff5 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -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 mOnGround; std::atomic mOnSlope; diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp index 5f0322a1f2..a393ec5784 100644 --- a/apps/openmw/mwphysics/movementsolver.cpp +++ b/apps/openmw/mwphysics/movementsolver.cpp @@ -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;