From 5e6fcc2aefbf2eccf5e16deeb2f064c66efcb497 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Wed, 29 Jul 2015 14:15:06 -0400 Subject: [PATCH 1/6] Alert the user if attempting to play an animation fails This is mostly propogating the error up the stack so the game can do something about it. Working on avoiding log spam from calling an animation that doesn't exist every frame. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 ++- apps/openmw/mwmechanics/actors.cpp | 12 ++++++++++-- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 6 +++++- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++--- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 +++- apps/openmw/mwmechanics/objects.cpp | 13 +++++++++++-- apps/openmw/mwmechanics/objects.hpp | 2 +- 9 files changed, 37 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 2c4a22c07..63ad1d32f 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -160,12 +160,13 @@ namespace MWBase virtual void forceStateUpdate(const MWWorld::Ptr &ptr) = 0; ///< Forces an object to refresh its animation state. - virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; + virtual bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number=1) = 0; ///< Run animation for a MW-reference. Calls to this function for references that are currently not /// in the scene should be ignored. /// /// \param mode 0 normal, 1 immediate start, 2 immediate loop /// \param count How many times the animation should be run + /// \return Success or error virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c135811dd..dd2fe3cad 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1,6 +1,7 @@ #include "actors.hpp" #include +#include #include @@ -1241,11 +1242,18 @@ namespace MWMechanics iter->second->getCharacterController()->forceStateUpdate(); } - void Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) + bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrActorMap::iterator iter = mActors.find(ptr); if(iter != mActors.end()) - iter->second->getCharacterController()->playGroup(groupName, mode, number); + { + return iter->second->getCharacterController()->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Actors::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Actors::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4baaea28d..a16b80884 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -105,7 +105,7 @@ namespace MWMechanics void forceStateUpdate(const MWWorld::Ptr &ptr); - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 9d5f7137f..1bd12b53f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1866,10 +1866,13 @@ void CharacterController::update(float duration) } -void CharacterController::playGroup(const std::string &groupname, int mode, int count) +bool CharacterController::playGroup(const std::string &groupname, int mode, int count) { if(!mAnimation || !mAnimation->hasAnimation(groupname)) + { std::cerr<< "Animation "< + #include "movement.hpp" #include "../mwbase/environment.hpp" @@ -77,11 +79,18 @@ void Objects::update(float duration, bool paused) } } -void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { PtrControllerMap::iterator iter = mObjects.find(ptr); if(iter != mObjects.end()) - iter->second->playGroup(groupName, mode, number); + { + return iter->second->playGroup(groupName, mode, number); + } + else + { + std::cerr<< "Error in Objects::playAnimationGroup: Unable to find " << ptr.getTypeName() << std::endl; + return false; + } } void Objects::skipAnimation(const MWWorld::Ptr& ptr) { diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6e22c0582..07e00675c 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,7 +38,7 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); From f69de1f2636f6627a25e1c026e7d176cf7e6108e Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:08:58 -0400 Subject: [PATCH 2/6] Alert the user if trying to play a non-idle animation Continue to propagate success/failure up the call stack. --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- apps/openmw/mwmechanics/aiwander.hpp | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e230998eb..e3ce4ae2a 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,6 +1,7 @@ #include "aiwander.hpp" #include +#include #include @@ -621,12 +622,17 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mPosition[1] = 0; } - void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) { const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + return MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } + else + { + std::cerr<< "Attempted to play out of range idle animation \""< Date: Thu, 30 Jul 2015 08:15:45 -0400 Subject: [PATCH 3/6] Refactor onChooseActionStatePerFrameActions This prevents playIdle errors from tyring to play idleAnimation 0 --- apps/openmw/mwmechanics/aiwander.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e3ce4ae2a..f05040b66 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -392,18 +392,24 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); + //If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; } else { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + //Recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); mStartTime = currentTime; - playIdle(actor, idleAnimation); storage.mState = Wander_IdleNow; } + + //If we aren't going to just stand + if(idleAnimation) + { + playIdle(actor, idleAnimation); + } } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) From 61c38356378fb4ab0de5bf4a23cd828b40ab7a29 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Thu, 30 Jul 2015 08:20:16 -0400 Subject: [PATCH 4/6] Don't try to play animations we know are bad Prevents log spam --- apps/openmw/mwmechanics/aiwander.cpp | 34 +++++++++++++++++----------- apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f05040b66..331ec8b9d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -58,7 +58,6 @@ namespace MWMechanics bool mTurnActorGivingGreetingToFacePlayer; float mReaction; // update some actions infrequently - AiWander::GreetingState mSaidGreeting; int mGreetingTimer; @@ -68,6 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; + std::vector mBadIdles; //Idle animations that when called cause errors PathFinder mPathFinder; @@ -79,7 +79,8 @@ namespace MWMechanics mGreetingTimer(0), mCell(NULL), mState(AiWander::Wander_ChooseAction), - mIdleAnimation(0) + mIdleAnimation(0), + mBadIdles() {}; }; @@ -392,24 +393,31 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - //If we should be moving + // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; + return; } - else - { - //Recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartTime = currentTime; - storage.mState = Wander_IdleNow; - } - - //If we aren't going to just stand + // If we aren't going to just stand if(idleAnimation) { - playIdle(actor, idleAnimation); + // If the idle animation actually exists + if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) + { + if(!playIdle(actor, idleAnimation)) + { + std::cerr<< "Unable to play idle animation "<getTimeStamp(); + storage.mState = Wander_IdleNow; + return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index c03cdfaa2..27e6fe9fb 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -76,8 +76,8 @@ namespace MWMechanics void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage); - ///Have the given actor play an idle animation - ///@return Success or error + /// Have the given actor play an idle animation + /// @return Success or error bool playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); short unsigned getRandomIdle(); From 6fce49bfb5e6a32127852193dc9413bec59488c5 Mon Sep 17 00:00:00 2001 From: Arthur Moore Date: Fri, 31 Jul 2015 18:00:17 -0400 Subject: [PATCH 5/6] Don't warn twice when unable to play an idle animation --- apps/openmw/mwmechanics/aiwander.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 331ec8b9d..b356c6e7d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -407,7 +407,6 @@ namespace MWMechanics { if(!playIdle(actor, idleAnimation)) { - std::cerr<< "Unable to play idle animation "< Date: Fri, 31 Jul 2015 18:23:07 -0400 Subject: [PATCH 6/6] Remove more comments --- apps/openmw/mwmechanics/aiwander.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b356c6e7d..440814fb7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -67,7 +67,7 @@ namespace MWMechanics AiWander::WanderState mState; unsigned short mIdleAnimation; - std::vector mBadIdles; //Idle animations that when called cause errors + std::vector mBadIdles; // Idle animations that when called cause errors PathFinder mPathFinder; @@ -393,16 +393,13 @@ namespace MWMechanics short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); - // If we should be moving if (!idleAnimation && mDistance) { storage.mState = Wander_MoveNow; return; } - // If we aren't going to just stand if(idleAnimation) { - // If the idle animation actually exists if(std::find(storage.mBadIdles.begin(), storage.mBadIdles.end(), idleAnimation)==storage.mBadIdles.end()) { if(!playIdle(actor, idleAnimation)) @@ -416,7 +413,6 @@ namespace MWMechanics // Recreate vanilla (broken?) behavior of resetting start time of AIWander: mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); storage.mState = Wander_IdleNow; - return; } void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration)