diff --git a/.claude/analysis/EXTREME_LAG_ROOT_CAUSE_ANALYSIS.md b/.claude/analysis/EXTREME_LAG_ROOT_CAUSE_ANALYSIS.md index 9d88cca17..628775d83 100644 --- a/.claude/analysis/EXTREME_LAG_ROOT_CAUSE_ANALYSIS.md +++ b/.claude/analysis/EXTREME_LAG_ROOT_CAUSE_ANALYSIS.md @@ -353,13 +353,36 @@ When 100 bots enter a map simultaneously, ALL 100 queue on exclusive lock. | GameSystemsManager Throttling | HIGH | ✅ FIXED | ~30x fewer manager updates | | SpatialGridManager Thundering Herd | MEDIUM | ✅ FIXED | Instant returns for existing grids | | Main Thread ThreadPool Blocking | HIGH | ⚠️ MITIGATED | Fixed by making workers faster | -| CombatEventRouter | MEDIUM | ⏳ ACCEPTABLE | Already uses good patterns | +| CombatEventRouter | MEDIUM | ✅ FIXED | Lock-free stats with atomics | +| VMAP Repeated Load Attempts | HIGH | ✅ FIXED | Cache failed loads, no retries | +| MMAP Repeated Load Attempts | HIGH | ✅ FIXED | Cache failed loads, no retries | | Unordered Mutexes | LOW | ⏳ DEFERRED | For future cleanup | **Total Build Status:** ✅ worldserver.exe compiled successfully --- +## VMAP/MMAP LOAD CACHING FIX + +### Problem +When maps reference VMAP/MMAP tiles that don't exist in client data (e.g., "8.0 Boost Experience", +TWW dungeons), the server repeatedly attempts to load them on every grid access, causing: +- Repeated file I/O operations +- Log spam with warnings +- Significant server slowdown + +### Solution +Added `_vmapLoadFailed` and `_mmapLoadFailed` bitset caches to `TerrainInfo` class: +- On first load failure, mark the grid as failed +- Skip subsequent load attempts for the same grid +- Changed log level from WARN to DEBUG for expected failures + +**File:** `src/server/game/Maps/TerrainMgr.h` and `TerrainMgr.cpp` + +**Expected Impact:** Near-instant returns for grids with missing map data + +--- + ## THREADING CONFIGURATION ### TrinityCore MapUpdate.Threads diff --git a/src/server/game/Maps/TerrainMgr.cpp b/src/server/game/Maps/TerrainMgr.cpp index 9f6e428e1..123fd7427 100644 --- a/src/server/game/Maps/TerrainMgr.cpp +++ b/src/server/game/Maps/TerrainMgr.cpp @@ -252,6 +252,10 @@ void TerrainInfo::LoadMMapImpl(uint32 instanceId, int32 gx, int32 gy) if (!DisableMgr::IsPathfindingEnabled(GetId())) return; + // PLAYERBOT FIX: Skip loading if we already know this tile failed (prevents repeated file access attempts) + if (_mmapLoadFailed[GetBitsetIndex(gx, gy)]) + return; + switch (MMAP::LoadResult mmapLoadResult = MMAP::MMapManager::instance()->loadMap(sWorld->GetDataPath(), GetId(), instanceId, gx, gy)) { case MMAP::LoadResult::Success: @@ -260,9 +264,19 @@ void TerrainInfo::LoadMMapImpl(uint32 instanceId, int32 gx, int32 gy) case MMAP::LoadResult::AlreadyLoaded: break; case MMAP::LoadResult::FileNotFound: + // PLAYERBOT FIX: Cache the failure to prevent repeated load attempts + _mmapLoadFailed[GetBitsetIndex(gx, gy)] = true; if (_parentTerrain) break; // don't log tile not found errors for child maps - [[fallthrough]]; + TC_LOG_DEBUG("mmaps.tiles", "MMAP not available name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{}) - will not retry", GetMapName(), GetId(), gx, gy, gx, gy); + break; + case MMAP::LoadResult::VersionMismatch: + case MMAP::LoadResult::ReadFromFileFailed: + case MMAP::LoadResult::LibraryError: + // PLAYERBOT FIX: Cache these failures too - they won't succeed on retry + _mmapLoadFailed[GetBitsetIndex(gx, gy)] = true; + TC_LOG_WARN("mmaps.tiles", "MMAP failed name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{}) result: {} - will not retry", GetMapName(), GetId(), gx, gy, gx, gy, AsUnderlyingType(mmapLoadResult)); + break; default: TC_LOG_WARN("mmaps.tiles", "Could not load MMAP name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{}) result: {}", GetMapName(), GetId(), gx, gy, gx, gy, AsUnderlyingType(mmapLoadResult)); break; diff --git a/src/server/game/Maps/TerrainMgr.h b/src/server/game/Maps/TerrainMgr.h index 08535ebe9..df47de23c 100644 --- a/src/server/game/Maps/TerrainMgr.h +++ b/src/server/game/Maps/TerrainMgr.h @@ -116,6 +116,7 @@ private: std::array _loadedGrids; std::bitset _gridFileExists; // cache what grids are available for this map (not including parent/child maps) std::bitset _vmapLoadFailed; // PLAYERBOT FIX: cache failed VMAP loads to prevent repeated attempts + std::bitset _mmapLoadFailed; // PLAYERBOT FIX: cache failed MMAP loads to prevent repeated attempts static constexpr Milliseconds CleanupInterval = 1min;