Skip to content

Commit

Permalink
improve: spectators and map sector (#3062)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
phacUFPE authored Nov 10, 2024
1 parent 685f4cd commit d7f7820
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 30 deletions.
94 changes: 72 additions & 22 deletions src/map/spectators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Spectators Spectators::insertAll(const CreatureVector &list) {
return *this;
}

bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, const Position &centerPos, 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 &centerPos, 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) {
Expand All @@ -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())

Check warning on line 66 in src/map/spectators.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]

Check warning on line 66 in src/map/spectators.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
|| (onlyMonsters && creature->getMonster())
|| (onlyNpcs && creature->getNpc()))
|| (!onlyPlayers && !onlyMonsters && !onlyNpcs))) {
spectators.emplace_back(creature);
}
}
Expand All @@ -75,7 +78,7 @@ bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onl
return true;
}

CreatureVector Spectators::getSpectators(const Position &centerPos, bool multifloor, bool onlyPlayers, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) {
CreatureVector Spectators::getSpectators(const Position &centerPos, 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;

Expand Down Expand Up @@ -126,8 +129,12 @@ CreatureVector Spectators::getSpectators(const Position &centerPos, 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<uint32_t>(static_cast<int32_t>(cpos.z) - minRangeZ) <= depth) {
const int_fast16_t offsetZ = Position::getOffsetZ(centerPos, cpos);
Expand All @@ -152,14 +159,14 @@ CreatureVector Spectators::getSpectators(const Position &centerPos, bool multifl
return spectators;
}

Spectators Spectators::find(const Position &centerPos, bool multifloor, bool onlyPlayers, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, bool useCache) {
Spectators Spectators::find(const Position &centerPos, 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;
}

Expand All @@ -176,29 +183,38 @@ Spectators Spectators::find(const Position &centerPos, 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();
Expand All @@ -215,6 +231,40 @@ Spectators Spectators::find(const Position &centerPos, 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())) {

Check warning on line 260 in src/map/spectators.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]

Check warning on line 260 in src/map/spectators.cpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
specs.insert(c);
}
}

return specs;
}

Spectators Spectators::filter(bool onlyPlayers, bool onlyMonsters, bool onlyNpcs) const {
auto specs = Spectators();
specs.creatures.reserve(creatures.size());
Expand Down
23 changes: 15 additions & 8 deletions src/map/spectators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct SpectatorsCache {
int32_t maxRangeY { 0 };

FloorData creatures;
FloorData monsters;
FloorData npcs;
FloorData players;
};

Expand All @@ -38,21 +40,26 @@ class Spectators {
static void clearCache();

template <typename T>
requires std::is_same_v<Creature, T> || std::is_same_v<Player, T>
requires std::is_base_of_v<Creature, T>
Spectators find(const Position &centerPos, 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<T, Player>;
return find(centerPos, multifloor, onlyPlayers, minRangeX, maxRangeX, minRangeY, maxRangeY, useCache);
constexpr bool onlyMonsters = std::is_same_v<T, Monster>;
constexpr bool onlyNpcs = std::is_same_v<T, Npc>;
return find(centerPos, multifloor, onlyPlayers, onlyMonsters, onlyNpcs, minRangeX, maxRangeX, minRangeY, maxRangeY, useCache);
}

template <typename T>
requires std::is_base_of_v<Creature, T>
Spectators filter() const {
bool onlyPlayers = std::is_same_v<T, Player>;
bool onlyMonsters = std::is_same_v<T, Monster>;
bool onlyNpcs = std::is_same_v<T, Npc>;
constexpr bool onlyPlayers = std::is_same_v<T, Player>;
constexpr bool onlyMonsters = std::is_same_v<T, Monster>;
constexpr bool onlyNpcs = std::is_same_v<T, Npc>;
return filter(onlyPlayers, onlyMonsters, onlyNpcs);
}

Spectators excludeMaster() const;
Spectators excludePlayerMaster() const;

Spectators insert(const std::shared_ptr<Creature> &creature);
Spectators insertAll(const CreatureVector &list);
Spectators join(const Spectators &anotherSpectators) {
Expand Down Expand Up @@ -90,12 +97,12 @@ class Spectators {
private:
static phmap::flat_hash_map<Position, SpectatorsCache> spectatorsCache;

Spectators find(const Position &centerPos, 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 &centerPos, 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 &centerPos, 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 &centerPos, 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 &centerPos, 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 &centerPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY);

CreatureVector creatures;
};
24 changes: 24 additions & 0 deletions src/map/utils/mapsector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ void MapSector::addCreature(const std::shared_ptr<Creature> &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);
}
}

Expand All @@ -41,5 +45,25 @@ void MapSector::removeCreature(const std::shared_ptr<Creature> &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();
}
}
2 changes: 2 additions & 0 deletions src/map/utils/mapsector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class MapSector {

std::vector<std::shared_ptr<Creature>> creature_list;
std::vector<std::shared_ptr<Creature>> player_list;
std::vector<std::shared_ptr<Creature>> monster_list;
std::vector<std::shared_ptr<Creature>> npc_list;

mutable std::mutex floors_mutex;

Expand Down

0 comments on commit d7f7820

Please sign in to comment.