Explorar el Código

Nullkiller: fix freeze on accessing guarded object

Andrii Danylchenko hace 4 años
padre
commit
645c393e25

+ 1 - 1
AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp

@@ -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)
 		{

+ 2 - 2
AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.h

@@ -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();
 	}
 };
 

+ 13 - 4
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -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())),

+ 1 - 1
AI/Nullkiller/Engine/Nullkiller.h

@@ -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;
 };

+ 3 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -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;
 	}
 

+ 2 - 0
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -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);

+ 4 - 3
AI/Nullkiller/Pathfinding/AIPathfinder.cpp

@@ -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

+ 12 - 1
AI/Nullkiller/Pathfinding/AIPathfinder.h

@@ -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();
 };

+ 7 - 0
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -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;
 	}