浏览代码

#1228 - prevent second AI activation on AI defeat due to wrong EndTurn packet

Andrii Danylchenko 2 年之前
父节点
当前提交
56bf8ec2c4

+ 10 - 1
AI/Nullkiller/AIGateway.cpp

@@ -535,6 +535,7 @@ void AIGateway::yourTurn()
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
 	status.startedTurn();
+
 	makingTurn = make_unique<boost::thread>(&AIGateway::makeTurn, this);
 }
 
@@ -1428,7 +1429,15 @@ void AIGateway::endTurn()
 	{
 		logAi->error("Not having turn at the end of turn???");
 	}
+
 	logAi->debug("Resources at the end of turn: %s", cb->getResourceAmount().toString());
+
+	if(cb->getPlayerStatus(playerID) != EPlayerStatus::INGAME)
+	{
+		logAi->info("Ending turn is not needed because we already lost");
+		return;
+	}
+
 	do
 	{
 		cb->endTurn();
@@ -1601,7 +1610,7 @@ void AIStatus::waitTillFree()
 {
 	boost::unique_lock<boost::mutex> lock(mx);
 	while(battle != NO_BATTLE || !remainingQueries.empty() || !objectsBeingVisited.empty() || ongoingHeroMovement)
-		cv.timed_wait(lock, boost::posix_time::milliseconds(100));
+		cv.timed_wait(lock, boost::posix_time::milliseconds(10));
 }
 
 bool AIStatus::haveTurn()

+ 8 - 0
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -74,6 +74,8 @@ Goals::TTask Nullkiller::choseBestTask(Goals::TTaskVec & tasks) const
 
 Goals::TTask Nullkiller::choseBestTask(Goals::TSubgoal behavior, int decompositionMaxDepth) const
 {
+	boost::this_thread::interruption_point();
+
 	logAi->debug("Checking behavior %s", behavior->toString());
 
 	auto start = std::chrono::high_resolution_clock::now();
@@ -160,8 +162,12 @@ void Nullkiller::updateAiState(int pass, bool fast)
 			cfg.mainTurnDistanceLimit = MAIN_TURN_DISTANCE_LIMIT * ((int)scanDepth + 1);
 		}
 
+		boost::this_thread::interruption_point();
+
 		pathfinder->updatePaths(activeHeroes, cfg);
 
+		boost::this_thread::interruption_point();
+
 		objectClusterizer->clusterize();
 	}
 
@@ -212,6 +218,8 @@ HeroLockedReason Nullkiller::getHeroLockedReason(const CGHeroInstance * hero) co
 
 void Nullkiller::makeTurn()
 {
+	boost::lock_guard<boost::mutex> sharedStorageLock(AISharedStorage::locker);
+
 	const int MAX_DEPTH = 10;
 
 	resetAiState();

+ 1 - 0
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -23,6 +23,7 @@ namespace NKAI
 {
 
 std::shared_ptr<boost::multi_array<AIPathNode, 5>> AISharedStorage::shared;
+boost::mutex AISharedStorage::locker;
 std::set<int3> commitedTiles;
 std::set<int3> commitedTilesInitial;
 

+ 2 - 0
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -135,6 +135,8 @@ class AISharedStorage
 	static std::shared_ptr<boost::multi_array<AIPathNode, 5>> shared;
 	std::shared_ptr<boost::multi_array<AIPathNode, 5>> nodes;
 public:
+	static boost::mutex locker;
+
 	AISharedStorage(int3 mapSize);
 	~AISharedStorage();
 

+ 4 - 0
AI/Nullkiller/Pathfinding/AIPathfinder.cpp

@@ -80,6 +80,8 @@ void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes
 
 		do
 		{
+			boost::this_thread::interruption_point();
+
 			while(storage->calculateHeroChain())
 			{
 				boost::this_thread::interruption_point();
@@ -91,6 +93,8 @@ void AIPathfinder::updatePaths(std::map<const CGHeroInstance *, HeroRole> heroes
 			logAi->trace("Select next actor");
 		} while(storage->selectNextActor());
 
+		boost::this_thread::interruption_point();
+
 		if(storage->calculateHeroChainFinal())
 		{
 			boost::this_thread::interruption_point();

+ 11 - 1
server/NetPacksServer.cpp

@@ -89,7 +89,17 @@ bool SaveGame::applyGh(CGameHandler * gh)
 
 bool EndTurn::applyGh(CGameHandler * gh)
 {
-	PlayerColor player = GS(gh)->currentPlayer;
+	PlayerColor currentPlayer = GS(gh)->currentPlayer;
+	if(player != currentPlayer)
+	{
+		if(gh->getPlayerStatus(player) == EPlayerStatus::INGAME)
+			throwAndComplain(gh, "Player attempted to end turn for another player!");
+
+		logGlobal->debug("Player attempted to end turn after game over. Ignoring this request.");
+
+		return true;
+	}
+
 	throwOnWrongPlayer(gh, player);
 	if(gh->queries.topQuery(player))
 		throwAndComplain(gh, "Cannot end turn before resolving queries!");