diff --git a/client/Client.cpp b/client/Client.cpp index 43c708ea7..2d57375ca 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -13,6 +13,7 @@ #include "CGameInfo.h" #include "CPlayerInterface.h" +#include "PlayerLocalState.h" #include "CServerHandler.h" #include "ClientNetPackVisitors.h" #include "adventureMap/AdventureMapInterface.h" @@ -495,6 +496,19 @@ void CClient::startPlayerBattleAction(const BattleID & battleID, PlayerColor col } } +void CClient::updatePath(const ObjectInstanceID & id) +{ + invalidatePaths(); + auto hero = getHero(id); + updatePath(hero); +} + +void CClient::updatePath(const CGHeroInstance * hero) +{ + if(LOCPLINT && hero) + LOCPLINT->localState->verifyPath(hero); +} + void CClient::invalidatePaths() { boost::unique_lock pathLock(pathCacheMutex); diff --git a/client/Client.h b/client/Client.h index c5b763a49..d63f70578 100644 --- a/client/Client.h +++ b/client/Client.h @@ -150,7 +150,9 @@ public: void battleFinished(const BattleID & battleID); void startPlayerBattleAction(const BattleID & battleID, PlayerColor color); - void invalidatePaths(); + void invalidatePaths(); // clears this->pathCache() + void updatePath(const ObjectInstanceID & heroID); // invalidatePaths and update displayed hero path + void updatePath(const CGHeroInstance * hero); std::shared_ptr getPathsInfo(const CGHeroInstance * h); friend class CCallback; //handling players actions diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index aadcdcc54..cda16c4b3 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -101,7 +101,7 @@ void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & bat { assert(cl.gameState()->getBattle(battleID)); - if (!cl.gameState()->getBattle(battleID)) + if(!cl.gameState()->getBattle(battleID)) { logGlobal->error("Attempt to call battle interface without ongoing battle!"); return; @@ -161,14 +161,14 @@ void ApplyClientNetPackVisitor::visitSetMana(SetMana & pack) if(settings["session"]["headless"].Bool()) return; - for (auto window : GH.windows().findWindows()) + for(auto window : GH.windows().findWindows()) window->heroManaPointsChanged(h); } void ApplyClientNetPackVisitor::visitSetMovePoints(SetMovePoints & pack) { const CGHeroInstance *h = cl.getHero(pack.hid); - cl.invalidatePaths(); + cl.updatePath(h); callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroMovePointsChanged, h); } @@ -229,7 +229,7 @@ void ApplyClientNetPackVisitor::visitSetStackType(SetStackType & pack) void ApplyClientNetPackVisitor::visitEraseStack(EraseStack & pack) { dispatchGarrisonChange(cl, pack.army, ObjectInstanceID()); - cl.invalidatePaths(); //it is possible to remove last non-native unit for current terrain and lose movement penalty + cl.updatePath(pack.army); //it is possible to remove last non-native unit for current terrain and lose movement penalty } void ApplyClientNetPackVisitor::visitSwapStacks(SwapStacks & pack) @@ -237,15 +237,14 @@ void ApplyClientNetPackVisitor::visitSwapStacks(SwapStacks & pack) dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy); if(pack.srcArmy != pack.dstArmy) - cl.invalidatePaths(); // adding/removing units may change terrain type penalty based on creature native terrains + cl.updatePath(pack.dstArmy); // adding/removing units may change terrain type penalty based on creature native terrains } void ApplyClientNetPackVisitor::visitInsertNewStack(InsertNewStack & pack) { dispatchGarrisonChange(cl, pack.army, ObjectInstanceID()); - if(gs.getHero(pack.army)) - cl.invalidatePaths(); // adding/removing units may change terrain type penalty based on creature native terrains + cl.updatePath(pack.army); // adding/removing units may change terrain type penalty based on creature native terrains } void ApplyClientNetPackVisitor::visitRebalanceStacks(RebalanceStacks & pack) @@ -253,7 +252,10 @@ void ApplyClientNetPackVisitor::visitRebalanceStacks(RebalanceStacks & pack) dispatchGarrisonChange(cl, pack.srcArmy, pack.dstArmy); if(pack.srcArmy != pack.dstArmy) - cl.invalidatePaths(); // adding/removing units may change terrain type penalty based on creature native terrains + { + cl.updatePath(pack.srcArmy); // adding/removing units may change terrain type penalty based on creature native terrains + cl.updatePath(pack.dstArmy); + } } void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & pack) @@ -266,7 +268,10 @@ void ApplyClientNetPackVisitor::visitBulkRebalanceStacks(BulkRebalanceStacks & p dispatchGarrisonChange(cl, pack.moves[0].srcArmy, destArmy); if(pack.moves[0].srcArmy != destArmy) - cl.invalidatePaths(); // adding/removing units may change terrain type penalty based on creature native terrains + { + cl.updatePath(destArmy); // adding/removing units may change terrain type penalty based on creature native terrains + cl.updatePath(pack.moves[0].srcArmy); + } } } @@ -292,6 +297,7 @@ void ApplyClientNetPackVisitor::visitPutArtifact(PutArtifact & pack) void ApplyClientNetPackVisitor::visitEraseArtifact(BulkEraseArtifacts & pack) { + cl.updatePath(pack.artHolder); for(const auto & slotErase : pack.posPack) callInterfaceIfPresent(cl, cl.getOwner(pack.artHolder), &IGameEventsReceiver::artifactRemoved, ArtifactLocation(pack.artHolder, slotErase)); } @@ -312,7 +318,8 @@ void ApplyClientNetPackVisitor::visitBulkMoveArtifacts(BulkMoveArtifacts & pack) if(pack.interfaceOwner != dstOwner) callInterfaceIfPresent(cl, dstOwner, &IGameEventsReceiver::artifactMoved, srcLoc, dstLoc); - cl.invalidatePaths(); // hero might have equipped/unequipped Angel Wings + cl.updatePath(pack.srcArtHolder); // hero might have equipped/unequipped Angel Wings + cl.updatePath(pack.dstArtHolder); } }; @@ -342,14 +349,14 @@ void ApplyClientNetPackVisitor::visitAssembledArtifact(AssembledArtifact & pack) { callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactAssembled, pack.al); - cl.invalidatePaths(); // hero might have equipped/unequipped Angel Wings + cl.updatePath(pack.al.artHolder); // hero might have equipped/unequipped Angel Wings } void ApplyClientNetPackVisitor::visitDisassembledArtifact(DisassembledArtifact & pack) { callInterfaceIfPresent(cl, cl.getOwner(pack.al.artHolder), &IGameEventsReceiver::artifactDisassembled, pack.al); - cl.invalidatePaths(); // hero might have equipped/unequipped Angel Wings + cl.updatePath(pack.al.artHolder); // hero might have equipped/unequipped Angel Wings } void ApplyClientNetPackVisitor::visitHeroVisit(HeroVisit & pack) @@ -363,7 +370,7 @@ void ApplyClientNetPackVisitor::visitNewTurn(NewTurn & pack) { cl.invalidatePaths(); - if (pack.newWeekNotification) + if(pack.newWeekNotification) { const auto & newWeek = *pack.newWeekNotification; @@ -380,7 +387,7 @@ void ApplyClientNetPackVisitor::visitGiveBonus(GiveBonus & pack) case GiveBonus::ETarget::OBJECT: { const CGHeroInstance *h = gs.getHero(pack.id.as()); - if (h) + if(h) callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, true); } break; @@ -419,7 +426,7 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack) bool lastHumanEndsGame = CSH->howManyPlayerInterfaces() == 1 && vstd::contains(cl.playerint, pack.player) && cl.getPlayerState(pack.player)->human && !settings["session"]["spectate"].Bool(); - if (lastHumanEndsGame) + if(lastHumanEndsGame) { assert(adventureInt); if(adventureInt) @@ -446,9 +453,9 @@ void ApplyClientNetPackVisitor::visitPlayerReinitInterface(PlayerReinitInterface { cl.initPlayerInterfaces(); - for (PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player) + for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player) { - if (cl.gameState()->isPlayerMakingTurn(player)) + if(cl.gameState()->isPlayerMakingTurn(player)) { callAllInterfaces(cl, &IGameEventsReceiver::playerStartsTurn, player); callOnlyThatInterface(cl, player, &CGameInterface::yourTurn, QueryID::NONE); @@ -482,7 +489,7 @@ void ApplyClientNetPackVisitor::visitRemoveBonus(RemoveBonus & pack) case GiveBonus::ETarget::OBJECT: { const CGHeroInstance *h = gs.getHero(pack.whoID.as()); - if (h) + if(h) callInterfaceIfPresent(cl, h->tempOwner, &IGameEventsReceiver::heroBonusChanged, h, pack.bonus, false); } break; @@ -701,7 +708,7 @@ void ApplyFirstClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & } // invalidate section of map view with our object and force an update with new flag color - if (pack.what == ObjProperty::OWNER && CGI->mh) + if(pack.what == ObjProperty::OWNER && CGI->mh) { auto object = gs.getObjInstance(pack.id); CGI->mh->onObjectInstantRemove(object, object->getOwner()); @@ -718,7 +725,7 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack) } // invalidate section of map view with our object and force an update with new flag color - if (pack.what == ObjProperty::OWNER && CGI->mh) + if(pack.what == ObjProperty::OWNER && CGI->mh) { auto object = gs.getObjInstance(pack.id); CGI->mh->onObjectInstantAdd(object, object->getOwner()); @@ -807,7 +814,7 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & const CStack *activated = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack); PlayerColor playerToCall; //pack.player that will move activated stack - if (activated->hasBonusOfType(BonusType::HYPNOTIZED)) + if(activated->hasBonusOfType(BonusType::HYPNOTIZED)) { playerToCall = gs.getBattle(pack.battleID)->getSide(BattleSide::ATTACKER).color == activated->unitOwner() ? gs.getBattle(pack.battleID)->getSide(BattleSide::DEFENDER).color