diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 91ff712de4c..8e3de0da1bd 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -937,7 +937,8 @@ void Combat::addDistanceEffect(std::shared_ptr caster, const Position void Combat::doChainEffect(const Position &origin, const Position &dest, uint8_t effect) { if (effect > 0) { - stdext::arraylist dirList(128); + std::vector dirList; + FindPathParams fpp; fpp.minTargetDist = 0; fpp.maxTargetDist = 1; diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index b9603d010a2..34db29dcd4a 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -1926,7 +1926,7 @@ bool ConditionFeared::getFleeDirection(std::shared_ptr creature) { return false; } -bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList) { +bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, std::vector &dirList) { const std::vector walkSize { 15, 9, 3, 1 }; bool found = false; std::ptrdiff_t found_size = 0; @@ -2029,7 +2029,7 @@ bool ConditionFeared::startCondition(std::shared_ptr creature) { bool ConditionFeared::executeCondition(std::shared_ptr creature, int32_t interval) { Position currentPos = creature->getPosition(); - stdext::arraylist listDir(128); + std::vector listDir; g_logger().debug("[ConditionFeared::executeCondition] Executing condition, current position is {}", currentPos.toString()); @@ -2039,7 +2039,7 @@ bool ConditionFeared::executeCondition(std::shared_ptr creature, int32 } if (getFleePath(creature, currentPos, listDir)) { - g_dispatcher().addEvent([id = creature->getID(), listDir = listDir.data()] { + g_dispatcher().addEvent([id = creature->getID(), listDir] { g_game().forcePlayerAutoWalk(id, listDir); }, "ConditionFeared::executeCondition"); diff --git a/src/creatures/combat/condition.hpp b/src/creatures/combat/condition.hpp index 07b31b42d15..2b28029bcef 100644 --- a/src/creatures/combat/condition.hpp +++ b/src/creatures/combat/condition.hpp @@ -333,7 +333,7 @@ class ConditionFeared final : public Condition { private: bool canWalkTo(std::shared_ptr creature, Position pos, Direction moveDirection) const; bool getFleeDirection(std::shared_ptr creature); - bool getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList); + bool getFleePath(std::shared_ptr creature, const Position &pos, std::vector &dirList); bool getRandomDirection(std::shared_ptr creature, Position pos); bool isStuck(std::shared_ptr creature, Position pos) const; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index e3474ab2436..94795669561 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -213,8 +213,8 @@ bool Creature::getNextStep(Direction &dir, uint32_t &) { return false; } - dir = listWalkDir.front(); - listWalkDir.pop_front(); + dir = listWalkDir.back(); + listWalkDir.pop_back(); onWalk(dir); return true; } @@ -814,7 +814,6 @@ bool Creature::dropCorpse(std::shared_ptr lastHitCreature, std::shared player->sendLootMessage(lootMessage.str()); } - stdext::arraylist dirList(128); FindPathParams fpp; fpp.minTargetDist = 0; fpp.maxTargetDist = 1; @@ -822,6 +821,7 @@ bool Creature::dropCorpse(std::shared_ptr lastHitCreature, std::shared fpp.clearSight = true; fpp.maxSearchDist = 0; + std::vector dirList; auto isReachable = g_game().map.getPathMatching(player->getPosition(), dirList, FrozenPathingConditionCall(corpse->getPosition()), fpp); if (player->checkAutoLoot(monster->isRewardBoss()) && isReachable) { @@ -1078,7 +1078,8 @@ void Creature::goToFollowCreature() { } bool executeOnFollow = true; - stdext::arraylist listDir(128); + std::vector listDir; + listDir.reserve(128); FindPathParams fpp; getPathSearchParams(followCreature, fpp); @@ -1101,7 +1102,7 @@ void Creature::goToFollowCreature() { hasFollowPath = getPathTo(followCreature->getPosition(), listDir, fpp); } - startAutoWalk(listDir.data()); + startAutoWalk(listDir); if (executeOnFollow) { onFollowCreatureComplete(followCreature); @@ -1737,12 +1738,15 @@ bool Creature::isInvisible() const { != conditions.end(); } -bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp) { +bool Creature::getPathTo(const Position &targetPos, std::vector &dirList, const FindPathParams &fpp) { metrics::method_latency measure(__METHOD_NAME__); - return g_game().map.getPathMatching(getCreature(), dirList, FrozenPathingConditionCall(targetPos), fpp); + if (fpp.maxSearchDist != 0 || fpp.keepDistance) { + return g_game().map.getPathMatchingCond(getCreature(), targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp); + } + return g_game().map.getPathMatching(getCreature(), targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp); } -bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { +bool Creature::getPathTo(const Position &targetPos, std::vector &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { FindPathParams fpp; fpp.fullPathSearch = fullPathSearch; fpp.maxSearchDist = maxSearchDist; diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index edf2fa55b74..138e8b364c8 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -584,8 +584,8 @@ class Creature : virtual public Thing, public SharedObject { double getDamageRatio(std::shared_ptr attacker) const; - bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp); - bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); + bool getPathTo(const Position &targetPos, std::vector &dirList, const FindPathParams &fpp); + bool getPathTo(const Position &targetPos, std::vector &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); struct CountBlock_t { int32_t total; @@ -720,7 +720,7 @@ class Creature : virtual public Thing, public SharedObject { CreatureEventList eventsList; ConditionList conditions; - std::deque listWalkDir; + std::vector listWalkDir; std::weak_ptr m_tile; std::weak_ptr m_attackedCreature; diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 4b993cbab0e..575ee321914 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -1257,12 +1257,12 @@ void Monster::doWalkBack(uint32_t &flags, Direction &nextDirection, bool &result return; } - stdext::arraylist listDir(128); + std::vector listDir; if (!getPathTo(masterPos, listDir, 0, std::max(0, distance - 5), true, true, distance)) { isWalkingBack = false; return; } - startAutoWalk(listDir.data()); + startAutoWalk(listDir); } } diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index fdbf58853b4..18ca0dd0758 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -522,7 +522,7 @@ void Npc::onThinkWalk(uint32_t interval) { if (Direction newDirection; getRandomStep(newDirection)) { - listWalkDir.push_front(newDirection); + listWalkDir.emplace_back(newDirection); addEventWalk(); } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index a6db39f587d..c2d8c7a8c70 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -7818,9 +7818,9 @@ SoundEffect_t Player::getAttackSoundEffect() const { bool Player::canAutoWalk(const Position &toPosition, const std::function &function, uint32_t delay /* = 500*/) { if (!Position::areInRange<1, 1>(getPosition(), toPosition)) { // Check if can walk to the toPosition and send event to use function - stdext::arraylist listDir(128); + std::vector listDir; if (getPathTo(toPosition, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([creatureId = getID(), dirs = listDir.data()] { g_game().playerAutoWalk(creatureId, dirs); }, __FUNCTION__); + g_dispatcher().addEvent([creatureId = getID(), listDir] { g_game().playerAutoWalk(creatureId, listDir); }, __FUNCTION__); std::shared_ptr task = createPlayerTask(delay, function, __FUNCTION__); setNextWalkActionTask(task); diff --git a/src/game/game.cpp b/src/game/game.cpp index b353537cf0c..8cc6754392c 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1405,9 +1405,9 @@ void Game::playerMoveCreature(std::shared_ptr player, std::shared_ptr(movingCreatureOrigPos, player->getPosition())) { // need to walk to the creature first before moving it - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(movingCreatureOrigPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); const auto &task = createPlayerTask( 600, [this, player, movingCreature, toTile, movingCreatureOrigPos] { playerMoveCreatureByID(player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()); }, "Game::playerMoveCreatureByID" ); @@ -1694,9 +1694,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo if (!Position::areInRange<1, 1>(playerPos, mapFromPos)) { // need to walk to the item first before using it - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(item->getPosition(), listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId = player->getID(), fromPos, itemId, fromStackPos, toPos, count] { @@ -1756,9 +1756,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo internalGetPosition(moveItem, itemPos, itemStackPos); } - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(walkPos, listDir, 0, 0, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId = player->getID(), itemPos, itemId, itemStackPos, toPos, count] { @@ -3681,9 +3681,9 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f internalGetPosition(moveItem, itemPos, itemStackPos); } - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId] { playerUseItemEx(playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId); }, "Game::playerUseItemEx" @@ -3795,9 +3795,9 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo ReturnValue ret = g_actions().canUse(player, pos); if (ret != RETURNVALUE_NOERROR) { if (ret == RETURNVALUE_TOOFARAWAY) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, index, itemId] { playerUseItem(playerId, pos, stackPos, index, itemId); }, "Game::playerUseItem" @@ -3952,9 +3952,9 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin internalGetPosition(moveItem, itemPos, itemStackPos); } - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, itemPos, itemStackPos, creatureId, itemId] { @@ -4113,9 +4113,9 @@ void Game::playerRotateItem(uint32_t playerId, const Position &pos, uint8_t stac } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, itemId] { @@ -4169,9 +4169,9 @@ void Game::playerConfigureShowOffSocket(uint32_t playerId, const Position &pos, bool isPodiumOfRenown = itemId == ITEM_PODIUM_OF_RENOWN1 || itemId == ITEM_PODIUM_OF_RENOWN2; if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task; if (isPodiumOfRenown) { task = createPlayerTask( @@ -4230,9 +4230,9 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" ); @@ -4371,9 +4371,9 @@ void Game::playerWrapableItem(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, itemId] { playerWrapableItem(playerId, pos, stackPos, itemId); }, "Game::playerWrapableItem" @@ -4552,9 +4552,9 @@ void Game::playerBrowseField(uint32_t playerId, const Position &pos) { } if (!Position::areInRange<1, 1>(playerPos, pos)) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" ); @@ -4815,9 +4815,9 @@ void Game::playerRequestTrade(uint32_t playerId, const Position &pos, uint8_t st } if (!Position::areInRange<1, 1>(tradeItemPosition, playerPosition)) { - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, tradePlayerId, itemId] { playerRequestTrade(playerId, pos, stackPos, tradePlayerId, itemId); }, "Game::playerRequestTrade" @@ -5394,9 +5394,9 @@ void Game::playerQuickLoot(uint32_t playerId, const Position &pos, uint16_t item if (!autoLoot && pos.x != 0xffff) { if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { // need to walk to the corpse first before looting it - stdext::arraylist listDir(128); + std::vector listDir; if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 0, [this, playerId = player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot] { playerQuickLoot(playerId, pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot); @@ -9486,9 +9486,9 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (stdext::arraylist listDir(128); + if (std::vector listDir; player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" ); @@ -9586,9 +9586,9 @@ void Game::playerRotatePodium(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (stdext::arraylist listDir(128); + if (std::vector listDir; player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); + g_dispatcher().addEvent([this, playerId = player->getID(), listDir] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, itemId] { playerRotatePodium(playerId, pos, stackPos, itemId); diff --git a/src/game/scheduling/task.hpp b/src/game/scheduling/task.hpp index 7bdc7db8084..9c561b41381 100644 --- a/src/game/scheduling/task.hpp +++ b/src/game/scheduling/task.hpp @@ -69,32 +69,30 @@ class Task { } bool hasTraceableContext() const { - const static auto tasksContext = std::unordered_set({ - "Decay::checkDecay", - "Dispatcher::asyncEvent", - "Game::checkCreatureAttack", - "Game::checkCreatureWalk", - "Game::checkCreatures", - "Game::checkImbuements", - "Game::checkLight", - "Game::createFiendishMonsters", - "Game::createInfluencedMonsters", - "Game::updateCreatureWalk", - "Game::updateForgeableMonsters", - "GlobalEvents::think", - "LuaEnvironment::executeTimerEvent", - "Modules::executeOnRecvbyte", - "OutputMessagePool::sendAll", - "ProtocolGame::addGameTask", - "ProtocolGame::parsePacketFromDispatcher", - "Raids::checkRaids", - "SpawnMonster::checkSpawnMonster", - "SpawnMonster::scheduleSpawn", - "SpawnMonster::startup", - "SpawnNpc::checkSpawnNpc", - "Webhook::run", - "Protocol::sendRecvMessageCallback", - }); + const static auto tasksContext = std::unordered_set({ "Decay::checkDecay", + "Dispatcher::asyncEvent", + "Game::checkCreatureAttack", + "Game::checkCreatureWalk", + "Game::checkCreatures", + "Game::checkImbuements", + "Game::checkLight", + "Game::createFiendishMonsters", + "Game::createInfluencedMonsters", + "Game::updateCreatureWalk", + "Game::updateForgeableMonsters", + "GlobalEvents::think", + "LuaEnvironment::executeTimerEvent", + "Modules::executeOnRecvbyte", + "OutputMessagePool::sendAll", + "ProtocolGame::addGameTask", + "ProtocolGame::parsePacketFromDispatcher", + "Raids::checkRaids", + "SpawnMonster::checkSpawnMonster", + "SpawnMonster::scheduleSpawn", + "SpawnMonster::startup", + "SpawnNpc::checkSpawnNpc", + "Webhook::run", + "Protocol::sendRecvMessageCallback" }); return tasksContext.contains(context); } diff --git a/src/lua/functions/creatures/creature_functions.cpp b/src/lua/functions/creatures/creature_functions.cpp index 4ae5da0e132..6b09945971a 100644 --- a/src/lua/functions/creatures/creature_functions.cpp +++ b/src/lua/functions/creatures/creature_functions.cpp @@ -938,7 +938,7 @@ int CreatureFunctions::luaCreatureGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - stdext::arraylist dirList(128); + std::vector dirList; if (creature->getPathTo(position, dirList, fpp)) { lua_newtable(L); diff --git a/src/lua/functions/map/position_functions.cpp b/src/lua/functions/map/position_functions.cpp index 579304266c0..0e4397f3fce 100644 --- a/src/lua/functions/map/position_functions.cpp +++ b/src/lua/functions/map/position_functions.cpp @@ -97,7 +97,7 @@ int PositionFunctions::luaPositionGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - stdext::arraylist dirList(128); + std::vector dirList; if (g_game().map.getPathMatching(pos, dirList, FrozenPathingConditionCall(position), fpp)) { lua_newtable(L); diff --git a/src/map/map.cpp b/src/map/map.cpp index 7406ecffbdf..0d9a38b7cc1 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -638,11 +638,7 @@ std::shared_ptr Map::canWalkTo(const std::shared_ptr &creature, return tile; } -bool Map::getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { - return getPathMatching(creature, creature->getPosition(), dirList, pathCondition, fpp); -} - -bool Map::getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { +bool Map::getPathMatching(const std::shared_ptr &creature, const Position &__targetPos, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { static int_fast32_t allNeighbors[8][2] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }; @@ -658,15 +654,25 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } }; - Position pos = startPos; + const bool withoutCreature = creature == nullptr; + + Position pos = withoutCreature ? __targetPos : creature->getPosition(); Position endPos; - AStarNodes nodes(pos.x, pos.y); + AStarNodes nodes(pos.x, pos.y, AStarNodes::getTileWalkCost(creature, getTile(pos.x, pos.y, pos.z))); int32_t bestMatch = 0; + const auto &startPos = pos; + const auto &targetPos = withoutCreature ? pathCondition.getTargetPos() : __targetPos; + + const int_fast32_t sX = std::abs(targetPos.getX() - pos.getX()); + const int_fast32_t sY = std::abs(targetPos.getY() - pos.getY()); + + uint_fast16_t cntDirs = 0; + AStarNode* found = nullptr; - while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { + do { AStarNode* n = nodes.getBestNode(); if (!n) { if (found) { @@ -687,6 +693,8 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit } } + ++cntDirs; + uint_fast32_t dirCount; int_fast32_t* neighbors; if (n->parent) { @@ -698,7 +706,7 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit } else { neighbors = *dirNeighbors[DIRECTION_EAST]; } - } else if (!fpp.allowDiagonal || offset_x == 0) { + } else if (offset_x == 0) { if (offset_y == -1) { neighbors = *dirNeighbors[DIRECTION_NORTH]; } else { @@ -715,7 +723,7 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit } else { neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; } - dirCount = fpp.allowDiagonal ? 5 : 3; + dirCount = 5; } else { dirCount = 8; neighbors = *allNeighbors; @@ -726,6 +734,185 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit pos.x = x + *neighbors++; pos.y = y + *neighbors++; + int_fast32_t extraCost; + AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); + if (neighborNode) { + extraCost = neighborNode->c; + } else { + const auto &tile = withoutCreature ? getTile(pos.x, pos.y, pos.z) : canWalkTo(creature, pos); + if (!tile) { + continue; + } + extraCost = AStarNodes::getTileWalkCost(creature, tile); + } + + // The cost (g) for this neighbor + const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos); + const int_fast32_t newf = f + cost + extraCost; + if (neighborNode) { + if (neighborNode->f <= newf) { + // The node on the closed/open list is cheaper than this one + continue; + } + neighborNode->f = newf; + neighborNode->parent = n; + nodes.openNode(neighborNode); + } else { + // Does not exist in the open/closed list, create a new node + const int_fast32_t dX = std::abs(targetPos.getX() - pos.getX()); + const int_fast32_t dY = std::abs(targetPos.getY() - pos.getY()); + if (!nodes.createOpenNode(n, pos.x, pos.y, newf, ((dX - sX) << 3) + ((dY - sY) << 3) + (std::max(dX, dY) << 3), extraCost)) { + if (found) { + break; + } + return false; + } + } + } + nodes.closeNode(n); + } while (nodes.getClosedNodes() < 100); + if (!found) { + return false; + } + + int_fast32_t prevx = endPos.x; + int_fast32_t prevy = endPos.y; + + dirList.reserve(cntDirs); + + found = found->parent; + while (found) { + pos.x = found->x; + pos.y = found->y; + + int_fast32_t dx = pos.getX() - prevx; + int_fast32_t dy = pos.getY() - prevy; + + prevx = pos.x; + prevy = pos.y; + if (dx == 1) { + if (dy == 1) { + dirList.emplace_back(DIRECTION_NORTHWEST); + } else if (dy == -1) { + dirList.emplace_back(DIRECTION_SOUTHWEST); + } else { + dirList.emplace_back(DIRECTION_WEST); + } + } else if (dx == -1) { + if (dy == 1) { + dirList.emplace_back(DIRECTION_NORTHEAST); + } else if (dy == -1) { + dirList.emplace_back(DIRECTION_SOUTHEAST); + } else { + dirList.emplace_back(DIRECTION_EAST); + } + } else if (dy == 1) { + dirList.emplace_back(DIRECTION_NORTH); + } else if (dy == -1) { + dirList.emplace_back(DIRECTION_SOUTH); + } + found = found->parent; + } + + return true; +} + +bool Map::getPathMatching(const std::shared_ptr &creature, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + return getPathMatching(creature, creature->getPosition(), dirList, pathCondition, fpp); +} + +bool Map::getPathMatchingCond(const std::shared_ptr &creature, const Position &targetPos, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + Position pos = creature->getPosition(); + Position endPos; + + AStarNodes nodes(pos.x, pos.y, AStarNodes::getTileWalkCost(creature, getTile(pos.x, pos.y, pos.z))); + + int32_t bestMatch = 0; + + static int_fast32_t dirNeighbors[8][5][2] = { + { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }, + { { -1, 0 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 1 } }, + { { -1, 0 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 } }, + { { 0, 1 }, { 1, 0 }, { 0, -1 }, { 1, -1 }, { 1, 1 } }, + { { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 } }, + { { -1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { -1, 1 } }, + { { 0, 1 }, { 1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }, + { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } + }; + + static int_fast32_t allNeighbors[8][2] = { + { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } + }; + + const Position startPos = pos; + + const int_fast32_t sX = std::abs(targetPos.getX() - pos.getX()); + const int_fast32_t sY = std::abs(targetPos.getY() - pos.getY()); + + uint_fast16_t cntDirs = 0; + + AStarNode* found = nullptr; + do { + AStarNode* n = nodes.getBestNode(); + if (!n) { + if (found) { + break; + } + return false; + } + + const int_fast32_t x = n->x; + const int_fast32_t y = n->y; + pos.x = x; + pos.y = y; + if (pathCondition(startPos, pos, fpp, bestMatch)) { + found = n; + endPos = pos; + if (bestMatch == 0) { + break; + } + } + + ++cntDirs; + + uint_fast32_t dirCount; + int_fast32_t* neighbors; + if (n->parent) { + const int_fast32_t offset_x = n->parent->x - x; + const int_fast32_t offset_y = n->parent->y - y; + if (offset_y == 0) { + if (offset_x == -1) { + neighbors = *dirNeighbors[DIRECTION_WEST]; + } else { + neighbors = *dirNeighbors[DIRECTION_EAST]; + } + } else if (offset_x == 0) { + if (offset_y == -1) { + neighbors = *dirNeighbors[DIRECTION_NORTH]; + } else { + neighbors = *dirNeighbors[DIRECTION_SOUTH]; + } + } else if (offset_y == -1) { + if (offset_x == -1) { + neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; + } else { + neighbors = *dirNeighbors[DIRECTION_NORTHEAST]; + } + } else if (offset_x == -1) { + neighbors = *dirNeighbors[DIRECTION_SOUTHWEST]; + } else { + neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; + } + dirCount = 5; + } else { + dirCount = 8; + neighbors = *allNeighbors; + } + + const int_fast32_t f = n->f; + for (uint_fast32_t i = 0; i < dirCount; ++i) { + pos.x = x + *neighbors++; + pos.y = y + *neighbors++; if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } @@ -734,33 +921,34 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit continue; } + int_fast32_t extraCost; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); - - const bool withoutCreature = creature == nullptr; - const auto &tile = neighborNode || withoutCreature ? getTile(pos.x, pos.y, pos.z) : canWalkTo(creature, pos); - - if (!tile || (!neighborNode && withoutCreature && tile->hasFlag(TILESTATE_BLOCKSOLID))) { - continue; + if (neighborNode) { + extraCost = neighborNode->c; + } else { + const auto &tile = Map::canWalkTo(creature, pos); + if (!tile) { + continue; + } + extraCost = AStarNodes::getTileWalkCost(creature, tile); } // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos, withoutCreature); - const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); + const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos); const int_fast32_t newf = f + cost + extraCost; - if (neighborNode) { if (neighborNode->f <= newf) { // The node on the closed/open list is cheaper than this one continue; } - neighborNode->f = newf; neighborNode->parent = n; nodes.openNode(neighborNode); } else { - // Does not exist in the open/closed list, create a std::make_shared - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); - if (!neighborNode) { + // Does not exist in the open/closed list, create a new node + const int_fast32_t dX = std::abs(targetPos.getX() - pos.getX()); + const int_fast32_t dY = std::abs(targetPos.getY() - pos.getY()); + if (!nodes.createOpenNode(n, pos.x, pos.y, newf, ((dX - sX) << 3) + ((dY - sY) << 3) + (std::max(dX, dY) << 3), extraCost)) { if (found) { break; } @@ -768,9 +956,8 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit } } } - nodes.closeNode(n); - } + } while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100); if (!found) { return false; @@ -779,37 +966,42 @@ bool Map::getPathMatching(const std::shared_ptr &creature, const Posit int_fast32_t prevx = endPos.x; int_fast32_t prevy = endPos.y; + dirList.reserve(cntDirs); + found = found->parent; while (found) { pos.x = found->x; pos.y = found->y; - const int_fast32_t dx = pos.getX() - prevx; - const int_fast32_t dy = pos.getY() - prevy; + int_fast32_t dx = pos.getX() - prevx; + int_fast32_t dy = pos.getY() - prevy; prevx = pos.x; prevy = pos.y; - - if (dx == 1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHWEST); - } else if (dx == -1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHEAST); - } else if (dx == 1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHWEST); - } else if (dx == -1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHEAST); - } else if (dx == 1) { - dirList.push_front(DIRECTION_WEST); + if (dx == 1) { + if (dy == 1) { + dirList.emplace_back(DIRECTION_NORTHWEST); + } else if (dy == -1) { + dirList.emplace_back(DIRECTION_SOUTHWEST); + } else { + dirList.emplace_back(DIRECTION_WEST); + } } else if (dx == -1) { - dirList.push_front(DIRECTION_EAST); + if (dy == 1) { + dirList.emplace_back(DIRECTION_NORTHEAST); + } else if (dy == -1) { + dirList.emplace_back(DIRECTION_SOUTHEAST); + } else { + dirList.emplace_back(DIRECTION_EAST); + } } else if (dy == 1) { - dirList.push_front(DIRECTION_NORTH); + dirList.emplace_back(DIRECTION_NORTH); } else if (dy == -1) { - dirList.push_front(DIRECTION_SOUTH); + dirList.emplace_back(DIRECTION_SOUTH); } - found = found->parent; } + return true; } diff --git a/src/map/map.hpp b/src/map/map.hpp index bae07445156..a2000766382 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -123,9 +123,11 @@ class Map : public MapCache { std::shared_ptr canWalkTo(const std::shared_ptr &creature, const Position &pos); - bool getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const std::shared_ptr &creature, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const std::shared_ptr &creature, const Position &targetPos, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatchingCond(const std::shared_ptr &creature, const Position &targetPos, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); - bool getPathMatching(const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + bool getPathMatching(const Position &startPos, std::vector &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { return getPathMatching(nullptr, startPos, dirList, pathCondition, fpp); } @@ -143,8 +145,6 @@ class Map : public MapCache { Houses housesCustomMaps[50]; private: - bool getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); - /** * Set a single tile. */ diff --git a/src/map/utils/astarnodes.cpp b/src/map/utils/astarnodes.cpp index 9342fd8436b..21ebe5f982f 100644 --- a/src/map/utils/astarnodes.cpp +++ b/src/map/utils/astarnodes.cpp @@ -13,8 +13,28 @@ #include "creatures/monsters/monster.hpp" #include "creatures/combat/combat.hpp" -AStarNodes::AStarNodes(uint32_t x, uint32_t y) : - nodes(), openNodes() { +AStarNodes::AStarNodes(uint32_t x, uint32_t y, int_fast32_t extraCost) : + openNodes(), nodes() { +#if defined(__AVX2__) + __m256i defaultCost = _mm256_set1_epi32(std::numeric_limits::max()); + for (int32_t i = 0; i < MAX_NODES; i += 32) { + _mm256_stream_si256(reinterpret_cast<__m256i*>(&calculatedNodes[i + 0]), defaultCost); + _mm256_stream_si256(reinterpret_cast<__m256i*>(&calculatedNodes[i + 8]), defaultCost); + _mm256_stream_si256(reinterpret_cast<__m256i*>(&calculatedNodes[i + 16]), defaultCost); + _mm256_stream_si256(reinterpret_cast<__m256i*>(&calculatedNodes[i + 24]), defaultCost); + } + _mm_sfence(); +#elif defined(__SSE2__) + __m128i defaultCost = _mm_set1_epi32(std::numeric_limits::max()); + for (int32_t i = 0; i < MAX_NODES; i += 16) { + _mm_stream_si128(reinterpret_cast<__m128i*>(&calculatedNodes[i + 0]), defaultCost); + _mm_stream_si128(reinterpret_cast<__m128i*>(&calculatedNodes[i + 4]), defaultCost); + _mm_stream_si128(reinterpret_cast<__m128i*>(&calculatedNodes[i + 8]), defaultCost); + _mm_stream_si128(reinterpret_cast<__m128i*>(&calculatedNodes[i + 12]), defaultCost); + } + _mm_sfence(); +#endif + curNode = 1; closedNodes = 0; openNodes[0] = true; @@ -24,121 +44,239 @@ AStarNodes::AStarNodes(uint32_t x, uint32_t y) : startNode.x = x; startNode.y = y; startNode.f = 0; - nodeTable[(x << 16) | y] = nodes; + startNode.g = 0; + startNode.c = extraCost; + nodesTable[0] = (x << 16) | y; +#if defined(__SSE2__) + calculatedNodes[0] = 0; +#endif } -AStarNode* AStarNodes::createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f) { +bool AStarNodes::createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f, int_fast32_t heuristic, int_fast32_t extraCost) { if (curNode >= MAX_NODES) { - return nullptr; + return false; } - size_t retNode = curNode++; + int32_t retNode = curNode++; openNodes[retNode] = true; - AStarNode* node = nodes + retNode; - nodeTable[(x << 16) | y] = node; - node->parent = parent; - node->x = x; - node->y = y; - node->f = f; - return node; + AStarNode &node = nodes[retNode]; + node.parent = parent; + node.x = x; + node.y = y; + node.f = f; + node.g = heuristic; + node.c = extraCost; + nodesTable[retNode] = (x << 16) | y; +#if defined(__SSE2__) + calculatedNodes[retNode] = f + heuristic; +#endif + return true; } AStarNode* AStarNodes::getBestNode() { - if (curNode == 0) { - return nullptr; +// Branchless best node search +#if defined(__AVX512F__) + const __m512i increment = _mm512_set1_epi32(16); + __m512i indices = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + __m512i minindices = indices; + __m512i minvalues = _mm512_load_si512(reinterpret_cast(calculatedNodes)); + for (int32_t pos = 16; pos < curNode; pos += 16) { + const __m512i values = _mm512_load_si512(reinterpret_cast(&calculatedNodes[pos])); + indices = _mm512_add_epi32(indices, increment); + minindices = _mm512_mask_blend_epi32(_mm512_cmplt_epi32_mask(values, minvalues), minindices, indices); + minvalues = _mm512_min_epi32(minvalues, values); + } + + alignas(64) int32_t values_array[16]; + alignas(64) int32_t indices_array[16]; + _mm512_store_si512(reinterpret_cast(values_array), minvalues); + _mm512_store_si512(reinterpret_cast(indices_array), minindices); + + int32_t best_node = indices_array[0]; + int32_t best_node_f = values_array[0]; + for (int32_t i = 1; i < 16; ++i) { + int32_t total_cost = values_array[i]; + best_node = (total_cost < best_node_f ? indices_array[i] : best_node); + best_node_f = (total_cost < best_node_f ? total_cost : best_node_f); + } + return (openNodes[best_node] ? &nodes[best_node] : NULL); +#elif defined(__AVX2__) + const __m256i increment = _mm256_set1_epi32(8); + __m256i indices = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); + __m256i minindices = indices; + __m256i minvalues = _mm256_load_si256(reinterpret_cast(calculatedNodes)); + for (int32_t pos = 8; pos < curNode; pos += 8) { + const __m256i values = _mm256_load_si256(reinterpret_cast(&calculatedNodes[pos])); + indices = _mm256_add_epi32(indices, increment); + minindices = _mm256_blendv_epi8(minindices, indices, _mm256_cmpgt_epi32(minvalues, values)); + minvalues = _mm256_min_epi32(values, minvalues); + } + + __m256i res = _mm256_min_epi32(minvalues, _mm256_shuffle_epi32(minvalues, _MM_SHUFFLE(2, 3, 0, 1))); // Calculate horizontal minimum + res = _mm256_min_epi32(res, _mm256_shuffle_epi32(res, _MM_SHUFFLE(0, 1, 2, 3))); // Calculate horizontal minimum + res = _mm256_min_epi32(res, _mm256_permutevar8x32_epi32(res, _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7))); // Calculate horizontal minimum + + alignas(32) int32_t indices_array[8]; + _mm256_store_si256(reinterpret_cast<__m256i*>(indices_array), minindices); + + int32_t best_node = indices_array[(_mm_ctz(_mm256_movemask_epi8(_mm256_cmpeq_epi32(minvalues, res))) >> 2)]; + return (openNodes[best_node] ? &nodes[best_node] : NULL); +#elif defined(__SSE4_1__) + const __m128i increment = _mm_set1_epi32(4); + __m128i indices = _mm_setr_epi32(0, 1, 2, 3); + __m128i minindices = indices; + __m128i minvalues = _mm_load_si128(reinterpret_cast(calculatedNodes)); + for (int32_t pos = 4; pos < curNode; pos += 4) { + const __m128i values = _mm_load_si128(reinterpret_cast(&calculatedNodes[pos])); + indices = _mm_add_epi32(indices, increment); + minindices = _mm_blendv_epi8(minindices, indices, _mm_cmplt_epi32(values, minvalues)); + minvalues = _mm_min_epi32(values, minvalues); } + __m128i res = _mm_min_epi32(minvalues, _mm_shuffle_epi32(minvalues, _MM_SHUFFLE(2, 3, 0, 1))); // Calculate horizontal minimum + res = _mm_min_epi32(res, _mm_shuffle_epi32(res, _MM_SHUFFLE(0, 1, 2, 3))); // Calculate horizontal minimum + + alignas(16) int32_t indices_array[4]; + _mm_store_si128(reinterpret_cast<__m128i*>(indices_array), minindices); + + int32_t best_node = indices_array[(_mm_ctz(_mm_movemask_epi8(_mm_cmpeq_epi32(minvalues, res))) >> 2)]; + return (openNodes[best_node] ? &nodes[best_node] : NULL); +#elif defined(__SSE2__) + auto _mm_sse2_min_epi32 = [](const __m128i a, const __m128i b) { + __m128i mask = _mm_cmpgt_epi32(a, b); + return _mm_or_si128(_mm_and_si128(mask, b), _mm_andnot_si128(mask, a)); + }; + + auto _mm_sse2_blendv_epi8 = [](const __m128i a, const __m128i b, __m128i mask) { + mask = _mm_cmplt_epi8(mask, _mm_setzero_si128()); + return _mm_or_si128(_mm_andnot_si128(mask, a), _mm_and_si128(mask, b)); + }; + + const __m128i increment = _mm_set1_epi32(4); + __m128i indices = _mm_setr_epi32(0, 1, 2, 3); + __m128i minindices = indices; + __m128i minvalues = _mm_load_si128(reinterpret_cast(calculatedNodes)); + for (int32_t pos = 4; pos < curNode; pos += 4) { + const __m128i values = _mm_load_si128(reinterpret_cast(&calculatedNodes[pos])); + indices = _mm_add_epi32(indices, increment); + minindices = _mm_sse2_blendv_epi8(minindices, indices, _mm_cmplt_epi32(values, minvalues)); + minvalues = _mm_sse2_min_epi32(values, minvalues); + } + + __m128i res = _mm_sse2_min_epi32(minvalues, _mm_shuffle_epi32(minvalues, _MM_SHUFFLE(2, 3, 0, 1))); // Calculate horizontal minimum + res = _mm_sse2_min_epi32(res, _mm_shuffle_epi32(res, _MM_SHUFFLE(0, 1, 2, 3))); // Calculate horizontal minimum + + alignas(16) int32_t indices_array[4]; + _mm_store_si128(reinterpret_cast<__m128i*>(indices_array), minindices); + + int32_t best_node = indices_array[(_mm_ctz(_mm_movemask_epi8(_mm_cmpeq_epi32(minvalues, res))) >> 2)]; + return (openNodes[best_node] ? &nodes[best_node] : NULL); +#else int32_t best_node_f = std::numeric_limits::max(); int32_t best_node = -1; - for (size_t i = 0; i < curNode; i++) { - if (openNodes[i] && nodes[i].f < best_node_f) { - best_node_f = nodes[i].f; - best_node = i; + for (int32_t pos = 0; pos < curNode; ++pos) { + if (!openNodes[pos]) { + continue; } - } - if (best_node >= 0) { - return nodes + best_node; + int32_t total_cost = nodes[pos].f + nodes[pos].g; + best_node = (total_cost < best_node_f ? pos : best_node); + best_node_f = (total_cost < best_node_f ? total_cost : best_node_f); } - return nullptr; + return (best_node != -1 ? &nodes[best_node] : nullptr); +#endif } void AStarNodes::closeNode(const AStarNode* node) { - size_t index = node - nodes; - if (index >= MAX_NODES) { - g_logger().error("[{}]: node index out of bounds!", __FUNCTION__); - return; - } - + const size_t index = node - nodes; assert(index < MAX_NODES); +#if defined(__SSE2__) + calculatedNodes[index] = std::numeric_limits::max(); +#endif openNodes[index] = false; ++closedNodes; } void AStarNodes::openNode(const AStarNode* node) { - size_t index = node - nodes; - if (index >= MAX_NODES) { - g_logger().error("[{}]: node index out of bounds!", __FUNCTION__); - return; - } - + const size_t index = node - nodes; assert(index < MAX_NODES); - if (!openNodes[index]) { - openNodes[index] = true; - --closedNodes; - } +#if defined(__SSE2__) + calculatedNodes[index] = nodes[index].f + nodes[index].g; +#endif + closedNodes -= (openNodes[index] ? 0 : 1); + openNodes[index] = true; } -int_fast32_t AStarNodes::getClosedNodes() const { +int32_t AStarNodes::getClosedNodes() const { return closedNodes; } AStarNode* AStarNodes::getNodeByPosition(uint32_t x, uint32_t y) { - auto it = nodeTable.find((x << 16) | y); - if (it == nodeTable.end()) { - return nullptr; - } - return it->second; -} + uint32_t xy = (x << 16) | y; +#if defined(__SSE2__) + const __m128i key = _mm_set1_epi32(xy); -int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position &neighborPos, bool preferDiagonal) { - if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { - // diagonal movement extra cost - if (preferDiagonal) { - return MAP_PREFERDIAGONALWALKCOST; - } else { - return MAP_DIAGONALWALKCOST; + int32_t pos = 0; + int32_t curRound = curNode - 16; + for (; pos <= curRound; pos += 16) { + __m128i v[4]; + v[0] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos])), key); + v[1] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos + 4])), key); + v[2] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos + 8])), key); + v[3] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos + 12])), key); + const uint32_t mask = _mm_movemask_epi8(_mm_packs_epi16(_mm_packs_epi32(v[0], v[1]), _mm_packs_epi32(v[2], v[3]))); + if (mask != 0) { + return &nodes[pos + _mm_ctz(mask)]; + } + } + curRound = curNode - 8; + if (pos <= curRound) { + __m128i v[2]; + v[0] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos])), key); + v[1] = _mm_cmpeq_epi32(_mm_load_si128(reinterpret_cast(&nodesTable[pos + 4])), key); + const uint32_t mask = _mm_movemask_epi8(_mm_packs_epi32(v[0], v[1])); + if (mask != 0) { + return &nodes[pos + (_mm_ctz(mask) >> 1)]; + } + pos += 8; + } + for (; pos < curNode; ++pos) { + if (nodesTable[pos] == xy) { + return &nodes[pos]; } } - return MAP_NORMALWALKCOST; + return nullptr; +#else + for (int32_t i = 1; i < curNode; ++i) { + if (nodesTable[i] == xy) { + return &nodes[i]; + } + } + return (nodesTable[0] == xy ? &nodes[0] : nullptr); // The first node is very unlikely to be the "neighbor" so leave it for end +#endif } -int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile) { - if (!creature || !tile) { - return 0; - } +int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position &neighborPos) { + // diagonal movement extra cost + return (((std::abs(node->x - neighborPos.x) + std::abs(node->y - neighborPos.y)) - 1) * MAP_DIAGONALWALKCOST) + MAP_NORMALWALKCOST; +} +int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile) { int_fast32_t cost = 0; - if (tile->getTopVisibleCreature(creature) != nullptr) { - // destroy creature cost - cost += MAP_NORMALWALKCOST * 3; - } - if (const auto &field = tile->getFieldItem()) { - const CombatType_t combatType = field->getCombatType(); - const auto &monster = creature->getMonster(); - - if (!creature->isImmune(combatType) && !creature->hasCondition(Combat::DamageToConditionType(combatType)) && (monster && !monster->canWalkOnFieldType(combatType))) { - cost += MAP_NORMALWALKCOST * 18; + if (creature) { + if (tile->getTopVisibleCreature(creature) != nullptr) { + // destroy creature cost + cost += MAP_NORMALWALKCOST * 4; } - /** - * Make player try to avoid magic fields, when calculating pathing - */ - const auto &player = creature->getPlayer(); - if (player && !field->isBlocking() && field->getDamage() != 0) { - cost += MAP_NORMALWALKCOST * 18; + if (const auto &field = tile->getFieldItem()) { + CombatType_t combatType = field->getCombatType(); + if (!creature->isImmune(combatType) && !creature->hasCondition(Combat::DamageToConditionType(combatType)) && (creature->getMonster() && !creature->getMonster()->canWalkOnFieldType(combatType))) { + cost += MAP_NORMALWALKCOST * 18; + } } } + return cost; } diff --git a/src/map/utils/astarnodes.hpp b/src/map/utils/astarnodes.hpp index 546d490d858..d66171f0d53 100644 --- a/src/map/utils/astarnodes.hpp +++ b/src/map/utils/astarnodes.hpp @@ -15,22 +15,22 @@ class Tile; struct AStarNode { AStarNode* parent; - int_fast32_t f; + int_fast32_t f, g, c; uint16_t x, y; }; class AStarNodes { public: - AStarNodes(uint32_t x, uint32_t y); + AStarNodes(uint32_t x, uint32_t y, int_fast32_t extraCost); - AStarNode* createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f); + bool createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f, int_fast32_t heuristic, int_fast32_t extraCost); AStarNode* getBestNode(); void closeNode(const AStarNode* node); void openNode(const AStarNode* node); - int_fast32_t getClosedNodes() const; + int32_t getClosedNodes() const; AStarNode* getNodeByPosition(uint32_t x, uint32_t y); - static int_fast32_t getMapWalkCost(AStarNode* node, const Position &neighborPos, bool preferDiagonal = false); + static int_fast32_t getMapWalkCost(AStarNode* node, const Position &neighborPos); static int_fast32_t getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile); private: @@ -39,9 +39,15 @@ class AStarNodes { static constexpr int32_t MAP_PREFERDIAGONALWALKCOST = 14; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; +#if defined(__SSE2__) + alignas(16) uint32_t nodesTable[MAX_NODES]; + alignas(64) int32_t calculatedNodes[MAX_NODES]; AStarNode nodes[MAX_NODES]; +#else + AStarNode nodes[MAX_NODES]; + uint32_t nodesTable[MAX_NODES]; +#endif + int32_t closedNodes; + int32_t curNode; bool openNodes[MAX_NODES]; - phmap::flat_hash_map nodeTable; - size_t curNode; - int_fast32_t closedNodes; }; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 4c17b20965f..ae8510011b0 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -1599,35 +1599,34 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { return; } - msg.skipBytes(numdirs); - - stdext::arraylist path; - for (uint8_t i = 0; i < numdirs; ++i) { - uint8_t rawdir = msg.getPreviousByte(); + std::vector path; + path.resize(numdirs, DIRECTION_NORTH); + for (size_t i = numdirs; --i < numdirs;) { + const uint8_t rawdir = msg.getByte(); switch (rawdir) { case 1: - path.push_front(DIRECTION_EAST); + path[i] = DIRECTION_EAST; break; case 2: - path.push_front(DIRECTION_NORTHEAST); + path[i] = DIRECTION_NORTHEAST; break; case 3: - path.push_front(DIRECTION_NORTH); + path[i] = DIRECTION_NORTH; break; case 4: - path.push_front(DIRECTION_NORTHWEST); + path[i] = DIRECTION_NORTHWEST; break; case 5: - path.push_front(DIRECTION_WEST); + path[i] = DIRECTION_WEST; break; case 6: - path.push_front(DIRECTION_SOUTHWEST); + path[i] = DIRECTION_SOUTHWEST; break; case 7: - path.push_front(DIRECTION_SOUTH); + path[i] = DIRECTION_SOUTH; break; case 8: - path.push_front(DIRECTION_SOUTHEAST); + path[i] = DIRECTION_SOUTHEAST; break; default: break; @@ -1638,7 +1637,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { return; } - g_game().playerAutoWalk(player->getID(), path.data()); + g_game().playerAutoWalk(player->getID(), path); } void ProtocolGame::parseSetOutfit(NetworkMessage &msg) {