1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-27 22:49:25 +02:00

Pathfinder now uses IGameInfoCallback instead of CGameState

This commit is contained in:
Ivan Savenko
2025-05-15 21:23:54 +03:00
parent fe2f5f9217
commit c0850f41b3
26 changed files with 139 additions and 128 deletions

View File

@@ -15,7 +15,6 @@
#include "PathfindingRules.h"
#include "TurnInfo.h"
#include "../gameState/CGameState.h"
#include "../IGameSettings.h"
#include "../CPlayerState.h"
#include "../TerrainHandler.h"
@@ -75,8 +74,8 @@ void CPathfinderHelper::calculateNeighbourTiles(NeighbourTilesVector & result, c
}
}
CPathfinder::CPathfinder(const 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 : gameState().getTeleportChannelExits(channelID, hero->tempOwner))
for(const auto & objId : gameInfo.getTeleportChannelExits(channelID, hero->tempOwner))
{
const auto * obj = gameState().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() && gameState().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 : gameState().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 && !gameState().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 || !gameState().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 && gameState().isTeleportChannelBidirectional(obj->channel, hero->tempOwner);
return options.useTeleportTwoWay && gameInfo.isTeleportChannelBidirectional(obj->channel, hero->tempOwner);
}
bool CPathfinderHelper::addTeleportOneWay(const CGTeleport * obj) const
{
if(options.useTeleportOneWay && gameState().isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
if(options.useTeleportOneWay && gameInfo.isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
{
auto passableExits = CGTeleport::getPassableExits(gameState(), hero, gameState().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 && gameState().isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
if(options.useTeleportOneWayRandom && gameInfo.isTeleportChannelUnidirectional(obj->channel, hero->tempOwner))
{
auto passableExits = CGTeleport::getPassableExits(gameState(), hero, gameState().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 gameState().getGuardingCreatures(tile).size();
return gameInfo.getGuardingCreatures(tile).size();
}
CPathfinderHelper::CPathfinderHelper(const 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 = gameState().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 = gameState().getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
int baseCost = gameInfo.getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
return std::min(baseCost, costWithPathfinding);
}