mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	AI: optimizae explore logically, reduce amount of scanned tiles during full map scan for new exploration point
This commit is contained in:
		| @@ -148,11 +148,6 @@ std::vector<AIPath> AIhelper::getPathsToTile(HeroPtr hero, int3 tile) | ||||
| 	return pathfindingManager->getPathsToTile(hero, tile); | ||||
| } | ||||
|  | ||||
| bool AIhelper::isTileAccessible(HeroPtr hero, int3 tile) | ||||
| { | ||||
| 	return pathfindingManager->isTileAccessible(hero, tile); | ||||
| } | ||||
|  | ||||
| void AIhelper::resetPaths() | ||||
| { | ||||
| 	pathfindingManager->resetPaths(); | ||||
|   | ||||
| @@ -60,9 +60,14 @@ public: | ||||
| 	Goals::TGoalVec howToVisitTile(int3 tile) override; | ||||
| 	Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override; | ||||
| 	std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override; | ||||
| 	bool isTileAccessible(HeroPtr hero, int3 tile) override; | ||||
| 	void resetPaths() override; | ||||
|  | ||||
| 	STRONG_INLINE | ||||
| 	bool isTileAccessible(const HeroPtr & hero, const int3 & tile) | ||||
| 	{ | ||||
| 		return pathfindingManager->isTileAccessible(hero, tile); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	bool notifyGoalCompleted(Goals::TSubgoal goal) override; | ||||
|  | ||||
|   | ||||
| @@ -26,6 +26,208 @@ extern FuzzyHelper * fh; | ||||
|  | ||||
| using namespace Goals; | ||||
|  | ||||
| namespace Goals | ||||
| { | ||||
| 	struct ExplorationHelper | ||||
| 	{ | ||||
| 		HeroPtr hero; | ||||
| 		int sightRadius; | ||||
| 		float bestValue; | ||||
| 		TSubgoal bestGoal; | ||||
| 		VCAI * aip; | ||||
| 		CCallback * cbp; | ||||
| 		const TeamState * ts; | ||||
| 		int3 ourPos; | ||||
| 		bool allowDeadEndCancellation; | ||||
| 		bool allowGatherArmy; | ||||
|  | ||||
| 		ExplorationHelper(HeroPtr h, bool gatherArmy) | ||||
| 		{ | ||||
| 			cbp = cb.get(); | ||||
| 			aip = ai.get(); | ||||
| 			hero = h; | ||||
| 			ts = cbp->getPlayerTeam(ai->playerID); | ||||
| 			sightRadius = hero->getSightRadius(); | ||||
| 			bestGoal = sptr(Goals::Invalid()); | ||||
| 			bestValue = 0; | ||||
| 			ourPos = h->convertPosition(h->pos, false); | ||||
| 			allowDeadEndCancellation = true; | ||||
| 			allowGatherArmy = gatherArmy; | ||||
| 		} | ||||
|  | ||||
| 		void scanSector(int scanRadius) | ||||
| 		{ | ||||
| 			for(int x = ourPos.x - scanRadius; x <= ourPos.x + scanRadius; x++) | ||||
| 			{ | ||||
| 				for(int y = ourPos.y - scanRadius; y <= ourPos.y + scanRadius; y++) | ||||
| 				{ | ||||
| 					int3 tile = int3(x, y, ourPos.z); | ||||
|  | ||||
| 					if(cbp->isInTheMap(tile) && ts->fogOfWarMap[tile.x][tile.y][tile.z]) | ||||
| 					{ | ||||
| 						scanTile(tile); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void scanMap() | ||||
| 		{ | ||||
| 			int3 mapSize = cbp->getMapSize(); | ||||
| 			int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y); | ||||
|  | ||||
| 			std::vector<int3> from; | ||||
| 			std::vector<int3> to; | ||||
|  | ||||
| 			from.reserve(perimeter); | ||||
| 			to.reserve(perimeter); | ||||
|  | ||||
| 			foreach_tile_pos([&](const int3 & pos) | ||||
| 			{ | ||||
| 				if(ts->fogOfWarMap[pos.x][pos.y][pos.z]) | ||||
| 				{ | ||||
| 					bool hasInvisibleNeighbor = false; | ||||
|  | ||||
| 					foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour) | ||||
| 					{ | ||||
| 						if(!ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) | ||||
| 						{ | ||||
| 							hasInvisibleNeighbor = true; | ||||
| 						} | ||||
| 					}); | ||||
|  | ||||
| 					if(hasInvisibleNeighbor) | ||||
| 						from.push_back(pos); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			logAi->debug("Exploration scan visible area perimeter for hero %s", hero.name); | ||||
|  | ||||
| 			for(const int3 & tile : from) | ||||
| 			{ | ||||
| 				scanTile(tile); | ||||
| 			} | ||||
|  | ||||
| 			if(!bestGoal->invalid()) | ||||
| 			{ | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			allowDeadEndCancellation = false; | ||||
|  | ||||
| 			for(int i = 0; i < sightRadius; i++) | ||||
| 			{ | ||||
| 				getVisibleNeighbours(from, to); | ||||
| 				vstd::concatenate(from, to); | ||||
| 				vstd::removeDuplicates(from); | ||||
| 			} | ||||
|  | ||||
| 			logAi->debug("Exploration scan all possible tiles for hero %s", hero.name); | ||||
|  | ||||
| 			for(const int3 & tile : from) | ||||
| 			{ | ||||
| 				scanTile(tile); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void scanTile(const int3 & tile) | ||||
| 		{ | ||||
| 			if(tile == ourPos | ||||
| 				|| !aip->ah->isTileAccessible(hero, tile)) //shouldn't happen, but it does | ||||
| 				return; | ||||
|  | ||||
| 			int tilesDiscovered = howManyTilesWillBeDiscovered(tile); | ||||
| 			if(!tilesDiscovered) | ||||
| 				return; | ||||
|  | ||||
| 			auto waysToVisit = aip->ah->howToVisitTile(hero, tile, allowGatherArmy); | ||||
| 			for(auto goal : waysToVisit) | ||||
| 			{ | ||||
| 				if(goal->evaluationContext.movementCost <= 0.0) // should not happen | ||||
| 					continue; | ||||
|  | ||||
| 				float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost; | ||||
|  | ||||
| 				if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much | ||||
| 				{ | ||||
| 					auto obj = cb->getTopObj(tile); | ||||
|  | ||||
| 					// picking up resources does not yield any exploration at all. | ||||
| 					// if it blocks the way to some explorable tile AIPathfinder will take care of it | ||||
| 					if(obj && obj->blockVisit) | ||||
| 					{ | ||||
| 						continue; | ||||
| 					} | ||||
|  | ||||
| 					if(isSafeToVisit(hero, tile)) | ||||
| 					{ | ||||
| 						bestGoal = goal; | ||||
| 						bestValue = ourValue; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out) const | ||||
| 		{ | ||||
| 			for(const int3 & tile : tiles) | ||||
| 			{ | ||||
| 				foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour) | ||||
| 				{ | ||||
| 					if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) | ||||
| 					{ | ||||
| 						out.push_back(neighbour); | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		int howManyTilesWillBeDiscovered( | ||||
| 			const int3 & pos) const | ||||
| 		{ | ||||
| 			int ret = 0; | ||||
| 			for(int x = pos.x - sightRadius; x <= pos.x + sightRadius; x++) | ||||
| 			{ | ||||
| 				for(int y = pos.y - sightRadius; y <= pos.y + sightRadius; y++) | ||||
| 				{ | ||||
| 					int3 npos = int3(x, y, pos.z); | ||||
| 					if(cbp->isInTheMap(npos) | ||||
| 						&& pos.dist2d(npos) - 0.5 < sightRadius | ||||
| 						&& !ts->fogOfWarMap[npos.x][npos.y][npos.z]) | ||||
| 					{ | ||||
| 						if(allowDeadEndCancellation | ||||
| 							&& !hasReachableNeighbor(npos)) | ||||
| 						{ | ||||
| 							continue; | ||||
| 						} | ||||
|  | ||||
| 						ret++; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return ret; | ||||
| 		} | ||||
|  | ||||
| 		bool hasReachableNeighbor(const int3 &pos) const | ||||
| 		{ | ||||
| 			for(crint3 dir : int3::getDirs()) | ||||
| 			{ | ||||
| 				int3 tile = pos + dir; | ||||
| 				if(cbp->isInTheMap(tile)) | ||||
| 				{ | ||||
| 					auto isAccessible = aip->ah->isTileAccessible(hero, tile); | ||||
|  | ||||
| 					if(isAccessible) | ||||
| 						return true; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return false; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| bool Explore::operator==(const Explore & other) const | ||||
| { | ||||
| 	return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy; | ||||
| @@ -38,18 +240,7 @@ std::string Explore::completeMessage() const | ||||
|  | ||||
| TSubgoal Explore::whatToDoToAchieve() | ||||
| { | ||||
| 	auto ret = fh->chooseSolution(getAllPossibleSubgoals()); | ||||
| 	if(hero) //use best step for this hero | ||||
| 	{ | ||||
| 		return ret; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if(ret->hero.get(true)) | ||||
| 			return sptr(Explore().sethero(ret->hero.h)); //choose this hero and then continue with him | ||||
| 		else | ||||
| 			return ret; //other solutions, like buying hero from tavern | ||||
| 	} | ||||
| 	return fh->chooseSolution(getAllPossibleSubgoals()); | ||||
| } | ||||
|  | ||||
| TGoalVec Explore::getAllPossibleSubgoals() | ||||
| @@ -143,6 +334,8 @@ TGoalVec Explore::getAllPossibleSubgoals() | ||||
| 	{ | ||||
| 		for(auto h : heroes) | ||||
| 		{ | ||||
| 			logAi->trace("Exploration searching for a new point for hero %s", h->name); | ||||
|  | ||||
| 			TSubgoal goal = explorationNewPoint(h); | ||||
|  | ||||
| 			if(goal->invalid()) | ||||
| @@ -180,197 +373,43 @@ bool Explore::fulfillsMe(TSubgoal goal) | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool Explore::hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const | ||||
| TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const | ||||
| { | ||||
| 	for(crint3 dir : int3::getDirs()) | ||||
| 	{ | ||||
| 		int3 tile = pos + dir; | ||||
| 		if(cbp->isInTheMap(tile)) | ||||
| 		{ | ||||
| 			auto isAccessible = vcai->ah->isTileAccessible(hero, tile); | ||||
|  | ||||
| 			if(isAccessible) | ||||
| 				return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| int Explore::howManyTilesWillBeDiscovered( | ||||
| 	const int3 & pos, | ||||
| 	int radious, | ||||
| 	CCallback * cbp, | ||||
| 	const TeamState * ts, | ||||
| 	VCAI * aip, | ||||
| 	HeroPtr h) const | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	for(int x = pos.x - radious; x <= pos.x + radious; x++) | ||||
| 	{ | ||||
| 		for(int y = pos.y - radious; y <= pos.y + radious; y++) | ||||
| 		{ | ||||
| 			int3 npos = int3(x, y, pos.z); | ||||
| 			if(cbp->isInTheMap(npos) | ||||
| 				&& pos.dist2d(npos) - 0.5 < radious | ||||
| 				&& !ts->fogOfWarMap[npos.x][npos.y][npos.z] | ||||
| 				&& hasReachableNeighbor(npos, h, cbp, aip)) | ||||
| 			{ | ||||
| 				ret++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| TSubgoal Explore::explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) const | ||||
| { | ||||
| 	std::map<int3, int> dstToRevealedTiles; | ||||
| 	VCAI * aip = ai.get(); | ||||
| 	CCallback * cbp = cb.get(); | ||||
| 	const TeamState * ts = cbp->getPlayerTeam(ai->playerID); | ||||
| 	ExplorationHelper scanResult(h, allowGatherArmy); | ||||
|  | ||||
| 	for(crint3 dir : int3::getDirs()) | ||||
| 	{ | ||||
| 		int3 tile = hpos + dir; | ||||
| 		if(cb->isInTheMap(tile)) | ||||
| 		{ | ||||
| 			if(isBlockVisitObj(tile)) | ||||
| 				continue; | ||||
|  | ||||
| 			if(isSafeToVisit(h, tile) && ai->isAccessibleForHero(tile, h)) | ||||
| 			{ | ||||
| 				auto distance = hpos.dist2d(tile); // diagonal movement opens more tiles but spends more mp | ||||
| 				int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, ts, aip, h); | ||||
|  | ||||
| 				if(tilesDiscovered > 0) | ||||
| 					dstToRevealedTiles[tile] = tilesDiscovered / distance; | ||||
| 			} | ||||
| 			scanResult.scanTile(tile); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(dstToRevealedTiles.empty()) //yes, it DID happen! | ||||
| 		return sptr(Invalid()); | ||||
|  | ||||
| 	auto paths = cb->getPathsInfo(h.get()); | ||||
|  | ||||
| 	auto best = dstToRevealedTiles.begin(); | ||||
| 	for(auto i = dstToRevealedTiles.begin(); i != dstToRevealedTiles.end(); i++) | ||||
| 	{ | ||||
| 		const CGPathNode * pn = paths->getPathInfo(i->first); | ||||
| 		if(best->second < i->second && pn->reachable() && pn->accessible == CGPathNode::ACCESSIBLE) | ||||
| 			best = i; | ||||
| 	} | ||||
|  | ||||
| 	if(best->second) | ||||
| 		return sptr(VisitTile(best->first).sethero(h)); | ||||
|  | ||||
| 	return sptr(Invalid()); | ||||
| 	return scanResult.bestGoal; | ||||
| } | ||||
|  | ||||
|  | ||||
| TSubgoal Explore::explorationNewPoint(HeroPtr h) const | ||||
| { | ||||
| 	int radius = h->getSightRadius(); | ||||
| 	CCallback * cbp = cb.get(); | ||||
| 	VCAI *aip = ai.get(); | ||||
| 	const TeamState * ts = cbp->getPlayerTeam(aip->playerID); | ||||
| 	ExplorationHelper scanResult(h, allowGatherArmy); | ||||
|  | ||||
| 	int3 mapSize = cbp->getMapSize(); | ||||
| 	int perimiter = 2 * radius * (mapSize.x + mapSize.y); | ||||
| 	scanResult.scanSector(10); | ||||
|  | ||||
| 	std::vector<int3> from; | ||||
| 	std::vector<int3> to; | ||||
|  | ||||
| 	from.reserve(perimiter); | ||||
| 	to.reserve(perimiter); | ||||
|  | ||||
| 	foreach_tile_pos([&](const int3 & pos) | ||||
| 	if(!scanResult.bestGoal->invalid()) | ||||
| 	{ | ||||
| 		if(ts->fogOfWarMap[pos.x][pos.y][pos.z]) | ||||
| 		{ | ||||
| 			bool hasInvisibleNeighbor = false; | ||||
|  | ||||
| 			foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour) | ||||
| 			{ | ||||
| 				if(!ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) | ||||
| 				{ | ||||
| 					hasInvisibleNeighbor = true; | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 			if(hasInvisibleNeighbor) | ||||
| 				from.push_back(pos); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	for(int i = 0; i < radius; i++) | ||||
| 	{ | ||||
| 		getVisibleNeighbours(from, to, cbp, ts); | ||||
| 		vstd::concatenate(from, to); | ||||
| 		vstd::removeDuplicates(from); | ||||
| 		return scanResult.bestGoal; | ||||
| 	} | ||||
|  | ||||
| 	return explorationScanRange(h, from); | ||||
| 	scanResult.scanMap(); | ||||
|  | ||||
| 	return scanResult.bestGoal; | ||||
| } | ||||
|  | ||||
| TSubgoal Explore::explorationScanRange(HeroPtr h, std::vector<int3> & range) const | ||||
| { | ||||
| 	int radius = h->getSightRadius(); | ||||
| 	CCallback * cbp = cb.get(); | ||||
| 	VCAI *aip = ai.get(); | ||||
| 	const TeamState * ts = cbp->getPlayerTeam(aip->playerID); | ||||
|  | ||||
| 	float bestValue = 0; //discovered tile to node distance ratio | ||||
| 	TSubgoal bestWay = sptr(Invalid()); | ||||
| 	int3 ourPos = h->convertPosition(h->pos, false); | ||||
|  | ||||
| 	for(const int3 & tile : range) | ||||
| 	{ | ||||
| 		if(tile == ourPos) //shouldn't happen, but it does | ||||
| 			continue; | ||||
|  | ||||
| 		int tilesDiscovered = howManyTilesWillBeDiscovered(tile, radius, cbp, ts, aip, h); | ||||
| 		if(!tilesDiscovered) | ||||
| 			continue; | ||||
|  | ||||
| 		auto waysToVisit = aip->ah->howToVisitTile(h, tile, allowGatherArmy); | ||||
| 		for(auto goal : waysToVisit) | ||||
| 		{ | ||||
| 			if(goal->evaluationContext.movementCost <= 0.0) // should not happen | ||||
| 				continue; | ||||
|  | ||||
| 			float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost; | ||||
|  | ||||
| 			if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much | ||||
| 			{ | ||||
| 				auto obj = cb->getTopObj(tile); | ||||
| 				if(obj && obj->blockVisit && !isObjectRemovable(obj)) //we can't stand on that object | ||||
| 				{ | ||||
| 					continue; | ||||
| 				} | ||||
|  | ||||
| 				if(isSafeToVisit(h, tile)) | ||||
| 				{ | ||||
| 					bestWay = goal; | ||||
| 					bestValue = ourValue; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(!bestWay->invalid()) | ||||
| 	{ | ||||
| 		return bestWay; | ||||
| 	} | ||||
|  | ||||
| 	return bestWay; | ||||
| } | ||||
|  | ||||
| TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const | ||||
| { | ||||
| 	TimeCheck tc("where to explore"); | ||||
| 	int radius = h->getSightRadius(); | ||||
| 	int3 hpos = h->visitablePos(); | ||||
|  | ||||
| 	//look for nearby objs -> visit them if they're close enough | ||||
| @@ -406,19 +445,5 @@ TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const | ||||
| 	} | ||||
|  | ||||
| 	//check if nearby tiles allow us to reveal anything - this is quick | ||||
| 	return explorationBestNeighbour(hpos, radius, h); | ||||
| } | ||||
|  | ||||
| void Explore::getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out, CCallback * cbp, const TeamState * ts) const | ||||
| { | ||||
| 	for(const int3 & tile : tiles) | ||||
| 	{ | ||||
| 		foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour) | ||||
| 		{ | ||||
| 			if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z]) | ||||
| 			{ | ||||
| 				out.push_back(neighbour); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	return explorationBestNeighbour(hpos, h); | ||||
| } | ||||
|   | ||||
| @@ -17,6 +17,8 @@ class FuzzyHelper; | ||||
|  | ||||
| namespace Goals | ||||
| { | ||||
| 	struct ExplorationHelper; | ||||
|  | ||||
| 	class DLL_EXPORT Explore : public CGoal<Explore> | ||||
| 	{ | ||||
| 	private: | ||||
| @@ -49,8 +51,8 @@ namespace Goals | ||||
| 	private: | ||||
| 		TSubgoal exploreNearestNeighbour(HeroPtr h) const; | ||||
| 		TSubgoal explorationNewPoint(HeroPtr h) const; | ||||
| 		TSubgoal explorationBestNeighbour(int3 hpos, int radius, HeroPtr h) const; | ||||
| 		TSubgoal explorationScanRange(HeroPtr h, std::vector<int3> & range) const; | ||||
| 		TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const; | ||||
| 		void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const; | ||||
| 		bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const; | ||||
|  | ||||
| 		void getVisibleNeighbours( | ||||
| @@ -59,12 +61,6 @@ namespace Goals | ||||
| 			CCallback * cbp, | ||||
| 			const TeamState * ts) const; | ||||
|  | ||||
| 		int howManyTilesWillBeDiscovered( | ||||
| 			const int3 & pos, | ||||
| 			int radious, | ||||
| 			CCallback * cbp, | ||||
| 			const TeamState * ts, | ||||
| 			VCAI * aip, | ||||
| 			HeroPtr h) const; | ||||
| 		int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const; | ||||
| 	}; | ||||
| } | ||||
|   | ||||
| @@ -220,18 +220,18 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations( | ||||
|  | ||||
| 	if(source.isNodeObjectVisitable()) | ||||
| 	{ | ||||
| 	auto accessibleExits = pathfinderHelper->getTeleportExits(source); | ||||
| 	auto srcNode = getAINode(source.node); | ||||
| 		auto accessibleExits = pathfinderHelper->getTeleportExits(source); | ||||
| 		auto srcNode = getAINode(source.node); | ||||
|  | ||||
| 	for(auto & neighbour : accessibleExits) | ||||
| 	{ | ||||
| 		auto node = getOrCreateNode(neighbour, source.node->layer, srcNode->chainMask); | ||||
| 		for(auto & neighbour : accessibleExits) | ||||
| 		{ | ||||
| 			auto node = getOrCreateNode(neighbour, source.node->layer, srcNode->chainMask); | ||||
|  | ||||
| 		if(!node) | ||||
| 			continue; | ||||
| 			if(!node) | ||||
| 				continue; | ||||
|  | ||||
| 		neighbours.push_back(node.get()); | ||||
| 	} | ||||
| 			neighbours.push_back(node.get()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(hero->getPosition(false) == source.coord) | ||||
| @@ -342,19 +342,11 @@ bool AINodeStorage::hasBetterChain(const PathNodeInfo & source, CDestinationNode | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool AINodeStorage::isTileAccessible(int3 pos, const EPathfindingLayer layer) const | ||||
| bool AINodeStorage::isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const | ||||
| { | ||||
| 	auto chains = nodes[pos.x][pos.y][pos.z][layer]; | ||||
| 	const AIPathNode & node = nodes[pos.x][pos.y][pos.z][layer][0]; | ||||
|  | ||||
| 	for(const AIPathNode & node : chains) | ||||
| 	{ | ||||
| 		if(node.action != CGPathNode::ENodeAction::UNKNOWN) | ||||
| 		{ | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| 	return node.action != CGPathNode::ENodeAction::UNKNOWN; | ||||
| } | ||||
|  | ||||
| std::vector<AIPath> AINodeStorage::getChainInfo(int3 pos, bool isOnLand) const | ||||
|   | ||||
| @@ -114,7 +114,7 @@ public: | ||||
| 	bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const; | ||||
| 	boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber); | ||||
| 	std::vector<AIPath> getChainInfo(int3 pos, bool isOnLand) const; | ||||
| 	bool isTileAccessible(int3 pos, const EPathfindingLayer layer) const; | ||||
| 	bool isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const; | ||||
|  | ||||
| 	void setHero(HeroPtr heroPtr); | ||||
|  | ||||
|   | ||||
| @@ -35,7 +35,7 @@ void AIPathfinder::init() | ||||
| 	storageMap.clear(); | ||||
| } | ||||
|  | ||||
| bool AIPathfinder::isTileAccessible(HeroPtr hero, int3 tile) | ||||
| bool AIPathfinder::isTileAccessible(const HeroPtr & hero, const int3 & tile) | ||||
| { | ||||
| 	boost::unique_lock<boost::mutex> storageLock(storageMutex); | ||||
|  | ||||
| @@ -61,7 +61,7 @@ std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile) | ||||
| 	return nodeStorage->getChainInfo(tile, !tileInfo->isWater()); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<AINodeStorage> AIPathfinder::getOrCreateStorage(HeroPtr hero) | ||||
| std::shared_ptr<AINodeStorage> AIPathfinder::getOrCreateStorage(const HeroPtr & hero) | ||||
| { | ||||
| 	std::shared_ptr<AINodeStorage> nodeStorage; | ||||
|  | ||||
|   | ||||
| @@ -23,11 +23,11 @@ private: | ||||
| 	CPlayerSpecificInfoCallback * cb; | ||||
| 	VCAI * ai; | ||||
|  | ||||
| 	std::shared_ptr<AINodeStorage> getOrCreateStorage(HeroPtr hero); | ||||
| 	std::shared_ptr<AINodeStorage> getOrCreateStorage(const HeroPtr & hero); | ||||
| public: | ||||
| 	AIPathfinder(CPlayerSpecificInfoCallback * cb, VCAI * ai); | ||||
| 	std::vector<AIPath> getPathInfo(HeroPtr hero, int3 tile); | ||||
| 	bool isTileAccessible(HeroPtr hero, int3 tile); | ||||
| 	bool isTileAccessible(const HeroPtr & hero, const int3 & tile); | ||||
| 	void clear(); | ||||
| 	void init(); | ||||
| }; | ||||
|   | ||||
| @@ -107,11 +107,6 @@ std::vector<AIPath> PathfindingManager::getPathsToTile(HeroPtr hero, int3 tile) | ||||
| 	return pathfinder->getPathInfo(hero, tile); | ||||
| } | ||||
|  | ||||
| bool PathfindingManager::isTileAccessible(HeroPtr hero, int3 tile) | ||||
| { | ||||
| 	return pathfinder->isTileAccessible(hero, tile); | ||||
| } | ||||
|  | ||||
| Goals::TGoalVec PathfindingManager::findPath( | ||||
| 	HeroPtr hero, | ||||
| 	crint3 dest, | ||||
|   | ||||
| @@ -26,7 +26,6 @@ public: | ||||
| 	virtual Goals::TGoalVec howToVisitTile(int3 tile) = 0; | ||||
| 	virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj) = 0; | ||||
| 	virtual std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) = 0; | ||||
| 	virtual bool isTileAccessible(HeroPtr hero, int3 tile) = 0; | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT PathfindingManager : public IPathfindingManager | ||||
| @@ -47,9 +46,14 @@ public: | ||||
| 	Goals::TGoalVec howToVisitTile(int3 tile) override; | ||||
| 	Goals::TGoalVec howToVisitObj(ObjectIdRef obj) override; | ||||
| 	std::vector<AIPath> getPathsToTile(HeroPtr hero, int3 tile) override; | ||||
| 	bool isTileAccessible(HeroPtr hero, int3 tile) override; | ||||
| 	void resetPaths() override; | ||||
|  | ||||
| 	STRONG_INLINE | ||||
| 	bool isTileAccessible(const HeroPtr & hero, const int3 & tile) | ||||
| 	{ | ||||
| 		return pathfinder->isTileAccessible(hero, tile); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	void init(CPlayerSpecificInfoCallback * CB) override; | ||||
| 	void setAI(VCAI * AI) override; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user