Core/MMaps: Allow loading mmap meshes per map instance

This commit is contained in:
Shauren
2025-11-06 18:34:58 +01:00
parent f439120b1f
commit a9c752af97
8 changed files with 161 additions and 104 deletions

View File

@@ -20,6 +20,7 @@
#include "Hash.h"
#include "Log.h"
#include "MMapDefines.h"
#include "MapUtils.h"
#include "Memory.h"
#include <algorithm>
@@ -28,22 +29,44 @@ namespace MMAP
constexpr char MAP_FILE_NAME_FORMAT[] = "{}mmaps/{:04}.mmap";
constexpr char TILE_FILE_NAME_FORMAT[] = "{}mmaps/{:04}_{:02}_{:02}.mmtile";
using NavMeshPtr = std::unique_ptr<dtNavMesh, decltype(Trinity::unique_ptr_deleter<dtNavMesh*, &::dtFreeNavMesh>())>;
using NavMeshQueryPtr = std::unique_ptr<dtNavMeshQuery, decltype(Trinity::unique_ptr_deleter<dtNavMeshQuery*, &::dtFreeNavMeshQuery>())>;
static thread_local bool thread_safe_environment = false;
typedef std::unordered_map<std::pair<uint32, uint32>, NavMeshQueryPtr> NavMeshQuerySet;
typedef std::unordered_map<uint32, dtTileRef> MMapTileSet;
using NavMeshQuerySet = std::unordered_map<std::pair<uint32, uint32>, dtNavMeshQuery>;
using MMapTileSet = std::unordered_map<uint32, dtTileRef>;
struct MMapMapData
{
dtNavMesh navMesh;
MMapTileSet loadedTileRefs; // maps [map grid coords] to [dtTile]
};
using MeshDataMap = std::unordered_map<uint32, MMapMapData>;
// dummy struct to hold map's mmap data
struct MMapData
{
explicit MMapData(NavMeshPtr&& mesh) : navMesh(std::move(mesh)) { }
MeshDataMap meshData;
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe
NavMeshQuerySet navMeshQueries; // instanceId to query
NavMeshPtr navMesh;
MMapTileSet loadedTileRefs; // maps [map grid coords] to [dtTile]
static uint32 GetInstanceIdForMeshLookup([[maybe_unused]] uint32 mapId, [[maybe_unused]] uint32 instanceId)
{
// for maps that won't have dynamic mesh, return 0 to reuse the same mesh across all instances
return 0;
}
std::pair<MeshDataMap::iterator, bool> GetMeshData(uint32 mapId, uint32 instanceId)
{
// for maps that won't have dynamic mesh, return 0 to reuse the same mesh across all instances
return meshData.try_emplace(GetInstanceIdForMeshLookup(mapId, instanceId));
}
MeshDataMap::iterator FindMeshData(uint32 mapId, uint32 instanceId)
{
// for maps that won't have dynamic mesh, return 0 to reuse the same mesh across all instances
return meshData.find(GetInstanceIdForMeshLookup(mapId, instanceId));
}
};
// ######################## MMapManager ########################
@@ -61,12 +84,13 @@ namespace MMAP
// the caller must pass the list of all mapIds that will be used in the MMapManager lifetime
for (auto const& [mapId, childMapIds] : mapData)
{
loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr));
loadedMMaps[mapId].reset(new MMapData());
for (uint32 childMapId : childMapIds)
parentMapData[childMapId] = mapId;
}
thread_safe_environment = false;
// mark the loading main thread as safe
thread_safe_environment = true;
}
MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const
@@ -79,40 +103,47 @@ namespace MMAP
return itr;
}
LoadResult MMapManager::loadMapData(std::string_view basePath, uint32 mapId)
LoadResult MMapManager::loadMapData(std::string_view basePath, uint32 mapId, uint32 instanceId)
{
// we already have this map loaded?
MMapDataSet::iterator itr = loadedMMaps.find(mapId);
if (itr != loadedMMaps.end())
MMapDataSet::iterator itr;
if (thread_safe_environment)
{
if (itr->second)
return LoadResult::AlreadyLoaded;
bool needsLoading;
std::tie(itr, needsLoading) = loadedMMaps.try_emplace(mapId);
if (needsLoading)
itr->second.reset(new MMapData());
}
else
{
if (thread_safe_environment)
itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
else
itr = loadedMMaps.find(mapId);
if (itr == loadedMMaps.end())
ABORT_MSG("Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
}
auto [meshItr, needsLoading] = itr->second->GetMeshData(mapId, instanceId);
if (!needsLoading)
return LoadResult::AlreadyLoaded;
auto loadGuard = Trinity::make_unique_ptr_with_deleter(&meshItr, [&](MeshDataMap::iterator* m)
{
itr->second->meshData.erase(*m);
});
// load and init dtNavMesh - read parameters from file
dtNavMeshParams params;
if (LoadResult paramsResult = parseNavMeshParamsFile(basePath, mapId, &params); paramsResult != LoadResult::Success)
return paramsResult;
NavMeshPtr mesh(dtAllocNavMesh());
ASSERT(mesh);
if (dtStatusFailed(mesh->init(&params)))
if (dtStatusFailed(meshItr->second.navMesh.init(&params)))
{
TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {:04}", mapId);
return LoadResult::LibraryError;
}
TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded {:04}.mmap", mapId);
(void)loadGuard.release();
// store inside our map list
itr->second.reset(new MMapData(std::move(mesh)));
return LoadResult::Success;
}
@@ -168,10 +199,10 @@ namespace MMAP
return uint32(x << 16 | y);
}
LoadResult MMapManager::loadMap(std::string_view basePath, uint32 mapId, int32 x, int32 y)
LoadResult MMapManager::loadMap(std::string_view basePath, uint32 mapId, uint32 instanceId, int32 x, int32 y)
{
// make sure the mmap is loaded and ready to load tiles
switch (LoadResult mapResult = loadMapData(basePath, mapId))
switch (LoadResult mapResult = loadMapData(basePath, mapId, instanceId))
{
case LoadResult::Success:
case LoadResult::AlreadyLoaded:
@@ -182,11 +213,11 @@ namespace MMAP
// get this mmap data
MMapData* mmap = loadedMMaps[mapId].get();
ASSERT(mmap->navMesh);
MMapMapData& meshData = mmap->GetMeshData(mapId, instanceId).first->second;
// check if we already have this tile loaded
uint32 packedGridPos = packTileID(x, y);
if (mmap->loadedTileRefs.contains(packedGridPos))
if (meshData.loadedTileRefs.contains(packedGridPos))
return LoadResult::AlreadyLoaded;
// load this tile :: mmaps/MMMM_XX_YY.mmtile
@@ -253,9 +284,9 @@ namespace MMAP
dtTileRef tileRef = 0;
// memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
if (dtStatusSucceed(mmap->navMesh->addTile(static_cast<unsigned char*>(data.release()), fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
if (dtStatusSucceed(meshData.navMesh.addTile(static_cast<unsigned char*>(data.release()), fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
{
mmap->loadedTileRefs.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
meshData.loadedTileRefs[packedGridPos] = tileRef;
++loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile {:04}[{:02}, {:02}] into {:04}[{:02}, {:02}]", mapId, x, y, mapId, header->x, header->y);
return LoadResult::Success;
@@ -269,7 +300,7 @@ namespace MMAP
bool MMapManager::loadMapInstance(std::string_view basePath, uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
{
switch (loadMapData(basePath, meshMapId))
switch (loadMapData(basePath, meshMapId, instanceId))
{
case LoadResult::Success:
case LoadResult::AlreadyLoaded:
@@ -279,14 +310,17 @@ namespace MMAP
}
MMapData* mmap = loadedMMaps[meshMapId].get();
auto [queryItr, inserted] = mmap->navMeshQueries.try_emplace({ instanceMapId, instanceId }, nullptr);
auto [queryItr, inserted] = mmap->navMeshQueries.try_emplace({ instanceMapId, instanceId });
if (!inserted)
return true;
auto loadGuard = Trinity::make_unique_ptr_with_deleter(&queryItr, [&](NavMeshQuerySet::iterator* m)
{
mmap->navMeshQueries.erase(*m);
});
// allocate mesh query
NavMeshQueryPtr query(dtAllocNavMeshQuery());
ASSERT(query);
if (dtStatusFailed(query->init(mmap->navMesh.get(), 1024)))
if (dtStatusFailed(queryItr->second.init(&mmap->GetMeshData(meshMapId, instanceId).first->second.navMesh, 1024)))
{
mmap->navMeshQueries.erase(queryItr);
TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {:04} instanceId {}", instanceMapId, instanceId);
@@ -294,11 +328,11 @@ namespace MMAP
}
TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId {:04} instanceId {}", instanceMapId, instanceId);
queryItr->second = std::move(query);
(void)loadGuard.release();
return true;
}
bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
void MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
{
// check if we have this map loaded
MMapDataSet::const_iterator itr = GetMMapData(mapId);
@@ -306,72 +340,69 @@ namespace MMAP
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. {:04}_{:02}_{:02}.mmtile", mapId, x, y);
return false;
return;
}
MMapData* mmap = itr->second.get();
// check if we have this tile loaded
uint32 packedGridPos = packTileID(x, y);
auto tileRef = mmap->loadedTileRefs.extract(packedGridPos);
if (!tileRef)
for (auto& [instanceId, meshData] : mmap->meshData)
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. {:04}{:02}{:02}.mmtile", mapId, x, y);
return false;
}
// check if we have this tile loaded
auto tileRef = meshData.loadedTileRefs.extract(packedGridPos);
if (!tileRef)
continue;
// unload, and mark as non loaded
if (dtStatusFailed(mmap->navMesh->removeTile(tileRef.mapped(), nullptr, nullptr)))
{
// this is technically a memory leak
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
// we cannot recover from this error - assert out
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
ABORT();
// unload, and mark as non loaded
if (dtStatusFailed(meshData.navMesh.removeTile(tileRef.mapped(), nullptr, nullptr)))
{
// this is technically a memory leak
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
// we cannot recover from this error - assert out
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
ABORT();
}
else
{
--loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:04}[{:02}, {:02}] from {:03}", mapId, x, y, mapId);
}
}
else
{
--loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:04}[{:02}, {:02}] from {:03}", mapId, x, y, mapId);
return true;
}
return false;
}
bool MMapManager::unloadMap(uint32 mapId)
void MMapManager::unloadMap(uint32 mapId)
{
MMapDataSet::iterator itr = loadedMMaps.find(mapId);
if (itr == loadedMMaps.end() || !itr->second)
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map {:04}", mapId);
return false;
return;
}
// unload all tiles from given map
MMapData* mmap = itr->second.get();
for (auto const& [tileId, tileRef] : mmap->loadedTileRefs)
if (MMapData::GetInstanceIdForMeshLookup(mapId, std::numeric_limits<uint32>::max()) == 0)
{
uint32 x = (tileId >> 16);
uint32 y = (tileId & 0x0000FFFF);
if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, nullptr, nullptr)))
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
else
// unload all tiles from given map
MMapMapData& mesh = itr->second->meshData[0];
for (auto const& [tileId, tileRef] : mesh.loadedTileRefs)
{
--loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:04}[{:02}, {:02}] from {:04}", mapId, x, y, mapId);
uint32 x = (tileId >> 16);
uint32 y = (tileId & 0x0000FFFF);
if (dtStatusFailed(mesh.navMesh.removeTile(tileRef, nullptr, nullptr)))
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
else
{
--loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:04}[{:02}, {:02}] from {:04}", mapId, x, y, mapId);
}
}
}
else // require all tiles to be already unloaded
ASSERT(std::ranges::all_of(itr->second->meshData, [](MMapMapData const& mesh) { return mesh.loadedTileRefs.empty(); }, Trinity::Containers::MapValue));
itr->second = nullptr;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded {:04}.mmap", mapId);
return true;
}
bool MMapManager::unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
void MMapManager::unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
{
// check if we have this map loaded
MMapDataSet::const_iterator itr = GetMMapData(meshMapId);
@@ -379,29 +410,48 @@ namespace MMAP
{
// file may not exist, therefore not loaded
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map {:04}", meshMapId);
return false;
return;
}
MMapData* mmap = itr->second.get();
std::size_t erased = mmap->navMeshQueries.erase({ instanceMapId, instanceId });
if (!erased)
{
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId {:04} instanceId {}", instanceMapId, instanceId);
return false;
MeshDataMap::iterator meshItr = mmap->FindMeshData(meshMapId, instanceId);
if (meshItr != mmap->meshData.end())
{
// unload all tiles from given map
for (auto const& [tileId, tileRef] : meshItr->second.loadedTileRefs)
{
uint32 x = (tileId >> 16);
uint32 y = (tileId & 0x0000FFFF);
if (dtStatusFailed(meshItr->second.navMesh.removeTile(tileRef, nullptr, nullptr)))
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", meshMapId, x, y);
else
{
--loadedTiles;
TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:04}[{:02}, {:02}] from {:04}", meshMapId, x, y, meshMapId);
}
}
mmap->meshData.erase(meshItr);
}
TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId {:04} instanceId {}", instanceMapId, instanceId);
return true;
}
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId, uint32 instanceId)
{
MMapDataSet::const_iterator itr = GetMMapData(mapId);
if (itr == loadedMMaps.end())
return nullptr;
return itr->second->navMesh.get();
MeshDataMap::iterator meshItr = itr->second->FindMeshData(mapId, instanceId);
if (meshItr == itr->second->meshData.end())
return nullptr;
return &meshItr->second.navMesh;
}
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
@@ -414,6 +464,6 @@ namespace MMAP
if (queryItr == itr->second->navMeshQueries.end())
return nullptr;
return queryItr->second.get();
return &queryItr->second;
}
}

View File

@@ -59,26 +59,25 @@ namespace MMAP
void InitializeThreadUnsafe(std::unordered_map<uint32, std::vector<uint32>> const& mapData);
static LoadResult parseNavMeshParamsFile(std::string_view basePath, uint32 mapId, dtNavMeshParams* params, std::vector<OffMeshData>* offmeshConnections = nullptr);
LoadResult loadMap(std::string_view basePath, uint32 mapId, int32 x, int32 y);
LoadResult loadMap(std::string_view basePath, uint32 mapId, uint32 instanceId, int32 x, int32 y);
bool loadMapInstance(std::string_view basePath, uint32 meshMapId, uint32 instanceMapId, uint32 instanceId);
bool unloadMap(uint32 mapId, int32 x, int32 y);
bool unloadMap(uint32 mapId);
bool unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId);
void unloadMap(uint32 mapId, int32 x, int32 y);
void unloadMap(uint32 mapId);
void unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId);
// the returned [dtNavMeshQuery const*] is NOT threadsafe
dtNavMeshQuery const* GetNavMeshQuery(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId);
dtNavMesh const* GetNavMesh(uint32 mapId);
dtNavMesh const* GetNavMesh(uint32 mapId, uint32 instanceId);
uint32 getLoadedTilesCount() const { return loadedTiles; }
uint32 getLoadedMapsCount() const { return uint32(loadedMMaps.size()); }
private:
LoadResult loadMapData(std::string_view basePath, uint32 mapId);
LoadResult loadMapData(std::string_view basePath, uint32 mapId, uint32 instanceId);
uint32 packTileID(int32 x, int32 y);
MMapDataSet::const_iterator GetMMapData(uint32 mapId) const;
MMapDataSet loadedMMaps;
uint32 loadedTiles = 0;
bool thread_safe_environment = true;
std::unordered_map<uint32, uint32> parentMapData;
};

View File

@@ -290,6 +290,7 @@ void Map::EnsureGridCreated(GridCoord const& p)
int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
m_terrain->LoadMapAndVMap(gx, gy);
m_terrain->LoadMMap(GetInstanceId(), gx, gy);
}
}

View File

@@ -25,7 +25,6 @@
#include "MMapManager.h"
#include "PhasingHandler.h"
#include "Random.h"
#include "ScriptMgr.h"
#include "Util.h"
#include "VMapFactory.h"
#include "VMapManager.h"
@@ -144,7 +143,7 @@ bool TerrainInfo::ExistVMap(uint32 mapid, int32 gx, int32 gy)
bool TerrainInfo::HasChildTerrainGridFile(uint32 mapId, int32 gx, int32 gy) const
{
auto childMapItr = std::find_if(_childTerrain.begin(), _childTerrain.end(), [mapId](std::shared_ptr<TerrainInfo> const& childTerrain) { return childTerrain->GetId() == mapId; });
auto childMapItr = std::ranges::find(_childTerrain, mapId, [](std::shared_ptr<TerrainInfo> const& childTerrain) { return childTerrain->GetId(); });
return childMapItr != _childTerrain.end() && (*childMapItr)->_gridFileExists[GetBitsetIndex(gx, gy)];
}
@@ -171,11 +170,18 @@ void TerrainInfo::LoadMMapInstance(uint32 mapId, uint32 instanceId)
childTerrain->LoadMMapInstanceImpl(mapId, instanceId);
}
void TerrainInfo::LoadMMap(uint32 instanceId, int32 gx, int32 gy)
{
LoadMMapImpl(instanceId, gx, gy);
for (std::shared_ptr<TerrainInfo> const& childTerrain : _childTerrain)
childTerrain->LoadMMapImpl(instanceId, gx, gy);
}
void TerrainInfo::LoadMapAndVMapImpl(int32 gx, int32 gy)
{
LoadMap(gx, gy);
LoadVMap(gx, gy);
LoadMMap(gx, gy);
for (std::shared_ptr<TerrainInfo> const& childTerrain : _childTerrain)
childTerrain->LoadMapAndVMapImpl(gx, gy);
@@ -233,12 +239,12 @@ void TerrainInfo::LoadVMap(int32 gx, int32 gy)
}
}
void TerrainInfo::LoadMMap(int32 gx, int32 gy)
void TerrainInfo::LoadMMapImpl(uint32 instanceId, int32 gx, int32 gy)
{
if (!DisableMgr::IsPathfindingEnabled(GetId()))
return;
switch (MMAP::LoadResult mmapLoadResult = MMAP::MMapManager::instance()->loadMap(sWorld->GetDataPath(), GetId(), gx, gy))
switch (MMAP::LoadResult mmapLoadResult = MMAP::MMapManager::instance()->loadMap(sWorld->GetDataPath(), GetId(), instanceId, gx, gy))
{
case MMAP::LoadResult::Success:
TC_LOG_DEBUG("mmaps.tiles", "MMAP loaded name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})", GetMapName(), GetId(), gx, gy, gx, gy);

View File

@@ -58,13 +58,14 @@ public:
void LoadMapAndVMap(int32 gx, int32 gy);
void LoadMMapInstance(uint32 mapId, uint32 instanceId);
void LoadMMap(uint32 instanceId, int32 gx, int32 gy);
private:
void LoadMapAndVMapImpl(int32 gx, int32 gy);
void LoadMMapInstanceImpl(uint32 mapId, uint32 instanceId);
void LoadMap(int32 gx, int32 gy);
void LoadVMap(int32 gx, int32 gy);
void LoadMMap(int32 gx, int32 gy);
void LoadMMapImpl(uint32 instanceId, int32 gx, int32 gy);
public:
void UnloadMap(int32 gx, int32 gy);

View File

@@ -43,7 +43,7 @@ PathGenerator::PathGenerator(WorldObject const* owner) :
{
MMAP::MMapManager* mmap = MMAP::MMapManager::instance();
_navMeshQuery = mmap->GetNavMeshQuery(mapId, _source->GetMapId(), _source->GetInstanceId());
_navMesh = _navMeshQuery ? _navMeshQuery->getAttachedNavMesh() : mmap->GetNavMesh(mapId);
_navMesh = _navMeshQuery ? _navMeshQuery->getAttachedNavMesh() : mmap->GetNavMesh(mapId, _source->GetInstanceId());
}
CreateFilter();

View File

@@ -258,7 +258,7 @@ public:
uint32 haveMap = TerrainInfo::ExistMap(mapId, gridX, gridY) ? 1 : 0;
uint32 haveVMap = TerrainInfo::ExistVMap(mapId, gridX, gridY) ? 1 : 0;
uint32 haveMMap = (DisableMgr::IsPathfindingEnabled(mapId) && MMAP::MMapManager::instance()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0;
uint32 haveMMap = (DisableMgr::IsPathfindingEnabled(mapId) && MMAP::MMapManager::instance()->GetNavMesh(object->GetMapId(), object->GetInstanceId())) ? 1 : 0;
if (haveVMap)
{

View File

@@ -66,7 +66,8 @@ public:
static bool HandleMmapPathCommand(ChatHandler* handler, char const* args)
{
if (!MMAP::MMapManager::instance()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
Player* player = handler->GetSession()->GetPlayer();
if (!MMAP::MMapManager::instance()->GetNavMesh(player->GetMapId(), player->GetInstanceId()))
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
return true;
@@ -75,7 +76,6 @@ public:
handler->PSendSysMessage("mmap path:");
// units
Player* player = handler->GetSession()->GetPlayer();
Unit* target = handler->getSelectedUnit();
if (!player || !target)
{
@@ -144,7 +144,7 @@ public:
handler->PSendSysMessage("%04u_%02i_%02i.mmtile", terrainMapId, gx, gy);
handler->PSendSysMessage("tileloc [%i, %i]", gy, gx);
dtNavMesh const* navmesh = MMAP::MMapManager::instance()->GetNavMesh(terrainMapId);
dtNavMesh const* navmesh = MMAP::MMapManager::instance()->GetNavMesh(terrainMapId, player->GetInstanceId());
dtNavMeshQuery const* navmeshquery = MMAP::MMapManager::instance()->GetNavMeshQuery(terrainMapId, player->GetMapId(), player->GetInstanceId());
if (!navmesh || !navmeshquery)
{
@@ -195,7 +195,7 @@ public:
{
Player* player = handler->GetSession()->GetPlayer();
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMapId(), player->GetMap()->GetTerrain(), player->GetPositionX(), player->GetPositionY());
dtNavMesh const* navmesh = MMAP::MMapManager::instance()->GetNavMesh(terrainMapId);
dtNavMesh const* navmesh = MMAP::MMapManager::instance()->GetNavMesh(terrainMapId, player->GetInstanceId());
dtNavMeshQuery const* navmeshquery = MMAP::MMapManager::instance()->GetNavMeshQuery(terrainMapId, player->GetMapId(), player->GetInstanceId());
if (!navmesh || !navmeshquery)
{
@@ -227,7 +227,7 @@ public:
MMAP::MMapManager* manager = MMAP::MMapManager::instance();
handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
dtNavMesh const* navmesh = manager->GetNavMesh(terrainMapId);
dtNavMesh const* navmesh = manager->GetNavMesh(terrainMapId, player->GetInstanceId());
if (!navmesh)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");