mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-19 21:10:12 +02:00
Merge pull request #5304 from IvanSavenko/oneway_ai
Enable one-way monoliths for AI
This commit is contained in:
commit
5ea4014589
@ -1296,7 +1296,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CGPath path;
|
CGPath path;
|
||||||
cb->getPathsInfo(h.get())->getPath(path, dst);
|
nullkiller->getPathsInfo(h.get())->getPath(path, dst);
|
||||||
if(path.nodes.empty())
|
if(path.nodes.empty())
|
||||||
{
|
{
|
||||||
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
||||||
@ -1808,4 +1808,9 @@ bool AIStatus::channelProbing()
|
|||||||
return ongoingChannelProbing;
|
return ongoingChannelProbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AIGateway::invalidatePaths()
|
||||||
|
{
|
||||||
|
nullkiller->invalidatePaths();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -159,6 +159,8 @@ public:
|
|||||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override;
|
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override;
|
||||||
void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
|
void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
|
||||||
|
|
||||||
|
void invalidatePaths() override;
|
||||||
|
|
||||||
void makeTurn();
|
void makeTurn();
|
||||||
|
|
||||||
void buildArmyIn(const CGTownInstance * t);
|
void buildArmyIn(const CGTownInstance * t);
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "../Goals/Composition.h"
|
#include "../Goals/Composition.h"
|
||||||
#include "../../../lib/CPlayerState.h"
|
#include "../../../lib/CPlayerState.h"
|
||||||
#include "../../lib/StartInfo.h"
|
#include "../../lib/StartInfo.h"
|
||||||
|
#include "../../lib/pathfinder/PathfinderCache.h"
|
||||||
|
#include "../../lib/pathfinder/PathfinderOptions.h"
|
||||||
|
|
||||||
namespace NKAI
|
namespace NKAI
|
||||||
{
|
{
|
||||||
@ -43,6 +45,8 @@ Nullkiller::Nullkiller()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Nullkiller::~Nullkiller() = default;
|
||||||
|
|
||||||
bool canUseOpenMap(std::shared_ptr<CCallback> cb, PlayerColor playerID)
|
bool canUseOpenMap(std::shared_ptr<CCallback> cb, PlayerColor playerID)
|
||||||
{
|
{
|
||||||
if(!cb->getStartInfo()->extraOptionsInfo.cheatsAllowed)
|
if(!cb->getStartInfo()->extraOptionsInfo.cheatsAllowed)
|
||||||
@ -73,6 +77,14 @@ void Nullkiller::init(std::shared_ptr<CCallback> cb, AIGateway * gateway)
|
|||||||
|
|
||||||
settings = std::make_unique<Settings>(cb->getStartInfo()->difficulty);
|
settings = std::make_unique<Settings>(cb->getStartInfo()->difficulty);
|
||||||
|
|
||||||
|
PathfinderOptions pathfinderOptions(cb.get());
|
||||||
|
|
||||||
|
pathfinderOptions.useTeleportTwoWay = true;
|
||||||
|
pathfinderOptions.useTeleportOneWay = settings->isOneWayMonolithUsageAllowed();
|
||||||
|
pathfinderOptions.useTeleportOneWayRandom = settings->isOneWayMonolithUsageAllowed();
|
||||||
|
|
||||||
|
pathfinderCache = std::make_unique<PathfinderCache>(cb.get(), pathfinderOptions);
|
||||||
|
|
||||||
if(canUseOpenMap(cb, playerID))
|
if(canUseOpenMap(cb, playerID))
|
||||||
{
|
{
|
||||||
useObjectGraph = settings->isObjectGraphAllowed();
|
useObjectGraph = settings->isObjectGraphAllowed();
|
||||||
@ -721,4 +733,14 @@ bool Nullkiller::handleTrading()
|
|||||||
return haveTraded;
|
return haveTraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CPathsInfo> Nullkiller::getPathsInfo(const CGHeroInstance * h) const
|
||||||
|
{
|
||||||
|
return pathfinderCache->getPathsInfo(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Nullkiller::invalidatePaths()
|
||||||
|
{
|
||||||
|
pathfinderCache->invalidatePaths();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,12 @@
|
|||||||
#include "../Analyzers/ObjectClusterizer.h"
|
#include "../Analyzers/ObjectClusterizer.h"
|
||||||
#include "../Helpers/ArmyFormation.h"
|
#include "../Helpers/ArmyFormation.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class PathfinderCache;
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
namespace NKAI
|
namespace NKAI
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -72,6 +78,7 @@ private:
|
|||||||
int3 targetTile;
|
int3 targetTile;
|
||||||
ObjectInstanceID targetObject;
|
ObjectInstanceID targetObject;
|
||||||
std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
|
std::map<const CGHeroInstance *, HeroLockedReason> lockedHeroes;
|
||||||
|
std::unique_ptr<PathfinderCache> pathfinderCache;
|
||||||
ScanDepth scanDepth;
|
ScanDepth scanDepth;
|
||||||
TResources lockedResources;
|
TResources lockedResources;
|
||||||
bool useHeroChain;
|
bool useHeroChain;
|
||||||
@ -101,6 +108,7 @@ public:
|
|||||||
std::mutex aiStateMutex;
|
std::mutex aiStateMutex;
|
||||||
|
|
||||||
Nullkiller();
|
Nullkiller();
|
||||||
|
~Nullkiller();
|
||||||
void init(std::shared_ptr<CCallback> cb, AIGateway * gateway);
|
void init(std::shared_ptr<CCallback> cb, AIGateway * gateway);
|
||||||
void makeTurn();
|
void makeTurn();
|
||||||
bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
|
bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
|
||||||
@ -124,6 +132,9 @@ public:
|
|||||||
bool handleTrading();
|
bool handleTrading();
|
||||||
void invalidatePathfinderData();
|
void invalidatePathfinderData();
|
||||||
|
|
||||||
|
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h) const;
|
||||||
|
void invalidatePaths();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetAiState();
|
void resetAiState();
|
||||||
void updateAiState(int pass, bool fast = false);
|
void updateAiState(int pass, bool fast = false);
|
||||||
|
@ -38,6 +38,7 @@ namespace NKAI
|
|||||||
pathfinderBucketsCount(1),
|
pathfinderBucketsCount(1),
|
||||||
pathfinderBucketSize(32),
|
pathfinderBucketSize(32),
|
||||||
allowObjectGraph(true),
|
allowObjectGraph(true),
|
||||||
|
useOneWayMonoliths(false),
|
||||||
useTroopsFromGarrisons(false),
|
useTroopsFromGarrisons(false),
|
||||||
updateHitmapOnTileReveal(false),
|
updateHitmapOnTileReveal(false),
|
||||||
openMap(true),
|
openMap(true),
|
||||||
@ -64,5 +65,6 @@ namespace NKAI
|
|||||||
openMap = node["openMap"].Bool();
|
openMap = node["openMap"].Bool();
|
||||||
useFuzzy = node["useFuzzy"].Bool();
|
useFuzzy = node["useFuzzy"].Bool();
|
||||||
useTroopsFromGarrisons = node["useTroopsFromGarrisons"].Bool();
|
useTroopsFromGarrisons = node["useTroopsFromGarrisons"].Bool();
|
||||||
|
useOneWayMonoliths = node["useOneWayMonoliths"].Bool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ namespace NKAI
|
|||||||
float maxArmyLossTarget;
|
float maxArmyLossTarget;
|
||||||
bool allowObjectGraph;
|
bool allowObjectGraph;
|
||||||
bool useTroopsFromGarrisons;
|
bool useTroopsFromGarrisons;
|
||||||
|
bool useOneWayMonoliths;
|
||||||
bool updateHitmapOnTileReveal;
|
bool updateHitmapOnTileReveal;
|
||||||
bool openMap;
|
bool openMap;
|
||||||
bool useFuzzy;
|
bool useFuzzy;
|
||||||
@ -58,6 +59,7 @@ namespace NKAI
|
|||||||
int getPathfinderBucketSize() const { return pathfinderBucketSize; }
|
int getPathfinderBucketSize() const { return pathfinderBucketSize; }
|
||||||
bool isObjectGraphAllowed() const { return allowObjectGraph; }
|
bool isObjectGraphAllowed() const { return allowObjectGraph; }
|
||||||
bool isGarrisonTroopsUsageAllowed() const { return useTroopsFromGarrisons; }
|
bool isGarrisonTroopsUsageAllowed() const { return useTroopsFromGarrisons; }
|
||||||
|
bool isOneWayMonolithUsageAllowed() const { return useOneWayMonoliths; }
|
||||||
bool isUpdateHitmapOnTileReveal() const { return updateHitmapOnTileReveal; }
|
bool isUpdateHitmapOnTileReveal() const { return updateHitmapOnTileReveal; }
|
||||||
bool isOpenMap() const { return openMap; }
|
bool isOpenMap() const { return openMap; }
|
||||||
bool isUseFuzzy() const { return useFuzzy; }
|
bool isUseFuzzy() const { return useFuzzy; }
|
||||||
|
@ -166,7 +166,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
|||||||
if(nextNode.specialAction || nextNode.chainMask != chainMask)
|
if(nextNode.specialAction || nextNode.chainMask != chainMask)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
auto targetNode = cb->getPathsInfo(hero)->getPathInfo(nextNode.coord);
|
auto targetNode = ai->nullkiller->getPathsInfo(hero)->getPathInfo(nextNode.coord);
|
||||||
|
|
||||||
if(!targetNode->reachable()
|
if(!targetNode->reachable()
|
||||||
|| targetNode->getCost() > nextNode.cost)
|
|| targetNode->getCost() > nextNode.cost)
|
||||||
@ -182,7 +182,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
|||||||
|
|
||||||
if(node->turns == 0 && node->coord != hero->visitablePos())
|
if(node->turns == 0 && node->coord != hero->visitablePos())
|
||||||
{
|
{
|
||||||
auto targetNode = cb->getPathsInfo(hero)->getPathInfo(node->coord);
|
auto targetNode = ai->nullkiller->getPathsInfo(hero)->getPathInfo(node->coord);
|
||||||
|
|
||||||
if(targetNode->accessible == EPathAccessibility::NOT_SET
|
if(targetNode->accessible == EPathAccessibility::NOT_SET
|
||||||
|| targetNode->accessible == EPathAccessibility::BLOCKED
|
|| targetNode->accessible == EPathAccessibility::BLOCKED
|
||||||
@ -239,7 +239,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
|||||||
if(hero->movementPointsRemaining() > 0)
|
if(hero->movementPointsRemaining() > 0)
|
||||||
{
|
{
|
||||||
CGPath path;
|
CGPath path;
|
||||||
bool isOk = cb->getPathsInfo(hero)->getPath(path, node->coord);
|
bool isOk = ai->nullkiller->getPathsInfo(hero)->getPath(path, node->coord);
|
||||||
|
|
||||||
if(isOk && path.nodes.back().turns > 0)
|
if(isOk && path.nodes.back().turns > 0)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +35,7 @@ void ExploreNeighbourTile::accept(AIGateway * ai)
|
|||||||
int3 target = int3(-1);
|
int3 target = int3(-1);
|
||||||
foreach_neighbour(pos, [&](int3 tile)
|
foreach_neighbour(pos, [&](int3 tile)
|
||||||
{
|
{
|
||||||
auto pathInfo = ai->myCb->getPathsInfo(hero)->getPathInfo(tile);
|
auto pathInfo = ai->nullkiller->getPathsInfo(hero)->getPathInfo(tile);
|
||||||
|
|
||||||
if(pathInfo->turns > 0)
|
if(pathInfo->turns > 0)
|
||||||
return;
|
return;
|
||||||
|
@ -223,7 +223,7 @@ bool ExplorationHelper::hasReachableNeighbor(const int3 & pos) const
|
|||||||
if(cbp->isInTheMap(tile))
|
if(cbp->isInTheMap(tile))
|
||||||
{
|
{
|
||||||
auto isAccessible = useCPathfinderAccessibility
|
auto isAccessible = useCPathfinderAccessibility
|
||||||
? ai->cb->getPathsInfo(hero)->getPathInfo(tile)->reachable()
|
? ai->getPathsInfo(hero)->getPathInfo(tile)->reachable()
|
||||||
: ai->pathfinder->isTileAccessible(hero, tile);
|
: ai->pathfinder->isTileAccessible(hero, tile);
|
||||||
|
|
||||||
if(isAccessible)
|
if(isAccessible)
|
||||||
|
@ -50,6 +50,8 @@ namespace AIPathfinding
|
|||||||
options.allowLayerTransitioningAfterBattle = true;
|
options.allowLayerTransitioningAfterBattle = true;
|
||||||
options.useTeleportWhirlpool = true;
|
options.useTeleportWhirlpool = true;
|
||||||
options.forceUseTeleportWhirlpool = true;
|
options.forceUseTeleportWhirlpool = true;
|
||||||
|
options.useTeleportOneWay = ai->settings->isOneWayMonolithUsageAllowed();;
|
||||||
|
options.useTeleportOneWayRandom = ai->settings->isOneWayMonolithUsageAllowed();;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIPathfinderConfig::~AIPathfinderConfig() = default;
|
AIPathfinderConfig::~AIPathfinderConfig() = default;
|
||||||
|
@ -133,8 +133,8 @@ bool HeroPtr::operator==(const HeroPtr & rhs) const
|
|||||||
|
|
||||||
bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const
|
bool CDistanceSorter::operator()(const CGObjectInstance * lhs, const CGObjectInstance * rhs) const
|
||||||
{
|
{
|
||||||
const CGPathNode * ln = ai->myCb->getPathsInfo(hero)->getPathInfo(lhs->visitablePos());
|
const CGPathNode * ln = ai->getPathsInfo(hero)->getPathInfo(lhs->visitablePos());
|
||||||
const CGPathNode * rn = ai->myCb->getPathsInfo(hero)->getPathInfo(rhs->visitablePos());
|
const CGPathNode * rn = ai->getPathsInfo(hero)->getPathInfo(rhs->visitablePos());
|
||||||
|
|
||||||
return ln->getCost() < rn->getCost();
|
return ln->getCost() < rn->getCost();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ float HeroMovementGoalEngineBase::calculateTurnDistanceInputValue(const Goals::A
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto pathInfo = ai->myCb->getPathsInfo(goal.hero.h)->getPathInfo(goal.tile);
|
auto pathInfo = ai->getPathsInfo(goal.hero.h)->getPathInfo(goal.tile);
|
||||||
return pathInfo->getCost();
|
return pathInfo->getCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||||
#include "../../lib/networkPacks/PacksForServer.h"
|
#include "../../lib/networkPacks/PacksForServer.h"
|
||||||
#include "../../lib/serializer/CTypeList.h"
|
#include "../../lib/serializer/CTypeList.h"
|
||||||
|
#include "../../lib/pathfinder/PathfinderCache.h"
|
||||||
|
#include "../../lib/pathfinder/PathfinderOptions.h"
|
||||||
|
|
||||||
#include "AIhelper.h"
|
#include "AIhelper.h"
|
||||||
|
|
||||||
@ -621,6 +623,7 @@ void VCAI::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<C
|
|||||||
playerID = *myCb->getPlayerID();
|
playerID = *myCb->getPlayerID();
|
||||||
myCb->waitTillRealize = true;
|
myCb->waitTillRealize = true;
|
||||||
myCb->unlockGsWhenWaiting = true;
|
myCb->unlockGsWhenWaiting = true;
|
||||||
|
pathfinderCache = std::make_unique<PathfinderCache>(myCb.get(), PathfinderOptions(myCb.get()));
|
||||||
|
|
||||||
if(!fh)
|
if(!fh)
|
||||||
fh = new FuzzyHelper();
|
fh = new FuzzyHelper();
|
||||||
@ -628,6 +631,16 @@ void VCAI::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<C
|
|||||||
retrieveVisitableObjs();
|
retrieveVisitableObjs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CPathsInfo> VCAI::getPathsInfo(const CGHeroInstance * h) const
|
||||||
|
{
|
||||||
|
return pathfinderCache->getPathsInfo(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VCAI::invalidatePaths()
|
||||||
|
{
|
||||||
|
pathfinderCache->invalidatePaths();
|
||||||
|
}
|
||||||
|
|
||||||
void VCAI::yourTurn(QueryID queryID)
|
void VCAI::yourTurn(QueryID queryID)
|
||||||
{
|
{
|
||||||
LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
|
LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
|
||||||
@ -1800,7 +1813,7 @@ bool VCAI::isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cb->getPathsInfo(h.get())->getPathInfo(pos)->reachable();
|
return getPathsInfo(h.get())->getPathInfo(pos)->reachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||||
@ -1837,7 +1850,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CGPath path;
|
CGPath path;
|
||||||
cb->getPathsInfo(h.get())->getPath(path, dst);
|
getPathsInfo(h.get())->getPath(path, dst);
|
||||||
if(path.nodes.empty())
|
if(path.nodes.empty())
|
||||||
{
|
{
|
||||||
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
struct QuestInfo;
|
struct QuestInfo;
|
||||||
|
class PathfinderCache;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
@ -80,6 +81,7 @@ public:
|
|||||||
std::vector<ObjectInstanceID> teleportChannelProbingList; //list of teleport channel exits that not visible and need to be (re-)explored
|
std::vector<ObjectInstanceID> teleportChannelProbingList; //list of teleport channel exits that not visible and need to be (re-)explored
|
||||||
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
|
//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
|
||||||
std::map<HeroPtr, std::set<const CGTownInstance *>> townVisitsThisWeek;
|
std::map<HeroPtr, std::set<const CGTownInstance *>> townVisitsThisWeek;
|
||||||
|
std::unique_ptr<PathfinderCache> pathfinderCache;
|
||||||
|
|
||||||
//part of mainLoop, but accessible from outside
|
//part of mainLoop, but accessible from outside
|
||||||
std::vector<Goals::TSubgoal> basicGoals;
|
std::vector<Goals::TSubgoal> basicGoals;
|
||||||
@ -254,6 +256,8 @@ public:
|
|||||||
std::vector<HeroPtr> getMyHeroes() const;
|
std::vector<HeroPtr> getMyHeroes() const;
|
||||||
HeroPtr primaryHero() const;
|
HeroPtr primaryHero() const;
|
||||||
void checkHeroArmy(HeroPtr h);
|
void checkHeroArmy(HeroPtr h);
|
||||||
|
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h) const;
|
||||||
|
void invalidatePaths() override;
|
||||||
|
|
||||||
void requestSent(const CPackForServer * pack, int requestID) override;
|
void requestSent(const CPackForServer * pack, int requestID) override;
|
||||||
void answerQuery(QueryID queryID, int selection);
|
void answerQuery(QueryID queryID, int selection);
|
||||||
|
@ -384,11 +384,6 @@ bool CCallback::canMoveBetween(const int3 &a, const int3 &b)
|
|||||||
return gs->map->canMoveBetween(a, b);
|
return gs->map->canMoveBetween(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const CPathsInfo> CCallback::getPathsInfo(const CGHeroInstance * h)
|
|
||||||
{
|
|
||||||
return cl->getPathsInfo(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<PlayerColor> CCallback::getPlayerID() const
|
std::optional<PlayerColor> CCallback::getPlayerID() const
|
||||||
{
|
{
|
||||||
return CBattleCallback::getPlayerID();
|
return CBattleCallback::getPlayerID();
|
||||||
|
@ -157,7 +157,6 @@ public:
|
|||||||
//client-specific functionalities (pathfinding)
|
//client-specific functionalities (pathfinding)
|
||||||
virtual bool canMoveBetween(const int3 &a, const int3 &b);
|
virtual bool canMoveBetween(const int3 &a, const int3 &b);
|
||||||
virtual int3 getGuardingCreaturePosition(int3 tile);
|
virtual int3 getGuardingCreaturePosition(int3 tile);
|
||||||
virtual std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
|
|
||||||
|
|
||||||
std::optional<PlayerColor> getPlayerID() const override;
|
std::optional<PlayerColor> getPlayerID() const override;
|
||||||
|
|
||||||
|
@ -97,6 +97,8 @@
|
|||||||
#include "../lib/networkPacks/PacksForServer.h"
|
#include "../lib/networkPacks/PacksForServer.h"
|
||||||
|
|
||||||
#include "../lib/pathfinder/CGPathNode.h"
|
#include "../lib/pathfinder/CGPathNode.h"
|
||||||
|
#include "../lib/pathfinder/PathfinderCache.h"
|
||||||
|
#include "../lib/pathfinder/PathfinderOptions.h"
|
||||||
|
|
||||||
#include "../lib/serializer/CTypeList.h"
|
#include "../lib/serializer/CTypeList.h"
|
||||||
#include "../lib/serializer/ESerializationVersion.h"
|
#include "../lib/serializer/ESerializationVersion.h"
|
||||||
@ -156,6 +158,7 @@ CPlayerInterface::~CPlayerInterface()
|
|||||||
if (LOCPLINT == this)
|
if (LOCPLINT == this)
|
||||||
LOCPLINT = nullptr;
|
LOCPLINT = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
|
void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB)
|
||||||
{
|
{
|
||||||
cb = CB;
|
cb = CB;
|
||||||
@ -164,9 +167,20 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
|
|||||||
CCS->musich->loadTerrainMusicThemes();
|
CCS->musich->loadTerrainMusicThemes();
|
||||||
initializeHeroTownList();
|
initializeHeroTownList();
|
||||||
|
|
||||||
|
pathfinderCache = std::make_unique<PathfinderCache>(cb.get(), PathfinderOptions(cb.get()));
|
||||||
adventureInt.reset(new AdventureMapInterface());
|
adventureInt.reset(new AdventureMapInterface());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CPathsInfo> CPlayerInterface::getPathsInfo(const CGHeroInstance * h)
|
||||||
|
{
|
||||||
|
return pathfinderCache->getPathsInfo(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPlayerInterface::invalidatePaths()
|
||||||
|
{
|
||||||
|
pathfinderCache->invalidatePaths();
|
||||||
|
}
|
||||||
|
|
||||||
void CPlayerInterface::closeAllDialogs()
|
void CPlayerInterface::closeAllDialogs()
|
||||||
{
|
{
|
||||||
// remove all active dialogs that do not expect query answer
|
// remove all active dialogs that do not expect query answer
|
||||||
@ -467,6 +481,8 @@ void CPlayerInterface::heroSecondarySkillChanged(const CGHeroInstance * hero, in
|
|||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
for (auto cuw : GH.windows().findWindows<IMarketHolder>())
|
for (auto cuw : GH.windows().findWindows<IMarketHolder>())
|
||||||
cuw->updateSecondarySkills();
|
cuw->updateSecondarySkills();
|
||||||
|
|
||||||
|
localState->verifyPath(hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
|
void CPlayerInterface::heroManaPointsChanged(const CGHeroInstance * hero)
|
||||||
@ -583,6 +599,8 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CArmedInstance *> objs
|
|||||||
|
|
||||||
if (hero)
|
if (hero)
|
||||||
{
|
{
|
||||||
|
localState->verifyPath(hero);
|
||||||
|
|
||||||
adventureInt->onHeroChanged(hero);
|
adventureInt->onHeroChanged(hero);
|
||||||
if(hero->inTownGarrison && hero->visitedTown != town)
|
if(hero->inTownGarrison && hero->visitedTown != town)
|
||||||
adventureInt->onTownChanged(hero->visitedTown);
|
adventureInt->onTownChanged(hero->visitedTown);
|
||||||
|
@ -27,6 +27,7 @@ class CGObjectInstance;
|
|||||||
class UpgradeInfo;
|
class UpgradeInfo;
|
||||||
class ConditionalWait;
|
class ConditionalWait;
|
||||||
struct CPathsInfo;
|
struct CPathsInfo;
|
||||||
|
class PathfinderCache;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ class CPlayerInterface : public CGameInterface, public IUpdateable
|
|||||||
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
|
std::list<std::shared_ptr<CInfoWindow>> dialogs; //queue of dialogs awaiting to be shown (not currently shown!)
|
||||||
|
|
||||||
std::unique_ptr<HeroMovementController> movementController;
|
std::unique_ptr<HeroMovementController> movementController;
|
||||||
|
std::unique_ptr<PathfinderCache> pathfinderCache;
|
||||||
public: // TODO: make private
|
public: // TODO: make private
|
||||||
std::unique_ptr<ArtifactsUIController> artifactController;
|
std::unique_ptr<ArtifactsUIController> artifactController;
|
||||||
std::shared_ptr<Environment> env;
|
std::shared_ptr<Environment> env;
|
||||||
@ -198,6 +200,8 @@ public: // public interface for use by client via LOCPLINT access
|
|||||||
void gamePause(bool pause);
|
void gamePause(bool pause);
|
||||||
void endNetwork();
|
void endNetwork();
|
||||||
void closeAllDialogs();
|
void closeAllDialogs();
|
||||||
|
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
|
||||||
|
void invalidatePaths() override;
|
||||||
|
|
||||||
///returns true if all events are processed internally
|
///returns true if all events are processed internally
|
||||||
bool capturedAllEvents();
|
bool capturedAllEvents();
|
||||||
|
@ -222,8 +222,6 @@ void CClient::initMapHandler()
|
|||||||
CGI->mh = std::make_shared<CMapHandler>(gs->map);
|
CGI->mh = std::make_shared<CMapHandler>(gs->map);
|
||||||
logNetwork->trace("Creating mapHandler: %d ms", CSH->th->getDiff());
|
logNetwork->trace("Creating mapHandler: %d ms", CSH->th->getDiff());
|
||||||
}
|
}
|
||||||
|
|
||||||
pathCache.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::initPlayerEnvironments()
|
void CClient::initPlayerEnvironments()
|
||||||
@ -494,24 +492,7 @@ void CClient::startPlayerBattleAction(const BattleID & battleID, PlayerColor col
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::updatePath(const ObjectInstanceID & id)
|
|
||||||
{
|
|
||||||
invalidatePaths();
|
|
||||||
auto hero = getHero(id);
|
|
||||||
updatePath(hero);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CClient::updatePath(const CGHeroInstance * hero)
|
|
||||||
{
|
|
||||||
if(LOCPLINT && hero)
|
|
||||||
LOCPLINT->localState->verifyPath(hero);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CClient::invalidatePaths()
|
|
||||||
{
|
|
||||||
boost::unique_lock<boost::mutex> pathLock(pathCacheMutex);
|
|
||||||
pathCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
vstd::RNG & CClient::getRandomGenerator()
|
vstd::RNG & CClient::getRandomGenerator()
|
||||||
{
|
{
|
||||||
@ -520,28 +501,6 @@ vstd::RNG & CClient::getRandomGenerator()
|
|||||||
throw std::runtime_error("Illegal access to random number generator from client code!");
|
throw std::runtime_error("Illegal access to random number generator from client code!");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const CPathsInfo> CClient::getPathsInfo(const CGHeroInstance * h)
|
|
||||||
{
|
|
||||||
assert(h);
|
|
||||||
boost::unique_lock<boost::mutex> pathLock(pathCacheMutex);
|
|
||||||
|
|
||||||
auto iter = pathCache.find(h);
|
|
||||||
|
|
||||||
if(iter == std::end(pathCache))
|
|
||||||
{
|
|
||||||
auto paths = std::make_shared<CPathsInfo>(getMapSize(), h);
|
|
||||||
|
|
||||||
gs->calculatePaths(h, *paths.get());
|
|
||||||
|
|
||||||
pathCache[h] = paths;
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SCRIPTING_ENABLED
|
#if SCRIPTING_ENABLED
|
||||||
scripting::Pool * CClient::getGlobalContextPool() const
|
scripting::Pool * CClient::getGlobalContextPool() const
|
||||||
{
|
{
|
||||||
|
@ -149,11 +149,6 @@ public:
|
|||||||
void battleFinished(const BattleID & battleID);
|
void battleFinished(const BattleID & battleID);
|
||||||
void startPlayerBattleAction(const BattleID & battleID, PlayerColor color);
|
void startPlayerBattleAction(const BattleID & battleID, PlayerColor color);
|
||||||
|
|
||||||
void invalidatePaths(); // clears this->pathCache()
|
|
||||||
void updatePath(const ObjectInstanceID & heroID); // invalidatePaths and update displayed hero path
|
|
||||||
void updatePath(const CGHeroInstance * hero);
|
|
||||||
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
|
|
||||||
|
|
||||||
friend class CCallback; //handling players actions
|
friend class CCallback; //handling players actions
|
||||||
friend class CBattleCallback; //handling players actions
|
friend class CBattleCallback; //handling players actions
|
||||||
|
|
||||||
@ -235,8 +230,5 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
std::unique_ptr<events::EventBus> clientEventBus;
|
std::unique_ptr<events::EventBus> clientEventBus;
|
||||||
|
|
||||||
mutable boost::mutex pathCacheMutex;
|
|
||||||
std::map<const CGHeroInstance *, std::shared_ptr<CPathsInfo>> pathCache;
|
|
||||||
|
|
||||||
void reinitScripting();
|
void reinitScripting();
|
||||||
};
|
};
|
||||||
|
@ -168,7 +168,6 @@ void ApplyClientNetPackVisitor::visitSetMana(SetMana & pack)
|
|||||||
void ApplyClientNetPackVisitor::visitSetMovePoints(SetMovePoints & pack)
|
void ApplyClientNetPackVisitor::visitSetMovePoints(SetMovePoints & pack)
|
||||||
{
|
{
|
||||||
const CGHeroInstance *h = cl.getHero(pack.hid);
|
const CGHeroInstance *h = cl.getHero(pack.hid);
|
||||||
cl.updatePath(h);
|
|
||||||
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroMovePointsChanged, h);
|
callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroMovePointsChanged, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +193,7 @@ void ApplyClientNetPackVisitor::visitFoWChange(FoWChange & pack)
|
|||||||
i.second->tileHidden(pack.tiles);
|
i.second->tileHidden(pack.tiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatchGarrisonChange(CClient & cl, ObjectInstanceID army1, ObjectInstanceID army2)
|
static void dispatchGarrisonChange(CClient & cl, ObjectInstanceID army1, ObjectInstanceID army2)
|
||||||
@ -235,33 +234,21 @@ void ApplyClientNetPackVisitor::visitSetStackType(SetStackType & pack)
|
|||||||
void ApplyClientNetPackVisitor::visitEraseStack(EraseStack & pack)
|
void ApplyClientNetPackVisitor::visitEraseStack(EraseStack & pack)
|
||||||
{
|
{
|
||||||
dispatchGarrisonChange(cl, pack.army, ObjectInstanceID());
|
dispatchGarrisonChange(cl, pack.army, ObjectInstanceID());
|
||||||
cl.updatePath(pack.army); //it is possible to remove last non-native unit for current terrain and lose movement penalty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitSwapStacks(SwapStacks & pack)
|
void ApplyClientNetPackVisitor::visitSwapStacks(SwapStacks & pack)
|
||||||
{
|
{
|
||||||
dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy);
|
dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy);
|
||||||
|
|
||||||
if(pack.srcArmy != pack.dstArmy)
|
|
||||||
cl.updatePath(pack.dstArmy); // adding/removing units may change terrain type penalty based on creature native terrains
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitInsertNewStack(InsertNewStack & pack)
|
void ApplyClientNetPackVisitor::visitInsertNewStack(InsertNewStack & pack)
|
||||||
{
|
{
|
||||||
dispatchGarrisonChange(cl, pack.army, ObjectInstanceID());
|
dispatchGarrisonChange(cl, pack.army, ObjectInstanceID());
|
||||||
|
|
||||||
cl.updatePath(pack.army); // adding/removing units may change terrain type penalty based on creature native terrains
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitRebalanceStacks(RebalanceStacks & pack)
|
void ApplyClientNetPackVisitor::visitRebalanceStacks(RebalanceStacks & pack)
|
||||||
{
|
{
|
||||||
dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy);
|
dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy);
|
||||||
|
|
||||||
if(pack.srcArmy != pack.dstArmy)
|
|
||||||
{
|
|
||||||
cl.updatePath(pack.srcArmy); // adding/removing units may change terrain type penalty based on creature native terrains
|
|
||||||
cl.updatePath(pack.dstArmy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & pack)
|
void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & pack)
|
||||||
@ -272,12 +259,6 @@ void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & p
|
|||||||
? ObjectInstanceID()
|
? ObjectInstanceID()
|
||||||
: pack.moves[0].dstArmy;
|
: pack.moves[0].dstArmy;
|
||||||
dispatchGarrisonChange(cl, pack.moves[0].srcArmy, destArmy);
|
dispatchGarrisonChange(cl, pack.moves[0].srcArmy, destArmy);
|
||||||
|
|
||||||
if(pack.moves[0].srcArmy != destArmy)
|
|
||||||
{
|
|
||||||
cl.updatePath(destArmy); // adding/removing units may change terrain type penalty based on creature native terrains
|
|
||||||
cl.updatePath(pack.moves[0].srcArmy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +284,6 @@ void ApplyClientNetPackVisitor::visitPutArtifact(PutArtifact & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitEraseArtifact(BulkEraseArtifacts & pack)
|
void ApplyClientNetPackVisitor::visitEraseArtifact(BulkEraseArtifacts & pack)
|
||||||
{
|
{
|
||||||
cl.updatePath(pack.artHolder);
|
|
||||||
for(const auto & slotErase : pack.posPack)
|
for(const auto & slotErase : pack.posPack)
|
||||||
callInterfaceIfPresent(cl, cl.getOwner(pack.artHolder), &IGameEventsReceiver::artifactRemoved, ArtifactLocation(pack.artHolder, slotErase));
|
callInterfaceIfPresent(cl, cl.getOwner(pack.artHolder), &IGameEventsReceiver::artifactRemoved, ArtifactLocation(pack.artHolder, slotErase));
|
||||||
}
|
}
|
||||||
@ -323,9 +303,6 @@ void ApplyClientNetPackVisitor::visitBulkMoveArtifacts(BulkMoveArtifacts & pack)
|
|||||||
callInterfaceIfPresent(cl, pack.interfaceOwner, &IGameEventsReceiver::askToAssembleArtifact, dstLoc);
|
callInterfaceIfPresent(cl, pack.interfaceOwner, &IGameEventsReceiver::askToAssembleArtifact, dstLoc);
|
||||||
if(pack.interfaceOwner != dstOwner)
|
if(pack.interfaceOwner != dstOwner)
|
||||||
callInterfaceIfPresent(cl, dstOwner, &IGameEventsReceiver::artifactMoved, srcLoc, dstLoc);
|
callInterfaceIfPresent(cl, dstOwner, &IGameEventsReceiver::artifactMoved, srcLoc, dstLoc);
|
||||||
|
|
||||||
cl.updatePath(pack.srcArtHolder); // hero might have equipped/unequipped Angel Wings
|
|
||||||
cl.updatePath(pack.dstArtHolder);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -354,15 +331,11 @@ void ApplyClientNetPackVisitor::visitBulkMoveArtifacts(BulkMoveArtifacts & pack)
|
|||||||
void ApplyClientNetPackVisitor::visitAssembledArtifact(AssembledArtifact & pack)
|
void ApplyClientNetPackVisitor::visitAssembledArtifact(AssembledArtifact & pack)
|
||||||
{
|
{
|
||||||
callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactAssembled, pack.al);
|
callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactAssembled, pack.al);
|
||||||
|
|
||||||
cl.updatePath(pack.al.artHolder); // hero might have equipped/unequipped Angel Wings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitDisassembledArtifact(DisassembledArtifact & pack)
|
void ApplyClientNetPackVisitor::visitDisassembledArtifact(DisassembledArtifact & pack)
|
||||||
{
|
{
|
||||||
callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactDisassembled, pack.al);
|
callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactDisassembled, pack.al);
|
||||||
|
|
||||||
cl.updatePath(pack.al.artHolder); // hero might have equipped/unequipped Angel Wings
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitHeroVisit(HeroVisit & pack)
|
void ApplyClientNetPackVisitor::visitHeroVisit(HeroVisit & pack)
|
||||||
@ -374,7 +347,7 @@ void ApplyClientNetPackVisitor::visitHeroVisit(HeroVisit & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitNewTurn(NewTurn & pack)
|
void ApplyClientNetPackVisitor::visitNewTurn(NewTurn & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
if(pack.newWeekNotification)
|
if(pack.newWeekNotification)
|
||||||
{
|
{
|
||||||
@ -387,7 +360,8 @@ void ApplyClientNetPackVisitor::visitNewTurn(NewTurn & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack)
|
void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
switch(pack.who)
|
switch(pack.who)
|
||||||
{
|
{
|
||||||
case GiveBonus::ETarget::OBJECT:
|
case GiveBonus::ETarget::OBJECT:
|
||||||
@ -423,7 +397,7 @@ void ApplyClientNetPackVisitor::visitChangeObjPos(ChangeObjPos & pack)
|
|||||||
CGI->mh->onObjectFadeIn(obj, pack.initiator);
|
CGI->mh->onObjectFadeIn(obj, pack.initiator);
|
||||||
CGI->mh->waitForOngoingAnimations();
|
CGI->mh->waitForOngoingAnimations();
|
||||||
}
|
}
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
|
void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
|
||||||
@ -490,7 +464,6 @@ void ApplyClientNetPackVisitor::visitPlayerReinitInterface(PlayerReinitInterface
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack)
|
void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
|
||||||
switch(pack.who)
|
switch(pack.who)
|
||||||
{
|
{
|
||||||
case GiveBonus::ETarget::OBJECT:
|
case GiveBonus::ETarget::OBJECT:
|
||||||
@ -531,7 +504,8 @@ void ApplyFirstClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
|
void ApplyClientNetPackVisitor::visitRemoveObject(RemoveObject & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
|
for(auto i=cl.playerint.begin(); i!=cl.playerint.end(); i++)
|
||||||
i->second->objectRemovedAfter();
|
i->second->objectRemovedAfter();
|
||||||
}
|
}
|
||||||
@ -561,7 +535,7 @@ void ApplyFirstClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
|
|||||||
void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
|
void ApplyClientNetPackVisitor::visitTryMoveHero(TryMoveHero & pack)
|
||||||
{
|
{
|
||||||
const CGHeroInstance *h = cl.getHero(pack.id);
|
const CGHeroInstance *h = cl.getHero(pack.id);
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
if(CGI->mh)
|
if(CGI->mh)
|
||||||
{
|
{
|
||||||
@ -976,7 +950,8 @@ void ApplyClientNetPackVisitor::visitPlayerMessageClient(PlayerMessageClient & p
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack)
|
void ApplyClientNetPackVisitor::visitAdvmapSpellCast(AdvmapSpellCast & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
auto caster = cl.getHero(pack.casterID);
|
auto caster = cl.getHero(pack.casterID);
|
||||||
if(caster)
|
if(caster)
|
||||||
//consider notifying other interfaces that see hero?
|
//consider notifying other interfaces that see hero?
|
||||||
@ -1068,7 +1043,7 @@ void ApplyClientNetPackVisitor::visitCenterView(CenterView & pack)
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
|
void ApplyClientNetPackVisitor::visitNewObject(NewObject & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
|
|
||||||
const CGObjectInstance *obj = pack.newObject;
|
const CGObjectInstance *obj = pack.newObject;
|
||||||
if(CGI->mh)
|
if(CGI->mh)
|
||||||
@ -1101,5 +1076,5 @@ void ApplyClientNetPackVisitor::visitSetAvailableArtifacts(SetAvailableArtifacts
|
|||||||
|
|
||||||
void ApplyClientNetPackVisitor::visitEntitiesChanged(EntitiesChanged & pack)
|
void ApplyClientNetPackVisitor::visitEntitiesChanged(EntitiesChanged & pack)
|
||||||
{
|
{
|
||||||
cl.invalidatePaths();
|
callAllInterfaces(cl, &CGameInterface::invalidatePaths);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ bool PlayerLocalState::hasPath(const CGHeroInstance * h) const
|
|||||||
bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destination)
|
bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destination)
|
||||||
{
|
{
|
||||||
CGPath path;
|
CGPath path;
|
||||||
if(!owner.cb->getPathsInfo(h)->getPath(path, destination))
|
if(!owner.getPathsInfo(h)->getPath(path, destination))
|
||||||
{
|
{
|
||||||
paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired)
|
paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired)
|
||||||
syncronizeState();
|
syncronizeState();
|
||||||
|
@ -17,6 +17,7 @@ class CArmedInstance;
|
|||||||
class JsonNode;
|
class JsonNode;
|
||||||
struct CGPath;
|
struct CGPath;
|
||||||
class int3;
|
class int3;
|
||||||
|
struct CPathsInfo;
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -107,6 +107,9 @@ void AdventureMapInterface::onHeroMovementStarted(const CGHeroInstance * hero)
|
|||||||
|
|
||||||
void AdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
|
void AdventureMapInterface::onHeroChanged(const CGHeroInstance *h)
|
||||||
{
|
{
|
||||||
|
if (h)
|
||||||
|
LOCPLINT->localState->verifyPath(h);
|
||||||
|
|
||||||
widget->getHeroList()->updateElement(h);
|
widget->getHeroList()->updateElement(h);
|
||||||
|
|
||||||
if (h && h == LOCPLINT->localState->getCurrentHero() && !widget->getInfoBar()->showingComponents())
|
if (h && h == LOCPLINT->localState->getCurrentHero() && !widget->getInfoBar()->showingComponents())
|
||||||
@ -546,7 +549,7 @@ void AdventureMapInterface::onTileLeftClicked(const int3 &targetPosition)
|
|||||||
{
|
{
|
||||||
isHero = true;
|
isHero = true;
|
||||||
|
|
||||||
const CGPathNode *pn = LOCPLINT->cb->getPathsInfo(currentHero)->getPathInfo(targetPosition);
|
const CGPathNode *pn = LOCPLINT->getPathsInfo(currentHero)->getPathInfo(targetPosition);
|
||||||
if(currentHero == topBlocking) //clicked selected hero
|
if(currentHero == topBlocking) //clicked selected hero
|
||||||
{
|
{
|
||||||
LOCPLINT->openHeroWindow(currentHero);
|
LOCPLINT->openHeroWindow(currentHero);
|
||||||
@ -685,7 +688,7 @@ void AdventureMapInterface::onTileHovered(const int3 &targetPosition)
|
|||||||
std::array<Cursor::Map, 4> cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, };
|
std::array<Cursor::Map, 4> cursorVisit = { Cursor::Map::T1_VISIT, Cursor::Map::T2_VISIT, Cursor::Map::T3_VISIT, Cursor::Map::T4_VISIT, };
|
||||||
std::array<Cursor::Map, 4> cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, };
|
std::array<Cursor::Map, 4> cursorSailVisit = { Cursor::Map::T1_SAIL_VISIT, Cursor::Map::T2_SAIL_VISIT, Cursor::Map::T3_SAIL_VISIT, Cursor::Map::T4_SAIL_VISIT, };
|
||||||
|
|
||||||
const CGPathNode * pathNode = LOCPLINT->cb->getPathsInfo(hero)->getPathInfo(targetPosition);
|
const CGPathNode * pathNode = LOCPLINT->getPathsInfo(hero)->getPathInfo(targetPosition);
|
||||||
assert(pathNode);
|
assert(pathNode);
|
||||||
|
|
||||||
if((GH.isKeyboardAltDown() || settings["gameTweaks"]["forceMovementInfo"].Bool()) && pathNode->reachable()) //overwrite status bar text with movement info
|
if((GH.isKeyboardAltDown() || settings["gameTweaks"]["forceMovementInfo"].Bool()) && pathNode->reachable()) //overwrite status bar text with movement info
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"updateHitmapOnTileReveal" : true,
|
"updateHitmapOnTileReveal" : true,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
|
"useOneWayMonoliths" : false,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": false,
|
"allowObjectGraph": false,
|
||||||
"pathfinderBucketsCount" : 3,
|
"pathfinderBucketsCount" : 3,
|
||||||
@ -63,6 +64,7 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"updateHitmapOnTileReveal" : true,
|
"updateHitmapOnTileReveal" : true,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
|
"useOneWayMonoliths" : false,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": false,
|
"allowObjectGraph": false,
|
||||||
"pathfinderBucketsCount" : 3,
|
"pathfinderBucketsCount" : 3,
|
||||||
@ -84,6 +86,7 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"updateHitmapOnTileReveal" : true,
|
"updateHitmapOnTileReveal" : true,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
|
"useOneWayMonoliths" : false,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": false,
|
"allowObjectGraph": false,
|
||||||
"pathfinderBucketsCount" : 3,
|
"pathfinderBucketsCount" : 3,
|
||||||
@ -105,6 +108,7 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"updateHitmapOnTileReveal" : true,
|
"updateHitmapOnTileReveal" : true,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
|
"useOneWayMonoliths" : false,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": false,
|
"allowObjectGraph": false,
|
||||||
"pathfinderBucketsCount" : 3,
|
"pathfinderBucketsCount" : 3,
|
||||||
@ -126,6 +130,7 @@
|
|||||||
"maxGoldPressure" : 0.3,
|
"maxGoldPressure" : 0.3,
|
||||||
"updateHitmapOnTileReveal" : true,
|
"updateHitmapOnTileReveal" : true,
|
||||||
"useTroopsFromGarrisons" : true,
|
"useTroopsFromGarrisons" : true,
|
||||||
|
"useOneWayMonoliths" : false,
|
||||||
"openMap": true,
|
"openMap": true,
|
||||||
"allowObjectGraph": false,
|
"allowObjectGraph": false,
|
||||||
"pathfinderBucketsCount" : 3,
|
"pathfinderBucketsCount" : 3,
|
||||||
|
@ -473,7 +473,7 @@ std::vector <const CGObjectInstance *> CGameInfoCallback::getVisitableObjs(int3
|
|||||||
|
|
||||||
for(const CGObjectInstance * obj : t->visitableObjects)
|
for(const CGObjectInstance * obj : t->visitableObjects)
|
||||||
{
|
{
|
||||||
if(getPlayerID() || obj->ID != Obj::EVENT) //hide events from players
|
if(!getPlayerID().has_value() || obj->ID != Obj::EVENT) //hide events from players
|
||||||
ret.push_back(obj);
|
ret.push_back(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,16 +945,11 @@ void CGameInfoCallback::getVisibleTilesInRange(std::unordered_set<int3> &tiles,
|
|||||||
gs->getTilesInRange(tiles, pos, radious, ETileVisibility::REVEALED, *getPlayerID(), distanceFormula);
|
gs->getTilesInRange(tiles, pos, radious, ETileVisibility::REVEALED, *getPlayerID(), distanceFormula);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameInfoCallback::calculatePaths(const std::shared_ptr<PathfinderConfig> & config)
|
void CGameInfoCallback::calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const
|
||||||
{
|
{
|
||||||
gs->calculatePaths(config);
|
gs->calculatePaths(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameInfoCallback::calculatePaths( const CGHeroInstance *hero, CPathsInfo &out)
|
|
||||||
{
|
|
||||||
gs->calculatePaths(hero, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const
|
const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const
|
||||||
{
|
{
|
||||||
return gs->map->artInstances.at(aid.num);
|
return gs->map->artInstances.at(aid.num);
|
||||||
|
@ -207,8 +207,7 @@ public:
|
|||||||
virtual std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
|
virtual std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> getAllVisibleTiles() const;
|
||||||
virtual bool isInTheMap(const int3 &pos) const;
|
virtual bool isInTheMap(const int3 &pos) const;
|
||||||
virtual void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
|
virtual void getVisibleTilesInRange(std::unordered_set<int3> &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula = int3::DIST_2D) const;
|
||||||
virtual void calculatePaths(const std::shared_ptr<PathfinderConfig> & config);
|
virtual void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const;
|
||||||
virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out);
|
|
||||||
virtual EDiggingStatus getTileDigStatus(int3 tile, bool verbose = true) const;
|
virtual EDiggingStatus getTileDigStatus(int3 tile, bool verbose = true) const;
|
||||||
|
|
||||||
//town
|
//town
|
||||||
|
@ -56,6 +56,7 @@ class CSaveFile;
|
|||||||
class BattleStateInfo;
|
class BattleStateInfo;
|
||||||
struct ArtifactLocation;
|
struct ArtifactLocation;
|
||||||
class BattleStateInfoForRetreat;
|
class BattleStateInfoForRetreat;
|
||||||
|
struct CPathsInfo;
|
||||||
|
|
||||||
#if SCRIPTING_ENABLED
|
#if SCRIPTING_ENABLED
|
||||||
namespace scripting
|
namespace scripting
|
||||||
@ -108,6 +109,9 @@ public:
|
|||||||
virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain){};
|
virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain){};
|
||||||
|
|
||||||
virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0;
|
virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0;
|
||||||
|
|
||||||
|
/// Invalidates and destroys all paths for all heroes
|
||||||
|
virtual void invalidatePaths(){};
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CDynLibHandler
|
class DLL_LINKAGE CDynLibHandler
|
||||||
|
@ -172,6 +172,7 @@ set(lib_MAIN_SRCS
|
|||||||
pathfinder/CGPathNode.cpp
|
pathfinder/CGPathNode.cpp
|
||||||
pathfinder/CPathfinder.cpp
|
pathfinder/CPathfinder.cpp
|
||||||
pathfinder/NodeStorage.cpp
|
pathfinder/NodeStorage.cpp
|
||||||
|
pathfinder/PathfinderCache.cpp
|
||||||
pathfinder/PathfinderOptions.cpp
|
pathfinder/PathfinderOptions.cpp
|
||||||
pathfinder/PathfindingRules.cpp
|
pathfinder/PathfindingRules.cpp
|
||||||
pathfinder/TurnInfo.cpp
|
pathfinder/TurnInfo.cpp
|
||||||
@ -584,6 +585,7 @@ set(lib_MAIN_HEADERS
|
|||||||
pathfinder/CGPathNode.h
|
pathfinder/CGPathNode.h
|
||||||
pathfinder/CPathfinder.h
|
pathfinder/CPathfinder.h
|
||||||
pathfinder/NodeStorage.h
|
pathfinder/NodeStorage.h
|
||||||
|
pathfinder/PathfinderCache.h
|
||||||
pathfinder/PathfinderOptions.h
|
pathfinder/PathfinderOptions.h
|
||||||
pathfinder/PathfinderUtil.h
|
pathfinder/PathfinderUtil.h
|
||||||
pathfinder/PathfindingRules.h
|
pathfinder/PathfindingRules.h
|
||||||
|
@ -1144,15 +1144,9 @@ void CGameState::apply(CPackForClient & pack)
|
|||||||
pack.applyGs(this);
|
pack.applyGs(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out)
|
void CGameState::calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const
|
||||||
{
|
{
|
||||||
calculatePaths(std::make_shared<SingleHeroPathfinderConfig>(out, this, hero));
|
CPathfinder pathfinder(const_cast<CGameState*>(this), config);
|
||||||
}
|
|
||||||
|
|
||||||
void CGameState::calculatePaths(const std::shared_ptr<PathfinderConfig> & config)
|
|
||||||
{
|
|
||||||
//FIXME: creating pathfinder is costly, maybe reset / clear is enough?
|
|
||||||
CPathfinder pathfinder(this, config);
|
|
||||||
pathfinder.calculatePaths();
|
pathfinder.calculatePaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +96,7 @@ public:
|
|||||||
void fillUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const override;
|
void fillUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const override;
|
||||||
PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const override;
|
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
|
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
|
||||||
void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out) override; //calculates possible paths for hero, by default uses current hero position and movement left; returns pointer to newly allocated CPath or nullptr if path does not exists
|
void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) const override;
|
||||||
void calculatePaths(const std::shared_ptr<PathfinderConfig> & config) override;
|
|
||||||
int3 guardingCreaturePosition (int3 pos) const override;
|
int3 guardingCreaturePosition (int3 pos) const override;
|
||||||
std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;
|
std::vector<CGObjectInstance*> guardingCreatures (int3 pos) const;
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ CPathsInfo::CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_)
|
|||||||
: sizes(Sizes), hero(hero_)
|
: sizes(Sizes), hero(hero_)
|
||||||
{
|
{
|
||||||
nodes.resize(boost::extents[ELayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y]);
|
nodes.resize(boost::extents[ELayer::NUM_LAYERS][sizes.z][sizes.x][sizes.y]);
|
||||||
|
heroBonusTreeVersion = hero->getTreeVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
CPathsInfo::~CPathsInfo() = default;
|
CPathsInfo::~CPathsInfo() = default;
|
||||||
|
@ -188,6 +188,8 @@ struct DLL_LINKAGE CPathsInfo
|
|||||||
const CGHeroInstance * hero;
|
const CGHeroInstance * hero;
|
||||||
int3 hpos;
|
int3 hpos;
|
||||||
int3 sizes;
|
int3 sizes;
|
||||||
|
/// Bonus tree version for which this information can be considered to be valid
|
||||||
|
int heroBonusTreeVersion = 0;
|
||||||
boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
|
boost::multi_array<CGPathNode, 4> nodes; //[layer][level][w][h]
|
||||||
|
|
||||||
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
|
CPathsInfo(const int3 & Sizes, const CGHeroInstance * hero_);
|
||||||
|
66
lib/pathfinder/PathfinderCache.cpp
Normal file
66
lib/pathfinder/PathfinderCache.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* PathfinderCache.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "StdInc.h"
|
||||||
|
#include "PathfinderCache.h"
|
||||||
|
|
||||||
|
#include "CGPathNode.h"
|
||||||
|
#include "PathfinderOptions.h"
|
||||||
|
|
||||||
|
#include "../CGameInfoCallback.h"
|
||||||
|
#include "../mapObjects/CGHeroInstance.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
std::shared_ptr<PathfinderConfig> PathfinderCache::createConfig(const CGHeroInstance * h, CPathsInfo & out)
|
||||||
|
{
|
||||||
|
auto config = std::make_shared<SingleHeroPathfinderConfig>(out, cb, h);
|
||||||
|
config->options = options;
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<CPathsInfo> PathfinderCache::buildPaths(const CGHeroInstance * h)
|
||||||
|
{
|
||||||
|
std::shared_ptr<CPathsInfo> result = std::make_shared<CPathsInfo>(cb->getMapSize(), h);
|
||||||
|
auto config = createConfig(h, *result);
|
||||||
|
|
||||||
|
cb->calculatePaths(config);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathfinderCache::PathfinderCache(const CGameInfoCallback * cb, const PathfinderOptions & options)
|
||||||
|
: cb(cb)
|
||||||
|
, options(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PathfinderCache::invalidatePaths()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(pathCacheMutex);
|
||||||
|
pathCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const CPathsInfo> PathfinderCache::getPathsInfo(const CGHeroInstance * h)
|
||||||
|
{
|
||||||
|
std::lock_guard lock(pathCacheMutex);
|
||||||
|
|
||||||
|
auto iter = pathCache.find(h);
|
||||||
|
if(iter == std::end(pathCache) || iter->second->heroBonusTreeVersion != h->getTreeVersion())
|
||||||
|
{
|
||||||
|
auto result = buildPaths(h);
|
||||||
|
pathCache[h] = result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
40
lib/pathfinder/PathfinderCache.h
Normal file
40
lib/pathfinder/PathfinderCache.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* PathfinderCache.h, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "PathfinderOptions.h"
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class CGameInfoCallback;
|
||||||
|
class CGHeroInstance;
|
||||||
|
class PathfinderConfig;
|
||||||
|
struct CPathsInfo;
|
||||||
|
|
||||||
|
class DLL_LINKAGE PathfinderCache
|
||||||
|
{
|
||||||
|
const CGameInfoCallback * cb;
|
||||||
|
std::mutex pathCacheMutex;
|
||||||
|
std::map<const CGHeroInstance *, std::shared_ptr<CPathsInfo>> pathCache;
|
||||||
|
PathfinderOptions options;
|
||||||
|
|
||||||
|
std::shared_ptr<PathfinderConfig> createConfig(const CGHeroInstance *h, CPathsInfo &out);
|
||||||
|
std::shared_ptr<CPathsInfo> buildPaths(const CGHeroInstance *h);
|
||||||
|
public:
|
||||||
|
PathfinderCache(const CGameInfoCallback * cb, const PathfinderOptions & options);
|
||||||
|
|
||||||
|
/// Invalidates and erases all existing paths from the cache
|
||||||
|
void invalidatePaths();
|
||||||
|
|
||||||
|
/// Returns compute path information for requested hero
|
||||||
|
std::shared_ptr<const CPathsInfo> getPathsInfo(const CGHeroInstance * h);
|
||||||
|
};
|
||||||
|
|
||||||
|
VCMI_LIB_NAMESPACE_END
|
@ -59,14 +59,17 @@ std::vector<std::shared_ptr<IPathfindingRule>> SingleHeroPathfinderConfig::build
|
|||||||
|
|
||||||
SingleHeroPathfinderConfig::~SingleHeroPathfinderConfig() = default;
|
SingleHeroPathfinderConfig::~SingleHeroPathfinderConfig() = default;
|
||||||
|
|
||||||
SingleHeroPathfinderConfig::SingleHeroPathfinderConfig(CPathsInfo & out, CGameState * gs, const CGHeroInstance * hero)
|
SingleHeroPathfinderConfig::SingleHeroPathfinderConfig(CPathsInfo & out, const CGameInfoCallback * gs, const CGHeroInstance * hero)
|
||||||
: PathfinderConfig(std::make_shared<NodeStorage>(out, hero), gs, buildRuleSet())
|
: PathfinderConfig(std::make_shared<NodeStorage>(out, hero), gs, buildRuleSet())
|
||||||
|
, hero(hero)
|
||||||
{
|
{
|
||||||
pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, hero, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CPathfinderHelper * SingleHeroPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs)
|
CPathfinderHelper * SingleHeroPathfinderConfig::getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs)
|
||||||
{
|
{
|
||||||
|
if (!pathfinderHelper)
|
||||||
|
pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, hero, options);
|
||||||
|
|
||||||
return pathfinderHelper.get();
|
return pathfinderHelper.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,9 +108,10 @@ class DLL_LINKAGE SingleHeroPathfinderConfig : public PathfinderConfig
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<CPathfinderHelper> pathfinderHelper;
|
std::unique_ptr<CPathfinderHelper> pathfinderHelper;
|
||||||
|
const CGHeroInstance * hero;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SingleHeroPathfinderConfig(CPathsInfo & out, CGameState * gs, const CGHeroInstance * hero);
|
SingleHeroPathfinderConfig(CPathsInfo & out, const CGameInfoCallback * gs, const CGHeroInstance * hero);
|
||||||
virtual ~SingleHeroPathfinderConfig();
|
virtual ~SingleHeroPathfinderConfig();
|
||||||
|
|
||||||
CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
|
CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
|
||||||
|
@ -120,7 +120,7 @@ TurnInfo::TurnInfo(TurnInfoCache * sharedCache, const CGHeroInstance * target, i
|
|||||||
{
|
{
|
||||||
static const CSelector selector = Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT);
|
static const CSelector selector = Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT);
|
||||||
const auto & bonuses = sharedCache->roughTerrainDiscount.getBonusList(target, selector);
|
const auto & bonuses = sharedCache->roughTerrainDiscount.getBonusList(target, selector);
|
||||||
roughTerrainDiscountValue = bonuses->getFirst(daySelector) != nullptr;
|
roughTerrainDiscountValue = bonuses->valOfBonuses(daySelector);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user