MWWorld::Ptr:
- they are equivalent
- btCollisionObject* is readily available from the simulation, it saves
a call to a mutex
- btCollisionObject* is smaller
- compute the swimming state instead of storing it, it changes as part of the simulation and was not updated, so it was wrong anyway.
- store the swim level in ActorFrameData, it is constant per Actor so no need to compute it inside the simulation
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)
When we call moveObject(), we might trigger a change of cell for the
actor, which in turn triggers updatePtr(). The erase/emplace
construct invalidate references, whereas extract/insert do not.
The reason is was working before !1075 is because we were always
"refreshing" the reference by a call to getActor().
- inline PhysicsSystem::applyQueuedMovements() into PhysicsSystem::stepSimulation()
- rename PhysicsTaskScheduler::moveActors() to PhysicsTaskScheduler::applyQueuedMovements()
- move the actor movement code from World::doPhysics() to
PhysicsSystem::moveActors() (analogically to the projectile manager)
mCanWaterWalk was set to false and updated during next frame's simulation
mOnGround is set to true but then was updated as part of the scene
loading logic.
Since actors can be active in 3x3 grid around the player, we need to
first load all objects in a 5x5 grid around the player.
Split load and unloading in 2 phases. Add an mInactiveCells set into the
scene, which contains all cells inside the aforementioned 5x5 grid.
These cells contains only heightfields and non-animated physics objects.
Animated objects are tied to the scene graph, which doesn't exists yet
in these cells, so we skip them.
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
Restore projectile caster from savegame (#5860)
See merge request OpenMW/openmw!616
(cherry picked from commit d595c7adb0fb45eafed6d3d0403ad640a91411ed)
c5426bec In the savegame, projectile caster is identified by its actor id. When
Since actors can be active in 3x3 grid around the player, we need to
first load all statics in a 5x5 grid around the player.
Split load and unloading in 2 phases. Add an mInactiveCells set into the
scene, which contains all cells inside the aforementioned 5x5 grid.
These cells contains only heightfields and physics objects of static
class.
imprecision issue with projectile collision detection.
Simplify the mechanics: manage hits in one spot.
Give magic projectiles a collision shape similar in size to their visible
model.
Rename the 2 convex result callback to clearly state their purpose.
This unbreak abot's boat mods: they're continually teleporting
the boats (who is an actor with waterwalking effect). As such, the
physics simulation was never run and the boat never went to sea level.
One of the issue since the introduction of async physics is the quirky
handling of scripted moves. Previous attempt to account for them was
based on detecting changes in actor position while the physics thread is
running. To this end, semantics of Actor::updatePosition() (which is
responsible for set the absolute position of an actor in the world) was
toned down to merely store the desired position, with the physics system
actually responsible for moving the actor. For the cases were complete
override of the physics simulation was needed, I introduced
Actor::resetPosition(), which actually have same semantics as
original updatePosition(). This in turn introduced a loads of new bugs
when the weakened semantics broke key assumptions inside the engine
(spawning, summoning, teleport, etc).
Instead of tracking them down, count on the newly introduced support for
object relative movements in the engine (World::moveObjectBy) to
register relative movements and restore original handling of absolute positionning.
Changes are relatively small:
- move resetPosition() content into updatePosition()
- call updatePosition() everywhere it was called before
- remove all added calls to the now non-existing resetPosition()
tldr; ditch last month worth of bug introduction and eradication and redo
it properly
This gives finer control over reseting positions (switch off tcl is no
longer glitchy) and solve most of the erroneous usage of stale World::Ptr
indicated by:
"Error in frame: moveTo: object is not in this cell"
When an NPC fire a projectile, it should affect only its targeted actor.
To this end, after a hit is detected the target is checked against the
list of AI targets and reactivated if necessary.
Problem occurs when the hit occurs as a result of a friendly actor going
into the projectile (detected in ClosestNotMeConvexResultCallback):
while the projectile is inside the friend's collision box, it is
deactivated, just to be immediately reactivated. Effectively, the
projectile does nothing until the actor moves out.
Add a check inside the ClosestNotMeConvexResultCallback before declaring
a hit.
Since the necessary data is not safely accessible from the async thread,
maintain a copy inside the Projectile class.