From 9e58f67ab5dab97d578ad19704e7c8ca2d1ff220 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Wed, 19 Jul 2023 12:09:03 +0300 Subject: [PATCH] Fix autocombat AI threading --- client/CPlayerInterface.cpp | 3 ++ client/battle/BattleInterface.cpp | 48 +++++++++++++++++-------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 7e68dc73e..6f2528584 100644 --- a/client/CPlayerInterface.cpp +++ b/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; } diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 589b1a2ec..6514de640 100644 --- a/client/battle/BattleInterface.cpp +++ b/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) + 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 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)