浏览代码

Refactor HD mod army exchange

Andrii Danylchenko 4 年之前
父节点
当前提交
78efd09e2e
共有 2 个文件被更改,包括 101 次插入84 次删除
  1. 87 84
      client/windows/GUIClasses.cpp
  2. 14 0
      client/windows/GUIClasses.h

+ 87 - 84
client/windows/GUIClasses.cpp

@@ -795,42 +795,48 @@ static bool isHdLayoutAvailable()
 	return CResourceHandler::get()->existsResource(ResourceID(std::string("SPRITES/") + HD_EXCHANGE_BG, EResType::IMAGE));
 }
 
+// Runs a task asynchronously with gamestate locking and waitTillRealize set to true
 class GsThread
 {
 private:
-	struct GsThreadState
+	std::function<void()> action;
+	std::shared_ptr<CCallback> cb;
+
+public:
+
+	static void run(std::function<void()> action)
 	{
-		boost::shared_lock<boost::shared_mutex> gsLock;
-		std::function<void()> action;
-		std::shared_ptr<CCallback> cb;
+		std::shared_ptr<GsThread> instance(new GsThread(action));
 
-		GsThreadState(std::function<void()> action)
-			: action(action), cb(LOCPLINT->cb)
-		{
-		}
-	};
 
-public:
+		boost::thread(std::bind(&GsThread::staticRun, instance));
+	}
+
+private:
 	GsThread(std::function<void()> action)
+		:action(action), cb(LOCPLINT->cb)
 	{
-		boost::thread(std::bind(&GsThread::run, std::make_shared<GsThreadState>(action)));
 	}
 
-private:
-	static void run(std::shared_ptr<GsThreadState> state)
+	static void staticRun(std::shared_ptr<GsThread> instance)
+	{
+		instance->run();
+	}
+
+	void run()
 	{
 		boost::shared_lock<boost::shared_mutex> gsLock(CGameState::mutex);
 
-		auto originalWaitTillRealize = state->cb->waitTillRealize;
-		auto originalUnlockGsWhenWating = state->cb->unlockGsWhenWaiting;
+		auto originalWaitTillRealize = cb->waitTillRealize;
+		auto originalUnlockGsWhenWating = cb->unlockGsWhenWaiting;
 
-		state->cb->waitTillRealize = true;
-		state->cb->unlockGsWhenWaiting = true;
+		cb->waitTillRealize = true;
+		cb->unlockGsWhenWaiting = true;
 
-		state->action();
+		action();
 
-		state->cb->waitTillRealize = originalWaitTillRealize;
-		state->cb->unlockGsWhenWaiting = originalUnlockGsWhenWating;
+		cb->waitTillRealize = originalWaitTillRealize;
+		cb->unlockGsWhenWaiting = originalUnlockGsWhenWating;
 	}
 };
 
@@ -884,18 +890,6 @@ void CExchangeController::swapArtifacts(ArtifactPosition slot)
 	}
 }
 
-struct ArtWearingTask
-{
-	ArtifactPosition artPosition;
-	const CGHeroInstance * target;
-	const CArtifactInstance * art;
-
-	ArtWearingTask(ArtifactPosition artPosition, const CGHeroInstance * target, const CArtifactInstance * art)
-		:artPosition(artPosition), target(target), art(art)
-	{
-	}
-};
-
 std::vector<CArtifactInstance *> getBackpackArts(const CGHeroInstance * hero)
 {
 	std::vector<CArtifactInstance *> result;
@@ -917,71 +911,80 @@ bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
 		&& !vstd::contains(unmovablePositions, slot.first);
 }
 
-std::function<void()> CExchangeController::onSwapArtifacts()
+// Puts all composite arts to backpack and returns their previous location
+std::vector<HeroArtifact> CExchangeController::moveCompositeArtsToBackpack()
 {
-	return [&]()
+	std::vector<const CGHeroInstance *> sides = {left, right};
+	std::vector<HeroArtifact> artPositions;
+
+	for(auto hero : sides)
 	{
-		GsThread([=]
+		for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
 		{
-			std::vector<const CGHeroInstance *> sides = {left, right};
-			std::vector<ArtWearingTask> compositeArtWearingTasks;
+			auto artPosition = ArtifactPosition(i);
+			auto art = hero->getArt(artPosition);
 
-			for(auto hero : sides)
+			if(art && art->canBeDisassembled())
 			{
-				for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
-				{
-					auto artPosition = ArtifactPosition(i);
-					auto art = hero->getArt(artPosition);
-
-					if(art && art->canBeDisassembled())
-					{
-						// it is not possible to directly swap Angelic Alliance and Armor of Damned
-						// so move them to backpack first
-						cb->swapArtifacts(
-							ArtifactLocation(hero, artPosition),
-							ArtifactLocation(hero, ArtifactPosition(GameConstants::BACKPACK_START)));
-
-						// and a task to wear it back
-						compositeArtWearingTasks.push_back(
-							ArtWearingTask(artPosition, hero == left ? right : left, art));
-					}
-				}
+				cb->swapArtifacts(
+					ArtifactLocation(hero, artPosition),
+					ArtifactLocation(hero, ArtifactPosition(GameConstants::BACKPACK_START)));
+
+				artPositions.push_back(HeroArtifact(hero, art, artPosition));
 			}
+		}
+	}
 
-			for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
-			{
-				if(vstd::contains(unmovablePositions, i))
-					continue;
+	return artPositions;
+}
 
-				swapArtifacts(ArtifactPosition(i));
-			}
+void CExchangeController::swapArtifacts()
+{
+	for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
+	{
+		if(vstd::contains(unmovablePositions, i))
+			continue;
 
-			auto leftHeroBackpack = getBackpackArts(left);
-			auto rightHeroBackpack = getBackpackArts(right);
+		swapArtifacts(ArtifactPosition(i));
+	}
 
-			for(auto leftArt : leftHeroBackpack)
-			{
-				cb->swapArtifacts(
-					ArtifactLocation(left, left->getArtPos(leftArt)),
-					ArtifactLocation(right, ArtifactPosition(GameConstants::BACKPACK_START)));
-			}
+	auto leftHeroBackpack = getBackpackArts(left);
+	auto rightHeroBackpack = getBackpackArts(right);
 
-			for(auto rightArt : rightHeroBackpack)
-			{
-				cb->swapArtifacts(
-					ArtifactLocation(right, right->getArtPos(rightArt)),
-					ArtifactLocation(left, ArtifactPosition(GameConstants::BACKPACK_START)));
-			}
+	for(auto leftArt : leftHeroBackpack)
+	{
+		cb->swapArtifacts(
+			ArtifactLocation(left, left->getArtPos(leftArt)),
+			ArtifactLocation(right, ArtifactPosition(GameConstants::BACKPACK_START)));
+	}
+
+	for(auto rightArt : rightHeroBackpack)
+	{
+		cb->swapArtifacts(
+			ArtifactLocation(right, right->getArtPos(rightArt)),
+			ArtifactLocation(left, ArtifactPosition(GameConstants::BACKPACK_START)));
+	}
+}
+
+std::function<void()> CExchangeController::onSwapArtifacts()
+{
+	return [&]()
+	{
+		GsThread::run([=]
+		{
+			// it is not possible directly exchange composite artifacts like Angelic Alliance and Armor of Damned
+			auto compositeArtLocations = moveCompositeArtsToBackpack();
 
-			int maxBackPackSize;
+			swapArtifacts();
 
-			for(auto wearingTask : compositeArtWearingTasks)
+			for(HeroArtifact artLocation : compositeArtLocations)
 			{
-				auto currentPos = wearingTask.target->getArtPos(wearingTask.art);
+				auto target = artLocation.hero == left ? right : left;
+				auto currentPos = target->getArtPos(artLocation.artifact);
 
 				cb->swapArtifacts(
-					ArtifactLocation(wearingTask.target, currentPos),
-					ArtifactLocation(wearingTask.target, wearingTask.artPosition));
+					ArtifactLocation(target, currentPos),
+					ArtifactLocation(target, artLocation.artPosition));
 			}
 
 			view->redraw();
@@ -1010,7 +1013,7 @@ std::function<void()> CExchangeController::onSwapArmy()
 {
 	return [&]()
 	{
-		GsThread([=]
+		GsThread::run([=]
 		{
 			auto leftSlots = getStacks(left);
 			auto rightSlots = getStacks(right);
@@ -1071,7 +1074,7 @@ void CExchangeController::moveArmy(bool leftToRight)
 	const CGHeroInstance * source = leftToRight ? left : right;
 	const CGHeroInstance * target = leftToRight ? right : left;
 
-	GsThread([=]
+	GsThread::run([=]
 	{
 		auto stacks = getStacks(source);
 
@@ -1092,7 +1095,7 @@ void CExchangeController::moveArtifacts(bool leftToRight)
 	const CGHeroInstance * source = leftToRight ? left : right;
 	const CGHeroInstance * target = leftToRight ? right : left;
 
-	GsThread([=]
+	GsThread::run([=]
 	{	
 		while(vstd::contains_if(source->artifactsWorn, isArtRemovable))
 		{

+ 14 - 0
client/windows/GUIClasses.h

@@ -283,6 +283,18 @@ public:
 class CCallback;
 class CExchangeWindow;
 
+struct HeroArtifact
+{
+	const CGHeroInstance * hero;
+	const CArtifactInstance * artifact;
+	ArtifactPosition artPosition;
+
+	HeroArtifact(const CGHeroInstance * hero, const CArtifactInstance * artifact, ArtifactPosition artPosition)
+		:hero(hero), artifact(artifact), artPosition(artPosition)
+	{
+	}
+};
+
 class CExchangeController
 {
 private:
@@ -306,6 +318,8 @@ private:
 	void moveArtifact(const CGHeroInstance * source, const CGHeroInstance * target, ArtifactPosition srcPosition);
 	void moveStack(const CGHeroInstance * source, const CGHeroInstance * target, SlotID sourceSlot);
 	void swapArtifacts(ArtifactPosition artPosition);
+	std::vector<HeroArtifact> moveCompositeArtsToBackpack();
+	void swapArtifacts();
 };
 
 class CExchangeWindow : public CStatusbarWindow, public CGarrisonHolder, public CWindowWithArtifacts