Ver código fonte

Reduce excessive updates of garrisons. Fixes selection reset in simturns

Ivan Savenko 1 ano atrás
pai
commit
864462b84a

+ 13 - 19
client/CPlayerInterface.cpp

@@ -499,8 +499,9 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 	adventureInt->onHeroChanged(nullptr);
 	adventureInt->onTownChanged(town);
 
-	for (auto gh : GH.windows().findWindows<IGarrisonHolder>())
-		gh->updateGarrisons();
+	for (auto cgh : GH.windows().findWindows<IGarrisonHolder>())
+		if (cgh->holdsGarrison(town))
+			cgh->updateGarrisons();
 
 	for (auto ki : GH.windows().findWindows<CKingdomInterface>())
 		ki->townChanged(town);
@@ -521,49 +522,42 @@ void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownIn
 
 void CPlayerInterface::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2)
 {
-	std::vector<const CGObjectInstance *> instances;
+	std::vector<const CArmedInstance *> instances;
 
-	if(auto obj = cb->getObj(id1))
+	if(auto obj = dynamic_cast<const CArmedInstance *>(cb->getObjInstance(id1)))
 		instances.push_back(obj);
 
 
 	if(id2 != ObjectInstanceID() && id2 != id1)
 	{
-		if(auto obj = cb->getObj(id2))
+		if(auto obj = dynamic_cast<const CArmedInstance *>(cb->getObjInstance(id2)))
 			instances.push_back(obj);
 	}
 
 	garrisonsChanged(instances);
 }
 
-void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> objs)
+void CPlayerInterface::garrisonsChanged(std::vector<const CArmedInstance *> objs)
 {
 	for (auto object : objs)
 	{
 		auto * hero = dynamic_cast<const CGHeroInstance*>(object);
 		auto * town = dynamic_cast<const CGTownInstance*>(object);
 
+		if (town)
+			adventureInt->onTownChanged(town);
+
 		if (hero)
 		{
 			adventureInt->onHeroChanged(hero);
-
-			if(hero->inTownGarrison)
-			{
+			if(hero->inTownGarrison && hero->visitedTown != town)
 				adventureInt->onTownChanged(hero->visitedTown);
-			}
 		}
-		if (town)
-			adventureInt->onTownChanged(town);
 	}
 
 	for (auto cgh : GH.windows().findWindows<IGarrisonHolder>())
-		cgh->updateGarrisons();
-
-	for (auto cmw : GH.windows().findWindows<CAltarWindow>())
-	{
-		if(vstd::contains(objs, cmw->getHero()))
-			cmw->updateGarrison();
-	}
+		if (cgh->holdsGarrisons(objs))
+			cgh->updateGarrisons();
 
 	GH.windows().totalRedraw();
 }

+ 1 - 1
client/CPlayerInterface.h

@@ -223,7 +223,7 @@ private:
 	};
 
 	void heroKilled(const CGHeroInstance* hero);
-	void garrisonsChanged(std::vector<const CGObjectInstance *> objs);
+	void garrisonsChanged(std::vector<const CArmedInstance *> objs);
 	void requestReturningToMainMenu(bool won);
 	void acceptTurn(QueryID queryID); //used during hot seat after your turn message is close
 	void initializeHeroTownList();

+ 13 - 0
client/gui/CIntObject.h

@@ -19,6 +19,10 @@ class CGuiHandler;
 class CPicture;
 class Canvas;
 
+VCMI_LIB_NAMESPACE_BEGIN
+class CArmedInstance;
+VCMI_LIB_NAMESPACE_BEGIN
+
 class IUpdateable
 {
 public:
@@ -150,6 +154,15 @@ protected:
 class IGarrisonHolder
 {
 public:
+	bool holdsGarrisons(std::vector<const CArmedInstance *> armies)
+	{
+		for (auto const * army : armies)
+			if (holdsGarrison(army))
+				return true;
+		return false;
+	}
+
+	virtual bool holdsGarrison(const CArmedInstance * army) = 0;
 	virtual void updateGarrisons() = 0;
 };
 

+ 6 - 1
client/windows/CAltarWindow.cpp

@@ -45,12 +45,17 @@ void CAltarWindow::updateExpToLevel()
 	altar->expToLevel->setText(std::to_string(CGI->heroh->reqExp(CGI->heroh->level(altar->hero->exp) + 1) - altar->hero->exp));
 }
 
-void CAltarWindow::updateGarrison()
+void CAltarWindow::updateGarrisons()
 {
 	if(auto altarCreatures = std::static_pointer_cast<CAltarCreatures>(altar))
 		altarCreatures->updateGarrison();
 }
 
+bool CAltarWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return hero == army;
+}
+
 const CGHeroInstance * CAltarWindow::getHero() const
 {
 	return hero;

+ 3 - 2
client/windows/CAltarWindow.h

@@ -13,12 +13,13 @@
 #include "../widgets/CWindowWithArtifacts.h"
 #include "CWindowObject.h"
 
-class CAltarWindow : public CWindowObject, public CWindowWithArtifacts
+class CAltarWindow : public CWindowObject, public CWindowWithArtifacts, public IGarrisonHolder
 {
 public:
 	CAltarWindow(const IMarket * market, const CGHeroInstance * hero, const std::function<void()> & onWindowClosed, EMarketMode mode);
 	void updateExpToLevel();
-	void updateGarrison();
+	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 	const CGHeroInstance * getHero() const;
 	void close() override;
 

+ 5 - 0
client/windows/CCastleInterface.cpp

@@ -1262,6 +1262,11 @@ void CCastleInterface::updateGarrisons()
 	redraw();
 }
 
+bool CCastleInterface::holdsGarrison(const CArmedInstance * army)
+{
+	return army == town || army == town->getUpperArmy() || army == town->visitingHero;
+}
+
 void CCastleInterface::close()
 {
 	if(town->tempOwner == LOCPLINT->playerID) //we may have opened window for an allied town

+ 2 - 1
client/windows/CCastleInterface.h

@@ -249,7 +249,8 @@ public:
 	CCastleInterface(const CGTownInstance * Town, const CGTownInstance * from = nullptr);
 	~CCastleInterface();
 
-	virtual void updateGarrisons() override;
+	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 
 	void castleTeleport(int where);
 	void townChange();

+ 5 - 0
client/windows/CHeroWindow.cpp

@@ -353,3 +353,8 @@ void CHeroWindow::updateGarrisons()
 	garr->recreateSlots();
 	morale->set(curHero);
 }
+
+bool CHeroWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return army == curHero;
+}

+ 1 - 0
client/windows/CHeroWindow.h

@@ -107,6 +107,7 @@ public:
 	void commanderWindow();
 	void switchHero(); //changes displayed hero
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 	void createBackpackWindow();
 
 	//friends

+ 33 - 0
client/windows/CKingdomInterface.cpp

@@ -662,6 +662,11 @@ void CKingdomInterface::updateGarrisons()
 		garrison->updateGarrisons();
 }
 
+bool CKingdomInterface::holdsGarrison(const CArmedInstance * army)
+{
+	return army->getOwner() == LOCPLINT->playerID;
+}
+
 void CKingdomInterface::artifactAssembled(const ArtifactLocation& artLoc)
 {
 	if(auto arts = std::dynamic_pointer_cast<CArtifactHolder>(tabArea->getItem()))
@@ -709,6 +714,15 @@ void CKingdHeroList::updateGarrisons()
 	}
 }
 
+bool CKingdHeroList::holdsGarrison(const CArmedInstance * army)
+{
+	for(std::shared_ptr<CIntObject> object : heroes->getItems())
+		if(IGarrisonHolder * garrison = dynamic_cast<IGarrisonHolder*>(object.get()))
+			if (garrison->holdsGarrison(army))
+				return true;
+	return false;
+}
+
 std::shared_ptr<CIntObject> CKingdHeroList::createHeroItem(size_t index)
 {
 	ui32 picCount = 4; // OVSLOT contains 4 images
@@ -761,6 +775,15 @@ void CKingdTownList::updateGarrisons()
 	}
 }
 
+bool CKingdTownList::holdsGarrison(const CArmedInstance * army)
+{
+	for(std::shared_ptr<CIntObject> object : towns->getItems())
+		if(IGarrisonHolder * garrison = dynamic_cast<IGarrisonHolder*>(object.get()))
+			if (garrison->holdsGarrison(army))
+				return true;
+	return false;
+}
+
 std::shared_ptr<CIntObject> CKingdTownList::createTownItem(size_t index)
 {
 	ui32 picCount = 4; // OVSLOT contains 4 images
@@ -836,6 +859,11 @@ void CTownItem::updateGarrisons()
 	garr->recreateSlots();
 }
 
+bool CTownItem::holdsGarrison(const CArmedInstance * army)
+{
+	return army == town || army == town->getUpperArmy() || army == town->visitingHero;
+}
+
 void CTownItem::update()
 {
 	std::string incomeVal = std::to_string(town->dailyIncome()[EGameResID::GOLD]);
@@ -998,6 +1026,11 @@ void CHeroItem::updateGarrisons()
 	garr->recreateSlots();
 }
 
+bool CHeroItem::holdsGarrison(const CArmedInstance * army)
+{
+	return hero == army;
+}
+
 std::shared_ptr<CIntObject> CHeroItem::onTabSelected(size_t index)
 {
 	return artTabs.at(index);

+ 5 - 0
client/windows/CKingdomInterface.h

@@ -253,6 +253,7 @@ public:
 	void townChanged(const CGTownInstance *town);
 	void heroRemoved();
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 	void artifactRemoved(const ArtifactLocation &artLoc) override;
 	void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc, bool withRedraw) override;
 	void artifactDisassembled(const ArtifactLocation &artLoc) override;
@@ -290,6 +291,7 @@ public:
 	CTownItem(const CGTownInstance * Town);
 
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 	void update();
 };
 
@@ -322,6 +324,7 @@ public:
 	std::shared_ptr<CArtifactsOfHeroKingdom> heroArts;
 
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 
 	CHeroItem(const CGHeroInstance * hero);
 };
@@ -340,6 +343,7 @@ public:
 	CKingdHeroList(size_t maxSize);
 
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 };
 
 /// Tab with all town-specific data
@@ -358,4 +362,5 @@ public:
 
 	void townChanged(const CGTownInstance * town);
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 };

+ 20 - 0
client/windows/GUIClasses.cpp

@@ -861,6 +861,11 @@ void CExchangeWindow::updateGarrisons()
 	updateWidgets();
 }
 
+bool CExchangeWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return garr->upperArmy() == army || garr->lowerArmy() == army;
+}
+
 void CExchangeWindow::questlog(int whichHero)
 {
 	CCS->curh->dragAndDropCursor(nullptr);
@@ -1008,6 +1013,11 @@ void CTransformerWindow::updateGarrisons()
 		item->update();
 }
 
+bool CTransformerWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return army == hero;
+}
+
 CTransformerWindow::CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero, const std::function<void()> & onWindowClosed)
 	: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("SKTRNBK")),
 	hero(_hero),
@@ -1251,6 +1261,11 @@ void CGarrisonWindow::updateGarrisons()
 	garr->recreateSlots();
 }
 
+bool CGarrisonWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return garr->upperArmy() == army || garr->lowerArmy() == army;
+}
+
 CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectInstance * object)
 	: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("APHLFTBK")),
 	fort(object),
@@ -1292,6 +1307,11 @@ CHillFortWindow::CHillFortWindow(const CGHeroInstance * visitor, const CGObjectI
 	updateGarrisons();
 }
 
+bool CHillFortWindow::holdsGarrison(const CArmedInstance * army)
+{
+	return hero == army;
+}
+
 void CHillFortWindow::updateGarrisons()
 {
 	std::array<TResources, slotsCount> costs;// costs [slot ID] [resource ID] = resource count for upgrade

+ 4 - 0
client/windows/GUIClasses.h

@@ -290,6 +290,7 @@ public:
 	std::array<std::shared_ptr<CArtifactsOfHeroMain>, 2> artifs;
 
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 
 	void questlog(int whichHero); //questlog button callback; whichHero: 0 - left, 1 - right
 
@@ -362,6 +363,7 @@ public:
 	void addAll();
 	void close() override;
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 	CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero, const std::function<void()> & onWindowClosed);
 };
 
@@ -443,6 +445,7 @@ public:
 	CGarrisonWindow(const CArmedInstance * up, const CGHeroInstance * down, bool removableUnits);
 
 	void updateGarrisons() override;
+	bool holdsGarrison(const CArmedInstance * army) override;
 };
 
 /// Hill fort is the building where you can upgrade units
@@ -482,6 +485,7 @@ private:
 public:
 	CHillFortWindow(const CGHeroInstance * visitor, const CGObjectInstance * object);
 	void updateGarrisons() override;//update buttons after garrison changes
+	bool holdsGarrison(const CArmedInstance * army) override;
 };
 
 class CThievesGuildWindow : public CStatusbarWindow