Explicitely store all the potential states an Actor can have into the

ActActorFrameData structure. It makes it easier to reason about the
simulation (and hopefully simplify it).
Remove atomics from Actor class as a side effect.

Rename mFloatToSurface to mInert to make is explicit what it represent, not what it is used for
Store the Actor rotation (1 Vec2) instead of the whole ESM::Position (2 Vec3)
pull/3097/head
fredzio 4 years ago
parent 9472728fa4
commit 1bfaf353be

@ -82,7 +82,7 @@ Actor::~Actor()
void Actor::enableCollisionMode(bool collision)
{
mInternalCollisionMode.store(collision, std::memory_order_release);
mInternalCollisionMode = collision;
}
void Actor::enableCollisionBody(bool collision)
@ -250,22 +250,22 @@ void Actor::setInertialForce(const osg::Vec3f &force)
void Actor::setOnGround(bool grounded)
{
mOnGround.store(grounded, std::memory_order_release);
mOnGround = grounded;
}
void Actor::setOnSlope(bool slope)
{
mOnSlope.store(slope, std::memory_order_release);
mOnSlope = slope;
}
bool Actor::isWalkingOnWater() const
{
return mWalkingOnWater.load(std::memory_order_acquire);
return mWalkingOnWater;
}
void Actor::setWalkingOnWater(bool walkingOnWater)
{
mWalkingOnWater.store(walkingOnWater, std::memory_order_release);
mWalkingOnWater = walkingOnWater;
}
void Actor::setCanWaterWalk(bool waterWalk)

@ -1,7 +1,6 @@
#ifndef OPENMW_MWPHYSICS_ACTOR_H
#define OPENMW_MWPHYSICS_ACTOR_H
#include <atomic>
#include <memory>
#include <mutex>
@ -37,7 +36,7 @@ namespace MWPhysics
bool getCollisionMode() const
{
return mInternalCollisionMode.load(std::memory_order_acquire);
return mInternalCollisionMode;
}
btConvexShape* getConvexShape() const { return mConvexShape; }
@ -123,14 +122,14 @@ namespace MWPhysics
bool getOnGround() const
{
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnGround.load(std::memory_order_acquire);
return mInternalCollisionMode && mOnGround;
}
void setOnSlope(bool slope);
bool getOnSlope() const
{
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnSlope.load(std::memory_order_acquire);
return mInternalCollisionMode && mOnSlope;
}
btCollisionObject* getCollisionObject() const
@ -182,7 +181,7 @@ namespace MWPhysics
osg::Vec3f getScaledMeshTranslation() const;
bool mCanWaterWalk;
std::atomic<bool> mWalkingOnWater;
bool mWalkingOnWater;
bool mRotationallyInvariant;
@ -211,9 +210,9 @@ namespace MWPhysics
osg::Vec3f mLastStuckPosition;
osg::Vec3f mForce;
std::atomic<bool> mOnGround;
std::atomic<bool> mOnSlope;
std::atomic<bool> mInternalCollisionMode;
bool mOnGround;
bool mOnSlope;
bool mInternalCollisionMode;
bool mExternalCollisionMode;
PhysicsTaskScheduler* mTaskScheduler;

@ -119,15 +119,14 @@ namespace MWPhysics
WorldFrameData& worldData)
{
auto* physicActor = actor.mActorRaw;
const ESM::Position& refpos = actor.mRefpos;
// Reset per-frame data
physicActor->setWalkingOnWater(false);
actor.mWalkingOnWater = false;
// Anything to collide with?
if(!physicActor->getCollisionMode() || actor.mSkipCollisionDetection)
if(actor.mSkipCollisionDetection)
{
actor.mPosition += (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) *
osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))
actor.mPosition += (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) *
osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))
) * actor.mMovement * time;
return;
}
@ -151,22 +150,22 @@ namespace MWPhysics
if (actor.mPosition.z() < swimlevel || actor.mFlying)
{
velocity = (osg::Quat(refpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
velocity = (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
}
else
{
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
velocity = (osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
if ((velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
|| (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && physicActor->getOnSlope()))
if ((velocity.z() > 0.f && actor.mIsOnGround && !actor.mIsOnSlope)
|| (velocity.z() > 0.f && velocity.z() + inertia.z() <= -velocity.z() && actor.mIsOnSlope))
inertia = velocity;
else if (!physicActor->getOnGround() || physicActor->getOnSlope())
else if (!actor.mIsOnGround || actor.mIsOnSlope)
velocity = velocity + inertia;
}
// Dead and paralyzed actors underwater will float to the surface,
// if the CharacterController tells us to do so
if (actor.mMovement.z() > 0 && actor.mFloatToSurface && actor.mPosition.z() < swimlevel)
if (actor.mMovement.z() > 0 && actor.mInert && actor.mPosition.z() < swimlevel)
velocity = osg::Vec3f(0,0,1) * 25;
if (actor.mWantJump)
@ -190,7 +189,7 @@ namespace MWPhysics
* The initial velocity was set earlier (see above).
*/
float remainingTime = time;
bool seenGround = physicActor->getOnGround() && !physicActor->getOnSlope() && !actor.mFlying;
bool seenGround = actor.mIsOnGround && !actor.mIsOnSlope && !actor.mFlying;
int numTimesSlid = 0;
osg::Vec3f lastSlideNormal(0,0,1);
@ -349,7 +348,7 @@ namespace MWPhysics
if (forceGroundTest || (inertia.z() <= 0.f && newPosition.z() >= swimlevel))
{
osg::Vec3f from = newPosition;
auto dropDistance = 2*sGroundOffset + (physicActor->getOnGround() ? sStepSizeDown : 0);
auto dropDistance = 2*sGroundOffset + (actor.mIsOnGround ? sStepSizeDown : 0);
osg::Vec3f to = newPosition - osg::Vec3f(0,0,dropDistance);
tracer.doTrace(colobj, from, to, collisionWorld);
if(tracer.mFraction < 1.0f)
@ -365,7 +364,7 @@ namespace MWPhysics
actor.mStandingOn = ptrHolder->getPtr();
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Water)
physicActor->setWalkingOnWater(true);
actor.mWalkingOnWater = true;
if (!actor.mFlying && !isOnSlope)
{
if (tracer.mFraction*dropDistance > sGroundOffset)
@ -408,8 +407,8 @@ namespace MWPhysics
}
physicActor->setInertialForce(inertia);
}
physicActor->setOnGround(isOnGround);
physicActor->setOnSlope(isOnSlope);
actor.mIsOnGround = isOnGround;
actor.mIsOnSlope = isOnSlope;
actor.mPosition = newPosition;
// remove what was added earlier in compensating for doTrace not taking interior transformation into account
@ -426,7 +425,7 @@ namespace MWPhysics
void MovementSolver::unstuck(ActorFrameData& actor, const btCollisionWorld* collisionWorld)
{
auto* physicActor = actor.mActorRaw;
if(!physicActor->getCollisionMode() || actor.mSkipCollisionDetection) // noclipping/tcl
if(actor.mSkipCollisionDetection) // noclipping/tcl
return;
auto* collisionObject = physicActor->getCollisionObject();
@ -448,9 +447,9 @@ namespace MWPhysics
const auto verticalHalfExtent = osg::Vec3f(0.0, 0.0, physicActor->getHalfExtents().z());
// use a 3d approximation of the movement vector to better judge player intent
auto velocity = (osg::Quat(actor.mRefpos.rot[0], osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRefpos.rot[2], osg::Vec3f(0, 0, -1))) * actor.mMovement;
auto velocity = (osg::Quat(actor.mRotation.x(), osg::Vec3f(-1, 0, 0)) * osg::Quat(actor.mRotation.y(), osg::Vec3f(0, 0, -1))) * actor.mMovement;
// try to pop outside of the world before doing anything else if we're inside of it
if (!physicActor->getOnGround() || physicActor->getOnSlope())
if (!actor.mIsOnGround || actor.mIsOnSlope)
velocity += physicActor->getInertialForce();
// because of the internal collision box offset hack, and the fact that we're moving the collision box manually,

@ -54,7 +54,7 @@ namespace
{
const float heightDiff = actorData.mPosition.z() - actorData.mOldHeight;
const bool isStillOnGround = (simulationPerformed && actorData.mWasOnGround && actorData.mActorRaw->getOnGround());
const bool isStillOnGround = (simulationPerformed && actorData.mWasOnGround && actorData.mIsOnGround);
if (isStillOnGround || actorData.mFlying || actorData.mSwimming || actorData.mSlowFall < 1)
actorData.mNeedLand = true;
@ -256,7 +256,12 @@ namespace MWPhysics
// these variables are accessed directly from the main thread, update them here to prevent accessing "too new" values
if (mAdvanceSimulation)
{
data.mActorRaw->setStandingOnPtr(data.mStandingOn);
data.mActorRaw->setOnGround(data.mIsOnGround);
data.mActorRaw->setOnSlope(data.mIsOnSlope);
data.mActorRaw->setWalkingOnWater(data.mWalkingOnWater);
}
data.mActorRaw->setSimulationPosition(interpolateMovements(data, mTimeAccum, mPhysicsDt));
}
}
@ -555,7 +560,12 @@ namespace MWPhysics
actorData.mActorRaw->setSimulationPosition(interpolateMovements(actorData, mTimeAccum, mPhysicsDt));
updateMechanics(actorData);
if (mAdvanceSimulation)
{
actorData.mActorRaw->setStandingOnPtr(actorData.mStandingOn);
actorData.mActorRaw->setOnGround(actorData.mIsOnGround);
actorData.mActorRaw->setOnSlope(actorData.mIsOnSlope);
actorData.mActorRaw->setWalkingOnWater(actorData.mWalkingOnWater);
}
}
refreshLOSCache();
}

@ -950,9 +950,24 @@ namespace MWPhysics
ActorFrameData::ActorFrameData(const std::shared_ptr<Actor>& actor, const MWWorld::Ptr standingOn,
bool waterCollision, float slowFall, float waterlevel)
: mActor(actor), mActorRaw(actor.get()), mStandingOn(standingOn),
mDidJump(false), mNeedLand(false), mWaterCollision(waterCollision), mSkipCollisionDetection(actor->skipCollisions()),
mWaterlevel(waterlevel), mSlowFall(slowFall), mOldHeight(0), mFallHeight(0), mMovement(actor->velocity()), mPosition(), mRefpos()
: mActor(actor)
, mActorRaw(actor.get())
, mStandingOn(standingOn)
, mWasOnGround(actor->getOnGround())
, mIsOnGround(actor->getOnGround())
, mIsOnSlope(actor->getOnSlope())
, mDidJump(false)
, mNeedLand(false)
, mWaterCollision(waterCollision)
, mWalkingOnWater(false)
, mSkipCollisionDetection(actor->skipCollisions() || !actor->getCollisionMode())
, mWaterlevel(waterlevel)
, mSlowFall(slowFall)
, mOldHeight(0)
, mFallHeight(0)
, mMovement(actor->velocity())
, mPosition()
, mRotation()
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const auto ptr = actor->getPtr();
@ -961,8 +976,7 @@ namespace MWPhysics
mWantJump = ptr.getClass().getMovementSettings(ptr).mPosition[2] != 0;
auto& stats = ptr.getClass().getCreatureStats(ptr);
const bool godmode = ptr == world->getPlayerConstPtr() && world->getGodModeState();
mFloatToSurface = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
mWasOnGround = actor->getOnGround();
mInert = stats.isDead() || (!godmode && stats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0);
}
void ActorFrameData::updatePosition(btCollisionWorld* world)
@ -975,7 +989,8 @@ namespace MWPhysics
MWBase::Environment::get().getWorld()->moveObject(mActorRaw->getPtr(), mPosition, false);
}
mOldHeight = mPosition.z();
mRefpos = mActorRaw->getPtr().getRefData().getPosition();
const auto rotation = mActorRaw->getPtr().getRefData().getPosition().asRotationVec3();
mRotation = osg::Vec2f(rotation.x(), rotation.z());
}
WorldFrameData::WorldFrameData()

@ -86,11 +86,14 @@ namespace MWPhysics
bool mFlying;
bool mSwimming;
bool mWasOnGround;
bool mIsOnGround;
bool mIsOnSlope;
bool mWantJump;
bool mDidJump;
bool mFloatToSurface;
bool mInert;
bool mNeedLand;
bool mWaterCollision;
bool mWalkingOnWater;
bool mSkipCollisionDetection;
float mWaterlevel;
float mSlowFall;
@ -98,7 +101,7 @@ namespace MWPhysics
float mFallHeight;
osg::Vec3f mMovement;
osg::Vec3f mPosition;
ESM::Position mRefpos;
osg::Vec2f mRotation;
};
struct WorldFrameData

Loading…
Cancel
Save