Pārlūkot izejas kodu

Made player interface tolerant to active stack removal.

AlexVinS 10 gadi atpakaļ
vecāks
revīzija
f99bf099ca

+ 14 - 3
client/CPlayerInterface.cpp

@@ -772,7 +772,8 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
 {
 	THREAD_CREATED_BY_CLIENT;
 	logGlobal->traceStream() << "Awaiting command for " << stack->nodeName();
-
+	auto stackId = stack->ID;
+	auto stackName = stack->nodeName();
 	if(autofightingAI)
 	{
 		if(isAutoFightOn)
@@ -806,17 +807,27 @@ BattleAction CPlayerInterface::activeStack(const CStack * stack) //called when i
 	while(!b->givenCommand->data)
 	{
 		b->givenCommand->cond.wait(lock);
-		if(!battleInt) //batle ended while we were waiting for movement (eg. because of spell)
+		if(!battleInt) //battle ended while we were waiting for movement (eg. because of spell)
 			throw boost::thread_interrupted(); //will shut the thread peacefully
 	}
 
 	//tidy up
 	BattleAction ret = *(b->givenCommand->data);
+	//todo: remove this evil hack
+	//dirty evil hack...
+	//if active stack was changed, new thread was started for new active stack but we will receive notification too
+	//we need check that givenCommand is for our stack (use ID as stack object may be even destroyed)
+	if(stackId != ret.stackNumber)
+	{
+		logGlobal->traceStream() << "Interrupted command for " << stackName;
+		throw boost::thread_interrupted();
+	}
+			
 	delete b->givenCommand->data;
 	b->givenCommand->data = nullptr;
 
 	//return command
-	logGlobal->traceStream() << "Giving command for " << stack->nodeName();
+	logGlobal->traceStream() << "Giving command for " << stackName;
 	return ret;
 }
 

+ 1 - 1
client/NetPacksClient.cpp

@@ -750,7 +750,7 @@ void CatapultAttack::applyCl( CClient *cl )
 	BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleCatapultAttacked, *this);
 }
 
-void BattleStacksRemoved::applyCl( CClient *cl )
+void BattleStacksRemoved::applyFirstCl(CClient * cl)
 {
 	//inform interfaces about removed stacks
 	BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(battleStacksRemoved, *this);

+ 8 - 2
client/battle/CBattleInterface.cpp

@@ -1005,11 +1005,17 @@ void CBattleInterface::newStack(const CStack * stack)
 
 void CBattleInterface::stackRemoved(int stackID)
 {
+	if(activeStack != nullptr)
+	{
+		if(activeStack->ID == stackID)
+		{
+			setActiveStack(nullptr);
+		}
+	}
+	
 	delete creAnims[stackID];
 	creAnims.erase(stackID);
 	creDir.erase(stackID);
-	//FIXME: what if currently removed stack is active one (Sacrifice)?
-
 	redrawBackgroundWithHexes(activeStack);
 	queue->update();
 }

+ 1 - 1
lib/NetPacks.h

@@ -1604,7 +1604,7 @@ struct BattleStacksRemoved : public CPackForClient //3016
 	BattleStacksRemoved(){type = 3016;}
 
 	DLL_LINKAGE void applyGs(CGameState *gs);
-	void applyCl(CClient *cl);
+	void applyFirstCl(CClient *cl);//inform client before stack objects are destroyed
 
 	std::set<ui32> stackIDs; //IDs of removed stacks
 

+ 1 - 1
lib/spells/BattleSpellMechanics.cpp

@@ -609,7 +609,7 @@ void SacrificeMechanics::applyBattleEffects(const SpellCastEnvironment * env, co
 		}
 		BattleSetActiveStack sas;
 		sas.stack = stackToActivate->ID;
-		env->sendAndApply(&sas);
+		//env->sendAndApply(&sas);
 	}
 	BattleStacksRemoved bsr;
 	bsr.stackIDs.insert(victim->ID);

+ 2 - 0
server/CGameHandler.cpp

@@ -5452,6 +5452,8 @@ void CGameHandler::runBattle()
 								return true;
 							if(battleResult.get())// battle is finished
 								return true;
+							if(next == nullptr)//active stack was been removed
+								return true;
 							return !next->alive();//active stack is dead
 						};