Explorar o código

Merge pull request #516 from nullkiller/freeze-pathfinding

Freeze when try to bypass a few adjacent guards
Alexander Shishkin %!s(int64=7) %!d(string=hai) anos
pai
achega
ff75e5e6e8

+ 1 - 1
AI/VCAI/Pathfinding/AIPathfinder.cpp

@@ -49,7 +49,7 @@ std::vector<AIPath> AIPathfinder::getPathInfo(HeroPtr hero, int3 tile)
 
 
 		storageMap[hero] = nodeStorage;
 		storageMap[hero] = nodeStorage;
 		
 		
-		auto config = std::make_shared<AIPathfinderConfig>(cb, ai, nodeStorage);
+		auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, nodeStorage);
 
 
 		nodeStorage->setHero(hero.get());
 		nodeStorage->setHero(hero.get());
 		cb->calculatePaths(config, hero.get());
 		cb->calculatePaths(config, hero.get());

+ 272 - 288
AI/VCAI/Pathfinding/AIPathfinderConfig.cpp

@@ -13,395 +13,379 @@
 #include "../../../lib/mapping/CMap.h"
 #include "../../../lib/mapping/CMap.h"
 #include "../../../lib/mapObjects/MapObjects.h"
 #include "../../../lib/mapObjects/MapObjects.h"
 
 
-class BuildBoatAction : public ISpecialAction
+namespace AIPathfinding
 {
 {
-private:
-	const IShipyard * shipyard;
-
-public:
-	BuildBoatAction(const IShipyard * shipyard)
-		:shipyard(shipyard)
+	class BuildBoatAction : public ISpecialAction
 	{
 	{
-	}
+	private:
+		const IShipyard * shipyard;
 
 
-	virtual Goals::TSubgoal whatToDo(HeroPtr hero) const override
-	{
-		return sptr(Goals::BuildBoat(shipyard));
-	}
-};
+	public:
+		BuildBoatAction(const IShipyard * shipyard)
+			:shipyard(shipyard)
+		{
+		}
 
 
-class AILayerTransitionRule : public LayerTransitionRule
-{
-private:
-	CPlayerSpecificInfoCallback * cb;
-	VCAI * ai;
-	std::map<int3, std::shared_ptr<const BuildBoatAction>> virtualBoats;
-	std::shared_ptr<AINodeStorage> nodeStorage;
-
-public:
-	AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage)
-		:cb(cb), ai(ai), nodeStorage(nodeStorage)
-	{
-		setup();
-	}
+		virtual Goals::TSubgoal whatToDo(HeroPtr hero) const override
+		{
+			return sptr(Goals::BuildBoat(shipyard));
+		}
+	};
 
 
-	virtual void process(
-		const PathNodeInfo & source,
-		CDestinationNodeInfo & destination,
-		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const override
+	class BattleAction : public ISpecialAction
 	{
 	{
-		LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
+	private:
+		const int3  target;
+		const HeroPtr  hero;
 
 
-		if(!destination.blocked)
+	public:
+		BattleAction(const int3 target)
+			:target(target)
 		{
 		{
-			return;
 		}
 		}
 
 
-		if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::SAIL
-			&& vstd::contains(virtualBoats, destination.coord))
+		virtual Goals::TSubgoal whatToDo(HeroPtr hero) const override
 		{
 		{
-			logAi->trace("Bypassing virtual boat at %s!", destination.coord.toString());
-			
-			nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
-			{
-				std::shared_ptr<const BuildBoatAction> virtualBoat = virtualBoats.at(destination.coord);
-
-				auto boatNodeOptional = nodeStorage->getOrCreateNode(
-					node->coord,
-					node->layer,
-					node->chainMask | AINodeStorage::RESOURCE_CHAIN);
-
-				if(boatNodeOptional)
-				{
-					AIPathNode * boatNode = boatNodeOptional.get();
-
-					boatNode->specialAction = virtualBoat;
-					destination.blocked = false;
-					destination.action = CGPathNode::ENodeAction::EMBARK;
-					destination.node = boatNode;
-				}
-				else
-				{
-					logAi->trace(
-						"Can not allocate boat node while moving %s -> %s",
-						source.coord.toString(),
-						destination.coord.toString());
-				}
-			});
+			return sptr(Goals::VisitTile(target).sethero(hero));
 		}
 		}
-	}
+	};
 
 
-private:
-	void setup()
+	class AILayerTransitionRule : public LayerTransitionRule
 	{
 	{
-		std::vector<const IShipyard *> shipyards;
-
-		for(const CGTownInstance * t : cb->getTownsInfo())
+	private:
+		CPlayerSpecificInfoCallback * cb;
+		VCAI * ai;
+		std::map<int3, std::shared_ptr<const BuildBoatAction>> virtualBoats;
+		std::shared_ptr<AINodeStorage> nodeStorage;
+
+	public:
+		AILayerTransitionRule(CPlayerSpecificInfoCallback * cb, VCAI * ai, std::shared_ptr<AINodeStorage> nodeStorage)
+			:cb(cb), ai(ai), nodeStorage(nodeStorage)
 		{
 		{
-			if(t->hasBuilt(BuildingID::SHIPYARD))
-				shipyards.push_back(t);
+			setup();
 		}
 		}
 
 
-		for(const CGObjectInstance * obj : ai->visitableObjs)
+		virtual void process(
+			const PathNodeInfo & source,
+			CDestinationNodeInfo & destination,
+			const PathfinderConfig * pathfinderConfig,
+			CPathfinderHelper * pathfinderHelper) const override
 		{
 		{
-			if(obj->ID != Obj::TOWN) //towns were handled in the previous loop
+			LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
+
+			if(!destination.blocked)
 			{
 			{
-				if(const IShipyard * shipyard = IShipyard::castFrom(obj))
-					shipyards.push_back(shipyard);
+				return;
 			}
 			}
-		}
 
 
-		for(const IShipyard * shipyard : shipyards)
-		{
-			if(shipyard->shipyardStatus() == IShipyard::GOOD)
+			if(source.node->layer == EPathfindingLayer::LAND && destination.node->layer == EPathfindingLayer::SAIL
+				&& vstd::contains(virtualBoats, destination.coord))
 			{
 			{
-				int3 boatLocation = shipyard->bestLocation();
-				virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(shipyard);
-				logAi->debug("Virtual boat added at %s", boatLocation.toString());
+				logAi->trace("Bypassing virtual boat at %s!", destination.coord.toString());
+
+				nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
+				{
+					std::shared_ptr<const BuildBoatAction> virtualBoat = virtualBoats.at(destination.coord);
+
+					auto boatNodeOptional = nodeStorage->getOrCreateNode(
+						node->coord,
+						node->layer,
+						node->chainMask | AINodeStorage::RESOURCE_CHAIN);
+
+					if(boatNodeOptional)
+					{
+						AIPathNode * boatNode = boatNodeOptional.get();
+
+						boatNode->specialAction = virtualBoat;
+						destination.blocked = false;
+						destination.action = CGPathNode::ENodeAction::EMBARK;
+						destination.node = boatNode;
+					}
+					else
+					{
+						logAi->trace(
+							"Can not allocate boat node while moving %s -> %s",
+							source.coord.toString(),
+							destination.coord.toString());
+					}
+				});
 			}
 			}
 		}
 		}
-	}
-};
-
-class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
-{
-private:
-	CPlayerSpecificInfoCallback * cb;
-	std::shared_ptr<AINodeStorage> nodeStorage;
 
 
-public:
-	AIMovementAfterDestinationRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
-		:cb(cb), nodeStorage(nodeStorage)
-	{
-	}
-
-	virtual void process(
-		const PathNodeInfo & source,
-		CDestinationNodeInfo & destination,
-		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const override
-	{
-		if(nodeStorage->hasBetterChain(source, destination))
+	private:
+		void setup()
 		{
 		{
-			destination.blocked = true;
+			std::vector<const IShipyard *> shipyards;
 
 
-			return;
-		}
-
-		auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
-
-		if(blocker == BlockingReason::NONE)
-			return;
+			for(const CGTownInstance * t : cb->getTownsInfo())
+			{
+				if(t->hasBuilt(BuildingID::SHIPYARD))
+					shipyards.push_back(t);
+			}
 
 
-		if(blocker == BlockingReason::DESTINATION_BLOCKVIS && destination.nodeObject)
-		{
-			auto objID = destination.nodeObject->ID;
-			if((objID == Obj::HERO && destination.objectRelations != PlayerRelations::ENEMIES)
-				|| objID == Obj::SUBTERRANEAN_GATE || objID == Obj::MONOLITH_TWO_WAY
-				|| objID == Obj::MONOLITH_ONE_WAY_ENTRANCE || objID == Obj::MONOLITH_ONE_WAY_EXIT
-				|| objID == Obj::WHIRLPOOL)
+			for(const CGObjectInstance * obj : ai->visitableObjs)
 			{
 			{
-				destination.blocked = true;
+				if(obj->ID != Obj::TOWN) //towns were handled in the previous loop
+				{
+					if(const IShipyard * shipyard = IShipyard::castFrom(obj))
+						shipyards.push_back(shipyard);
+				}
 			}
 			}
 
 
-			return;
+			for(const IShipyard * shipyard : shipyards)
+			{
+				if(shipyard->shipyardStatus() == IShipyard::GOOD)
+				{
+					int3 boatLocation = shipyard->bestLocation();
+					virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(shipyard);
+					logAi->debug("Virtual boat added at %s", boatLocation.toString());
+				}
+			}
 		}
 		}
+	};
+
+	class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
+	{
+	private:
+		CPlayerSpecificInfoCallback * cb;
+		std::shared_ptr<AINodeStorage> nodeStorage;
 
 
-		if(blocker == BlockingReason::DESTINATION_VISIT)
+	public:
+		AIMovementAfterDestinationRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
+			:cb(cb), nodeStorage(nodeStorage)
 		{
 		{
-			return;
 		}
 		}
 
 
-		if(blocker == BlockingReason::DESTINATION_GUARDED)
+		virtual void process(
+			const PathNodeInfo & source,
+			CDestinationNodeInfo & destination,
+			const PathfinderConfig * pathfinderConfig,
+			CPathfinderHelper * pathfinderHelper) const override
 		{
 		{
-			auto srcGuardians = cb->getGuardingCreatures(source.coord);
-			auto destGuardians = cb->getGuardingCreatures(destination.coord);
-
-			if(destGuardians.empty())
+			if(nodeStorage->hasBetterChain(source, destination))
 			{
 			{
 				destination.blocked = true;
 				destination.blocked = true;
 
 
 				return;
 				return;
 			}
 			}
 
 
-			vstd::erase_if(destGuardians, [&](const CGObjectInstance * destGuard) -> bool
-			{
-				return vstd::contains(srcGuardians, destGuard);
-			});
+			auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
 
 
-			auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
-			if(guardsAlreadyBypassed && nodeStorage->isBattleNode(source.node))
+			if(blocker == BlockingReason::NONE)
+				return;
+
+			if(blocker == BlockingReason::DESTINATION_BLOCKVIS && destination.nodeObject)
 			{
 			{
-				logAi->trace(
-					"Bypass guard at destination while moving %s -> %s",
-					source.coord.toString(),
-					destination.coord.toString());
+				auto objID = destination.nodeObject->ID;
+				if((objID == Obj::HERO && destination.objectRelations != PlayerRelations::ENEMIES)
+					|| objID == Obj::SUBTERRANEAN_GATE || objID == Obj::MONOLITH_TWO_WAY
+					|| objID == Obj::MONOLITH_ONE_WAY_ENTRANCE || objID == Obj::MONOLITH_ONE_WAY_EXIT
+					|| objID == Obj::WHIRLPOOL)
+				{
+					destination.blocked = true;
+				}
 
 
 				return;
 				return;
 			}
 			}
 
 
-			const AIPathNode * destNode = nodeStorage->getAINode(destination.node);
-			auto battleNodeOptional = nodeStorage->getOrCreateNode(
-				destination.coord, 
-				destination.node->layer, 
-				destNode->chainMask | AINodeStorage::BATTLE_CHAIN);
-
-			if(!battleNodeOptional)
+			if(blocker == BlockingReason::DESTINATION_VISIT)
 			{
 			{
-				logAi->trace(
-					"Can not allocate battle node while moving %s -> %s",
-					source.coord.toString(),
-					destination.coord.toString());
-
-				destination.blocked = true;
-
 				return;
 				return;
 			}
 			}
 
 
-			AIPathNode *  battleNode = battleNodeOptional.get();
-
-			if(battleNode->locked)
+			if(blocker == BlockingReason::DESTINATION_GUARDED)
 			{
 			{
-				logAi->trace(
-					"Block bypass guard at destination while moving %s -> %s",
-					source.coord.toString(),
-					destination.coord.toString());
+				auto srcGuardians = cb->getGuardingCreatures(source.coord);
+				auto destGuardians = cb->getGuardingCreatures(destination.coord);
 
 
-				destination.blocked = true;
+				if(destGuardians.empty())
+				{
+					destination.blocked = true;
 
 
-				return;
-			}
+					return;
+				}
 
 
-			auto hero = nodeStorage->getHero();
-			auto danger = evaluateDanger(destination.coord, hero);
+				vstd::erase_if(destGuardians, [&](const CGObjectInstance * destGuard) -> bool
+				{
+					return vstd::contains(srcGuardians, destGuard);
+				});
 
 
-			destination.node = battleNode;
-			nodeStorage->commit(destination, source);
+				auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
+				if(guardsAlreadyBypassed && nodeStorage->isBattleNode(source.node))
+				{
+					logAi->trace(
+						"Bypass guard at destination while moving %s -> %s",
+						source.coord.toString(),
+						destination.coord.toString());
 
 
-			if(battleNode->danger < danger)
-			{
-				battleNode->danger = danger;
-			}
+					return;
+				}
 
 
-			logAi->trace(
-				"Begin bypass guard at destination with danger %s while moving %s -> %s",
-				std::to_string(danger),
-				source.coord.toString(),
-				destination.coord.toString());
+				const AIPathNode * destNode = nodeStorage->getAINode(destination.node);
+				auto battleNodeOptional = nodeStorage->getOrCreateNode(
+					destination.coord,
+					destination.node->layer,
+					destNode->chainMask | AINodeStorage::BATTLE_CHAIN);
 
 
-			return;
-		}
+				if(!battleNodeOptional)
+				{
+					logAi->trace(
+						"Can not allocate battle node while moving %s -> %s",
+						source.coord.toString(),
+						destination.coord.toString());
 
 
-		destination.blocked = true;
-	}
-};
+					destination.blocked = true;
 
 
-class AIMovementToDestinationRule : public MovementToDestinationRule
-{
-private:
-	CPlayerSpecificInfoCallback * cb;
-	std::shared_ptr<AINodeStorage> nodeStorage;
+					return;
+				}
 
 
-public:
-	AIMovementToDestinationRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
-		:cb(cb), nodeStorage(nodeStorage)
-	{
-	}
+				AIPathNode *  battleNode = battleNodeOptional.get();
 
 
-	virtual void process(
-		const PathNodeInfo & source,
-		CDestinationNodeInfo & destination,
-		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const override
-	{
-		auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
+				if(battleNode->locked)
+				{
+					logAi->trace(
+						"Block bypass guard at destination while moving %s -> %s",
+						source.coord.toString(),
+						destination.coord.toString());
 
 
-		if(blocker == BlockingReason::NONE)
-			return;
+					destination.blocked = true;
 
 
-		if(blocker == BlockingReason::DESTINATION_BLOCKED
-			&& destination.action == CGPathNode::EMBARK
-			&& nodeStorage->getAINode(destination.node)->specialAction)
-		{
-			return;
-		}
-		
-		if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->isBattleNode(source.node))
-		{
-			auto srcGuardians = cb->getGuardingCreatures(source.coord);
-			auto destGuardians = cb->getGuardingCreatures(destination.coord);
+					return;
+				}
 
 
-			for(auto srcGuard : srcGuardians)
-			{
-				if(!vstd::contains(destGuardians, srcGuard))
-					continue;
+				auto hero = nodeStorage->getHero();
+				auto danger = evaluateDanger(destination.coord, hero);
+
+				destination.node = battleNode;
+				nodeStorage->commit(destination, source);
 
 
-				auto guardPos = srcGuard->visitablePos();
-				if(guardPos != source.coord && guardPos != destination.coord)
+				if(battleNode->danger < danger)
 				{
 				{
-					destination.blocked = true; // allow to pass monster only through guard tile
+					battleNode->danger = danger;
 				}
 				}
-			}
 
 
-			if(!destination.blocked)
-			{
+				battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
+
 				logAi->trace(
 				logAi->trace(
-					"Bypass src guard while moving from %s to %s",
+					"Begin bypass guard at destination with danger %s while moving %s -> %s",
+					std::to_string(danger),
 					source.coord.toString(),
 					source.coord.toString(),
 					destination.coord.toString());
 					destination.coord.toString());
+
+				return;
 			}
 			}
 
 
-			return;
+			destination.blocked = true;
 		}
 		}
+	};
 
 
-		destination.blocked = true;
-	}
-};
-
-class AIPreviousNodeRule : public MovementToDestinationRule
-{
-private:
-	CPlayerSpecificInfoCallback * cb;
-	std::shared_ptr<AINodeStorage> nodeStorage;
-
-public:
-	AIPreviousNodeRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
-		:cb(cb), nodeStorage(nodeStorage)
+	class AIMovementToDestinationRule : public MovementToDestinationRule
 	{
 	{
-	}
+	private:
+		CPlayerSpecificInfoCallback * cb;
+		std::shared_ptr<AINodeStorage> nodeStorage;
 
 
-	virtual void process(
-		const PathNodeInfo & source,
-		CDestinationNodeInfo & destination,
-		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const override
-	{
-//FIXME: unused
-//		auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
+	public:
+		AIMovementToDestinationRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
+			:cb(cb), nodeStorage(nodeStorage)
+		{
+		}
 
 
-		if(source.guarded)
+		virtual void process(
+			const PathNodeInfo & source,
+			CDestinationNodeInfo & destination,
+			const PathfinderConfig * pathfinderConfig,
+			CPathfinderHelper * pathfinderHelper) const override
 		{
 		{
-			auto srcGuardian = cb->guardingCreaturePosition(source.node->coord);
+			auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
 
 
-			if(srcGuardian == source.node->coord)
+			if(blocker == BlockingReason::NONE)
+				return;
+
+			if(blocker == BlockingReason::DESTINATION_BLOCKED
+				&& destination.action == CGPathNode::EMBARK
+				&& nodeStorage->getAINode(destination.node)->specialAction)
 			{
 			{
-				// guardian tile is used as chain junction
-				destination.node->theNodeBefore = source.node;
+				return;
+			}
 
 
+			if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->isBattleNode(source.node))
+			{
 				logAi->trace(
 				logAi->trace(
-					"Link src node %s to destination node %s while bypassing guard",
+					"Bypass src guard while moving from %s to %s",
 					source.coord.toString(),
 					source.coord.toString(),
 					destination.coord.toString());
 					destination.coord.toString());
 
 
 				return;
 				return;
 			}
 			}
+
+			destination.blocked = true;
 		}
 		}
+	};
+
+	class AIPreviousNodeRule : public MovementToDestinationRule
+	{
+	private:
+		CPlayerSpecificInfoCallback * cb;
+		std::shared_ptr<AINodeStorage> nodeStorage;
 
 
-		if(source.node->action == CGPathNode::ENodeAction::BLOCKING_VISIT || source.node->action == CGPathNode::ENodeAction::VISIT)
+	public:
+		AIPreviousNodeRule(CPlayerSpecificInfoCallback * cb, std::shared_ptr<AINodeStorage> nodeStorage)
+			:cb(cb), nodeStorage(nodeStorage)
 		{
 		{
-			// we can not directly bypass objects, we need to interact with them first
-			destination.node->theNodeBefore = source.node;
+		}
 
 
-			logAi->trace(
-				"Link src node %s to destination node %s while bypassing visitable obj",
-				source.coord.toString(),
-				destination.coord.toString());
+		virtual void process(
+			const PathNodeInfo & source,
+			CDestinationNodeInfo & destination,
+			const PathfinderConfig * pathfinderConfig,
+			CPathfinderHelper * pathfinderHelper) const override
+		{
+			if(source.node->action == CGPathNode::ENodeAction::BLOCKING_VISIT || source.node->action == CGPathNode::ENodeAction::VISIT)
+			{
+				// we can not directly bypass objects, we need to interact with them first
+				destination.node->theNodeBefore = source.node;
 
 
-			return;
-		}
+				logAi->trace(
+					"Link src node %s to destination node %s while bypassing visitable obj",
+					source.coord.toString(),
+					destination.coord.toString());
 
 
-		auto aiSourceNode = nodeStorage->getAINode(source.node);
+				return;
+			}
 
 
-		if(aiSourceNode->specialAction)
-		{
-			// there is some action on source tile which should be performed before we can bypass it
-			destination.node->theNodeBefore = source.node;
-		}
-	}
-};
+			auto aiSourceNode = nodeStorage->getAINode(source.node);
 
 
-std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
-	CPlayerSpecificInfoCallback * cb,
-	VCAI * ai,
-	std::shared_ptr<AINodeStorage> nodeStorage)
-{
-	std::vector<std::shared_ptr<IPathfindingRule>> rules = {
-		std::make_shared<AILayerTransitionRule>(cb, ai, nodeStorage),
-		std::make_shared<DestinationActionRule>(),
-		std::make_shared<AIMovementToDestinationRule>(cb, nodeStorage),
-		std::make_shared<MovementCostRule>(),
-		std::make_shared<AIPreviousNodeRule>(cb, nodeStorage),
-		std::make_shared<AIMovementAfterDestinationRule>(cb, nodeStorage)
+			if(aiSourceNode->specialAction)
+			{
+				// there is some action on source tile which should be performed before we can bypass it
+				destination.node->theNodeBefore = source.node;
+			}
+		}
 	};
 	};
 
 
-	return rules;
-}
+	std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
+		CPlayerSpecificInfoCallback * cb,
+		VCAI * ai,
+		std::shared_ptr<AINodeStorage> nodeStorage)
+	{
+		std::vector<std::shared_ptr<IPathfindingRule>> rules = {
+			std::make_shared<AILayerTransitionRule>(cb, ai, nodeStorage),
+			std::make_shared<DestinationActionRule>(),
+			std::make_shared<AIMovementToDestinationRule>(cb, nodeStorage),
+			std::make_shared<MovementCostRule>(),
+			std::make_shared<AIPreviousNodeRule>(cb, nodeStorage),
+			std::make_shared<AIMovementAfterDestinationRule>(cb, nodeStorage)
+		};
+
+		return rules;
+	}
 
 
-AIPathfinderConfig::AIPathfinderConfig(
-	CPlayerSpecificInfoCallback * cb,
-	VCAI * ai,
-	std::shared_ptr<AINodeStorage> nodeStorage)
-	:PathfinderConfig(nodeStorage, makeRuleset(cb, ai, nodeStorage))
-{
+	AIPathfinderConfig::AIPathfinderConfig(
+		CPlayerSpecificInfoCallback * cb,
+		VCAI * ai,
+		std::shared_ptr<AINodeStorage> nodeStorage)
+		:PathfinderConfig(nodeStorage, makeRuleset(cb, ai, nodeStorage))
+	{
+	}
 }
 }

+ 10 - 7
AI/VCAI/Pathfinding/AIPathfinderConfig.h

@@ -13,11 +13,14 @@
 #include "AINodeStorage.h"
 #include "AINodeStorage.h"
 #include "../VCAI.h"
 #include "../VCAI.h"
 
 
-class AIPathfinderConfig : public PathfinderConfig
+namespace AIPathfinding
 {
 {
-public:
-	AIPathfinderConfig(
-		CPlayerSpecificInfoCallback * cb,
-		VCAI * ai, 
-		std::shared_ptr<AINodeStorage> nodeStorage);
-};
+	class AIPathfinderConfig : public PathfinderConfig
+	{
+	public:
+		AIPathfinderConfig(
+			CPlayerSpecificInfoCallback * cb,
+			VCAI * ai,
+			std::shared_ptr<AINodeStorage> nodeStorage);
+	};
+}