From 68cc86013319148137e1f488826addb90e836160 Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Wed, 28 Oct 2015 23:53:44 +0300 Subject: [PATCH 1/4] Fix dynamic_cast on MacOSX in CQuery.cpp --- server/CGameHandler.cpp | 92 ++++++++++++++++++++--------------------- server/CQuery.cpp | 47 +++++++++++---------- server/StdInc.h | 14 +++++++ 3 files changed, 85 insertions(+), 68 deletions(-) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 17b0f7ed6..9a13c3285 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -65,14 +65,14 @@ class ServerSpellCastEnvironment: public SpellCastEnvironment public: ServerSpellCastEnvironment(CGameHandler * gh); ~ServerSpellCastEnvironment(){}; - void sendAndApply(CPackForClient * info) const override; + void sendAndApply(CPackForClient * info) const override; CRandomGenerator & getRandomGenerator() const override; void complain(const std::string & problem) const override; const CMap * getMap() const override; const CGameInfoCallback * getCb() const override; - bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const override; + bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const override; private: - mutable CGameHandler * gh; + mutable CGameHandler * gh; }; CondSh battleMadeAction; @@ -102,7 +102,7 @@ public: } }; -template <> +template <> class CApplyOnGH : public CBaseForGHApply { public: @@ -799,15 +799,15 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt const Bonus * bonus = att->getBonusLocalFirst(Selector::type(Bonus::SPELL_LIKE_ATTACK)); if (bonus && (bat.shot())) //TODO: make it work in melee? - { + { //this is need for displaying hit animation bat.flags |= BattleAttack::SPELL_LIKE; bat.spellID = SpellID(bonus->subtype); - + //TODO: should spell override creature`s projectile? - + std::set attackedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att->owner, bonus->val, targetHex, att); - + //TODO: get exact attacked hex for defender for(const CStack * stack : attackedCreatures) @@ -817,7 +817,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt applyBattleEffects(bat, att, stack, distance, true); } } - + //now add effect info for all attacked stacks for(BattleStackAttacked & bsa : bat.bsa) { @@ -828,7 +828,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt bsa.spellID = SpellID(bonus->subtype); } } - + } } void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, const CStack *def, int distance, bool secondary) //helper function for prepareAttack @@ -917,7 +917,7 @@ void CGameHandler::handleConnection(std::set players, CConnection & c << &applied; }; - CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object + CBaseForGHApply *apply = applier->apps[packType]; //and appropriate applier object if(isBlockedByQueries(pack, player)) { sendPackageResponse(false); @@ -1026,7 +1026,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest) int v = path.first.size()-1; bool stackIsMoving = true; - + while(stackIsMoving) { if(vstopsMovement() || !curStack->alive()) stackIsMoving = false; - obs.reset(); + obs.reset(); } }; - + processObstacle(obstacle); if(curStack->alive()) processObstacle(obstacle2); @@ -1105,14 +1105,14 @@ int CGameHandler::moveStack(int stack, BattleHex dest) if(curStack->alive() && curStack->doubleWide()) { BattleHex otherHex = curStack->occupiedHex(curStack->position); - + if(otherHex.isValid()) if(auto theLastObstacle = battleGetObstacleOnPos(otherHex, false)) { //two hex creature hit obstacle by backside handleDamageFromObstacle(*theLastObstacle, curStack); } - } + } return ret; } @@ -1125,7 +1125,7 @@ CGameHandler::CGameHandler(void) registerTypesServerPacks(*applier); visitObjectAfterVictory = false; queries.gh = this; - + spellEnv = new ServerSpellCastEnvironment(this); } @@ -3907,8 +3907,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) complain("That stack can't cast spells!"); else { - const CSpell * spell = SpellID(spellID).toSpell(); - BattleSpellCastParameters parameters(gs->curB, stack, spell); + const CSpell * spell = SpellID(spellID).toSpell(); + BattleSpellCastParameters parameters(gs->curB, stack, spell); parameters.spellLvl = 0; if (spellcaster) vstd::amax(parameters.spellLvl, spellcaster->val); @@ -3940,12 +3940,12 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message { SetMana sm; GiveBonus giveBonus(GiveBonus::HERO); - + CGHeroInstance *h = gs->getHero(currObj); if(!h && complain("Cannot realize cheat, no hero selected!")) return; sm.hid = h->id; - + giveBonus.id = h->id.getNum(); //give all spells with bonus (to allow banned spells) @@ -4107,11 +4107,11 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) } const CSpell * s = SpellID(ba.additionalInfo).toSpell(); - + BattleSpellCastParameters parameters(gs->curB, h, s); parameters.aimToHex(ba.destinationTile);//todo: allow multiple destinations parameters.mode = ECastingMode::HERO_CASTING; - parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); + parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h, s, ECastingMode::HERO_CASTING);//todo: should we check aimed cast(battleCanCastThisSpellHere)? if(escp != ESpellCastProblem::OK) @@ -4123,9 +4123,9 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) StartAction start_action(ba); sendAndApply(&start_action); //start spell casting - + s->battleCast(spellEnv, parameters); - + sendAndApply(&end_action); if( !gs->curB->battleGetStackByID(gs->curB->activeStack, true)) { @@ -4255,8 +4255,8 @@ void CGameHandler::stackTurnTrigger(const CStack * st) auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator()); auto spellID = SpellID(bonus->subtype); const CSpell * spell = SpellID(spellID).toSpell(); - bl.remove_if([&bonus](Bonus * b){return b==bonus;}); - + bl.remove_if([&bonus](Bonus * b){return b==bonus;}); + if (gs->curB->battleCanCastThisSpell(st, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK) { BattleSpellCastParameters parameters(gs->curB, st, spell); @@ -4265,8 +4265,8 @@ void CGameHandler::stackTurnTrigger(const CStack * st) parameters.aimToHex(BattleHex::INVALID); parameters.mode = ECastingMode::ENCHANTER_CASTING; parameters.selectedStack = nullptr; - - spell->battleCast(spellEnv, parameters); + + spell->battleCast(spellEnv, parameters); //todo: move to mechanics BattleSetStackProperty ssp; @@ -4275,9 +4275,9 @@ void CGameHandler::stackTurnTrigger(const CStack * st) ssp.val = bonus->additionalInfo; //increase cooldown counter ssp.stackID = st->ID; sendAndApply(&ssp); - + cast = true; - } + } }; } bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTED))); @@ -4383,7 +4383,7 @@ void CGameHandler::handleTimeEvents() while(gs->map->events.size() && gs->map->events.front().firstOccurence+1 == gs->day) { CMapEvent ev = gs->map->events.front(); - + for (int player = 0; player < PlayerColor::PLAYER_LIMIT_I; player++) { auto color = PlayerColor(player); @@ -4973,7 +4973,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; parameters.selectedStack = nullptr; - spell->battleCast(spellEnv, parameters); + spell->battleCast(spellEnv, parameters); } } } @@ -4990,7 +4990,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking); if (!attacker) //could be already dead return; - + auto cast = [=](SpellID spellID, int power) { const CSpell * spell = SpellID(spellID).toSpell(); @@ -4999,13 +4999,13 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) parameters.spellLvl = 0; parameters.effectLevel = 0; parameters.aimToStack(gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)); - parameters.effectPower = power; + parameters.effectPower = power; parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; parameters.selectedStack = nullptr; - spell->battleCast(this->spellEnv, parameters); - }; - + spell->battleCast(this->spellEnv, parameters); + }; + attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker); if(bat.bsa.at(0).newAmount <= 0) @@ -5056,11 +5056,11 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int3 &pos) { const CSpell *s = spellID.toSpell(); - + AdventureSpellCastParameters p; p.caster = h; p.pos = pos; - + return s->adventureCast(spellEnv, p); } @@ -5298,8 +5298,8 @@ void CGameHandler::runBattle() auto h = gs->curB->battleGetFightingHero(i); if(h && h->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL)) { - TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL)); - + TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL)); + for (Bonus *b : *bl) { const CSpell * spell = SpellID(b->subtype).toSpell(); @@ -5308,7 +5308,7 @@ void CGameHandler::runBattle() parameters.effectLevel = 3; parameters.aimToHex(BattleHex::INVALID); parameters.mode = ECastingMode::PASSIVE_CASTING; - parameters.selectedStack = nullptr; + parameters.selectedStack = nullptr; parameters.enchantPower = b->val; spell->battleCast(spellEnv, parameters); } @@ -5347,7 +5347,6 @@ void CGameHandler::runBattle() const CStack *next; while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove()) { - //check for bad morale => freeze int nextStackMorale = next->MoraleVal(); if( nextStackMorale < 0 && @@ -5483,7 +5482,7 @@ void CGameHandler::runBattle() { logGlobal->traceStream() << "Activating " << next->nodeName(); auto nextId = next->ID; - BattleSetActiveStack sas; + BattleSetActiveStack sas; sas.stack = nextId; sendAndApply(&sas); @@ -5900,7 +5899,7 @@ CGameHandler::FinishingBattleHelper::FinishingBattleHelper() ///ServerSpellCastEnvironment ServerSpellCastEnvironment::ServerSpellCastEnvironment(CGameHandler * gh): gh(gh) { - + } void ServerSpellCastEnvironment::sendAndApply(CPackForClient * info) const @@ -5933,4 +5932,3 @@ bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, ui8 te { return gh->moveHero(hid, dst, teleporting, false, asker); } - diff --git a/server/CQuery.cpp b/server/CQuery.cpp index f03e50e63..e3d36b52d 100644 --- a/server/CQuery.cpp +++ b/server/CQuery.cpp @@ -97,11 +97,11 @@ CObjectVisitQuery::CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroIn addPlayer(Hero->tempOwner); } -bool CObjectVisitQuery::blocksPack(const CPack *pack) const +bool CObjectVisitQuery::blocksPack(const CPack *pack) const { //During the visit itself ALL actions are blocked. //(However, the visit may trigger a query above that'll pass some.) - return true; + return true; } void CObjectVisitQuery::onRemoval(CGameHandler *gh, PlayerColor color) @@ -220,7 +220,7 @@ std::vector> Queries::allQueries() return ret; } -void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { assert(result); objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result); @@ -242,9 +242,14 @@ CBattleQuery::CBattleQuery() } -bool CBattleQuery::blocksPack(const CPack *pack) const +bool CBattleQuery::blocksPack(const CPack *pack) const { - return !dynamic_cast(pack) && !dynamic_cast(pack); + #ifndef __APPLE__ + bool dynamic_success = !dynamic_cast(pack) && !dynamic_cast(pack); + #else + const char * name = typeid(*pack).name(); + return strcmp(name, typeid(MakeAction).name()) && strcmp(name, typeid(MakeCustomAction).name()); + #endif } void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color) @@ -252,7 +257,7 @@ void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color) gh->battleAfterLevelUp(*result); } -void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { objectVisit.visitedObject->garrisonDialogClosed(objectVisit.visitingHero); } @@ -266,18 +271,18 @@ CGarrisonDialogQuery::CGarrisonDialogQuery(const CArmedInstance *up, const CArme addPlayer(down->tempOwner); } -bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const +bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const { std::set ourIds; ourIds.insert(this->exchangingArmies[0]->id); ourIds.insert(this->exchangingArmies[1]->id); - - if (auto stacks = dynamic_cast(pack)) + if (auto stacks = dynamic_ptr_cast(pack)) { return !vstd::contains(ourIds, stacks->id1) || !vstd::contains(ourIds, stacks->id2); } - if (auto arts = dynamic_cast(pack)) + + if (auto arts = dynamic_ptr_cast(pack)) { if(auto id1 = boost::apply_visitor(GetEngagedHeroIds(), arts->src.artHolder)) if(!vstd::contains(ourIds, *id1)) @@ -288,24 +293,24 @@ bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const return true; return false; } - if (auto dismiss = dynamic_cast(pack)) + if (auto dismiss = dynamic_ptr_cast(pack)) { return !vstd::contains(ourIds, dismiss->id); } - if (auto dismiss = dynamic_cast(pack)) + if (auto dismiss = dynamic_ptr_cast(pack)) { return !vstd::contains(ourIds, dismiss->heroID); } - - if(auto upgrade = dynamic_cast(pack)) + + if(auto upgrade = dynamic_ptr_cast(pack)) { return !vstd::contains(ourIds, upgrade->id); } return CDialogQuery::blocksPack(pack); } -void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { assert(answer); objectVisit.visitedObject->blockingDialogAnswered(objectVisit.visitingHero, *answer); @@ -319,7 +324,7 @@ CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd) void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { - auto obj = dynamic_cast(objectVisit.visitedObject); + auto obj = dynamic_ptr_cast(objectVisit.visitedObject); obj->teleportDialogAnswered(objectVisit.visitingHero, *answer, td.exits); } @@ -342,7 +347,7 @@ void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) gh->levelUpHero(hlu.hero, hlu.skills[*answer]); } -void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); } @@ -360,20 +365,20 @@ void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]); } -void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); } -bool CDialogQuery::endsByPlayerAnswer() const +bool CDialogQuery::endsByPlayerAnswer() const { return true; } -bool CDialogQuery::blocksPack(const CPack *pack) const +bool CDialogQuery::blocksPack(const CPack *pack) const { //We accept only query replies from correct player - if(auto reply = dynamic_cast(pack)) + if(auto reply = dynamic_ptr_cast(pack)) { return !vstd::contains(players, reply->player); } diff --git a/server/StdInc.h b/server/StdInc.h index 7418241e0..e2e51512e 100644 --- a/server/StdInc.h +++ b/server/StdInc.h @@ -8,3 +8,17 @@ #include #include #include + +template +inline const T * dynamic_ptr_cast(const F * ptr) +{ + #ifndef __APPLE__ + return dynamic_cast(ptr); + #else + if (!strcmp(typeid(*ptr).name(), typeid(T).name())) + { + return static_cast(ptr); + } + return nullptr; + #endif +} From fa8a2826963b3089a758beea6e61af0a660bdbf6 Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Sat, 31 Oct 2015 18:04:06 +0300 Subject: [PATCH 2/4] Fix pthread_mutex_lock abort() in requestActionASAP impl --- AI/VCAI/VCAI.cpp | 35 ++++++++++++++--------------------- server/CGameHandler.cpp | 4 ++-- server/CVCMIServer.cpp | 32 ++++++++++++++++---------------- server/NetPacksServer.cpp | 16 ++++++++-------- server/StdInc.h | 14 ++++++++++++++ 5 files changed, 54 insertions(+), 47 deletions(-) diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 6048e6487..b42d9eb64 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -822,7 +822,7 @@ void VCAI::makeTurnInternal() { if (h->movement) logAi->warnStream() << boost::format("hero %s has %d MP left") % h->name % h->movement; - } + } } catch(boost::thread_interrupted &e) { @@ -891,7 +891,7 @@ bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * sourc const CArmedInstance *armies[] = {army, source}; - + //we calculate total strength for each creature type available in armies std::map creToPower; for(auto armyPtr : armies) @@ -988,7 +988,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance * } void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other) -{ +{ auto equipBest = [](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void { bool changeMade = false; @@ -2059,7 +2059,7 @@ void VCAI::tryRealize(Goals::CollectRes & g) cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive); if(cb->getResourceAmount(static_cast(g.resID)) >= g.value) return; - } + } throw cannotFulfillGoalException("I cannot get needed resources by trade!"); } @@ -2277,7 +2277,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on completeGoal (goal); //completed goal was main goal //TODO: find better condition if (ultimateGoal->fulfillsMe(goal) || maxGoals > searchDepth2) - return sptr(Goals::Invalid()); + return sptr(Goals::Invalid()); } catch(std::exception &e) { @@ -2530,7 +2530,7 @@ int3 VCAI::explorationDesperate(HeroPtr h) //logAi->debugStream() << "Looking for an another place for exploration..."; SectorMap sm(h); int radius = h->getSightRadious(); - + std::vector > tiles; //tiles[distance_to_fow] tiles.resize(radius); @@ -2660,19 +2660,13 @@ void VCAI::finish() void VCAI::requestActionASAP(std::function whatToDo) { -// static boost::mutex m; -// boost::unique_lock mylock(m); - - boost::barrier b(2); - boost::thread newThread([&b,this,whatToDo]() + boost::thread newThread([this, whatToDo]() { - setThreadName("VCAI::requestActionASAP::helper"); + setThreadName("VCAI::requestActionASAP::whatToDo"); SET_GLOBAL_STATE(this); boost::shared_lock gsLock(cb->getGsMutex()); - b.wait(); whatToDo(); }); - b.wait(); } void VCAI::lostHero(HeroPtr h) @@ -2867,8 +2861,8 @@ void AIStatus::heroVisit(const CGObjectInstance *obj, bool started) objectsBeingVisited.push_back(obj); else { - // There can be more than one object visited at the time (eg. hero visits Subterranean Gate - // causing visit to hero on the other side. + // There can be more than one object visited at the time (eg. hero visits Subterranean Gate + // causing visit to hero on the other side. // However, we are guaranteed that start/end visit notification maintain stack order. assert(!objectsBeingVisited.empty()); objectsBeingVisited.pop_back(); @@ -2980,7 +2974,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp) s.embarkmentPoints.push_back(neighPos); } }); - + if(t->visitable) { auto obj = t->visitableObjects.front(); @@ -3036,7 +3030,7 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj) bool shouldVisit(HeroPtr h, const CGObjectInstance * obj) { switch (obj->ID) - { + { case Obj::TOWN: case Obj::HERO: //never visit our heroes at random return obj->tempOwner != h->tempOwner; //do not visit our towns at random @@ -3087,7 +3081,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj) return canRecruitCreatures; } case Obj::HILL_FORT: - { + { for (auto slot : h->Slots()) { if (slot.second->type->upgrades.size()) @@ -3386,7 +3380,7 @@ void SectorMap::makeParentBFS(crint3 source) ui8 &sec = retreiveTile(curPos); assert(sec == mySector); //consider only tiles from the same sector UNUSED(sec); - + foreach_neighbour(curPos, [&](crint3 neighPos) { if(retreiveTile(neighPos) == mySector && !vstd::contains(parent, neighPos)) @@ -3405,4 +3399,3 @@ unsigned char & SectorMap::retreiveTile(crint3 pos) { return retreiveTileN(sector, pos); } - diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 9a13c3285..3529c7d0b 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5688,7 +5688,7 @@ bool CGameHandler::isValidObject(const CGObjectInstance *obj) const bool CGameHandler::isBlockedByQueries(const CPack *pack, PlayerColor player) { - if(dynamic_cast(pack)) + if(!strcmp(typeid(*pack).name(), typeid(PlayerMessage).name())) return false; auto query = queries.topQuery(player); @@ -5826,7 +5826,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleI auto warMachine = VLC->arth->creatureToMachineID(st->type->idNumber); if (warMachine != ArtifactID::NONE) { - auto hero = dynamic_cast (army); + auto hero = dynamic_ptr_cast (army); if (hero) removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true))); } diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 1dc10fe67..cb8b690f8 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -86,8 +86,8 @@ void CPregameServer::handleConnection(CConnection *cpc) logNetwork->infoStream() << "Got package to announce " << typeid(*cpfs).name() << " from " << *cpc; boost::unique_lock queueLock(mx); - bool quitting = dynamic_cast(cpfs), - startingGame = dynamic_cast(cpfs); + bool quitting = dynamic_ptr_cast(cpfs), + startingGame = dynamic_ptr_cast(cpfs); if(quitting || startingGame) //host leaves main menu or wants to start game -> we end { cpc->receivedStop = true; @@ -258,11 +258,11 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen & *pc << &pack; } - if(dynamic_cast(&pack)) + if(dynamic_ptr_cast(&pack)) { pc->sendStop = true; } - else if(dynamic_cast(&pack)) + else if(dynamic_ptr_cast(&pack)) { pc->sendStop = true; } @@ -270,25 +270,25 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen & void CPregameServer::processPack(CPackForSelectionScreen * pack) { - if(dynamic_cast(pack)) + if(dynamic_ptr_cast(pack)) { sendPack(host, *pack); } - else if(SelectMap *sm = dynamic_cast(pack)) + else if(SelectMap *sm = dynamic_ptr_cast(pack)) { vstd::clear_pointer(curmap); curmap = sm->mapInfo; sm->free = false; announcePack(*pack); } - else if(UpdateStartOptions *uso = dynamic_cast(pack)) + else if(UpdateStartOptions *uso = dynamic_ptr_cast(pack)) { vstd::clear_pointer(curStartInfo); curStartInfo = uso->options; uso->free = false; announcePack(*pack); } - else if(dynamic_cast(pack)) + else if(dynamic_ptr_cast(pack)) { state = ENDING_AND_STARTING_GAME; announcePack(*pack); @@ -307,7 +307,7 @@ void CPregameServer::initConnection(CConnection *c) } void CPregameServer::startListeningThread(CConnection * pc) -{ +{ listeningThreads++; pc->enterPregameConnectionMode(); pc->handler = new boost::thread(&CPregameServer::handleConnection, this, pc); @@ -355,7 +355,7 @@ void CVCMIServer::newGame() { CConnection &c = *firstConnection; ui8 clients; - c >> clients; //how many clients should be connected + c >> clients; //how many clients should be connected assert(clients == 1); //multi goes now by newPregame, TODO: custom lobbies CGameHandler *gh = initGhFromHostingConnection(c); @@ -469,14 +469,14 @@ void CVCMIServer::loadGame() // char sig[8]; // CMapHeader dum; // StartInfo *si; -// +// // CLoadFile lf(CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME))); // lf >> sig >> dum >> si; // logNetwork->infoStream() <<"Reading save signature"; -// +// // lf >> *VLC; // logNetwork->infoStream() <<"Reading handlers"; -// +// // lf >> (gh.gs); // c.addStdVecItems(gh.gs); // logNetwork->infoStream() <<"Reading gamestate"; @@ -493,7 +493,7 @@ void CVCMIServer::loadGame() CConnection* cc; //tcp::socket * ss; for(int i=0; iteleportHero(hid,dest,source,gh->getPlayerAt(c)); } @@ -126,7 +126,7 @@ bool GarrisonHeroSwap::applyGh( CGameHandler *gh ) { const CGTownInstance * town = gh->getTown(tid); if (!PLAYER_OWNS(tid) && !( town->garrisonHero && PLAYER_OWNS(town->garrisonHero->id) ) ) - ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours + ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours return gh->garrisonSwap(tid); } @@ -201,7 +201,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh ) } bool SetFormation::applyGh( CGameHandler *gh ) -{ +{ ERROR_IF_NOT_OWNS(hid); return gh->setFormation(hid,formation); } @@ -209,7 +209,7 @@ bool SetFormation::applyGh( CGameHandler *gh ) bool HireHero::applyGh( CGameHandler *gh ) { const CGObjectInstance *obj = gh->getObj(tid); - const CGTownInstance *town = dynamic_cast(obj); + const CGTownInstance *town = dynamic_ptr_cast(obj); if(town && PlayerRelations::ENEMIES == gh->getPlayerRelations(obj->tempOwner, gh->getPlayerAt(c))) COMPLAIN_AND_RETURN("Can't buy hero in enemy town!"); @@ -240,16 +240,16 @@ bool MakeAction::applyGh( CGameHandler *gh ) { const BattleInfo *b = GS(gh)->curB; if(!b) ERROR_AND_RETURN; - + if(b->tacticDistance) { - if(ba.actionType != Battle::WALK && ba.actionType != Battle::END_TACTIC_PHASE + if(ba.actionType != Battle::WALK && ba.actionType != Battle::END_TACTIC_PHASE && ba.actionType != Battle::RETREAT && ba.actionType != Battle::SURRENDER) ERROR_AND_RETURN; - if(gh->connections[b->sides[b->tacticsSide].color] != c) + if(gh->connections[b->sides[b->tacticsSide].color] != c) ERROR_AND_RETURN; } - else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c) + else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c) ERROR_AND_RETURN; return gh->makeBattleAction(ba); diff --git a/server/StdInc.h b/server/StdInc.h index e2e51512e..08c4b8424 100644 --- a/server/StdInc.h +++ b/server/StdInc.h @@ -22,3 +22,17 @@ inline const T * dynamic_ptr_cast(const F * ptr) return nullptr; #endif } + +template +inline T * dynamic_ptr_cast(F * ptr) +{ + #ifndef __APPLE__ + return dynamic_cast(ptr); + #else + if (!strcmp(typeid(*ptr).name(), typeid(T).name())) + { + return static_cast(ptr); + } + return nullptr; + #endif +} From e6e975e9ef0c1d74db4ccc01a54ebf9634edb649 Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Sat, 31 Oct 2015 20:23:13 +0300 Subject: [PATCH 3/4] Fix adventure map movement segfault in some scenarios --- client/windows/CAdvmapInterface.cpp | 35 +++++++++++++++-------------- lib/CGameState.cpp | 10 ++++----- lib/CGameStateFwd.h | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/client/windows/CAdvmapInterface.cpp b/client/windows/CAdvmapInterface.cpp index e1b96e049..92622c738 100644 --- a/client/windows/CAdvmapInterface.cpp +++ b/client/windows/CAdvmapInterface.cpp @@ -62,9 +62,9 @@ CAdvMapInt *adventureInt; CTerrainRect::CTerrainRect() - : fadeSurface(nullptr), + : fadeSurface(nullptr), fadeAnim(new CFadeAnimation()), - curHoveredTile(-1,-1,-1), + curHoveredTile(-1,-1,-1), currentPath(nullptr) { tilesw=(ADVOPT.advmapW+31)/32; @@ -283,7 +283,7 @@ void CTerrainRect::show(SDL_Surface * to) info.heroAnim = adventureInt->heroAnim; if (ADVOPT.smoothMove) info.movement = int3(moveX, moveY, 0); - + lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info); if (fadeAnim->isFading()) { @@ -316,7 +316,7 @@ void CTerrainRect::showAll(SDL_Surface * to) } void CTerrainRect::showAnim(SDL_Surface * to) -{ +{ if (fadeAnim->isFading()) show(to); else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED) @@ -357,7 +357,7 @@ void CTerrainRect::fadeFromCurrentView() return; if (adventureInt->mode == EAdvMapMode::WORLD_VIEW) return; - + if (!fadeSurface) fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h); SDL_BlitSurface(screen, &pos, fadeSurface, nullptr); @@ -502,10 +502,10 @@ CAdvMapInt::CAdvMapInt(): endTurn = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e); int panelSpaceBottom = screen->h - resdatabar.pos.h - 4; - + panelMain = new CAdvMapPanel(nullptr, Point(0, 0)); // TODO correct drawing position - panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); + panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); panelMain->addChildColorableButton(kingOverview); panelMain->addChildColorableButton(underground); @@ -593,7 +593,7 @@ CAdvMapInt::CAdvMapInt(): Colors::WHITE, CGI->generaltexth->allTexts[618])); activeMapPanel = panelMain; - + changeMode(EAdvMapMode::NORMAL); underground->block(!CGI->mh->map->twoLevel); @@ -966,7 +966,7 @@ void CAdvMapInt::show(SDL_Surface * to) for(int i=0;i<4;i++) blitAt(gems[i]->ourImages[LOCPLINT->playerID.getNum()].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to); } - + infoBar.show(to); statusbar.showAll(to); } @@ -981,7 +981,7 @@ void CAdvMapInt::selectionChanged() void CAdvMapInt::centerOn(int3 on, bool fade /* = false */) { bool switchedLevels = on.z != position.z; - + if (fade) { terrain.fadeFromCurrentView(); @@ -1534,7 +1534,9 @@ void CAdvMapInt::tileHovered(const int3 &mapPos) } else if(const CGHeroInstance *h = curHero()) { - const CGPathNode *pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPos); + int3 mapPosCopy = mapPos; + const CGPathNode *pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPosCopy); + assert(pnode); int turns = pnode->turns; vstd::amin(turns, 3); @@ -1780,9 +1782,9 @@ void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale /* = 0.4f */) townList.activate(); heroList.activate(); infoBar.activate(); - + worldViewOptions.clear(); - + break; case EAdvMapMode::WORLD_VIEW: panelMain->deactivate(); @@ -1852,14 +1854,13 @@ CAdvMapInt::WorldViewOptions::WorldViewOptions() void CAdvMapInt::WorldViewOptions::clear() { showAllTerrain = false; - + iconPositions.clear(); } void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info) { info.showAllTerrain = showAllTerrain; - - info.additionalIcons = &iconPositions; -} + info.additionalIcons = &iconPositions; +} diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 41b138b08..51f8e8bd5 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -674,8 +674,8 @@ void CGameState::randomizeObject(CGObjectInstance *cur) } else { - cur->setType(ran.first, ran.second); - } + cur->setType(ran.first, ran.second); + } } int CGameState::getDate(Date::EDateType mode) const @@ -2899,11 +2899,11 @@ bool CGPathNode::reachable() const return turns < 255; } -const CGPathNode * CPathsInfo::getPathInfo( int3 tile ) const +const CGPathNode * CPathsInfo::getPathInfo( const int3& tile ) const { boost::unique_lock pathLock(pathMx); - - if (tile.x >= sizes.x || tile.y >= sizes.y || tile.z >= sizes.z) + if (tile.x >= sizes.x || tile.y >= sizes.y || tile.z >= sizes.z || + tile.x < 0 || tile.y < 0 || tile.z < 0) return nullptr; return &nodes[tile.x][tile.y][tile.z]; } diff --git a/lib/CGameStateFwd.h b/lib/CGameStateFwd.h index 5dc1672b6..8e6196ef1 100644 --- a/lib/CGameStateFwd.h +++ b/lib/CGameStateFwd.h @@ -158,7 +158,7 @@ struct DLL_LINKAGE CPathsInfo int3 sizes; CGPathNode ***nodes; //[w][h][level] - const CGPathNode * getPathInfo( int3 tile ) const; + const CGPathNode * getPathInfo( const int3& tile ) const; bool getPath(const int3 &dst, CGPath &out) const; int getDistance( int3 tile ) const; CPathsInfo(const int3 &Sizes); From 5c623868bf814cecb160d7cf92a0ab0c8f54a78c Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Sat, 31 Oct 2015 23:01:22 +0300 Subject: [PATCH 4/4] Fix invalid dynamic_cast replacement --- server/CQuery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/CQuery.cpp b/server/CQuery.cpp index e3d36b52d..7e1a53433 100644 --- a/server/CQuery.cpp +++ b/server/CQuery.cpp @@ -324,7 +324,7 @@ CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd) void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const { - auto obj = dynamic_ptr_cast(objectVisit.visitedObject); + auto obj = dynamic_cast(objectVisit.visitedObject); obj->teleportDialogAnswered(objectVisit.visitingHero, *answer, td.exits); }