From b8eb49bc827697a3527c1e470b87bf6f81cf0c84 Mon Sep 17 00:00:00 2001 From: Mircea TheHonestCTO Date: Fri, 12 Sep 2025 19:25:56 +0200 Subject: [PATCH] finished removing thread local from NK2 --- AI/Nullkiller2/AIGateway.cpp | 88 ++----------------- AI/Nullkiller2/AIGateway.h | 37 -------- AI/Nullkiller2/AIUtility.cpp | 48 ++-------- AI/Nullkiller2/AIUtility.h | 23 ++--- .../Analyzers/DangerHitMapAnalyzer.cpp | 36 +++++--- AI/Nullkiller2/Analyzers/HeroManager.cpp | 4 +- .../Analyzers/ObjectClusterizer.cpp | 1 - .../Behaviors/CaptureObjectsBehavior.cpp | 8 +- AI/Nullkiller2/Engine/Nullkiller.cpp | 7 +- AI/Nullkiller2/Engine/Nullkiller.h | 2 +- AI/Nullkiller2/Engine/ResourceTrader.cpp | 1 - AI/Nullkiller2/Goals/AdventureSpellCast.cpp | 2 +- AI/Nullkiller2/Goals/BuyArmy.cpp | 2 +- AI/Nullkiller2/Goals/CompleteQuest.cpp | 60 +++++++------ AI/Nullkiller2/Goals/CompleteQuest.h | 7 +- .../Goals/ExchangeSwapTownHeroes.cpp | 2 +- AI/Nullkiller2/Goals/ExecuteHeroChain.cpp | 4 +- AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp | 14 +-- AI/Nullkiller2/Helpers/ExplorationHelper.cpp | 6 +- AI/Nullkiller2/Pathfinding/AINodeStorage.cpp | 17 ++-- AI/Nullkiller2/Pathfinding/AINodeStorage.h | 2 +- AI/Nullkiller2/Pathfinding/AIPathfinder.cpp | 2 - .../Pathfinding/Actions/BattleAction.cpp | 2 +- .../Pathfinding/Actions/QuestAction.cpp | 4 +- AI/Nullkiller2/pforeach.h | 2 - 25 files changed, 117 insertions(+), 264 deletions(-) diff --git a/AI/Nullkiller2/AIGateway.cpp b/AI/Nullkiller2/AIGateway.cpp index 76789f45a..98548cff4 100644 --- a/AI/Nullkiller2/AIGateway.cpp +++ b/AI/Nullkiller2/AIGateway.cpp @@ -39,9 +39,6 @@ namespace NK2AI { -thread_local CCallback * ccTl = nullptr; -#define NET_EVENT_HANDLER SET_GLOBAL_STATE(this) - AIGateway::AIGateway() :status(this) { @@ -62,18 +59,14 @@ AIGateway::~AIGateway() void AIGateway::availableCreaturesChanged(const CGDwelling * town) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::heroMoved(const TryMoveHero & details, bool verbose) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; - - auto hero = cc->getHero(details.id); - + const auto hero = cc->getHero(details.id); if(!hero) - validateObject(ObjectIdRef(details.id)); //enemy hero may have left visible area + validateObject(ObjectIdRef(details.id, cc.get())); //enemy hero may have left visible area nullkiller->invalidatePathfinderData(); @@ -114,32 +107,26 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose) void AIGateway::heroInGarrisonChange(const CGTownInstance * town) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::centerView(int3 pos, int focusTime) { LOG_TRACE_PARAMS(logAi, "focusTime '%i'", focusTime); - NET_EVENT_HANDLER; } void AIGateway::artifactMoved(const ArtifactLocation & src, const ArtifactLocation & dst) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::artifactAssembled(const ArtifactLocation & al) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; - status.addQuery(queryID, "TavernWindow"); executeActionAsync("showTavernWindow", [this, queryID](){ answerQuery(queryID, 0); }); } @@ -147,13 +134,11 @@ void AIGateway::showTavernWindow(const CGObjectInstance * object, const CGHeroIn void AIGateway::showThievesGuildWindow(const CGObjectInstance * obj) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::playerBlocked(int reason, bool start) { LOG_TRACE_PARAMS(logAi, "reason '%i', start '%i'", reason % start); - NET_EVENT_HANDLER; if(start && reason == PlayerBlocked::UPCOMING_BATTLE) status.setBattle(UPCOMING_BATTLE); @@ -164,19 +149,16 @@ void AIGateway::playerBlocked(int reason, bool start) void AIGateway::showPuzzleMap() { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::showShipyardDialog(const IShipyard * obj) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) { LOG_TRACE_PARAMS(logAi, "victoryLossCheckResult '%s'", victoryLossCheckResult.messageToSelf.toString()); - NET_EVENT_HANDLER; logAi->debug("Player %d (%s): I heard that player %d (%s) %s.", playerID, playerID.toString(), player, player.toString(), (victoryLossCheckResult.victory() ? "won" : "lost")); // some whitespace to flush stream @@ -201,25 +183,21 @@ void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & vic void AIGateway::artifactPut(const ArtifactLocation & al) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::artifactRemoved(const ArtifactLocation & al) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::artifactDisassembled(const ArtifactLocation & al) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start) { LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->getObjectName() : std::string("n/a"))); - NET_EVENT_HANDLER; if(start && visitedObj) //we can end visit with null object, anyway { @@ -233,19 +211,16 @@ void AIGateway::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance void AIGateway::availableArtifactsChanged(const CGBlackMarket * bm) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::heroVisitsTown(const CGHeroInstance * hero, const CGTownInstance * town) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::tileHidden(const FowTilesType & pos) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; nullkiller->memory->removeInvisibleObjects(cc.get()); } @@ -253,7 +228,7 @@ void AIGateway::tileHidden(const FowTilesType & pos) void AIGateway::tileRevealed(const FowTilesType & pos) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; + for(int3 tile : pos) { for(const CGObjectInstance * obj : cc->getVisitableObjs(tile)) @@ -267,8 +242,6 @@ void AIGateway::tileRevealed(const FowTilesType & pos) void AIGateway::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; - auto firstHero = cc->getHero(hero1); auto secondHero = cc->getHero(hero2); @@ -303,20 +276,16 @@ void AIGateway::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID her void AIGateway::heroExperienceChanged(const CGHeroInstance * hero, si64 val) { LOG_TRACE_PARAMS(logAi, "val '%i'", val); - NET_EVENT_HANDLER; } void AIGateway::heroPrimarySkillChanged(const CGHeroInstance * hero, PrimarySkill which, si64 val) { LOG_TRACE_PARAMS(logAi, "which '%i', val '%i'", which.getNum() % val); - NET_EVENT_HANDLER; } void AIGateway::showRecruitmentDialog(const CGDwelling * dwelling, const CArmedInstance * dst, int level, QueryID queryID) { LOG_TRACE_PARAMS(logAi, "level '%i'", level); - NET_EVENT_HANDLER; - status.addQuery(queryID, "RecruitmentDialog"); executeActionAsync("showRecruitmentDialog", [this, dwelling, dst, queryID](){ @@ -328,19 +297,16 @@ void AIGateway::showRecruitmentDialog(const CGDwelling * dwelling, const CArmedI void AIGateway::heroMovePointsChanged(const CGHeroInstance * hero) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::newObject(const CGObjectInstance * obj) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; nullkiller->invalidatePathfinderData(); if(obj->isVisitable()) memorizeVisitableObj(obj, nullkiller->memory, nullkiller->dangerHitMap, playerID, cc); @@ -351,8 +317,6 @@ void AIGateway::newObject(const CGObjectInstance * obj) void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; - if(!nullkiller) // crash protection return; @@ -366,7 +330,7 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor & if(obj->ID == Obj::HERO && obj->tempOwner == playerID) { - lostHero(HeroPtr(cc->getHero(obj->id), cc)); //we can promote, since objectRemoved is called just before actual deletion + lostHero(HeroPtr(cc->getHero(obj->id), cc.get())); //we can promote, since objectRemoved is called just before actual deletion } if(obj->ID == Obj::HERO && cc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES) @@ -379,38 +343,32 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor & void AIGateway::showHillFortWindow(const CGObjectInstance * object, const CGHeroInstance * visitor) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::playerBonusChanged(const Bonus & bonus, bool gain) { LOG_TRACE_PARAMS(logAi, "gain '%i'", gain); - NET_EVENT_HANDLER; } void AIGateway::heroCreated(const CGHeroInstance * h) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; nullkiller->invalidatePathfinderData(); // new hero needs to look around } void AIGateway::advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) { LOG_TRACE_PARAMS(logAi, "spellID '%i", spellID); - NET_EVENT_HANDLER; } void AIGateway::showInfoDialog(EInfoWindowMode type, const std::string & text, const std::vector & components, int soundID) { LOG_TRACE_PARAMS(logAi, "soundID '%i'", soundID); - NET_EVENT_HANDLER; } void AIGateway::requestRealized(PackageApplied * pa) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; if(status.haveTurn()) { if(pa->packType == CTypeList::getInstance().getTypeID(nullptr)) @@ -429,13 +387,11 @@ void AIGateway::requestRealized(PackageApplied * pa) void AIGateway::receivedResource() { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; status.addQuery(queryID, "UniversityWindow"); executeActionAsync("showUniversityWindow", [this, queryID](){ answerQuery(queryID, 0); }); @@ -444,19 +400,16 @@ void AIGateway::showUniversityWindow(const IMarket * market, const CGHeroInstanc void AIGateway::heroManaPointsChanged(const CGHeroInstance * hero) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; } void AIGateway::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) { LOG_TRACE_PARAMS(logAi, "which '%d', val '%d'", which % val); - NET_EVENT_HANDLER; } void AIGateway::battleResultsApplied() { LOG_TRACE(logAi); - NET_EVENT_HANDLER; assert(status.getBattle() == ENDING_BATTLE); status.setBattle(NO_BATTLE); } @@ -470,7 +423,6 @@ void AIGateway::beforeObjectPropertyChanged(const SetObjectProperty * sop) void AIGateway::objectPropertyChanged(const SetObjectProperty * sop) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; if(sop->what == ObjProperty::OWNER) { auto relations = cc->getPlayerRelations(playerID, sop->identifier.as()); @@ -499,20 +451,16 @@ void AIGateway::objectPropertyChanged(const SetObjectProperty * sop) void AIGateway::buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) { LOG_TRACE_PARAMS(logAi, "what '%i'", what); - NET_EVENT_HANDLER; } void AIGateway::heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) { LOG_TRACE_PARAMS(logAi, "gain '%i'", gain); - NET_EVENT_HANDLER; } void AIGateway::showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; - status.addQuery(queryID, "MarketWindow"); executeActionAsync("showMarketWindow", [this, queryID](){ answerQuery(queryID, 0); }); } @@ -521,13 +469,11 @@ void AIGateway::showWorldViewEx(const std::vector & objectPositio { //TODO: AI support for ViewXXX spell LOG_TRACE(logAi); - NET_EVENT_HANDLER; } std::optional AIGateway::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { LOG_TRACE(logAi); - NET_EVENT_HANDLER; if(battleState.ourHero && battleState.ourHero->patrol.patrolling) { @@ -553,20 +499,16 @@ void AIGateway::initGameInterface(std::shared_ptr env, std::shared_ cbc = callback; cc = callback; this->env = env; - - NET_EVENT_HANDLER; playerID = *cc->getPlayerID(); cc->waitTillRealize = true; nullkiller->init(callback, this); - memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc); } void AIGateway::yourTurn(QueryID queryID) { LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID); - NET_EVENT_HANDLER; nullkiller->invalidatePathfinderData(); status.addQuery(queryID, "YourTurn"); executeActionAsync("yourTurn", [this, queryID](){ answerQuery(queryID, 0); }); @@ -584,10 +526,8 @@ void AIGateway::yourTurn(QueryID queryID) void AIGateway::heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, std::vector & skills, QueryID queryID) { LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID); - NET_EVENT_HANDLER; - status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->getNameTranslated() % hero->level)); - HeroPtr heroPtr(hero, cc); + HeroPtr heroPtr(hero, cc.get()); executeActionAsync("heroGotLevel", [this, heroPtr, skills, queryID]() { @@ -607,7 +547,6 @@ void AIGateway::heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, s void AIGateway::commanderGotLevel(const CCommanderInstance * commander, std::vector skills, QueryID queryID) { LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID); - NET_EVENT_HANDLER; status.addQuery(queryID, boost::str(boost::format("Commander %s of %s got level %d") % commander->name % commander->getArmy()->nodeName() % (int)commander->level)); executeActionAsync("commanderGotLevel", [this, queryID](){ answerQuery(queryID, 0); }); } @@ -615,7 +554,6 @@ void AIGateway::commanderGotLevel(const CCommanderInstance * commander, std::vec void AIGateway::showBlockingDialog(const std::string & text, const std::vector & components, QueryID askID, const int soundID, bool selection, bool cancel, bool safeToAutoaccept) { LOG_TRACE_PARAMS(logAi, "text '%s', askID '%i', soundID '%i', selection '%i', cancel '%i', autoaccept '%i'", text % askID % soundID % selection % cancel % safeToAutoaccept); - NET_EVENT_HANDLER; status.addQuery(askID, boost::str(boost::format("Blocking dialog query with %d components - %s") % components.size() % text)); @@ -699,7 +637,6 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vectornodeName(); std::string s2 = down->nodeName(); @@ -764,7 +699,6 @@ void AIGateway::showGarrisonDialog(const CArmedInstance * up, const CGHeroInstan void AIGateway::showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector & objects) { - NET_EVENT_HANDLER; status.addQuery(askID, "Map object select query"); executeActionAsync("showMapObjectSelectDialog", [this, askID](){ answerQuery(askID, selectedObject.getNum()); }); } @@ -816,13 +750,10 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj) void AIGateway::makeTurn() { - SET_GLOBAL_STATE(this); - auto day = cc->getDate(Date::DAY); logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day); std::shared_lock gsLock(CGameState::mutex); - cheatMapReveal(nullkiller); memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc); memorizeRevisitableObjs(nullkiller->memory, playerID, cc); @@ -1039,7 +970,6 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) { - NET_EVENT_HANDLER; assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); status.setBattle(ONGOING_BATTLE); const CGObjectInstance * presumedEnemy = vstd::backOrNull(cc->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit @@ -1049,7 +979,6 @@ void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army void AIGateway::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) { - NET_EVENT_HANDLER; assert(status.getBattle() == ONGOING_BATTLE); status.setBattle(ENDING_BATTLE); bool won = br->winner == cc->getBattle(battleID)->battleGetMySide(); @@ -1424,10 +1353,9 @@ void AIGateway::executeActionAsync(const std::string & description, const std::f if (!asyncTasks) throw std::runtime_error("Attempt to execute task on shut down AI state!"); - asyncTasks->run([this, description, whatToDo]() + asyncTasks->run([description, whatToDo]() { ScopedThreadName guard("NK2AI::AIGateway::" + description); - SET_GLOBAL_STATE(this); std::shared_lock gsLock(CGameState::mutex); whatToDo(); }); @@ -1472,7 +1400,7 @@ std::string AIGateway::getBattleAIName() const void AIGateway::validateObject(const CGObjectInstance * obj) { - validateObject(ObjectIdRef(obj->id)); + validateObject(ObjectIdRef(obj->id, cc.get())); } void AIGateway::validateObject(ObjectIdRef obj) @@ -1669,7 +1597,7 @@ void AIGateway::memorizeVisitableObjs(const std::unique_ptr & memory, const PlayerColor & playerID, const std::shared_ptr & cc) { - foreach_tile_pos([&](const int3 & pos) + foreach_tile_pos(*cc, [&](const int3 & pos) { // TODO: Inspect what not visible means when using verbose true for(const CGObjectInstance * obj : cc->getVisitableObjs(pos, false)) diff --git a/AI/Nullkiller2/AIGateway.h b/AI/Nullkiller2/AIGateway.h index 99cb67a36..b4091c0aa 100644 --- a/AI/Nullkiller2/AIGateway.h +++ b/AI/Nullkiller2/AIGateway.h @@ -28,43 +28,6 @@ VCMI_LIB_NAMESPACE_END namespace NK2AI { -extern thread_local CCallback * ccTl; - -// helper RAII to manage global ai/cb ptrs -struct SetGlobalState -{ - CCallback * previousCc; - bool wasAlreadySet; - - SetGlobalState(AIGateway * aiGw, CCallback * cc) - : previousCc(ccTl), wasAlreadySet(ccTl != nullptr) - { - ccTl = cc; -// #if NK2AI_TRACE_LEVEL >= 2 -// if(wasAlreadySet) -// { -// logAi->trace("SetGlobalState constructed (was already set)"); -// } -// else -// { -// logAi->trace("SetGlobalState constructed"); -// } -// #endif - } - - ~SetGlobalState() - { - // Restore previous values instead of always setting to nullptr - ccTl = previousCc; -// #if NK2AI_TRACE_LEVEL >= 2 -// logAi->trace("SetGlobalState destroyed"); -// #endif - } -}; - -#define SET_GLOBAL_STATE(aiGw) SetGlobalState _hlpSetState(aiGw, aiGw->cc.get()) -#define SET_GLOBAL_STATE_TBB(aiGw) SET_GLOBAL_STATE(aiGw) - class AIStatus { AIGateway * aiGw; diff --git a/AI/Nullkiller2/AIUtility.cpp b/AI/Nullkiller2/AIUtility.cpp index 0c5adad58..85c101db0 100644 --- a/AI/Nullkiller2/AIUtility.cpp +++ b/AI/Nullkiller2/AIUtility.cpp @@ -30,38 +30,27 @@ namespace NK2AI const CGObjectInstance * ObjectIdRef::operator->() const { - return ccTl->getObj(id, false); + return cpsic->getObj(id, false); } ObjectIdRef::operator const CGObjectInstance *() const { - return ccTl->getObj(id, false); + return cpsic->getObj(id, false); } ObjectIdRef::operator bool() const { - return ccTl->getObj(id, false); + return cpsic->getObj(id, false); } -ObjectIdRef::ObjectIdRef(ObjectInstanceID _id) - : id(_id) -{ -} - -ObjectIdRef::ObjectIdRef(const CGObjectInstance * obj) - : id(obj->id) -{ -} +ObjectIdRef::ObjectIdRef(ObjectInstanceID id, const CPlayerSpecificInfoCallback * cpsic) : id(id), cpsic(cpsic) {} bool ObjectIdRef::operator<(const ObjectIdRef & rhs) const { return id < rhs.id; } -HeroPtr::HeroPtr(const CGHeroInstance * input, std::shared_ptr cpsic) - : hero(input), cpsic(cpsic) -{ -} +HeroPtr::HeroPtr(const CGHeroInstance * input, const CPlayerSpecificInfoCallback * cpsic) : hero(input), cpsic(cpsic) {} bool HeroPtr::operator<(const HeroPtr & rhs) const { @@ -181,22 +170,6 @@ bool isObjectRemovable(const CGObjectInstance * obj) } } -bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater) -{ - // TODO: Such information should be provided by pathfinder - // Tile must be free or with unoccupied boat - if(!t->blocked()) - { - return true; - } - else if(!fromWater) // do not try to board when in water sector - { - if(t->visitableObjects.size() == 1 && ccTl->getObjInstance(t->topVisitableObj())->ID == Obj::BOAT) - return true; - } - return false; -} - bool isObjectPassable(const Nullkiller * aiNk, const CGObjectInstance * obj) { return isObjectPassable(obj, aiNk->playerID, aiNk->cc->getPlayerRelations(obj->tempOwner, aiNk->playerID)); @@ -220,17 +193,6 @@ bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, Pla return false; } -bool isBlockVisitObj(const int3 & pos) -{ - if(auto obj = ccTl->getTopObj(pos)) - { - if(obj->isBlockedVisitable()) //we can't stand on that object - return true; - } - - return false; -} - creInfo infoFromDC(const dwellingContent & dc) { creInfo ci; diff --git a/AI/Nullkiller2/AIUtility.h b/AI/Nullkiller2/AIUtility.h index ebd1ab550..2eb2c731a 100644 --- a/AI/Nullkiller2/AIUtility.h +++ b/AI/Nullkiller2/AIUtility.h @@ -62,8 +62,6 @@ const int WOOD_ORE_MINE_PRODUCTION = 2; const int RESOURCE_MINE_PRODUCTION = 1; const int ACTUAL_RESOURCE_COUNT = 7; -extern thread_local CCallback * ccTl; - enum HeroRole { SCOUT = 0, @@ -78,11 +76,11 @@ struct DLL_EXPORT HeroPtr { private: const CGHeroInstance * hero; - std::shared_ptr cpsic; + const CPlayerSpecificInfoCallback * cpsic; bool verify(bool verbose = true) const; public: - explicit HeroPtr(const CGHeroInstance * input, std::shared_ptr cpsic); + explicit HeroPtr(const CGHeroInstance * input, const CPlayerSpecificInfoCallback * cpsic); bool operator<(const HeroPtr & rhs) const; const CGHeroInstance * operator->() const; @@ -112,10 +110,10 @@ enum BattleState // This class stores object id, so we can detect when we lose access to the underlying object. struct ObjectIdRef { - ObjectInstanceID id; + const ObjectInstanceID id; + const CPlayerSpecificInfoCallback * cpsic; - explicit ObjectIdRef(ObjectInstanceID _id); - explicit ObjectIdRef(const CGObjectInstance * obj); + explicit ObjectIdRef(ObjectInstanceID id, const CPlayerSpecificInfoCallback * cpsic); const CGObjectInstance * operator->() const; operator const CGObjectInstance *() const; @@ -138,11 +136,11 @@ struct creInfo creInfo infoFromDC(const dwellingContent & dc); template -void foreach_tile_pos(const Func & foo) +void foreach_tile_pos(const CCallback & cc, const Func & foo) { // some micro-optimizations since this function gets called a LOT // callback pointer is thread-specific and slow to retrieve -> read map size only once - int3 mapSize = ccTl->getMapSize(); + int3 mapSize = cc.getMapSize(); for(int z = 0; z < mapSize.z; z++) { for(int x = 0; x < mapSize.x; x++) @@ -172,13 +170,12 @@ void foreach_tile_pos(TCallback * cbp, const Func & foo) // avoid costly retriev } template -void foreach_neighbour(const int3 & pos, const Func & foo) +void foreach_neighbour(const CCallback & cc, const int3 & pos, const Func & foo) { - CCallback * cbp = ccTl; // avoid costly retrieval of thread-specific pointer for(const int3 & dir : int3::getDirs()) { const int3 n = pos + dir; - if(cbp->isInTheMap(n)) + if(cc.isInTheMap(n)) foo(pos + dir); } } @@ -194,10 +191,8 @@ void foreach_neighbour(CCallback * cbp, const int3 & pos, const Func & foo) // a } } -bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater); bool isObjectPassable(const Nullkiller * aiNk, const CGObjectInstance * obj); bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, PlayerRelations objectRelations); -bool isBlockVisitObj(const int3 & pos); bool isWeeklyRevisitable(const PlayerColor & playerID, const CGObjectInstance * obj); diff --git a/AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.cpp b/AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.cpp index ac97b1ad1..e21b58fa3 100644 --- a/AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.cpp +++ b/AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.cpp @@ -20,12 +20,16 @@ namespace NK2AI const HitMapInfo HitMapInfo::NoThreat; -void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data) +void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data, const CCallback & cc) { #if NK2AI_TRACE_LEVEL >= 1 - logVisual->updateWithLock(playerID.toString() + ".danger.max", [&data](IVisualLogBuilder & b) + logVisual->updateWithLock( + playerID.toString() + ".danger.max", + [&data, &cc](IVisualLogBuilder & b) { - foreach_tile_pos([&b, &data](const int3 & pos) + foreach_tile_pos( + cc, + [&b, &data](const int3 & pos) { auto & threat = data.getTileThreat(pos).maximumDanger; b.addText(pos, std::to_string(threat.danger)); @@ -35,12 +39,18 @@ void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data) b.addText(pos, std::to_string(threat.turn)); b.addText(pos, threat.heroPtr->getNameTranslated()); } - }); - }); + } + ); + } + ); - logVisual->updateWithLock(playerID.toString() + ".danger.fast", [&data](IVisualLogBuilder & b) + logVisual->updateWithLock( + playerID.toString() + ".danger.fast", + [&data, &cc](IVisualLogBuilder & b) { - foreach_tile_pos([&b, &data](const int3 & pos) + foreach_tile_pos( + cc, + [&b, &data](const int3 & pos) { auto & threat = data.getTileThreat(pos).fastestDanger; b.addText(pos, std::to_string(threat.danger)); @@ -50,8 +60,10 @@ void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data) b.addText(pos, std::to_string(threat.turn)); b.addText(pos, threat.heroPtr->getNameTranslated()); } - }); - }); + } + ); + } + ); #endif } @@ -100,7 +112,7 @@ void DangerHitMapAnalyzer::updateHitMap() townThreats[town->id]; // insert empty list } - foreach_tile_pos([&](const int3 & pos){ + foreach_tile_pos(*aiNk->cc, [&](const int3 & pos){ hitMap[pos.x][pos.y][pos.z].reset(); }); @@ -132,7 +144,7 @@ void DangerHitMapAnalyzer::updateHitMap() HitMapInfo newThreat; - newThreat.heroPtr = HeroPtr(path.targetHero, aiNk->cc); + newThreat.heroPtr = HeroPtr(path.targetHero, aiNk->cc.get()); newThreat.turn = path.turn(); newThreat.threat = path.getHeroStrength() * (1 - path.movementCost() / 2.0); // TODO: Mircea: Why is this danger calculated so differently than FuzzyHelper::evaluateDanger? @@ -189,7 +201,7 @@ void DangerHitMapAnalyzer::updateHitMap() logAi->trace("Danger hit map updated in %ld", timeElapsed(start)); - logHitmap(aiNk->playerID, *this); + logHitmap(aiNk->playerID, *this, *aiNk->cc); } void DangerHitMapAnalyzer::calculateTileOwners() diff --git a/AI/Nullkiller2/Analyzers/HeroManager.cpp b/AI/Nullkiller2/Analyzers/HeroManager.cpp index f459c7cf0..8935d1de9 100644 --- a/AI/Nullkiller2/Analyzers/HeroManager.cpp +++ b/AI/Nullkiller2/Analyzers/HeroManager.cpp @@ -133,7 +133,7 @@ void HeroManager::update() for(const auto hero : myHeroes) { - HeroPtr heroPtr(hero, aiNk->cc); + HeroPtr heroPtr(hero, aiNk->cc.get()); HeroRole role; if(hero->patrol.patrolling) { @@ -151,7 +151,7 @@ void HeroManager::update() HeroRole HeroManager::getHeroRoleOrDefaultInefficient(const CGHeroInstance * hero) const { - return getHeroRoleOrDefault(HeroPtr(hero, aiNk->cc)); + return getHeroRoleOrDefault(HeroPtr(hero, aiNk->cc.get())); } // TODO: Mircea: Do we need this map on HeroPtr or is enough just on hero? diff --git a/AI/Nullkiller2/Analyzers/ObjectClusterizer.cpp b/AI/Nullkiller2/Analyzers/ObjectClusterizer.cpp index 4a903d572..b666be1e6 100644 --- a/AI/Nullkiller2/Analyzers/ObjectClusterizer.cpp +++ b/AI/Nullkiller2/Analyzers/ObjectClusterizer.cpp @@ -332,7 +332,6 @@ void ObjectClusterizer::clusterize() tbb::blocked_range(0, objs.size()), [&](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); auto priorityEvaluator = aiNk->priorityEvaluators->acquire(); auto heroes = aiNk->cc->getHeroesInfo(); std::vector pathCache; diff --git a/AI/Nullkiller2/Behaviors/CaptureObjectsBehavior.cpp b/AI/Nullkiller2/Behaviors/CaptureObjectsBehavior.cpp index 8b4898944..f74ef9866 100644 --- a/AI/Nullkiller2/Behaviors/CaptureObjectsBehavior.cpp +++ b/AI/Nullkiller2/Behaviors/CaptureObjectsBehavior.cpp @@ -60,7 +60,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals( std::unordered_map closestWaysByRole; std::vector waysToVisitObj; - for(auto & path : paths) + for(const auto & path : paths) { tasks.push_back(sptr(Goals::Invalid())); @@ -76,9 +76,8 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals( continue; } - auto hero = path.targetHero; - auto danger = path.getTotalDanger(); - + const auto * hero = path.targetHero; + const auto danger = path.getTotalDanger(); if (hero->getOwner() != nullkiller->playerID) continue; @@ -177,7 +176,6 @@ void CaptureObjectsBehavior::decomposeObjects( tbb::blocked_range(0, objs.size()), [this, &objs, &sync, &result, nullkiller](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(nullkiller->aiGw); std::vector paths; Goals::TGoalVec tasksLocal; diff --git a/AI/Nullkiller2/Engine/Nullkiller.cpp b/AI/Nullkiller2/Engine/Nullkiller.cpp index f96a92b7b..b80d14c28 100644 --- a/AI/Nullkiller2/Engine/Nullkiller.cpp +++ b/AI/Nullkiller2/Engine/Nullkiller.cpp @@ -191,7 +191,6 @@ Goals::TTaskVec Nullkiller::buildPlan(TGoalVec & tasks, int priorityTier) const tbb::parallel_for(tbb::blocked_range(0, tasks.size()), [this, &tasks, priorityTier](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(this->aiGw); auto evaluator = this->priorityEvaluators->acquire(); for(size_t i = r.begin(); i != r.end(); i++) @@ -464,7 +463,7 @@ void Nullkiller::makeTurn() logAi->info("Pass %d: Performing task (prioOfTask %d) %s with prio: %d", i, prioOfTask, selectedTask->toString(), selectedTask->priority); - if(HeroPtr heroPtr(selectedTask->getHero(), cc); selectedTask->getHero() && !heroPtr.isVerified(false)) + if(HeroPtr heroPtr(selectedTask->getHero(), cc.get()); selectedTask->getHero() && !heroPtr.isVerified(false)) { logAi->error("Nullkiller::makeTurn Skipping pass due to unverified hero: %s", heroPtr.nameOrDefault()); } @@ -516,7 +515,7 @@ bool Nullkiller::updateStateAndExecutePriorityPass(Goals::TGoalVec & tempResults logAi->info("Pass %d: priorityPass %d: Performing task %s with prio: %d", passIndex, i, bestPrioPassTask->toString(), bestPrioPassTask->priority); const bool isRecruitHeroGoal = dynamic_cast(bestPrioPassTask.get()) != nullptr; - HeroPtr heroPtr(bestPrioPassTask->getHero(), cc); + HeroPtr heroPtr(bestPrioPassTask->getHero(), cc.get()); if(!isRecruitHeroGoal && bestPrioPassTask->getHero() && !heroPtr.isVerified(false)) { logAi->error("Nullkiller::updateStateAndExecutePriorityPass Skipping priorityPass due to unverified hero: %s", heroPtr.nameOrDefault()); @@ -557,7 +556,7 @@ bool Nullkiller::areAffectedObjectsPresent(const Goals::TTask & task) const HeroRole Nullkiller::getTaskRole(const Goals::TTask & task) const { - HeroPtr heroPtr(task->getHero(), cc); + HeroPtr heroPtr(task->getHero(), cc.get()); HeroRole heroRole = HeroRole::MAIN; if(heroPtr.isVerified()) diff --git a/AI/Nullkiller2/Engine/Nullkiller.h b/AI/Nullkiller2/Engine/Nullkiller.h index 2b5c7b62b..7905e115b 100644 --- a/AI/Nullkiller2/Engine/Nullkiller.h +++ b/AI/Nullkiller2/Engine/Nullkiller.h @@ -120,7 +120,7 @@ public: bool updateStateAndExecutePriorityPass(Goals::TGoalVec& tempResults, int passIndex); bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; } bool isHeroLocked(const CGHeroInstance * hero) const; - HeroPtr getActiveHero() { return HeroPtr(activeHero, cc); } + HeroPtr getActiveHero() { return HeroPtr(activeHero, cc.get()); } HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const; int3 getTargetTile() const { return targetTile; } ObjectInstanceID getTargetObject() const { return targetObject; } diff --git a/AI/Nullkiller2/Engine/ResourceTrader.cpp b/AI/Nullkiller2/Engine/ResourceTrader.cpp index 0f0ff50c0..4ae4d709c 100644 --- a/AI/Nullkiller2/Engine/ResourceTrader.cpp +++ b/AI/Nullkiller2/Engine/ResourceTrader.cpp @@ -151,7 +151,6 @@ bool ResourceTrader::tradeHelper( int givenPerUnit; int receivedPerUnit; market.getOffer(mostExpendable, mostWanted, givenPerUnit, receivedPerUnit, EMarketMode::RESOURCE_RESOURCE); - logAi->info("ResourceTrader: Offer: %d of %d for %d of %d", givenPerUnit, mostExpendable, receivedPerUnit, mostWanted); if(!givenPerUnit || !receivedPerUnit) { diff --git a/AI/Nullkiller2/Goals/AdventureSpellCast.cpp b/AI/Nullkiller2/Goals/AdventureSpellCast.cpp index 4bc5743ee..dcad2ea9c 100644 --- a/AI/Nullkiller2/Goals/AdventureSpellCast.cpp +++ b/AI/Nullkiller2/Goals/AdventureSpellCast.cpp @@ -66,7 +66,7 @@ void AdventureSpellCast::accept(AIGateway * aiGw) if(town && townPortalEffect) { // visit town - aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(hero, aiGw->cc)); + aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(hero, aiGw->cc.get())); } aiGw->cc->waitTillRealize = wait; diff --git a/AI/Nullkiller2/Goals/BuyArmy.cpp b/AI/Nullkiller2/Goals/BuyArmy.cpp index adbef9aa2..a9346478b 100644 --- a/AI/Nullkiller2/Goals/BuyArmy.cpp +++ b/AI/Nullkiller2/Goals/BuyArmy.cpp @@ -99,7 +99,7 @@ void BuyArmy::accept(AIGateway * aiGw) if(town->getVisitingHero() && !town->getGarrisonHero()) { - aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(town->getVisitingHero(), aiGw->cc)); + aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(town->getVisitingHero(), aiGw->cc.get())); } } diff --git a/AI/Nullkiller2/Goals/CompleteQuest.cpp b/AI/Nullkiller2/Goals/CompleteQuest.cpp index 95a825e1f..7cb3737bf 100644 --- a/AI/Nullkiller2/Goals/CompleteQuest.cpp +++ b/AI/Nullkiller2/Goals/CompleteQuest.cpp @@ -8,21 +8,21 @@ * */ #include "StdInc.h" -#include "CompleteQuest.h" -#include "../Behaviors/CaptureObjectsBehavior.h" -#include "../AIGateway.h" #include "../../../lib/GameLibrary.h" #include "../../../lib/mapObjects/CQuest.h" #include "../../../lib/texts/CGeneralTextHandler.h" +#include "../AIGateway.h" +#include "../Behaviors/CaptureObjectsBehavior.h" +#include "CompleteQuest.h" namespace NK2AI { using namespace Goals; -bool isKeyMaster(const QuestInfo & q) +bool isKeyMaster(const QuestInfo & q, CCallback & cc) { - const auto object = q.getObject(ccTl); + const auto * const object = q.getObject(&cc); return object && (object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD); } @@ -33,7 +33,7 @@ std::string CompleteQuest::toString() const TGoalVec CompleteQuest::decompose(const Nullkiller * aiNk) const { - if(isKeyMaster(q)) + if(isKeyMaster(q, *aiNk->cc)) { return missionKeymaster(aiNk); } @@ -68,40 +68,40 @@ TGoalVec CompleteQuest::decompose(const Nullkiller * aiNk) const bool CompleteQuest::operator==(const CompleteQuest & other) const { - if(isKeyMaster(q)) + if(isKeyMaster(q, cc)) { - return isKeyMaster(other.q) && q.getObject(ccTl)->subID == other.q.getObject(ccTl)->subID; + return isKeyMaster(other.q, cc) && q.getObject(&cc)->subID == other.q.getObject(&cc)->subID; } - else if(isKeyMaster(other.q)) + else if(isKeyMaster(other.q, cc)) { return false; } - return q.getQuest(ccTl) == other.q.getQuest(ccTl); + return q.getQuest(&cc) == other.q.getQuest(&cc); } uint64_t CompleteQuest::getHash() const { - if(isKeyMaster(q)) + if(isKeyMaster(q, cc)) { - return q.getObject(ccTl)->subID; + return q.getObject(&cc)->subID; } - return q.getObject(ccTl)->id.getNum(); + return q.getObject(&cc)->id.getNum(); } std::string CompleteQuest::questToString() const { - if(isKeyMaster(q)) + if(isKeyMaster(q, cc)) { - return "find " + LIBRARY->generaltexth->tentColors[q.getObject(ccTl)->subID] + " keymaster tent"; + return "find " + LIBRARY->generaltexth->tentColors[q.getObject(&cc)->subID] + " keymaster tent"; } - if(q.getQuest(ccTl)->questName == CQuest::missionName(EQuestMission::NONE)) + if(q.getQuest(&cc)->questName == CQuest::missionName(EQuestMission::NONE)) return "inactive quest"; MetaString ms; - q.getQuest(ccTl)->getRolloverText(ccTl, ms, false); + q.getQuest(&cc)->getRolloverText(&cc, ms, false); return ms.toString(); } @@ -110,11 +110,14 @@ TGoalVec CompleteQuest::tryCompleteQuest(const Nullkiller * aiNk) const { auto paths = aiNk->pathfinder->getPathInfo(q.getObject(aiNk->cc.get())->visitablePos()); - vstd::erase_if(paths, [&](const AIPath & path) -> bool - { - return !q.getQuest(aiNk->cc.get())->checkQuest(path.targetHero); - }); - + vstd::erase_if( + paths, + [&](const AIPath & path) -> bool + { + return !q.getQuest(aiNk->cc.get())->checkQuest(path.targetHero); + } + ); + return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(aiNk->cc.get())); } @@ -152,10 +155,13 @@ TGoalVec CompleteQuest::missionArmy(const Nullkiller * aiNk) const { auto paths = aiNk->pathfinder->getPathInfo(q.getObject(aiNk->cc.get())->visitablePos()); - vstd::erase_if(paths, [&](const AIPath & path) -> bool - { - return !CQuest::checkMissionArmy(q.getQuest(aiNk->cc.get()), path.heroArmy); - }); + vstd::erase_if( + paths, + [&](const AIPath & path) -> bool + { + return !CQuest::checkMissionArmy(q.getQuest(aiNk->cc.get()), path.heroArmy); + } + ); return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(aiNk->cc.get())); } @@ -202,7 +208,7 @@ TGoalVec CompleteQuest::missionDestroyObj(const Nullkiller * aiNk) const // //solutions.push_back(sptr(GatherArmy().sethero(heroToProtect))); //} - //else + //else if(relations == PlayerRelations::ENEMIES) { return CaptureObjectsBehavior(obj).decompose(aiNk); diff --git a/AI/Nullkiller2/Goals/CompleteQuest.h b/AI/Nullkiller2/Goals/CompleteQuest.h index 90c04d068..c72244415 100644 --- a/AI/Nullkiller2/Goals/CompleteQuest.h +++ b/AI/Nullkiller2/Goals/CompleteQuest.h @@ -19,14 +19,11 @@ namespace Goals { class CompleteQuest : public CGoal { - private: QuestInfo q; + CCallback & cc; public: - CompleteQuest(const QuestInfo & quest) - :CGoal(COMPLETE_QUEST), q(quest) - { - } + CompleteQuest(const QuestInfo & quest, CCallback & cc) : CGoal(COMPLETE_QUEST), q(quest), cc(cc) {} Goals::TGoalVec decompose(const Nullkiller * aiNk) const override; std::string toString() const override; diff --git a/AI/Nullkiller2/Goals/ExchangeSwapTownHeroes.cpp b/AI/Nullkiller2/Goals/ExchangeSwapTownHeroes.cpp index bf5e866e9..70c0fee89 100644 --- a/AI/Nullkiller2/Goals/ExchangeSwapTownHeroes.cpp +++ b/AI/Nullkiller2/Goals/ExchangeSwapTownHeroes.cpp @@ -84,7 +84,7 @@ void ExchangeSwapTownHeroes::accept(AIGateway * aiGw) aiGw->cc->swapGarrisonHero(town); aiGw->makePossibleUpgrades(town); - aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(getGarrisonHero(), aiGw->cc)); + aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(getGarrisonHero(), aiGw->cc.get())); auto upperArmy = town->getUpperArmy(); diff --git a/AI/Nullkiller2/Goals/ExecuteHeroChain.cpp b/AI/Nullkiller2/Goals/ExecuteHeroChain.cpp index 62e994fd9..cb04bc227 100644 --- a/AI/Nullkiller2/Goals/ExecuteHeroChain.cpp +++ b/AI/Nullkiller2/Goals/ExecuteHeroChain.cpp @@ -109,7 +109,7 @@ void ExecuteHeroChain::accept(AIGateway * aiGw) auto * node = &chainPath.nodes[i]; const CGHeroInstance * hero = node->targetHero; - HeroPtr heroPtr(hero, aiGw->cc); + HeroPtr heroPtr(hero, aiGw->cc.get()); if(!heroPtr.isVerified()) { @@ -303,7 +303,7 @@ bool ExecuteHeroChain::moveHeroToTile(AIGateway * aiGw, const CGHeroInstance * h return true; } - return aiGw->moveHeroToTile(tile, HeroPtr(hero, aiGw->cc)); + return aiGw->moveHeroToTile(tile, HeroPtr(hero, aiGw->cc.get())); } } diff --git a/AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp b/AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp index 1def04fc4..355fd735b 100644 --- a/AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp +++ b/AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp @@ -33,17 +33,18 @@ void ExploreNeighbourTile::accept(AIGateway * aiGw) int3 pos = hero->visitablePos(); float value = 0; int3 target = int3(-1); - foreach_neighbour(pos, [&](int3 tile) + foreach_neighbour( + *aiGw->cc, + pos, + [&](int3 tile) { - auto pathInfo = aiGw->nullkiller->getPathsInfo(hero)->getPathInfo(tile); - + const auto pathInfo = aiGw->nullkiller->getPathsInfo(hero)->getPathInfo(tile); if(pathInfo->turns > 0) return; if(pathInfo->accessible == EPathAccessibility::ACCESSIBLE) { float newValue = h.howManyTilesWillBeDiscovered(tile); - newValue /= std::min(0.1f, pathInfo->getCost()); if(newValue > value) @@ -52,7 +53,8 @@ void ExploreNeighbourTile::accept(AIGateway * aiGw) target = tile; } } - }); + } + ); if(!target.isValid()) { @@ -61,7 +63,7 @@ void ExploreNeighbourTile::accept(AIGateway * aiGw) auto danger = aiGw->nullkiller->dangerEvaluator->evaluateDanger(target, hero, true); - if(danger > 0 || !aiGw->moveHeroToTile(target, HeroPtr(hero, aiGw->cc))) + if(danger > 0 || !aiGw->moveHeroToTile(target, HeroPtr(hero, aiGw->cc.get()))) { return; } diff --git a/AI/Nullkiller2/Helpers/ExplorationHelper.cpp b/AI/Nullkiller2/Helpers/ExplorationHelper.cpp index 91141f91c..f904a3f32 100644 --- a/AI/Nullkiller2/Helpers/ExplorationHelper.cpp +++ b/AI/Nullkiller2/Helpers/ExplorationHelper.cpp @@ -73,7 +73,7 @@ bool ExplorationHelper::scanMap() std::vector edgeTiles; edgeTiles.reserve(perimeter); - foreach_tile_pos([&](const int3 & pos) + foreach_tile_pos(*aiNk->cc, [&](const int3 & pos) { if(ts->fogOfWarMap[pos.z][pos.x][pos.y]) { @@ -144,7 +144,7 @@ void ExplorationHelper::scanTile(const int3 & tile) { if(tile == ourPos || !aiNk->cc->getTile(tile, false) - || !aiNk->pathfinder->isTileAccessible(HeroPtr(hero, aiNk->cc), tile)) //shouldn't happen, but it does + || !aiNk->pathfinder->isTileAccessible(HeroPtr(hero, aiNk->cc.get()), tile)) //shouldn't happen, but it does return; int tilesDiscovered = howManyTilesWillBeDiscovered(tile); @@ -224,7 +224,7 @@ bool ExplorationHelper::hasReachableNeighbor(const int3 & pos) const { auto isAccessible = useCPathfinderAccessibility ? aiNk->getPathsInfo(hero)->getPathInfo(tile)->reachable() - : aiNk->pathfinder->isTileAccessible(HeroPtr(hero, aiNk->cc), tile); + : aiNk->pathfinder->isTileAccessible(HeroPtr(hero, aiNk->cc.get()), tile); if(isAccessible) return true; diff --git a/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp b/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp index b58acd6d1..4ebbbdf97 100644 --- a/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp +++ b/AI/Nullkiller2/Pathfinding/AINodeStorage.cpp @@ -41,7 +41,7 @@ const uint64_t CHAIN_MAX_DEPTH = 4; const bool DO_NOT_SAVE_TO_COMMITTED_TILES = false; -AISharedStorage::AISharedStorage(int3 sizes, int numChains) +AISharedStorage::AISharedStorage(int3 sizes, int numChains, const CCallback & cc) { if(!shared) { @@ -49,6 +49,7 @@ AISharedStorage::AISharedStorage(int3 sizes, int numChains) nodes = shared; foreach_tile_pos( + cc, [&](const int3 & pos) { for(auto i = 0; i < numChains; i++) @@ -104,8 +105,8 @@ int AINodeStorage::getBucketSize() const return aiNk->settings->getPathfinderBucketSize(); } -AINodeStorage::AINodeStorage(Nullkiller * aiNk, const int3 & Sizes) - : sizes(Sizes), aiNk(aiNk), nodes(Sizes, aiNk->settings->getPathfinderBucketSize() * aiNk->settings->getPathfinderBucketsCount()) +AINodeStorage::AINodeStorage(Nullkiller * aiNk, const int3 & sizes) + : sizes(sizes), aiNk(aiNk), nodes(sizes, aiNk->settings->getPathfinderBucketSize() * aiNk->settings->getPathfinderBucketsCount(), *aiNk->cc) { accessibility = std::make_unique>( boost::extents[sizes.z][sizes.x][sizes.y][EPathfindingLayer::NUM_LAYERS]); @@ -129,7 +130,6 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const IGameInf tbb::parallel_for(tbb::blocked_range(0, sizes.x), [&](const tbb::blocked_range& r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); int3 pos; for(pos.z = 0; pos.z < sizes.z; ++pos.z) @@ -430,7 +430,7 @@ bool AINodeStorage::increaseHeroChainTurnLimit() for(auto layer : phisycalLayers) { - foreach_tile_pos([&](const int3 & pos) + foreach_tile_pos(*aiNk->cc, [&](const int3 & pos) { iterateValidNodesUntil(pos, layer, [&](AIPathNode & node) { @@ -455,7 +455,7 @@ bool AINodeStorage::calculateHeroChainFinal() for(auto layer : phisycalLayers) { - foreach_tile_pos([&](const int3 & pos) + foreach_tile_pos(*aiNk->cc, [&](const int3 & pos) { iterateValidNodes(pos, layer, [&](AIPathNode & node) { @@ -603,9 +603,7 @@ bool AINodeStorage::calculateHeroChain() tbb::parallel_for(tbb::blocked_range(0, data.size()), [&](const tbb::blocked_range& r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); HeroChainCalculationTask task(*this, data, chainMask, heroChainTurn); - int ourThread = tbb::this_task_arena::current_thread_index(); task.execute(r); task.flushResult(results.at(ourThread)); @@ -1276,7 +1274,6 @@ void AINodeStorage::calculateTownPortalTeleportations(std::vector { tbb::parallel_for(tbb::blocked_range(0, actorsVector.size()), [&](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); for(int i = r.begin(); i != r.end(); i++) { calculateTownPortal(actorsVector[i], maskMap, initialNodes, output); @@ -1447,7 +1444,7 @@ void AINodeStorage::calculateChainInfo(std::vector & paths, const int3 & continue; } - if(HeroPtr heroPtr(node.actor->hero, aiNk->cc); !heroPtr.isVerified(false)) + if(HeroPtr heroPtr(node.actor->hero, aiNk->cc.get()); !heroPtr.isVerified(false)) { #if NK2AI_TRACE_LEVEL >= 1 logAi->warn("AINodeStorage::calculateChainInfo Skipping path due to unverified hero: %s", heroPtr.nameOrDefault()); diff --git a/AI/Nullkiller2/Pathfinding/AINodeStorage.h b/AI/Nullkiller2/Pathfinding/AINodeStorage.h index 9b62b31cf..5b7fc54b8 100644 --- a/AI/Nullkiller2/Pathfinding/AINodeStorage.h +++ b/AI/Nullkiller2/Pathfinding/AINodeStorage.h @@ -148,7 +148,7 @@ public: static std::mutex locker; static uint32_t version; - AISharedStorage(int3 sizes, int numChains); + explicit AISharedStorage(int3 sizes, int numChains, const CCallback & cc); ~AISharedStorage(); STRONG_INLINE diff --git a/AI/Nullkiller2/Pathfinding/AIPathfinder.cpp b/AI/Nullkiller2/Pathfinding/AIPathfinder.cpp index acf8237e6..7374e1d02 100644 --- a/AI/Nullkiller2/Pathfinding/AIPathfinder.cpp +++ b/AI/Nullkiller2/Pathfinding/AIPathfinder.cpp @@ -156,8 +156,6 @@ void AIPathfinder::updateGraphs( tbb::parallel_for(tbb::blocked_range(0, heroesVector.size()), [this, &heroesVector, &heroes, mainScanDepth, scoutScanDepth](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); - for(auto i = r.begin(); i != r.end(); i++) { auto role = heroes.at(heroesVector[i]); diff --git a/AI/Nullkiller2/Pathfinding/Actions/BattleAction.cpp b/AI/Nullkiller2/Pathfinding/Actions/BattleAction.cpp index 7665a5342..df52134d3 100644 --- a/AI/Nullkiller2/Pathfinding/Actions/BattleAction.cpp +++ b/AI/Nullkiller2/Pathfinding/Actions/BattleAction.cpp @@ -20,7 +20,7 @@ namespace AIPathfinding { void BattleAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const { - aiGw->moveHeroToTile(targetTile, HeroPtr(hero, aiGw->cc)); + aiGw->moveHeroToTile(targetTile, HeroPtr(hero, aiGw->cc.get())); } std::string BattleAction::toString() const diff --git a/AI/Nullkiller2/Pathfinding/Actions/QuestAction.cpp b/AI/Nullkiller2/Pathfinding/Actions/QuestAction.cpp index 04a77ea0c..e99386685 100644 --- a/AI/Nullkiller2/Pathfinding/Actions/QuestAction.cpp +++ b/AI/Nullkiller2/Pathfinding/Actions/QuestAction.cpp @@ -47,12 +47,12 @@ namespace AIPathfinding Goals::TSubgoal QuestAction::decompose(const Nullkiller * aiNk, const CGHeroInstance * hero) const { - return Goals::sptr(Goals::CompleteQuest(questInfo)); + return Goals::sptr(Goals::CompleteQuest(questInfo, *aiNk->cc)); } void QuestAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const { - aiGw->moveHeroToTile(questInfo.getObject(aiGw->cc.get())->visitablePos(), HeroPtr(hero, aiGw->cc)); + aiGw->moveHeroToTile(questInfo.getObject(aiGw->cc.get())->visitablePos(), HeroPtr(hero, aiGw->cc.get())); } std::string QuestAction::toString() const diff --git a/AI/Nullkiller2/pforeach.h b/AI/Nullkiller2/pforeach.h index a60dd60f0..c13cbe409 100644 --- a/AI/Nullkiller2/pforeach.h +++ b/AI/Nullkiller2/pforeach.h @@ -13,7 +13,6 @@ namespace NK2AI // { // tbb::parallel_for(tbb::blocked_range(0, mapSize.x), [&](const tbb::blocked_range & r) // { -// SET_GLOBAL_STATE_TBB(this->aiGw); // int3 pos(0, 0, z); // // for(pos.x = r.begin(); pos.x != r.end(); ++pos.x) @@ -34,7 +33,6 @@ void pforeachTilePaths(const int3 & mapSize, const Nullkiller * aiNk, TFunc fn) { tbb::parallel_for(tbb::blocked_range(0, mapSize.x), [&](const tbb::blocked_range & r) { - SET_GLOBAL_STATE_TBB(aiNk->aiGw); int3 pos(0, 0, z); std::vector paths;