1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 03:40:14 +00:00

Store CharacterController by value in MWMechanics::Actor

This commit is contained in:
elsid 2022-05-18 19:55:13 +02:00
parent e2c44d13f3
commit 77c09dff39
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40
5 changed files with 45 additions and 51 deletions

View File

@ -5,24 +5,24 @@
namespace MWMechanics namespace MWMechanics
{ {
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation) Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
: mPositionAdjusted(false) : mCharacterController(ptr, animation)
, mPositionAdjusted(false)
{ {
mCharacterController.reset(new CharacterController(ptr, animation));
} }
const MWWorld::Ptr& Actor::getPtr() const const MWWorld::Ptr& Actor::getPtr() const
{ {
return mCharacterController->getPtr(); return mCharacterController.getPtr();
} }
void Actor::updatePtr(const MWWorld::Ptr &newPtr) void Actor::updatePtr(const MWWorld::Ptr &newPtr)
{ {
mCharacterController->updatePtr(newPtr); mCharacterController.updatePtr(newPtr);
} }
CharacterController* Actor::getCharacterController() CharacterController& Actor::getCharacterController()
{ {
return mCharacterController.get(); return mCharacterController;
} }
int Actor::getGreetingTimer() const int Actor::getGreetingTimer() const

View File

@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include "actorutil.hpp" #include "actorutil.hpp"
#include "character.hpp"
#include <components/misc/timer.hpp> #include <components/misc/timer.hpp>
@ -18,8 +19,6 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
class CharacterController;
/// @brief Holds temporary state for an actor that will be discarded when the actor leaves the scene. /// @brief Holds temporary state for an actor that will be discarded when the actor leaves the scene.
class Actor class Actor
{ {
@ -31,7 +30,7 @@ namespace MWMechanics
/// Notify this actor of its new base object Ptr, use when the object changed cells /// Notify this actor of its new base object Ptr, use when the object changed cells
void updatePtr(const MWWorld::Ptr& newPtr); void updatePtr(const MWWorld::Ptr& newPtr);
CharacterController* getCharacterController(); CharacterController& getCharacterController();
int getGreetingTimer() const; int getGreetingTimer() const;
void setGreetingTimer(int timer); void setGreetingTimer(int timer);
@ -51,7 +50,7 @@ namespace MWMechanics
bool getPositionAdjusted() const; bool getPositionAdjusted() const;
private: private:
std::unique_ptr<CharacterController> mCharacterController; CharacterController mCharacterController;
int mGreetingTimer{0}; int mGreetingTimer{0};
float mTargetAngleRadians{0.f}; float mTargetAngleRadians{0.f};
GreetingState mGreetingState{Greet_None}; GreetingState mGreetingState{Greet_None};

View File

@ -774,9 +774,7 @@ namespace MWMechanics
const auto it = mIndex.find(ptr.mRef); const auto it = mIndex.find(ptr.mRef);
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
CharacterController* ctrl = it->second->getCharacterController(); return it->second->getCharacterController().isAttackPreparing();
return ctrl->isAttackPreparing();
} }
bool Actors::isRunning(const MWWorld::Ptr& ptr) bool Actors::isRunning(const MWWorld::Ptr& ptr)
@ -784,9 +782,7 @@ namespace MWMechanics
const auto it = mIndex.find(ptr.mRef); const auto it = mIndex.find(ptr.mRef);
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
CharacterController* ctrl = it->second->getCharacterController(); return it->second->getCharacterController().isRunning();
return ctrl->isRunning();
} }
bool Actors::isSneaking(const MWWorld::Ptr& ptr) bool Actors::isSneaking(const MWWorld::Ptr& ptr)
@ -794,9 +790,7 @@ namespace MWMechanics
const auto it = mIndex.find(ptr.mRef); const auto it = mIndex.find(ptr.mRef);
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
CharacterController* ctrl = it->second->getCharacterController(); return it->second->getCharacterController().isSneaking();
return ctrl->isSneaking();
} }
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer) void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration, bool isKnockedOut, bool isPlayer)
@ -1055,9 +1049,8 @@ namespace MWMechanics
const auto it = mActors.emplace(mActors.end(), ptr, anim); const auto it = mActors.emplace(mActors.end(), ptr, anim);
mIndex.emplace(ptr.mRef, it); mIndex.emplace(ptr.mRef, it);
CharacterController* ctrl = it->getCharacterController();
if (updateImmediately) if (updateImmediately)
ctrl->update(0); it->getCharacterController().update(0);
// We should initially hide actors outside of processing range. // We should initially hide actors outside of processing range.
// Note: since we update player after other actors, distance will be incorrect during teleportation. // Note: since we update player after other actors, distance will be incorrect during teleportation.
@ -1065,10 +1058,10 @@ namespace MWMechanics
if (MWBase::Environment::get().getWorld()->getPlayer().wasTeleported()) if (MWBase::Environment::get().getWorld()->getPlayer().wasTeleported())
return; return;
updateVisibility(ptr, ctrl); updateVisibility(ptr, it->getCharacterController());
} }
void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl) void Actors::updateVisibility (const MWWorld::Ptr& ptr, CharacterController& ctrl)
{ {
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
if (ptr == player) if (ptr == player)
@ -1093,7 +1086,7 @@ namespace MWMechanics
visibilityRatio = std::min(1.f, visibilityRatio); visibilityRatio = std::min(1.f, visibilityRatio);
ctrl->setVisibility(visibilityRatio); ctrl.setVisibility(visibilityRatio);
} }
void Actors::removeActor (const MWWorld::Ptr& ptr, bool keepActive) void Actors::removeActor (const MWWorld::Ptr& ptr, bool keepActive)
@ -1112,7 +1105,7 @@ namespace MWMechanics
{ {
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if (iter != mIndex.end()) if (iter != mIndex.end())
iter->second->getCharacterController()->castSpell(spellId, manualSpell); iter->second->getCharacterController().castSpell(spellId, manualSpell);
} }
bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) bool Actors::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
@ -1402,7 +1395,7 @@ namespace MWMechanics
for (Actor& actor : mActors) for (Actor& actor : mActors)
{ {
const bool isPlayer = actor.getPtr() == player; const bool isPlayer = actor.getPtr() == player;
CharacterController* const ctrl = actor.getCharacterController(); CharacterController& ctrl = actor.getCharacterController();
MWBase::LuaManager::ActorControls* luaControls = MWBase::LuaManager::ActorControls* luaControls =
MWBase::Environment::get().getLuaManager()->getActorControls(actor.getPtr()); MWBase::Environment::get().getLuaManager()->getActorControls(actor.getPtr());
@ -1428,7 +1421,7 @@ namespace MWMechanics
// They can be added during the death animation // They can be added during the death animation
if (!actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished()) if (!actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished())
adjustMagicEffects(actor.getPtr(), duration); adjustMagicEffects(actor.getPtr(), duration);
ctrl->updateContinuousVfx(); ctrl.updateContinuousVfx();
} }
else else
{ {
@ -1441,7 +1434,7 @@ namespace MWMechanics
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles), // Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
// so updating VFX immediately after that would just remove the particle effects instantly. // so updating VFX immediately after that would just remove the particle effects instantly.
// There needs to be a magic effect update in between. // There needs to be a magic effect update in between.
ctrl->updateContinuousVfx(); ctrl.updateContinuousVfx();
if (!cellChanged && world->hasCellChanged()) if (!cellChanged && world->hasCellChanged())
{ {
@ -1498,7 +1491,7 @@ namespace MWMechanics
} }
} }
ctrl->setHeadTrackTarget(headTrackTarget); ctrl.setHeadTrackTarget(headTrackTarget);
} }
if (actor.getPtr().getClass().isNpc() && actor.getPtr() != player) if (actor.getPtr().getClass().isNpc() && actor.getPtr() != player)
@ -1509,7 +1502,7 @@ namespace MWMechanics
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr()); CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
if (isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI)) if (isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI))
{ {
stats.getAiSequence().execute(actor.getPtr(), *ctrl, duration); stats.getAiSequence().execute(actor.getPtr(), ctrl, duration);
updateGreetingState(actor.getPtr(), actor, mTimerUpdateHello > 0); updateGreetingState(actor.getPtr(), actor, mTimerUpdateHello > 0);
playIdleDialogue(actor.getPtr()); playIdleDialogue(actor.getPtr());
updateMovementSpeed(actor.getPtr()); updateMovementSpeed(actor.getPtr());
@ -1519,13 +1512,13 @@ namespace MWMechanics
else if (aiActive && actor.getPtr() != player && isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI)) else if (aiActive && actor.getPtr() != player && isConscious(actor.getPtr()) && !(luaControls && luaControls->mDisableAI))
{ {
CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr()); CreatureStats &stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
stats.getAiSequence().execute(actor.getPtr(), *ctrl, duration, /*outOfRange*/true); stats.getAiSequence().execute(actor.getPtr(), ctrl, duration, /*outOfRange*/true);
} }
if (inProcessingRange && actor.getPtr().getClass().isNpc()) if (inProcessingRange && actor.getPtr().getClass().isNpc())
{ {
// We can not update drowning state for actors outside of AI distance - they can not resurface to breathe // We can not update drowning state for actors outside of AI distance - they can not resurface to breathe
updateDrowning(actor.getPtr(), duration, ctrl->isKnockedOut(), isPlayer); updateDrowning(actor.getPtr(), duration, ctrl.isKnockedOut(), isPlayer);
} }
if (mTimerUpdateEquippedLight == 0 && actor.getPtr().getClass().hasInventoryStore(actor.getPtr())) if (mTimerUpdateEquippedLight == 0 && actor.getPtr().getClass().hasInventoryStore(actor.getPtr()))
updateEquippedLight(actor.getPtr(), updateEquippedLightInterval, showTorches); updateEquippedLight(actor.getPtr(), updateEquippedLightInterval, showTorches);
@ -1594,8 +1587,8 @@ namespace MWMechanics
activeFlag = 2; activeFlag = 2;
int active = inRange ? activeFlag : 0; int active = inRange ? activeFlag : 0;
CharacterController* const ctrl = actor.getCharacterController(); CharacterController& ctrl = actor.getCharacterController();
ctrl->setActive(active); ctrl.setActive(active);
if (!inRange) if (!inRange)
{ {
@ -1615,18 +1608,18 @@ namespace MWMechanics
const bool isDead = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead(); const bool isDead = actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead();
if (!isDead && (!godmode || !isPlayer) && actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isParalyzed()) if (!isDead && (!godmode || !isPlayer) && actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isParalyzed())
ctrl->skipAnim(); ctrl.skipAnim();
// Handle player last, in case a cell transition occurs by casting a teleportation spell // Handle player last, in case a cell transition occurs by casting a teleportation spell
// (would invalidate the iterator) // (would invalidate the iterator)
if (actor.getPtr() == getPlayer()) if (actor.getPtr() == getPlayer())
{ {
playerCharacter = ctrl; playerCharacter = &ctrl;
continue; continue;
} }
world->setActorCollisionMode(actor.getPtr(), true, !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished()); world->setActorCollisionMode(actor.getPtr(), true, !actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDeathAnimationFinished());
ctrl->update(duration); ctrl.update(duration);
updateVisibility(actor.getPtr(), ctrl); updateVisibility(actor.getPtr(), ctrl);
} }
@ -1676,11 +1669,11 @@ namespace MWMechanics
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if (iter != mIndex.end()) if (iter != mIndex.end())
{ {
if (iter->second->getCharacterController()->isDead()) if (iter->second->getCharacterController().isDead())
{ {
// Actor has been resurrected. Notify the CharacterController and re-enable collision. // Actor has been resurrected. Notify the CharacterController and re-enable collision.
MWBase::Environment::get().getWorld()->enableActorCollision(iter->second->getPtr(), true); MWBase::Environment::get().getWorld()->enableActorCollision(iter->second->getPtr(), true);
iter->second->getCharacterController()->resurrect(); iter->second->getCharacterController().resurrect();
} }
} }
} }
@ -1696,7 +1689,7 @@ namespace MWMechanics
continue; continue;
MWBase::Environment::get().getWorld()->removeActorPath(actor.getPtr()); MWBase::Environment::get().getWorld()->removeActorPath(actor.getPtr());
CharacterController::KillResult killResult = actor.getCharacterController()->kill(); CharacterController::KillResult killResult = actor.getCharacterController().kill();
if (killResult == CharacterController::Result_DeathAnimStarted) if (killResult == CharacterController::Result_DeathAnimStarted)
{ {
// Play dying words // Play dying words
@ -1926,7 +1919,7 @@ namespace MWMechanics
{ {
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if (iter != mIndex.end()) if (iter != mIndex.end())
iter->second->getCharacterController()->forceStateUpdate(); iter->second->getCharacterController().forceStateUpdate();
} }
bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) bool Actors::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist)
@ -1934,7 +1927,7 @@ namespace MWMechanics
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if(iter != mIndex.end()) if(iter != mIndex.end())
{ {
return iter->second->getCharacterController()->playGroup(groupName, mode, number, persist); return iter->second->getCharacterController().playGroup(groupName, mode, number, persist);
} }
else else
{ {
@ -1946,21 +1939,21 @@ namespace MWMechanics
{ {
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if (iter != mIndex.end()) if (iter != mIndex.end())
iter->second->getCharacterController()->skipAnim(); iter->second->getCharacterController().skipAnim();
} }
bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
{ {
const auto iter = mIndex.find(ptr.mRef); const auto iter = mIndex.find(ptr.mRef);
if(iter != mIndex.end()) if(iter != mIndex.end())
return iter->second->getCharacterController()->isAnimPlaying(groupName); return iter->second->getCharacterController().isAnimPlaying(groupName);
return false; return false;
} }
void Actors::persistAnimationStates() void Actors::persistAnimationStates()
{ {
for (Actor& actor : mActors) for (Actor& actor : mActors)
actor.getCharacterController()->persistAnimationState(); actor.getCharacterController().persistAnimationState();
} }
void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out) void Actors::getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out)
@ -2195,7 +2188,7 @@ namespace MWMechanics
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
return it->second->getCharacterController()->isReadyToBlock(); return it->second->getCharacterController().isReadyToBlock();
} }
bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const bool Actors::isCastingSpell(const MWWorld::Ptr &ptr) const
@ -2204,7 +2197,7 @@ namespace MWMechanics
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
return it->second->getCharacterController()->isCastingSpell(); return it->second->getCharacterController().isCastingSpell();
} }
bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const bool Actors::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
@ -2212,9 +2205,8 @@ namespace MWMechanics
const auto it = mIndex.find(ptr.mRef); const auto it = mIndex.find(ptr.mRef);
if (it == mIndex.end()) if (it == mIndex.end())
return false; return false;
CharacterController* ctrl = it->second->getCharacterController();
return ctrl->isAttackingOrSpell(); return it->second->getCharacterController().isAttackingOrSpell();
} }
int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const

View File

@ -200,7 +200,7 @@ namespace MWMechanics
bool mSmoothMovement; bool mSmoothMovement;
MusicType mCurrentMusic = MusicType::Explore; MusicType mCurrentMusic = MusicType::Explore;
void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl); void updateVisibility (const MWWorld::Ptr& ptr, CharacterController& ctrl);
void adjustMagicEffects (const MWWorld::Ptr& creature, float duration); void adjustMagicEffects (const MWWorld::Ptr& creature, float duration);

View File

@ -241,7 +241,10 @@ public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();
const MWWorld::Ptr& getPtr() const { return mPtr; }; CharacterController(const CharacterController&) = delete;
CharacterController(CharacterController&&) = delete;
const MWWorld::Ptr& getPtr() const { return mPtr; }
void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override; void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override;