2
0
Эх сурвалжийг харах

Merge pull request #5718 from IvanSavenko/gamestate_access_remove

Reduce direct access to gamestate class
Ivan Savenko 6 сар өмнө
parent
commit
184e841b16

+ 11 - 14
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -11,12 +11,9 @@
 #include "AINodeStorage.h"
 #include "Actions/TownPortalAction.h"
 #include "Actions/WhirlpoolAction.h"
-#include "../Goals/Goals.h"
-#include "../AIGateway.h"
 #include "../Engine/Nullkiller.h"
 #include "../../../lib/callback/IGameInfoCallback.h"
 #include "../../../lib/mapping/CMap.h"
-#include "../../../lib/mapObjects/MapObjects.h"
 #include "../../../lib/pathfinder/CPathfinder.h"
 #include "../../../lib/pathfinder/PathfinderUtil.h"
 #include "../../../lib/pathfinder/PathfinderOptions.h"
@@ -112,7 +109,7 @@ AINodeStorage::AINodeStorage(const Nullkiller * ai, const int3 & Sizes)
 
 AINodeStorage::~AINodeStorage() = default;
 
-void AINodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs)
+void AINodeStorage::initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo)
 {
 	if(heroChainPass != EHeroChainPass::INITIAL)
 		return;
@@ -121,8 +118,8 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
 
 	//TODO: fix this code duplication with NodeStorage::initialize, problem is to keep `resetTile` inline
 	const PlayerColor fowPlayer = ai->playerID;
-	const auto & fow = static_cast<const IGameInfoCallback *>(gs)->getPlayerTeam(fowPlayer)->fogOfWarMap;
-	const int3 sizes = gs->getMapSize();
+	const auto & fow = gameInfo.getPlayerTeam(fowPlayer)->fogOfWarMap;
+	const int3 sizes = gameInfo.getMapSize();
 
 	//Each thread gets different x, but an array of y located next to each other in memory
 
@@ -140,23 +137,23 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
 			{
 				for(pos.y = 0; pos.y < sizes.y; ++pos.y)
 				{
-					const TerrainTile & tile = gs->getMap().getTile(pos);
-					if (!tile.getTerrain()->isPassable())
+					const TerrainTile * tile = gameInfo.getTile(pos);
+					if (!tile->getTerrain()->isPassable())
 						continue;
 
-					if (tile.isWater())
+					if (tile->isWater())
 					{
-						resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, *tile, fow, player, gameInfo));
 						if (useFlying)
-							resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+							resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 						if (useWaterWalking)
-							resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
+							resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, *tile, fow, player, gameInfo));
 					}
 					else
 					{
-						resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, *tile, fow, player, gameInfo));
 						if (useFlying)
-							resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+							resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 					}
 				}
 			}

+ 1 - 5
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -16,10 +16,6 @@ constexpr int NKAI_GRAPH_TRACE_LEVEL = 0; // To actually enable graph visualizat
 
 #include "../../../lib/pathfinder/CGPathNode.h"
 #include "../../../lib/pathfinder/INodeStorage.h"
-#include "../../../lib/mapObjects/CGHeroInstance.h"
-#include "../AIUtility.h"
-#include "../Engine/FuzzyHelper.h"
-#include "../Goals/AbstractGoal.h"
 #include "Actions/SpecialAction.h"
 #include "Actors.h"
 
@@ -186,7 +182,7 @@ public:
 	AINodeStorage(const Nullkiller * ai, const int3 & sizes);
 	~AINodeStorage();
 
-	void initialize(const PathfinderOptions & options, const CGameState * gs) override;
+	void initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo) override;
 
 	bool increaseHeroChainTurnLimit();
 	bool selectFirstActor();

+ 2 - 2
AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp

@@ -56,14 +56,14 @@ namespace AIPathfinding
 
 	AIPathfinderConfig::~AIPathfinderConfig() = default;
 
-	CPathfinderHelper * AIPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs)
+	CPathfinderHelper * AIPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo)
 	{
 		auto hero = aiNodeStorage->getHero(source.node);
 		auto & helper = pathfindingHelpers[hero];
 
 		if(!helper)
 		{
-			helper.reset(new CPathfinderHelper(gs, hero, options));
+			helper.reset(new CPathfinderHelper(gameInfo, hero, options));
 		}
 
 		return helper.get();

+ 1 - 1
AI/Nullkiller/Pathfinding/AIPathfinderConfig.h

@@ -35,7 +35,7 @@ namespace AIPathfinding
 
 		~AIPathfinderConfig();
 
-		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs) override;
+		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo) override;
 	};
 }
 

+ 11 - 13
AI/VCAI/Pathfinding/AINodeStorage.cpp

@@ -10,10 +10,8 @@
 #include "StdInc.h"
 #include "AINodeStorage.h"
 #include "Actions/TownPortalAction.h"
-#include "../Goals/Goals.h"
 #include "../../../lib/callback/IGameInfoCallback.h"
 #include "../../../lib/mapping/CMap.h"
-#include "../../../lib/mapObjects/MapObjects.h"
 #include "../../../lib/pathfinder/CPathfinder.h"
 #include "../../../lib/pathfinder/PathfinderOptions.h"
 #include "../../../lib/pathfinder/PathfinderUtil.h"
@@ -29,11 +27,11 @@ AINodeStorage::AINodeStorage(const int3 & Sizes)
 
 AINodeStorage::~AINodeStorage() = default;
 
-void AINodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs)
+void AINodeStorage::initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo)
 {
 	int3 pos;
-	const int3 sizes = gs->getMapSize();
-	const auto & fow = static_cast<const IGameInfoCallback *>(gs)->getPlayerTeam(hero->tempOwner)->fogOfWarMap;
+	const int3 sizes = gameInfo.getMapSize();
+	const auto & fow = gameInfo.getPlayerTeam(hero->tempOwner)->fogOfWarMap;
 	const PlayerColor player = hero->tempOwner;
 
 	//make 200% sure that these are loop invariants (also a bit shorter code), let compiler do the rest(loop unswitching)
@@ -46,23 +44,23 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
 		{
 			for(pos.y=0; pos.y < sizes.y; ++pos.y)
 			{
-				const TerrainTile & tile = gs->getMap().getTile(pos);
-				if(!tile.getTerrain()->isPassable())
+				const TerrainTile * tile = gameInfo.getTile(pos);
+				if(!tile->getTerrain()->isPassable())
 					continue;
 				
-				if(tile.getTerrain()->isWater())
+				if(tile->getTerrain()->isWater())
 				{
-					resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
+					resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, *tile, fow, player, gameInfo));
 					if(useFlying)
-						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 					if(useWaterWalking)
-						resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, *tile, fow, player, gameInfo));
 				}
 				else
 				{
-					resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
+					resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, *tile, fow, player, gameInfo));
 					if(useFlying)
-						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 				}
 			}
 		}

+ 1 - 4
AI/VCAI/Pathfinding/AINodeStorage.h

@@ -10,12 +10,9 @@
 
 #pragma once
 
-#include "../../../lib/mapObjects/CGHeroInstance.h"
 #include "../../../lib/pathfinder/CGPathNode.h"
 #include "../../../lib/pathfinder/INodeStorage.h"
-#include "../AIUtility.h"
 #include "../FuzzyHelper.h"
-#include "../Goals/AbstractGoal.h"
 #include "Actions/ISpecialAction.h"
 
 struct AIPathNode : public CGPathNode
@@ -83,7 +80,7 @@ public:
 	AINodeStorage(const int3 & sizes);
 	~AINodeStorage();
 
-	void initialize(const PathfinderOptions & options, const CGameState * gs) override;
+	void initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo) override;
 
 	std::vector<CGPathNode *> getInitialNodes() override;
 

+ 2 - 2
AI/VCAI/Pathfinding/AIPathfinderConfig.cpp

@@ -51,11 +51,11 @@ namespace AIPathfinding
 
 	AIPathfinderConfig::~AIPathfinderConfig() = default;
 
-	CPathfinderHelper * AIPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs)
+	CPathfinderHelper * AIPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo)
 	{
 		if(!helper)
 		{
-			helper.reset(new CPathfinderHelper(gs, hero, options));
+			helper.reset(new CPathfinderHelper(gameInfo, hero, options));
 		}
 
 		return helper.get();

+ 1 - 2
AI/VCAI/Pathfinding/AIPathfinderConfig.h

@@ -11,7 +11,6 @@
 #pragma once
 
 #include "AINodeStorage.h"
-#include "../VCAI.h"
 #include "../../../lib/pathfinder/PathfinderOptions.h"
 
 namespace AIPathfinding
@@ -30,6 +29,6 @@ namespace AIPathfinding
 
 		~AIPathfinderConfig();
 
-		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs) override;
+		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo) override;
 	};
 }

+ 8 - 1
lib/callback/CGameInfoCallback.cpp

@@ -650,7 +650,7 @@ const CMapHeader * CGameInfoCallback::getMapHeader() const
 
 bool CGameInfoCallback::hasAccess(std::optional<PlayerColor> playerId) const
 {
-	return !getPlayerID() || getPlayerID()->isSpectator() || gameState().getPlayerRelations(*playerId, *getPlayerID()) != PlayerRelations::ENEMIES;
+	return !getPlayerID() || getPlayerID()->isSpectator() || getPlayerRelations(*playerId, *getPlayerID()) != PlayerRelations::ENEMIES;
 }
 
 EPlayerStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const
@@ -973,6 +973,13 @@ void CGameInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::option
 	}
 }
 
+bool CGameInfoCallback::checkForVisitableDir(const int3 & src, const int3 & dst) const
+{
+	const CMap & map = gameState().getMap();
+	const TerrainTile * pom = &map.getTile(dst);
+	return map.checkForVisitableDir(src, pom, dst);
+}
+
 #if SCRIPTING_ENABLED
 scripting::Pool * CGameInfoCallback::getGlobalContextPool() const
 {

+ 3 - 2
lib/callback/CGameInfoCallback.h

@@ -75,8 +75,8 @@ public:
 	const IMarket * getMarket(ObjectInstanceID objid) const;
 
 	//map
-	int3 guardingCreaturePosition (int3 pos) const;
-	std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const;
+	int3 guardingCreaturePosition (int3 pos) const override;
+	std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const override;
 	bool isTileGuardedUnchecked(int3 tile) const;
 	const CMapHeader * getMapHeader()const override;
 	int3 getMapSize() const override;
@@ -86,6 +86,7 @@ public:
 	void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
 	void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
 	EDiggingStatus getTileDigStatus(int3 tile, bool verbose = true) const override;
+	bool checkForVisitableDir(const int3 & src, const int3 & dst) const override;
 
 	//town
 	const CGTownInstance* getTown(ObjectInstanceID objid) const override;

+ 7 - 0
lib/callback/IGameInfoCallback.h

@@ -141,6 +141,13 @@ public:
 	/// Calculates pathfinding data into specified pathfinder config
 	virtual void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const = 0;
 
+	/// Returns position of creature that guards specified tile, or invalid tile if there are no guards
+	virtual int3 guardingCreaturePosition (int3 pos) const = 0;
+	/// Return true if src tile is visitable from dst tile
+	virtual bool checkForVisitableDir(const int3 & src, const int3 & dst) const = 0;
+	/// Returns all wandering monsters that guard specified tile
+	virtual std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const = 0;
+
 	/// Returns all tiles within specified range with specific tile visibility mode
 	virtual void getTilesInRange(std::unordered_set<int3> & tiles, const int3 & pos, int radius, ETileVisibility mode, std::optional<PlayerColor> player = std::optional<PlayerColor>(), int3::EDistanceFormula formula = int3::DIST_2D) const = 0;
 

+ 2 - 6
lib/gameState/CGameState.cpp

@@ -1089,7 +1089,7 @@ void CGameState::apply(CPackForClient & pack)
 
 void CGameState::calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const
 {
-	CPathfinder pathfinder(*const_cast<CGameState*>(this), config);
+	CPathfinder pathfinder(*this, config);
 	pathfinder.calculatePaths();
 }
 
@@ -1190,11 +1190,7 @@ bool CGameState::isVisibleFor(const CGObjectInstance * obj, PlayerColor player)
 	return false;
 }
 
-bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
-{
-	const TerrainTile * pom = &map->getTile(dst);
-	return map->checkForVisitableDir(src, pom, dst);
-}
+
 
 EVictoryLossCheckResult CGameState::checkForVictoryAndLoss(const PlayerColor & player) const
 {

+ 0 - 1
lib/gameState/CGameState.h

@@ -100,7 +100,6 @@ public:
 	BattleField battleGetBattlefieldType(int3 tile, vstd::RNG & randomGenerator);
 
 	PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const override;
-	bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
 	void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
 	std::vector<const CGObjectInstance*> guardingCreatures (int3 pos) const;
 

+ 1 - 1
lib/mapObjects/CGDwelling.cpp

@@ -223,7 +223,7 @@ void CGDwelling::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstan
 		return;
 	}
 
-	PlayerRelations relations = cb->gameState().getPlayerRelations( h->tempOwner, tempOwner );
+	PlayerRelations relations = cb->getPlayerRelations( h->tempOwner, tempOwner );
 
 	if ( relations == PlayerRelations::ALLIES )
 		return;//do not allow recruiting or capturing

+ 3 - 3
lib/mapObjects/CGHeroInstance.cpp

@@ -370,7 +370,7 @@ TObjectTypeHandler CGHeroInstance::getObjectHandler() const
 void CGHeroInstance::updateAppearance()
 {
 	auto handler = LIBRARY->objtypeh->getHandlerFor(Obj::HERO, getHeroClass()->getIndex());
-	auto terrain = cb->gameState().getTile(visitablePos())->getTerrainID();
+	auto terrain = cb->getTile(visitablePos())->getTerrainID();
 	auto app = handler->getOverride(terrain, this);
 	if (app)
 		appearance = app;
@@ -556,7 +556,7 @@ void CGHeroInstance::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroIn
 
 	if (ID == Obj::HERO)
 	{
-		if( cb->gameState().getPlayerRelations(tempOwner, h->tempOwner) != PlayerRelations::ENEMIES)
+		if( cb->getPlayerRelations(tempOwner, h->tempOwner) != PlayerRelations::ENEMIES)
 		{
 			//exchange
 			gameEvents.heroExchange(h->id, id);
@@ -581,7 +581,7 @@ void CGHeroInstance::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroIn
 
 			ObjectInstanceID boatId;
 			const auto boatPos = visitablePos();
-			if (cb->gameState().getMap().getTile(boatPos).isWater())
+			if (cb->getTile(boatPos)->isWater())
 			{
 				smp.val = movementPointsLimit(false);
 				if (!inBoat())

+ 4 - 4
lib/mapObjects/CGObjectInstance.cpp

@@ -123,19 +123,19 @@ void CGObjectInstance::setType(MapObjectID newID, MapObjectSubID newSubID)
 {
 	auto position = visitablePos();
 	auto oldOffset = appearance->getCornerOffset();
-	auto &tile = cb->gameState().getMap().getTile(position);
+	const auto * tile = cb->getTile(position);
 
 	//recalculate blockvis tiles - new appearance might have different blockmap than before
 	cb->gameState().getMap().hideObject(this);
 	auto handler = LIBRARY->objtypeh->getHandlerFor(newID, newSubID);
 
-	if(!handler->getTemplates(tile.getTerrainID()).empty())
+	if(!handler->getTemplates(tile->getTerrainID()).empty())
 	{
-		appearance = handler->getTemplates(tile.getTerrainID())[0];
+		appearance = handler->getTemplates(tile->getTerrainID())[0];
 	}
 	else
 	{
-		logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", newID, newSubID, visitablePos().toString(), tile.getTerrain()->getNameTranslated());
+		logGlobal->warn("Object %d:%d at %s has no templates suitable for terrain %s", newID, newSubID, visitablePos().toString(), tile->getTerrain()->getNameTranslated());
 		appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
 	}
 

+ 3 - 3
lib/mapObjects/CGTownInstance.cpp

@@ -306,7 +306,7 @@ void CGTownInstance::setOwner(IGameEventCallback & gameEvents, const PlayerColor
 
 void CGTownInstance::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance * h) const
 {
-	if(cb->gameState().getPlayerRelations( getOwner(), h->getOwner() ) == PlayerRelations::ENEMIES)
+	if(cb->getPlayerRelations( getOwner(), h->getOwner() ) == PlayerRelations::ENEMIES)
 	{
 		if(armedGarrison() || getVisitingHero())
 		{
@@ -625,7 +625,7 @@ void CGTownInstance::removeCapitols(IGameEventCallback & gameEvents, const Playe
 {
 	if (hasCapitol()) // search if there's an older capitol
 	{
-		PlayerState* state = cb->gameState().getPlayerState(owner); //get all towns owned by player
+		const PlayerState* state = cb->getPlayerState(owner); //get all towns owned by player
 		for (const auto & otherTown : state->getTowns())
 		{
 			if (otherTown != this && otherTown->hasCapitol())
@@ -695,7 +695,7 @@ ObjectInstanceID CGTownInstance::getObjInstanceID() const
 
 void CGTownInstance::updateAppearance()
 {
-	auto terrain = cb->gameState().getTile(visitablePos())->getTerrainID();
+	auto terrain = cb->getTile(visitablePos())->getTerrainID();
 	//FIXME: not the best way to do this
 	auto app = getObjectHandler()->getOverride(terrain, this);
 	if (app)

+ 10 - 12
lib/mapObjects/MiscObjects.cpp

@@ -19,7 +19,6 @@
 #include "../entities/artifact/CArtifact.h"
 #include "../CConfigHandler.h"
 #include "../texts/CGeneralTextHandler.h"
-#include "../CSoundBase.h"
 #include "../CSkillHandler.h"
 #include "../spells/CSpellHandler.h"
 #include "../gameState/CGameState.h"
@@ -30,7 +29,6 @@
 #include "../mapObjectConstructors/AObjectTypeHandler.h"
 #include "../mapObjectConstructors/CObjectClassesHandler.h"
 #include "../mapObjects/CGHeroInstance.h"
-#include "../modding/ModScope.h"
 #include "../networkPacks/PacksForClient.h"
 #include "../networkPacks/PacksForClientBattle.h"
 #include "../networkPacks/StackLocation.h"
@@ -76,7 +74,7 @@ bool CTeamVisited::wasVisited(const TeamID & team) const
 //CGMine
 void CGMine::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance * h) const
 {
-	auto relations = cb->gameState().getPlayerRelations(h->tempOwner, tempOwner);
+	auto relations = cb->getPlayerRelations(h->tempOwner, tempOwner);
 
 	if(relations == PlayerRelations::SAME_PLAYER) //we're visiting our mine
 	{
@@ -322,10 +320,10 @@ bool CGTeleport::isConnected(const CGObjectInstance * src, const CGObjectInstanc
 	return isConnected(srcObj, dstObj);
 }
 
-bool CGTeleport::isExitPassable(const CGameState & gs, const CGHeroInstance * h, const CGObjectInstance * obj)
+bool CGTeleport::isExitPassable(const IGameInfoCallback & gameInfo, const CGHeroInstance * h, const CGObjectInstance * obj)
 {
-	ObjectInstanceID topObjectID = gs.getMap().getTile(obj->visitablePos()).topVisitableObj();
-	const CGObjectInstance * topObject = gs.getObjInstance(topObjectID);
+	ObjectInstanceID topObjectID = gameInfo.getTile(obj->visitablePos())->topVisitableObj();
+	const CGObjectInstance * topObject = gameInfo.getObjInstance(topObjectID);
 
 	if(topObject->ID == Obj::HERO)
 	{
@@ -333,7 +331,7 @@ bool CGTeleport::isExitPassable(const CGameState & gs, const CGHeroInstance * h,
 			return false;
 
 		// Check if it's friendly hero or not
-		if(gs.getPlayerRelations(h->tempOwner, topObject->tempOwner) != PlayerRelations::ENEMIES)
+		if(gameInfo.getPlayerRelations(h->tempOwner, topObject->tempOwner) != PlayerRelations::ENEMIES)
 		{
 			// Exchange between heroes only possible via subterranean gates
 			if(!dynamic_cast<const CGSubterraneanGate *>(obj))
@@ -343,11 +341,11 @@ bool CGTeleport::isExitPassable(const CGameState & gs, const CGHeroInstance * h,
 	return true;
 }
 
-std::vector<ObjectInstanceID> CGTeleport::getPassableExits(const CGameState & gs, const CGHeroInstance * h, std::vector<ObjectInstanceID> exits)
+std::vector<ObjectInstanceID> CGTeleport::getPassableExits(const IGameInfoCallback & gameInfo, const CGHeroInstance * h, std::vector<ObjectInstanceID> exits)
 {
 	vstd::erase_if(exits, [&](const ObjectInstanceID & exit) -> bool 
 	{
-		return !isExitPassable(gs, h, gs.getObj(exit));
+		return !isExitPassable(gameInfo, h, gameInfo.getObj(exit));
 	});
 	return exits;
 }
@@ -878,7 +876,7 @@ std::vector<CreatureID> CGGarrison::providedCreatures() const
 
 void CGGarrison::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance * h) const
 {
-	auto relations = cb->gameState().getPlayerRelations(h->tempOwner, tempOwner);
+	auto relations = cb->getPlayerRelations(h->tempOwner, tempOwner);
 	if (relations == PlayerRelations::ENEMIES && stacksCount() > 0) {
 		//TODO: Find a way to apply magic garrison effects in battle.
 		gameEvents.startBattle(h, this);
@@ -1097,7 +1095,7 @@ const IObjectInterface * CGShipyard::getObject() const
 
 void CGShipyard::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstance * h) const
 {
-	if(cb->gameState().getPlayerRelations(tempOwner, h->tempOwner) == PlayerRelations::ENEMIES)
+	if(cb->getPlayerRelations(tempOwner, h->tempOwner) == PlayerRelations::ENEMIES)
 		gameEvents.setOwner(this, h->tempOwner);
 
 	if(shipyardStatus() != IBoatGenerator::GOOD)
@@ -1149,7 +1147,7 @@ void CGObelisk::onHeroVisit(IGameEventCallback & gameEvents, const CGHeroInstanc
 	InfoWindow iw;
 	iw.type = EInfoWindowMode::AUTO;
 	iw.player = h->tempOwner;
-	TeamState *ts = cb->gameState().getPlayerTeam(h->tempOwner);
+	const TeamState *ts = cb->getPlayerTeam(h->tempOwner);
 	assert(ts);
 	TeamID team = ts->id;
 

+ 2 - 2
lib/mapObjects/MiscObjects.h

@@ -220,8 +220,8 @@ public:
 	static bool isConnected(const CGTeleport * src, const CGTeleport * dst);
 	static bool isConnected(const CGObjectInstance * src, const CGObjectInstance * dst);
 	static void addToChannel(std::map<TeleportChannelID, std::shared_ptr<TeleportChannel> > &channelsList, const CGTeleport * obj);
-	static std::vector<ObjectInstanceID> getPassableExits(const CGameState & gs, const CGHeroInstance * h, std::vector<ObjectInstanceID> exits);
-	static bool isExitPassable(const CGameState & gs, const CGHeroInstance * h, const CGObjectInstance * obj);
+	static std::vector<ObjectInstanceID> getPassableExits(const IGameInfoCallback & gameInfo, const CGHeroInstance * h, std::vector<ObjectInstanceID> exits);
+	static bool isExitPassable(const IGameInfoCallback & gameInfo, const CGHeroInstance * h, const CGObjectInstance * obj);
 
 	template <typename Handler> void serialize(Handler &h)
 	{

+ 11 - 11
lib/pathfinder/CGPathNode.cpp

@@ -12,7 +12,7 @@
 
 #include "CPathfinder.h"
 
-#include "../gameState/CGameState.h"
+#include "../callback/IGameInfoCallback.h"
 #include "../mapObjects/CGHeroInstance.h"
 #include "../mapping/CMapDefines.h"
 
@@ -100,7 +100,7 @@ PathNodeInfo::PathNodeInfo()
 {
 }
 
-void PathNodeInfo::setNode(CGameState & gs, CGPathNode * n)
+void PathNodeInfo::setNode(const IGameInfoCallback & gameInfo, CGPathNode * n)
 {
 	node = n;
 	guarded = false;
@@ -110,14 +110,14 @@ void PathNodeInfo::setNode(CGameState & gs, CGPathNode * n)
 		assert(node->coord.isValid());
 
 		coord = node->coord;
-		tile = gs.getTile(coord);
+		tile = gameInfo.getTile(coord);
 		nodeObject = nullptr;
 		nodeHero = nullptr;
 
 		ObjectInstanceID topObjectID = tile->topVisitableObj();
 		if (topObjectID.hasValue())
 		{
-			nodeObject = gs.getObjInstance(topObjectID);
+			nodeObject = gameInfo.getObjInstance(topObjectID);
 
 			if (nodeObject->ID == Obj::HERO)
 			{
@@ -125,28 +125,28 @@ void PathNodeInfo::setNode(CGameState & gs, CGPathNode * n)
 				ObjectInstanceID bottomObjectID = tile->topVisitableObj(true);
 
 				if (bottomObjectID.hasValue())
-					nodeObject = gs.getObjInstance(bottomObjectID);
+					nodeObject = gameInfo.getObjInstance(bottomObjectID);
 			}
 		}
 	}
 
 }
 
-void PathNodeInfo::updateInfo(CPathfinderHelper * hlp, CGameState & gs)
+void PathNodeInfo::updateInfo(CPathfinderHelper * hlp, const IGameInfoCallback & gameInfo)
 {
-	if(gs.guardingCreaturePosition(node->coord).isValid() && !isInitialPosition)
+	if(gameInfo.guardingCreaturePosition(node->coord).isValid() && !isInitialPosition)
 	{
 		guarded = true;
 	}
 
 	if(nodeObject)
 	{
-		objectRelations = gs.getPlayerRelations(hlp->owner, nodeObject->tempOwner);
+		objectRelations = gameInfo.getPlayerRelations(hlp->owner, nodeObject->tempOwner);
 	}
 
 	if(nodeHero)
 	{
-		heroRelations = gs.getPlayerRelations(hlp->owner, nodeHero->tempOwner);
+		heroRelations = gameInfo.getPlayerRelations(hlp->owner, nodeHero->tempOwner);
 	}
 }
 
@@ -164,9 +164,9 @@ CDestinationNodeInfo::CDestinationNodeInfo():
 {
 }
 
-void CDestinationNodeInfo::setNode(CGameState & gs, CGPathNode * n)
+void CDestinationNodeInfo::setNode(const IGameInfoCallback & gameInfo, CGPathNode * n)
 {
-	PathNodeInfo::setNode(gs, n);
+	PathNodeInfo::setNode(gameInfo, n);
 
 	blocked = false;
 	action = EPathNodeAction::UNKNOWN;

+ 5 - 4
lib/pathfinder/CGPathNode.h

@@ -9,7 +9,8 @@
  */
 #pragma once
 
-#include "../GameConstants.h"
+#include "../constants/Enumerations.h"
+#include "../constants/EntityIdentifiers.h"
 #include "../int3.h"
 
 #include <boost/heap/fibonacci_heap.hpp>
@@ -219,9 +220,9 @@ struct DLL_LINKAGE PathNodeInfo
 
 	PathNodeInfo();
 
-	virtual void setNode(CGameState & gs, CGPathNode * n);
+	virtual void setNode(const IGameInfoCallback & gameInfo, CGPathNode * n);
 
-	void updateInfo(CPathfinderHelper * hlp, CGameState & gs);
+	void updateInfo(CPathfinderHelper * hlp, const IGameInfoCallback & gameInfo);
 
 	bool isNodeObjectVisitable() const;
 };
@@ -237,7 +238,7 @@ struct DLL_LINKAGE CDestinationNodeInfo : public PathNodeInfo
 
 	CDestinationNodeInfo();
 
-	void setNode(CGameState & gs, CGPathNode * n) override;
+	void setNode(const IGameInfoCallback & gameInfo, CGPathNode * n) override;
 
 	virtual bool isBetterWay() const;
 };

+ 41 - 43
lib/pathfinder/CPathfinder.cpp

@@ -15,7 +15,6 @@
 #include "PathfindingRules.h"
 #include "TurnInfo.h"
 
-#include "../gameState/CGameState.h"
 #include "../IGameSettings.h"
 #include "../CPlayerState.h"
 #include "../TerrainHandler.h"
@@ -25,7 +24,7 @@
 #include "../mapObjects/CGTownInstance.h"
 #include "../mapObjects/MiscObjects.h"
 #include "../mapping/CMap.h"
-#include "spells/CSpellHandler.h"
+#include "../spells/CSpellHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -75,8 +74,8 @@ void CPathfinderHelper::calculateNeighbourTiles(NeighbourTilesVector & result, c
 	}
 }
 
-CPathfinder::CPathfinder(CGameState & gamestate, std::shared_ptr<PathfinderConfig> config):
-	gamestate(gamestate),
+CPathfinder::CPathfinder(const IGameInfoCallback & gameInfo, std::shared_ptr<PathfinderConfig> config):
+	gameInfo(gameInfo),
 	config(std::move(config))
 {
 	initializeGraph();
@@ -112,14 +111,14 @@ void CPathfinder::calculatePaths()
 
 	for(auto * initialNode : initialNodes)
 	{
-		if(!gamestate.isInTheMap(initialNode->coord)/* || !gameState().getMap().isInTheMap(dest)*/) //check input
+		if(!gameInfo.isInTheMap(initialNode->coord)/* || !gameInfo.getMap().isInTheMap(dest)*/) //check input
 		{
-			logGlobal->error("CGameState::calculatePaths: Hero outside the gameState().map? How dare you...");
+			logGlobal->error("CgameInfo::calculatePaths: Hero outside the gameInfo.map? How dare you...");
 			throw std::runtime_error("Wrong checksum");
 		}
 
-		source.setNode(gamestate, initialNode);
-		auto * hlp = config->getOrCreatePathfinderHelper(source, gamestate);
+		source.setNode(gameInfo, initialNode);
+		auto * hlp = config->getOrCreatePathfinderHelper(source, gameInfo);
 
 		if(hlp->isHeroPatrolLocked())
 			continue;
@@ -134,14 +133,14 @@ void CPathfinder::calculatePaths()
 		counter++;
 		auto * node = topAndPop();
 
-		source.setNode(gamestate, node);
+		source.setNode(gameInfo, node);
 		source.node->locked = true;
 
 		int movement = source.node->moveRemains;
 		uint8_t turn = source.node->turns;
 		float cost = source.node->getCost();
 
-		auto * hlp = config->getOrCreatePathfinderHelper(source, gamestate);
+		auto * hlp = config->getOrCreatePathfinderHelper(source, gameInfo);
 
 		hlp->updateTurnInfo(turn);
 		if(movement == 0)
@@ -155,7 +154,7 @@ void CPathfinder::calculatePaths()
 		}
 
 		source.isInitialPosition = source.nodeHero == hlp->hero;
-		source.updateInfo(hlp, gamestate);
+		source.updateInfo(hlp, gameInfo);
 
 		//add accessible neighbouring nodes to the queue
 		for(EPathfindingLayer layer = EPathfindingLayer::LAND; layer < EPathfindingLayer::NUM_LAYERS; layer.advance(1))
@@ -170,8 +169,8 @@ void CPathfinder::calculatePaths()
 				if(neighbour->locked)
 					continue;
 
-				destination.setNode(gamestate, neighbour);
-				hlp = config->getOrCreatePathfinderHelper(destination, gamestate);
+				destination.setNode(gameInfo, neighbour);
+				hlp = config->getOrCreatePathfinderHelper(destination, gameInfo);
 
 				if(!hlp->isPatrolMovementAllowed(neighbour->coord))
 					continue;
@@ -183,7 +182,7 @@ void CPathfinder::calculatePaths()
 				destination.turn = turn;
 				destination.movementLeft = movement;
 				destination.cost = cost;
-				destination.updateInfo(hlp, gamestate);
+				destination.updateInfo(hlp, gameInfo);
 				destination.isGuardianTile = destination.guarded && isDestinationGuardian();
 
 				for(const auto & rule : config->rules)
@@ -201,7 +200,7 @@ void CPathfinder::calculatePaths()
 		}
 
 		//just add all passable teleport exits
-		hlp = config->getOrCreatePathfinderHelper(source, gamestate);
+		hlp = config->getOrCreatePathfinderHelper(source, gameInfo);
 
 		/// For now we disable teleports usage for patrol movement
 		/// VCAI not aware about patrol and may stuck while attempt to use teleport
@@ -221,7 +220,7 @@ void CPathfinder::calculatePaths()
 			if(teleportNode->accessible == EPathAccessibility::BLOCKED)
 				continue;
 
-			destination.setNode(gamestate, teleportNode);
+			destination.setNode(gameInfo, teleportNode);
 			destination.turn = turn;
 			destination.movementLeft = movement;
 			destination.cost = cost;
@@ -244,20 +243,20 @@ TeleporterTilesVector CPathfinderHelper::getAllowedTeleportChannelExits(const Te
 {
 	TeleporterTilesVector allowedExits;
 
-	for(const auto & objId : getTeleportChannelExits(channelID, hero->tempOwner))
+	for(const auto & objId : gameInfo.getTeleportChannelExits(channelID, hero->tempOwner))
 	{
-		const auto * obj = getObj(objId);
+		const auto * obj = gameInfo.getObj(objId);
 		if(dynamic_cast<const CGWhirlpool *>(obj))
 		{
 			auto pos = obj->getBlockedPos();
 			for(const auto & p : pos)
 			{
-				ObjectInstanceID topObject = gameState().getMap().getTile(p).topVisitableObj();
-				if(topObject.hasValue() && getObj(topObject)->ID == obj->ID)
+				ObjectInstanceID topObject = gameInfo.getTile(p)->topVisitableObj();
+				if(topObject.hasValue() && gameInfo.getObj(topObject)->ID == obj->ID)
 					allowedExits.push_back(p);
 			}
 		}
-		else if(obj && CGTeleport::isExitPassable(gameState(), hero, obj))
+		else if(obj && CGTeleport::isExitPassable(gameInfo, hero, obj))
 			allowedExits.push_back(obj->visitablePos());
 	}
 
@@ -268,7 +267,7 @@ TeleporterTilesVector CPathfinderHelper::getCastleGates(const PathNodeInfo & sou
 {
 	TeleporterTilesVector allowedExits;
 
-	for(const auto & town : getPlayerState(hero->tempOwner)->getTowns())
+	for(const auto & town : gameInfo.getPlayerState(hero->tempOwner)->getTowns())
 	{
 		if(town->id != source.nodeObject->id && town->getVisitingHero() == nullptr
 			&& town->hasBuilt(BuildingSubID::CASTLE_GATE))
@@ -391,19 +390,19 @@ EPathNodeAction CPathfinder::getTeleportDestAction() const
 
 bool CPathfinder::isDestinationGuardian() const
 {
-	return gamestate.guardingCreaturePosition(destination.node->coord) == destination.node->coord;
+	return gameInfo.guardingCreaturePosition(destination.node->coord) == destination.node->coord;
 }
 
 void CPathfinderHelper::initializePatrol()
 {
 	auto state = PATROL_NONE;
 
-	if(hero->patrol.patrolling && !getPlayerState(hero->tempOwner)->human)
+	if(hero->patrol.patrolling && !gameInfo.getPlayerState(hero->tempOwner)->human)
 	{
 		if(hero->patrol.patrolRadius)
 		{
 			state = PATROL_RADIUS;
-			gameState().getTilesInRange(patrolTiles, hero->patrol.initialPos, hero->patrol.patrolRadius, ETileVisibility::REVEALED, std::optional<PlayerColor>(), int3::DIST_MANHATTAN);
+			gameInfo.getTilesInRange(patrolTiles, hero->patrol.initialPos, hero->patrol.patrolRadius, ETileVisibility::REVEALED, std::optional<PlayerColor>(), int3::DIST_MANHATTAN);
 		}
 		else
 			state = PATROL_LOCKED;
@@ -415,17 +414,17 @@ void CPathfinderHelper::initializePatrol()
 void CPathfinder::initializeGraph()
 {
 	INodeStorage * nodeStorage = config->nodeStorage.get();
-	nodeStorage->initialize(config->options, &gamestate);
+	nodeStorage->initialize(config->options, gameInfo);
 }
 
 bool CPathfinderHelper::canMoveBetween(const int3 & a, const int3 & b) const
 {
-	return gameState().checkForVisitableDir(a, b);
+	return gameInfo.checkForVisitableDir(a, b);
 }
 
 bool CPathfinderHelper::isAllowedTeleportEntrance(const CGTeleport * obj) const
 {
-	if(!obj || !isTeleportEntrancePassable(obj, hero->tempOwner))
+	if(!obj || !gameInfo.isTeleportEntrancePassable(obj, hero->tempOwner))
 		return false;
 
 	const auto * whirlpool = dynamic_cast<const CGWhirlpool *>(obj);
@@ -442,14 +441,14 @@ bool CPathfinderHelper::isAllowedTeleportEntrance(const CGTeleport * obj) const
 
 bool CPathfinderHelper::addTeleportTwoWay(const CGTeleport * obj) const
 {
-	return options.useTeleportTwoWay && isTeleportChannelBidirectional(obj->channel, hero->tempOwner);
+	return options.useTeleportTwoWay && gameInfo.isTeleportChannelBidirectional(obj->channel, hero->tempOwner);
 }
 
 bool CPathfinderHelper::addTeleportOneWay(const CGTeleport * obj) const
 {
-	if(options.useTeleportOneWay && isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
+	if(options.useTeleportOneWay && gameInfo.isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
 	{
-		auto passableExits = CGTeleport::getPassableExits(gameState(), hero, getTeleportChannelExits(obj->channel, hero->tempOwner));
+		auto passableExits = CGTeleport::getPassableExits(gameInfo, hero, gameInfo.getTeleportChannelExits(obj->channel, hero->tempOwner));
 		if(passableExits.size() == 1)
 			return true;
 	}
@@ -458,9 +457,9 @@ bool CPathfinderHelper::addTeleportOneWay(const CGTeleport * obj) const
 
 bool CPathfinderHelper::addTeleportOneWayRandom(const CGTeleport * obj) const
 {
-	if(options.useTeleportOneWayRandom && isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
+	if(options.useTeleportOneWayRandom && gameInfo.isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
 	{
-		auto passableExits = CGTeleport::getPassableExits(gameState(), hero, getTeleportChannelExits(obj->channel, hero->tempOwner));
+		auto passableExits = CGTeleport::getPassableExits(gameInfo, hero, gameInfo.getTeleportChannelExits(obj->channel, hero->tempOwner));
 		if(passableExits.size() > 1)
 			return true;
 	}
@@ -495,11 +494,11 @@ bool CPathfinderHelper::passOneTurnLimitCheck(const PathNodeInfo & source) const
 
 int CPathfinderHelper::getGuardiansCount(int3 tile) const
 {
-	return getGuardingCreatures(tile).size();
+	return gameInfo.getGuardingCreatures(tile).size();
 }
 
-CPathfinderHelper::CPathfinderHelper(CGameState & gs, const CGHeroInstance * Hero, const PathfinderOptions & Options):
-	gs(gs),
+CPathfinderHelper::CPathfinderHelper(const IGameInfoCallback & gameInfo, const CGHeroInstance * Hero, const PathfinderOptions & Options):
+	gameInfo(gameInfo),
 	turn(-1),
 	owner(Hero->tempOwner),
 	hero(Hero),
@@ -573,7 +572,6 @@ void CPathfinderHelper::getNeighbours(
 	const boost::logic::tribool & onLand,
 	const bool limitCoastSailing) const
 {
-	const CMap * map = &gameState().getMap();
 	const TerrainType * sourceTerrain = sourceTile.getTerrain();
 
 	static constexpr std::array dirs = {
@@ -585,11 +583,11 @@ void CPathfinderHelper::getNeighbours(
 	for(const auto & dir : dirs)
 	{
 		const int3 destCoord = srcCoord + dir;
-		if(!map->isInTheMap(destCoord))
+		if(!gameInfo.isInTheMap(destCoord))
 			continue;
 
-		const TerrainTile & destTile = map->getTile(destCoord);
-		const TerrainType * destTerrain = destTile.getTerrain();
+		const TerrainTile * destTile = gameInfo.getTile(destCoord);
+		const TerrainType * destTerrain = destTile->getTerrain();
 		if(!destTerrain->isPassable())
 			continue;
 
@@ -598,7 +596,7 @@ void CPathfinderHelper::getNeighbours(
 		{
 			const int3 horizontalNeighbour = srcCoord + int3{dir.x, 0, 0};
 			const int3 verticalNeighbour = srcCoord + int3{0, dir.y, 0};
-			if(map->getTile(horizontalNeighbour).isLand() || map->getTile(verticalNeighbour).isLand())
+			if(gameInfo.getTile(horizontalNeighbour)->isLand() || gameInfo.getTile(verticalNeighbour)->isLand())
 				continue;
 		}
 
@@ -670,7 +668,7 @@ int CPathfinderHelper::getMovementCost(
 	}
 	else if(isAirLayer)
 	{
-		int baseCost = getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
+		int baseCost = gameInfo.getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
 		vstd::amin(movementCost, baseCost + ti->getFlyingMovementValue());
 	}
 	else if(isWaterLayer && ti->hasWaterWalking())
@@ -716,7 +714,7 @@ ui32 CPathfinderHelper::getTileMovementCost(const TerrainTile & dest, const Terr
 	//if hero can move without penalty - either all-native army, or creatures like Nomads in army
 	if(ti->hasNoTerrainPenalty(from.getTerrainID()))
 	{
-		int baseCost = getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
+		int baseCost = gameInfo.getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
 		return std::min(baseCost, costWithPathfinding);
 	}
 

+ 8 - 8
lib/pathfinder/CPathfinder.h

@@ -10,12 +10,14 @@
 #pragma once
 
 #include "CGPathNode.h"
-#include "../callback/CGameInfoCallback.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
+class IGameInfoCallback;
+class PathfinderConfig;
 class CGWhirlpool;
 class TurnInfo;
+class CGTeleport;
 struct PathfinderOptions;
 
 // Optimized storage - tile can have 0-8 neighbour tiles
@@ -32,13 +34,13 @@ public:
 	friend class CPathfinderHelper;
 
 	CPathfinder(
-		CGameState & _gs,
+		const IGameInfoCallback & gameInfo,
 		std::shared_ptr<PathfinderConfig> config);
 
 	void calculatePaths(); //calculates possible paths for hero, uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
 
 private:
-	CGameState & gamestate;
+	const IGameInfoCallback & gameInfo;
 
 	using ELayer = EPathfindingLayer;
 
@@ -63,12 +65,12 @@ private:
 	CGPathNode * topAndPop();
 };
 
-class DLL_LINKAGE CPathfinderHelper : private CGameInfoCallback
+class DLL_LINKAGE CPathfinderHelper : boost::noncopyable
 {
 	/// returns base movement cost for movement between specific tiles. Does not accounts for diagonal movement or last tile exception
 	ui32 getTileMovementCost(const TerrainTile & dest, const TerrainTile & from, const TurnInfo * ti) const;
 
-	CGameState & gs;
+	const IGameInfoCallback & gameInfo;
 public:
 	enum EPatrolState
 	{
@@ -87,10 +89,8 @@ public:
 	bool canCastWaterWalk;
 	bool whirlpoolProtection;
 
-	CPathfinderHelper(CGameState & gs, const CGHeroInstance * Hero, const PathfinderOptions & Options);
+	CPathfinderHelper(const IGameInfoCallback & gameInfo, const CGHeroInstance * Hero, const PathfinderOptions & Options);
 	virtual ~CPathfinderHelper();
-	CGameState & gameState() final { return gs; }
-	const CGameState & gameState() const final { return gs; }
 	void initializePatrol();
 	bool isHeroPatrolLocked() const;
 	bool canMoveFromNode(const PathNodeInfo & source) const;

+ 2 - 2
lib/pathfinder/INodeStorage.h

@@ -9,7 +9,7 @@
  */
 #pragma once
 
-#include "../GameConstants.h"
+#include "../constants/EntityIdentifiers.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -45,7 +45,7 @@ public:
 
 	virtual void commit(CDestinationNodeInfo & destination, const PathNodeInfo & source) = 0;
 
-	virtual void initialize(const PathfinderOptions & options, const CGameState * gs) = 0;
+	virtual void initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo) = 0;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 11 - 11
lib/pathfinder/NodeStorage.cpp

@@ -21,14 +21,14 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-void NodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs)
+void NodeStorage::initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo)
 {
 	//TODO: fix this code duplication with AINodeStorage::initialize, problem is to keep `resetTile` inline
 
 	int3 pos;
 	const PlayerColor player = out.hero->tempOwner;
-	const int3 sizes = gs->getMapSize();
-	const auto & fow = static_cast<const IGameInfoCallback *>(gs)->getPlayerTeam(player)->fogOfWarMap;
+	const int3 sizes = gameInfo.getMapSize();
+	const auto & fow = gameInfo.getPlayerTeam(player)->fogOfWarMap;
 
 	//make 200% sure that these are loop invariants (also a bit shorter code), let compiler do the rest(loop unswitching)
 	const bool useFlying = options.useFlying;
@@ -40,20 +40,20 @@ void NodeStorage::initialize(const PathfinderOptions & options, const CGameState
 		{
 			for(pos.y=0; pos.y < sizes.y; ++pos.y)
 			{
-				const TerrainTile & tile = gs->getMap().getTile(pos);
-				if(tile.isWater())
+				const TerrainTile * tile = gameInfo.getTile(pos);
+				if(tile->isWater())
 				{
-					resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, tile, fow, player, gs));
+					resetTile(pos, ELayer::SAIL, PathfinderUtil::evaluateAccessibility<ELayer::SAIL>(pos, *tile, fow, player, gameInfo));
 					if(useFlying)
-						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 					if(useWaterWalking)
-						resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::WATER, PathfinderUtil::evaluateAccessibility<ELayer::WATER>(pos, *tile, fow, player, gameInfo));
 				}
-				if(tile.isLand())
+				if(tile->isLand())
 				{
-					resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, tile, fow, player, gs));
+					resetTile(pos, ELayer::LAND, PathfinderUtil::evaluateAccessibility<ELayer::LAND>(pos, *tile, fow, player, gameInfo));
 					if(useFlying)
-						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, tile, fow, player, gs));
+						resetTile(pos, ELayer::AIR, PathfinderUtil::evaluateAccessibility<ELayer::AIR>(pos, *tile, fow, player, gameInfo));
 				}
 			}
 		}

+ 1 - 1
lib/pathfinder/NodeStorage.h

@@ -31,7 +31,7 @@ public:
 		return out.getNode(coord, layer);
 	}
 
-	void initialize(const PathfinderOptions & options, const CGameState * gs) override;
+	void initialize(const PathfinderOptions & options, const IGameInfoCallback & gameInfo) override;
 	virtual ~NodeStorage() = default;
 
 	std::vector<CGPathNode *> getInitialNodes() override;

+ 6 - 5
lib/pathfinder/PathfinderOptions.cpp

@@ -10,13 +10,14 @@
 #include "StdInc.h"
 #include "PathfinderOptions.h"
 
-#include "../gameState/CGameState.h"
-#include "../IGameSettings.h"
-#include "../GameLibrary.h"
 #include "NodeStorage.h"
 #include "PathfindingRules.h"
 #include "CPathfinder.h"
 
+#include "../IGameSettings.h"
+#include "../GameLibrary.h"
+#include "../callback/IGameInfoCallback.h"
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 PathfinderOptions::PathfinderOptions(const IGameInfoCallback & cb)
@@ -65,10 +66,10 @@ SingleHeroPathfinderConfig::SingleHeroPathfinderConfig(CPathsInfo & out, const I
 {
 }
 
-CPathfinderHelper * SingleHeroPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs)
+CPathfinderHelper * SingleHeroPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo)
 {
 	if (!pathfinderHelper)
-		pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, hero, options);
+		pathfinderHelper = std::make_unique<CPathfinderHelper>(gameInfo, hero, options);
 
 	return pathfinderHelper.get();
 }

+ 2 - 2
lib/pathfinder/PathfinderOptions.h

@@ -101,7 +101,7 @@ public:
 		std::vector<std::shared_ptr<IPathfindingRule>> rules);
 	virtual ~PathfinderConfig() = default;
 
-	virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs) = 0;
+	virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo) = 0;
 };
 
 class DLL_LINKAGE SingleHeroPathfinderConfig : public PathfinderConfig
@@ -114,7 +114,7 @@ public:
 	SingleHeroPathfinderConfig(CPathsInfo & out, const IGameInfoCallback & gs, const CGHeroInstance * hero);
 	virtual ~SingleHeroPathfinderConfig();
 
-	CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState & gs) override;
+	CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo) override;
 
 	static std::vector<std::shared_ptr<IPathfindingRule>> buildRuleSet();
 };

+ 6 - 7
lib/pathfinder/PathfinderUtil.h

@@ -9,10 +9,9 @@
  */
 #pragma once
 
-#include "../TerrainHandler.h"
 #include "../mapObjects/CGObjectInstance.h"
 #include "../mapping/CMapDefines.h"
-#include "../gameState/CGameState.h"
+#include "../callback/IGameInfoCallback.h"
 #include "CGPathNode.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -23,7 +22,7 @@ namespace PathfinderUtil
 	using ELayer = EPathfindingLayer;
 
 	template<EPathfindingLayer::Type layer>
-	EPathAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile & tinfo, const FoW & fow, const PlayerColor player, const CGameState * gs)
+	EPathAccessibility evaluateAccessibility(const int3 & pos, const TerrainTile & tinfo, const FoW & fow, const PlayerColor player, const IGameInfoCallback & gameInfo)
 	{
 		if(!fow[pos.z][pos.x][pos.y])
 			return EPathAccessibility::BLOCKED;
@@ -34,8 +33,8 @@ namespace PathfinderUtil
 		case ELayer::SAIL:
 			if(tinfo.visitable())
 			{
-				auto frontVisitable = gs->getObjInstance(tinfo.visitableObjects.front());
-				auto backVisitable = gs->getObjInstance(tinfo.visitableObjects.front());
+				auto frontVisitable = gameInfo.getObjInstance(tinfo.visitableObjects.front());
+				auto backVisitable = gameInfo.getObjInstance(tinfo.visitableObjects.front());
 
 				if(frontVisitable->ID == Obj::SANCTUARY && backVisitable->ID == Obj::HERO && backVisitable->getOwner() != player) //non-owned hero stands on Sanctuary
 				{
@@ -48,7 +47,7 @@ namespace PathfinderUtil
 
 					for(const auto objID : tinfo.visitableObjects)
 					{
-						auto obj = gs->getObjInstance(objID);
+						auto obj = gameInfo.getObjInstance(objID);
 
 						if(obj->isBlockedVisitable())
 							hasBlockedVisitable = true;
@@ -68,7 +67,7 @@ namespace PathfinderUtil
 			{
 				return EPathAccessibility::BLOCKED;
 			}
-			else if(gs->guardingCreaturePosition(pos).isValid())
+			else if(gameInfo.guardingCreaturePosition(pos).isValid())
 			{
 				// Monster close by; blocked visit for battle
 				return EPathAccessibility::GUARDED;

+ 4 - 0
test/mock/mock_IGameInfoCallback.h

@@ -75,6 +75,10 @@ public:
 	MOCK_CONST_METHOD2(isTeleportChannelBidirectional, bool(TeleportChannelID id, PlayerColor player));
 	MOCK_CONST_METHOD2(isTeleportChannelUnidirectional, bool(TeleportChannelID id, PlayerColor player));
 	MOCK_CONST_METHOD2(isTeleportEntrancePassable, bool(const CGTeleport * obj, PlayerColor player));
+	MOCK_CONST_METHOD1(guardingCreaturePosition, int3(int3 pos));
+	MOCK_CONST_METHOD2(checkForVisitableDir, bool(const int3 & src, const int3 & dst));
+	MOCK_CONST_METHOD1(getGuardingCreatures, std::vector<const CGObjectInstance *>(int3 pos));
+
 	MOCK_METHOD2(pickAllowedArtsSet, void(std::vector<ArtifactID> & out, vstd::RNG & rand));
 
 #if SCRIPTING_ENABLED