Browse Source

Shut down the thread for tactic phase properly

Adriankhl 2 years ago
parent
commit
1d6192ca62
5 changed files with 37 additions and 1 deletions
  1. 6 0
      client/CPlayerInterface.cpp
  2. 1 0
      client/CPlayerInterface.h
  3. 24 1
      client/Client.cpp
  4. 5 0
      client/Client.h
  5. 1 0
      lib/CGameInterface.h

+ 6 - 0
client/CPlayerInterface.cpp

@@ -1032,6 +1032,12 @@ void CPlayerInterface::yourTacticPhase(int distance)
 		boost::this_thread::sleep(boost::posix_time::millisec(1));
 }
 
+void CPlayerInterface::forceEndTacticPhase()
+{
+	if (battleInt)
+		battleInt->tacticsMode = false;
+}
+
 void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &text, const std::vector<Component> & components, int soundID)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;

+ 1 - 0
client/CPlayerInterface.h

@@ -226,6 +226,7 @@ public:
 	void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
 	void battleGateStateChanged(const EGateState state) override;
 	void yourTacticPhase(int distance) override;
+	void forceEndTacticPhase() override;
 
 	//-------------//
 	void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes);

+ 24 - 1
client/Client.cpp

@@ -7,6 +7,7 @@
  * Full text of license available in license.txt file, in main folder
  *
  */
+#include "Global.h"
 #include "StdInc.h"
 #include "Client.h"
 
@@ -31,6 +32,7 @@
 #include "../lib/registerTypes/RegisterTypes.h"
 #include "../lib/serializer/Connection.h"
 
+#include <memory>
 #include <vcmi/events/EventBus.h>
 
 #if SCRIPTING_ENABLED
@@ -369,6 +371,9 @@ void CClient::endGame()
 		logNetwork->info("Deleted mapHandler and gameState.");
 	}
 
+	//threads cleanup has to be after gs cleanup and before battleints cleanup to stop tacticThread
+	cleanThreads();
+
 	playerint.clear();
 	battleints.clear();
 	battleCallbacks.clear();
@@ -593,7 +598,8 @@ void CClient::battleStarted(const BattleInfo * info)
 
 	if(info->tacticDistance && vstd::contains(battleints, info->sides[info->tacticsSide].color))
 	{
-		boost::thread(&CClient::commenceTacticPhaseForInt, this, battleints[info->sides[info->tacticsSide].color]);
+		PlayerColor color = info->sides[info->tacticsSide].color;
+		playerTacticThreads[color] = std::make_unique<boost::thread>(&CClient::commenceTacticPhaseForInt, this, battleints[color]);
 	}
 }
 
@@ -754,6 +760,23 @@ void CClient::removeGUI()
 	LOCPLINT = nullptr;
 }
 
+void CClient::cleanThreads()
+{
+	stopAllBattleActions();
+
+	while (!playerTacticThreads.empty())
+	{
+		PlayerColor color = playerTacticThreads.begin()->first;
+
+		//set tacticcMode of the players to false to stop tacticThread
+		if (vstd::contains(battleints, color))
+			battleints[color]->forceEndTacticPhase();
+
+		playerTacticThreads[color]->join();
+		playerTacticThreads.erase(color);
+	}
+}
+
 #ifdef VCMI_ANDROID
 #ifndef SINGLE_PROCESS_APP
 extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls)

+ 5 - 0
client/Client.h

@@ -9,6 +9,7 @@
  */
 #pragma once
 
+#include <memory>
 #include <vcmi/Environment.h>
 
 #include "../lib/IGameCallback.h"
@@ -241,6 +242,8 @@ public:
 	void showInfoDialog(const std::string & msg, PlayerColor player) override {};
 	void removeGUI();
 
+	void cleanThreads();
+
 #if SCRIPTING_ENABLED
 	scripting::Pool * getGlobalContextPool() const override;
 	scripting::Pool * getContextPool() const override;
@@ -262,6 +265,8 @@ private:
 
 	std::map<PlayerColor, std::shared_ptr<boost::thread>> playerActionThreads;
 
+	std::map<PlayerColor, std::unique_ptr<boost::thread>> playerTacticThreads;
+
 	void waitForMoveAndSend(PlayerColor color);
 	void reinitScripting();
 };

+ 1 - 0
lib/CGameInterface.h

@@ -82,6 +82,7 @@ public:
 	//battle call-ins
 	virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
 	virtual void yourTacticPhase(int distance){}; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function
+	virtual void forceEndTacticPhase(){}; //force the tatic phase to end to clean up the tactic phase thread
 };
 
 /// Central class for managing human player / AI interface logic