From 92a5e524070a88d2cf972c4191b2cee9993914ea Mon Sep 17 00:00:00 2001 From: Mads Buvik Sandvei Date: Wed, 25 Oct 2023 19:53:34 +0200 Subject: [PATCH] rename "persisted" animations to "scripted", because that is what they actually are. And begin teaching the animation system to distinguish between a scripted and an unscripted animation. --- apps/openmw/mwmechanics/actors.cpp | 4 +- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 59 +++++++++++-------- apps/openmw/mwmechanics/character.hpp | 8 +-- .../mwmechanics/mechanicsmanagerimp.cpp | 6 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwmechanics/objects.cpp | 4 +- apps/openmw/mwmechanics/objects.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 12 +++- apps/openmw/mwrender/animation.hpp | 3 + 10 files changed, 60 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 743c5d5ab5..3e7b075e62 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1998,12 +1998,12 @@ namespace MWMechanics } bool Actors::playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist) const + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted) const { const auto iter = mIndex.find(ptr.mRef); if (iter != mIndex.end()) { - return iter->second->getCharacterController().playGroup(groupName, mode, number, persist); + return iter->second->getCharacterController().playGroup(groupName, mode, number, scripted); } else { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 98c64397ab..15a39136a6 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -113,7 +113,7 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr& ptr) const; bool playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist = false) const; + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted = false) const; void skipAnimation(const MWWorld::Ptr& ptr) const; bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) const; void persistAnimationStates() const; diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9c39b5b60d..0d9cda9263 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -538,7 +538,7 @@ namespace MWMechanics if (mAnimation->isPlaying("containerclose")) return false; - mAnimation->play("containeropen", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, + mAnimation->play("containeropen", Priority_Scripted, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.f, 0); if (mAnimation->isPlaying("containeropen")) return false; @@ -559,7 +559,7 @@ namespace MWMechanics if (animPlaying) startPoint = 1.f - complete; - mAnimation->play("containerclose", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, + mAnimation->play("containerclose", Priority_Scripted, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, 0); } } @@ -828,7 +828,7 @@ namespace MWMechanics CharacterState idle, CharacterState movement, JumpingState jump, bool force) { // If the current animation is persistent, do not touch it - if (isPersistentAnimPlaying()) + if (isScriptedAnimPlaying()) return; refreshHitRecoilAnims(); @@ -882,7 +882,7 @@ namespace MWMechanics mDeathState = chooseRandomDeathState(); // Do not interrupt scripted animation by death - if (isPersistentAnimPlaying()) + if (isScriptedAnimPlaying()) return; playDeath(startpoint, mDeathState); @@ -1482,7 +1482,7 @@ namespace MWMechanics } // Combat for actors with persistent animations obviously will be buggy - if (isPersistentAnimPlaying()) + if (isScriptedAnimPlaying()) return forcestateupdate; float complete = 0.f; @@ -1855,10 +1855,18 @@ namespace MWMechanics if (mAnimQueue.empty()) return; - if (mAnimation->isPlaying(mAnimQueue.front().mGroup) == false) + bool isFrontAnimPlaying = false; + if (mAnimQueue.front().mScripted) + isFrontAnimPlaying = mAnimation->isPlayingScripted(mAnimQueue.front().mGroup); + else + isFrontAnimPlaying = mAnimation->isPlaying(mAnimQueue.front().mGroup); + + + if (!isFrontAnimPlaying) { if (mAnimQueue.size() > 1) { + // Curren animation finished, move to the next in queue mAnimation->disable(mAnimQueue.front().mGroup); mAnimQueue.pop_front(); @@ -1866,14 +1874,13 @@ namespace MWMechanics mAnimation->play(mAnimQueue.front().mGroup, Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback); } - else if (mAnimQueue.front().mLoopCount > 1 && mAnimQueue.front().mPersist) + else if (mAnimQueue.front().mLoopCount > 1 && mAnimQueue.front().mScripted) { - // The last animation stopped playing when it shouldn't have. - // This is caused by a rebuild of the animation object, so we should restart the animation here - // Subtract 1 from mLoopCount to consider the current loop done. + // A scripted animation stopped playing before time. + // This happens when the animation object is rebuilt, so we should restart the animation here. bool loopfallback = mAnimQueue.front().mGroup.starts_with("idle"); - mAnimation->play(mAnimQueue.front().mGroup, Priority_Persistent, MWRender::Animation::BlendMask_All, - false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount - 1, loopfallback); + mAnimation->play(mAnimQueue.front().mGroup, Priority_Scripted, MWRender::Animation::BlendMask_All, + false, 1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback); } else { @@ -2393,7 +2400,7 @@ namespace MWMechanics } } - bool isPersist = isPersistentAnimPlaying(); + bool isPersist = isScriptedAnimPlaying(); osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim && !isPersist ? 0.f : duration); if (duration > 0.0f) moved /= duration; @@ -2450,7 +2457,7 @@ namespace MWMechanics state.mScriptedAnims.clear(); for (AnimationQueue::const_iterator iter = mAnimQueue.begin(); iter != mAnimQueue.end(); ++iter) { - if (!iter->mPersist) + if (!iter->mScripted) continue; ESM::AnimationState::ScriptedAnimation anim; @@ -2486,7 +2493,7 @@ namespace MWMechanics AnimationQueueEntry entry; entry.mGroup = iter->mGroup; entry.mLoopCount = iter->mLoopCount; - entry.mPersist = true; + entry.mScripted = true; mAnimQueue.push_back(entry); } @@ -2505,18 +2512,18 @@ namespace MWMechanics mIdleState = CharState_SpecialIdle; bool loopfallback = mAnimQueue.front().mGroup.starts_with("idle"); - mAnimation->play(anim.mGroup, Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", + mAnimation->play(anim.mGroup, Priority_Scripted, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", complete, anim.mLoopCount, loopfallback); } } - bool CharacterController::playGroup(std::string_view groupname, int mode, int count, bool persist) + bool CharacterController::playGroup(std::string_view groupname, int mode, int count, bool scripted) { if (!mAnimation || !mAnimation->hasAnimation(groupname)) return false; // We should not interrupt persistent animations by non-persistent ones - if (isPersistentAnimPlaying() && !persist) + if (isScriptedAnimPlaying() && !scripted) return true; // If this animation is a looped animation (has a "loop start" key) that is already playing @@ -2545,17 +2552,17 @@ namespace MWMechanics AnimationQueueEntry entry; entry.mGroup = groupname; entry.mLoopCount = count - 1; - entry.mPersist = persist; + entry.mScripted = scripted; if (mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup)) { - clearAnimQueue(persist); + clearAnimQueue(scripted); clearStateAnimation(mCurrentIdle); mIdleState = CharState_SpecialIdle; bool loopfallback = entry.mGroup.starts_with("idle"); - mAnimation->play(groupname, persist && groupname != "idle" ? Priority_Persistent : Priority_Default, + mAnimation->play(groupname, scripted && groupname != "idle" ? Priority_Scripted : Priority_Default, MWRender::Animation::BlendMask_All, false, 1.0f, ((mode == 2) ? "loop start" : "start"), "stop", 0.0f, count - 1, loopfallback); } @@ -2566,7 +2573,7 @@ namespace MWMechanics // "PlayGroup idle" is a special case, used to remove to stop scripted animations playing if (groupname == "idle") - entry.mPersist = false; + entry.mScripted = false; mAnimQueue.push_back(entry); @@ -2578,12 +2585,12 @@ namespace MWMechanics mSkipAnim = true; } - bool CharacterController::isPersistentAnimPlaying() const + bool CharacterController::isScriptedAnimPlaying() const { if (!mAnimQueue.empty()) { const AnimationQueueEntry& first = mAnimQueue.front(); - return first.mPersist && isAnimPlaying(first.mGroup); + return first.mScripted && isAnimPlaying(first.mGroup); } return false; @@ -2609,7 +2616,7 @@ namespace MWMechanics void CharacterController::clearAnimQueue(bool clearPersistAnims) { // Do not interrupt scripted animations, if we want to keep them - if ((!isPersistentAnimPlaying() || clearPersistAnims) && !mAnimQueue.empty()) + if ((!isScriptedAnimPlaying() || clearPersistAnims) && !mAnimQueue.empty()) mAnimation->disable(mAnimQueue.front().mGroup); if (clearPersistAnims) @@ -2620,7 +2627,7 @@ namespace MWMechanics for (AnimationQueue::iterator it = mAnimQueue.begin(); it != mAnimQueue.end();) { - if (!it->mPersist) + if (!it->mScripted) it = mAnimQueue.erase(it); else ++it; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 316a1cff0e..79bbe73538 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -40,7 +40,7 @@ namespace MWMechanics Priority_Torch, Priority_Storm, Priority_Death, - Priority_Persistent, + Priority_Scripted, Num_Priorities }; @@ -135,7 +135,7 @@ namespace MWMechanics { std::string mGroup; size_t mLoopCount; - bool mPersist; + bool mScripted; }; typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; @@ -215,7 +215,7 @@ namespace MWMechanics std::string chooseRandomAttackAnimation() const; static bool isRandomAttackAnimation(std::string_view group); - bool isPersistentAnimPlaying() const; + bool isScriptedAnimPlaying() const; bool isMovementAnimationControlled() const; void updateAnimQueue(); @@ -270,7 +270,7 @@ namespace MWMechanics void persistAnimationState() const; void unpersistAnimationState(); - bool playGroup(std::string_view groupname, int mode, int count, bool persist = false); + bool playGroup(std::string_view groupname, int mode, int count, bool scripted = false); void skipAnim(); bool isAnimPlaying(std::string_view groupName) const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 071ac164f3..f95df16855 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -760,12 +760,12 @@ namespace MWMechanics } bool MechanicsManager::playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist) + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted) { if (ptr.getClass().isActor()) - return mActors.playAnimationGroup(ptr, groupName, mode, number, persist); + return mActors.playAnimationGroup(ptr, groupName, mode, number, scripted); else - return mObjects.playAnimationGroup(ptr, groupName, mode, number, persist); + return mObjects.playAnimationGroup(ptr, groupName, mode, number, scripted); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 36bb18e022..997636522e 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -142,7 +142,7 @@ namespace MWMechanics /// Attempt to play an animation group /// @return Success or error bool playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist = false) override; + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted = false) override; void skipAnimation(const MWWorld::Ptr& ptr) override; bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) override; void persistAnimationStates() override; diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index ab981dd459..5bdfc91ac7 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -99,12 +99,12 @@ namespace MWMechanics } bool Objects::playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist) + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted) { const auto iter = mIndex.find(ptr.mRef); if (iter != mIndex.end()) { - return iter->second->playGroup(groupName, mode, number, persist); + return iter->second->playGroup(groupName, mode, number, scripted); } else { diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 8b5962109c..296f454e4f 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -46,7 +46,7 @@ namespace MWMechanics void onClose(const MWWorld::Ptr& ptr); bool playAnimationGroup( - const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool persist = false); + const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted = false); void skipAnimation(const MWWorld::Ptr& ptr); void persistAnimationStates(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b49f382f66..cae3687afb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1020,6 +1020,14 @@ namespace MWRender return false; } + bool Animation::isPlayingScripted(std::string_view groupname) const + { + AnimStateMap::const_iterator state(mStates.find(groupname)); + if (state != mStates.end()) + return state->second.mPlaying && state->second.mPriority.contains(MWMechanics::Priority::Priority_Scripted); + return false; + } + bool Animation::getInfo(std::string_view groupname, float* complete, float* speedmult) const { AnimStateMap::const_iterator iter = mStates.find(groupname); @@ -1145,7 +1153,7 @@ namespace MWRender bool hasScriptedAnims = false; for (AnimStateMap::iterator stateiter = mStates.begin(); stateiter != mStates.end(); stateiter++) { - if (stateiter->second.mPriority.contains(int(MWMechanics::Priority_Persistent)) + if (stateiter->second.mPriority.contains(int(MWMechanics::Priority_Scripted)) && stateiter->second.mPlaying) { hasScriptedAnims = true; @@ -1158,7 +1166,7 @@ namespace MWRender while (stateiter != mStates.end()) { AnimState& state = stateiter->second; - if (hasScriptedAnims && !state.mPriority.contains(int(MWMechanics::Priority_Persistent))) + if (hasScriptedAnims && !state.mPriority.contains(int(MWMechanics::Priority_Scripted))) { ++stateiter; continue; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 8615811cc3..9a55c91fc4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -432,6 +432,9 @@ namespace MWRender /** Returns true if the named animation group is playing. */ bool isPlaying(std::string_view groupname) const; + /** Returns true if the named, scripted animation group is playing. */ + bool isPlayingScripted(std::string_view groupname) const; + /// Returns true if no important animations are currently playing on the upper body. bool upperBodyReady() const;