فهرست منبع

Fixed at least two #1428 freezes, likely more.
They were occurring when AI hero visited bank that was also guarded by neutral creature nearby,

Michał W. Urbańczyk 12 سال پیش
والد
کامیت
d1807585ad
8فایلهای تغییر یافته به همراه71 افزوده شده و 12 حذف شده
  1. 31 6
      AI/VCAI/VCAI.cpp
  2. 5 1
      AI/VCAI/VCAI.h
  3. 1 1
      client/NetPacksClient.cpp
  4. 1 1
      lib/IGameEventsReceiver.h
  5. 5 3
      lib/NetPacks.h
  6. 1 0
      server/CGameHandler.cpp
  7. 24 0
      server/CQuery.cpp
  8. 3 0
      server/CQuery.h

+ 31 - 6
AI/VCAI/VCAI.cpp

@@ -493,12 +493,15 @@ void VCAI::showThievesGuildWindow (const CGObjectInstance * obj)
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::playerBlocked(int reason)
+void VCAI::playerBlocked(int reason, bool start)
 {
-	LOG_TRACE_PARAMS(logAi, "reason '%i'", reason);
+	LOG_TRACE_PARAMS(logAi, "reason '%i', start '%i'", reason % start);
 	NET_EVENT_HANDLER;
-	if (reason == PlayerBlocked::UPCOMING_BATTLE)
+	if (start && reason == PlayerBlocked::UPCOMING_BATTLE)
 		status.setBattle(UPCOMING_BATTLE);
+
+	if(reason == PlayerBlocked::ONGOING_MOVEMENT)
+		status.setMove(start);
 }
 
 void VCAI::showPuzzleMap()
@@ -571,15 +574,17 @@ void VCAI::artifactDisassembled(const ArtifactLocation &al)
 
 void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
 {
-	LOG_TRACE_PARAMS(logAi, "start '%i'", start);
+	LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->hoverName : std::string("n/a")));
 	NET_EVENT_HANDLER;
-	if (start)
+	if(start)
 	{
 		markObjectVisited (visitedObj);
 		erase_if_present(reservedObjs, visitedObj); //unreserve objects
 		erase_if_present(reservedHeroesMap[visitor], visitedObj);
 		completeGoal (CGoal(GET_OBJ).sethero(visitor)); //we don't need to visit in anymore
 	}
+
+	status.heroVisit(visitedObj, start);
 }
 
 void VCAI::availableArtifactsChanged(const CGBlackMarket *bm /*= nullptr*/)
@@ -2701,7 +2706,7 @@ void AIStatus::madeTurn()
 void AIStatus::waitTillFree()
 {
 	boost::unique_lock<boost::mutex> lock(mx);
-	while(battle != NO_BATTLE || remainingQueries.size())
+	while(battle != NO_BATTLE || remainingQueries.size() || objectsBeingVisited.size() || ongoingHeroMovement)
 		cv.wait(lock);
 }
 
@@ -2738,6 +2743,26 @@ void AIStatus::receivedAnswerConfirmation(int answerRequestID, int result)
 	}
 }
 
+void AIStatus::heroVisit(const CGObjectInstance *obj, bool started)
+{
+	boost::unique_lock<boost::mutex> lock(mx);
+	if(started)
+		objectsBeingVisited.push_back(obj);
+	else
+	{
+		assert(objectsBeingVisited.size() == 1);
+		objectsBeingVisited.clear();
+	}
+	cv.notify_all();
+}
+
+void AIStatus::setMove(bool ongoing)
+{
+	boost::unique_lock<boost::mutex> lock(mx);
+	ongoingHeroMovement = ongoing;
+	cv.notify_all();
+}
+
 int3 whereToExplore(HeroPtr h)
 {
 	//TODO it's stupid and ineffective, write sth better

+ 5 - 1
AI/VCAI/VCAI.h

@@ -75,6 +75,8 @@ class AIStatus
 	BattleState battle;
 	std::map<QueryID, std::string> remainingQueries;
 	std::map<int, QueryID> requestToQueryID; //IDs of answer-requests sent to server => query ids (so we can match answer confirmation from server to the query)
+	std::vector<const CGObjectInstance*> objectsBeingVisited;
+	bool ongoingHeroMovement;
 
 	bool havingTurn;
 
@@ -82,6 +84,7 @@ public:
 	AIStatus();
 	~AIStatus();
 	void setBattle(BattleState BS);
+	void setMove(bool ongoing);
 	BattleState getBattle();
 	void addQuery(QueryID ID, std::string description);
 	void removeQuery(QueryID ID);
@@ -92,6 +95,7 @@ public:
 	bool haveTurn();
 	void attemptedAnsweringQuery(QueryID queryID, int answerRequestID);
 	void receivedAnswerConfirmation(int answerRequestID, int result);
+	void heroVisit(const CGObjectInstance *obj, bool started);
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -327,7 +331,7 @@ public:
 	virtual void artifactAssembled(const ArtifactLocation &al) override;
 	virtual void showTavernWindow(const CGObjectInstance *townOrTavern) override;
 	virtual void showThievesGuildWindow (const CGObjectInstance * obj) override;
-	virtual void playerBlocked(int reason) override;
+	virtual void playerBlocked(int reason, bool start) override;
 	virtual void showPuzzleMap() override;
 	virtual void showShipyardDialog(const IShipyard *obj) override;
 	virtual void gameOver(PlayerColor player, bool victory) override;

+ 1 - 1
client/NetPacksClient.cpp

@@ -791,7 +791,7 @@ void SystemMessage::applyCl( CClient *cl )
 
 void PlayerBlocked::applyCl( CClient *cl )
 {
-	INTERFACE_CALL_IF_PRESENT(player,playerBlocked,reason);
+	INTERFACE_CALL_IF_PRESENT(player,playerBlocked,reason, startOrEnd==BLOCKADE_STARTED);
 }
 
 void YourTurn::applyCl( CClient *cl )

+ 1 - 1
lib/IGameEventsReceiver.h

@@ -127,7 +127,7 @@ public:
 	virtual void requestRealized(PackageApplied *pa){};
 	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 playerBlocked(int reason){}; //reason: 0 - upcoming battle
+	virtual void playerBlocked(int reason, bool start){}; //reason: 0 - upcoming battle
 	virtual void gameOver(PlayerColor player, bool victory){}; //player lost or won the game
 	virtual void playerStartsTurn(PlayerColor player){};
 	virtual void showComp(const Component &comp, std::string message) {}; //display component in the advmapint infobox

+ 5 - 3
lib/NetPacks.h

@@ -230,14 +230,16 @@ struct PlayerBlocked : public CPackForClient //96
 	PlayerBlocked(){type = 96;};
 	void applyCl(CClient *cl);
 
-	enum EReason { UPCOMING_BATTLE };
-
+	enum EReason { UPCOMING_BATTLE, ONGOING_MOVEMENT };
+	enum EMode { BLOCKADE_STARTED, BLOCKADE_ENDED };
+	
 	EReason reason;
+	EMode startOrEnd;
 	PlayerColor player;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & reason & player;
+		h & reason & startOrEnd & player;
 	}
 };
 

+ 1 - 0
server/CGameHandler.cpp

@@ -5037,6 +5037,7 @@ void CGameHandler::engageIntoBattle( PlayerColor player )
 	PlayerBlocked pb;
 	pb.player = player;
 	pb.reason = PlayerBlocked::UPCOMING_BATTLE;
+	pb.startOrEnd = PlayerBlocked::BLOCKADE_STARTED;
 	sendAndApply(&pb);
 }
 

+ 24 - 0
server/CQuery.cpp

@@ -86,6 +86,11 @@ void CQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
 	gh->queries.popQuery(*this);
 }
 
+void CQuery::onAdding(CGameHandler *gh, PlayerColor color)
+{
+
+}
+
 CObjectVisitQuery::CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile)
 	: visitedObject(Obj), visitingHero(Hero), tile(Tile), removeObjectAfterVisit(false)
 {
@@ -169,6 +174,7 @@ void Queries::addQuery(QueryPtr query)
 void Queries::addQuery(PlayerColor player, QueryPtr query)
 {
 	LOG_TRACE_PARAMS(logGlobal, "player='%s', query='%s'", player % query);
+	query->onAdding(gh, player);
 	queries[player].push_back(query);
 }
 
@@ -372,3 +378,21 @@ void CHeroMovementQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
 
 	gh->queries.popIfTop(*this);
 }
+
+void CHeroMovementQuery::onRemoval(CGameHandler *gh, PlayerColor color)
+{
+	PlayerBlocked pb;
+	pb.player = color;
+	pb.reason = PlayerBlocked::ONGOING_MOVEMENT;
+	pb.startOrEnd = PlayerBlocked::BLOCKADE_ENDED;
+	gh->sendAndApply(&pb);
+}
+
+void CHeroMovementQuery::onAdding(CGameHandler *gh, PlayerColor color)
+{
+	PlayerBlocked pb;
+	pb.player = color;
+	pb.reason = PlayerBlocked::ONGOING_MOVEMENT;
+	pb.startOrEnd = PlayerBlocked::BLOCKADE_STARTED;
+	gh->sendAndApply(&pb);
+}

+ 3 - 0
server/CQuery.h

@@ -36,6 +36,7 @@ public:
 	virtual bool blocksPack(const CPack *pack) const; //query can block attempting actions by player. Eg. he can't move hero during the battle.
 
 	virtual bool endsByPlayerAnswer() const; //query is removed after player gives answer (like dialogs)
+	virtual void onAdding(CGameHandler *gh, PlayerColor color); //called just before query is pushed on stack
 	virtual void onRemoval(CGameHandler *gh, PlayerColor color); //called after query is removed from stack
 	virtual void onExposure(CGameHandler *gh, QueryPtr topQuery);//called when query immediately above is removed and this is exposed (becomes top)
 	virtual std::string toString() const;
@@ -98,6 +99,8 @@ public:
 	virtual void onExposure(CGameHandler *gh, QueryPtr topQuery);
 
 	CHeroMovementQuery(const TryMoveHero &Tmh, const CGHeroInstance *Hero, bool VisitDestAfterVictory = false);
+	virtual void onAdding(CGameHandler *gh, PlayerColor color) override;
+	virtual void onRemoval(CGameHandler *gh, PlayerColor color) override;
 };
 
 class CDialogQuery : public CQuery