diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 95308ae61..57428999f 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -97,6 +97,8 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose) if(!hero) validateObject(details.id); //enemy hero may have left visible area + nullkiller->invalidatePathfinderData(); + const int3 from = hero ? hero->convertToVisitablePos(details.start) : (details.start - int3(0,1,0)); const int3 to = hero ? hero->convertToVisitablePos(details.end) : (details.end - int3(0,1,0)); @@ -358,6 +360,7 @@ void AIGateway::newObject(const CGObjectInstance * obj) { LOG_TRACE(logAi); NET_EVENT_HANDLER; + nullkiller->invalidatePathfinderData(); if(obj->isVisitable()) addVisitableObj(obj); } @@ -582,6 +585,7 @@ void AIGateway::yourTurn(QueryID queryID) { LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID); NET_EVENT_HANDLER; + nullkiller->invalidatePathfinderData(); status.addQuery(queryID, "YourTurn"); requestActionASAP([=](){ answerQuery(queryID, 0); }); status.startedTurn(); diff --git a/AI/Nullkiller/Engine/Nullkiller.cpp b/AI/Nullkiller/Engine/Nullkiller.cpp index b2c3d0eb1..88ee4f1dc 100644 --- a/AI/Nullkiller/Engine/Nullkiller.cpp +++ b/AI/Nullkiller/Engine/Nullkiller.cpp @@ -37,6 +37,7 @@ Nullkiller::Nullkiller() : activeHero(nullptr) , scanDepth(ScanDepth::MAIN_FULL) , useHeroChain(true) + , pathfinderInvalidated(false) , memory(std::make_unique()) { @@ -239,6 +240,11 @@ void Nullkiller::resetAiState() } } +void Nullkiller::invalidatePathfinderData() +{ + pathfinderInvalidated = true; +} + void Nullkiller::updateAiState(int pass, bool fast) { boost::this_thread::interruption_point(); @@ -253,7 +259,10 @@ void Nullkiller::updateAiState(int pass, bool fast) decomposer->reset(); buildAnalyzer->update(); - if(!fast) + if (!pathfinderInvalidated) + logAi->trace("Skipping paths regeneration - up to date"); + + if(!fast && pathfinderInvalidated) { memory->removeInvisibleObjects(cb.get()); @@ -304,11 +313,13 @@ void Nullkiller::updateAiState(int pass, bool fast) boost::this_thread::interruption_point(); objectClusterizer->clusterize(); + + pathfinderInvalidated = false; } armyManager->update(); - logAi->debug("AI state updated in %ld", timeElapsed(start)); + logAi->debug("AI state updated in %ld ms", timeElapsed(start)); } bool Nullkiller::isHeroLocked(const CGHeroInstance * hero) const @@ -379,7 +390,7 @@ void Nullkiller::makeTurn() Goals::TTask bestTask = taskptr(Goals::Invalid()); - while(true) + for(int j = 1; j <= settings->getMaxPriorityPass() && cb->getPlayerStatus(playerID) == EPlayerStatus::INGAME; j++) { bestTasks.clear(); diff --git a/AI/Nullkiller/Engine/Nullkiller.h b/AI/Nullkiller/Engine/Nullkiller.h index 941e71f16..369fe7116 100644 --- a/AI/Nullkiller/Engine/Nullkiller.h +++ b/AI/Nullkiller/Engine/Nullkiller.h @@ -78,6 +78,7 @@ private: AIGateway * gateway; bool openMap; bool useObjectGraph; + bool pathfinderInvalidated; public: static std::unique_ptr baseGraph; @@ -121,6 +122,7 @@ public: bool isOpenMap() const { return openMap; } bool isObjectGraphAllowed() const { return useObjectGraph; } bool handleTrading(); + void invalidatePathfinderData(); private: void resetAiState(); diff --git a/AI/Nullkiller/Engine/Settings.cpp b/AI/Nullkiller/Engine/Settings.cpp index 6cc7a5266..44ef27176 100644 --- a/AI/Nullkiller/Engine/Settings.cpp +++ b/AI/Nullkiller/Engine/Settings.cpp @@ -32,7 +32,8 @@ namespace NKAI retreatThresholdRelative(0.3), retreatThresholdAbsolute(10000), safeAttackRatio(1.1), - maxpass(10), + maxPass(10), + maxPriorityPass(10), pathfinderBucketsCount(1), pathfinderBucketSize(32), allowObjectGraph(true), @@ -48,7 +49,8 @@ namespace NKAI maxRoamingHeroes = node["maxRoamingHeroes"].Integer(); mainHeroTurnDistanceLimit = node["mainHeroTurnDistanceLimit"].Integer(); scoutHeroTurnDistanceLimit = node["scoutHeroTurnDistanceLimit"].Integer(); - maxpass = node["maxpass"].Integer(); + maxPass = node["maxPass"].Integer(); + maxPriorityPass = node["maxPriorityPass"].Integer(); pathfinderBucketsCount = node["pathfinderBucketsCount"].Integer(); pathfinderBucketSize = node["pathfinderBucketSize"].Integer(); maxGoldPressure = node["maxGoldPressure"].Float(); diff --git a/AI/Nullkiller/Engine/Settings.h b/AI/Nullkiller/Engine/Settings.h index ac8b718ec..01f4f2a9c 100644 --- a/AI/Nullkiller/Engine/Settings.h +++ b/AI/Nullkiller/Engine/Settings.h @@ -24,7 +24,8 @@ namespace NKAI int maxRoamingHeroes; int mainHeroTurnDistanceLimit; int scoutHeroTurnDistanceLimit; - int maxpass; + int maxPass; + int maxPriorityPass; int pathfinderBucketsCount; int pathfinderBucketSize; float maxGoldPressure; @@ -41,7 +42,8 @@ namespace NKAI public: explicit Settings(int difficultyLevel); - int getMaxPass() const { return maxpass; } + int getMaxPass() const { return maxPass; } + int getMaxPriorityPass() const { return maxPriorityPass; } float getMaxGoldPressure() const { return maxGoldPressure; } float getRetreatThresholdRelative() const { return retreatThresholdRelative; } float getRetreatThresholdAbsolute() const { return retreatThresholdAbsolute; } diff --git a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp index a46584649..b504f9e7d 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinder.cpp +++ b/AI/Nullkiller/Pathfinding/AIPathfinder.cpp @@ -106,7 +106,7 @@ void AIPathfinder::updatePaths(const std::map if(!pathfinderSettings.useHeroChain) { - logAi->trace("Recalculated paths in %ld", timeElapsed(start)); + logAi->trace("Recalculated paths in %ld ms", timeElapsed(start)); return; } @@ -141,7 +141,7 @@ void AIPathfinder::updatePaths(const std::map } } while(storage->increaseHeroChainTurnLimit()); - logAi->trace("Recalculated paths in %ld", timeElapsed(start)); + logAi->trace("Recalculated paths in %ld ms", timeElapsed(start)); } void AIPathfinder::updateGraphs( diff --git a/config/ai/nkai/nkai-settings.json b/config/ai/nkai/nkai-settings.json index a4356c34a..55cfe9cb5 100644 --- a/config/ai/nkai/nkai-settings.json +++ b/config/ai/nkai/nkai-settings.json @@ -33,17 +33,18 @@ "pawn" : { - "maxRoamingHeroes" : 4, //H3 value: 3, - "maxpass" : 30, + "maxRoamingHeroes" : 3, //H3 value: 3, + "maxPass" : 30, + "maxPriorityPass" : 10, "mainHeroTurnDistanceLimit" : 10, "scoutHeroTurnDistanceLimit" : 5, "maxGoldPressure" : 0.3, "updateHitmapOnTileReveal" : false, "useTroopsFromGarrisons" : true, "openMap": true, - "allowObjectGraph": false, - "pathfinderBucketsCount" : 1, // old value: 3, - "pathfinderBucketSize" : 32, // old value: 7, + "allowObjectGraph": true, + "pathfinderBucketsCount" : 4, // old value: 3, + "pathfinderBucketSize" : 8, // old value: 7, "retreatThresholdRelative" : 0, "retreatThresholdAbsolute" : 0, "safeAttackRatio" : 1.1, @@ -52,17 +53,18 @@ }, "knight" : { - "maxRoamingHeroes" : 6, //H3 value: 3, - "maxpass" : 30, + "maxRoamingHeroes" : 3, //H3 value: 3, + "maxPass" : 30, + "maxPriorityPass" : 10, "mainHeroTurnDistanceLimit" : 10, "scoutHeroTurnDistanceLimit" : 5, "maxGoldPressure" : 0.3, "updateHitmapOnTileReveal" : false, "useTroopsFromGarrisons" : true, "openMap": true, - "allowObjectGraph": false, - "pathfinderBucketsCount" : 1, // old value: 3, - "pathfinderBucketSize" : 32, // old value: 7, + "allowObjectGraph": true, + "pathfinderBucketsCount" : 4, // old value: 3, + "pathfinderBucketSize" : 8, // old value: 7, "retreatThresholdRelative" : 0.1, "retreatThresholdAbsolute" : 5000, "safeAttackRatio" : 1.1, @@ -71,17 +73,18 @@ }, "rook" : { - "maxRoamingHeroes" : 8, //H3 value: 4 - "maxpass" : 30, + "maxRoamingHeroes" : 4, //H3 value: 4 + "maxPass" : 30, + "maxPriorityPass" : 10, "mainHeroTurnDistanceLimit" : 10, "scoutHeroTurnDistanceLimit" : 5, "maxGoldPressure" : 0.3, "updateHitmapOnTileReveal" : false, "useTroopsFromGarrisons" : true, "openMap": true, - "allowObjectGraph": false, - "pathfinderBucketsCount" : 1, // old value: 3, - "pathfinderBucketSize" : 32, // old value: 7, + "allowObjectGraph": true, + "pathfinderBucketsCount" : 4, // old value: 3, + "pathfinderBucketSize" : 8, // old value: 7, "retreatThresholdRelative" : 0.3, "retreatThresholdAbsolute" : 10000, "safeAttackRatio" : 1.1, @@ -90,17 +93,18 @@ }, "queen" : { - "maxRoamingHeroes" : 8, //H3 value: 5 - "maxpass" : 30, + "maxRoamingHeroes" : 6, //H3 value: 5 + "maxPass" : 30, + "maxPriorityPass" : 10, "mainHeroTurnDistanceLimit" : 10, "scoutHeroTurnDistanceLimit" : 5, "maxGoldPressure" : 0.3, "updateHitmapOnTileReveal" : false, "useTroopsFromGarrisons" : true, "openMap": true, - "allowObjectGraph": false, - "pathfinderBucketsCount" : 1, // old value: 3, - "pathfinderBucketSize" : 32, // old value: 7, + "allowObjectGraph": true, + "pathfinderBucketsCount" : 4, // old value: 3, + "pathfinderBucketSize" : 8, // old value: 7, "retreatThresholdRelative" : 0.3, "retreatThresholdAbsolute" : 10000, "safeAttackRatio" : 1.1, @@ -110,16 +114,17 @@ "king" : { "maxRoamingHeroes" : 8, //H3 value: 6 - "maxpass" : 30, + "maxPass" : 30, + "maxPriorityPass" : 10, "mainHeroTurnDistanceLimit" : 10, "scoutHeroTurnDistanceLimit" : 5, "maxGoldPressure" : 0.3, "updateHitmapOnTileReveal" : false, "useTroopsFromGarrisons" : true, "openMap": true, - "allowObjectGraph": false, - "pathfinderBucketsCount" : 1, // old value: 3, - "pathfinderBucketSize" : 32, // old value: 7, + "allowObjectGraph": true, + "pathfinderBucketsCount" : 4, // old value: 3, + "pathfinderBucketSize" : 8, // old value: 7, "retreatThresholdRelative" : 0.3, "retreatThresholdAbsolute" : 10000, "safeAttackRatio" : 1.1,