浏览代码

Fix autocombat AI threading

Ivan Savenko 2 年之前
父节点
当前提交
9e58f67ab5
共有 2 个文件被更改,包括 29 次插入22 次删除
  1. 3 0
      client/CPlayerInterface.cpp
  2. 26 22
      client/battle/BattleInterface.cpp

+ 3 - 0
client/CPlayerInterface.cpp

@@ -786,6 +786,9 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn
 	{
 		if (isAutoFightOn)
 		{
+			//FIXME: we want client rendering to proceed while AI is making actions
+			// so unlock mutex while AI is busy since this might take quite a while, especially if hero has many spells
+			auto unlockPim = vstd::makeUnlockGuard(*pim);
 			autofightingAI->activeStack(stack);
 			return;
 		}

+ 26 - 22
client/battle/BattleInterface.cpp

@@ -701,35 +701,39 @@ void BattleInterface::requestAutofightingAIToTakeAction()
 {
 	assert(curInt->isAutoFightOn);
 
-	boost::thread aiThread([&]()
+	if(curInt->cb->battleIsFinished())
 	{
-		if(curInt->cb->battleIsFinished())
-		{
-			return; // battle finished with spellcast
-		}
+		return; // battle finished with spellcast
+	}
+
+	if (tacticsMode)
+	{
+		// Always end tactics mode. Player interface is blocked currently, so it's not possible that
+		// the AI can take any action except end tactics phase (AI actions won't be triggered)
+		//TODO implement the possibility that the AI will be triggered for further actions
+		//TODO any solution to merge tactics phase & normal phase in the way it is handled by the player and battle interface?
+		tacticPhaseEnd();
+		stacksController->setActiveStack(nullptr);
+	}
+	else
+	{
+		const CStack* activeStack = stacksController->getActiveStack();
 
-		if (tacticsMode)
+		// If enemy is moving, activeStack can be null
+		if (activeStack)
 		{
-			// Always end tactics mode. Player interface is blocked currently, so it's not possible that
-			// the AI can take any action except end tactics phase (AI actions won't be triggered)
-			//TODO implement the possibility that the AI will be triggered for further actions
-			//TODO any solution to merge tactics phase & normal phase in the way it is handled by the player and battle interface?
-			tacticPhaseEnd();
 			stacksController->setActiveStack(nullptr);
-		}
-		else
-		{
-			const CStack* activeStack = stacksController->getActiveStack();
 
-			// If enemy is moving, activeStack can be null
-			if (activeStack)
+			// FIXME: unsafe
+			// Run task in separate thread to avoid UI lock while AI is making turn (which might take some time)
+			// HOWEVER this thread won't atttempt to lock game state, potentially leading to races
+			boost::thread aiThread([&]()
+			{
 				curInt->autofightingAI->activeStack(activeStack);
-
-			stacksController->setActiveStack(nullptr);
+			});
+			aiThread.detach();
 		}
-	});
-
-	aiThread.detach();
+	}
 }
 
 void BattleInterface::castThisSpell(SpellID spellID)