1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-21 21:17:49 +02:00

Nullkiller: fix freeze on accessing guarded object

This commit is contained in:
Andrii Danylchenko 2021-05-16 14:56:21 +03:00 committed by Andrii Danylchenko
parent 5bfe71c8f3
commit 645c393e25
9 changed files with 45 additions and 14 deletions

View File

@ -44,7 +44,7 @@ void DangerHitMapAnalyzer::updateHitMap()
for(auto pair : heroes)
{
ai->pathfinder->updatePaths(pair.second, false);
ai->pathfinder->updatePaths(pair.second, PathfinderSettings());
foreach_tile_pos([&](const int3 & pos)
{

View File

@ -15,13 +15,13 @@ struct HitMapInfo
{
uint64_t danger;
uint8_t turn;
const CGHeroInstance * hero;
HeroPtr hero;
void reset()
{
danger = 0;
turn = 255;
hero = nullptr;
hero = HeroPtr();
}
};

View File

@ -25,6 +25,12 @@ extern boost::thread_specific_ptr<VCAI> ai;
using namespace Goals;
#if AI_TRACE_LEVEL >= 1
#define MAXPASS 1000000
#else
#define MAXPASS 30
#endif
Nullkiller::Nullkiller()
{
memory.reset(new AIMemory());
@ -152,7 +158,7 @@ void Nullkiller::resetAiState()
dangerHitMap->reset();
}
void Nullkiller::updateAiState()
void Nullkiller::updateAiState(int pass)
{
auto start = boost::chrono::high_resolution_clock::now();
@ -174,7 +180,10 @@ void Nullkiller::updateAiState()
activeHeroes[hero] = heroManager->getHeroRole(hero);
}
pathfinder->updatePaths(activeHeroes, true);
PathfinderSettings cfg;
cfg.useHeroChain = true;
pathfinder->updatePaths(activeHeroes, cfg);
armyManager->update();
@ -226,9 +235,9 @@ void Nullkiller::makeTurn()
{
resetAiState();
while(true)
for(int i = 1; i <= MAXPASS; i++)
{
updateAiState();
updateAiState(i);
Goals::TTaskVec bestTasks = {
choseBestTask(sptr(BuyArmyBehavior())),

View File

@ -68,7 +68,7 @@ public:
private:
void resetAiState();
void updateAiState();
void updateAiState(int pass);
Goals::TTask choseBestTask(Goals::TSubgoal behavior) const;
Goals::TTask choseBestTask(Goals::TTaskVec & tasks) const;
};

View File

@ -84,6 +84,7 @@ void AINodeStorage::clear()
heroChainPass = EHeroChainPass::INITIAL;
heroChainTurn = 0;
heroChainMaxTurns = 1;
scoutTurnDistanceLimit = 255;
}
const AIPathNode * AINodeStorage::getAINode(const CGPathNode * node) const
@ -625,12 +626,12 @@ bool AINodeStorage::isDistanceLimitReached(const PathNodeInfo & source, CDestina
if(heroChainPass == EHeroChainPass::FINAL)
{
if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > 3)
if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > scoutTurnDistanceLimit)
return true;
}
else if(heroChainPass == EHeroChainPass::INITIAL)
{
if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > 5)
if(aiNode->actor->heroRole == HeroRole::SCOUT && destination.node->turns > scoutTurnDistanceLimit)
return true;
}

View File

@ -116,6 +116,7 @@ private:
int heroChainTurn;
int heroChainMaxTurns;
PlayerColor playerID;
uint8_t scoutTurnDistanceLimit;
public:
/// more than 1 chain layer for each hero allows us to have more than 1 path to each tile so we can chose more optimal one.
@ -174,6 +175,7 @@ public:
std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const;
bool isTileAccessible(const HeroPtr & hero, const int3 & pos, const EPathfindingLayer layer) const;
void setHeroes(std::map<const CGHeroInstance *, HeroRole> heroes);
void setScoutTurnDistanceLimit(uint8_t distanceLimit) { scoutTurnDistanceLimit = distanceLimit; }
void setTownsAndDwellings(
const std::vector<const CGTownInstance *> & towns,
const std::set<const CGObjectInstance *> & visitableObjs);

View File

@ -42,7 +42,7 @@ std::vector<AIPath> AIPathfinder::getPathInfo(const int3 & tile) const
return storage->getChainInfo(tile, !tileInfo->isWater());
}
void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes, bool useHeroChain)
void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes, PathfinderSettings pathfinderSettings)
{
if(!storage)
{
@ -55,8 +55,9 @@ void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes
storage->clear();
storage->setHeroes(heroes);
storage->setScoutTurnDistanceLimit(pathfinderSettings.scoutTurnDistanceLimit);
if(useHeroChain)
if(pathfinderSettings.useHeroChain)
{
storage->setTownsAndDwellings(cb->getTownsInfo(), ai->memory->visitableObjs);
}
@ -66,7 +67,7 @@ void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes
logAi->trace("Recalculate paths pass %d", pass++);
cb->calculatePaths(config);
if(!useHeroChain)
if(!pathfinderSettings.useHeroChain)
return;
do

View File

@ -15,6 +15,17 @@
class Nullkiller;
struct PathfinderSettings
{
bool useHeroChain;
uint8_t scoutTurnDistanceLimit;
PathfinderSettings()
:useHeroChain(false),
scoutTurnDistanceLimit(255)
{ }
};
class AIPathfinder
{
private:
@ -26,6 +37,6 @@ public:
AIPathfinder(CPlayerSpecificInfoCallback * cb, Nullkiller * ai);
std::vector<AIPath> getPathInfo(const int3 & tile) const;
bool isTileAccessible(const HeroPtr & hero, const int3 & tile) const;
void updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes, bool useHeroChain = false);
void updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes, PathfinderSettings pathfinderSettings);
void init();
};

View File

@ -135,6 +135,13 @@ namespace AIPathfinding
return false;
}
auto danger = nodeStorage->evaluateDanger(destination.coord, nodeStorage->getHero(destination.node), true);
if(danger)
{
return bypassBattle(source, destination, pathfinderConfig, pathfinderHelper);
}
return true;
}