From 990ba89d5a2915225c3ae61b3409c73f418b73d0 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:00:21 -0700 Subject: [PATCH 01/94] Optimize pathfinding --- src/creature.cpp | 67 +++++++++++++------ src/creature.h | 6 +- src/game.cpp | 19 ++++++ src/game.h | 1 + src/map.cpp | 170 +++++++++++++++++++++++++++++++++-------------- src/map.h | 19 ++++-- src/player.cpp | 1 - 7 files changed, 203 insertions(+), 80 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index d224aeb837..9d91e1ecd0 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -139,27 +139,56 @@ void Creature::onThink(uint32_t interval) blockTicks = 0; } - if (followCreature) { - walkUpdateTicks += interval; - if (forceUpdateFollowPath || walkUpdateTicks >= 2000) { - walkUpdateTicks = 0; - forceUpdateFollowPath = false; - isUpdatingPath = true; - } - } + forceUpdateFollowPath = true; - if (isUpdatingPath) { - isUpdatingPath = false; - goToFollowCreature(); - } - - // scripting event - onThink + //scripting event - onThink const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEvent* thinkEvent : thinkEvents) { thinkEvent->executeOnThink(this, interval); } } +void Creature::checkPath() +{ + if (attackedCreature || followCreature) { + + Position targetPos; + if (attackedCreature) { + targetPos = attackedCreature->getPosition(); + } + else { + targetPos = followCreature->getPosition(); + } + + if (followPosition != targetPos || forceUpdateFollowPath) { + forceUpdateFollowPath = false; + FindPathParams fpp; + + if (attackedCreature) { + getPathSearchParams(attackedCreature, fpp); + } + else { + getPathSearchParams(followCreature, fpp); + } + + const Position& pos = getPosition(); + if (Position::getDistanceX(pos, targetPos) > fpp.maxSearchDist || Position::getDistanceY(pos, targetPos) > fpp.maxSearchDist) { + // Follow Creature has gone too far. Stop trying to get a path. + listWalkDir.clear(); + return; + } + + if (attackedCreature) { + followPosition = attackedCreature->getPosition(); + } + else { + followPosition = followCreature->getPosition(); + } + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + } + } +} + void Creature::onAttacking(uint32_t interval) { if (!attackedCreature) { @@ -611,10 +640,6 @@ void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Pos } if (creature == followCreature || (creature == this && followCreature)) { - if (hasFollowPath) { - isUpdatingPath = true; - } - if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) { onCreatureDisappear(followCreature, false); } @@ -931,6 +956,7 @@ bool Creature::setAttackedCreature(Creature* creature) } attackedCreature = creature; + followPosition = creaturePos; onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } else { @@ -1018,11 +1044,8 @@ bool Creature::setFollowCreature(Creature* creature) } hasFollowPath = false; - forceUpdateFollowPath = false; followCreature = creature; - isUpdatingPath = true; } else { - isUpdatingPath = false; followCreature = nullptr; } @@ -1656,7 +1679,7 @@ bool Creature::isInvisible() const bool Creature::getPathTo(const Position& targetPos, std::vector& dirList, const FindPathParams& fpp) const { - return g_game.map.getPathMatching(*this, dirList, FrozenPathingConditionCall(targetPos), fpp); + return g_game.map.getPathMatching(*this, targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp); } bool Creature::getPathTo(const Position& targetPos, std::vector& dirList, int32_t minTargetDist, diff --git a/src/creature.h b/src/creature.h index 170a4b5abe..d2c311a331 100644 --- a/src/creature.h +++ b/src/creature.h @@ -53,6 +53,7 @@ struct FindPathParams static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; +static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 20; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); @@ -272,6 +273,7 @@ class Creature : virtual public Thing void setCreatureLight(LightInfo lightInfo); virtual void onThink(uint32_t interval); + virtual void checkPath(); void onAttacking(uint32_t interval); virtual void onWalk(); virtual bool getNextStep(Direction& dir, uint32_t& flags); @@ -375,6 +377,7 @@ class Creature : virtual public Thing Tile* tile = nullptr; Creature* attackedCreature = nullptr; + Position followPosition; Creature* master = nullptr; Creature* followCreature = nullptr; @@ -407,14 +410,13 @@ class Creature : virtual public Thing bool localMapCache[mapWalkHeight][mapWalkWidth] = {{false}}; bool isInternalRemoved = false; bool isMapLoaded = false; - bool isUpdatingPath = false; bool creatureCheck = false; bool inCheckCreaturesVector = false; bool skillLoss = true; bool lootDrop = true; bool cancelNextWalk = false; - bool hasFollowPath = false; bool forceUpdateFollowPath = false; + bool hasFollowPath = false; bool hiddenHealth = false; bool canUseDefense = true; bool movementBlocked = false; diff --git a/src/game.cpp b/src/game.cpp index e4b1fb058c..6f616dcc67 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -74,6 +74,7 @@ void Game::start(ServiceManager* manager) serviceManager = manager; g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); + g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, [this]() { checkCreaturesPath(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } @@ -3887,6 +3888,24 @@ void Game::checkCreatures(size_t index) cleanup(); } +void Game::checkCreaturesPath(size_t index) +{ + g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, + [=]() { checkCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); + + auto& checkCreatureList = checkCreatureLists[index]; + auto it = checkCreatureList.begin(), end = checkCreatureList.end(); + while (it != end) { + Creature* creature = *it; + if (creature->getHealth() > 0) { + creature->checkPath(); + } + ++it; + } + + cleanup(); +} + void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta) { int32_t varSpeed = creature->getSpeed() - creature->getBaseSpeed(); diff --git a/src/game.h b/src/game.h index eca08f4dc4..abc75d17df 100644 --- a/src/game.h +++ b/src/game.h @@ -428,6 +428,7 @@ class Game void updateCreatureWalk(uint32_t creatureId); void checkCreatureAttack(uint32_t creatureId); void checkCreatures(size_t index); + void checkCreaturesPath(size_t index); void checkLight(); bool combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, diff --git a/src/map.cpp b/src/map.cpp index 852cc09549..288cb4c56b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -493,13 +493,22 @@ bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool return !checkLineOfSight || isSightClear(fromPos, toPos, sameFloor); } -bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= false*/) const +bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= false*/, + bool isPathfinding /*= false*/) const { const Tile* tile = getTile(x, y, z); if (!tile) { return true; } + if (isPathfinding) { + const Creature* creature = tile->getTopCreature(); + if (creature && tile->getTopVisibleCreature(creature) || tile->hasProperty(CONST_PROP_BLOCKPATH) || + tile->hasProperty(CONST_PROP_BLOCKSOLID)) { + return false; + } + } + if (blockFloor && tile->getGround()) { return false; } @@ -509,7 +518,7 @@ bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= fal namespace { -bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) +bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, bool isPathfinding) { float dx = x1 - x0; float slope = (dx == 0) ? 1 : (y1 - y0) / dx; @@ -517,7 +526,7 @@ bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t for (uint16_t x = x0 + 1; x < x1; ++x) { // 0.1 is necessary to avoid loss of precision during calculation - if (!g_game.map.isTileClear(std::floor(yi + 0.1), x, z)) { + if (!g_game.map.isTileClear(std::floor(yi + 0.1), x, z, false, isPathfinding)) { return false; } yi += slope; @@ -526,7 +535,7 @@ bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t return true; } -bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) +bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, bool isPathfinding) { float dx = x1 - x0; float slope = (dx == 0) ? 1 : (y1 - y0) / dx; @@ -534,7 +543,7 @@ bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t for (uint16_t x = x0 + 1; x < x1; ++x) { // 0.1 is necessary to avoid loss of precision during calculation - if (!g_game.map.isTileClear(x, std::floor(yi + 0.1), z)) { + if (!g_game.map.isTileClear(x, std::floor(yi + 0.1), z, false, isPathfinding)) { return false; } yi += slope; @@ -545,7 +554,8 @@ bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t } // namespace -bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const +bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, + bool isPathfinding /*= false*/) const { if (x0 == x1 && y0 == y1) { return true; @@ -553,19 +563,20 @@ bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uin if (std::abs(y1 - y0) > std::abs(x1 - x0)) { if (y1 > y0) { - return checkSteepLine(y0, x0, y1, x1, z); + return checkSteepLine(y0, x0, y1, x1, z, isPathfinding); } - return checkSteepLine(y1, x1, y0, x0, z); + return checkSteepLine(y1, x1, y0, x0, z, isPathfinding); } if (x0 > x1) { - return checkSlightLine(x1, y1, x0, y0, z); + return checkSlightLine(x1, y1, x0, y0, z, isPathfinding); } - return checkSlightLine(x0, y0, x1, y1, z); + return checkSlightLine(x0, y0, x1, y1, z, isPathfinding); } -bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor /*= false*/) const +bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor /*= false*/, + bool isPathfinding /*= false*/) const { // target is on the same floor if (fromPos.z == toPos.z) { @@ -574,6 +585,11 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool same return true; } + // Path finding line is clear + if (isPathfinding) { + return checkSightLine(fromPos.x, fromPos.y, toPos.x, toPos.y, fromPos.z, true); + } + // sight is clear or sameFloor is enabled bool sightClear = checkSightLine(fromPos.x, fromPos.y, toPos.x, toPos.y, fromPos.z); if (sightClear || sameFloor) { @@ -652,24 +668,23 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const return tile; } -bool Map::getPathMatching(const Creature& creature, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const +bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { Position pos = creature.getPosition(); Position endPos; + const Position startPos = pos; - AStarNodes nodes(pos.x, pos.y); + // Don't update path if the target is too far away + if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || + Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + return false; + } 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}}; + AStarNodes nodes(pos.x, pos.y); - const Position startPos = pos; + bool sightClear = isSightClear(startPos, targetPos, true, true); AStarNode* found = nullptr; while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { @@ -701,39 +716,46 @@ bool Map::getPathMatching(const Creature& creature, std::vector& dirL if (offset_y == 0) { if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_WEST]; - } else { + } + else { neighbors = *dirNeighbors[DIRECTION_EAST]; } - } else if (!fpp.allowDiagonal || offset_x == 0) { + } + else if (!fpp.allowDiagonal || offset_x == 0) { if (offset_y == -1) { neighbors = *dirNeighbors[DIRECTION_NORTH]; - } else { + } + else { neighbors = *dirNeighbors[DIRECTION_SOUTH]; } - } else if (offset_y == -1) { + } + else if (offset_y == -1) { if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; - } else { + } + else { neighbors = *dirNeighbors[DIRECTION_NORTHEAST]; } - } else if (offset_x == -1) { + } + else if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_SOUTHWEST]; - } else { + } + else { neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; } dirCount = fpp.allowDiagonal ? 5 : 3; - } else { + } + 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)) { + if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } @@ -741,34 +763,74 @@ bool Map::getPathMatching(const Creature& creature, std::vector& dirL continue; } + // Sight is clear. + if (sightClear && (!creature.isSummon() && !creature.attackedCreature)) { + + if (startPos.x == targetPos.x) { + // Don't check nodes if start and end pos X are the same and node X is different. + if (pos.x != targetPos.x) { + continue; + } + } + else if (startPos.y == targetPos.y) { + // Don't check nodes if start and end pos Y are the same and node Y is different. + if (pos.y != targetPos.y) { + continue; + } + } + + const int_fast32_t startDistXtarget = std::abs(startPos.x - targetPos.x); + const int_fast32_t startDistYtarget = std::abs(startPos.y - targetPos.y); + const int_fast32_t startDistXNode = std::abs(startPos.x - pos.x); + const int_fast32_t startDistYNode = std::abs(startPos.y - pos.y); + // We shouldn't check past the targets X or Y + if (startDistXtarget < startDistXNode) { + continue; + } + else if (startDistYtarget < startDistYNode) { + continue; + } + + // We don't need to check behind us. The sight is clear to go forward. + const int_fast32_t nodeDistXtarget = std::abs(pos.x - targetPos.x); + const int_fast32_t nodeDistYtarget = std::abs(pos.y - targetPos.y); + if (startDistXtarget < nodeDistXtarget || startDistYtarget < nodeDistYtarget) { + continue; + } + } + const Tile* tile; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); if (neighborNode) { tile = getTile(pos.x, pos.y, pos.z); - } else { + } + else { tile = canWalkTo(creature, pos); if (!tile) { continue; } } - // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos); - const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); - const int_fast32_t newf = f + cost + extraCost; + // The cost to walk to this neighbor + const int_fast32_t walkCost = AStarNodes::getMapWalkCost(n, pos); + const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); + const int_fast32_t distEnd = Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); + const int_fast32_t distStart = Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); + const int_fast32_t f = distEnd + distStart + (walkCost + speedCost); if (neighborNode) { - if (neighborNode->f <= newf) { - // The node on the closed/open list is cheaper than this one + if (neighborNode->f <= f) { + //The node on the closed/open list is cheaper than this one continue; } - neighborNode->f = newf; + neighborNode->f = f; neighborNode->parent = n; nodes.openNode(neighborNode); - } else { - // Does not exist in the open/closed list, create a new node - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); + } + else { + //Does not exist in the open/closed list, create a new node + neighborNode = nodes.createOpenNode(n, pos.x, pos.y, f); if (!neighborNode) { if (found) { break; @@ -801,24 +863,32 @@ bool Map::getPathMatching(const Creature& creature, std::vector& dirL if (dx == 1 && dy == 1) { dirList.push_back(DIRECTION_NORTHWEST); - } else if (dx == -1 && dy == 1) { + } + else if (dx == -1 && dy == 1) { dirList.push_back(DIRECTION_NORTHEAST); - } else if (dx == 1 && dy == -1) { + } + else if (dx == 1 && dy == -1) { dirList.push_back(DIRECTION_SOUTHWEST); - } else if (dx == -1 && dy == -1) { + } + else if (dx == -1 && dy == -1) { dirList.push_back(DIRECTION_SOUTHEAST); - } else if (dx == 1) { + } + else if (dx == 1) { dirList.push_back(DIRECTION_WEST); - } else if (dx == -1) { + } + else if (dx == -1) { dirList.push_back(DIRECTION_EAST); - } else if (dy == 1) { + } + else if (dy == 1) { dirList.push_back(DIRECTION_NORTH); - } else if (dy == -1) { + } + else if (dy == -1) { dirList.push_back(DIRECTION_SOUTH); } found = found->parent; } + return true; } diff --git a/src/map.h b/src/map.h index 781fb3c6eb..8327a528ee 100644 --- a/src/map.h +++ b/src/map.h @@ -26,6 +26,13 @@ static constexpr int32_t MAX_NODES = 512; static constexpr int32_t MAP_NORMALWALKCOST = 10; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; +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} }; + class AStarNodes { public: @@ -227,7 +234,7 @@ class Map * \param blockFloor counts the ground tile as an obstacle * \returns The result if there is an obstacle or not */ - bool isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor = false) const; + bool isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor = false, bool isPathfinding = false) const; /** * Checks if path is clear from fromPos to toPos @@ -236,13 +243,15 @@ class Map *Destination point \param sameFloor checks if the destination is on same *floor \returns The result if there is no obstacles */ - bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false) const; - bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const; + bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false, + bool isPathfinding = false) const; + bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, + bool isPathfinding = false) const; const Tile* canWalkTo(const Creature& creature, const Position& pos) const; - bool getPathMatching(const Creature& creature, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; + bool getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; std::map waypoints; diff --git a/src/player.cpp b/src/player.cpp index 18aa11fb25..39868988aa 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1340,7 +1340,6 @@ void Player::onCreatureMove(Creature* creature, const Tile* newTile, const Posit Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if (hasFollowPath && (creature == followCreature || (creature == this && followCreature))) { - isUpdatingPath = false; g_dispatcher.addTask([id = getID()]() { g_game.updateCreatureWalk(id); }); } From 00951d293861fe8103cdf8b03faecd53b0a9d2a6 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:21:07 -0700 Subject: [PATCH 02/94] Minor fleeing monsters fix --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 288cb4c56b..f8ae64284e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -764,7 +764,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // Sight is clear. - if (sightClear && (!creature.isSummon() && !creature.attackedCreature)) { + if (sightClear && ((!creature.isSummon() && !creature.attackedCreature) || (fpp.keepDistance && fpp.keepDistance > 1))) { if (startPos.x == targetPos.x) { // Don't check nodes if start and end pos X are the same and node X is different. From 89be1ad83fd56024e651a41d48461a2626357c47 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:37:37 -0700 Subject: [PATCH 03/94] Fix whitespace and else brackets --- src/creature.cpp | 10 +++------- src/map.cpp | 52 ++++++++++++++++++------------------------------ src/map.h | 8 ++++---- 3 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 9d91e1ecd0..4118f09347 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -151,12 +151,10 @@ void Creature::onThink(uint32_t interval) void Creature::checkPath() { if (attackedCreature || followCreature) { - Position targetPos; if (attackedCreature) { targetPos = attackedCreature->getPosition(); - } - else { + } else { targetPos = followCreature->getPosition(); } @@ -166,8 +164,7 @@ void Creature::checkPath() if (attackedCreature) { getPathSearchParams(attackedCreature, fpp); - } - else { + } else { getPathSearchParams(followCreature, fpp); } @@ -180,8 +177,7 @@ void Creature::checkPath() if (attackedCreature) { followPosition = attackedCreature->getPosition(); - } - else { + } else { followPosition = followCreature->getPosition(); } g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); diff --git a/src/map.cpp b/src/map.cpp index f8ae64284e..6fc4bc9bf4 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -668,7 +668,8 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const return tile; } -bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const +bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { Position pos = creature.getPosition(); Position endPos; @@ -716,46 +717,40 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (offset_y == 0) { if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_WEST]; - } - else { + } else { neighbors = *dirNeighbors[DIRECTION_EAST]; } } else if (!fpp.allowDiagonal || offset_x == 0) { if (offset_y == -1) { neighbors = *dirNeighbors[DIRECTION_NORTH]; - } - else { + } else { neighbors = *dirNeighbors[DIRECTION_SOUTH]; } } else if (offset_y == -1) { if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; - } - else { + } else { neighbors = *dirNeighbors[DIRECTION_NORTHEAST]; } - } - else if (offset_x == -1) { + } else if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_SOUTHWEST]; - } - else { + } else { neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; } dirCount = fpp.allowDiagonal ? 5 : 3; - } - else { + } else { dirCount = 8; neighbors = *allNeighbors; } - 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)) { + if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || + Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } @@ -803,8 +798,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); if (neighborNode) { tile = getTile(pos.x, pos.y, pos.z); - } - else { + } else { tile = canWalkTo(creature, pos); if (!tile) { continue; @@ -827,8 +821,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighborNode->f = f; neighborNode->parent = n; nodes.openNode(neighborNode); - } - else { + } else { //Does not exist in the open/closed list, create a new node neighborNode = nodes.createOpenNode(n, pos.x, pos.y, f); if (!neighborNode) { @@ -863,26 +856,19 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (dx == 1 && dy == 1) { dirList.push_back(DIRECTION_NORTHWEST); - } - else if (dx == -1 && dy == 1) { + } else if (dx == -1 && dy == 1) { dirList.push_back(DIRECTION_NORTHEAST); - } - else if (dx == 1 && dy == -1) { + } else if (dx == 1 && dy == -1) { dirList.push_back(DIRECTION_SOUTHWEST); - } - else if (dx == -1 && dy == -1) { + } else if (dx == -1 && dy == -1) { dirList.push_back(DIRECTION_SOUTHEAST); - } - else if (dx == 1) { + } else if (dx == 1) { dirList.push_back(DIRECTION_WEST); - } - else if (dx == -1) { + } else if (dx == -1) { dirList.push_back(DIRECTION_EAST); - } - else if (dy == 1) { + } else if (dy == 1) { dirList.push_back(DIRECTION_NORTH); - } - else if (dy == -1) { + } else if (dy == -1) { dirList.push_back(DIRECTION_SOUTH); } diff --git a/src/map.h b/src/map.h index 8327a528ee..5f785394f4 100644 --- a/src/map.h +++ b/src/map.h @@ -244,14 +244,14 @@ class Map *floor \returns The result if there is no obstacles */ bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false, - bool isPathfinding = false) const; - bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, - bool isPathfinding = false) const; + bool isPathfinding = false) const; + bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, + bool isPathfinding = false) const; const Tile* canWalkTo(const Creature& creature, const Position& pos) const; bool getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; std::map waypoints; From 82ad8c90cf66c887cc728110e2f35e0413508041 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:40:44 -0700 Subject: [PATCH 04/94] More cleanup --- src/map.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 6fc4bc9bf4..50dca644c1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -720,15 +720,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } else { neighbors = *dirNeighbors[DIRECTION_EAST]; } - } - else if (!fpp.allowDiagonal || offset_x == 0) { + } else if (!fpp.allowDiagonal || offset_x == 0) { if (offset_y == -1) { neighbors = *dirNeighbors[DIRECTION_NORTH]; } else { neighbors = *dirNeighbors[DIRECTION_SOUTH]; } - } - else if (offset_y == -1) { + } else if (offset_y == -1) { if (offset_x == -1) { neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; } else { @@ -760,14 +758,12 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // Sight is clear. if (sightClear && ((!creature.isSummon() && !creature.attackedCreature) || (fpp.keepDistance && fpp.keepDistance > 1))) { - if (startPos.x == targetPos.x) { // Don't check nodes if start and end pos X are the same and node X is different. if (pos.x != targetPos.x) { continue; } - } - else if (startPos.y == targetPos.y) { + } else if (startPos.y == targetPos.y) { // Don't check nodes if start and end pos Y are the same and node Y is different. if (pos.y != targetPos.y) { continue; @@ -781,8 +777,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // We shouldn't check past the targets X or Y if (startDistXtarget < startDistXNode) { continue; - } - else if (startDistYtarget < startDistYNode) { + } else if (startDistYtarget < startDistYNode) { continue; } @@ -874,7 +869,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s found = found->parent; } - return true; } From 632d202f2f0aadd8e133304371b6fa844139164a Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:52:28 -0700 Subject: [PATCH 05/94] Cleanup --- src/creature.cpp | 2 +- src/creature.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 4118f09347..f421c94ed7 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -141,7 +141,7 @@ void Creature::onThink(uint32_t interval) forceUpdateFollowPath = true; - //scripting event - onThink + // scripting event - onThink const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEvent* thinkEvent : thinkEvents) { thinkEvent->executeOnThink(this, interval); diff --git a/src/creature.h b/src/creature.h index d2c311a331..7231b46b74 100644 --- a/src/creature.h +++ b/src/creature.h @@ -415,8 +415,8 @@ class Creature : virtual public Thing bool skillLoss = true; bool lootDrop = true; bool cancelNextWalk = false; - bool forceUpdateFollowPath = false; bool hasFollowPath = false; + bool forceUpdateFollowPath = false; bool hiddenHealth = false; bool canUseDefense = true; bool movementBlocked = false; From e7b57250d9cbbe9440273ede80798cc9f8332c2f Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:55:14 -0700 Subject: [PATCH 06/94] Remove uneeded variable name change --- src/map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 50dca644c1..81da1359f3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -805,20 +805,20 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t distEnd = Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); const int_fast32_t distStart = Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); - const int_fast32_t f = distEnd + distStart + (walkCost + speedCost); + const int_fast32_t newf = distEnd + distStart + (walkCost + speedCost); if (neighborNode) { - if (neighborNode->f <= f) { + if (neighborNode->f <= newf) { //The node on the closed/open list is cheaper than this one continue; } - neighborNode->f = f; + neighborNode->f = newf; neighborNode->parent = n; nodes.openNode(neighborNode); } else { //Does not exist in the open/closed list, create a new node - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, f); + neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); if (!neighborNode) { if (found) { break; From bc36d30da5a311e8962f396c37c5312ce32c95ba Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 01:55:56 -0700 Subject: [PATCH 07/94] Cleanup --- src/map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 81da1359f3..3ea93294bc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -809,7 +809,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (neighborNode) { if (neighborNode->f <= newf) { - //The node on the closed/open list is cheaper than this one + // The node on the closed/open list is cheaper than this one continue; } @@ -817,7 +817,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighborNode->parent = n; nodes.openNode(neighborNode); } else { - //Does not exist in the open/closed list, create a new node + // Does not exist in the open/closed list, create a new node neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); if (!neighborNode) { if (found) { From 68841aa7e31f25f91546afb66a94984861e85368 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 07:53:07 -0700 Subject: [PATCH 08/94] Move neighbor arrays back to map.cpp to fix unused variable failure --- src/map.cpp | 11 +++++++++-- src/map.h | 7 ------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 3ea93294bc..a0da4a070c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -669,7 +669,7 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { Position pos = creature.getPosition(); Position endPos; @@ -687,6 +687,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s bool sightClear = isSightClear(startPos, targetPos, true, true); + 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} }; + AStarNode* found = nullptr; while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { AStarNode* n = nodes.getBestNode(); @@ -748,7 +755,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s pos.y = y + *neighbors++; if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { + Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } diff --git a/src/map.h b/src/map.h index 5f785394f4..61db59ed17 100644 --- a/src/map.h +++ b/src/map.h @@ -26,13 +26,6 @@ static constexpr int32_t MAX_NODES = 512; static constexpr int32_t MAP_NORMALWALKCOST = 10; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; -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} }; - class AStarNodes { public: From edc1746d2c97d1bb70f1ea4c28572a74858bcd91 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 23 Mar 2024 15:31:24 -0700 Subject: [PATCH 09/94] Fix some compiling warnings --- src/game.cpp | 2 +- src/map.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 6f616dcc67..ff0ff0bed3 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3891,7 +3891,7 @@ void Game::checkCreatures(size_t index) void Game::checkCreaturesPath(size_t index) { g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, - [=]() { checkCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); + [=, this]() { checkCreatures((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; auto it = checkCreatureList.begin(), end = checkCreatureList.end(); diff --git a/src/map.cpp b/src/map.cpp index a0da4a070c..ab208ae789 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -503,8 +503,8 @@ bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= fal if (isPathfinding) { const Creature* creature = tile->getTopCreature(); - if (creature && tile->getTopVisibleCreature(creature) || tile->hasProperty(CONST_PROP_BLOCKPATH) || - tile->hasProperty(CONST_PROP_BLOCKSOLID)) { + if (creature && (tile->getTopVisibleCreature(creature) || tile->hasProperty(CONST_PROP_BLOCKPATH) || + tile->hasProperty(CONST_PROP_BLOCKSOLID))) { return false; } } @@ -764,7 +764,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // Sight is clear. - if (sightClear && ((!creature.isSummon() && !creature.attackedCreature) || (fpp.keepDistance && fpp.keepDistance > 1))) { + if (sightClear && ((!creature.isSummon() && !creature.attackedCreature) || fpp.keepDistance)) { if (startPos.x == targetPos.x) { // Don't check nodes if start and end pos X are the same and node X is different. if (pos.x != targetPos.x) { From 2476334a44b730d8d9640e50fa5ee8f6619e217c Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 24 Mar 2024 21:59:44 -0700 Subject: [PATCH 10/94] Fix incorrect method call in game.cpp --- src/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game.cpp b/src/game.cpp index ff0ff0bed3..1b27fc5431 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3891,7 +3891,7 @@ void Game::checkCreatures(size_t index) void Game::checkCreaturesPath(size_t index) { g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, - [=, this]() { checkCreatures((index + 1) % EVENT_CREATURECOUNT); })); + [=, this]() { checkCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; auto it = checkCreatureList.begin(), end = checkCreatureList.end(); From aa4153a4f7a15e9b695097a6341ecb5d40cb5d35 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 24 Mar 2024 23:18:54 -0700 Subject: [PATCH 11/94] Update to new creature isDead method --- src/game.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 1b27fc5431..b8d6b9a911 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3897,8 +3897,10 @@ void Game::checkCreaturesPath(size_t index) auto it = checkCreatureList.begin(), end = checkCreatureList.end(); while (it != end) { Creature* creature = *it; - if (creature->getHealth() > 0) { - creature->checkPath(); + if (creature->creatureCheck) { + if (!creature->isDead()) { + creature->checkPath(); + } } ++it; } From 9f882cab0459bee7cff5a081c9f9949298b0c9b6 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 25 Mar 2024 09:56:55 -0700 Subject: [PATCH 12/94] Update to clang format --- src/map.cpp | 24 +++++++++++++----------- src/map.h | 6 +++--- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index ab208ae789..6d31c163fa 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -504,7 +504,7 @@ bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= fal if (isPathfinding) { const Creature* creature = tile->getTopCreature(); if (creature && (tile->getTopVisibleCreature(creature) || tile->hasProperty(CONST_PROP_BLOCKPATH) || - tile->hasProperty(CONST_PROP_BLOCKSOLID))) { + tile->hasProperty(CONST_PROP_BLOCKSOLID))) { return false; } } @@ -555,7 +555,7 @@ bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t } // namespace bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, - bool isPathfinding /*= false*/) const + bool isPathfinding /*= false*/) const { if (x0 == x1 && y0 == y1) { return true; @@ -576,7 +576,7 @@ bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uin } bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor /*= false*/, - bool isPathfinding /*= false*/) const + bool isPathfinding /*= false*/) const { // target is on the same floor if (fromPos.z == toPos.z) { @@ -677,7 +677,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // Don't update path if the target is too far away if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { return false; } @@ -688,11 +688,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s bool sightClear = isSightClear(startPos, targetPos, true, true); 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} }; + {{-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}}; AStarNode* found = nullptr; while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { @@ -810,8 +810,10 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // The cost to walk to this neighbor const int_fast32_t walkCost = AStarNodes::getMapWalkCost(n, pos); const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); - const int_fast32_t distEnd = Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); - const int_fast32_t distStart = Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); + const int_fast32_t distEnd = + Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); + const int_fast32_t distStart = + Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); const int_fast32_t newf = distEnd + distStart + (walkCost + speedCost); if (neighborNode) { diff --git a/src/map.h b/src/map.h index 61db59ed17..82e8b9f3c5 100644 --- a/src/map.h +++ b/src/map.h @@ -237,14 +237,14 @@ class Map *floor \returns The result if there is no obstacles */ bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false, - bool isPathfinding = false) const; + bool isPathfinding = false) const; bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, - bool isPathfinding = false) const; + bool isPathfinding = false) const; const Tile* canWalkTo(const Creature& creature, const Position& pos) const; bool getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const; std::map waypoints; From 8d5078056954c71ed88a6731b58980367c2ed8dc Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 25 Mar 2024 17:32:37 -0700 Subject: [PATCH 13/94] Update to clang format --- src/creature.cpp | 3 ++- src/map.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f421c94ed7..55ca025053 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -169,7 +169,8 @@ void Creature::checkPath() } const Position& pos = getPosition(); - if (Position::getDistanceX(pos, targetPos) > fpp.maxSearchDist || Position::getDistanceY(pos, targetPos) > fpp.maxSearchDist) { + if (Position::getDistanceX(pos, targetPos) > fpp.maxSearchDist || + Position::getDistanceY(pos, targetPos) > fpp.maxSearchDist) { // Follow Creature has gone too far. Stop trying to get a path. listWalkDir.clear(); return; diff --git a/src/map.cpp b/src/map.cpp index 6d31c163fa..9a97381dbb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -494,7 +494,7 @@ bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool } bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= false*/, - bool isPathfinding /*= false*/) const + bool isPathfinding /*= false*/) const { const Tile* tile = getTile(x, y, z); if (!tile) { From b89076bd5379eb68cf39ce517094a9e7894e07f5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 26 Mar 2024 00:54:51 -0700 Subject: [PATCH 14/94] Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature --- src/creature.cpp | 1 + src/map.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 55ca025053..9af8002253 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1042,6 +1042,7 @@ bool Creature::setFollowCreature(Creature* creature) hasFollowPath = false; followCreature = creature; + followPosition = creaturePos; } else { followCreature = nullptr; } diff --git a/src/map.cpp b/src/map.cpp index 9a97381dbb..45dfafc3c7 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -676,9 +676,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const Position startPos = pos; // Don't update path if the target is too far away - if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { - return false; + if (fpp.maxSearchDist) { + if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || + Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + return false; + } } int32_t bestMatch = 0; From f4163e537056c0e207f620afeb09e3dfa87c2c28 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 26 Mar 2024 03:41:47 -0700 Subject: [PATCH 15/94] Fix fleeing monster randomly turning --- src/monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monster.cpp b/src/monster.cpp index 898668fbe1..6695ce1fdb 100644 --- a/src/monster.cpp +++ b/src/monster.cpp @@ -833,7 +833,7 @@ void Monster::doAttacking(uint32_t interval) } // ensure ranged creatures turn to player - if (!lookUpdated && lastMeleeAttack == 0) { + if (!lookUpdated && lastMeleeAttack == 0 && !isFleeing()) { updateLookDirection(); } From cab2968ea87de1b1d4b903ed4d44909f4675c2a6 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 30 Mar 2024 02:26:39 -0700 Subject: [PATCH 16/94] Reduce memory consumption and update pathmatching algorithm --- src/map.cpp | 177 ++++++++++++++++++++-------------------------------- src/map.h | 18 ------ 2 files changed, 69 insertions(+), 126 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 45dfafc3c7..003fd1d9db 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -669,36 +669,70 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { Position pos = creature.getPosition(); Position endPos; const Position startPos = pos; - // Don't update path if the target is too far away + // Don't update path. The target is too far away. if (fpp.maxSearchDist) { if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { return false; } } - int32_t bestMatch = 0; - - AStarNodes nodes(pos.x, pos.y); + // Dont update path. We are at the same position we want to go to. + if (startPos.x == targetPos.x && startPos.y == targetPos.y) { + return false; + } + 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} }; + + // Create a vector for storing and sorting nodes. + // Create a node map to easily find nodes using x and y + std::vector nodes; + std::map> nodeMap; + + // Check if our path to the target is clear bool sightClear = isSightClear(startPos, targetPos, true, true); - 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}}; + // If sight is blocked we want to allocate more memory than if it isn't to increase efficiency. + int_fast32_t reserveSize; + if (sightClear) { + reserveSize = Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos) * 3; + } else { + reserveSize = (Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos)) * 10; + } + // Reserve some memory so we don't have to keep moving our nodes to different memory locations + nodes.reserve(reserveSize); + + // Create our first node to check. + AStarNode* firstNode = new AStarNode; + firstNode->parent = nullptr; + firstNode->x = pos.x; + firstNode->y = pos.y; + firstNode->f = 0; + + // Add node to node vector and map + nodes.push_back(firstNode); + nodeMap[pos.x][pos.y] = firstNode; AStarNode* found = nullptr; - while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { - AStarNode* n = nodes.getBestNode(); + int32_t bestMatch = 0; + int_fast32_t iterations = 0; + while (fpp.maxSearchDist != 0 || iterations < 100) { + iterations++; + + std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) {return left->f > right->f; }); + + AStarNode* n = nodes.back(); if (!n) { if (found) { break; @@ -706,6 +740,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } + nodes.pop_back(); + const int_fast32_t x = n->x; const int_fast32_t y = n->y; pos.x = x; @@ -752,12 +788,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighbors = *allNeighbors; } + 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)) { + Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } @@ -765,8 +802,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } - // Sight is clear. - if (sightClear && ((!creature.isSummon() && !creature.attackedCreature) || fpp.keepDistance)) { + // Sight is clear. We shouldn't have to move backwards. + if (sightClear && (!creature.isSummon() || fpp.keepDistance)) { if (startPos.x == targetPos.x) { // Don't check nodes if start and end pos X are the same and node X is different. if (pos.x != targetPos.x) { @@ -799,7 +836,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } const Tile* tile; - AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); + AStarNode* neighborNode = nodeMap[pos.x][pos.y]; if (neighborNode) { tile = getTile(pos.x, pos.y, pos.z); } else { @@ -813,10 +850,10 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const int_fast32_t walkCost = AStarNodes::getMapWalkCost(n, pos); const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t distEnd = - Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); + Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); const int_fast32_t distStart = - Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); - const int_fast32_t newf = distEnd + distStart + (walkCost + speedCost); + Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); + const int_fast32_t newf = distStart + distEnd + (walkCost + speedCost); if (neighborNode) { if (neighborNode->f <= newf) { @@ -826,20 +863,26 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighborNode->f = newf; neighborNode->parent = n; - nodes.openNode(neighborNode); + nodes.push_back(neighborNode); } else { // Does not exist in the open/closed list, create a new node - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); - if (!neighborNode) { + AStarNode* newNode = new AStarNode; + newNode->parent = n; + newNode->x = pos.x; + newNode->y = pos.y; + newNode->f = newf; + + if (!newNode) { if (found) { break; } return false; } + + nodes.push_back(newNode); + nodeMap[pos.x][pos.y] = newNode; } } - - nodes.closeNode(n); } if (!found) { @@ -885,88 +928,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // AStarNodes -AStarNodes::AStarNodes(uint32_t x, uint32_t y) : nodes(), openNodes() -{ - curNode = 1; - closedNodes = 0; - openNodes[0] = true; - - AStarNode& startNode = nodes[0]; - startNode.parent = nullptr; - startNode.x = x; - startNode.y = y; - startNode.f = 0; - nodeTable[(x << 16) | y] = nodes; -} - -AStarNode* AStarNodes::createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f) -{ - if (curNode >= MAX_NODES) { - return nullptr; - } - - size_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* AStarNodes::getBestNode() -{ - if (curNode == 0) { - return nullptr; - } - - 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; - } - } - - if (best_node >= 0) { - return nodes + best_node; - } - return nullptr; -} - -void AStarNodes::closeNode(AStarNode* node) -{ - size_t index = node - nodes; - assert(index < MAX_NODES); - openNodes[index] = false; - ++closedNodes; -} - -void AStarNodes::openNode(AStarNode* node) -{ - size_t index = node - nodes; - assert(index < MAX_NODES); - if (!openNodes[index]) { - openNodes[index] = true; - --closedNodes; - } -} - -int_fast32_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; -} - int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index 82e8b9f3c5..893dc0b134 100644 --- a/src/map.h +++ b/src/map.h @@ -21,32 +21,14 @@ struct AStarNode uint16_t x, y; }; -static constexpr int32_t MAX_NODES = 512; - static constexpr int32_t MAP_NORMALWALKCOST = 10; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; class AStarNodes { public: - AStarNodes(uint32_t x, uint32_t y); - - AStarNode* createOpenNode(AStarNode* parent, uint32_t x, uint32_t y, int_fast32_t f); - AStarNode* getBestNode(); - void closeNode(AStarNode* node); - void openNode(AStarNode* node); - int_fast32_t getClosedNodes() const; - AStarNode* getNodeByPosition(uint32_t x, uint32_t y); - static int_fast32_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static int_fast32_t getTileWalkCost(const Creature& creature, const Tile* tile); - -private: - AStarNode nodes[MAX_NODES]; - bool openNodes[MAX_NODES]; - std::unordered_map nodeTable; - size_t curNode; - int_fast32_t closedNodes; }; using SpectatorCache = std::map; From 3834fd50a3eb8aafb9d66a82c71c34f44df971e5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 30 Mar 2024 02:29:14 -0700 Subject: [PATCH 17/94] Clang formatting --- src/map.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 003fd1d9db..9b10385116 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -669,7 +669,7 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, - const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const + const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { Position pos = creature.getPosition(); Position endPos; @@ -678,7 +678,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // Don't update path. The target is too far away. if (fpp.maxSearchDist) { if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { return false; } } @@ -689,11 +689,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } 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} }; + {{-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}}; // Create a vector for storing and sorting nodes. // Create a node map to easily find nodes using x and y @@ -730,7 +730,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s while (fpp.maxSearchDist != 0 || iterations < 100) { iterations++; - std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) {return left->f > right->f; }); + std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); AStarNode* n = nodes.back(); if (!n) { @@ -794,7 +794,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s pos.y = y + *neighbors++; if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { + Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { continue; } @@ -850,9 +850,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const int_fast32_t walkCost = AStarNodes::getMapWalkCost(n, pos); const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t distEnd = - Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); + Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); const int_fast32_t distStart = - Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); + Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); const int_fast32_t newf = distStart + distEnd + (walkCost + speedCost); if (neighborNode) { From 3009b5273c1060215593f70510b9442d5e7d4be1 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 30 Mar 2024 13:32:34 -0700 Subject: [PATCH 18/94] Clang formatting --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 9b10385116..aae9ad2e1d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -788,7 +788,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighbors = *allNeighbors; } - for (uint_fast32_t i = 0; i < dirCount; ++i) { pos.x = x + *neighbors++; pos.y = y + *neighbors++; @@ -923,6 +922,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s found = found->parent; } + return true; } From 57ce0035a5a9761328e04c83fb56d6225fe9e3cf Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 30 Mar 2024 14:40:24 -0700 Subject: [PATCH 19/94] Remove uneeded check on new nodes --- src/map.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index aae9ad2e1d..d70314e4ef 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -871,13 +871,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s newNode->y = pos.y; newNode->f = newf; - if (!newNode) { - if (found) { - break; - } - return false; - } - nodes.push_back(newNode); nodeMap[pos.x][pos.y] = newNode; } From a68e1f56c05470067177ff43e37c647e973f8318 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 2 Apr 2024 02:18:22 -0700 Subject: [PATCH 20/94] Normalize pathfinding algorithm --- src/creature.cpp | 4 +- src/map.cpp | 208 +++++++++++++---------------------------------- src/map.h | 20 +++-- 3 files changed, 74 insertions(+), 158 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 9af8002253..1024727c93 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -953,7 +953,7 @@ bool Creature::setAttackedCreature(Creature* creature) } attackedCreature = creature; - followPosition = creaturePos; + forceUpdateFollowPath = true; onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } else { @@ -1042,7 +1042,7 @@ bool Creature::setFollowCreature(Creature* creature) hasFollowPath = false; followCreature = creature; - followPosition = creaturePos; + forceUpdateFollowPath = true; } else { followCreature = nullptr; } diff --git a/src/map.cpp b/src/map.cpp index d70314e4ef..57c6f8a680 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -493,22 +493,13 @@ bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool return !checkLineOfSight || isSightClear(fromPos, toPos, sameFloor); } -bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= false*/, - bool isPathfinding /*= false*/) const +bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= false*/) const { const Tile* tile = getTile(x, y, z); if (!tile) { return true; } - if (isPathfinding) { - const Creature* creature = tile->getTopCreature(); - if (creature && (tile->getTopVisibleCreature(creature) || tile->hasProperty(CONST_PROP_BLOCKPATH) || - tile->hasProperty(CONST_PROP_BLOCKSOLID))) { - return false; - } - } - if (blockFloor && tile->getGround()) { return false; } @@ -518,7 +509,7 @@ bool Map::isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor /*= fal namespace { -bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, bool isPathfinding) +bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) { float dx = x1 - x0; float slope = (dx == 0) ? 1 : (y1 - y0) / dx; @@ -526,7 +517,7 @@ bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t for (uint16_t x = x0 + 1; x < x1; ++x) { // 0.1 is necessary to avoid loss of precision during calculation - if (!g_game.map.isTileClear(std::floor(yi + 0.1), x, z, false, isPathfinding)) { + if (!g_game.map.isTileClear(std::floor(yi + 0.1), x, z)) { return false; } yi += slope; @@ -535,7 +526,7 @@ bool checkSteepLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t return true; } -bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, bool isPathfinding) +bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) { float dx = x1 - x0; float slope = (dx == 0) ? 1 : (y1 - y0) / dx; @@ -543,7 +534,7 @@ bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t for (uint16_t x = x0 + 1; x < x1; ++x) { // 0.1 is necessary to avoid loss of precision during calculation - if (!g_game.map.isTileClear(x, std::floor(yi + 0.1), z, false, isPathfinding)) { + if (!g_game.map.isTileClear(x, std::floor(yi + 0.1), z)) { return false; } yi += slope; @@ -554,8 +545,7 @@ bool checkSlightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t } // namespace -bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, - bool isPathfinding /*= false*/) const +bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const { if (x0 == x1 && y0 == y1) { return true; @@ -563,20 +553,19 @@ bool Map::checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uin if (std::abs(y1 - y0) > std::abs(x1 - x0)) { if (y1 > y0) { - return checkSteepLine(y0, x0, y1, x1, z, isPathfinding); + return checkSteepLine(y0, x0, y1, x1, z); } - return checkSteepLine(y1, x1, y0, x0, z, isPathfinding); + return checkSteepLine(y1, x1, y0, x0, z); } if (x0 > x1) { - return checkSlightLine(x1, y1, x0, y0, z, isPathfinding); + return checkSlightLine(x1, y1, x0, y0, z); } - return checkSlightLine(x0, y0, x1, y1, z, isPathfinding); + return checkSlightLine(x0, y0, x1, y1, z); } -bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor /*= false*/, - bool isPathfinding /*= false*/) const +bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor /*= false*/) const { // target is on the same floor if (fromPos.z == toPos.z) { @@ -585,11 +574,6 @@ bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool same return true; } - // Path finding line is clear - if (isPathfinding) { - return checkSightLine(fromPos.x, fromPos.y, toPos.x, toPos.y, fromPos.z, true); - } - // sight is clear or sameFloor is enabled bool sightClear = checkSightLine(fromPos.x, fromPos.y, toPos.x, toPos.y, fromPos.z); if (sightClear || sameFloor) { @@ -683,56 +667,22 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } - // Dont update path. We are at the same position we want to go to. + // Dont update path. We are on top of our target position. Let dance step decide. if (startPos.x == targetPos.x && startPos.y == targetPos.y) { return false; } - 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}}; - // Create a vector for storing and sorting nodes. - // Create a node map to easily find nodes using x and y - std::vector nodes; - std::map> nodeMap; - - // Check if our path to the target is clear - bool sightClear = isSightClear(startPos, targetPos, true, true); - - // If sight is blocked we want to allocate more memory than if it isn't to increase efficiency. - int_fast32_t reserveSize; - if (sightClear) { - reserveSize = Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos) * 3; - } else { - reserveSize = (Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos)) * 10; - } - // Reserve some memory so we don't have to keep moving our nodes to different memory locations - nodes.reserve(reserveSize); - - // Create our first node to check. - AStarNode* firstNode = new AStarNode; - firstNode->parent = nullptr; - firstNode->x = pos.x; - firstNode->y = pos.y; - firstNode->f = 0; - - // Add node to node vector and map - nodes.push_back(firstNode); - nodeMap[pos.x][pos.y] = firstNode; + AStarNodes nodes(pos.x, pos.y); AStarNode* found = nullptr; int32_t bestMatch = 0; - int_fast32_t iterations = 0; + int32_t iterations = 0; while (fpp.maxSearchDist != 0 || iterations < 100) { iterations++; - std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); - - AStarNode* n = nodes.back(); + AStarNode* n = nodes.getBestNode(); if (!n) { if (found) { break; @@ -740,8 +690,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - nodes.pop_back(); - const int_fast32_t x = n->x; const int_fast32_t y = n->y; pos.x = x; @@ -754,43 +702,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } - 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 (!fpp.allowDiagonal || 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 = fpp.allowDiagonal ? 5 : 3; - } else { - dirCount = 8; - neighbors = *allNeighbors; - } - - for (uint_fast32_t i = 0; i < dirCount; ++i) { - pos.x = x + *neighbors++; - pos.y = y + *neighbors++; + for (uint_fast32_t i = 0; i < 8; ++i) { + pos.x = x + allNeighbors[i][0]; + pos.y = y + allNeighbors[i][1]; if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { @@ -801,41 +715,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } - // Sight is clear. We shouldn't have to move backwards. - if (sightClear && (!creature.isSummon() || fpp.keepDistance)) { - if (startPos.x == targetPos.x) { - // Don't check nodes if start and end pos X are the same and node X is different. - if (pos.x != targetPos.x) { - continue; - } - } else if (startPos.y == targetPos.y) { - // Don't check nodes if start and end pos Y are the same and node Y is different. - if (pos.y != targetPos.y) { - continue; - } - } - - const int_fast32_t startDistXtarget = std::abs(startPos.x - targetPos.x); - const int_fast32_t startDistYtarget = std::abs(startPos.y - targetPos.y); - const int_fast32_t startDistXNode = std::abs(startPos.x - pos.x); - const int_fast32_t startDistYNode = std::abs(startPos.y - pos.y); - // We shouldn't check past the targets X or Y - if (startDistXtarget < startDistXNode) { - continue; - } else if (startDistYtarget < startDistYNode) { - continue; - } - - // We don't need to check behind us. The sight is clear to go forward. - const int_fast32_t nodeDistXtarget = std::abs(pos.x - targetPos.x); - const int_fast32_t nodeDistYtarget = std::abs(pos.y - targetPos.y); - if (startDistXtarget < nodeDistXtarget || startDistYtarget < nodeDistYtarget) { - continue; - } - } - const Tile* tile; - AStarNode* neighborNode = nodeMap[pos.x][pos.y]; + AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); if (neighborNode) { tile = getTile(pos.x, pos.y, pos.z); } else { @@ -850,9 +731,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t distEnd = Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); - const int_fast32_t distStart = - Position::getDistanceX(pos, startPos) + Position::getDistanceY(pos, startPos); - const int_fast32_t newf = distStart + distEnd + (walkCost + speedCost); + const int_fast32_t newf = distEnd + (walkCost + speedCost); if (neighborNode) { if (neighborNode->f <= newf) { @@ -862,17 +741,10 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighborNode->f = newf; neighborNode->parent = n; - nodes.push_back(neighborNode); + nodes.addNode(neighborNode); } else { // Does not exist in the open/closed list, create a new node - AStarNode* newNode = new AStarNode; - newNode->parent = n; - newNode->x = pos.x; - newNode->y = pos.y; - newNode->f = newf; - - nodes.push_back(newNode); - nodeMap[pos.x][pos.y] = newNode; + nodes.createNewNode(n, pos.x, pos.y, newf); } } } @@ -915,12 +787,46 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s found = found->parent; } - return true; } // AStarNodes +AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() +{ + // Create our first node to check. + AStarNode* firstNode = new AStarNode; + firstNode->parent = nullptr; + firstNode->x = x; + firstNode->y = y; + firstNode->f = 0; + + // Add node to node vector and map + nodes.reserve(50); + nodes.push_back(firstNode); + nodeMap[x][y] = firstNode; +} + +void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, int_fast32_t f) +{ + AStarNode* newNode = new AStarNode; + newNode->parent = parent; + newNode->x = x; + newNode->y = y; + newNode->f = f; + + nodes.push_back(newNode); + nodeMap[x][y] = newNode; +} + +AStarNode* AStarNodes::getBestNode() +{ + std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); + AStarNode* retNode = nodes.back(); + nodes.pop_back(); + return retNode; +} + int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index 893dc0b134..e704a15600 100644 --- a/src/map.h +++ b/src/map.h @@ -27,8 +27,20 @@ static constexpr int32_t MAP_DIAGONALWALKCOST = 25; class AStarNodes { public: + AStarNodes(uint16_t x, uint16_t y); + + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, int_fast32_t f); + void addNode(AStarNode* node) { nodes.push_back(node); }; + + AStarNode* getBestNode(); + AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; + static int_fast32_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static int_fast32_t getTileWalkCost(const Creature& creature, const Tile* tile); + +private: + std::vector nodes; + std::map> nodeMap; }; using SpectatorCache = std::map; @@ -209,7 +221,7 @@ class Map * \param blockFloor counts the ground tile as an obstacle * \returns The result if there is an obstacle or not */ - bool isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor = false, bool isPathfinding = false) const; + bool isTileClear(uint16_t x, uint16_t y, uint8_t z, bool blockFloor = false) const; /** * Checks if path is clear from fromPos to toPos @@ -218,10 +230,8 @@ class Map *Destination point \param sameFloor checks if the destination is on same *floor \returns The result if there is no obstacles */ - bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false, - bool isPathfinding = false) const; - bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z, - bool isPathfinding = false) const; + bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor = false) const; + bool checkSightLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t z) const; const Tile* canWalkTo(const Creature& creature, const Position& pos) const; From 9e53616a874c63f84cfdfc18b7f2129243689333 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 4 Apr 2024 11:56:22 -0700 Subject: [PATCH 21/94] Final Changes: Move pathfinding call to onWalk --- src/creature.cpp | 91 ++++++++++++++++++++++++++---------------------- src/creature.h | 13 ++++--- src/game.cpp | 12 +++---- src/game.h | 4 +-- src/map.cpp | 45 ++++++++++++++++++++---- src/map.h | 5 +-- 6 files changed, 107 insertions(+), 63 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 1024727c93..913a423053 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -139,8 +139,6 @@ void Creature::onThink(uint32_t interval) blockTicks = 0; } - forceUpdateFollowPath = true; - // scripting event - onThink const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEvent* thinkEvent : thinkEvents) { @@ -148,42 +146,13 @@ void Creature::onThink(uint32_t interval) } } -void Creature::checkPath() +void Creature::forceUpdatePath() { - if (attackedCreature || followCreature) { - Position targetPos; - if (attackedCreature) { - targetPos = attackedCreature->getPosition(); - } else { - targetPos = followCreature->getPosition(); - } - - if (followPosition != targetPos || forceUpdateFollowPath) { - forceUpdateFollowPath = false; - FindPathParams fpp; - - if (attackedCreature) { - getPathSearchParams(attackedCreature, fpp); - } else { - getPathSearchParams(followCreature, fpp); - } - - const Position& pos = getPosition(); - if (Position::getDistanceX(pos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(pos, targetPos) > fpp.maxSearchDist) { - // Follow Creature has gone too far. Stop trying to get a path. - listWalkDir.clear(); - return; - } - - if (attackedCreature) { - followPosition = attackedCreature->getPosition(); - } else { - followPosition = followCreature->getPosition(); - } - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); - } + if (!attackedCreature && !followCreature) { + return; } + + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } void Creature::onAttacking(uint32_t interval) @@ -220,8 +189,6 @@ void Creature::onWalk() player->sendCancelMessage(ret); player->sendCancelWalk(); } - - forceUpdateFollowPath = true; } } else { stopEventWalk(); @@ -232,6 +199,8 @@ void Creature::onWalk() } } + updateFollowingCreaturesPath(); + if (cancelNextWalk) { listWalkDir.clear(); onWalkAborted(); @@ -953,7 +922,7 @@ bool Creature::setAttackedCreature(Creature* creature) } attackedCreature = creature; - forceUpdateFollowPath = true; + creature:addFollowedByCreature(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } else { @@ -1040,9 +1009,9 @@ bool Creature::setFollowCreature(Creature* creature) onWalkAborted(); } - hasFollowPath = false; followCreature = creature; - forceUpdateFollowPath = true; + creature:addFollowedByCreature(this); + hasFollowPath = false; } else { followCreature = nullptr; } @@ -1051,6 +1020,46 @@ bool Creature::setFollowCreature(Creature* creature) return true; } +// Pathfinding Functions +void Creature::addFollowedByCreature(Creature* creature) +{ + if (creature) { + followedByCreatures.push_back(creature); + } +} + +// Pathfinding Events +void Creature::updateFollowingCreaturesPath() +{ + if (followedByCreatures.empty()) { + return; + } + + std::list newFollowedByList; + for (Creature* followedByCreature : followedByCreatures) { + if (followedByCreature == nullptr) { + continue; + } + + if (!canSee(followedByCreature->getPosition())) { + continue; + } + + newFollowedByList.push_back(followedByCreature); + g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); + } + + followedByCreatures.clear(); + + for (Creature* newFollowCreature : newFollowedByList) { + if (newFollowCreature == nullptr) { + continue; + } + + addFollowedByCreature(newFollowCreature); + } +} + double Creature::getDamageRatio(Creature* attacker) const { uint32_t totalDamage = 0; diff --git a/src/creature.h b/src/creature.h index 7231b46b74..4239badc00 100644 --- a/src/creature.h +++ b/src/creature.h @@ -53,7 +53,7 @@ struct FindPathParams static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; -static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 20; +static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 2000; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); @@ -190,6 +190,12 @@ class Creature : virtual public Thing virtual void onFollowCreature(const Creature*) {} virtual void onFollowCreatureComplete(const Creature*) {} + // Pathfinding functions + virtual void addFollowedByCreature(Creature* creature); + + // Pathfinding events + void updateFollowingCreaturesPath(); + // combat functions Creature* getAttackedCreature() { return attackedCreature; } virtual bool setAttackedCreature(Creature* creature); @@ -273,7 +279,7 @@ class Creature : virtual public Thing void setCreatureLight(LightInfo lightInfo); virtual void onThink(uint32_t interval); - virtual void checkPath(); + virtual void forceUpdatePath(); void onAttacking(uint32_t interval); virtual void onWalk(); virtual bool getNextStep(Direction& dir, uint32_t& flags); @@ -377,9 +383,9 @@ class Creature : virtual public Thing Tile* tile = nullptr; Creature* attackedCreature = nullptr; - Position followPosition; Creature* master = nullptr; Creature* followCreature = nullptr; + std::list followedByCreatures; uint64_t lastStep = 0; uint32_t referenceCounter = 0; @@ -416,7 +422,6 @@ class Creature : virtual public Thing bool lootDrop = true; bool cancelNextWalk = false; bool hasFollowPath = false; - bool forceUpdateFollowPath = false; bool hiddenHealth = false; bool canUseDefense = true; bool movementBlocked = false; diff --git a/src/game.cpp b/src/game.cpp index b8d6b9a911..765e2eebea 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -74,7 +74,7 @@ void Game::start(ServiceManager* manager) serviceManager = manager; g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); - g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, [this]() { checkCreaturesPath(0); })); + g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, [this]() { updateCreaturesPath(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } @@ -3888,19 +3888,17 @@ void Game::checkCreatures(size_t index) cleanup(); } -void Game::checkCreaturesPath(size_t index) +void Game::updateCreaturesPath(size_t index) { g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, - [=, this]() { checkCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); + [=, this]() { updateCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; auto it = checkCreatureList.begin(), end = checkCreatureList.end(); while (it != end) { Creature* creature = *it; - if (creature->creatureCheck) { - if (!creature->isDead()) { - creature->checkPath(); - } + if (!creature->isDead()) { + creature->forceUpdatePath(); } ++it; } diff --git a/src/game.h b/src/game.h index abc75d17df..b98e8037c6 100644 --- a/src/game.h +++ b/src/game.h @@ -428,8 +428,8 @@ class Game void updateCreatureWalk(uint32_t creatureId); void checkCreatureAttack(uint32_t creatureId); void checkCreatures(size_t index); - void checkCreaturesPath(size_t index); - void checkLight(); + void updateCreaturesPath(size_t index); + // void checkLight(); bool combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, bool field, bool ignoreResistances = false); diff --git a/src/map.cpp b/src/map.cpp index 57c6f8a680..87f176ddc4 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -667,6 +667,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } + // We are at the target where we should be. Don't update path. + if (fpp.maxTargetDist == 1) { + if (Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos) <= 2) { + return true; + } + } + // Dont update path. We are on top of our target position. Let dance step decide. if (startPos.x == targetPos.x && startPos.y == targetPos.y) { return false; @@ -679,9 +686,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s AStarNode* found = nullptr; int32_t bestMatch = 0; int32_t iterations = 0; - while (fpp.maxSearchDist != 0 || iterations < 100) { + while (fpp.maxSearchDist != 0) { iterations++; + if (iterations >= 150) { + return false; + } + AStarNode* n = nodes.getBestNode(); if (!n) { if (found) { @@ -715,6 +726,10 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } + if (Position::getDistanceX(pos, startPos) >= 20 || Position::getDistanceY(pos, startPos) >= 20) { + return false; + } + const Tile* tile; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); if (neighborNode) { @@ -727,11 +742,17 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // The cost to walk to this neighbor - const int_fast32_t walkCost = AStarNodes::getMapWalkCost(n, pos); - const int_fast32_t speedCost = AStarNodes::getTileWalkCost(creature, tile); - const int_fast32_t distEnd = - Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos); - const int_fast32_t newf = distEnd + (walkCost + speedCost); + const int_fast32_t g = AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); + const float h = AStarNodes::calculateEuclidean(pos, targetPos); + float newf = h + g; + + if (creature.isSummon() && + (!creature.attackedCreature && creature.followCreature == creature.getMaster())) { + if (Position::getDistanceX(pos, targetPos) < Position::getDistanceX(startPos, targetPos) || + Position::getDistanceY(pos, targetPos) < Position::getDistanceY(startPos, targetPos)) { + newf += g; + } + } if (neighborNode) { if (neighborNode->f <= newf) { @@ -787,6 +808,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s found = found->parent; } + return true; } @@ -807,7 +829,7 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() nodeMap[x][y] = firstNode; } -void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, int_fast32_t f) +void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float f) { AStarNode* newNode = new AStarNode; newNode->parent = parent; @@ -827,6 +849,15 @@ AStarNode* AStarNodes::getBestNode() return retNode; } +float AStarNodes::calculateEuclidean(const Position& p1, const Position& p2) +{ + uint16_t dx = std::abs(p1.x - p2.x); + uint16_t dy = std::abs(p1.y - p2.y); + uint16_t aspbs = (dx * dx) + (dy * dy); + float f = std::sqrt(aspbs); + return f; +} + int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index e704a15600..fde24b6bb5 100644 --- a/src/map.h +++ b/src/map.h @@ -17,7 +17,7 @@ struct FindPathParams; struct AStarNode { AStarNode* parent; - int_fast32_t f; + float f; uint16_t x, y; }; @@ -29,12 +29,13 @@ class AStarNodes public: AStarNodes(uint16_t x, uint16_t y); - void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, int_fast32_t f); + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float f); void addNode(AStarNode* node) { nodes.push_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; + static float calculateEuclidean(const Position& p1, const Position& p2); static int_fast32_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static int_fast32_t getTileWalkCost(const Creature& creature, const Tile* tile); From bf0cc405baa1e91bbb42250b6a49f6ca8846335c Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 4 Apr 2024 12:38:07 -0700 Subject: [PATCH 22/94] Remove incorrect code --- src/map.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 87f176ddc4..e02bcff478 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -667,13 +667,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } - // We are at the target where we should be. Don't update path. - if (fpp.maxTargetDist == 1) { - if (Position::getDistanceX(startPos, targetPos) + Position::getDistanceY(startPos, targetPos) <= 2) { - return true; - } - } - // Dont update path. We are on top of our target position. Let dance step decide. if (startPos.x == targetPos.x && startPos.y == targetPos.y) { return false; From 44a300dcc3560f5df9af5647c214b0ee3590c8b1 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 5 Apr 2024 03:41:24 -0700 Subject: [PATCH 23/94] Move from Euclidean to standard A* --- src/map.cpp | 37 ++++++++++++++++++------------------- src/map.h | 12 ++++++------ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index e02bcff478..5a65076b62 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -735,9 +735,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // The cost to walk to this neighbor - const int_fast32_t g = AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); - const float h = AStarNodes::calculateEuclidean(pos, targetPos); - float newf = h + g; + const float walkCost = AStarNodes::getMapWalkCost(n, pos); + const float tileCost = AStarNodes::getTileWalkCost(creature, tile); + const float newf = n->f + walkCost + tileCost; + const float distEnd = + Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos) + newf; if (creature.isSummon() && (!creature.attackedCreature && creature.followCreature == creature.getMaster())) { @@ -755,10 +757,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s neighborNode->f = newf; neighborNode->parent = n; + neighborNode->h = distEnd; nodes.addNode(neighborNode); } else { // Does not exist in the open/closed list, create a new node - nodes.createNewNode(n, pos.x, pos.y, newf); + nodes.createNewNode(n, pos.x, pos.y, distEnd, newf); } } } @@ -801,7 +804,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s found = found->parent; } - return true; } @@ -814,6 +816,7 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() firstNode->parent = nullptr; firstNode->x = x; firstNode->y = y; + firstNode->h = 0; firstNode->f = 0; // Add node to node vector and map @@ -822,12 +825,13 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() nodeMap[x][y] = firstNode; } -void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float f) +void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float h, float f) { AStarNode* newNode = new AStarNode; newNode->parent = parent; newNode->x = x; newNode->y = y; + newNode->h = h; newNode->f = f; nodes.push_back(newNode); @@ -836,22 +840,17 @@ void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float AStarNode* AStarNodes::getBestNode() { - std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); + if (nodes.size() == 0) { + return nullptr; + } + + std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->h > right->h; }); AStarNode* retNode = nodes.back(); nodes.pop_back(); return retNode; } -float AStarNodes::calculateEuclidean(const Position& p1, const Position& p2) -{ - uint16_t dx = std::abs(p1.x - p2.x); - uint16_t dy = std::abs(p1.y - p2.y); - uint16_t aspbs = (dx * dx) + (dy * dy); - float f = std::sqrt(aspbs); - return f; -} - -int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) +float AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { // diagonal movement extra cost @@ -860,9 +859,9 @@ int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighbo return MAP_NORMALWALKCOST; } -int_fast32_t AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) +float AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) { - int_fast32_t cost = 0; + float cost = 0; if (tile->getTopVisibleCreature(&creature)) { // destroy creature cost cost += MAP_NORMALWALKCOST * 3; diff --git a/src/map.h b/src/map.h index fde24b6bb5..74b2ab9d23 100644 --- a/src/map.h +++ b/src/map.h @@ -17,27 +17,27 @@ struct FindPathParams; struct AStarNode { AStarNode* parent; + float h; float f; uint16_t x, y; }; -static constexpr int32_t MAP_NORMALWALKCOST = 10; -static constexpr int32_t MAP_DIAGONALWALKCOST = 25; +static constexpr float MAP_NORMALWALKCOST = 1.0f; +static constexpr float MAP_DIAGONALWALKCOST = 2.5f; class AStarNodes { public: AStarNodes(uint16_t x, uint16_t y); - void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float f); + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float h, float f); void addNode(AStarNode* node) { nodes.push_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; - static float calculateEuclidean(const Position& p1, const Position& p2); - static int_fast32_t getMapWalkCost(AStarNode* node, const Position& neighborPos); - static int_fast32_t getTileWalkCost(const Creature& creature, const Tile* tile); + static float getMapWalkCost(AStarNode* node, const Position& neighborPos); + static float getTileWalkCost(const Creature& creature, const Tile* tile); private: std::vector nodes; From e69384d253eebc6fa27aab48ddeffcdfeddd136c Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 5 Apr 2024 11:06:16 -0700 Subject: [PATCH 24/94] Fix overlooked typos and uneeded logic --- src/map.cpp | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 5a65076b62..38cd6f4c9c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -679,18 +679,12 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s AStarNode* found = nullptr; int32_t bestMatch = 0; int32_t iterations = 0; - while (fpp.maxSearchDist != 0) { - iterations++; - if (iterations >= 150) { - return false; - } + AStarNode* n = nodes.getBestNode(); + while (n) { + iterations++; - AStarNode* n = nodes.getBestNode(); - if (!n) { - if (found) { - break; - } + if (iterations >= 250) { return false; } @@ -741,14 +735,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s const float distEnd = Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos) + newf; - if (creature.isSummon() && - (!creature.attackedCreature && creature.followCreature == creature.getMaster())) { - if (Position::getDistanceX(pos, targetPos) < Position::getDistanceX(startPos, targetPos) || - Position::getDistanceY(pos, targetPos) < Position::getDistanceY(startPos, targetPos)) { - newf += g; - } - } - if (neighborNode) { if (neighborNode->f <= newf) { // The node on the closed/open list is cheaper than this one @@ -764,6 +750,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s nodes.createNewNode(n, pos.x, pos.y, distEnd, newf); } } + + n = nodes.getBestNode(); } if (!found) { From 8a9a093dc2338446af0872e21dfb0f390bb0980a Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 11 Apr 2024 05:37:14 -0700 Subject: [PATCH 25/94] Remove uneeded nullptr check and change iterations to int8_t --- src/creature.cpp | 4 ---- src/map.cpp | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 913a423053..1111a3a74e 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1037,10 +1037,6 @@ void Creature::updateFollowingCreaturesPath() std::list newFollowedByList; for (Creature* followedByCreature : followedByCreatures) { - if (followedByCreature == nullptr) { - continue; - } - if (!canSee(followedByCreature->getPosition())) { continue; } diff --git a/src/map.cpp b/src/map.cpp index 38cd6f4c9c..0f27d91187 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -678,8 +678,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s AStarNode* found = nullptr; int32_t bestMatch = 0; - int32_t iterations = 0; - + int8_t iterations = 0; AStarNode* n = nodes.getBestNode(); while (n) { iterations++; From d0346d1aace4890fde10f8c293624f144c5c6744 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 11 Apr 2024 05:41:40 -0700 Subject: [PATCH 26/94] Revert int8_t --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 0f27d91187..46dda25bae 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -678,7 +678,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s AStarNode* found = nullptr; int32_t bestMatch = 0; - int8_t iterations = 0; + int16_t iterations = 0; AStarNode* n = nodes.getBestNode(); while (n) { iterations++; From bf4067207759258685ee34718a21e6823e9c8b03 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 12 Apr 2024 13:14:34 -0700 Subject: [PATCH 27/94] Fix creature label error and update algorithm --- src/creature.cpp | 10 ++++------ src/map.cpp | 34 ++++++++++++++++++++-------------- src/map.h | 11 ++++++----- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 1111a3a74e..86619c89ca 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -922,9 +922,10 @@ bool Creature::setAttackedCreature(Creature* creature) } attackedCreature = creature; - creature:addFollowedByCreature(this); + creature->addFollowedByCreature(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } else { attackedCreature = nullptr; } @@ -1010,8 +1011,9 @@ bool Creature::setFollowCreature(Creature* creature) } followCreature = creature; - creature:addFollowedByCreature(this); + creature->addFollowedByCreature(this); hasFollowPath = false; + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } else { followCreature = nullptr; } @@ -1048,10 +1050,6 @@ void Creature::updateFollowingCreaturesPath() followedByCreatures.clear(); for (Creature* newFollowCreature : newFollowedByList) { - if (newFollowCreature == nullptr) { - continue; - } - addFollowedByCreature(newFollowCreature); } } diff --git a/src/map.cpp b/src/map.cpp index 46dda25bae..a5dedf91c1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -728,11 +728,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // The cost to walk to this neighbor - const float walkCost = AStarNodes::getMapWalkCost(n, pos); - const float tileCost = AStarNodes::getTileWalkCost(creature, tile); - const float newf = n->f + walkCost + tileCost; - const float distEnd = - Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos) + newf; + const double g = n->g + AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); + const double h = AStarNodes::calculateHeuristic(pos, targetPos); + const double newf = h + g; if (neighborNode) { if (neighborNode->f <= newf) { @@ -740,13 +738,13 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } + neighborNode->g = g; neighborNode->f = newf; neighborNode->parent = n; - neighborNode->h = distEnd; nodes.addNode(neighborNode); } else { // Does not exist in the open/closed list, create a new node - nodes.createNewNode(n, pos.x, pos.y, distEnd, newf); + nodes.createNewNode(n, pos.x, pos.y, g, newf); } } @@ -803,7 +801,7 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() firstNode->parent = nullptr; firstNode->x = x; firstNode->y = y; - firstNode->h = 0; + firstNode->g = 0; firstNode->f = 0; // Add node to node vector and map @@ -812,13 +810,13 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() nodeMap[x][y] = firstNode; } -void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float h, float f) +void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double g, double f) { AStarNode* newNode = new AStarNode; newNode->parent = parent; newNode->x = x; newNode->y = y; - newNode->h = h; + newNode->g = g; newNode->f = f; nodes.push_back(newNode); @@ -831,13 +829,21 @@ AStarNode* AStarNodes::getBestNode() return nullptr; } - std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->h > right->h; }); + std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); AStarNode* retNode = nodes.back(); nodes.pop_back(); return retNode; } -float AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) +double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) +{ + uint16_t dx = std::abs(p1.x - p2.x); + uint16_t dy = std::abs(p1.y - p2.y); + + return std::sqrt((dx * dx) + (dy * dy)); +} + +double AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { // diagonal movement extra cost @@ -846,9 +852,9 @@ float AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) return MAP_NORMALWALKCOST; } -float AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) +double AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) { - float cost = 0; + double cost = 0; if (tile->getTopVisibleCreature(&creature)) { // destroy creature cost cost += MAP_NORMALWALKCOST * 3; diff --git a/src/map.h b/src/map.h index 74b2ab9d23..278dde5071 100644 --- a/src/map.h +++ b/src/map.h @@ -17,8 +17,8 @@ struct FindPathParams; struct AStarNode { AStarNode* parent; - float h; - float f; + double g; + double f; uint16_t x, y; }; @@ -30,14 +30,15 @@ class AStarNodes public: AStarNodes(uint16_t x, uint16_t y); - void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, float h, float f); + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double g, double f); void addNode(AStarNode* node) { nodes.push_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; - static float getMapWalkCost(AStarNode* node, const Position& neighborPos); - static float getTileWalkCost(const Creature& creature, const Tile* tile); + static double calculateHeuristic(const Position& p1, const Position& p2); + static double getMapWalkCost(AStarNode* node, const Position& neighborPos); + static double getTileWalkCost(const Creature& creature, const Tile* tile); private: std::vector nodes; From 40581afad51503d3aab144038779f92cfc56d168 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 12 Apr 2024 13:31:34 -0700 Subject: [PATCH 28/94] Remove uneeded resizing --- src/creature.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 86619c89ca..791706fcf8 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1037,21 +1037,13 @@ void Creature::updateFollowingCreaturesPath() return; } - std::list newFollowedByList; for (Creature* followedByCreature : followedByCreatures) { if (!canSee(followedByCreature->getPosition())) { continue; } - newFollowedByList.push_back(followedByCreature); g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); } - - followedByCreatures.clear(); - - for (Creature* newFollowCreature : newFollowedByList) { - addFollowedByCreature(newFollowCreature); - } } double Creature::getDamageRatio(Creature* attacker) const From d5e6586022ddce4dd19146e89cdb0c3fdbb6b084 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 12 Apr 2024 14:35:01 -0700 Subject: [PATCH 29/94] Revert comment --- src/game.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game.h b/src/game.h index b98e8037c6..e41a5f0ba4 100644 --- a/src/game.h +++ b/src/game.h @@ -429,7 +429,7 @@ class Game void checkCreatureAttack(uint32_t creatureId); void checkCreatures(size_t index); void updateCreaturesPath(size_t index); - // void checkLight(); + void checkLight(); bool combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, bool field, bool ignoreResistances = false); From 093b939cda46a13a22b09b0d4354c619d28961f5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 13 Apr 2024 05:42:58 -0700 Subject: [PATCH 30/94] Add missing pathmatching call --- src/creature.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/creature.cpp b/src/creature.cpp index 791706fcf8..2211e7607f 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -211,6 +211,24 @@ void Creature::onWalk() eventWalk = 0; addEventWalk(); } + + if (getTimeSinceLastMove() >= 500) { + const Position& position = getPosition(); + + if (attackedCreature) { + const Position& targetPosition = attackedCreature->getPosition(); + if (Position::getDistanceX(position, targetPosition) <= Map::maxViewportX && + Position::getDistanceY(position, targetPosition) <= Map::maxViewportY) { + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + } + } else if (followCreature) { + const Position& targetPosition = followCreature->getPosition(); + if (Position::getDistanceX(position, targetPosition) <= Map::maxViewportX && + Position::getDistanceY(position, targetPosition) <= Map::maxViewportY) { + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + } + } + } } void Creature::onWalk(Direction& dir) From d3fdf383e9cd7647b263f3b898eb83f320015bd5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 13 Apr 2024 06:32:11 -0700 Subject: [PATCH 31/94] Allow force update path to be called more often --- src/creature.cpp | 10 ++++++---- src/creature.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 2211e7607f..1d45275f16 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -148,11 +148,13 @@ void Creature::onThink(uint32_t interval) void Creature::forceUpdatePath() { - if (!attackedCreature && !followCreature) { - return; - } + if (attackedCreature || followCreature) { + const Position& position = attackedCreature ? attackedCreature->getPosition() : followCreature->getPosition(); - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + if (g_game.isSightClear(getPosition(), position, true)) { + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + } + } } void Creature::onAttacking(uint32_t interval) diff --git a/src/creature.h b/src/creature.h index 4239badc00..e0d8405bc6 100644 --- a/src/creature.h +++ b/src/creature.h @@ -53,7 +53,7 @@ struct FindPathParams static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; -static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 2000; +static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 200; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); From 1e42f12765777a47df6a849ad2fb13ce08f2555f Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 06:00:18 -0700 Subject: [PATCH 32/94] Fix sight blocked monsters path updating --- src/creature.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/creature.cpp b/src/creature.cpp index 1d45275f16..05c3bc2054 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1057,8 +1057,11 @@ void Creature::updateFollowingCreaturesPath() return; } + const Position& thisPosition = getPosition(); for (Creature* followedByCreature : followedByCreatures) { - if (!canSee(followedByCreature->getPosition())) { + const Position& followedCreaturePosition = followedByCreature->getPosition(); + if (Position::getDistanceX(thisPosition, followedCreaturePosition) > Map::maxViewportX || + Position::getDistanceY(thisPosition, followedCreaturePosition) > Map::maxViewportY) { continue; } From 1c38ce1ba7d90851163e21f3a816b0ba782658d7 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 07:16:24 -0700 Subject: [PATCH 33/94] Additional blocked sight fix --- src/creature.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 05c3bc2054..7210b51bd1 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -149,11 +149,15 @@ void Creature::onThink(uint32_t interval) void Creature::forceUpdatePath() { if (attackedCreature || followCreature) { + const Position& thisPosition = getPosition(); const Position& position = attackedCreature ? attackedCreature->getPosition() : followCreature->getPosition(); - if (g_game.isSightClear(getPosition(), position, true)) { - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + if (Position::getDistanceX(thisPosition, position) > Map::maxViewportX || + Position::getDistanceY(thisPosition, position) > Map::maxViewportY) { + return; } + + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } } From 9f924e18d0e81fe1bb31f28a5f0438b36a723094 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 07:20:00 -0700 Subject: [PATCH 34/94] Allow paths to be drawn a little farther like rl tibia --- src/creature.cpp | 2 +- src/map.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 7210b51bd1..e4c90a0da5 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -964,7 +964,7 @@ void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const { fpp.fullPathSearch = !hasFollowPath; fpp.clearSight = true; - fpp.maxSearchDist = 12; + fpp.maxSearchDist = Map::maxViewportX * 2; fpp.minTargetDist = 1; fpp.maxTargetDist = 1; } diff --git a/src/map.cpp b/src/map.cpp index a5dedf91c1..227ceb4f9c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -712,10 +712,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } - if (Position::getDistanceX(pos, startPos) >= 20 || Position::getDistanceY(pos, startPos) >= 20) { - return false; - } - const Tile* tile; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); if (neighborNode) { From 4f57e8887a412b1dd58dff2cb86e525dc1a02048 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 08:51:00 -0700 Subject: [PATCH 35/94] Add delay to pathfinding and optimize code --- src/creature.cpp | 45 ++++++++++++--------------------------------- src/creature.h | 3 ++- src/map.cpp | 2 +- 3 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index e4c90a0da5..2eab11cace 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -148,17 +148,11 @@ void Creature::onThink(uint32_t interval) void Creature::forceUpdatePath() { - if (attackedCreature || followCreature) { - const Position& thisPosition = getPosition(); - const Position& position = attackedCreature ? attackedCreature->getPosition() : followCreature->getPosition(); - - if (Position::getDistanceX(thisPosition, position) > Map::maxViewportX || - Position::getDistanceY(thisPosition, position) > Map::maxViewportY) { - return; - } - - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + if (!attackedCreature || !followCreature) { + return; } + + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } void Creature::onAttacking(uint32_t interval) @@ -218,21 +212,10 @@ void Creature::onWalk() addEventWalk(); } - if (getTimeSinceLastMove() >= 500) { - const Position& position = getPosition(); - - if (attackedCreature) { - const Position& targetPosition = attackedCreature->getPosition(); - if (Position::getDistanceX(position, targetPosition) <= Map::maxViewportX && - Position::getDistanceY(position, targetPosition) <= Map::maxViewportY) { - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); - } - } else if (followCreature) { - const Position& targetPosition = followCreature->getPosition(); - if (Position::getDistanceX(position, targetPosition) <= Map::maxViewportX && - Position::getDistanceY(position, targetPosition) <= Map::maxViewportY) { - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); - } + if (attackedCreature || followCreature) { + if (lastPathUpdate - OTSYS_TIME() <= 0) { + lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_INTERVAL; + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } } } @@ -964,7 +947,7 @@ void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const { fpp.fullPathSearch = !hasFollowPath; fpp.clearSight = true; - fpp.maxSearchDist = Map::maxViewportX * 2; + fpp.maxSearchDist = Map::maxViewportX + Map::maxViewportY; fpp.minTargetDist = 1; fpp.maxTargetDist = 1; } @@ -1061,15 +1044,11 @@ void Creature::updateFollowingCreaturesPath() return; } - const Position& thisPosition = getPosition(); for (Creature* followedByCreature : followedByCreatures) { - const Position& followedCreaturePosition = followedByCreature->getPosition(); - if (Position::getDistanceX(thisPosition, followedCreaturePosition) > Map::maxViewportX || - Position::getDistanceY(thisPosition, followedCreaturePosition) > Map::maxViewportY) { - continue; + if (followedByCreature->lastPathUpdate - OTSYS_TIME() <= 0) { + followedByCreature->lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_INTERVAL; + g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); } - - g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); } } diff --git a/src/creature.h b/src/creature.h index e0d8405bc6..96c7efd1a5 100644 --- a/src/creature.h +++ b/src/creature.h @@ -53,7 +53,7 @@ struct FindPathParams static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; -static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 200; +static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 100; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); @@ -388,6 +388,7 @@ class Creature : virtual public Thing std::list followedByCreatures; uint64_t lastStep = 0; + uint64_t lastPathUpdate = 0; uint32_t referenceCounter = 0; uint32_t id = 0; uint32_t scriptEventsBitField = 0; diff --git a/src/map.cpp b/src/map.cpp index 227ceb4f9c..674904490b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -683,7 +683,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s while (n) { iterations++; - if (iterations >= 250) { + if (iterations >= 200) { return false; } From 1d36c7b5c3d1071a5cb740a95afbe1954acd8ef2 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 09:18:07 -0700 Subject: [PATCH 36/94] Fix incorrect conditional --- src/creature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature.cpp b/src/creature.cpp index 2eab11cace..68e8343ce5 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -148,7 +148,7 @@ void Creature::onThink(uint32_t interval) void Creature::forceUpdatePath() { - if (!attackedCreature || !followCreature) { + if (!attackedCreature && !followCreature) { return; } From 78aabb46d2bcc9d87858f4f453146e64f2a59063 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 09:37:49 -0700 Subject: [PATCH 37/94] Move path delay to force update path --- src/creature.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 68e8343ce5..a920750222 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -152,6 +152,11 @@ void Creature::forceUpdatePath() return; } + if (lastPathUpdate - OTSYS_TIME() > 0) { + return; + } + + lastPathUpdate = OTSYS_TIME() + 200; g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } @@ -213,10 +218,7 @@ void Creature::onWalk() } if (attackedCreature || followCreature) { - if (lastPathUpdate - OTSYS_TIME() <= 0) { - lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_INTERVAL; - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); - } + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } } @@ -1045,10 +1047,7 @@ void Creature::updateFollowingCreaturesPath() } for (Creature* followedByCreature : followedByCreatures) { - if (followedByCreature->lastPathUpdate - OTSYS_TIME() <= 0) { - followedByCreature->lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_INTERVAL; - g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); - } + g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); } } From f6f075313a9839e18058e921a79040d83d5341ea Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 12:24:38 -0700 Subject: [PATCH 38/94] Change uint64_t to int64_t --- src/creature.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature.h b/src/creature.h index 96c7efd1a5..93872f06f9 100644 --- a/src/creature.h +++ b/src/creature.h @@ -388,7 +388,7 @@ class Creature : virtual public Thing std::list followedByCreatures; uint64_t lastStep = 0; - uint64_t lastPathUpdate = 0; + int64_t lastPathUpdate = 0; uint32_t referenceCounter = 0; uint32_t id = 0; uint32_t scriptEventsBitField = 0; From e7efcfbf7aca2d19aa131f36d2e88d97b063c36f Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 15:41:50 -0700 Subject: [PATCH 39/94] Add pathfinding interval and delay to config.lua --- config.lua.dist | 6 ++++++ src/configmanager.cpp | 2 ++ src/configmanager.h | 2 ++ src/creature.cpp | 10 +--------- src/creature.h | 10 ++++++++-- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index 3515116b06..2451ecd72d 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -35,6 +35,12 @@ replaceKickOnLogin = true maxPacketsPerSecond = 25 enableTwoFactorAuth = true +-- Pathfinding +-- NOTE: pathfindingInterval how often paths are force drawn +-- NOTE: pathfindingDelay delay recently force drawn paths from drawing again +pathfindingInterval = 100 +pathfindingDelay = 200 + -- Deaths -- NOTE: Leave deathLosePercent as -1 if you want to use the default -- death penalty formula. For the old formula, set it to 10. For diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 718d7cfbb9..54f63eea97 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -285,6 +285,8 @@ bool ConfigManager::load() integer[QUEST_TRACKER_PREMIUM_LIMIT] = getGlobalNumber(L, "questTrackerPremiumLimit", 15); integer[STAMINA_REGEN_MINUTE] = getGlobalNumber(L, "timeToRegenMinuteStamina", 3 * 60); integer[STAMINA_REGEN_PREMIUM] = getGlobalNumber(L, "timeToRegenMinutePremiumStamina", 6 * 60); + integer[PATHFINDING_INTERVAL] = getGlobalNumber(L, "pathfindingInterval", 100); + integer[PATHFINDING_DELAY] = getGlobalNumber(L, "pathfindingDelay", 200); expStages = loadXMLStages(); if (expStages.empty()) { diff --git a/src/configmanager.h b/src/configmanager.h index d86be2a802..49e2801c13 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -125,6 +125,8 @@ class ConfigManager QUEST_TRACKER_PREMIUM_LIMIT, STAMINA_REGEN_MINUTE, STAMINA_REGEN_PREMIUM, + PATHFINDING_INTERVAL, + PATHFINDING_DELAY, LAST_INTEGER_CONFIG /* this must be the last one */ }; diff --git a/src/creature.cpp b/src/creature.cpp index a920750222..7e53bdfb85 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -156,7 +156,7 @@ void Creature::forceUpdatePath() return; } - lastPathUpdate = OTSYS_TIME() + 200; + lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_DELAY; g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } @@ -1031,14 +1031,6 @@ bool Creature::setFollowCreature(Creature* creature) return true; } -// Pathfinding Functions -void Creature::addFollowedByCreature(Creature* creature) -{ - if (creature) { - followedByCreatures.push_back(creature); - } -} - // Pathfinding Events void Creature::updateFollowingCreaturesPath() { diff --git a/src/creature.h b/src/creature.h index 93872f06f9..5928f4b0e6 100644 --- a/src/creature.h +++ b/src/creature.h @@ -4,6 +4,7 @@ #ifndef FS_CREATURE_H #define FS_CREATURE_H +#include "configmanager.h" #include "const.h" #include "creatureevent.h" #include "enums.h" @@ -18,6 +19,8 @@ class Monster; class Npc; class Player; +extern ConfigManager g_config; + using ConditionList = std::list; using CreatureEventList = std::list; @@ -53,8 +56,11 @@ struct FindPathParams static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; -static constexpr int32_t EVENT_CREATURE_PATH_INTERVAL = 100; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); + +static int32_t EVENT_CREATURE_PATH_INTERVAL = g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL); +static int32_t EVENT_CREATURE_PATH_DELAY = g_config.getNumber(ConfigManager::PATHFINDING_DELAY); + static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); @@ -191,7 +197,7 @@ class Creature : virtual public Thing virtual void onFollowCreatureComplete(const Creature*) {} // Pathfinding functions - virtual void addFollowedByCreature(Creature* creature); + virtual void addFollowedByCreature(Creature* creature) { followedByCreatures.push_back(creature); }; // Pathfinding events void updateFollowingCreaturesPath(); From 14d42f81e03e60bee80da423c180b2b0fad1a59b Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 14 Apr 2024 15:47:59 -0700 Subject: [PATCH 40/94] Add viewport check --- src/map.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/map.cpp b/src/map.cpp index 674904490b..84cccddf0c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -667,6 +667,12 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } + // Don't update path. Target in not in the viewport. + if (Position::getDistanceX(startPos, targetPos) > Map::maxViewportX + 1 || + Position::getDistanceY(startPos, targetPos) > Map::maxViewportY + 1) { + return false; + } + // Dont update path. We are on top of our target position. Let dance step decide. if (startPos.x == targetPos.x && startPos.y == targetPos.y) { return false; From 920da7b2de0123863dc67c92930df79675edca3c Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 15 Apr 2024 06:04:07 -0700 Subject: [PATCH 41/94] Fix memory leak --- src/creature.cpp | 2 +- src/creature.h | 6 ------ src/game.cpp | 5 +++-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 7e53bdfb85..45c7e94dcc 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -156,7 +156,7 @@ void Creature::forceUpdatePath() return; } - lastPathUpdate = OTSYS_TIME() + EVENT_CREATURE_PATH_DELAY; + lastPathUpdate = OTSYS_TIME() + g_config.getNumber(ConfigManager::PATHFINDING_DELAY); g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } diff --git a/src/creature.h b/src/creature.h index 5928f4b0e6..988bfe38ad 100644 --- a/src/creature.h +++ b/src/creature.h @@ -4,7 +4,6 @@ #ifndef FS_CREATURE_H #define FS_CREATURE_H -#include "configmanager.h" #include "const.h" #include "creatureevent.h" #include "enums.h" @@ -19,8 +18,6 @@ class Monster; class Npc; class Player; -extern ConfigManager g_config; - using ConditionList = std::list; using CreatureEventList = std::list; @@ -58,9 +55,6 @@ static constexpr int32_t EVENT_CREATURECOUNT = 10; static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000; static constexpr int32_t EVENT_CHECK_CREATURE_INTERVAL = (EVENT_CREATURE_THINK_INTERVAL / EVENT_CREATURECOUNT); -static int32_t EVENT_CREATURE_PATH_INTERVAL = g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL); -static int32_t EVENT_CREATURE_PATH_DELAY = g_config.getNumber(ConfigManager::PATHFINDING_DELAY); - static constexpr uint32_t CREATURE_ID_MIN = 0x10000000; static constexpr uint32_t CREATURE_ID_MAX = std::numeric_limits::max(); diff --git a/src/game.cpp b/src/game.cpp index 765e2eebea..5e7959811f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -74,7 +74,8 @@ void Game::start(ServiceManager* manager) serviceManager = manager; g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); - g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, [this]() { updateCreaturesPath(0); })); + g_scheduler.addEvent(createSchedulerTask(g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL), + [this]() { updateCreaturesPath(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } @@ -3890,7 +3891,7 @@ void Game::checkCreatures(size_t index) void Game::updateCreaturesPath(size_t index) { - g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_PATH_INTERVAL, + g_scheduler.addEvent(createSchedulerTask(g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL), [=, this]() { updateCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; From bebb988bda3e08c2e9542db796371b439006f8da Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 15 Apr 2024 16:15:07 -0700 Subject: [PATCH 42/94] Add memory management to follow list and pathmatching --- src/creature.cpp | 22 ++++++++++++++++++++-- src/map.cpp | 8 ++++++++ src/map.h | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 45c7e94dcc..80f91d2ec2 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1038,9 +1038,27 @@ void Creature::updateFollowingCreaturesPath() return; } - for (Creature* followedByCreature : followedByCreatures) { - g_dispatcher.addTask(createTask([id = followedByCreature->getID()]() { g_game.updateCreatureWalk(id); })); + std::list newList; + newList.resize(followedByCreatures.size()); + const Position& thisPosition = getPosition(); + for (auto follower : followedByCreatures) { + const Position& followerPosition = follower->getPosition(); + if (Position::getDistanceX(thisPosition, followerPosition) >= Map::maxViewportX + 2 || + Position::getDistanceY(thisPosition, followerPosition) >= Map::maxViewportY + 2) { + continue; + } + + newList.push_back(follower); + g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); } + + followedByCreatures.clear(); + + for (auto follower : followedByCreatures) { + followedByCreatures.push_back(follower); + } + + newList.clear(); } double Creature::getDamageRatio(Creature* attacker) const diff --git a/src/map.cpp b/src/map.cpp index 84cccddf0c..4e458ce747 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -753,6 +753,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s n = nodes.getBestNode(); } + nodes.clear(); + if (!found) { return false; } @@ -845,6 +847,12 @@ double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) return std::sqrt((dx * dx) + (dy * dy)); } +void AStarNodes::clear() +{ + nodes.clear(); + nodeMap.clear(); +}; + double AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index 278dde5071..74cd076c32 100644 --- a/src/map.h +++ b/src/map.h @@ -35,6 +35,7 @@ class AStarNodes AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; + void clear(); static double calculateHeuristic(const Position& p1, const Position& p2); static double getMapWalkCost(AStarNode* node, const Position& neighborPos); From dac4fc538f6fdf4bf8dbd029664d63fa97d52964 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 16 Apr 2024 07:16:13 -0700 Subject: [PATCH 43/94] Replace std::sqrt for std::hypot --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 4e458ce747..cc6d5b457e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -844,7 +844,7 @@ double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) uint16_t dx = std::abs(p1.x - p2.x); uint16_t dy = std::abs(p1.y - p2.y); - return std::sqrt((dx * dx) + (dy * dy)); + return std::hypot(dx, dy); } void AStarNodes::clear() From a6b3f25fa75c100dc2df5a8616f56399a7736b3d Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 18 Apr 2024 21:40:03 -0700 Subject: [PATCH 44/94] Update to new constexpr position methods --- src/creature.cpp | 4 ++-- src/map.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f312cfd225..d7324fc9ed 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1049,8 +1049,8 @@ void Creature::updateFollowingCreaturesPath() const Position& thisPosition = getPosition(); for (auto follower : followedByCreatures) { const Position& followerPosition = follower->getPosition(); - if (Position::getDistanceX(thisPosition, followerPosition) >= Map::maxViewportX + 2 || - Position::getDistanceY(thisPosition, followerPosition) >= Map::maxViewportY + 2) { + if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || + thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { continue; } diff --git a/src/map.cpp b/src/map.cpp index f45803c1c2..32937d8ebc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -666,15 +666,15 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // Don't update path. The target is too far away. if (fpp.maxSearchDist) { - if (Position::getDistanceX(startPos, targetPos) > fpp.maxSearchDist || - Position::getDistanceY(startPos, targetPos) > fpp.maxSearchDist) { + if (startPos.getDistanceX(targetPos) > fpp.maxSearchDist || + startPos.getDistanceY(targetPos) > fpp.maxSearchDist) { return false; } } // Don't update path. Target in not in the viewport. - if (Position::getDistanceX(startPos, targetPos) > Map::maxViewportX + 1 || - Position::getDistanceY(startPos, targetPos) > Map::maxViewportY + 1) { + if (startPos.getDistanceX(targetPos) > Map::maxViewportX + 1 || + startPos.getDistanceY(targetPos) > Map::maxViewportY + 1) { return false; } From 4d891e9585a96b943885e3fb694b58842615b8f2 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 20 Apr 2024 08:48:39 -0700 Subject: [PATCH 45/94] Revert int declarations in pathmatching --- src/creature.cpp | 18 +++++++++++++++--- src/map.cpp | 8 ++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index d7324fc9ed..8eac44b924 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -940,7 +940,12 @@ bool Creature::setAttackedCreature(Creature* creature) creature->addFollowedByCreature(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + + FindPathParams fpp; + getPathSearchParams(attackedCreature, fpp); + if (getPathTo(creaturePos, listWalkDir, fpp)) { + startAutoWalk(); + } } else { attackedCreature = nullptr; } @@ -1027,8 +1032,15 @@ bool Creature::setFollowCreature(Creature* creature) followCreature = creature; creature->addFollowedByCreature(this); - hasFollowPath = false; - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + + FindPathParams fpp; + getPathSearchParams(followCreature, fpp); + if (getPathTo(creaturePos, listWalkDir, fpp)) { + hasFollowPath = true; + startAutoWalk(); + } else { + hasFollowPath = false; + } } else { followCreature = nullptr; } diff --git a/src/map.cpp b/src/map.cpp index 32937d8ebc..05f6b6f9bc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -764,16 +764,16 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - int32_t prevx = endPos.getX(); - int32_t prevy = endPos.getY(); + int_fast32_t prevx = endPos.getX(); + int_fast32_t prevy = endPos.getY(); found = found->parent; while (found) { pos.x = found->x; pos.y = found->y; - int32_t dx = pos.getX() - prevx; - int32_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; From 60efba9a2bd334b2bc02effc2376992e20b6411d Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 20 Apr 2024 09:13:46 -0700 Subject: [PATCH 46/94] Change std::hypot for much faster std::sqrtf --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 05f6b6f9bc..353c9d6841 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -849,7 +849,7 @@ double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) uint16_t dx = std::abs(p1.x - p2.x); uint16_t dy = std::abs(p1.y - p2.y); - return std::hypot(dx, dy); + return std::sqrtf(dx*dx + dy*dy); } void AStarNodes::clear() From c1d8530097db545c50ed41cecbdbe975c5e43617 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 20 Apr 2024 09:16:08 -0700 Subject: [PATCH 47/94] Formatting --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 353c9d6841..2310a1b089 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -849,7 +849,7 @@ double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) uint16_t dx = std::abs(p1.x - p2.x); uint16_t dy = std::abs(p1.y - p2.y); - return std::sqrtf(dx*dx + dy*dy); + return std::sqrtf(dx * dx + dy * dy); } void AStarNodes::clear() From 13e9d66208c6695c7b0a2d7b442364279f9c30cd Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 20 Apr 2024 09:24:16 -0700 Subject: [PATCH 48/94] Add math.h --- src/otpch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/otpch.h b/src/otpch.h index fbc57677cb..be0bcb3f10 100644 --- a/src/otpch.h +++ b/src/otpch.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include From c3d86cac47f97a1b18a29bb51ee39c634e3d0550 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 20 Apr 2024 09:29:17 -0700 Subject: [PATCH 49/94] Revert sqrtf and math.h --- src/map.cpp | 2 +- src/otpch.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 2310a1b089..7d324e690b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -849,7 +849,7 @@ double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) uint16_t dx = std::abs(p1.x - p2.x); uint16_t dy = std::abs(p1.y - p2.y); - return std::sqrtf(dx * dx + dy * dy); + return std::sqrt(dx * dx + dy * dy); } void AStarNodes::clear() diff --git a/src/otpch.h b/src/otpch.h index be0bcb3f10..fbc57677cb 100644 --- a/src/otpch.h +++ b/src/otpch.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include From 8efe712723725fc41813db7b7bbbaf2196e842f9 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 22 Apr 2024 08:36:34 -0700 Subject: [PATCH 50/94] Remove uneeded path call and add speed check --- src/creature.cpp | 16 +--------------- src/map.cpp | 5 +++++ 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 8eac44b924..f1114b244a 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -940,12 +940,6 @@ bool Creature::setAttackedCreature(Creature* creature) creature->addFollowedByCreature(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); - - FindPathParams fpp; - getPathSearchParams(attackedCreature, fpp); - if (getPathTo(creaturePos, listWalkDir, fpp)) { - startAutoWalk(); - } } else { attackedCreature = nullptr; } @@ -1032,15 +1026,7 @@ bool Creature::setFollowCreature(Creature* creature) followCreature = creature; creature->addFollowedByCreature(this); - - FindPathParams fpp; - getPathSearchParams(followCreature, fpp); - if (getPathTo(creaturePos, listWalkDir, fpp)) { - hasFollowPath = true; - startAutoWalk(); - } else { - hasFollowPath = false; - } + hasFollowPath = false; } else { followCreature = nullptr; } diff --git a/src/map.cpp b/src/map.cpp index 7d324e690b..1902d69cb0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -664,6 +664,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s Position endPos; const Position startPos = pos; + // We can't walk, no need to create path. + if (creature.getSpeed() <= 0) { + return false; + } + // Don't update path. The target is too far away. if (fpp.maxSearchDist) { if (startPos.getDistanceX(targetPos) > fpp.maxSearchDist || From 3c42e9451734e4fc3c4ba4484451b457d749c8c2 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:24:21 -0700 Subject: [PATCH 51/94] Fix rainsalt review --- src/creature.cpp | 13 +------------ src/game.cpp | 5 +---- src/map.cpp | 3 ++- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f1114b244a..4313132094 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -152,7 +152,7 @@ void Creature::forceUpdatePath() return; } - if (lastPathUpdate - OTSYS_TIME() > 0) { + if (lastPathUpdate > OTSYS_TIME()) { return; } @@ -1042,8 +1042,6 @@ void Creature::updateFollowingCreaturesPath() return; } - std::list newList; - newList.resize(followedByCreatures.size()); const Position& thisPosition = getPosition(); for (auto follower : followedByCreatures) { const Position& followerPosition = follower->getPosition(); @@ -1052,17 +1050,8 @@ void Creature::updateFollowingCreaturesPath() continue; } - newList.push_back(follower); g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); } - - followedByCreatures.clear(); - - for (auto follower : followedByCreatures) { - followedByCreatures.push_back(follower); - } - - newList.clear(); } double Creature::getDamageRatio(Creature* attacker) const diff --git a/src/game.cpp b/src/game.cpp index 47d6ef39bf..c1d32afa2d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3887,13 +3887,10 @@ void Game::updateCreaturesPath(size_t index) [=, this]() { updateCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; - auto it = checkCreatureList.begin(), end = checkCreatureList.end(); - while (it != end) { - Creature* creature = *it; + for (Creature* creature : checkCreatureList) { if (!creature->isDead()) { creature->forceUpdatePath(); } - ++it; } cleanup(); diff --git a/src/map.cpp b/src/map.cpp index 1902d69cb0..a1cdf180cf 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -843,7 +843,8 @@ AStarNode* AStarNodes::getBestNode() return nullptr; } - std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); + std::nth_element(nodes.begin(), nodes.end() - 1, nodes.end(), + [](AStarNode* left, AStarNode* right) { return left->f > right->f; }); AStarNode* retNode = nodes.back(); nodes.pop_back(); return retNode; From 297a1bb633faff1bbf0ef474b6f6d6c799878bd4 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:27:30 -0700 Subject: [PATCH 52/94] Update configmanager --- src/configmanager.h | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/configmanager.h b/src/configmanager.h index 49e2801c13..117bc23ab5 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -108,6 +108,8 @@ class ConfigManager GAME_PORT, LOGIN_PORT, STATUS_PORT, + HTTP_PORT, + HTTP_WORKERS, STAIRHOP_DELAY, MARKET_OFFER_DURATION, CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES, @@ -125,31 +127,21 @@ class ConfigManager QUEST_TRACKER_PREMIUM_LIMIT, STAMINA_REGEN_MINUTE, STAMINA_REGEN_PREMIUM, - PATHFINDING_INTERVAL, - PATHFINDING_DELAY, LAST_INTEGER_CONFIG /* this must be the last one */ }; bool load(); - const std::string& getString(string_config_t what) const; - int32_t getNumber(integer_config_t what) const; - bool getBoolean(boolean_config_t what) const; - float getExperienceStage(uint32_t level) const; + const std::string& getString(string_config_t what); + int32_t getNumber(integer_config_t what); + bool getBoolean(boolean_config_t what); + float getExperienceStage(uint32_t level); bool setString(string_config_t what, std::string_view value); bool setNumber(integer_config_t what, int32_t value); bool setBoolean(boolean_config_t what, bool value); -private: - std::string string[LAST_STRING_CONFIG] = {}; - int32_t integer[LAST_INTEGER_CONFIG] = {}; - bool boolean[LAST_BOOLEAN_CONFIG] = {}; - - ExperienceStages expStages = {}; - - bool loaded = false; -}; +}; // namespace ConfigManager #endif // FS_CONFIGMANAGER_H From 147d89619fe651c5fbe3bd2a1c869c2abe78dd5f Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:28:32 -0700 Subject: [PATCH 53/94] Update configmanager --- src/configmanager.h | 249 ++++++++++++++++++++++---------------------- 1 file changed, 122 insertions(+), 127 deletions(-) diff --git a/src/configmanager.h b/src/configmanager.h index 117bc23ab5..2ee4541304 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -4,143 +4,138 @@ #ifndef FS_CONFIGMANAGER_H #define FS_CONFIGMANAGER_H -using ExperienceStages = std::vector>; +namespace ConfigManager { -class ConfigManager +enum boolean_config_t { -public: - ConfigManager(); + ALLOW_CHANGEOUTFIT, + ONE_PLAYER_ON_ACCOUNT, + AIMBOT_HOTKEY_ENABLED, + REMOVE_RUNE_CHARGES, + REMOVE_WEAPON_AMMO, + REMOVE_WEAPON_CHARGES, + REMOVE_POTION_CHARGES, + EXPERIENCE_FROM_PLAYERS, + FREE_PREMIUM, + REPLACE_KICK_ON_LOGIN, + ALLOW_CLONES, + ALLOW_WALKTHROUGH, + BIND_ONLY_GLOBAL_ADDRESS, + OPTIMIZE_DATABASE, + MARKET_PREMIUM, + EMOTE_SPELLS, + STAMINA_SYSTEM, + WARN_UNSAFE_SCRIPTS, + CONVERT_UNSAFE_SCRIPTS, + CLASSIC_EQUIPMENT_SLOTS, + CLASSIC_ATTACK_SPEED, + SCRIPTS_CONSOLE_LOGS, + SERVER_SAVE_NOTIFY_MESSAGE, + SERVER_SAVE_CLEAN_MAP, + SERVER_SAVE_CLOSE, + SERVER_SAVE_SHUTDOWN, + ONLINE_OFFLINE_CHARLIST, + YELL_ALLOW_PREMIUM, + PREMIUM_TO_SEND_PRIVATE, + FORCE_MONSTERTYPE_LOAD, + DEFAULT_WORLD_LIGHT, + HOUSE_OWNED_BY_ACCOUNT, + CLEAN_PROTECTION_ZONES, + HOUSE_DOOR_SHOW_PRICE, + ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS, + REMOVE_ON_DESPAWN, + TWO_FACTOR_AUTH, + MANASHIELD_BREAKABLE, + CHECK_DUPLICATE_STORAGE_KEYS, + MONSTER_OVERSPAWN, - enum boolean_config_t - { - ALLOW_CHANGEOUTFIT, - ONE_PLAYER_ON_ACCOUNT, - AIMBOT_HOTKEY_ENABLED, - REMOVE_RUNE_CHARGES, - REMOVE_WEAPON_AMMO, - REMOVE_WEAPON_CHARGES, - REMOVE_POTION_CHARGES, - EXPERIENCE_FROM_PLAYERS, - FREE_PREMIUM, - REPLACE_KICK_ON_LOGIN, - ALLOW_CLONES, - ALLOW_WALKTHROUGH, - BIND_ONLY_GLOBAL_ADDRESS, - OPTIMIZE_DATABASE, - MARKET_PREMIUM, - EMOTE_SPELLS, - STAMINA_SYSTEM, - WARN_UNSAFE_SCRIPTS, - CONVERT_UNSAFE_SCRIPTS, - CLASSIC_EQUIPMENT_SLOTS, - CLASSIC_ATTACK_SPEED, - SCRIPTS_CONSOLE_LOGS, - SERVER_SAVE_NOTIFY_MESSAGE, - SERVER_SAVE_CLEAN_MAP, - SERVER_SAVE_CLOSE, - SERVER_SAVE_SHUTDOWN, - ONLINE_OFFLINE_CHARLIST, - YELL_ALLOW_PREMIUM, - PREMIUM_TO_SEND_PRIVATE, - FORCE_MONSTERTYPE_LOAD, - DEFAULT_WORLD_LIGHT, - HOUSE_OWNED_BY_ACCOUNT, - CLEAN_PROTECTION_ZONES, - HOUSE_DOOR_SHOW_PRICE, - ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS, - REMOVE_ON_DESPAWN, - TWO_FACTOR_AUTH, - MANASHIELD_BREAKABLE, - CHECK_DUPLICATE_STORAGE_KEYS, - MONSTER_OVERSPAWN, + LAST_BOOLEAN_CONFIG /* this must be the last one */ +}; - LAST_BOOLEAN_CONFIG /* this must be the last one */ - }; - - enum string_config_t - { - MAP_NAME, - HOUSE_RENT_PERIOD, - SERVER_NAME, - OWNER_NAME, - OWNER_EMAIL, - URL, - LOCATION, - IP, - WORLD_TYPE, - MYSQL_HOST, - MYSQL_USER, - MYSQL_PASS, - MYSQL_DB, - MYSQL_SOCK, - DEFAULT_PRIORITY, - MAP_AUTHOR, - CONFIG_FILE, +enum string_config_t +{ + MAP_NAME, + HOUSE_RENT_PERIOD, + SERVER_NAME, + OWNER_NAME, + OWNER_EMAIL, + URL, + LOCATION, + IP, + WORLD_TYPE, + MYSQL_HOST, + MYSQL_USER, + MYSQL_PASS, + MYSQL_DB, + MYSQL_SOCK, + DEFAULT_PRIORITY, + MAP_AUTHOR, + CONFIG_FILE, - LAST_STRING_CONFIG /* this must be the last one */ - }; + LAST_STRING_CONFIG /* this must be the last one */ +}; - enum integer_config_t - { - SQL_PORT, - MAX_PLAYERS, - PZ_LOCKED, - DEFAULT_DESPAWNRANGE, - DEFAULT_DESPAWNRADIUS, - DEFAULT_WALKTOSPAWNRADIUS, - RATE_EXPERIENCE, - RATE_SKILL, - RATE_LOOT, - RATE_MAGIC, - RATE_SPAWN, - HOUSE_PRICE, - KILLS_TO_RED, - KILLS_TO_BLACK, - MAX_MESSAGEBUFFER, - ACTIONS_DELAY_INTERVAL, - EX_ACTIONS_DELAY_INTERVAL, - KICK_AFTER_MINUTES, - PROTECTION_LEVEL, - DEATH_LOSE_PERCENT, - STATUSQUERY_TIMEOUT, - FRAG_TIME, - WHITE_SKULL_TIME, - GAME_PORT, - LOGIN_PORT, - STATUS_PORT, - HTTP_PORT, - HTTP_WORKERS, - STAIRHOP_DELAY, - MARKET_OFFER_DURATION, - CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES, - MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER, - EXP_FROM_PLAYERS_LEVEL_RANGE, - MAX_PACKETS_PER_SECOND, - SERVER_SAVE_NOTIFY_DURATION, - YELL_MINIMUM_LEVEL, - MINIMUM_LEVEL_TO_SEND_PRIVATE, - VIP_FREE_LIMIT, - VIP_PREMIUM_LIMIT, - DEPOT_FREE_LIMIT, - DEPOT_PREMIUM_LIMIT, - QUEST_TRACKER_FREE_LIMIT, - QUEST_TRACKER_PREMIUM_LIMIT, - STAMINA_REGEN_MINUTE, - STAMINA_REGEN_PREMIUM, +enum integer_config_t +{ + SQL_PORT, + MAX_PLAYERS, + PZ_LOCKED, + DEFAULT_DESPAWNRANGE, + DEFAULT_DESPAWNRADIUS, + DEFAULT_WALKTOSPAWNRADIUS, + RATE_EXPERIENCE, + RATE_SKILL, + RATE_LOOT, + RATE_MAGIC, + RATE_SPAWN, + HOUSE_PRICE, + KILLS_TO_RED, + KILLS_TO_BLACK, + MAX_MESSAGEBUFFER, + ACTIONS_DELAY_INTERVAL, + EX_ACTIONS_DELAY_INTERVAL, + KICK_AFTER_MINUTES, + PROTECTION_LEVEL, + DEATH_LOSE_PERCENT, + STATUSQUERY_TIMEOUT, + FRAG_TIME, + WHITE_SKULL_TIME, + GAME_PORT, + LOGIN_PORT, + STATUS_PORT, + HTTP_PORT, + HTTP_WORKERS, + STAIRHOP_DELAY, + MARKET_OFFER_DURATION, + CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES, + MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER, + EXP_FROM_PLAYERS_LEVEL_RANGE, + MAX_PACKETS_PER_SECOND, + SERVER_SAVE_NOTIFY_DURATION, + YELL_MINIMUM_LEVEL, + MINIMUM_LEVEL_TO_SEND_PRIVATE, + VIP_FREE_LIMIT, + VIP_PREMIUM_LIMIT, + DEPOT_FREE_LIMIT, + DEPOT_PREMIUM_LIMIT, + QUEST_TRACKER_FREE_LIMIT, + QUEST_TRACKER_PREMIUM_LIMIT, + STAMINA_REGEN_MINUTE, + STAMINA_REGEN_PREMIUM, - LAST_INTEGER_CONFIG /* this must be the last one */ - }; + LAST_INTEGER_CONFIG /* this must be the last one */ +}; - bool load(); +bool load(); - const std::string& getString(string_config_t what); - int32_t getNumber(integer_config_t what); - bool getBoolean(boolean_config_t what); - float getExperienceStage(uint32_t level); +const std::string& getString(string_config_t what); +int32_t getNumber(integer_config_t what); +bool getBoolean(boolean_config_t what); +float getExperienceStage(uint32_t level); - bool setString(string_config_t what, std::string_view value); - bool setNumber(integer_config_t what, int32_t value); - bool setBoolean(boolean_config_t what, bool value); +bool setString(string_config_t what, std::string_view value); +bool setNumber(integer_config_t what, int32_t value); +bool setBoolean(boolean_config_t what, bool value); }; // namespace ConfigManager From e1f35d5425593fb49ce8fcadda2b62db5a209cc8 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:38:55 -0700 Subject: [PATCH 54/94] Fix configmanager after merge --- src/configmanager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/configmanager.h b/src/configmanager.h index 2ee4541304..e84e8ebfb4 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -122,6 +122,8 @@ enum integer_config_t QUEST_TRACKER_PREMIUM_LIMIT, STAMINA_REGEN_MINUTE, STAMINA_REGEN_PREMIUM, + PATHFINDING_INTERVAL, + PATHFINDING_DELAY, LAST_INTEGER_CONFIG /* this must be the last one */ }; From 89f0402d61deba3b0121ca9c5f5f5ef3f5fb68d5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:44:34 -0700 Subject: [PATCH 55/94] Update to configermanager namespace methods --- src/creature.cpp | 2 +- src/game.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 01e4b41802..74c4aa0013 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -158,7 +158,7 @@ void Creature::forceUpdatePath() return; } - lastPathUpdate = OTSYS_TIME() + g_config.getNumber(ConfigManager::PATHFINDING_DELAY); + lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY); g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } diff --git a/src/game.cpp b/src/game.cpp index f49af54549..4d8c03ea15 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -67,7 +67,7 @@ void Game::start(ServiceManager* manager) serviceManager = manager; g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); - g_scheduler.addEvent(createSchedulerTask(g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL), + g_scheduler.addEvent(createSchedulerTask(getNumber(ConfigManager::PATHFINDING_INTERVAL), [this]() { updateCreaturesPath(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } @@ -3877,7 +3877,7 @@ void Game::checkCreatures(size_t index) void Game::updateCreaturesPath(size_t index) { - g_scheduler.addEvent(createSchedulerTask(g_config.getNumber(ConfigManager::PATHFINDING_INTERVAL), + g_scheduler.addEvent(createSchedulerTask(getNumber(ConfigManager::PATHFINDING_INTERVAL), [=, this]() { updateCreaturesPath((index + 1) % EVENT_CREATURECOUNT); })); auto& checkCreatureList = checkCreatureLists[index]; From 25b6a4b313a79959bddd61ee8646dc244fbc7b40 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:48:26 -0700 Subject: [PATCH 56/94] Clang format --- src/game.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game.cpp b/src/game.cpp index 4d8c03ea15..81e3cdb628 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -67,8 +67,8 @@ void Game::start(ServiceManager* manager) serviceManager = manager; g_scheduler.addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL, [this]() { checkCreatures(0); })); - g_scheduler.addEvent(createSchedulerTask(getNumber(ConfigManager::PATHFINDING_INTERVAL), - [this]() { updateCreaturesPath(0); })); + g_scheduler.addEvent( + createSchedulerTask(getNumber(ConfigManager::PATHFINDING_INTERVAL), [this]() { updateCreaturesPath(0); })); g_scheduler.addEvent(createSchedulerTask(EVENT_DECAYINTERVAL, [this]() { checkDecay(); })); } From 1b78b1083f6cb020df24110b5a9fc74d4230982f Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:58:48 -0700 Subject: [PATCH 57/94] Use getX()/getY() and remove calculateHueristic from AStarNodes --- src/map.cpp | 16 ++++++++-------- src/map.h | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index f71d43c3d6..f09968b86d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -657,6 +657,14 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const return tile; } +double calculateHeuristic(const Position& p1, const Position& p2) +{ + uint16_t dx = std::abs(p1.getX() - p2.getX()); + uint16_t dy = std::abs(p1.getY() - p2.getY()); + + return std::sqrt(dx * dx + dy * dy); +} + bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const { @@ -850,14 +858,6 @@ AStarNode* AStarNodes::getBestNode() return retNode; } -double AStarNodes::calculateHeuristic(const Position& p1, const Position& p2) -{ - uint16_t dx = std::abs(p1.x - p2.x); - uint16_t dy = std::abs(p1.y - p2.y); - - return std::sqrt(dx * dx + dy * dy); -} - void AStarNodes::clear() { nodes.clear(); diff --git a/src/map.h b/src/map.h index 2df4d75ed7..3a11177a93 100644 --- a/src/map.h +++ b/src/map.h @@ -38,7 +38,6 @@ class AStarNodes AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; void clear(); - static double calculateHeuristic(const Position& p1, const Position& p2); static double getMapWalkCost(AStarNode* node, const Position& neighborPos); static double getTileWalkCost(const Creature& creature, const Tile* tile); From 87e3709b2966d2a32a0b02bee496c6dfdca82973 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 7 Sep 2024 20:59:55 -0700 Subject: [PATCH 58/94] Replace AStarNodes:calculateHeuristic --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index f09968b86d..14d5607a13 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -749,7 +749,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // The cost to walk to this neighbor const double g = n->g + AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); - const double h = AStarNodes::calculateHeuristic(pos, targetPos); + const double h = calculateHeuristic(pos, targetPos); const double newf = h + g; if (neighborNode) { From f3cdd1a97cebd3c50dfdb390b940ec3e768bf44c Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Wed, 11 Sep 2024 06:47:16 -0700 Subject: [PATCH 59/94] Add a couple code optimizations --- src/map.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 14d5607a13..07ab7b0f40 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -659,10 +659,7 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const double calculateHeuristic(const Position& p1, const Position& p2) { - uint16_t dx = std::abs(p1.getX() - p2.getX()); - uint16_t dy = std::abs(p1.getY() - p2.getY()); - - return std::sqrt(dx * dx + dy * dy); + return (std::abs(p1.x - p2.x) + std::abs(p1.y - p2.y)) * 10; } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, @@ -678,16 +675,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // Don't update path. The target is too far away. - if (fpp.maxSearchDist) { - if (startPos.getDistanceX(targetPos) > fpp.maxSearchDist || - startPos.getDistanceY(targetPos) > fpp.maxSearchDist) { - return false; - } - } - - // Don't update path. Target in not in the viewport. - if (startPos.getDistanceX(targetPos) > Map::maxViewportX + 1 || - startPos.getDistanceY(targetPos) > Map::maxViewportY + 1) { + int32_t maxDistanceX = fpp.maxSearchDist ? fpp.maxSearchDist : Map::maxClientViewportX + 1; + int32_t maxDistanceY = fpp.maxSearchDist ? fpp.maxSearchDist : Map::maxClientViewportY + 1; + if (startPos.getDistanceX(targetPos) > maxDistanceX || startPos.getDistanceY(targetPos) > maxDistanceY) { return false; } From 4b757d8733f9678a5002110ea5ec19f9a8cd7dc9 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Wed, 11 Sep 2024 06:57:02 -0700 Subject: [PATCH 60/94] Move logic for better performance --- src/map.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 07ab7b0f40..4e6313fe9f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -674,6 +674,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } + // Dont update path. We are on top of our target position. Let dance step decide. + if (startPos.x == targetPos.x && startPos.y == targetPos.y) { + return false; + } + // Don't update path. The target is too far away. int32_t maxDistanceX = fpp.maxSearchDist ? fpp.maxSearchDist : Map::maxClientViewportX + 1; int32_t maxDistanceY = fpp.maxSearchDist ? fpp.maxSearchDist : Map::maxClientViewportY + 1; @@ -681,11 +686,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - // Dont update path. We are on top of our target position. Let dance step decide. - if (startPos.x == targetPos.x && startPos.y == targetPos.y) { - return false; - } - static int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; AStarNodes nodes(pos.x, pos.y); From 591b5f40f6ca574a113c7e4cce19dc2e89bdaf4b Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 16:31:54 -0700 Subject: [PATCH 61/94] Replace std::list for vector and modify datatypes --- src/creature.cpp | 2 +- src/creature.h | 4 ++-- src/map.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 74c4aa0013..be0113dd56 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1045,7 +1045,7 @@ void Creature::updateFollowingCreaturesPath() } const Position& thisPosition = getPosition(); - for (auto follower : followedByCreatures) { + for (const auto follower : followedByCreatures) { const Position& followerPosition = follower->getPosition(); if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { diff --git a/src/creature.h b/src/creature.h index 19e1051ce1..6d3044ddfc 100644 --- a/src/creature.h +++ b/src/creature.h @@ -197,7 +197,7 @@ class Creature : virtual public Thing virtual void onFollowCreatureComplete(const Creature*) {} // Pathfinding functions - virtual void addFollowedByCreature(Creature* creature) { followedByCreatures.push_back(creature); }; + void addFollowedByCreature(Creature* creature) { followedByCreatures.push_back(creature); }; // Pathfinding events void updateFollowingCreaturesPath(); @@ -392,7 +392,7 @@ class Creature : virtual public Thing Creature* attackedCreature = nullptr; Creature* master = nullptr; Creature* followCreature = nullptr; - std::list followedByCreatures; + std::vector followedByCreatures; uint64_t lastStep = 0; int64_t lastPathUpdate = 0; diff --git a/src/map.cpp b/src/map.cpp index 4e6313fe9f..b707e48012 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -686,7 +686,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - static int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; + static constexpr int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; AStarNodes nodes(pos.x, pos.y); From 089df96c8ccc13c216c3fb0be0d1baa80faf4e8d Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 16:44:08 -0700 Subject: [PATCH 62/94] Replace push_back for emplace_back and revert calculateHeuristic --- src/creature.h | 2 +- src/map.cpp | 12 ++++++++---- src/map.h | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/creature.h b/src/creature.h index 6d3044ddfc..f45517457c 100644 --- a/src/creature.h +++ b/src/creature.h @@ -197,7 +197,7 @@ class Creature : virtual public Thing virtual void onFollowCreatureComplete(const Creature*) {} // Pathfinding functions - void addFollowedByCreature(Creature* creature) { followedByCreatures.push_back(creature); }; + void addFollowedByCreature(Creature* creature) { followedByCreatures.emplace_back(creature); }; // Pathfinding events void updateFollowingCreaturesPath(); diff --git a/src/map.cpp b/src/map.cpp index b707e48012..36340c29a2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -659,7 +659,10 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const double calculateHeuristic(const Position& p1, const Position& p2) { - return (std::abs(p1.x - p2.x) + std::abs(p1.y - p2.y)) * 10; + uint16_t dx = std::abs(p1.getX() - p2.getX()); + uint16_t dy = std::abs(p1.getY() - p2.getY()); + + return std::sqrt(dx * dx + dy * dy); } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, @@ -686,7 +689,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - static constexpr int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; + static constexpr int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, + {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; AStarNodes nodes(pos.x, pos.y); @@ -818,7 +822,7 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() // Add node to node vector and map nodes.reserve(50); - nodes.push_back(firstNode); + nodes.emplace_back(firstNode); nodeMap[x][y] = firstNode; } @@ -831,7 +835,7 @@ void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double newNode->g = g; newNode->f = f; - nodes.push_back(newNode); + nodes.emplace_back(newNode); nodeMap[x][y] = newNode; } diff --git a/src/map.h b/src/map.h index 3a11177a93..10f71876b2 100644 --- a/src/map.h +++ b/src/map.h @@ -32,7 +32,7 @@ class AStarNodes AStarNodes(uint16_t x, uint16_t y); void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double g, double f); - void addNode(AStarNode* node) { nodes.push_back(node); }; + void addNode(AStarNode* node) { nodes.emplace_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; From 0d5348369c0e557981adcc10c5341ed0d2ae3c27 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 16:51:58 -0700 Subject: [PATCH 63/94] Replace followedByCreature for followers and update std::array --- src/creature.cpp | 4 ++-- src/creature.h | 4 ++-- src/map.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index be0113dd56..f52e3283f4 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1040,12 +1040,12 @@ bool Creature::setFollowCreature(Creature* creature) // Pathfinding Events void Creature::updateFollowingCreaturesPath() { - if (followedByCreatures.empty()) { + if (followers.empty()) { return; } const Position& thisPosition = getPosition(); - for (const auto follower : followedByCreatures) { + for (const auto follower : followers) { const Position& followerPosition = follower->getPosition(); if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { diff --git a/src/creature.h b/src/creature.h index f45517457c..34fc810568 100644 --- a/src/creature.h +++ b/src/creature.h @@ -197,7 +197,7 @@ class Creature : virtual public Thing virtual void onFollowCreatureComplete(const Creature*) {} // Pathfinding functions - void addFollowedByCreature(Creature* creature) { followedByCreatures.emplace_back(creature); }; + void addFollowedByCreature(Creature* creature) { followers.emplace_back(creature); }; // Pathfinding events void updateFollowingCreaturesPath(); @@ -392,7 +392,7 @@ class Creature : virtual public Thing Creature* attackedCreature = nullptr; Creature* master = nullptr; Creature* followCreature = nullptr; - std::vector followedByCreatures; + std::vector followers; uint64_t lastStep = 0; int64_t lastPathUpdate = 0; diff --git a/src/map.cpp b/src/map.cpp index 36340c29a2..64d052b7b0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -689,8 +689,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - static constexpr int_fast32_t allNeighbors[8][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, - {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; + static constexpr std::array, 8> allNeighbors = { + {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}}; AStarNodes nodes(pos.x, pos.y); @@ -718,8 +718,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } for (uint_fast32_t i = 0; i < 8; ++i) { - pos.x = x + allNeighbors[i][0]; - pos.y = y + allNeighbors[i][1]; + pos.x = x + allNeighbors[i].first; + pos.y = y + allNeighbors[i].second; if (fpp.maxSearchDist != 0 && (startPos.getDistanceX(pos) > fpp.maxSearchDist || startPos.getDistanceY(pos) > fpp.maxSearchDist)) { From b3698e47033ffc49e999d4726cbf4337bb978619 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 16:55:32 -0700 Subject: [PATCH 64/94] Change addFollowedByCreature to addFollower --- src/creature.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature.h b/src/creature.h index 34fc810568..5a39a4cfc6 100644 --- a/src/creature.h +++ b/src/creature.h @@ -197,7 +197,7 @@ class Creature : virtual public Thing virtual void onFollowCreatureComplete(const Creature*) {} // Pathfinding functions - void addFollowedByCreature(Creature* creature) { followers.emplace_back(creature); }; + void addFollower(Creature* creature) { followers.emplace_back(creature); }; // Pathfinding events void updateFollowingCreaturesPath(); From de8be8776e62002d724f91cfd65b54222c9a31e5 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 17:00:36 -0700 Subject: [PATCH 65/94] Update method calls --- src/creature.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f52e3283f4..b72228defa 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -939,7 +939,7 @@ bool Creature::setAttackedCreature(Creature* creature) } attackedCreature = creature; - creature->addFollowedByCreature(this); + creature->addFollower(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); } else { @@ -1027,7 +1027,7 @@ bool Creature::setFollowCreature(Creature* creature) } followCreature = creature; - creature->addFollowedByCreature(this); + creature->addFollower(this); hasFollowPath = false; } else { followCreature = nullptr; From 523821a5662fe9d43ed97a35b67d33f7a6b40215 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 20:30:15 -0700 Subject: [PATCH 66/94] Add additional checks for redundant pathfinding calls --- src/map.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 64d052b7b0..b9306b728a 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -677,9 +677,16 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - // Dont update path. We are on top of our target position. Let dance step decide. - if (startPos.x == targetPos.x && startPos.y == targetPos.y) { - return false; + // We can't get paths up or down floors. + if (startPos.getZ() != targetPos.getZ()) return false; + + // We are on top of our target position. Let dance step decide. + if (!fpp.keepDistance && startPos.getX() == targetPos.getX() && startPos.getY() == targetPos.getY()) return true; + + // We are next to our target. Let dance step decide. + if (!fpp.keepDistance && + startPos.getDistanceX(targetPos) + startPos.getDistanceY(targetPos) <= 2) { + return true; } // Don't update path. The target is too far away. From 7a07da2b99334cc5a8a572cb0da69693071c26b4 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 20:31:23 -0700 Subject: [PATCH 67/94] Remove redundant check --- src/map.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index b9306b728a..fba130c528 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -680,9 +680,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s // We can't get paths up or down floors. if (startPos.getZ() != targetPos.getZ()) return false; - // We are on top of our target position. Let dance step decide. - if (!fpp.keepDistance && startPos.getX() == targetPos.getX() && startPos.getY() == targetPos.getY()) return true; - // We are next to our target. Let dance step decide. if (!fpp.keepDistance && startPos.getDistanceX(targetPos) + startPos.getDistanceY(targetPos) <= 2) { From fac752f56044670379fb891f5cbf0ec41899ca4e Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 12 Sep 2024 20:32:28 -0700 Subject: [PATCH 68/94] Clang Format --- src/map.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index fba130c528..04a90afa47 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -681,8 +681,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (startPos.getZ() != targetPos.getZ()) return false; // We are next to our target. Let dance step decide. - if (!fpp.keepDistance && - startPos.getDistanceX(targetPos) + startPos.getDistanceY(targetPos) <= 2) { + if (!fpp.keepDistance && startPos.getDistanceX(targetPos) + startPos.getDistanceY(targetPos) <= 2) { return true; } From 27a16c75cf713c959939e71075ab8e4b05d6741d Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 13 Sep 2024 06:15:49 -0700 Subject: [PATCH 69/94] Change updateFollowingCreaturePaths to updateFollowersPaths --- src/creature.cpp | 4 ++-- src/creature.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index b72228defa..abecc86b31 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -206,7 +206,7 @@ void Creature::onWalk() } } - updateFollowingCreaturesPath(); + updateFollowersPaths(); if (cancelNextWalk) { listWalkDir.clear(); @@ -1038,7 +1038,7 @@ bool Creature::setFollowCreature(Creature* creature) } // Pathfinding Events -void Creature::updateFollowingCreaturesPath() +void Creature::updateFollowersPaths() { if (followers.empty()) { return; diff --git a/src/creature.h b/src/creature.h index 5a39a4cfc6..e67fe6d199 100644 --- a/src/creature.h +++ b/src/creature.h @@ -200,7 +200,7 @@ class Creature : virtual public Thing void addFollower(Creature* creature) { followers.emplace_back(creature); }; // Pathfinding events - void updateFollowingCreaturesPath(); + void updateFollowersPaths(); // combat functions Creature* getAttackedCreature() { return attackedCreature; } From 76241a55be7d5a23347e124a0102e94265d93469 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 16 Sep 2024 07:20:40 -0700 Subject: [PATCH 70/94] Fix a problem in most recent path conditional --- src/map.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 04a90afa47..f87451aa5b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -681,8 +681,10 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (startPos.getZ() != targetPos.getZ()) return false; // We are next to our target. Let dance step decide. - if (!fpp.keepDistance && startPos.getDistanceX(targetPos) + startPos.getDistanceY(targetPos) <= 2) { - return true; + if (!fpp.keepDistance && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { + if (!creature.isSummon()) { + return true; + } } // Don't update path. The target is too far away. From ef92d7ae57c72b07568e025507e1d48657a6fe0a Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 17 Sep 2024 08:19:20 -0700 Subject: [PATCH 71/94] Fix bug in pre path conditional check --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index f87451aa5b..3b7eb19d69 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -681,7 +681,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (startPos.getZ() != targetPos.getZ()) return false; // We are next to our target. Let dance step decide. - if (!fpp.keepDistance && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { + if (fpp.maxTargetDist > 1 && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { if (!creature.isSummon()) { return true; } From 2abf23001c65a211c8d280e772caaad144db9110 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Tue, 17 Sep 2024 08:25:06 -0700 Subject: [PATCH 72/94] Fix logic in last commit --- src/map.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 3b7eb19d69..0103cf1272 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -681,10 +681,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s if (startPos.getZ() != targetPos.getZ()) return false; // We are next to our target. Let dance step decide. - if (fpp.maxTargetDist > 1 && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { - if (!creature.isSummon()) { - return true; - } + if (fpp.maxTargetDist <= 1 && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { + return true; } // Don't update path. The target is too far away. From 6bf2b1f3791dc0ad1e6d65143dd4008d6ad0b177 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 20 Sep 2024 03:42:36 -0700 Subject: [PATCH 73/94] Add required nullptr check to stop crashes on creature death --- src/creature.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index abecc86b31..a62d74386e 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1046,13 +1046,15 @@ void Creature::updateFollowersPaths() const Position& thisPosition = getPosition(); for (const auto follower : followers) { - const Position& followerPosition = follower->getPosition(); - if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || - thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { - continue; - } + if (follower != nullptr) { + const Position& followerPosition = follower->getPosition(); + if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || + thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { + continue; + } - g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); + g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); + } } } From 3fdb59ff6f56b2bf9394ba9fd3905cf1401ddb32 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 20 Sep 2024 04:25:29 -0700 Subject: [PATCH 74/94] Revert crash unrelated --- src/creature.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index a62d74386e..abecc86b31 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -1046,15 +1046,13 @@ void Creature::updateFollowersPaths() const Position& thisPosition = getPosition(); for (const auto follower : followers) { - if (follower != nullptr) { - const Position& followerPosition = follower->getPosition(); - if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || - thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { - continue; - } - - g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); + const Position& followerPosition = follower->getPosition(); + if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || + thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { + continue; } + + g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); } } From 743b703f475489efcde202c398eec5141f354797 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Mon, 23 Sep 2024 18:39:11 -0700 Subject: [PATCH 75/94] Add updateCreaturesPath --- src/game.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game.h b/src/game.h index 40881a29a1..496f9c0f44 100644 --- a/src/game.h +++ b/src/game.h @@ -424,6 +424,7 @@ class Game void updateCreatureWalk(uint32_t creatureId); void checkCreatureAttack(uint32_t creatureId); void checkCreatures(size_t index); + void updateCreaturesPath(size_t index); bool combatBlockHit(CombatDamage& damage, Creature* attacker, Creature* target, bool checkDefense, bool checkArmor, bool field, bool ignoreResistances = false); From c7fbc3fecbac473508a02b142a9b81c8750d81d2 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Fri, 31 Jan 2025 17:52:55 -0800 Subject: [PATCH 76/94] Convert calculate heuristic to int --- src/map.cpp | 20 ++++++++++---------- src/map.h | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 0103cf1272..bd1d7e9822 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -657,12 +657,12 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const return tile; } -double calculateHeuristic(const Position& p1, const Position& p2) +uint16_t calculateHeuristic(const Position& p1, const Position& p2) { - uint16_t dx = std::abs(p1.getX() - p2.getX()); - uint16_t dy = std::abs(p1.getY() - p2.getY()); + uint16_t dx = p1.getX() - p2.getX(); + uint16_t dy = p1.getY() - p2.getY(); - return std::sqrt(dx * dx + dy * dy); + return dx * dx + dy * dy; } bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector& dirList, @@ -745,9 +745,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // The cost to walk to this neighbor - const double g = n->g + AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); - const double h = calculateHeuristic(pos, targetPos); - const double newf = h + g; + const uint16_t g = n->g + AStarNodes::getMapWalkCost(n, pos) + AStarNodes::getTileWalkCost(creature, tile); + const uint16_t h = calculateHeuristic(pos, targetPos); + const uint16_t newf = h + g; if (neighborNode) { if (neighborNode->f <= newf) { @@ -829,7 +829,7 @@ AStarNodes::AStarNodes(uint16_t x, uint16_t y) : nodes(), nodeMap() nodeMap[x][y] = firstNode; } -void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double g, double f) +void AStarNodes::createNewNode(AStarNode* parent, uint16_t x, uint16_t y, uint16_t g, uint16_t f) { AStarNode* newNode = new AStarNode; newNode->parent = parent; @@ -861,7 +861,7 @@ void AStarNodes::clear() nodeMap.clear(); }; -double AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) +uint16_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { // diagonal movement extra cost @@ -870,7 +870,7 @@ double AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) return MAP_NORMALWALKCOST; } -double AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) +uint16_t AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) { double cost = 0; if (tile->getTopVisibleCreature(&creature)) { diff --git a/src/map.h b/src/map.h index 10f71876b2..eeb4c7abc4 100644 --- a/src/map.h +++ b/src/map.h @@ -18,28 +18,28 @@ struct FindPathParams; struct AStarNode { AStarNode* parent; - double g; - double f; + uint16_t g; + uint16_t f; uint16_t x, y; }; -static constexpr float MAP_NORMALWALKCOST = 1.0f; -static constexpr float MAP_DIAGONALWALKCOST = 2.5f; +static constexpr uint16_t MAP_NORMALWALKCOST = 10; +static constexpr uint16_t MAP_DIAGONALWALKCOST = 25; class AStarNodes { public: AStarNodes(uint16_t x, uint16_t y); - void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, double g, double f); + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, uint16_t g, uint16_t f); void addNode(AStarNode* node) { nodes.emplace_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; void clear(); - static double getMapWalkCost(AStarNode* node, const Position& neighborPos); - static double getTileWalkCost(const Creature& creature, const Tile* tile); + static uint16_t getMapWalkCost(AStarNode* node, const Position& neighborPos); + static uint16_t getTileWalkCost(const Creature& creature, const Tile* tile); private: std::vector nodes; From bbd357cc4c0cb5570706ae9d73b669f0d90c90e1 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 2 Feb 2025 11:26:42 -0800 Subject: [PATCH 77/94] Convert to new code style --- src/creature.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f3ea6c73f7..3488e6af68 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -727,14 +727,13 @@ void Creature::setAttackedCreature(Creature* creature) return; } - if (!canAttackCreature(creature)) { removeAttackedCreature(); return; } - - attackedCreature = creature; - creature->addFollower(this); + + attackedCreature = creature; + creature->addFollower(this); onAttackedCreature(attackedCreature); attackedCreature->onAttacked(); @@ -782,6 +781,8 @@ void Creature::setFollowCreature(Creature* creature) } followCreature = creature; + creature->addFollower(this); + hasFollowPath = false; onFollowCreature(creature); } @@ -806,13 +807,9 @@ void Creature::onFollowCreature(const Creature*) listWalkDir.clear(); onWalkAborted(); } - - followCreature = creature; - creature->addFollower(this); - hasFollowPath = false; } -void Creature::onUnfollowCreature() { isUpdatingPath = false; } +void Creature::onUnfollowCreature() { hasFollowPath = false; } // Pathfinding Events void Creature::updateFollowersPaths() From 1b8cd02b44765eba73c896e6975a4e6a36bbf450 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 2 Feb 2025 12:10:39 -0800 Subject: [PATCH 78/94] Fix memory leak in followers --- src/creature.cpp | 17 +++++++++++++++++ src/creature.h | 1 + 2 files changed, 18 insertions(+) diff --git a/src/creature.cpp b/src/creature.cpp index 3488e6af68..d9ffe20a04 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -135,6 +135,12 @@ void Creature::onThink(uint32_t interval) blockTicks = 0; } + for (auto* creature : followers) { + if (!canSeeCreature(creature) || getPosition().z != creature->getPosition().z) { + removeFollower(creature); + } + } + // scripting event - onThink const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEvent* thinkEvent : thinkEvents) { @@ -812,6 +818,17 @@ void Creature::onFollowCreature(const Creature*) void Creature::onUnfollowCreature() { hasFollowPath = false; } // Pathfinding Events +void Creature::removeFollower(Creature* creature) +{ + for (auto it = followers.begin(); it != followers.end();) { + if (*it == creature) { + it = followers.erase(it); + } else { + ++it; + } + } +} + void Creature::updateFollowersPaths() { if (followers.empty()) { diff --git a/src/creature.h b/src/creature.h index 9c8cb2d8ab..1ec0670e84 100644 --- a/src/creature.h +++ b/src/creature.h @@ -202,6 +202,7 @@ class Creature : virtual public Thing // Pathfinding functions void addFollower(Creature* creature) { followers.emplace_back(creature); }; + void removeFollower(Creature* creature); // Pathfinding events void updateFollowersPaths(); From fdc0405d6c82c7cc245f603373ad0a12414475eb Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Wed, 5 Feb 2025 11:03:18 -0800 Subject: [PATCH 79/94] Additional nodes clear for possible memory leak --- src/map.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/map.cpp b/src/map.cpp index 1a74e2eb71..742e8b5643 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -697,6 +697,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s iterations++; if (iterations >= 200) { + nodes.clear(); return false; } From 049a357115af92fcfac8395cee3dd21e4ed1ba64 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Wed, 5 Feb 2025 12:05:28 -0800 Subject: [PATCH 80/94] Fix logic for when to remove follower --- src/creature.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/creature.cpp b/src/creature.cpp index d9ffe20a04..c2c1ff0da9 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -135,8 +135,11 @@ void Creature::onThink(uint32_t interval) blockTicks = 0; } + const Position& position = getPosition(); for (auto* creature : followers) { - if (!canSeeCreature(creature) || getPosition().z != creature->getPosition().z) { + const Position& followerPosition = creature->getPosition(); + uint16_t distance = position.getDistanceX(followerPosition) + position.getDistanceY(followerPosition); + if (distance >= Map::maxViewportX + Map::maxViewportY || getPosition().z != creature->getPosition().z) { removeFollower(creature); } } From 60a4f1fd6153b39eab842cda58524d99b6f65b20 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 8 Feb 2025 19:37:08 -0800 Subject: [PATCH 81/94] Dynamically allocated nodes MUST be deleted. --- src/map.cpp | 6 ------ src/map.h | 10 +++++++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 742e8b5643..88844749e0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -848,12 +848,6 @@ AStarNode* AStarNodes::getBestNode() return retNode; } -void AStarNodes::clear() -{ - nodes.clear(); - nodeMap.clear(); -}; - uint16_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index 4eaced5fed..bad5cdcb75 100644 --- a/src/map.h +++ b/src/map.h @@ -31,12 +31,20 @@ class AStarNodes public: AStarNodes(uint16_t x, uint16_t y); + ~AStarNodes() + { + for (AStarNode* node : nodes) { + delete node; + } + nodes.clear(); + nodeMap.clear(); + } + void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, uint16_t g, uint16_t f); void addNode(AStarNode* node) { nodes.emplace_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; - void clear(); static uint16_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static uint16_t getTileWalkCost(const Creature& creature, const Tile* tile); From 6ca6047601478111d76910b79b604ed13367ea6b Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 8 Feb 2025 19:38:27 -0800 Subject: [PATCH 82/94] Remove nodes.clear() --- src/map.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 88844749e0..3bdf320d61 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -697,7 +697,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s iterations++; if (iterations >= 200) { - nodes.clear(); return false; } @@ -761,8 +760,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s n = nodes.getBestNode(); } - nodes.clear(); - if (!found) { return false; } From 02c0b263a592aadf9aa4de1aecebd4c3f55f2e20 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 8 Feb 2025 20:00:16 -0800 Subject: [PATCH 83/94] Revert --- src/map.cpp | 9 +++++++++ src/map.h | 10 +--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 3bdf320d61..742e8b5643 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -697,6 +697,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s iterations++; if (iterations >= 200) { + nodes.clear(); return false; } @@ -760,6 +761,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s n = nodes.getBestNode(); } + nodes.clear(); + if (!found) { return false; } @@ -845,6 +848,12 @@ AStarNode* AStarNodes::getBestNode() return retNode; } +void AStarNodes::clear() +{ + nodes.clear(); + nodeMap.clear(); +}; + uint16_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index bad5cdcb75..4eaced5fed 100644 --- a/src/map.h +++ b/src/map.h @@ -31,20 +31,12 @@ class AStarNodes public: AStarNodes(uint16_t x, uint16_t y); - ~AStarNodes() - { - for (AStarNode* node : nodes) { - delete node; - } - nodes.clear(); - nodeMap.clear(); - } - void createNewNode(AStarNode* parent, uint16_t x, uint16_t y, uint16_t g, uint16_t f); void addNode(AStarNode* node) { nodes.emplace_back(node); }; AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; + void clear(); static uint16_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static uint16_t getTileWalkCost(const Creature& creature, const Tile* tile); From 6f2bb7a3cb9c511896a359b9b053d4acc47c2cdc Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 20 Feb 2025 13:01:51 -0800 Subject: [PATCH 84/94] Fix pathfinding delays. --- src/creature.cpp | 20 ++++++++++++++------ src/map.cpp | 5 +++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index c2c1ff0da9..cd1b52f3b1 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -840,13 +840,21 @@ void Creature::updateFollowersPaths() const Position& thisPosition = getPosition(); for (const auto follower : followers) { - const Position& followerPosition = follower->getPosition(); - if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX + 2 || - thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY + 2) { - continue; - } + if (follower != nullptr) { + const Position& followerPosition = follower->getPosition(); + + if (lastPathUpdate - OTSYS_TIME() > 0) { + continue; + } - g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); + if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX || + thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY) { + continue; + } + + g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); })); + follower->lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY); + } } } diff --git a/src/map.cpp b/src/map.cpp index 742e8b5643..1f3d93c615 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -664,6 +664,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s Position endPos; const Position startPos = pos; + // We are trying to find paths too fast. + if (creature.lastPathUpdate - OTSYS_TIME() > 0) { + return false; + } + // We can't walk, no need to create path. if (creature.getSpeed() <= 0) { return false; From f7fa3833bb7a73082810c48beab5aec3599d8a11 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 20 Feb 2025 13:27:43 -0800 Subject: [PATCH 85/94] Remove delay check in map.cpp and add in correct places. --- src/creature.cpp | 5 ++++- src/map.cpp | 5 ----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index cd1b52f3b1..31f1913b20 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -223,7 +223,10 @@ void Creature::onWalk() } if (attackedCreature || followCreature) { - g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + if (lastPathUpdate - OTSYS_TIME() > 0) { + g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); + lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY); + } } } diff --git a/src/map.cpp b/src/map.cpp index 1f3d93c615..742e8b5643 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -664,11 +664,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s Position endPos; const Position startPos = pos; - // We are trying to find paths too fast. - if (creature.lastPathUpdate - OTSYS_TIME() > 0) { - return false; - } - // We can't walk, no need to create path. if (creature.getSpeed() <= 0) { return false; From 0d9fc3d59742b1a279e3149febccbea47067c359 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 20 Feb 2025 13:45:06 -0800 Subject: [PATCH 86/94] Fix typo --- src/creature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creature.cpp b/src/creature.cpp index 31f1913b20..f5f300d5d6 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -846,7 +846,7 @@ void Creature::updateFollowersPaths() if (follower != nullptr) { const Position& followerPosition = follower->getPosition(); - if (lastPathUpdate - OTSYS_TIME() > 0) { + if (follower->lastPathUpdate - OTSYS_TIME() > 0) { continue; } From c4201c661465d1352ca30e3c7e45bf6f0a8a19c0 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Thu, 20 Feb 2025 19:45:18 -0800 Subject: [PATCH 87/94] Check for duplicate creatures, add optimization, and remove uneeded --- src/creature.cpp | 29 +++++++++++++++++++---------- src/creature.h | 3 ++- src/game.cpp | 2 -- src/map.cpp | 11 +++++++++-- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index f5f300d5d6..0cf58a6212 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -157,10 +157,6 @@ void Creature::forceUpdatePath() return; } - if (lastPathUpdate > OTSYS_TIME()) { - return; - } - lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY); g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); })); } @@ -824,14 +820,27 @@ void Creature::onFollowCreature(const Creature*) void Creature::onUnfollowCreature() { hasFollowPath = false; } // Pathfinding Events +bool Creature::isFollower(Creature* creature) +{ + auto it = std::find(followers.begin(), followers.end(), creature); + if (it != followers.end()) { + return true; + } + return false; +} + +void Creature::addFollower(Creature* creature) +{ + if (!isFollower(creature)) { + followers.push_back(creature); + } +} + void Creature::removeFollower(Creature* creature) { - for (auto it = followers.begin(); it != followers.end();) { - if (*it == creature) { - it = followers.erase(it); - } else { - ++it; - } + auto it = std::find(followers.begin(), followers.end(), creature); + if (it != followers.end()) { + followers.erase(it); } } diff --git a/src/creature.h b/src/creature.h index 1ec0670e84..44a60d0243 100644 --- a/src/creature.h +++ b/src/creature.h @@ -201,7 +201,8 @@ class Creature : virtual public Thing virtual void onUnfollowCreature(); // Pathfinding functions - void addFollower(Creature* creature) { followers.emplace_back(creature); }; + bool isFollower(Creature* creature); + void addFollower(Creature* creature); void removeFollower(Creature* creature); // Pathfinding events diff --git a/src/game.cpp b/src/game.cpp index 5cd4c42c6e..58f0afaf3c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3897,8 +3897,6 @@ void Game::updateCreaturesPath(size_t index) creature->forceUpdatePath(); } } - - cleanup(); } void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta) diff --git a/src/map.cpp b/src/map.cpp index 742e8b5643..27072579fa 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -670,7 +670,9 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } // We can't get paths up or down floors. - if (startPos.getZ() != targetPos.getZ()) return false; + if (startPos.getZ() != targetPos.getZ()) { + return false; + } // We are next to our target. Let dance step decide. if (fpp.maxTargetDist <= 1 && startPos.getDistanceX(targetPos) <= 1 && startPos.getDistanceY(targetPos) <= 1) { @@ -696,7 +698,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s while (n) { iterations++; - if (iterations >= 200) { + if (iterations >= 120) { nodes.clear(); return false; } @@ -722,6 +724,11 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } + if (startPos.getDistanceX(pos) >= Map::maxViewportX + 1 || + startPos.getDistanceY(pos) >= Map::maxViewportY + 1) { + break; + } + if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) { continue; } From d4701a0759edc019ca28f59ec40d258e7934c011 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 22 Feb 2025 16:07:50 -0800 Subject: [PATCH 88/94] Modify config values for best performance while maintaining proper following behavior --- config.lua.dist | 8 ++++---- src/configmanager.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index a72f7e07eb..98e310fc9a 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -38,10 +38,10 @@ maxPacketsPerSecond = 25 enableTwoFactorAuth = true -- Pathfinding --- NOTE: pathfindingInterval how often paths are force drawn --- NOTE: pathfindingDelay delay recently force drawn paths from drawing again -pathfindingInterval = 100 -pathfindingDelay = 200 +-- pathfindingInterval how often paths are force drawn +-- pathfindingDelay delay recently force drawn paths from drawing again +pathfindingInterval = 200 +pathfindingDelay = 300 -- Deaths -- NOTE: Leave deathLosePercent as -1 if you want to use the default diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 4da5eeb0e0..976558d6cf 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -292,8 +292,8 @@ bool ConfigManager::load() integer[QUEST_TRACKER_PREMIUM_LIMIT] = getGlobalNumber(L, "questTrackerPremiumLimit", 15); integer[STAMINA_REGEN_MINUTE] = getGlobalNumber(L, "timeToRegenMinuteStamina", 3 * 60); integer[STAMINA_REGEN_PREMIUM] = getGlobalNumber(L, "timeToRegenMinutePremiumStamina", 6 * 60); - integer[PATHFINDING_INTERVAL] = getGlobalNumber(L, "pathfindingInterval", 100); - integer[PATHFINDING_DELAY] = getGlobalNumber(L, "pathfindingDelay", 200); + integer[PATHFINDING_INTERVAL] = getGlobalNumber(L, "pathfindingInterval", 200); + integer[PATHFINDING_DELAY] = getGlobalNumber(L, "pathfindingDelay", 300); expStages = loadXMLStages(); if (expStages.empty()) { From c31ebb1c93fd6b12ed5d81b599a6820261caeea9 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 1 Mar 2025 16:44:12 -0800 Subject: [PATCH 89/94] Fix datatype typo --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 27072579fa..24e41d5c33 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -872,7 +872,7 @@ uint16_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos uint16_t AStarNodes::getTileWalkCost(const Creature& creature, const Tile* tile) { - double cost = 0; + uint16_t cost = 0; if (tile->getTopVisibleCreature(&creature)) { // destroy creature cost cost += MAP_NORMALWALKCOST * 3; From d0fc8267f00b3e7d934125d6f4a30230bff84e32 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 26 Apr 2025 13:54:07 -0700 Subject: [PATCH 90/94] Optimize removeFollower code && update datatypes. --- src/creature.cpp | 32 ++++++++++++++------------------ src/creature.h | 2 +- src/map.cpp | 18 +++++++++--------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 0cf58a6212..360697e802 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -135,15 +135,6 @@ void Creature::onThink(uint32_t interval) blockTicks = 0; } - const Position& position = getPosition(); - for (auto* creature : followers) { - const Position& followerPosition = creature->getPosition(); - uint16_t distance = position.getDistanceX(followerPosition) + position.getDistanceY(followerPosition); - if (distance >= Map::maxViewportX + Map::maxViewportY || getPosition().z != creature->getPosition().z) { - removeFollower(creature); - } - } - // scripting event - onThink const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEvent* thinkEvent : thinkEvents) { @@ -205,6 +196,7 @@ void Creature::onWalk() } } + removeFollowers(); updateFollowersPaths(); if (cancelNextWalk) { @@ -823,10 +815,7 @@ void Creature::onUnfollowCreature() { hasFollowPath = false; } bool Creature::isFollower(Creature* creature) { auto it = std::find(followers.begin(), followers.end(), creature); - if (it != followers.end()) { - return true; - } - return false; + return it != followers.end(); } void Creature::addFollower(Creature* creature) @@ -836,11 +825,18 @@ void Creature::addFollower(Creature* creature) } } -void Creature::removeFollower(Creature* creature) +void Creature::removeFollowers() { - auto it = std::find(followers.begin(), followers.end(), creature); - if (it != followers.end()) { - followers.erase(it); + const Position& position = getPosition(); + for (auto* creature : followers) { + const Position& followerPosition = creature->getPosition(); + uint16_t distance = position.getDistanceX(followerPosition) + position.getDistanceY(followerPosition); + if (distance >= Map::maxViewportX + Map::maxViewportY || getPosition().z != creature->getPosition().z) { + auto it = std::find(followers.begin(), followers.end(), creature); + if (it != followers.end()) { + followers.erase(it); + } + } } } @@ -851,7 +847,7 @@ void Creature::updateFollowersPaths() } const Position& thisPosition = getPosition(); - for (const auto follower : followers) { + for (const auto& follower : followers) { if (follower != nullptr) { const Position& followerPosition = follower->getPosition(); diff --git a/src/creature.h b/src/creature.h index 44a60d0243..a6071d3a5d 100644 --- a/src/creature.h +++ b/src/creature.h @@ -203,7 +203,7 @@ class Creature : virtual public Thing // Pathfinding functions bool isFollower(Creature* creature); void addFollower(Creature* creature); - void removeFollower(Creature* creature); + void removeFollowers(); // Pathfinding events void updateFollowersPaths(); diff --git a/src/map.cpp b/src/map.cpp index 24e41d5c33..d2a3f58648 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -686,14 +686,14 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - static constexpr std::array, 8> allNeighbors = { + const std::array, 8> allNeighbors = { {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}}; AStarNodes nodes(pos.x, pos.y); AStarNode* found = nullptr; int32_t bestMatch = 0; - int16_t iterations = 0; + uint8_t iterations = 0; AStarNode* n = nodes.getBestNode(); while (n) { iterations++; @@ -703,8 +703,8 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - const int_fast32_t x = n->x; - const int_fast32_t y = n->y; + const int32_t x = n->x; + const int32_t y = n->y; pos.x = x; pos.y = y; if (pathCondition(startPos, pos, fpp, bestMatch)) { @@ -715,7 +715,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s } } - for (uint_fast32_t i = 0; i < 8; ++i) { + for (uint8_t i = 0; i < 8; ++i) { pos.x = x + allNeighbors[i].first; pos.y = y + allNeighbors[i].second; @@ -774,16 +774,16 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - int_fast32_t prevx = endPos.getX(); - int_fast32_t prevy = endPos.getY(); + int32_t prevx = endPos.getX(); + int32_t prevy = endPos.getY(); 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; + int32_t dx = pos.getX() - prevx; + int32_t dy = pos.getY() - prevy; prevx = pos.x; prevy = pos.y; From 8ef6c7fdeaf8bf48db68f47e29d6caf7c0dcc4a7 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 26 Apr 2025 14:05:49 -0700 Subject: [PATCH 91/94] Update CMake_Lists --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21c3d4dfc8..bad49a032e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,4 +130,4 @@ if(NOT SKIP_GIT) endif() ### END Git Version ### -target_precompile_headers(tfs PUBLIC src/otpch.h) +target_precompile_headers(tfs PUBLIC src/otpch.h) \ No newline at end of file From 7aae302ced226c3f7693a0da6f331e074102914a Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 26 Apr 2025 14:07:02 -0700 Subject: [PATCH 92/94] Revert static const --- src/map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index d2a3f58648..effc8675eb 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -686,7 +686,7 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s return false; } - const std::array, 8> allNeighbors = { + static constexpr std::array, 8> allNeighbors = { {{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}}}; AStarNodes nodes(pos.x, pos.y); From a3c7744416f1002c0bb627b129da21521ea6d39a Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sat, 26 Apr 2025 15:54:14 -0700 Subject: [PATCH 93/94] Modify removefollower O(n2) to O(n) --- src/creature.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/creature.cpp b/src/creature.cpp index 360697e802..dcb872a3e4 100644 --- a/src/creature.cpp +++ b/src/creature.cpp @@ -828,16 +828,16 @@ void Creature::addFollower(Creature* creature) void Creature::removeFollowers() { const Position& position = getPosition(); - for (auto* creature : followers) { - const Position& followerPosition = creature->getPosition(); - uint16_t distance = position.getDistanceX(followerPosition) + position.getDistanceY(followerPosition); - if (distance >= Map::maxViewportX + Map::maxViewportY || getPosition().z != creature->getPosition().z) { - auto it = std::find(followers.begin(), followers.end(), creature); - if (it != followers.end()) { - followers.erase(it); - } - } - } + + followers.erase(std::remove_if(followers.begin(), followers.end(), + [&position](Creature* creature) { + const Position& followerPosition = creature->getPosition(); + uint16_t distance = position.getDistanceX(followerPosition) + + position.getDistanceY(followerPosition); + return distance >= Map::maxViewportX + Map::maxViewportY || + position.z != followerPosition.z; + }), + followers.end()); } void Creature::updateFollowersPaths() From b7d11d4db22cae494695897e39d93e148abeff18 Mon Sep 17 00:00:00 2001 From: NRH-AA Date: Sun, 11 May 2025 07:37:28 -0700 Subject: [PATCH 94/94] Code cleanup, Comments, remove uneeded code --- config.lua.dist | 5 +++-- src/creature.h | 1 - src/map.cpp | 14 -------------- src/map.h | 1 - 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index 98e310fc9a..96c1221bd3 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -38,8 +38,9 @@ maxPacketsPerSecond = 25 enableTwoFactorAuth = true -- Pathfinding --- pathfindingInterval how often paths are force drawn --- pathfindingDelay delay recently force drawn paths from drawing again +-- pathfindingInterval handles how often paths are force drawn +-- pathfindingDelay delays any recently drawn paths from drawing again +-- pathfindingDelay does not delay pathfindingInterval pathfindingInterval = 200 pathfindingDelay = 300 diff --git a/src/creature.h b/src/creature.h index a6071d3a5d..c16ac6c48f 100644 --- a/src/creature.h +++ b/src/creature.h @@ -425,7 +425,6 @@ class Creature : virtual public Thing Skulls_t skull = SKULL_NONE; bool isInternalRemoved = false; - bool isMapLoaded = false; bool creatureCheck = false; bool inCheckCreaturesVector = false; bool skillLoss = true; diff --git a/src/map.cpp b/src/map.cpp index effc8675eb..ce07509f35 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -699,7 +699,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s iterations++; if (iterations >= 120) { - nodes.clear(); return false; } @@ -724,11 +723,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s continue; } - if (startPos.getDistanceX(pos) >= Map::maxViewportX + 1 || - startPos.getDistanceY(pos) >= Map::maxViewportY + 1) { - break; - } - if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) { continue; } @@ -768,8 +762,6 @@ bool Map::getPathMatching(const Creature& creature, const Position& targetPos, s n = nodes.getBestNode(); } - nodes.clear(); - if (!found) { return false; } @@ -855,12 +847,6 @@ AStarNode* AStarNodes::getBestNode() return retNode; } -void AStarNodes::clear() -{ - nodes.clear(); - nodeMap.clear(); -}; - uint16_t AStarNodes::getMapWalkCost(AStarNode* node, const Position& neighborPos) { if (std::abs(node->x - neighborPos.x) == std::abs(node->y - neighborPos.y)) { diff --git a/src/map.h b/src/map.h index 4eaced5fed..386b4180e5 100644 --- a/src/map.h +++ b/src/map.h @@ -36,7 +36,6 @@ class AStarNodes AStarNode* getBestNode(); AStarNode* getNodeByPosition(uint16_t x, uint16_t y) { return nodeMap[x][y]; }; - void clear(); static uint16_t getMapWalkCost(AStarNode* node, const Position& neighborPos); static uint16_t getTileWalkCost(const Creature& creature, const Tile* tile);