Browse Source

NKAI: object graph fixes

Andrii Danylchenko 1 year ago
parent
commit
adfcb650e2

+ 0 - 43
AI/Nullkiller/AIUtility.h

@@ -50,7 +50,6 @@
 
 #include <chrono>
 
-using namespace tbb;
 
 using dwellingContent = std::pair<ui32, std::vector<CreatureID>>;
 
@@ -246,48 +245,6 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock>
 // todo: move to obj manager
 bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObjectInstance * obj);
 
-template<typename TFunc>
-void pforeachTilePos(const int3 & mapSize, TFunc fn)
-{
-	for(int z = 0; z < mapSize.z; ++z)
-	{
-		parallel_for(blocked_range<size_t>(0, mapSize.x), [&](const blocked_range<size_t>& r)
-		{
-			int3 pos(0, 0, z);
-
-			for(pos.x = r.begin(); pos.x != r.end(); ++pos.x)
-			{
-				for(pos.y = 0; pos.y < mapSize.y; ++pos.y)
-				{
-					fn(pos);
-				}
-			}
-		});
-	}
-}
-
-template<typename TFunc>
-void pforeachTilePaths(const int3 & mapSize, const Nullkiller * ai, TFunc fn)
-{
-	for(int z = 0; z < mapSize.z; ++z)
-	{
-		parallel_for(blocked_range<size_t>(0, mapSize.x), [&](const blocked_range<size_t> & r)
-			{
-				int3 pos(0, 0, z);
-				std::vector<AIPath> paths;
-
-				for(pos.x = r.begin(); pos.x != r.end(); ++pos.x)
-				{
-					for(pos.y = 0; pos.y < mapSize.y; ++pos.y)
-					{
-						ai->pathfinder->calculatePathInfo(paths, pos);
-						fn(pos, paths);
-					}
-				}
-			});
-	}
-}
-
 class CDistanceSorter
 {
 	const CGHeroInstance * hero;

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

@@ -11,6 +11,7 @@
 #include "DangerHitMapAnalyzer.h"
 
 #include "../Engine/Nullkiller.h"
+#include "../pforeach.h"
 #include "../../../lib/CRandomGenerator.h"
 
 namespace NKAI

+ 2 - 2
AI/Nullkiller/Analyzers/ObjectClusterizer.cpp

@@ -235,9 +235,9 @@ void ObjectClusterizer::clusterize()
 		ai->memory->visitableObjs.end());
 
 #if NKAI_TRACE_LEVEL == 0
-	parallel_for(blocked_range<size_t>(0, objs.size()), [&](const blocked_range<size_t> & r) {
+	tbb::parallel_for(tbb::blocked_range<size_t>(0, objs.size()), [&](const tbb::blocked_range<size_t> & r) {
 #else
-	blocked_range<size_t> r(0, objs.size());
+	tbb::blocked_range<size_t> r(0, objs.size());
 #endif
 		auto priorityEvaluator = ai->priorityEvaluators->acquire();
 		auto heroes = ai->cb->getHeroesInfo();

+ 2 - 2
AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp

@@ -69,7 +69,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
 	logAi->trace("Checking ways to gaher army for hero %s, %s", hero->getObjectName(), pos.toString());
 #endif
 
-	auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
+	auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, ai->nullkiller->settings->isObjectGraphAllowed());
 
 #if NKAI_TRACE_LEVEL >= 1
 	logAi->trace("Gather army found %d paths", paths.size());
@@ -231,7 +231,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
 	logAi->trace("Checking ways to upgrade army in town %s, %s", upgrader->getObjectName(), pos.toString());
 #endif
 	
-	auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
+	auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, ai->nullkiller->settings->isObjectGraphAllowed());
 	auto goals = CaptureObjectsBehavior::getVisitGoals(paths);
 
 	std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;

+ 1 - 0
AI/Nullkiller/CMakeLists.txt

@@ -81,6 +81,7 @@ set(Nullkiller_HEADERS
 		Pathfinding/Rules/AIPreviousNodeRule.h
 		Pathfinding/ObjectGraph.h
 		AIUtility.h
+		pforeach.h
 		Analyzers/ArmyManager.h
 		Analyzers/HeroManager.h
 		Engine/Settings.h

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

@@ -412,7 +412,6 @@ struct DelayedWork
 class HeroChainCalculationTask
 {
 private:
-	AISharedStorage & nodes;
 	AINodeStorage & storage;
 	std::vector<AIPathNode *> existingChains;
 	std::vector<ExchangeCandidate> newChains;
@@ -424,8 +423,8 @@ private:
 
 public:
 	HeroChainCalculationTask(
-		AINodeStorage & storage, AISharedStorage & nodes, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn)
-		:existingChains(), newChains(), delayedWork(), nodes(nodes), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles)
+		AINodeStorage & storage, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn)
+		:existingChains(), newChains(), delayedWork(), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles)
 	{
 		existingChains.reserve(AIPathfinding::NUM_CHAINS);
 		newChains.reserve(AIPathfinding::NUM_CHAINS);
@@ -621,7 +620,6 @@ void HeroChainCalculationTask::cleanupInefectiveChains(std::vector<ExchangeCandi
 {
 	vstd::erase_if(result, [&](const ExchangeCandidate & chainInfo) -> bool
 	{
-		auto pos = chainInfo.coord;
 		auto isNotEffective = storage.hasBetterChain(chainInfo.carrierParent, chainInfo)
 			|| storage.hasBetterChain(chainInfo.carrierParent, chainInfo, result);
 

+ 36 - 6
AI/Nullkiller/Pathfinding/ObjectGraph.cpp

@@ -168,6 +168,37 @@ private:
 					}
 				});
 
+			auto obj = ai->cb->getTopObj(pos);
+
+			if(obj && obj->ID == Obj::BOAT)
+			{
+				ai->pathfinder->calculatePathInfo(pathCache, pos);
+
+				for(AIPath & path : pathCache)
+				{
+					auto from = path.targetHero->visitablePos();
+					auto fromObj = actorObjectMap[path.targetHero];
+					auto fromTile = cb->getTile(from);
+
+					auto danger = ai->pathfinder->getStorage()->evaluateDanger(pos, path.targetHero, true);
+					auto updated = target->tryAddConnection(
+						from,
+						pos,
+						path.movementCost(),
+						danger);
+
+					if(NKAI_GRAPH_TRACE_LEVEL >= 2 && updated)
+					{
+						logAi->trace(
+							"Connected %s[%s] -> %s[%s] through [%s], cost %2f",
+							fromObj ? fromObj->getObjectName() : "J", from.toString(),
+							"Boat", pos.toString(),
+							pos.toString(),
+							path.movementCost());
+					}
+				}
+			}
+
 			return;
 		}
 
@@ -199,7 +230,9 @@ private:
 					if(!cb->getTile(pos)->isWater())
 						continue;
 
-					if(obj1 && (obj1->ID != Obj::BOAT || obj1->ID != Obj::SHIPYARD))
+					auto startingObjIsBoatOrShipyard = obj1 && (obj1->ID == Obj::BOAT || obj1->ID == Obj::SHIPYARD);
+
+					if(!startingObjIsBoatOrShipyard)
 						continue;
 				}
 
@@ -287,7 +320,7 @@ private:
 		assert(objectActor->visitablePos() == visitablePos);
 
 		actorObjectMap[objectActor] = obj;
-		actors[objectActor] = obj->ID == Obj::TOWN || obj->ID == Obj::SHIPYARD ? HeroRole::MAIN : HeroRole::SCOUT;
+		actors[objectActor] = obj->ID == Obj::TOWN || obj->ID == Obj::SHIPYARD || obj->ID == Obj::BOAT ? HeroRole::MAIN : HeroRole::SCOUT;
 
 		target->addObject(obj);
 	}
@@ -717,9 +750,6 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
 
 			auto currentNode = currentTile->second[current.nodeType];
 
-			if(!currentNode.previous.valid())
-				break;
-
 			allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
 			vstd::amax(danger, currentNode.danger);
 			vstd::amax(cost, currentNode.cost);
@@ -777,7 +807,7 @@ void GraphPaths::quickAddChainInfoWithBlocker(std::vector<AIPath> & paths, int3
 			}
 			
 			if(!path.nodes.empty())
-				break;
+				continue;
 
 			for(auto graphTile = tilesToPass.rbegin(); graphTile != tilesToPass.rend(); graphTile++)
 			{