From a904327656ee37f2c5cece2e7a47a24e2cdcf3af Mon Sep 17 00:00:00 2001 From: Shauren Date: Sun, 1 Feb 2026 20:19:59 +0100 Subject: [PATCH] Core/VMaps: Optimize vmap tile unload --- .../Collision/Management/VMapManager.cpp | 2 +- src/common/Collision/Maps/MapTree.cpp | 83 ++++++------------- src/common/Collision/Maps/MapTree.h | 4 +- .../Collision/Models/GameObjectModel.cpp | 2 +- 4 files changed, 29 insertions(+), 62 deletions(-) diff --git a/src/common/Collision/Management/VMapManager.cpp b/src/common/Collision/Management/VMapManager.cpp index 98137de183..d8a861787f 100644 --- a/src/common/Collision/Management/VMapManager.cpp +++ b/src/common/Collision/Management/VMapManager.cpp @@ -152,7 +152,7 @@ namespace VMAP auto instanceTree = iInstanceMapTrees.find(mapId); if (instanceTree != iInstanceMapTrees.end() && instanceTree->second) { - instanceTree->second->UnloadMapTile(x, y, this); + instanceTree->second->UnloadMapTile(x, y); if (instanceTree->second->numLoadedTiles() == 0) instanceTree->second = nullptr; } diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index ca61cf1289..7f7fe5c05c 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -294,6 +294,7 @@ namespace VMAP } LoadResult result = LoadResult::FileNotFound; + std::vector& tileReferenceVals = iLoadedTiles[packTileID(tileX, tileY)]; TileFileOpenResult fileResult = OpenMapTileFile(iBasePath, iMapID, tileX, tileY, vm); if (fileResult) { @@ -312,6 +313,7 @@ namespace VMAP result = LoadResult::ReadFromFileFailed; if (numSpawns != numSpawnIndices) result = LoadResult::ReadFromFileFailed; + tileReferenceVals.reserve(numSpawns); for (uint32 i = 0; i < numSpawns && result == LoadResult::Success; ++i) { // read model spawns @@ -321,11 +323,6 @@ namespace VMAP if (spawn.flags & MOD_PATH_ONLY && !vm->LoadPathOnlyModels) continue; - // acquire model instance - std::shared_ptr model = vm->acquireModelInstance(iBasePath, spawn.name); - if (!model) - TC_LOG_ERROR("misc", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [{}, {}]", tileX, tileY); - // update tree uint32 referencedVal = 0; if (fread(&referencedVal, sizeof(uint32), 1, fileResult.SpawnIndicesFile.get()) != 1) @@ -342,6 +339,14 @@ namespace VMAP continue; } + // acquire model instance + std::shared_ptr model = vm->acquireModelInstance(iBasePath, spawn.name); + if (!model) + { + TC_LOG_ERROR("misc", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [{}, {}]", tileX, tileY); + continue; + } + if (!iTreeValues[referencedVal].getWorldModel()) iTreeValues[referencedVal] = ModelInstance(spawn, std::move(model)); #ifdef VMAP_DEBUG @@ -354,6 +359,7 @@ namespace VMAP } #endif iTreeValues[referencedVal].AddTileReference(); + tileReferenceVals.push_back(referencedVal); } else { @@ -361,76 +367,37 @@ namespace VMAP result = LoadResult::ReadFromFileFailed; } } - iLoadedTiles[packTileID(tileX, tileY)] = true; } - else - iLoadedTiles[packTileID(tileX, tileY)] = false; + TC_METRIC_EVENT("map_events", "LoadMapTile", Trinity::StringFormat("Map: {} TileX: {} TileY: {}", iMapID, tileX, tileY)); return result; } //========================================================= - void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager* vm) + void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY) { uint32 tileID = packTileID(tileX, tileY); - loadedTileMap::iterator tile = iLoadedTiles.find(tileID); - if (tile == iLoadedTiles.end()) + auto tile = iLoadedTiles.extract(tileID); + if (!tile) { TC_LOG_ERROR("misc", "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:{} X:{} Y:{}", iMapID, tileX, tileY); return; } - if (tile->second) // file associated with tile + + for (uint32 referencedVal : tile.mapped()) { - TileFileOpenResult fileResult = OpenMapTileFile(iBasePath, iMapID, tileX, tileY, vm); - if (fileResult) + if (!iTreeValues[referencedVal].getWorldModel()) { - bool result = true; - char chunk[8]; - if (!readChunk(fileResult.TileFile.get(), chunk, VMAP_MAGIC, 8)) - result = false; - uint32 numSpawns; - if (fread(&numSpawns, sizeof(uint32), 1, fileResult.TileFile.get()) != 1) - result = false; - uint32 numSpawnIndices = 0; - if (result && fread(&numSpawnIndices, sizeof(uint32), 1, fileResult.SpawnIndicesFile.get()) != 1) - result = false; - if (numSpawns != numSpawnIndices) - result = false; - for (uint32 i = 0; i < numSpawns && result; ++i) - { - // read model spawns - ModelSpawn spawn; - if (!ModelSpawn::readFromFile(fileResult.TileFile.get(), spawn)) - break; - - if (spawn.flags & MOD_PATH_ONLY && !vm->LoadPathOnlyModels) - continue; - - // update tree - uint32 referencedNode = 0; - if (fread(&referencedNode, sizeof(uint32), 1, fileResult.SpawnIndicesFile.get()) != 1) - { - TC_LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : invalid tree element (spawn {}) referenced in tile {} by map {}", spawn.ID, fileResult.Name, iMapID); - result = false; - continue; - } - - if (referencedNode >= iTreeValues.size()) - { - TC_LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : invalid tree element ({}/{}) referenced in tile {}", referencedNode, iTreeValues.size(), fileResult.Name); - result = false; - continue; - } - - if (!iTreeValues[referencedNode].getWorldModel()) - TC_LOG_ERROR("misc", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '{}' (ID:{})", spawn.name, spawn.ID); - else if (!iTreeValues[referencedNode].RemoveTileReference()) - iTreeValues[referencedNode].setUnloaded(); - } + TC_LOG_ERROR("misc", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model ID: {} - Map:{} X:{} Y:{}", + iTreeValues[referencedVal].ID, iMapID, tileX, tileY); + continue; } + + if (!iTreeValues[referencedVal].RemoveTileReference()) + iTreeValues[referencedVal].setUnloaded(); } - iLoadedTiles.erase(tile); + TC_METRIC_EVENT("map_events", "UnloadMapTile", Trinity::StringFormat("Map: {} TileX: {} TileY: {}", iMapID, tileX, tileY)); } diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 049b1c416b..488f870d27 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -48,7 +48,7 @@ namespace VMAP class TC_COMMON_API StaticMapTree { - typedef std::unordered_map loadedTileMap; + typedef std::unordered_map> loadedTileMap; private: uint32 iMapID; BIH iTree; @@ -79,7 +79,7 @@ namespace VMAP LoadResult InitMap(std::string const& fname); void UnloadMap(); LoadResult LoadMapTile(uint32 tileX, uint32 tileY, VMapManager* vm); - void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager* vm); + void UnloadMapTile(uint32 tileX, uint32 tileY); uint32 numLoadedTiles() const { return uint32(iLoadedTiles.size()); } std::span getModelInstances() const; diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index c8866de790..02543e50bd 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -144,7 +144,7 @@ std::unique_ptr GameObjectModel::Create(std::unique_ptr mdl(new GameObjectModel()); if (!mdl->initialize(std::move(modelOwner), dataPath)) - return nullptr; + mdl = nullptr; return mdl; }