From b00e97e222279fe558ef42598bedb6e89e5234ba Mon Sep 17 00:00:00 2001 From: codinablack Date: Sat, 7 Dec 2024 00:31:07 -0600 Subject: [PATCH] Implemented Hash Cache for spectators. Co-Authored-By: Sarah Wesker --- src/map.cpp | 30 ++++++++++++++++++++++-------- src/map.h | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/tile.cpp | 15 +++------------ 3 files changed, 69 insertions(+), 21 deletions(-) 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..243a5b4f 100644 --- a/src/map.h +++ b/src/map.h @@ -34,6 +34,45 @@ static constexpr int32_t MAX_NODES = 512; static constexpr int32_t MAP_NORMALWALKCOST = 10; static constexpr int32_t MAP_DIAGONALWALKCOST = 25; +struct alignas(16) ChunkKey { + int32_t minRangeX, maxRangeX, minRangeY, maxRangeY; + uint16_t x, y; + uint8_t z; + bool multifloor, onlyPlayers; + + bool operator==(const ChunkKey& other) const noexcept { + return std::memcmp(this, &other, sizeof(ChunkKey)) == 0; + } +}; +static ChunkKey chunkKey; +struct ChunkKeyHash { + std::size_t operator()(const ChunkKey& key) const noexcept { + std::size_t hash = 0; + hash_combine(hash, key.minRangeX, key.maxRangeX, key.minRangeY, key.maxRangeY, + key.x, key.y, key.z, key.multifloor, key.onlyPlayers); + return hash; + } + +private: + template + static void hash_combine(std::size_t& seed, Args&&... args) { + (hash_combine_impl(seed, std::forward(args)), ...); + } + + template + static void hash_combine_impl(std::size_t& seed, const T& v) { + seed ^= std::hash{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } +}; + +struct ChunkKeyEqual { + bool operator()(const ChunkKey& lhs, const ChunkKey& rhs) const noexcept { + return std::memcmp(&lhs, &rhs, sizeof(ChunkKey)) == 0; + } +}; + +using ChunkCache = std::unordered_map; + class AStarNodes { public: @@ -169,6 +208,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 +311,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);