1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-21 08:23:53 +00:00

Merge pull request #2886 from elsid/ai_package_unique_ptr

Store AIPackages as unique_ptr
This commit is contained in:
Bret Curtis 2020-06-01 21:41:00 +02:00 committed by GitHub
commit 998f4f73f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 74 deletions

View file

@ -112,11 +112,11 @@ void adjustCommandedActor (const MWWorld::Ptr& actor)
bool hasCommandPackage = false;
std::list<MWMechanics::AiPackage*>::const_iterator it;
for (it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
auto it = stats.getAiSequence().begin();
for (; it != stats.getAiSequence().end(); ++it)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow &&
static_cast<MWMechanics::AiFollow*>(*it)->isCommanded())
static_cast<const MWMechanics::AiFollow*>(it->get())->isCommanded())
{
hasCommandPackage = true;
break;
@ -419,7 +419,7 @@ namespace MWMechanics
if (world->isSwimming(actor) || (playerPos - actorPos).length2() >= 3000 * 3000)
return;
// Our implementation is not FPS-dependent unlike Morrowind's so it needs to be recalibrated.
// Our implementation is not FPS-dependent unlike Morrowind's so it needs to be recalibrated.
// We chose to use the chance MW would have when run at 60 FPS with the default value of the GMST.
const float delta = MWBase::Environment::get().getFrameDuration() * 6.f;
static const float fVoiceIdleOdds = world->getStore().get<ESM::GameSetting>().find("fVoiceIdleOdds")->mValue.getFloat();
@ -435,9 +435,9 @@ namespace MWMechanics
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
MWMechanics::AiSequence& seq = stats.getAiSequence();
if (!seq.isEmpty() && seq.getActivePackage()->useVariableSpeed())
if (!seq.isEmpty() && seq.getActivePackage().useVariableSpeed())
{
osg::Vec3f targetPos = seq.getActivePackage()->getDestination();
osg::Vec3f targetPos = seq.getActivePackage().getDestination();
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
float distance = (targetPos - actorPos).length();
if (distance < DECELERATE_DISTANCE)
@ -604,7 +604,7 @@ namespace MWMechanics
bool isPlayerFollowerOrEscorter = playerAllies.find(actor1) != playerAllies.end();
// If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them
// Doesn't apply for player followers/escorters
// Doesn't apply for player followers/escorters
if (!aggressive && !isPlayerFollowerOrEscorter)
{
// Check that actor2 is in combat with actor1
@ -673,7 +673,7 @@ namespace MWMechanics
return;
bool followerOrEscorter = false;
for (const AiPackage* package : creatureStats2.getAiSequence())
for (const auto& package : creatureStats2.getAiSequence())
{
// The follow package must be first or have nothing but combat before it
if (package->sideWithTarget())
@ -1738,7 +1738,7 @@ namespace MWMechanics
if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed())
{
MWMechanics::AiSequence& seq = stats.getAiSequence();
alwaysActive = !seq.isEmpty() && seq.getActivePackage()->alwaysActive();
alwaysActive = !seq.isEmpty() && seq.getActivePackage().alwaysActive();
}
bool inRange = isPlayer || dist <= mActorsProcessingRange || alwaysActive;
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
@ -2158,7 +2158,7 @@ namespace MWMechanics
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
// Actors that are targeted by this actor's Follow or Escort packages also side with them
for (const AiPackage* package : stats.getAiSequence())
for (const auto& package : stats.getAiSequence())
{
if (package->sideWithTarget() && !package->getTarget().isEmpty())
{
@ -2192,9 +2192,9 @@ namespace MWMechanics
if (stats.isDead())
continue;
// An actor counts as following if AiFollow is the current AiPackage,
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (const AiPackage* package : stats.getAiSequence())
for (const auto& package : stats.getAiSequence())
{
if (package->followTargetThroughDoors() && package->getTarget() == actor)
list.push_back(iteratedActor);
@ -2257,11 +2257,11 @@ namespace MWMechanics
// An actor counts as following if AiFollow is the current AiPackage,
// or there are only Combat and Wander packages before the AiFollow package
for (AiPackage* package : stats.getAiSequence())
for (const auto& package : stats.getAiSequence())
{
if (package->followTargetThroughDoors() && package->getTarget() == actor)
{
list.push_back(static_cast<AiFollow*>(package)->getFollowIndex());
list.push_back(static_cast<const AiFollow*>(package.get())->getFollowIndex());
break;
}
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)

View file

@ -1,6 +1,8 @@
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
#define GAME_MWMECHANICS_AIPACKAGE_H
#include <memory>
#include <components/esm/defs.hpp>
#include "pathfinding.hpp"
@ -59,7 +61,7 @@ namespace MWMechanics
virtual ~AiPackage() = default;
///Clones the package
virtual AiPackage *clone() const = 0;
virtual std::unique_ptr<AiPackage> clone() const = 0;
/// Updates and runs the package (Should run every frame)
/// \return Package completed?

View file

@ -25,9 +25,8 @@ namespace MWMechanics
void AiSequence::copy (const AiSequence& sequence)
{
for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin());
iter!=sequence.mPackages.end(); ++iter)
mPackages.push_back ((*iter)->clone());
for (const auto& package : sequence.mPackages)
mPackages.push_back(package->clone());
// We need to keep an AiWander storage, if present - it has a state machine.
// Not sure about another temporary storages
@ -74,7 +73,7 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
{
if (getTypeId() != AiPackage::TypeIdCombat)
return false;
targetActor = mPackages.front()->getTarget();
return !targetActor.isEmpty();
@ -82,7 +81,7 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
{
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCombat)
targetActors.push_back((*it)->getTarget());
@ -91,24 +90,23 @@ bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
return !targetActors.empty();
}
std::list<AiPackage*>::const_iterator AiSequence::begin() const
std::list<std::unique_ptr<AiPackage>>::const_iterator AiSequence::begin() const
{
return mPackages.begin();
}
std::list<AiPackage*>::const_iterator AiSequence::end() const
std::list<std::unique_ptr<AiPackage>>::const_iterator AiSequence::end() const
{
return mPackages.end();
}
void AiSequence::erase(std::list<AiPackage*>::const_iterator package)
void AiSequence::erase(std::list<std::unique_ptr<AiPackage>>::const_iterator package)
{
// Not sure if manually terminated packages should trigger mDone, probably not?
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for(auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if (package == it)
{
delete *it;
mPackages.erase(it);
return;
}
@ -118,7 +116,7 @@ void AiSequence::erase(std::list<AiPackage*>::const_iterator package)
bool AiSequence::isInCombat() const
{
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
return true;
@ -128,7 +126,7 @@ bool AiSequence::isInCombat() const
bool AiSequence::isEngagedWithActor() const
{
for (std::list<AiPackage *>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
{
@ -142,7 +140,7 @@ bool AiSequence::isEngagedWithActor() const
bool AiSequence::hasPackage(int typeId) const
{
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == typeId)
return true;
@ -152,7 +150,7 @@ bool AiSequence::hasPackage(int typeId) const
bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
{
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
{
@ -165,11 +163,10 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
void AiSequence::stopCombat()
{
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
for(auto it = mPackages.begin(); it != mPackages.end(); )
{
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
{
delete *it;
it = mPackages.erase(it);
}
else
@ -179,11 +176,10 @@ void AiSequence::stopCombat()
void AiSequence::stopPursuit()
{
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
for(auto it = mPackages.begin(); it != mPackages.end(); )
{
if ((*it)->getTypeId() == AiPackage::TypeIdPursue)
{
delete *it;
it = mPackages.erase(it);
}
else
@ -213,7 +209,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
}
auto packageIt = mPackages.begin();
MWMechanics::AiPackage* package = *packageIt;
MWMechanics::AiPackage* package = packageIt->get();
if (!package->alwaysActive() && outOfRange)
return;
@ -231,7 +227,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
float bestRating = 0.f;
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
for (auto it = mPackages.begin(); it != mPackages.end();)
{
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
@ -240,7 +236,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
// target disappeared (e.g. summoned creatures)
if (target.isEmpty())
{
delete *it;
it = mPackages.erase(it);
}
else
@ -276,13 +271,13 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
}
packageIt = mPackages.begin();
package = *packageIt;
package = packageIt->get();
packageTypeId = package->getTypeId();
}
try
{
if (package->execute (actor, characterController, mAiState, duration))
if (package->execute(actor, characterController, mAiState, duration))
{
// Put repeating noncombat AI packages on the end of the stack so they can be used again
if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat()))
@ -293,7 +288,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
// To account for the rare case where AiPackage::execute() queued another AI package
// (e.g. AiPursue executing a dialogue script that uses startCombat)
mPackages.erase(packageIt);
delete package;
if (isActualAiPackage(packageTypeId))
mDone = true;
}
@ -311,9 +305,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
void AiSequence::clear()
{
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
delete *iter;
mPackages.clear();
}
@ -340,8 +331,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
osg::Vec3f dest;
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
{
AiPackage* activePackage = getActivePackage();
dest = activePackage->getDestination(actor);
dest = getActivePackage().getDestination(actor);
}
else
{
@ -355,11 +345,10 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
// remove previous packages if required
if (cancelOther && package.shouldCancelPreviousAi())
{
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
for (auto it = mPackages.begin(); it != mPackages.end();)
{
if((*it)->canCancel())
{
delete *it;
it = mPackages.erase(it);
}
else
@ -369,7 +358,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
}
// insert new package in correct place depending on priority
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
{
// We should keep current AiCast package, if we try to add a new one.
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCast &&
@ -380,12 +369,12 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
if((*it)->getPriority() <= package.getPriority())
{
mPackages.insert(it,package.clone());
mPackages.insert(it, package.clone());
return;
}
}
mPackages.push_back (package.clone());
mPackages.push_back(package.clone());
// Make sure that temporary storage is empty
if (cancelOther)
@ -401,12 +390,11 @@ bool MWMechanics::AiSequence::isEmpty() const
return mPackages.empty();
}
AiPackage* MWMechanics::AiSequence::getActivePackage()
const AiPackage& MWMechanics::AiSequence::getActivePackage()
{
if(mPackages.empty())
throw std::runtime_error(std::string("No AI Package!"));
else
return mPackages.front();
return *mPackages.front();
}
void AiSequence::fill(const ESM::AIPackageList &list)
@ -417,7 +405,7 @@ void AiSequence::fill(const ESM::AIPackageList &list)
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
{
MWMechanics::AiPackage* package;
std::unique_ptr<MWMechanics::AiPackage> package;
if (it->mType == ESM::AI_Wander)
{
ESM::AIWander data = it->mWander;
@ -425,38 +413,36 @@ void AiSequence::fill(const ESM::AIPackageList &list)
idles.reserve(8);
for (int i=0; i<8; ++i)
idles.push_back(data.mIdle[i]);
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
package = std::make_unique<MWMechanics::AiWander>(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
}
else if (it->mType == ESM::AI_Escort)
{
ESM::AITarget data = it->mTarget;
package = new MWMechanics::AiEscort(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
package = std::make_unique<MWMechanics::AiEscort>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
}
else if (it->mType == ESM::AI_Travel)
{
ESM::AITravel data = it->mTravel;
package = new MWMechanics::AiTravel(data.mX, data.mY, data.mZ);
package = std::make_unique<MWMechanics::AiTravel>(data.mX, data.mY, data.mZ);
}
else if (it->mType == ESM::AI_Activate)
{
ESM::AIActivate data = it->mActivate;
package = new MWMechanics::AiActivate(data.mName.toString());
package = std::make_unique<MWMechanics::AiActivate>(data.mName.toString());
}
else //if (it->mType == ESM::AI_Follow)
{
ESM::AITarget data = it->mTarget;
package = new MWMechanics::AiFollow(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
package = std::make_unique<MWMechanics::AiFollow>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
}
mPackages.push_back(package);
mPackages.push_back(std::move(package));
}
}
void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const
{
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
{
(*iter)->writeState(sequence);
}
for (const auto& package : mPackages)
package->writeState(sequence);
sequence.mLastAiPackage = mLastAiPackage;
}
@ -527,7 +513,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
if (!package.get())
continue;
mPackages.push_back(package.release());
mPackages.push_back(std::move(package));
}
mLastAiPackage = sequence.mLastAiPackage;
@ -537,8 +523,7 @@ void AiSequence::fastForward(const MWWorld::Ptr& actor)
{
if (!mPackages.empty())
{
MWMechanics::AiPackage* package = mPackages.front();
package->fastForward(actor, mAiState);
mPackages.front()->fastForward(actor, mAiState);
}
}

View file

@ -2,6 +2,7 @@
#define GAME_MWMECHANICS_AISEQUENCE_H
#include <list>
#include <memory>
#include "aistate.hpp"
@ -36,7 +37,7 @@ namespace MWMechanics
class AiSequence
{
///AiPackages to run though
std::list<AiPackage *> mPackages;
std::list<std::unique_ptr<AiPackage>> mPackages;
///Finished with top AIPackage, set for one frame
bool mDone;
@ -64,10 +65,10 @@ namespace MWMechanics
virtual ~AiSequence();
/// Iterator may be invalidated by any function calls other than begin() or end().
std::list<AiPackage*>::const_iterator begin() const;
std::list<AiPackage*>::const_iterator end() const;
std::list<std::unique_ptr<AiPackage>>::const_iterator begin() const;
std::list<std::unique_ptr<AiPackage>>::const_iterator end() const;
void erase (std::list<AiPackage*>::const_iterator package);
void erase(std::list<std::unique_ptr<AiPackage>>::const_iterator package);
/// Returns currently executing AiPackage type
/** \see enum AiPackage::TypeId **/
@ -125,7 +126,7 @@ namespace MWMechanics
/// Return the current active package.
/** If there is no active package, it will throw an exception **/
AiPackage* getActivePackage();
const AiPackage& getActivePackage();
/// Fills the AiSequence with packages
/** Typically used for loading from the ESM

View file

@ -8,9 +8,9 @@ namespace MWMechanics
template <class T>
struct TypedAiPackage : public AiPackage
{
virtual TypedAiPackage<T> *clone() const override
virtual std::unique_ptr<AiPackage> clone() const override
{
return new T(*static_cast<const T*>(this));
return std::make_unique<T>(*static_cast<const T*>(this));
}
};
}

View file

@ -3063,7 +3063,7 @@ namespace MWWorld
{
if (actor != MWMechanics::getPlayer())
{
for (const MWMechanics::AiPackage* package : stats.getAiSequence())
for (const auto& package : stats.getAiSequence())
{
if (package->getTypeId() == MWMechanics::AiPackage::TypeIdCast)
{