1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-29 01:45:33 +00:00
openmw-tes3mp/apps/openmw/mwphysics/mtphysics.hpp
fredzio e5fa457fe7 Properly account for interleaved move of actors.
Before this change, if an actor position was changed while the physics
simulation was running, the simulation result would be discarded. It is
fine in case of one off event such as teleport, but in the case of
scripts making use of this functionality to make lifts or conveyor (such
as Sotha Sil Expanded mod) it broke actor movement.

To alleviate this issue, at the end of the simulation, the position of the Actor
in the world is compared to the position it had at the beginning of the
simulation. A difference indicate a force move occured. In this case,
the Actor mPosition and mPreviousPosition are translated by the difference of position.

Since the Actor position will be really set while the next simulation runs, we
save it in the mNextPosition field.
2020-11-14 20:39:16 +01:00

93 lines
4.1 KiB
C++

#ifndef OPENMW_MWPHYSICS_MTPHYSICS_H
#define OPENMW_MWPHYSICS_MTPHYSICS_H
#include <atomic>
#include <condition_variable>
#include <optional>
#include <shared_mutex>
#include <thread>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include "physicssystem.hpp"
#include "ptrholder.hpp"
namespace Misc
{
class Barrier;
}
namespace MWPhysics
{
class PhysicsTaskScheduler
{
public:
PhysicsTaskScheduler(float physicsDt, std::shared_ptr<btCollisionWorld> collisionWorld);
~PhysicsTaskScheduler();
/// @brief move actors taking into account desired movements and collisions
/// @param numSteps how much simulation step to run
/// @param timeAccum accumulated time from previous run to interpolate movements
/// @param actorsData per actor data needed to compute new positions
/// @return new position of each actor
const PtrPositionList& moveActors(int numSteps, float timeAccum, std::vector<ActorFrameData>&& actorsData, CollisionMap& standingCollisions, bool skip);
// Thread safe wrappers
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
void convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, btCollisionWorld::ConvexResultCallback& resultCallback) const;
void contactTest(btCollisionObject* colObj, btCollisionWorld::ContactResultCallback& resultCallback);
std::optional<btVector3> getHitPoint(const btTransform& from, btCollisionObject* target);
void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback);
void getAabb(const btCollisionObject* obj, btVector3& min, btVector3& max);
void setCollisionFilterMask(btCollisionObject* collisionObject, int collisionFilterMask);
void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask);
void removeCollisionObject(btCollisionObject* collisionObject);
void updateSingleAabb(std::weak_ptr<PtrHolder> ptr);
bool getLineOfSight(const std::weak_ptr<Actor>& actor1, const std::weak_ptr<Actor>& actor2);
private:
void syncComputation();
void worker();
void updateActorsPositions();
bool hasLineOfSight(const Actor* actor1, const Actor* actor2);
void refreshLOSCache();
void updateAabbs();
void updatePtrAabb(const std::weak_ptr<PtrHolder>& ptr);
std::unique_ptr<WorldFrameData> mWorldFrameData;
std::vector<ActorFrameData> mActorsFrameData;
PtrPositionList mMovementResults;
PtrPositionList mPreviousMovementResults;
const float mPhysicsDt;
float mTimeAccum;
std::shared_ptr<btCollisionWorld> mCollisionWorld;
std::vector<LOSRequest> mLOSCache;
std::set<std::weak_ptr<PtrHolder>, std::owner_less<std::weak_ptr<PtrHolder>>> mUpdateAabb;
// TODO: use std::experimental::flex_barrier or std::barrier once it becomes a thing
std::unique_ptr<Misc::Barrier> mPreStepBarrier;
std::unique_ptr<Misc::Barrier> mPostStepBarrier;
std::unique_ptr<Misc::Barrier> mPostSimBarrier;
int mNumThreads;
int mNumJobs;
int mRemainingSteps;
int mLOSCacheExpiry;
bool mDeferAabbUpdate;
bool mNewFrame;
bool mAdvanceSimulation;
bool mThreadSafeBullet;
bool mQuit;
std::atomic<int> mNextJob;
std::atomic<int> mNextLOS;
std::vector<std::thread> mThreads;
mutable std::shared_mutex mSimulationMutex;
mutable std::shared_mutex mCollisionWorldMutex;
mutable std::shared_mutex mLOSCacheMutex;
mutable std::mutex mUpdateAabbMutex;
std::condition_variable_any mHasJob;
};
}
#endif