diff --git a/src/map.cpp b/src/map.cpp index de24d641..1f3b56f1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -407,9 +407,27 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo minRangeY = (minRangeY == 0 ? -maxViewportY : -minRangeY); maxRangeY = (maxRangeY == 0 ? maxViewportY : maxRangeY); - std::array cache_values{ - -maxViewportX , maxViewportX , -maxViewportY , maxViewportY - }; + chunkKey.minRangeX = minRangeX; + chunkKey.maxRangeX = maxRangeX; + chunkKey.minRangeY = minRangeY; + chunkKey.maxRangeY = maxRangeY; + chunkKey.x = centerPos.x; + chunkKey.y = centerPos.y; + chunkKey.z = centerPos.z; + chunkKey.multifloor = multifloor; + chunkKey.onlyPlayers = onlyPlayers; + + auto it = chunksSpectatorCache.find(chunkKey); + if (it != chunksSpectatorCache.end()) { + if (!spectators.empty()) { + spectators.addSpectators(it->second); + } else { + spectators = it->second; + } + foundCache = true; + } else { + cacheResult = true; + } if (minRangeX == -maxViewportX && maxRangeX == maxViewportX && minRangeY == -maxViewportY && maxRangeY == maxViewportY && multifloor) { if (onlyPlayers) { @@ -467,11 +485,7 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo getSpectatorsInternal(spectators, centerPos, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ, onlyPlayers); if (cacheResult) { - if (onlyPlayers) { - playersSpectatorCache[centerPos] = spectators; - } else { - spectatorCache[centerPos] = spectators; - } + chunksSpectatorCache.emplace(chunkKey, spectators); } } } diff --git a/src/map.h b/src/map.h index 5a7e824c..48baad96 100644 --- a/src/map.h +++ b/src/map.h @@ -34,6 +34,44 @@ static constexpr int32_t MAX_NODES = 512; static constexpr int32_t MAP_NORMALWALKCOST = 10; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; +struct ChunkKey +{ + int32_t minRangeX = 0; + int32_t maxRangeX = 0; + int32_t minRangeY = 0; + int32_t maxRangeY = 0; + uint16_t x = 0; + uint16_t y = 0; + uint8_t z = 0; + bool multifloor = false; + bool onlyPlayers = false; +}; + +static ChunkKey chunkKey; + +struct ChunkKeyHash +{ + std::size_t operator()(const ChunkKey& key) const + { + return std::hash()(key.minRangeX) ^ std::hash()(key.maxRangeX) ^ + std::hash()(key.minRangeY) ^ std::hash()(key.maxRangeY) ^ + std::hash()(key.x) ^ std::hash()(key.y) ^ std::hash()(key.z) ^ + std::hash()(key.multifloor) ^ std::hash()(key.onlyPlayers); + } +}; + +struct ChunkKeyEqual +{ + bool operator()(const ChunkKey& lhs, const ChunkKey& rhs) const + { + return std::tie(lhs.minRangeX, lhs.maxRangeX, lhs.minRangeY, lhs.maxRangeY, lhs.x, lhs.y, lhs.z, lhs.multifloor, + lhs.onlyPlayers) == std::tie(rhs.minRangeX, rhs.maxRangeX, rhs.minRangeY, rhs.maxRangeY, rhs.x, + rhs.y, rhs.z, rhs.multifloor, rhs.onlyPlayers); + } +}; + +using ChunkCache = std::unordered_map; + class AStarNodes { public: @@ -169,6 +207,10 @@ class Map * \returns true if the map was loaded successfully */ bool loadMap(const std::string& identifier, bool loadHouses); + void clearChunkSpectatorCache() { + playersSpectatorCache.clear(); + chunksSpectatorCache.clear(); + } /** * Save a map. @@ -268,7 +310,7 @@ class Map private: SpectatorCache spectatorCache; SpectatorCache playersSpectatorCache; - + ChunkCache chunksSpectatorCache; QTreeNode root; std::filesystem::path spawnfile; diff --git a/src/tile.cpp b/src/tile.cpp index e2f556c8..0cc640d5 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -902,10 +902,7 @@ void Tile::addThing(int32_t, Thing* thing) { Creature* creature = thing->getCreature(); if (creature) { - g_game.map.clearSpectatorCache(); - if (creature->getPlayer()) { - g_game.map.clearPlayersSpectatorCache(); - } + g_game.map.clearChunkSpectatorCache(); creature->setParent(this); CreatureVector* creatures = makeCreatures(); @@ -1111,10 +1108,7 @@ void Tile::removeThing(Thing* thing, uint32_t count) if (creatures) { auto it = std::find(creatures->begin(), creatures->end(), thing); if (it != creatures->end()) { - g_game.map.clearSpectatorCache(); - if (creature->getPlayer()) { - g_game.map.clearPlayersSpectatorCache(); - } + g_game.map.clearChunkSpectatorCache(); creatures->erase(it); } @@ -1491,10 +1485,7 @@ void Tile::internalAddThing(uint32_t, Thing* thing) Creature* creature = thing->getCreature(); if (creature) { - g_game.map.clearSpectatorCache(); - if (creature->getPlayer()) { - g_game.map.clearPlayersSpectatorCache(); - } + g_game.map.clearChunkSpectatorCache(); CreatureVector* creatures = makeCreatures(); creatures->insert(creatures->begin(), creature);