mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 20:19:56 +00:00
b13afd758c
Actor's position can be determined in 3 ways: 1/ as a result of physics simulation 2/ after a script require a relative position change (SetPos, Move) 3/ absolutely set from games mechanics event (teleport) or script (PositionCell) In case 1/, RefData::mPosition is updated with the physics simulation result In case 2/, when RefData::mPosition is updated, physics simulation is informed of the change and update accordingly In case 3/, when RefData::mPosition is updated, the physics simulation state is reset In all 3 cases, we don't need to check the RefData::mPosition to get a correct behaviour. TSAN reported the following data race: Read of size 4 at 0x7b50005b75b0 by thread T12 (mutexes: write M656173, write M84859534346343880): #0 ESM::Position::asVec3() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../.././components/esm/defs.hpp:55:27 (openmw+0xb809d5) #1 MWPhysics::Actor::updateWorldPosition() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/actor.cpp:131:59 (openmw+0xb809d5) #2 MWPhysics::Actor::setPosition(osg::Vec3f const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/actor.cpp:177:5 (openmw+0xb809d5) #3 MWPhysics::PhysicsTaskScheduler::updateActorsPositions() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:524:28 (openmw+0xb91ac0) #4 MWPhysics::PhysicsTaskScheduler::afterPostStep() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:614:13 (openmw+0xb915e7) #5 MWPhysics::PhysicsTaskScheduler::worker()::$_5::operator()() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:498:45 (openmw+0xb915e7) #6 void Misc::Barrier::wait<MWPhysics::PhysicsTaskScheduler::worker()::$_5>(MWPhysics::PhysicsTaskScheduler::worker()::$_5&&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../.././components/misc/barrier.hpp:30:21 (openmw+0xb915e7) #7 MWPhysics::PhysicsTaskScheduler::worker() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:498:31 (openmw+0xb915e7) #8 MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0::operator()() const /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwphysics/mtphysics.cpp:162:45 (openmw+0xb92630) #9 decltype(std::__1::forward<MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>(fp)()) std::__1::__invoke<MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>(MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0&&) /usr/include/c++/v1/type_traits:3899:1 (openmw+0xb92630) #10 void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0>&, std::__1::__tuple_indices<>) /usr/include/c++/v1/thread:280:5 (openmw+0xb92630) #11 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, MWPhysics::PhysicsTaskScheduler::PhysicsTaskScheduler(float, btCollisionWorld*, MWRender::DebugDrawer*)::$_0> >(void*) /usr/include/c++/v1/thread:291:5 (openmw+0xb92630) Previous write of size 8 at 0x7b50005b75b0 by main thread: #0 memcpy /wrkdirs/usr/ports/devel/llvm-devel/work-default/llvm-project-3f6753efe1990a928ed120bd907940a9fb3e2fc3/compiler-rt/lib/tsan/../sanitizer_common/sanitizer_common_interceptors.inc:827:5 (openmw+0x55a057) #1 MWWorld::RefData::setPosition(ESM::Position const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/refdata.cpp:216:19 (openmw+0xa3de1c) #2 MWWorld::World::moveObject(MWWorld::Ptr const&, MWWorld::CellStore*, float, float, float, bool) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1130:26 (openmw+0xa57300) #3 MWWorld::World::moveObject(MWWorld::Ptr const&, float, float, float, bool, bool) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1253:16 (openmw+0xa580c8) #4 MWWorld::World::doPhysics(float, unsigned long long, unsigned int, osg::Stats&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1530:17 (openmw+0xa5af8f) #5 MWWorld::World::updatePhysics(float, bool, unsigned long long, unsigned int, osg::Stats&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/mwworld/worldimp.cpp:1862:13 (openmw+0xa61a7c) #6 OMW::Engine::frame(float) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/engine.cpp:333:42 (openmw+0xcce9e7) #7 OMW::Engine::go() /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/engine.cpp:935:14 (openmw+0xcd86ed) #8 runApplication(int, char**) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/main.cpp:296:17 (openmw+0xcbffac) #9 wrapApplication(int (*)(int, char**), int, char**, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../components/debug/debugging.cpp:205:15 (openmw+0x1335442) #10 main /build/openmw/openmw/master2/.build/freebsd/TSAN/../../../apps/openmw/main.cpp:308:12 (openmw+0xcc008a) :wqa
228 lines
6.7 KiB
C++
228 lines
6.7 KiB
C++
#ifndef OPENMW_MWPHYSICS_ACTOR_H
|
|
#define OPENMW_MWPHYSICS_ACTOR_H
|
|
|
|
#include <atomic>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
#include "ptrholder.hpp"
|
|
|
|
#include <LinearMath/btTransform.h>
|
|
#include <osg/Vec3f>
|
|
#include <osg/Quat>
|
|
|
|
class btCollisionShape;
|
|
class btCollisionObject;
|
|
class btConvexShape;
|
|
|
|
namespace Resource
|
|
{
|
|
class BulletShape;
|
|
}
|
|
|
|
namespace MWPhysics
|
|
{
|
|
class PhysicsTaskScheduler;
|
|
|
|
class Actor final : public PtrHolder
|
|
{
|
|
public:
|
|
Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, PhysicsTaskScheduler* scheduler);
|
|
~Actor() override;
|
|
|
|
/**
|
|
* Sets the collisionMode for this actor. If disabled, the actor can fly and clip geometry.
|
|
*/
|
|
void enableCollisionMode(bool collision);
|
|
|
|
bool getCollisionMode() const
|
|
{
|
|
return mInternalCollisionMode.load(std::memory_order_acquire);
|
|
}
|
|
|
|
btConvexShape* getConvexShape() const { return mConvexShape; }
|
|
|
|
/**
|
|
* Enables or disables the *external* collision body. If disabled, other actors will not collide with this actor.
|
|
*/
|
|
void enableCollisionBody(bool collision);
|
|
|
|
void updateScale();
|
|
void updateRotation();
|
|
|
|
/**
|
|
* Return true if the collision shape looks the same no matter how its Z rotated.
|
|
*/
|
|
bool isRotationallyInvariant() const;
|
|
|
|
/**
|
|
* Used by the physics simulation to store the simulation result. Used in conjunction with mWorldPosition
|
|
* to account for e.g. scripted movements
|
|
*/
|
|
void setSimulationPosition(const osg::Vec3f& position);
|
|
osg::Vec3f getSimulationPosition() const;
|
|
|
|
void updateCollisionObjectPosition();
|
|
|
|
/**
|
|
* Returns the half extents of the collision body (scaled according to collision scale)
|
|
*/
|
|
osg::Vec3f getHalfExtents() const;
|
|
|
|
/**
|
|
* Returns the half extents of the collision body (not scaled)
|
|
*/
|
|
osg::Vec3f getOriginalHalfExtents() const;
|
|
|
|
/// Returns the mesh translation, scaled and rotated as necessary
|
|
osg::Vec3f getScaledMeshTranslation() const;
|
|
|
|
/**
|
|
* Returns the position of the collision body
|
|
* @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space.
|
|
*/
|
|
osg::Vec3f getCollisionObjectPosition() const;
|
|
|
|
/**
|
|
* Store the current position into mPreviousPosition, then move to this position.
|
|
* Returns true if the new position is different.
|
|
*/
|
|
bool setPosition(const osg::Vec3f& position);
|
|
|
|
// force set actor position to be as in Ptr::RefData
|
|
void updatePosition();
|
|
|
|
// register a position offset that will be applied during simulation.
|
|
void adjustPosition(const osg::Vec3f& offset, bool ignoreCollisions);
|
|
|
|
// apply position offset. Can't be called during simulation
|
|
void applyOffsetChange();
|
|
|
|
osg::Vec3f getPosition() const;
|
|
|
|
osg::Vec3f getPreviousPosition() const;
|
|
|
|
/**
|
|
* Returns the half extents of the collision body (scaled according to rendering scale)
|
|
* @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape,
|
|
* most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale.
|
|
*/
|
|
osg::Vec3f getRenderingHalfExtents() const;
|
|
|
|
/**
|
|
* Sets the current amount of inertial force (incl. gravity) affecting this physic actor
|
|
*/
|
|
void setInertialForce(const osg::Vec3f &force);
|
|
|
|
/**
|
|
* Gets the current amount of inertial force (incl. gravity) affecting this physic actor
|
|
*/
|
|
const osg::Vec3f &getInertialForce() const
|
|
{
|
|
return mForce;
|
|
}
|
|
|
|
void setOnGround(bool grounded);
|
|
|
|
bool getOnGround() const
|
|
{
|
|
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnGround.load(std::memory_order_acquire);
|
|
}
|
|
|
|
void setOnSlope(bool slope);
|
|
|
|
bool getOnSlope() const
|
|
{
|
|
return mInternalCollisionMode.load(std::memory_order_acquire) && mOnSlope.load(std::memory_order_acquire);
|
|
}
|
|
|
|
btCollisionObject* getCollisionObject() const
|
|
{
|
|
return mCollisionObject.get();
|
|
}
|
|
|
|
/// Sets whether this actor should be able to collide with the water surface
|
|
void setCanWaterWalk(bool waterWalk);
|
|
|
|
/// Sets whether this actor has been walking on the water surface in the last frame
|
|
void setWalkingOnWater(bool walkingOnWater);
|
|
bool isWalkingOnWater() const;
|
|
|
|
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;
|
|
}
|
|
|
|
bool skipCollisions();
|
|
|
|
void setVelocity(osg::Vec3f velocity);
|
|
osg::Vec3f velocity();
|
|
|
|
private:
|
|
MWWorld::Ptr mStandingOnPtr;
|
|
/// Removes then re-adds the collision object to the dynamics world
|
|
void updateCollisionMask();
|
|
void addCollisionMask(int collisionMask);
|
|
int getCollisionMask() const;
|
|
|
|
bool mCanWaterWalk;
|
|
std::atomic<bool> mWalkingOnWater;
|
|
|
|
bool mRotationallyInvariant;
|
|
|
|
std::unique_ptr<btCollisionShape> mShape;
|
|
btConvexShape* mConvexShape;
|
|
|
|
std::unique_ptr<btCollisionObject> mCollisionObject;
|
|
|
|
osg::Vec3f mMeshTranslation;
|
|
osg::Vec3f mHalfExtents;
|
|
osg::Quat mRotation;
|
|
|
|
osg::Vec3f mScale;
|
|
osg::Vec3f mRenderingScale;
|
|
osg::Vec3f mSimulationPosition;
|
|
osg::Vec3f mPosition;
|
|
osg::Vec3f mPreviousPosition;
|
|
osg::Vec3f mPositionOffset;
|
|
osg::Vec3f mVelocity;
|
|
bool mWorldPositionChanged;
|
|
bool mSkipCollisions;
|
|
btTransform mLocalTransform;
|
|
mutable std::mutex mPositionMutex;
|
|
|
|
unsigned int mStuckFrames;
|
|
osg::Vec3f mLastStuckPosition;
|
|
|
|
osg::Vec3f mForce;
|
|
std::atomic<bool> mOnGround;
|
|
std::atomic<bool> mOnSlope;
|
|
std::atomic<bool> mInternalCollisionMode;
|
|
bool mExternalCollisionMode;
|
|
|
|
PhysicsTaskScheduler* mTaskScheduler;
|
|
|
|
Actor(const Actor&);
|
|
Actor& operator=(const Actor&);
|
|
};
|
|
|
|
}
|
|
|
|
|
|
#endif
|