2
0
Эх сурвалжийг харах

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 жил өмнө
parent
commit
d1807585ad

+ 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