1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Fixed at least two #1428 freezes, likely more.

They were occurring when AI hero visited bank that was also guarded by neutral creature nearby,
This commit is contained in:
Michał W. Urbańczyk
2013-09-27 23:46:58 +00:00
parent 0a0048fdf4
commit d1807585ad
8 changed files with 71 additions and 12 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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 )

View File

@@ -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

View File

@@ -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;
}
};

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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