Explorar o código

Fix a few crashes

Andrii Danylchenko %!s(int64=3) %!d(string=hai) anos
pai
achega
fa9a420f99

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

@@ -1148,7 +1148,7 @@ bool AINodeStorage::hasBetterChain(
 	{
 		auto sameNode = node.actor == candidateNode->actor;
 
-		if(sameNode	|| node.action == CGPathNode::ENodeAction::UNKNOWN || !node.actor->hero)
+		if(sameNode	|| node.action == CGPathNode::ENodeAction::UNKNOWN || !node.actor || !node.actor->hero)
 		{
 			continue;
 		}

+ 5 - 0
client/battle/CBattleInterface.cpp

@@ -2799,6 +2799,11 @@ void CBattleInterface::requestAutofightingAIToTakeAction()
 	{
 		auto ba = make_unique<BattleAction>(curInt->autofightingAI->activeStack(activeStack));
 
+		if(curInt->cb->battleIsFinished())
+		{
+			return; // battle finished with spellcast
+		}
+
 		if (curInt->isAutoFightOn)
 		{
 			if (tacticsMode)

+ 44 - 11
lib/HeroBonus.cpp

@@ -97,7 +97,9 @@ CBonusProxy::CBonusProxy(const IBonusBearer * Target, CSelector Selector)
 	: bonusListCachedLast(0),
 	target(Target),
 	selector(Selector),
-	bonusList()
+	bonusList(),
+	currentBonusListIndex(0),
+	swapGuard()
 {
 
 }
@@ -106,27 +108,34 @@ CBonusProxy::CBonusProxy(const CBonusProxy & other)
 	: bonusListCachedLast(other.bonusListCachedLast),
 	target(other.target),
 	selector(other.selector),
-	bonusList(other.bonusList)
+	currentBonusListIndex(other.currentBonusListIndex),
+	swapGuard()
 {
-
+	bonusList[currentBonusListIndex] = other.bonusList[currentBonusListIndex];
 }
 
 CBonusProxy::CBonusProxy(CBonusProxy && other)
 	: bonusListCachedLast(0),
 	target(other.target),
 	selector(),
-	bonusList()
+	bonusList(),
+	currentBonusListIndex(0),
+	swapGuard()
 {
 	std::swap(bonusListCachedLast, other.bonusListCachedLast);
 	std::swap(selector, other.selector);
 	std::swap(bonusList, other.bonusList);
+	std::swap(currentBonusListIndex, other.currentBonusListIndex);
 }
 
 CBonusProxy & CBonusProxy::operator=(const CBonusProxy & other)
 {
-	bonusListCachedLast = other.bonusListCachedLast;
+	boost::lock_guard<boost::mutex> lock(swapGuard);
+
 	selector = other.selector;
-	bonusList = other.bonusList;
+	swapBonusList(other.bonusList[other.currentBonusListIndex]);
+	bonusListCachedLast = other.bonusListCachedLast;
+
 	return *this;
 }
 
@@ -135,18 +144,42 @@ CBonusProxy & CBonusProxy::operator=(CBonusProxy && other)
 	std::swap(bonusListCachedLast, other.bonusListCachedLast);
 	std::swap(selector, other.selector);
 	std::swap(bonusList, other.bonusList);
+	std::swap(currentBonusListIndex, other.currentBonusListIndex);
+
 	return *this;
 }
 
+void CBonusProxy::swapBonusList(TConstBonusListPtr other) const
+{
+	// The idea here is to avoid changing active bonusList while it can be read by a different thread.
+	// Because such use of shared ptr is not thread safe
+	// So to avoid this we change the second offline instance and swap active index
+	auto newCurrent = 1 - currentBonusListIndex;
+	bonusList[newCurrent] = other;
+	currentBonusListIndex = newCurrent;
+}
+
 TConstBonusListPtr CBonusProxy::getBonusList() const
 {
-	if(target->getTreeVersion() != bonusListCachedLast || !bonusList)
+	auto needUpdateBonusList = [&]() -> bool
+	{
+		return target->getTreeVersion() != bonusListCachedLast || !bonusList[currentBonusListIndex];
+	};
+
+	// avoid locking if everything is up-to-date
+	if(needUpdateBonusList())
 	{
-		//TODO: support limiters
-		bonusList = target->getAllBonuses(selector, Selector::all);
-		bonusListCachedLast = target->getTreeVersion();
+		boost::lock_guard<boost::mutex>lock(swapGuard);
+
+		if(needUpdateBonusList())
+		{
+			//TODO: support limiters
+			swapBonusList(target->getAllBonuses(selector, Selector::all));
+			bonusListCachedLast = target->getTreeVersion();
+		}
 	}
-	return bonusList;
+
+	return bonusList[currentBonusListIndex];
 }
 
 const BonusList * CBonusProxy::operator->() const

+ 4 - 1
lib/HeroBonus.h

@@ -84,7 +84,10 @@ protected:
 	CSelector selector;
 	const IBonusBearer * target;
 	mutable int64_t bonusListCachedLast;
-	mutable TConstBonusListPtr bonusList;
+	mutable TConstBonusListPtr bonusList[2];
+	mutable int currentBonusListIndex;
+	mutable boost::mutex swapGuard;
+	void swapBonusList(TConstBonusListPtr other) const;
 };
 
 class DLL_LINKAGE CTotalsProxy : public CBonusProxy