From 2e49d6aca92b2901daeb65ca81ea5b044570ec9d Mon Sep 17 00:00:00 2001 From: Mircea TheHonestCTO Date: Thu, 4 Sep 2025 00:56:36 +0200 Subject: [PATCH] fix: skip pass and priority pass if hero is not valid anymore to as extra checks for lost heroes --- AI/Nullkiller2/AIUtility.cpp | 8 +++--- AI/Nullkiller2/AIUtility.h | 4 +-- AI/Nullkiller2/Engine/Nullkiller.cpp | 28 +++++++++++++------- AI/Nullkiller2/Engine/Nullkiller.h | 2 +- AI/Nullkiller2/Pathfinding/AINodeStorage.cpp | 4 +-- lib/callback/CGameInfoCallback.cpp | 7 +++-- lib/callback/CGameInfoCallback.h | 2 +- lib/callback/MapInfoCallback.cpp | 10 +++---- lib/callback/MapInfoCallback.h | 2 +- 9 files changed, 37 insertions(+), 30 deletions(-) diff --git a/AI/Nullkiller2/AIUtility.cpp b/AI/Nullkiller2/AIUtility.cpp index dc7144eb8..0c5adad58 100644 --- a/AI/Nullkiller2/AIUtility.cpp +++ b/AI/Nullkiller2/AIUtility.cpp @@ -95,14 +95,14 @@ const CGHeroInstance * HeroPtr::getUnverified() const return hero; } -bool HeroPtr::verify() const +bool HeroPtr::verify(const bool verbose) const { // TODO: check if these all assertions every time we get info about hero affect efficiency // behave terribly when attempting unauthorized access to hero that is not ours (or was lost) if(hero) { - const auto *obj = cpsic->getObj(hero->id); + const auto *obj = cpsic->getObj(hero->id, verbose); //const bool owned = obj && obj->tempOwner == ai->playerID; if(!obj) @@ -123,9 +123,9 @@ const CGHeroInstance * HeroPtr::operator->() const } // Should be called before using the hero inside this HeroPtr, that's the point of this -bool HeroPtr::isVerified() const +bool HeroPtr::isVerified(const bool verbose) const { - return verify(); + return verify(verbose); } // enforces isVerified() diff --git a/AI/Nullkiller2/AIUtility.h b/AI/Nullkiller2/AIUtility.h index 3f325d846..4687d3caa 100644 --- a/AI/Nullkiller2/AIUtility.h +++ b/AI/Nullkiller2/AIUtility.h @@ -79,7 +79,7 @@ struct DLL_EXPORT HeroPtr private: const CGHeroInstance * hero; std::shared_ptr cpsic; - bool verify() const; + bool verify(bool verbose = true) const; public: explicit HeroPtr(const CGHeroInstance * input, std::shared_ptr cpsic); @@ -102,7 +102,7 @@ public: std::string nameOrDefault() const; const CGHeroInstance * get() const; const CGHeroInstance * getUnverified() const; - bool isVerified() const; + bool isVerified(bool verbose = true) const; }; enum BattleState diff --git a/AI/Nullkiller2/Engine/Nullkiller.cpp b/AI/Nullkiller2/Engine/Nullkiller.cpp index a55e73091..a55bc6d53 100644 --- a/AI/Nullkiller2/Engine/Nullkiller.cpp +++ b/AI/Nullkiller2/Engine/Nullkiller.cpp @@ -460,17 +460,22 @@ void Nullkiller::makeTurn() continue; } -#if NK2AI_TRACE_LEVEL >= 1 logAi->info("Pass %d: Performing prio %d task %s with prio: %d", i, prioOfTask, selectedTask->toString(), selectedTask->priority); -#endif - if(!executeTask(selectedTask)) + if(HeroPtr heroPtr(selectedTask->getHero(), cc); selectedTask->getHero() && !heroPtr.isVerified(false)) { - if(hasAnySuccess) - break; - return; + logAi->warn("Nullkiller::makeTurn Skipping pass due to unverified hero: %s", heroPtr.nameOrDefault()); + } + else + { + if(!executeTask(selectedTask)) + { + if(hasAnySuccess) + break; + return; + } + hasAnySuccess = true; } - hasAnySuccess = true; } hasAnySuccess |= handleTrading(); @@ -509,13 +514,16 @@ bool Nullkiller::updateStateAndExecutePriorityPass(Goals::TGoalVec & tempResults { logAi->info("Pass %d: Performing priorityPass %d task %s with prio: %d", passIndex, i, bestPrioPassTask->toString(), bestPrioPassTask->priority); - if(!executeTask(bestPrioPassTask)) + if(HeroPtr heroPtr(bestPrioPassTask->getHero(), cc); bestPrioPassTask->getHero() && !heroPtr.isVerified(false)) + { + logAi->warn("Nullkiller::updateStateAndExecutePriorityPass Skipping priorityPass due to unverified hero: %s", heroPtr.nameOrDefault()); + } + else if(!executeTask(bestPrioPassTask)) { logAi->warn("Task failed to execute"); return false; } - // TODO: Mircea: Might want to consider calling it before executeTask just in case updateState(); } else @@ -555,7 +563,7 @@ HeroRole Nullkiller::getTaskRole(const Goals::TTask & task) const return heroRole; } -bool Nullkiller::executeTask(const Goals::TTask & task) +bool Nullkiller::executeTask(const Goals::TTask & task) const { auto start = std::chrono::high_resolution_clock::now(); std::string taskDescr = task->toString(); diff --git a/AI/Nullkiller2/Engine/Nullkiller.h b/AI/Nullkiller2/Engine/Nullkiller.h index 274002b19..3c7b5b9bc 100644 --- a/AI/Nullkiller2/Engine/Nullkiller.h +++ b/AI/Nullkiller2/Engine/Nullkiller.h @@ -148,7 +148,7 @@ private: void decompose(Goals::TGoalVec & results, const Goals::TSubgoal& behavior, int decompositionMaxDepth) const; Goals::TTask choseBestTask(Goals::TGoalVec & tasks) const; Goals::TTaskVec buildPlan(Goals::TGoalVec & tasks, int priorityTier) const; - bool executeTask(const Goals::TTask & task); + bool executeTask(const Goals::TTask & task) const; bool areAffectedObjectsPresent(const Goals::TTask & task) const; HeroRole getTaskRole(const Goals::TTask & task) const; void tracePlayerStatus(bool beginning) const; diff --git a/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp index eb5f73fb1..70910e330 100644 --- a/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp @@ -1429,10 +1429,10 @@ void AINodeStorage::calculateChainInfo(std::vector & paths, const int3 & continue; } - if(HeroPtr heroPtr(node.actor->hero, aiNk->cc); !heroPtr.isVerified()) + if(HeroPtr heroPtr(node.actor->hero, aiNk->cc); !heroPtr.isVerified(false)) { #if NK2AI_TRACE_LEVEL >= 1 - logAi->warn("AINodeStorage::calculateChainInfo Skipping unverified hero: %s", heroPtr.nameOrDefault()); + logAi->warn("AINodeStorage::calculateChainInfo Skipping path due to unverified hero: %s", heroPtr.nameOrDefault()); #endif continue; } diff --git a/lib/callback/CGameInfoCallback.cpp b/lib/callback/CGameInfoCallback.cpp index afe80049c..be75d35dc 100644 --- a/lib/callback/CGameInfoCallback.cpp +++ b/lib/callback/CGameInfoCallback.cpp @@ -111,17 +111,16 @@ TurnTimerInfo CGameInfoCallback::getPlayerTurnTime(PlayerColor color) const /* */ /************************************************************************/ -const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const +const CGObjectInstance * CGameInfoCallback::getObj(const ObjectInstanceID objId, const bool verbose) const { - const CGObjectInstance * ret = MapInfoCallback::getObj(objid, verbose); - + const CGObjectInstance * ret = MapInfoCallback::getObj(objId, verbose); if(!ret) return nullptr; if(getPlayerID().has_value() && !isVisibleFor(ret, *getPlayerID()) && ret->tempOwner != getPlayerID()) { if(verbose) - logGlobal->error("Cannot get object with id %d. Object is not visible.", objid.getNum()); + logGlobal->error("Cannot get object with id %d. Object is not visible.", objId.getNum()); return nullptr; } diff --git a/lib/callback/CGameInfoCallback.h b/lib/callback/CGameInfoCallback.h index 27be083e3..5da24f8e3 100644 --- a/lib/callback/CGameInfoCallback.h +++ b/lib/callback/CGameInfoCallback.h @@ -61,7 +61,7 @@ public: const CArtifactSet * getArtSet(const ArtifactLocation & loc) const; //objects - const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override; + const CGObjectInstance * getObj(ObjectInstanceID objId, bool verbose = true) const override; std::vector getBlockingObjs(int3 pos) const; std::vector getVisitableObjs(int3 pos, bool verbose = true) const; std::vector getAllVisitableObjs() const; diff --git a/lib/callback/MapInfoCallback.cpp b/lib/callback/MapInfoCallback.cpp index 65eb71e2c..4cb784c1c 100644 --- a/lib/callback/MapInfoCallback.cpp +++ b/lib/callback/MapInfoCallback.cpp @@ -22,19 +22,19 @@ VCMI_LIB_NAMESPACE_BEGIN MapInfoCallback::~MapInfoCallback() = default; -const CGObjectInstance * MapInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const +const CGObjectInstance * MapInfoCallback::getObj(const ObjectInstanceID objId, const bool verbose) const { - if(!objid.hasValue()) + if(!objId.hasValue()) { if(verbose) - logGlobal->error("Cannot get object with id %d. No such object", objid.getNum()); + logGlobal->error("Cannot get object with id %d. No such object", objId.getNum()); return nullptr; } - const CGObjectInstance * ret = getMapConstPtr()->getObject(objid); + const CGObjectInstance * ret = getMapConstPtr()->getObject(objId); if(!ret && verbose) { - logGlobal->error("Cannot get object with id %d. Object was removed", objid.getNum()); + logGlobal->error("Cannot get object with id %d. Object was removed", objId.getNum()); return nullptr; } diff --git a/lib/callback/MapInfoCallback.h b/lib/callback/MapInfoCallback.h index 2f34e3d50..02f87fcc6 100644 --- a/lib/callback/MapInfoCallback.h +++ b/lib/callback/MapInfoCallback.h @@ -23,7 +23,7 @@ protected: public: virtual ~MapInfoCallback(); - const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override; + const CGObjectInstance * getObj(ObjectInstanceID objId, bool verbose = true) const override; const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const override; const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const override; const CGHeroInstance * getHero(ObjectInstanceID objid) const override;