From 31d8ce266b3f8f726b49f484e7fd1a8f5bec63f1 Mon Sep 17 00:00:00 2001 From: fredzio Date: Sat, 6 Mar 2021 09:46:37 +0100 Subject: [PATCH] Close a race between main and physics threads when actor is positioned by scripts. When a position is forced, the actor position in physics subsystem is overriden. The background physics thread is not made aware of this, its result are simply discarded. There is a short window where this doesn't work (in this example, actor is at A and script moves it to B) 1) actor position is set to B. (among others, Actor::mPosition is set to B) 2) physics thread reset Actor::mPosition with stale value (around A) 3) main thread read simulation result, reset Actor::mSkipSimulation flag => actor is at B 4) physics thread fetch latest Actor::mPosition value, which is around A 5) main thread read simulation result, actor is around A To avoid this situation, do not perform 2) until after 3) occurs. This way, at 4) starts the simulation with up-to-date Actor::mPosition --- apps/openmw/mwphysics/actor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 3b52ee934f..bbec4d4456 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -174,6 +174,9 @@ osg::Vec3f Actor::getCollisionObjectPosition() const bool Actor::setPosition(const osg::Vec3f& position) { std::scoped_lock lock(mPositionMutex); + // position is being forced, ignore simulation results until we sync up + if (mSkipSimulation) + return false; bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged; mPreviousPosition = mPosition + mPositionOffset; mPosition = position + mPositionOffset;