Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve: spectators and map sector #3062

Merged
merged 10 commits into from
Nov 10, 2024
110 changes: 91 additions & 19 deletions src/map/spectators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
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 @@
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 @@
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,16 @@
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 CreatureVector* nodeList = &sectorE->creature_list;
phacUFPE marked this conversation as resolved.
Show resolved Hide resolved
if (onlyPlayers) {
nodeList = &sectorE->player_list;
} else if (onlyMonsters) {
nodeList = &sectorE->monster_list;
} else if (onlyNpcs) {
nodeList = &sectorE->npc_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 +163,14 @@
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 @@ -178,28 +189,55 @@

if (onlyPlayers) {
// check players cache
if (checkCache(cache.players, true, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
if (checkCache(cache.players, true, false, false, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
phacUFPE marked this conversation as resolved.
Show resolved Hide resolved
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 (checkCache(cache.creatures, true, false, false, centerPos, true, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
return *this;
}
} else if (onlyMonsters) {
// check monsters cache
if (checkCache(cache.monsters, false, true, false, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
return *this;
}

// if there is no monsters cache, look for monsters in the creatures cache.
if (checkCache(cache.creatures, false, true, false, centerPos, true, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
return *this;
}
} else if (onlyNpcs) {
// check npcs cache
if (checkCache(cache.npcs, false, false, true, centerPos, checkDistance, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY)) {
return *this;
}

// if there is no npcs cache, look for npcs in the creatures cache.
if (checkCache(cache.creatures, false, false, true, 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 &creatureList = (multifloor ? creaturesCache.multiFloor : creaturesCache.floor);
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 = &cache.creatures;
phacUFPE marked this conversation as resolved.
Show resolved Hide resolved
if (onlyPlayers) {
creaturesCache = &cache.players;
} else if (onlyMonsters) {
creaturesCache = &cache.monsters;
} else if (onlyNpcs) {
creaturesCache = &cache.npcs;
}
auto &creatureList = (multifloor ? (*creaturesCache).multiFloor : (*creaturesCache).floor);
if (creatureList) {
creatureList->clear();
} else {
Expand All @@ -215,6 +253,40 @@
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);
}
}
dudantas marked this conversation as resolved.
Show resolved Hide resolved

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 282 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 282 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);
}
}
dudantas marked this conversation as resolved.
Show resolved Hide resolved

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
Loading