From d7f782086b168f39d5170024baad14d25a03293b Mon Sep 17 00:00:00 2001 From: Pedro Cruz Date: Sun, 10 Nov 2024 15:53:50 -0300 Subject: [PATCH] improve: spectators and map sector (#3062) Improves the spectators to find monsters and npcs, adds excludeMaster and excludePlayerMaster to filter monsters without masters. Added vectors to cache the monsters and npcs in spectators and map sectors as well. --- src/map/spectators.cpp | 94 ++++++++++++++++++++++++++++--------- src/map/spectators.hpp | 23 +++++---- src/map/utils/mapsector.cpp | 24 ++++++++++ src/map/utils/mapsector.hpp | 2 + 4 files changed, 113 insertions(+), 30 deletions(-) diff --git a/src/map/spectators.cpp b/src/map/spectators.cpp index 74c6aa19af0..6a3ca09c513 100644 --- a/src/map/spectators.cpp +++ b/src/map/spectators.cpp @@ -41,7 +41,7 @@ Spectators Spectators::insertAll(const CreatureVector &list) { return *this; } -bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) { +bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, bool onlyMonsters, bool onlyNpcs, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) { const auto &list = multifloor || !specData.floor ? specData.multiFloor : specData.floor; if (!list) { @@ -58,12 +58,15 @@ bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onl spectators.reserve(creatures.size()); for (const auto &creature : *list) { const auto &specPos = creature->getPosition(); - if (centerPos.x - specPos.x >= minRangeX - && centerPos.y - specPos.y >= minRangeY - && centerPos.x - specPos.x <= maxRangeX - && centerPos.y - specPos.y <= maxRangeY - && (multifloor || specPos.z == centerPos.z) - && (!onlyPlayers || creature->getPlayer())) { + if ((centerPos.x - specPos.x >= minRangeX + && centerPos.y - specPos.y >= minRangeY + && centerPos.x - specPos.x <= maxRangeX + && centerPos.y - specPos.y <= maxRangeY + && (multifloor || specPos.z == centerPos.z) + && ((onlyPlayers && creature->getPlayer()) + || (onlyMonsters && creature->getMonster()) + || (onlyNpcs && creature->getNpc())) + || (!onlyPlayers && !onlyMonsters && !onlyNpcs))) { spectators.emplace_back(creature); } } @@ -75,7 +78,7 @@ bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onl return true; } -CreatureVector Spectators::getSpectators(const Position ¢erPos, bool multifloor, bool onlyPlayers, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) { +CreatureVector Spectators::getSpectators(const Position ¢erPos, bool multifloor, bool onlyPlayers, bool onlyMonsters, bool onlyNpcs, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) { uint8_t minRangeZ = centerPos.z; uint8_t maxRangeZ = centerPos.z; @@ -126,8 +129,12 @@ CreatureVector Spectators::getSpectators(const Position ¢erPos, bool multifl const MapSector* sectorE = sectorS; for (int32_t nx = startx1; nx <= endx2; nx += SECTOR_SIZE) { if (sectorE) { - const auto &node_list = onlyPlayers ? sectorE->player_list : sectorE->creature_list; - for (const auto &creature : node_list) { + const auto &nodeList = onlyPlayers ? sectorE->player_list + : onlyMonsters ? sectorE->monster_list + : onlyNpcs ? sectorE->npc_list + : sectorE->creature_list; + + for (const auto &creature : nodeList) { const auto &cpos = creature->getPosition(); if (static_cast(static_cast(cpos.z) - minRangeZ) <= depth) { const int_fast16_t offsetZ = Position::getOffsetZ(centerPos, cpos); @@ -152,14 +159,14 @@ CreatureVector Spectators::getSpectators(const Position ¢erPos, bool multifl return spectators; } -Spectators Spectators::find(const Position ¢erPos, bool multifloor, bool onlyPlayers, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, bool useCache) { +Spectators Spectators::find(const Position ¢erPos, bool multifloor, bool onlyPlayers, bool onlyMonsters, bool onlyNpcs, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, bool useCache) { minRangeX = (minRangeX == 0 ? -MAP_MAX_VIEW_PORT_X : -minRangeX); maxRangeX = (maxRangeX == 0 ? MAP_MAX_VIEW_PORT_X : maxRangeX); minRangeY = (minRangeY == 0 ? -MAP_MAX_VIEW_PORT_Y : -minRangeY); maxRangeY = (maxRangeY == 0 ? MAP_MAX_VIEW_PORT_Y : maxRangeY); if (!useCache) { - insertAll(getSpectators(centerPos, multifloor, onlyPlayers, minRangeX, maxRangeX, minRangeY, maxRangeY)); + insertAll(getSpectators(centerPos, multifloor, onlyPlayers, onlyMonsters, onlyNpcs, minRangeX, maxRangeX, minRangeY, maxRangeY)); return *this; } @@ -176,29 +183,38 @@ Spectators Spectators::find(const Position ¢erPos, bool multifloor, bool onl } else { const bool checkDistance = minRangeX != cache.minRangeX || maxRangeX != cache.maxRangeX || minRangeY != cache.minRangeY || maxRangeY != cache.maxRangeY; - if (onlyPlayers) { - // check players cache - if (checkCache(cache.players, true, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { + if (onlyPlayers || onlyMonsters || onlyNpcs) { + static const SpectatorsCache::FloorData EMPTY_FLOOR_DATA; + + const auto &creaturesCache = onlyPlayers ? cache.players + : onlyMonsters ? cache.monsters + : onlyNpcs ? cache.npcs + : EMPTY_FLOOR_DATA; + + // check players/monsters/npcs cache + if (checkCache(creaturesCache, onlyPlayers, onlyMonsters, onlyNpcs, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { return *this; } - // if there is no player cache, look for players in the creatures cache. - if (checkCache(cache.creatures, true, centerPos, true, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { + // if there is no players/monsters/npcs cache, look for players/monsters/npcs in the creatures cache. + if (checkCache(cache.creatures, onlyPlayers, onlyMonsters, onlyNpcs, centerPos, true, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { return *this; } - // All Creatures - } else if (checkCache(cache.creatures, false, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { + } else if (checkCache(cache.creatures, false, false, false, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) { return *this; } } } - const auto &spectators = getSpectators(centerPos, multifloor, onlyPlayers, minRangeX, maxRangeX, minRangeY, maxRangeY); + const auto &spectators = getSpectators(centerPos, multifloor, onlyPlayers, onlyMonsters, onlyNpcs, minRangeX, maxRangeX, minRangeY, maxRangeY); // It is necessary to create the cache even if no spectators is found, so that there is no future query. - auto &cache = cacheFound ? it->second : spectatorsCache.emplace(centerPos, SpectatorsCache { .minRangeX = minRangeX, .maxRangeX = maxRangeX, .minRangeY = minRangeY, .maxRangeY = maxRangeY, .creatures = {}, .players = {} }).first->second; - auto &creaturesCache = onlyPlayers ? cache.players : cache.creatures; + auto &cache = cacheFound ? it->second : spectatorsCache.emplace(centerPos, SpectatorsCache { .minRangeX = minRangeX, .maxRangeX = maxRangeX, .minRangeY = minRangeY, .maxRangeY = maxRangeY, .creatures = {}, .monsters = {}, .npcs = {}, .players = {} }).first->second; + auto &creaturesCache = onlyPlayers ? cache.players + : onlyMonsters ? cache.monsters + : onlyNpcs ? cache.npcs + : cache.creatures; auto &creatureList = (multifloor ? creaturesCache.multiFloor : creaturesCache.floor); if (creatureList) { creatureList->clear(); @@ -215,6 +231,40 @@ Spectators Spectators::find(const Position ¢erPos, bool multifloor, bool onl return *this; } +Spectators Spectators::excludeMaster() const { + auto specs = Spectators(); + if (creatures.empty()) { + return specs; + } + + specs.creatures.reserve(creatures.size()); + + for (const auto &c : creatures) { + if (c->getMonster() != nullptr && !c->getMaster()) { + specs.insert(c); + } + } + + return specs; +} + +Spectators Spectators::excludePlayerMaster() const { + auto specs = Spectators(); + if (creatures.empty()) { + return specs; + } + + specs.creatures.reserve(creatures.size()); + + for (const auto &c : creatures) { + if ((c->getMonster() != nullptr && !c->getMaster() || !c->getMaster()->getPlayer())) { + specs.insert(c); + } + } + + return specs; +} + Spectators Spectators::filter(bool onlyPlayers, bool onlyMonsters, bool onlyNpcs) const { auto specs = Spectators(); specs.creatures.reserve(creatures.size()); diff --git a/src/map/spectators.hpp b/src/map/spectators.hpp index 68ad751b056..f858603a791 100644 --- a/src/map/spectators.hpp +++ b/src/map/spectators.hpp @@ -30,6 +30,8 @@ struct SpectatorsCache { int32_t maxRangeY { 0 }; FloorData creatures; + FloorData monsters; + FloorData npcs; FloorData players; }; @@ -38,21 +40,26 @@ class Spectators { static void clearCache(); template - requires std::is_same_v || std::is_same_v + requires std::is_base_of_v Spectators find(const Position ¢erPos, bool multifloor = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0, bool useCache = true) { constexpr bool onlyPlayers = std::is_same_v; - return find(centerPos, multifloor, onlyPlayers, minRangeX, maxRangeX, minRangeY, maxRangeY, useCache); + constexpr bool onlyMonsters = std::is_same_v; + constexpr bool onlyNpcs = std::is_same_v; + return find(centerPos, multifloor, onlyPlayers, onlyMonsters, onlyNpcs, minRangeX, maxRangeX, minRangeY, maxRangeY, useCache); } template requires std::is_base_of_v Spectators filter() const { - bool onlyPlayers = std::is_same_v; - bool onlyMonsters = std::is_same_v; - bool onlyNpcs = std::is_same_v; + constexpr bool onlyPlayers = std::is_same_v; + constexpr bool onlyMonsters = std::is_same_v; + constexpr bool onlyNpcs = std::is_same_v; return filter(onlyPlayers, onlyMonsters, onlyNpcs); } + Spectators excludeMaster() const; + Spectators excludePlayerMaster() const; + Spectators insert(const std::shared_ptr &creature); Spectators insertAll(const CreatureVector &list); Spectators join(const Spectators &anotherSpectators) { @@ -90,12 +97,12 @@ class Spectators { private: static phmap::flat_hash_map spectatorsCache; - Spectators find(const Position ¢erPos, bool multifloor = false, bool onlyPlayers = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0, bool useCache = true); - CreatureVector getSpectators(const Position ¢erPos, bool multifloor = false, bool onlyPlayers = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0); + Spectators find(const Position ¢erPos, bool multifloor = false, bool onlyPlayers = false, bool onlyMonsters = false, bool onlyNpcs = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0, bool useCache = true); + CreatureVector getSpectators(const Position ¢erPos, bool multifloor = false, bool onlyPlayers = false, bool onlyMonsters = false, bool onlyNpcs = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0); Spectators filter(bool onlyPlayers, bool onlyMonsters, bool onlyNpcs) const; - bool checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY); + bool checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, bool onlyMonsters, bool onlyNpcs, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY); CreatureVector creatures; }; diff --git a/src/map/utils/mapsector.cpp b/src/map/utils/mapsector.cpp index f07c2a3e1b1..c6546ebd02c 100644 --- a/src/map/utils/mapsector.cpp +++ b/src/map/utils/mapsector.cpp @@ -17,6 +17,10 @@ void MapSector::addCreature(const std::shared_ptr &c) { creature_list.emplace_back(c); if (c->getPlayer()) { player_list.emplace_back(c); + } else if (c->getMonster()) { + monster_list.emplace_back(c); + } else if (c->getNpc()) { + npc_list.emplace_back(c); } } @@ -41,5 +45,25 @@ void MapSector::removeCreature(const std::shared_ptr &c) { assert(iter != player_list.end()); *iter = player_list.back(); player_list.pop_back(); + } else if (c->getMonster()) { + iter = std::ranges::find(monster_list, c); + if (iter == monster_list.end()) { + g_logger().error("[{}]: Monster not found in player_list!", __FUNCTION__); + return; + } + + assert(iter != monster_list.end()); + *iter = monster_list.back(); + monster_list.pop_back(); + } else if (c->getNpc()) { + iter = std::ranges::find(npc_list, c); + if (iter == npc_list.end()) { + g_logger().error("[{}]: NPC not found in player_list!", __FUNCTION__); + return; + } + + assert(iter != npc_list.end()); + *iter = npc_list.back(); + npc_list.pop_back(); } } diff --git a/src/map/utils/mapsector.hpp b/src/map/utils/mapsector.hpp index 58130007e5e..0b8be45e973 100644 --- a/src/map/utils/mapsector.hpp +++ b/src/map/utils/mapsector.hpp @@ -98,6 +98,8 @@ class MapSector { std::vector> creature_list; std::vector> player_list; + std::vector> monster_list; + std::vector> npc_list; mutable std::mutex floors_mutex;