浏览代码

Fix possible assertion failure on removing non-owned town

Ivan Savenko 2 年之前
父节点
当前提交
1cbc6457ce

+ 6 - 0
AI/Nullkiller/AIGateway.cpp

@@ -448,6 +448,12 @@ void AIGateway::battleResultsApplied()
 	status.setBattle(NO_BATTLE);
 }
 
+void AIGateway::beforeObjectPropertyChanged(const SetObjectProperty * sop)
+{
+
+}
+
+
 void AIGateway::objectPropertyChanged(const SetObjectProperty * sop)
 {
 	LOG_TRACE(logAi);

+ 1 - 0
AI/Nullkiller/AIGateway.h

@@ -161,6 +161,7 @@ public:
 	void heroManaPointsChanged(const CGHeroInstance * hero) override;
 	void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
 	void battleResultsApplied() override;
+	void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
 	void objectPropertyChanged(const SetObjectProperty * sop) override;
 	void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
 	void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;

+ 5 - 0
AI/VCAI/VCAI.cpp

@@ -538,6 +538,11 @@ void VCAI::battleResultsApplied()
 	status.setBattle(NO_BATTLE);
 }
 
+void VCAI::beforeObjectPropertyChanged(const SetObjectProperty * sop)
+{
+
+}
+
 void VCAI::objectPropertyChanged(const SetObjectProperty * sop)
 {
 	LOG_TRACE(logAi);

+ 1 - 0
AI/VCAI/VCAI.h

@@ -194,6 +194,7 @@ public:
 	void heroManaPointsChanged(const CGHeroInstance * hero) override;
 	void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
 	void battleResultsApplied() override;
+	void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
 	void objectPropertyChanged(const SetObjectProperty * sop) override;
 	void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
 	void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;

+ 23 - 5
client/CPlayerInterface.cpp

@@ -1317,11 +1317,29 @@ void CPlayerInterface::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanc
 	GH.windows().createAndPushWindow<CExchangeWindow>(hero1, hero2, query);
 }
 
+void CPlayerInterface::beforeObjectPropertyChanged(const SetObjectProperty * sop)
+{
+	if (sop->what == ObjProperty::OWNER)
+	{
+		const CGObjectInstance * obj = cb->getObj(sop->id);
+
+		if(obj->ID == Obj::TOWN)
+		{
+			auto town = static_cast<const CGTownInstance *>(obj);
+
+			if(obj->tempOwner == playerID)
+			{
+				localState->removeOwnedTown(town);
+				adventureInt->onTownChanged(town);
+			}
+		}
+	}
+}
+
 void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	//redraw minimap if owner changed
 	if (sop->what == ObjProperty::OWNER)
 	{
 		const CGObjectInstance * obj = cb->getObj(sop->id);
@@ -1331,13 +1349,13 @@ void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop)
 			auto town = static_cast<const CGTownInstance *>(obj);
 
 			if(obj->tempOwner == playerID)
+			{
 				localState->addOwnedTown(town);
-			else
-				localState->removeOwnedTown(town);
-
-			adventureInt->onTownChanged(town);
+				adventureInt->onTownChanged(town);
+			}
 		}
 
+		//redraw minimap if owner changed
 		std::set<int3> pos = obj->getBlockedPos();
 		std::unordered_set<int3> upos(pos.begin(), pos.end());
 		adventureInt->onMapTilesChanged(upos);

+ 1 - 0
client/CPlayerInterface.h

@@ -144,6 +144,7 @@ protected: // Call-ins from server, should not be called directly, but only via
 	void requestRealized(PackageApplied *pa) override;
 	void heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID query) override;
 	void centerView (int3 pos, int focusTime) override;
+	void beforeObjectPropertyChanged(const SetObjectProperty * sop) override;
 	void objectPropertyChanged(const SetObjectProperty * sop) override;
 	void objectRemoved(const CGObjectInstance *obj) override;
 	void objectRemovedAfter() override;

+ 2 - 1
client/ClientNetPackVisitors.h

@@ -128,4 +128,5 @@ public:
 	virtual void visitBattleStackMoved(BattleStackMoved & pack) override;
 	virtual void visitBattleAttack(BattleAttack & pack) override;
 	virtual void visitStartAction(StartAction & pack) override;
-};
+	virtual void visitSetObjectProperty(SetObjectProperty & pack) override;
+};

+ 15 - 4
client/NetPacksClient.cpp

@@ -611,6 +611,20 @@ void ApplyClientNetPackVisitor::visitInfoWindow(InfoWindow & pack)
 		logNetwork->warn("We received InfoWindow for not our player...");
 }
 
+void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
+{
+	//inform all players that see this object
+	for(auto it = cl.playerint.cbegin(); it != cl.playerint.cend(); ++it)
+	{
+		if(gs.isVisible(gs.getObjInstance(pack.id), it->first))
+			callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::beforeObjectPropertyChanged, &pack);
+	}
+
+	// invalidate section of map view with our object and force an update with new flag color
+	if (pack.what == ObjProperty::OWNER)
+		CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
+}
+
 void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
 {
 	//inform all players that see this object
@@ -620,12 +634,9 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
 			callInterfaceIfPresent(cl, it->first, &IGameEventsReceiver::objectPropertyChanged, &pack);
 	}
 
+	// invalidate section of map view with our object and force an update with new flag color
 	if (pack.what == ObjProperty::OWNER)
-	{
-		// invalidate section of map view with our object and force an update with new flag color
-		CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
 		CGI->mh->onObjectInstantAdd(gs.getObjInstance(pack.id));
-	}
 }
 
 void ApplyClientNetPackVisitor::visitHeroLevelUp(HeroLevelUp & pack)

+ 1 - 0
lib/IGameEventsReceiver.h

@@ -127,6 +127,7 @@ public:
 	virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
 	virtual void requestSent(const CPackForServer *pack, int requestID){};
 	virtual void requestRealized(PackageApplied *pa){};
+	virtual void beforeObjectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
 	virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
 	virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
 	virtual void objectRemovedAfter(){}; //eg. collected resource, picked artifact, beaten hero