diff --git a/src/common/Collision/Management/IVMapMgr.h b/src/common/Collision/Management/IVMapMgr.h index 410743f76..4af323372 100644 --- a/src/common/Collision/Management/IVMapMgr.h +++ b/src/common/Collision/Management/IVMapMgr.h @@ -31,6 +31,8 @@ This is the minimum interface to the VMapMamager. namespace VMAP { + class StaticMapTree; + enum VMAP_LOAD_RESULT { VMAP_LOAD_RESULT_ERROR, @@ -88,20 +90,8 @@ namespace VMAP virtual ~IVMapMgr() = default; - virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0; - virtual LoadResult existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0; - virtual void unloadMap(unsigned int pMapId, int x, int y) = 0; - virtual void unloadMap(unsigned int pMapId) = 0; - - virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) = 0; - virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist) = 0; - /** - test if we hit an object. return true if we hit one. rx, ry, rz will hold the hit position or the dest position, if no intersection was found - return a position, that is pReduceDist closer to the origin - */ - virtual bool GetObjectHitPos(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float pModifyDist) = 0; /** send debug commands */ @@ -123,12 +113,6 @@ namespace VMAP [[nodiscard]] bool isMapLoadingEnabled() const { return (iEnableLineOfSightCalc || iEnableHeightCalc ); } [[nodiscard]] virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0; - - /** - Query world model area info. - \param z gets adjusted to the ground height for which this are info is valid - */ - virtual bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const = 0; }; } diff --git a/src/common/Collision/Management/MMapFactory.cpp b/src/common/Collision/Management/MMapFactory.cpp deleted file mode 100644 index 4409bcc77..000000000 --- a/src/common/Collision/Management/MMapFactory.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#include "MMapFactory.h" -#include -namespace MMAP -{ - // ######################## MMapFactory ######################## - // our global singleton copy - MMapMgr* g_MMapMgr = nullptr; - bool MMapFactory::forbiddenMaps[1000] = {0}; - - MMapMgr* MMapFactory::createOrGetMMapMgr() - { - if (!g_MMapMgr) - { - g_MMapMgr = new MMapMgr(); - } - - return g_MMapMgr; - } - - void MMapFactory::InitializeDisabledMaps() - { - memset(&forbiddenMaps, 0, sizeof(forbiddenMaps)); - int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1}; - uint32 i = 0; - while (f[i] >= 0) - { - forbiddenMaps[f[i++]] = true; - } - } - - void MMapFactory::clear() - { - if (g_MMapMgr) - { - delete g_MMapMgr; - g_MMapMgr = nullptr; - } - } -} diff --git a/src/common/Collision/Management/MMapFactory.h b/src/common/Collision/Management/MMapFactory.h deleted file mode 100644 index 923954ab4..000000000 --- a/src/common/Collision/Management/MMapFactory.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#ifndef _MMAP_FACTORY_H -#define _MMAP_FACTORY_H - -#include "MMapMgr.h" - -namespace MMAP -{ - enum MMAP_LOAD_RESULT - { - MMAP_LOAD_RESULT_ERROR, - MMAP_LOAD_RESULT_OK, - MMAP_LOAD_RESULT_IGNORED, - }; - - // static class - // holds all mmap global data - // access point to MMapMgr singleton - class MMapFactory - { - public: - static MMapMgr* createOrGetMMapMgr(); - static void clear(); - static void InitializeDisabledMaps(); - static bool forbiddenMaps[1000]; - }; -} - -#endif diff --git a/src/common/Collision/Management/MMapMgr.cpp b/src/common/Collision/Management/MMapMgr.cpp index d3c450097..9944995e4 100644 --- a/src/common/Collision/Management/MMapMgr.cpp +++ b/src/common/Collision/Management/MMapMgr.cpp @@ -24,63 +24,8 @@ namespace MMAP { // ######################## MMapMgr ######################## - MMapMgr::~MMapMgr() + std::shared_ptr MMapMgr::LoadNavMesh(uint32 mapId) { - for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i) - { - delete i->second; - } - - // by now we should not have maps loaded - // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost! - } - - void MMapMgr::InitializeThreadUnsafe(const std::vector& mapIds) - { - // the caller must pass the list of all mapIds that will be used in the VMapMgr2 lifetime - for (const uint32& mapId : mapIds) - { - loadedMMaps.emplace(mapId, nullptr); - } - - thread_safe_environment = false; - } - - MMapDataSet::const_iterator MMapMgr::GetMMapData(uint32 mapId) const - { - // return the iterator if found or end() if not found/NULL - MMapDataSet::const_iterator itr = loadedMMaps.find(mapId); - if (itr != loadedMMaps.cend() && !itr->second) - { - itr = loadedMMaps.cend(); - } - - return itr; - } - - bool MMapMgr::loadMapData(uint32 mapId) - { - // we already have this map loaded? - MMapDataSet::iterator itr = loadedMMaps.find(mapId); - if (itr != loadedMMaps.end()) - { - if (itr->second) - { - return true; - } - } - else - { - if (thread_safe_environment) - { - itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first; - } - else - { - ABORT("Invalid mapId {} passed to MMapMgr after startup in thread unsafe environment", mapId); - } - } - // load and init dtNavMesh - read parameters from file std::string fileName = Acore::StringFormat(MAP_FILE_NAME_FORMAT, sConfigMgr->GetOption("DataDir", "."), mapId); @@ -88,7 +33,7 @@ namespace MMAP if (!file) { LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '{}'", fileName); - return false; + return nullptr; } dtNavMeshParams params; @@ -97,7 +42,7 @@ namespace MMAP if (count != 1) { LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '{}'", fileName); - return false; + return nullptr; } dtNavMesh* mesh = dtAllocNavMesh(); @@ -106,15 +51,13 @@ namespace MMAP { dtFreeNavMesh(mesh); LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {:03} from file {}", mapId, fileName); - return false; + return nullptr; } LOG_DEBUG("maps", "MMAP:loadMapData: Loaded {:03}.mmap", mapId); - // store inside our map list - MMapData* mmap_data = new MMapData(mesh); - itr->second = mmap_data; - return true; + std::shared_ptr navMesh = std::shared_ptr(mesh, NavMeshDeleter()); + return navMesh; } uint32 MMapMgr::packTileID(int32 x, int32 y) @@ -122,26 +65,8 @@ namespace MMAP return uint32(x << 16 | y); } - bool MMapMgr::loadMap(uint32 mapId, int32 x, int32 y) + bool MMapMgr::LoadTile(dtNavMesh* navMesh, uint32 mapId, int32 x, int32 y) { - // make sure the mmap is loaded and ready to load tiles - if (!loadMapData(mapId)) - { - return false; - } - - // get this mmap data - MMapData* mmap = loadedMMaps[mapId]; - ASSERT(mmap->navMesh); - - // check if we already have this tile loaded - uint32 packedGridPos = packTileID(x, y); - if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end()) - { - LOG_ERROR("maps", "MMAP:loadMap: Asked to load already loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); - return false; - } - // load this tile :: mmaps/MMMXXYY.mmtile std::string fileName = Acore::StringFormat(TILE_FILE_NAME_FORMAT, sConfigMgr->GetOption("DataDir", "."), mapId, x, y); FILE* file = fopen(fileName.c_str(), "rb"); @@ -184,10 +109,8 @@ 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(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) + if (dtStatusSucceed(navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) { - mmap->loadedTileRefs.insert(std::pair(packedGridPos, tileRef)); - ++loadedTiles; dtMeshHeader* header = (dtMeshHeader*)data; LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile {:03}[{:02},{:02}] into {:03}[{:02},{:02}]", mapId, x, y, mapId, header->x, header->y); return true; @@ -198,149 +121,19 @@ namespace MMAP return false; } - bool MMapMgr::unloadMap(uint32 mapId, int32 x, int32 y) + ManagedNavMeshQuery MMapMgr::CreateNavMeshQuery(dtNavMesh* navMesh) { - // check if we have this map loaded - MMapDataSet::const_iterator itr = GetMMapData(mapId); - if (itr == loadedMMaps.end()) - { - // file may not exist, therefore not loaded - LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. {:03}{:02}{:02}.mmtile", mapId, x, y); - return false; - } - - MMapData* mmap = itr->second; - - // check if we have this tile loaded - uint32 packedGridPos = packTileID(x, y); - if (mmap->loadedTileRefs.find(packedGridPos) == mmap->loadedTileRefs.end()) - { - // file may not exist, therefore not loaded - LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. {:03}{:02}{:02}.mmtile", mapId, x, y); - return false; - } - - dtTileRef tileRef = mmap->loadedTileRefs[packedGridPos]; - - // unload, and mark as non loaded - if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, 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 - LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:03}{:02}{:02}.mmtile from navmesh", mapId, x, y); - ABORT(); - } - - mmap->loadedTileRefs.erase(packedGridPos); - --loadedTiles; - LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:03}[{:02},{:02}] from {:03}", mapId, x, y, mapId); - return true; - } - - bool MMapMgr::unloadMap(uint32 mapId) - { - MMapDataSet::iterator itr = loadedMMaps.find(mapId); - if (itr == loadedMMaps.end() || !itr->second) - { - // file may not exist, therefore not loaded - LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map {:03}", mapId); - return false; - } - - // unload all tiles from given map - MMapData* mmap = itr->second; - for (auto& i : mmap->loadedTileRefs) - { - uint32 x = (i.first >> 16); - uint32 y = (i.first & 0x0000FFFF); - - if (dtStatusFailed(mmap->navMesh->removeTile(i.second, nullptr, nullptr))) - { - LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:03}{:02}{:02}.mmtile from navmesh", mapId, x, y); - } - else - { - --loadedTiles; - LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile {:03}[{:02},{:02}] from {:03}", mapId, x, y, mapId); - } - } - - delete mmap; - itr->second = nullptr; - LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded {:03}.mmap", mapId); - - return true; - } - - bool MMapMgr::unloadMapInstance(uint32 mapId, uint32 instanceId) - { - // check if we have this map loaded - MMapDataSet::const_iterator itr = GetMMapData(mapId); - if (itr == loadedMMaps.end()) - { - // file may not exist, therefore not loaded - LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map {:03}", mapId); - return false; - } - - MMapData* mmap = itr->second; - if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) - { - LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId {:03} instanceId {}", mapId, instanceId); - return false; - } - - dtNavMeshQuery* query = mmap->navMeshQueries[instanceId]; - - dtFreeNavMeshQuery(query); - mmap->navMeshQueries.erase(instanceId); - LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId {:03} instanceId {}", mapId, instanceId); - - return true; - } - - dtNavMesh const* MMapMgr::GetNavMesh(uint32 mapId) - { - MMapDataSet::const_iterator itr = GetMMapData(mapId); - if (itr == loadedMMaps.end()) + // allocate mesh query + dtNavMeshQuery* query = dtAllocNavMeshQuery(); + ASSERT(query); + + if (dtStatusFailed(query->init(navMesh, 1024))) { + dtFreeNavMeshQuery(query); return nullptr; } - return itr->second->navMesh; - } - - dtNavMeshQuery const* MMapMgr::GetNavMeshQuery(uint32 mapId, uint32 instanceId) - { - MMapDataSet::const_iterator itr = GetMMapData(mapId); - if (itr == loadedMMaps.end()) - { - return nullptr; - } - - MMapData* mmap = itr->second; - if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) - { - // check again after acquiring mutex - if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) - { - // allocate mesh query - dtNavMeshQuery* query = dtAllocNavMeshQuery(); - ASSERT(query); - - if (dtStatusFailed(query->init(mmap->navMesh, 1024))) - { - dtFreeNavMeshQuery(query); - LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {:03} instanceId {}", mapId, instanceId); - return nullptr; - } - - LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId {:03} instanceId {}", mapId, instanceId); - mmap->navMeshQueries.insert(std::pair(instanceId, query)); - } - } - - return mmap->navMeshQueries[instanceId]; + ManagedNavMeshQuery navMeshQuery = ManagedNavMeshQuery(query); + return navMeshQuery; } } diff --git a/src/common/Collision/Management/MMapMgr.h b/src/common/Collision/Management/MMapMgr.h index 823142cde..3b02d280a 100644 --- a/src/common/Collision/Management/MMapMgr.h +++ b/src/common/Collision/Management/MMapMgr.h @@ -22,8 +22,7 @@ #include "DetourAlloc.h" #include "DetourExtended.h" #include "DetourNavMesh.h" -#include -#include +#include // memory management inline void* dtCustomAlloc(std::size_t size, dtAllocHint /*hint*/) @@ -39,67 +38,40 @@ inline void dtCustomFree(void* ptr) // move map related classes namespace MMAP { + enum MMAP_LOAD_RESULT + { + MMAP_LOAD_RESULT_ERROR, + MMAP_LOAD_RESULT_OK, + MMAP_LOAD_RESULT_IGNORED, + }; + static char const* const MAP_FILE_NAME_FORMAT = "{}/mmaps/{:03}.mmap"; static char const* const TILE_FILE_NAME_FORMAT = "{}/mmaps/{:03}{:02}{:02}.mmtile"; - typedef std::unordered_map MMapTileSet; - typedef std::unordered_map NavMeshQuerySet; - - // dummy struct to hold map's mmap data - struct MMapData + struct NavMeshDeleter { - MMapData(dtNavMesh* mesh) : navMesh(mesh) { } - - ~MMapData() - { - for (auto& navMeshQuerie : navMeshQueries) - { - dtFreeNavMeshQuery(navMeshQuerie.second); - } - - if (navMesh) - { - dtFreeNavMesh(navMesh); - } - } - - // we have to use single dtNavMeshQuery for every instance, since those are not thread safe - NavMeshQuerySet navMeshQueries; // instanceId to query - dtNavMesh* navMesh; - MMapTileSet loadedTileRefs; // maps [map grid coords] to [dtTile] + void operator()(dtNavMesh* navMesh) noexcept { dtFreeNavMesh(navMesh); } }; - typedef std::unordered_map MMapDataSet; + struct NavMeshQueryDeleter + { + void operator()(dtNavMeshQuery* query) noexcept { dtFreeNavMeshQuery(query); } + }; + + using ManagedNavMeshQuery = std::unique_ptr; - // singleton class - // holds all all access to mmap loading unloading and meshes class MMapMgr { public: - MMapMgr() = default; - ~MMapMgr(); + MMapMgr() = default; + ~MMapMgr() = default; - void InitializeThreadUnsafe(const std::vector& mapIds); - bool loadMap(uint32 mapId, int32 x, int32 y); - bool unloadMap(uint32 mapId, int32 x, int32 y); - bool unloadMap(uint32 mapId); - bool unloadMapInstance(uint32 mapId, uint32 instanceId); - - // the returned [dtNavMeshQuery const*] is NOT threadsafe - dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId); - dtNavMesh const* GetNavMesh(uint32 mapId); - - [[nodiscard]] uint32 getLoadedTilesCount() const { return loadedTiles; } - [[nodiscard]] uint32 getLoadedMapsCount() const { return loadedMMaps.size(); } + static std::shared_ptr LoadNavMesh(uint32 mapId); + static bool LoadTile(dtNavMesh* navMesh, uint32 mapId, int32 x, int32 y); + static ManagedNavMeshQuery CreateNavMeshQuery(dtNavMesh* navMesh); private: - bool loadMapData(uint32 mapId); - uint32 packTileID(int32 x, int32 y); - [[nodiscard]] MMapDataSet::const_iterator GetMMapData(uint32 mapId) const; - - MMapDataSet loadedMMaps; - uint32 loadedTiles{0}; - bool thread_safe_environment{true}; + static uint32 packTileID(int32 x, int32 y); }; } diff --git a/src/common/Collision/Management/VMapMgr2.cpp b/src/common/Collision/Management/VMapMgr2.cpp index 7639c9c6b..24e4745d7 100644 --- a/src/common/Collision/Management/VMapMgr2.cpp +++ b/src/common/Collision/Management/VMapMgr2.cpp @@ -17,11 +17,8 @@ #include "VMapMgr2.h" #include "Errors.h" -#include "Log.h" #include "MapDefines.h" #include "MapTree.h" -#include "ModelInstance.h" -#include "WorldModel.h" #include #include #include @@ -35,34 +32,13 @@ namespace VMAP { GetLiquidFlagsPtr = &GetLiquidFlagsDummy; IsVMAPDisabledForPtr = &IsVMAPDisabledForDummy; - thread_safe_environment = true; } VMapMgr2::~VMapMgr2() { - for (InstanceTreeMap::iterator i = iInstanceMapTrees.begin(); i != iInstanceMapTrees.end(); ++i) - { - delete i->second; - } - - for (ModelFileMap::iterator i = iLoadedModelFiles.begin(); i != iLoadedModelFiles.end(); ++i) - { - delete i->second.getModel(); - } } - void VMapMgr2::InitializeThreadUnsafe(const std::vector& mapIds) - { - // the caller must pass the list of all mapIds that will be used in the VMapMgr2 lifetime - for (const uint32& mapId : mapIds) - { - iInstanceMapTrees.emplace(mapId, nullptr); - } - - thread_safe_environment = false; - } - - Vector3 VMapMgr2::convertPositionToInternalRep(float x, float y, float z) const + Vector3 VMapMgr2::convertPositionToInternalRep(float x, float y, float z) { Vector3 pos; const float mid = 0.5f * MAX_NUMBER_OF_GRIDS * SIZE_OF_GRIDS; @@ -73,18 +49,6 @@ namespace VMAP return pos; } - InstanceTreeMap::const_iterator VMapMgr2::GetMapTree(uint32 mapId) const - { - // return the iterator if found or end() if not found/NULL - InstanceTreeMap::const_iterator itr = iInstanceMapTrees.find(mapId); - if (itr != iInstanceMapTrees.cend() && !itr->second) - { - itr = iInstanceMapTrees.cend(); - } - - return itr; - } - // move to MapTree too? std::string VMapMgr2::getMapFileName(unsigned int mapId) { @@ -95,245 +59,9 @@ namespace VMAP return fname.str(); } - int VMapMgr2::loadMap(const char* basePath, unsigned int mapId, int x, int y) - { - int result = VMAP_LOAD_RESULT_IGNORED; - if (isMapLoadingEnabled()) - { - if (_loadMap(mapId, basePath, x, y)) - { - result = VMAP_LOAD_RESULT_OK; - } - else - { - result = VMAP_LOAD_RESULT_ERROR; - } - } - - return result; - } - - // load one tile (internal use only) - bool VMapMgr2::_loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY) - { - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); - if (instanceTree == iInstanceMapTrees.end()) - { - if (thread_safe_environment) - { - instanceTree = iInstanceMapTrees.insert(InstanceTreeMap::value_type(mapId, nullptr)).first; - } - else - ABORT("Invalid mapId {} tile [{}, {}] passed to VMapMgr2 after startup in thread unsafe environment", - mapId, tileX, tileY); - } - - if (!instanceTree->second) - { - std::string mapFileName = getMapFileName(mapId); - StaticMapTree* newTree = new StaticMapTree(mapId, basePath); - if (!newTree->InitMap(mapFileName, this)) - { - delete newTree; - return false; - } - instanceTree->second = newTree; - } - - return instanceTree->second->LoadMapTile(tileX, tileY, this); - } - - void VMapMgr2::unloadMap(unsigned int mapId) - { - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); - if (instanceTree != iInstanceMapTrees.end() && instanceTree->second) - { - instanceTree->second->UnloadMap(this); - if (instanceTree->second->numLoadedTiles() == 0) - { - delete instanceTree->second; - instanceTree->second = nullptr; - } - } - } - - void VMapMgr2::unloadMap(unsigned int mapId, int x, int y) - { - InstanceTreeMap::iterator instanceTree = iInstanceMapTrees.find(mapId); - if (instanceTree != iInstanceMapTrees.end() && instanceTree->second) - { - instanceTree->second->UnloadMapTile(x, y, this); - if (instanceTree->second->numLoadedTiles() == 0) - { - delete instanceTree->second; - instanceTree->second = nullptr; - } - } - } - - bool VMapMgr2::isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) - { -#if defined(ENABLE_VMAP_CHECKS) - if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS)) - { - return true; - } -#endif - - InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); - if (instanceTree != iInstanceMapTrees.end()) - { - Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1); - Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2); - if (pos1 != pos2) - { - return instanceTree->second->isInLineOfSight(pos1, pos2, ignoreFlags); - } - } - - return true; - } - - /** - get the hit position and return true if we hit something - otherwise the result pos will be the dest pos - */ - bool VMapMgr2::GetObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) - { -#if defined(ENABLE_VMAP_CHECKS) - if (isLineOfSightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS)) -#endif - { - InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); - if (instanceTree != iInstanceMapTrees.end()) - { - Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1); - Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2); - Vector3 resultPos; - bool result = instanceTree->second->GetObjectHitPos(pos1, pos2, resultPos, modifyDist); - resultPos = convertPositionToInternalRep(resultPos.x, resultPos.y, resultPos.z); - rx = resultPos.x; - ry = resultPos.y; - rz = resultPos.z; - return result; - } - } - - rx = x2; - ry = y2; - rz = z2; - - return false; - } - - /** - get height or INVALID_HEIGHT if no height available - */ - - float VMapMgr2::getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist) - { -#if defined(ENABLE_VMAP_CHECKS) - if (isHeightCalcEnabled() && !IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_HEIGHT)) -#endif - { - InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); - if (instanceTree != iInstanceMapTrees.end()) - { - Vector3 pos = convertPositionToInternalRep(x, y, z); - float height = instanceTree->second->getHeight(pos, maxSearchDist); - if (height >= G3D::finf()) - { - return height = VMAP_INVALID_HEIGHT_VALUE; // No height - } - - return height; - } - } - - return VMAP_INVALID_HEIGHT_VALUE; - } - - bool VMapMgr2::GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const - { - InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); - if (instanceTree != iInstanceMapTrees.end()) - { - LocationInfo info; - Vector3 pos = convertPositionToInternalRep(x, y, z); - if (instanceTree->second->GetLocationInfo(pos, info)) - { - data.floorZ = info.ground_Z; - if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) - { - uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc - float liquidLevel; - if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & *reqLiquidType)) - if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) - data.liquidInfo.emplace(liquidType, liquidLevel); - } - - if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) - data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID); - return true; - } - } - - return false; - } - - WorldModel* VMapMgr2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */) - { - //! Critical section, thread safe access to iLoadedModelFiles - std::lock_guard lock(LoadedModelFilesLock); - - ModelFileMap::iterator model = iLoadedModelFiles.find(filename); - if (model == iLoadedModelFiles.end()) - { - WorldModel* worldmodel = new WorldModel(); - if (!worldmodel->readFile(basepath + filename + ".vmo")) - { - LOG_ERROR("maps", "VMapMgr2: could not load '{}{}.vmo'", basepath, filename); - delete worldmodel; - return nullptr; - } - LOG_DEBUG("maps", "VMapMgr2: loading file '{}{}'", basepath, filename); - - worldmodel->Flags = flags; - - model = iLoadedModelFiles.insert(std::pair(filename, ManagedModel())).first; - model->second.setModel(worldmodel); - } - - return model->second.getModel(); - } - - void VMapMgr2::releaseModelInstance(const std::string& filename) - { - //! Critical section, thread safe access to iLoadedModelFiles - std::lock_guard lock(LoadedModelFilesLock); - - ModelFileMap::iterator model = iLoadedModelFiles.find(filename); - if (model == iLoadedModelFiles.end()) - { - LOG_ERROR("maps", "VMapMgr2: trying to unload non-loaded file '{}'", filename); - return; - } - if (model->second.decRefCount() == 0) - { - LOG_DEBUG("maps", "VMapMgr2: unloading file '{}'", filename); - delete model->second.getModel(); - iLoadedModelFiles.erase(model); - } - } - LoadResult VMapMgr2::existsMap(const char* basePath, unsigned int mapId, int x, int y) { return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y); } - void VMapMgr2::GetInstanceMapTree(InstanceTreeMap& instanceMapTree) - { - instanceMapTree = iInstanceMapTrees; - } - } // namespace VMAP diff --git a/src/common/Collision/Management/VMapMgr2.h b/src/common/Collision/Management/VMapMgr2.h index 5fc4106d2..3c221b170 100644 --- a/src/common/Collision/Management/VMapMgr2.h +++ b/src/common/Collision/Management/VMapMgr2.h @@ -19,9 +19,6 @@ #define _VMAPMANAGER2_H #include "IVMapMgr.h" -#include -#include -#include //=========================================================== @@ -46,24 +43,6 @@ namespace G3D namespace VMAP { - class StaticMapTree; - class WorldModel; - - class ManagedModel - { - public: - ManagedModel() { } - void setModel(WorldModel* model) { iModel = model; } - WorldModel* getModel() { return iModel; } - int decRefCount() { return --iRefCount; } - protected: - WorldModel* iModel{nullptr}; - int iRefCount{0}; - }; - - typedef std::unordered_map InstanceTreeMap; - typedef std::unordered_map ModelFileMap; - enum DisableTypes { VMAP_DISABLE_AREAFLAG = 0x1, @@ -75,58 +54,25 @@ namespace VMAP class VMapMgr2 : public IVMapMgr { protected: - // Tree to check collision - ModelFileMap iLoadedModelFiles; - InstanceTreeMap iInstanceMapTrees; - bool thread_safe_environment; - - // Mutex for iLoadedModelFiles - std::mutex LoadedModelFilesLock; - - bool _loadMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY); - /* void _unloadMap(uint32 pMapId, uint32 x, uint32 y); */ - static uint32 GetLiquidFlagsDummy(uint32) { return 0; } static bool IsVMAPDisabledForDummy(uint32 /*entry*/, uint8 /*flags*/) { return false; } - InstanceTreeMap::const_iterator GetMapTree(uint32 mapId) const; - public: // public for debug - [[nodiscard]] G3D::Vector3 convertPositionToInternalRep(float x, float y, float z) const; + static G3D::Vector3 convertPositionToInternalRep(float x, float y, float z); static std::string getMapFileName(unsigned int mapId); VMapMgr2(); ~VMapMgr2() override; - void InitializeThreadUnsafe(const std::vector& mapIds); - - int loadMap(const char* pBasePath, unsigned int mapId, int x, int y) override; - - void unloadMap(unsigned int mapId, int x, int y) override; - void unloadMap(unsigned int mapId) override; - - bool isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) override ; - /** - fill the hit pos and return true, if an object was hit - */ - bool GetObjectHitPos(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) override; - float getHeight(unsigned int mapId, float x, float y, float z, float maxSearchDist) override; - bool processCommand(char* /*command*/) override { return false; } // for debug and extensions - bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional reqLiquidType, AreaAndLiquidData& data) const override; - - WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags); - void releaseModelInstance(const std::string& filename); - // what's the use of this? o.O [[nodiscard]] std::string getDirFileName(unsigned int mapId, int /*x*/, int /*y*/) const override { return getMapFileName(mapId); } LoadResult existsMap(const char* basePath, unsigned int mapId, int x, int y) override; - void GetInstanceMapTree(InstanceTreeMap& instanceMapTree); typedef uint32(*GetLiquidFlagsFn)(uint32 liquidType); GetLiquidFlagsFn GetLiquidFlagsPtr; diff --git a/src/common/Collision/Management/WorldModelStore.cpp b/src/common/Collision/Management/WorldModelStore.cpp new file mode 100644 index 000000000..af78a01d5 --- /dev/null +++ b/src/common/Collision/Management/WorldModelStore.cpp @@ -0,0 +1,43 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "Log.h" +#include "WorldModelStore.h" + +std::shared_ptr WorldModelStore::AcquireModelInstance(std::string const& basepath, std::string const& filename, uint32 flags/* Only used when creating the model */) +{ + //! Critical section, thread safe access + std::lock_guard lock(_lock); + + ModelFileMap::iterator model = _loadedModels.find(filename); + if (model == _loadedModels.end()) + { + std::shared_ptr worldmodel = std::make_shared(); + LOG_DEBUG("maps", "WorldModelStore: loading file '{}{}'", basepath, filename); + if (!worldmodel->readFile(basepath + filename + ".vmo")) + { + LOG_ERROR("maps", "WorldModelStore: could not load '{}{}.vmo'", basepath, filename); + return nullptr; + } + + worldmodel->Flags = flags; + + model = _loadedModels.insert(std::pair>(filename, worldmodel)).first; + } + + return model->second; +} diff --git a/src/common/Collision/Management/IMMAPMgr.h b/src/common/Collision/Management/WorldModelStore.h similarity index 55% rename from src/common/Collision/Management/IMMAPMgr.h rename to src/common/Collision/Management/WorldModelStore.h index 49452c4a7..a175e0d1f 100644 --- a/src/common/Collision/Management/IMMAPMgr.h +++ b/src/common/Collision/Management/WorldModelStore.h @@ -15,32 +15,32 @@ * with this program. If not, see . */ -#ifndef _IMMAPMANAGER_H -#define _IMMAPMANAGER_H +#ifndef _WORLDMODELSTORE_H +#define _WORLDMODELSTORE_H -// Interface for IMMapManger -namespace MMAP +#include "WorldModel.h" +#include +#include +#include + +class WorldModelStore { - enum MMAP_LOAD_RESULT +public: + static WorldModelStore* instance() { - MMAP_LOAD_RESULT_ERROR, - MMAP_LOAD_RESULT_OK, - MMAP_LOAD_RESULT_IGNORED, - }; + static WorldModelStore instance; + return &instance; + } - class IMMapMgr - { - private: - bool iEnablePathFinding; + std::shared_ptr AcquireModelInstance(std::string const& basepath, std::string const& filename, uint32 flags); - public: - IMMapMgr() : iEnablePathFinding(true) {} - virtual ~IMMapMgr(void) {} +private: + typedef std::unordered_map> ModelFileMap; + ModelFileMap _loadedModels; - //Enabled/Disabled Pathfinding - void setEnablePathFinding(bool value) { iEnablePathFinding = value; } - bool isEnablePathFinding() const { return (iEnablePathFinding); } - }; -} + std::mutex _lock; +}; + +#define sWorldModelStore WorldModelStore::instance() #endif diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index bb9577d4e..877b17085 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -22,6 +22,7 @@ #include "ModelInstance.h" #include "VMapDefinitions.h" #include "VMapMgr2.h" +#include "WorldModelStore.h" #include #include #include @@ -259,7 +260,7 @@ namespace VMAP //========================================================= - bool StaticMapTree::InitMap(const std::string& fname, VMapMgr2* vm) + bool StaticMapTree::InitMap(const std::string& fname) { //VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '{}'", fname); bool success = false; @@ -291,13 +292,12 @@ namespace VMAP #endif if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn)) { - WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name, spawn.flags); + std::shared_ptr model = sWorldModelStore->AcquireModelInstance(iBasePath, spawn.name, spawn.flags); //VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading {}", spawn.name); if (model) { // assume that global model always is the first and only tree value (could be improved...) iTreeValues[0] = ModelInstance(spawn, model); - iLoadedSpawns[0] = 1; } else { @@ -312,23 +312,14 @@ namespace VMAP //========================================================= - void StaticMapTree::UnloadMap(VMapMgr2* vm) + void StaticMapTree::UnloadMap() { - for (loadedSpawnMap::iterator i = iLoadedSpawns.begin(); i != iLoadedSpawns.end(); ++i) - { - iTreeValues[i->first].setUnloaded(); - for (uint32 refCount = 0; refCount < i->second; ++refCount) - { - vm->releaseModelInstance(iTreeValues[i->first].name); - } - } - iLoadedSpawns.clear(); iLoadedTiles.clear(); } //========================================================= - bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapMgr2* vm) + bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY) { if (!iIsTiled) { @@ -367,10 +358,11 @@ namespace VMAP if (result) { // acquire model instance - WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name, spawn.flags); + std::shared_ptr model = sWorldModelStore->AcquireModelInstance(iBasePath, spawn.name, spawn.flags); if (!model) { LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [{}, {}]", tileX, tileY); + // why do we continue to try to load if the model was unsuccessful here? } // update tree @@ -378,22 +370,22 @@ namespace VMAP if (fread(&referencedVal, sizeof(uint32), 1, tf) == 1) { - if (!iLoadedSpawns.count(referencedVal)) + if (referencedVal >= iNTreeValues) { -#if defined(VMAP_DEBUG) - if (referencedVal > iNTreeValues) - { - LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element ({}/{})", referencedVal, iNTreeValues); - continue; - } -#endif - iTreeValues[referencedVal] = ModelInstance(spawn, model); - iLoadedSpawns[referencedVal] = 1; + LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element ({}/{})", referencedVal, iNTreeValues); + continue; } + + // This looks odd and is confusing, took some research to figure it out: + // the first WorldModel will create a "groupmodel" of all other same-models in the tile + // we don't actually care about anything else + if (!iTreeValues[referencedVal].getWorldModel()) + { + iTreeValues[referencedVal] = ModelInstance(spawn, model); + } +#if defined(VMAP_DEBUG) else { - ++iLoadedSpawns[referencedVal]; -#if defined(VMAP_DEBUG) if (iTreeValues[referencedVal].ID != spawn.ID) { LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node"); @@ -402,8 +394,8 @@ namespace VMAP { LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID={}", spawn.ID); } -#endif } +#endif } else { @@ -427,7 +419,7 @@ namespace VMAP //========================================================= - void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY, VMapMgr2* vm) + void StaticMapTree::UnloadMapTile(uint32 tileX, uint32 tileY) { uint32 tileID = packTileID(tileX, tileY); loadedTileMap::iterator tile = iLoadedTiles.find(tileID); @@ -436,57 +428,6 @@ namespace VMAP LOG_ERROR("maps", "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:{} X:{} Y:{}", iMapID, tileX, tileY); return; } - if (tile->second) // file associated with tile - { - std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY); - FILE* tf = fopen(tilefile.c_str(), "rb"); - if (tf) - { - bool result = true; - char chunk[8]; - if (!readChunk(tf, chunk, VMAP_MAGIC, 8)) - { - result = false; - } - uint32 numSpawns; - if (fread(&numSpawns, sizeof(uint32), 1, tf) != 1) - { - result = false; - } - for (uint32 i = 0; i < numSpawns && result; ++i) - { - // read model spawns - ModelSpawn spawn; - result = ModelSpawn::readFromFile(tf, spawn); - if (result) - { - // release model instance - vm->releaseModelInstance(spawn.name); - - // update tree - uint32 referencedNode; - - if (fread(&referencedNode, sizeof(uint32), 1, tf) != 1) - { - result = false; - } - else - { - if (!iLoadedSpawns.count(referencedNode)) - { - LOG_ERROR("maps", "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '{}' (ID:{})", spawn.name, spawn.ID); - } - else if (--iLoadedSpawns[referencedNode] == 0) - { - iTreeValues[referencedNode].setUnloaded(); - iLoadedSpawns.erase(referencedNode); - } - } - } - } - fclose(tf); - } - } iLoadedTiles.erase(tile); METRIC_EVENT("map_events", "UnloadMapTile", diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 09e426e3f..88f0b8302 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -60,8 +60,6 @@ namespace VMAP // some maps are not splitted into tiles and we have to make sure, not removing the map before all tiles are removed // empty tiles have no tile file, hence map with bool instead of just a set (consistency check) loadedTileMap iLoadedTiles; - // stores to invalidate tree values, unload map, and to be able to report errors - loadedSpawnMap iLoadedSpawns; std::string iBasePath; private: @@ -81,10 +79,10 @@ namespace VMAP [[nodiscard]] float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const; bool GetLocationInfo(const G3D::Vector3& pos, LocationInfo& info) const; - bool InitMap(const std::string& fname, VMapMgr2* vm); - void UnloadMap(VMapMgr2* vm); - bool LoadMapTile(uint32 tileX, uint32 tileY, VMapMgr2* vm); - void UnloadMapTile(uint32 tileX, uint32 tileY, VMapMgr2* vm); + bool InitMap(const std::string& fname); + void UnloadMap(); + bool LoadMapTile(uint32 tileX, uint32 tileY); + void UnloadMapTile(uint32 tileX, uint32 tileY); [[nodiscard]] bool isTiled() const { return iIsTiled; } [[nodiscard]] uint32 numLoadedTiles() const { return iLoadedTiles.size(); } void GetModelInstances(ModelInstance*& models, uint32& count); diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index eebc7e62d..6a28164a2 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -24,6 +24,7 @@ #include "VMapFactory.h" #include "VMapMgr2.h" #include "WorldModel.h" +#include "WorldModelStore.h" using G3D::Vector3; using G3D::Ray; @@ -101,14 +102,6 @@ void LoadGameObjectModelList(std::string const& dataPath) LOG_INFO("server.loading", " "); } -GameObjectModel::~GameObjectModel() -{ - if (iModel) - { - VMAP::VMapFactory::createOrGetVMapMgr()->releaseModelInstance(name); - } -} - bool GameObjectModel::initialize(std::unique_ptr modelOwner, std::string const& dataPath) { ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId()); @@ -125,7 +118,7 @@ bool GameObjectModel::initialize(std::unique_ptr model return false; } - iModel = VMAP::VMapFactory::createOrGetVMapMgr()->acquireModelInstance(dataPath + "vmaps/", it->second.name, + iModel = sWorldModelStore->AcquireModelInstance(dataPath + "vmaps/", it->second.name, it->second.isWmo ? VMAP::ModelFlags::MOD_WORLDSPAWN : VMAP::ModelFlags::MOD_M2); if (!iModel) diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h index 5938a5c1d..695a5ee43 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace VMAP { @@ -58,7 +59,7 @@ public: [[nodiscard]] const G3D::AABox& GetBounds() const { return iBound; } - ~GameObjectModel(); + ~GameObjectModel() = default; [[nodiscard]] const G3D::Vector3& GetPosition() const { return iPos; } @@ -86,7 +87,7 @@ private: G3D::Vector3 iPos; float iInvScale{0}; float iScale{0}; - VMAP::WorldModel* iModel{nullptr}; + std::shared_ptr iModel; std::unique_ptr owner; bool isWmo{false}; }; diff --git a/src/common/Collision/Models/ModelInstance.cpp b/src/common/Collision/Models/ModelInstance.cpp index c5b6fbfdb..ecc97e85f 100644 --- a/src/common/Collision/Models/ModelInstance.cpp +++ b/src/common/Collision/Models/ModelInstance.cpp @@ -24,7 +24,7 @@ using G3D::Ray; namespace VMAP { - ModelInstance::ModelInstance(const ModelSpawn& spawn, WorldModel* model): ModelSpawn(spawn), iModel(model) + ModelInstance::ModelInstance(const ModelSpawn& spawn, std::shared_ptr model): ModelSpawn(spawn), iModel(model) { iInvRot = G3D::Matrix3::fromEulerAnglesZYX(G3D::pi() * iRot.y / 180.f, G3D::pi() * iRot.x / 180.f, G3D::pi() * iRot.z / 180.f).inverse(); iInvScale = 1.f / iScale; diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h index 3476a514d..f8c0ecbb1 100644 --- a/src/common/Collision/Models/ModelInstance.h +++ b/src/common/Collision/Models/ModelInstance.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace VMAP { @@ -63,16 +64,15 @@ namespace VMAP { public: ModelInstance() { } - ModelInstance(const ModelSpawn& spawn, WorldModel* model); - void setUnloaded() { iModel = nullptr; } + ModelInstance(const ModelSpawn& spawn, std::shared_ptr model); bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const; bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const; bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const; - WorldModel* getWorldModel() { return iModel; } + WorldModel* getWorldModel() { return iModel.get(); } protected: G3D::Matrix3 iInvRot; float iInvScale{0.0f}; - WorldModel* iModel{nullptr}; + std::shared_ptr iModel; }; } // namespace VMAP diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index c02c7c681..812b9668d 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -17,7 +17,6 @@ #include "DisableMgr.h" #include "GameEventMgr.h" -#include "MMapFactory.h" #include "ObjectMgr.h" #include "OutdoorPvP.h" #include "Player.h" @@ -448,5 +447,17 @@ bool DisableMgr::IsPathfindingEnabled(Map const* map) if (!map) return false; - return !MMAP::MMapFactory::forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena()); + // Still not an ideal solution but removes the extra awful forbiddenMaps hack + // int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1}; + switch (map->GetId()) + { + case 616: // EoE + case 649: // ToC25 + case 650: // ToC5 + return false; + default: + break; + } + + return (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena()); } diff --git a/src/server/game/Grids/GridTerrainLoader.cpp b/src/server/game/Grids/GridTerrainLoader.cpp index ecf9b0941..5b9598522 100644 --- a/src/server/game/Grids/GridTerrainLoader.cpp +++ b/src/server/game/Grids/GridTerrainLoader.cpp @@ -1,6 +1,6 @@ -#include "DisableMgr.h" #include "GridTerrainLoader.h" -#include "MMapFactory.h" +#include "IVMapMgr.h" +#include "Map.h" #include "MMapMgr.h" #include "ScriptMgr.h" #include "VMapFactory.h" @@ -9,6 +9,7 @@ void GridTerrainLoader::LoadTerrain() { LoadMap(); + if (_map->GetInstanceId() == 0) { LoadVMap(); @@ -18,13 +19,10 @@ void GridTerrainLoader::LoadTerrain() void GridTerrainLoader::LoadMap() { - // Instances will point to the parent maps terrain data + // Instances will point to the parent maps terrain data, no need to load anything. if (_map->GetInstanceId() != 0) { - // load grid map for base map Map* parentMap = const_cast(_map->GetParent()); - - // GetGridTerrainData will create the parent map grid _grid.SetTerrainData(parentMap->GetGridTerrainDataSharedPtr(GridCoord(_grid.GetX(), _grid.GetY()))); return; } @@ -51,7 +49,7 @@ void GridTerrainLoader::LoadMap() void GridTerrainLoader::LoadVMap() { - int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), _grid.GetX(), _grid.GetY()); + int const vmapLoadResult = _map->GetMapCollisionData().LoadVMapTile(_grid.GetX(), _grid.GetY()); switch (vmapLoadResult) { case VMAP::VMAP_LOAD_RESULT_OK: @@ -66,15 +64,14 @@ void GridTerrainLoader::LoadVMap() LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", _map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY()); break; + default: + break; } } void GridTerrainLoader::LoadMMap() { - if (!DisableMgr::IsPathfindingEnabled(_map)) - return; - - int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), _grid.GetX(), _grid.GetY()); + int const mmapLoadResult = _map->GetMapCollisionData().LoadMMapTile(_grid.GetX(), _grid.GetY()); switch (mmapLoadResult) { case MMAP::MMAP_LOAD_RESULT_OK: @@ -89,6 +86,8 @@ void GridTerrainLoader::LoadMMap() LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})", _map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY()); break; + default: + break; } } @@ -145,13 +144,3 @@ bool GridTerrainLoader::ExistVMap(uint32 mapid, int gx, int gy) return true; } - -void GridTerrainUnloader::UnloadTerrain() -{ - // Only parent maps manage terrain data - if (_map->GetInstanceId() != 0) - return; - - VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY()); - MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY()); -} diff --git a/src/server/game/Grids/GridTerrainLoader.h b/src/server/game/Grids/GridTerrainLoader.h index e1d6019bf..99b4b89ef 100644 --- a/src/server/game/Grids/GridTerrainLoader.h +++ b/src/server/game/Grids/GridTerrainLoader.h @@ -20,6 +20,8 @@ #include "GridDefines.h" +class Map; + class GridTerrainLoader { public: @@ -40,17 +42,4 @@ private: Map* _map; }; -class GridTerrainUnloader -{ -public: - GridTerrainUnloader(MapGridType& grid, Map* map) - : _grid(grid), _map(map) { } - - void UnloadTerrain(); - -private: - MapGridType& _grid; - Map* _map; -}; - #endif diff --git a/src/server/game/Grids/MapGridManager.cpp b/src/server/game/Grids/MapGridManager.cpp index 21ca5bfed..7821bfe2d 100644 --- a/src/server/game/Grids/MapGridManager.cpp +++ b/src/server/game/Grids/MapGridManager.cpp @@ -8,9 +8,19 @@ void MapGridManager::CreateGrid(uint16 const x, uint16 const y) if (IsGridCreated(x, y)) return; + // If we are an instance, ensure parent map has already created the grid before proceeding. + // Note: grid loading is locked and is safe across multiple map threads in the + // event of multiple child maps attempting to create the same parent map grid + if (_map->GetInstanceId() != 0) + { + Map* parentMap = const_cast(_map->GetParent()); + parentMap->EnsureGridCreated(GridCoord(x, y)); + } + std::unique_ptr grid = std::make_unique(x, y); grid->link(_map); + // Terrain is loading during create (should/can we move this to LoadGrid?) GridTerrainLoader loader(*grid, _map); loader.LoadTerrain(); @@ -19,6 +29,7 @@ void MapGridManager::CreateGrid(uint16 const x, uint16 const y) ++_createdGridsCount; } +// Loads objects, terrain already loaded in CreateGrid bool MapGridManager::LoadGrid(uint16 const x, uint16 const y) { MapGridType* grid = GetGrid(x, y); @@ -55,9 +66,6 @@ void MapGridManager::UnloadGrid(uint16 const x, uint16 const y) grid->VisitAllCells(visitor); } - GridTerrainUnloader terrainUnloader(*grid, _map); - terrainUnloader.UnloadTerrain(); - _mapGrid[x][y] = nullptr; } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 27d0b8fed..89cdd4bbf 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -32,7 +32,6 @@ #include "MapInstanced.h" #include "Metric.h" #include "MiscPackets.h" -#include "MMapFactory.h" #include "Object.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -62,13 +61,12 @@ Map::~Map() if (!m_scriptSchedule.empty()) sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size()); - - MMAP::MMapFactory::createOrGetMMapMgr()->unloadMapInstance(GetId(), i_InstanceId); } Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : - _mapGridManager(this), i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), - m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0), + _mapGridManager(this), i_mapEntry(sMapStore.LookupEntry(id)), _mapCollisionData(*this, _parent), + i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), + m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0), _transportsUpdateIter(_transports.end()), i_scriptLock(false), _defaultLight(GetDefaultMapLight(id)) { m_parentMap = (_parent ? _parent : this); @@ -432,7 +430,7 @@ void Map::UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone) void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/) { if (t_diff) - _dynamicTree.update(t_diff); + _mapCollisionData.GetDynamicTree().update(t_diff); // Update world sessions and players for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter) @@ -1074,9 +1072,9 @@ void Map::UnloadAll() std::shared_ptr Map::GetGridTerrainDataSharedPtr(GridCoord const& gridCoord) { - // ensure GridMap is created - EnsureGridCreated(gridCoord); - return _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord)->GetTerrainDataSharedPtr(); + MapGridType* grid = _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord); + ASSERT(grid); // Grid should always exist during this call + return grid->GetTerrainDataSharedPtr(); } GridTerrainData* Map::GetGridTerrainData(GridCoord const& gridCoord) @@ -1153,10 +1151,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float float vmapHeight = VMAP_INVALID_HEIGHT_VALUE; if (checkVMap) - { - VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); - vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist); // look from a bit higher pos to find the floor - } + vmapHeight = _mapCollisionData.GetStaticTree().getHeight(x, y, z, maxSearchDist); // look from a bit higher pos to find the floor // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT // vmapheight set for any under Z value or <= INVALID_HEIGHT @@ -1204,12 +1199,11 @@ static inline bool IsInWMOInterior(uint32 mogpFlags) bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const { float check_z = z; - VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::AreaAndLiquidData vdata; VMAP::AreaAndLiquidData ddata; - bool hasVmapAreaInfo = vmgr->GetAreaAndLiquidData(GetId(), x, y, z, {}, vdata) && vdata.areaInfo.has_value(); - bool hasDynamicAreaInfo = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value(); + bool hasVmapAreaInfo = _mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, {}, vdata) && vdata.areaInfo.has_value(); + bool hasDynamicAreaInfo = _mapCollisionData.GetDynamicTree().GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value(); auto useVmap = [&] { check_z = vdata.floorZ; groupId = vdata.areaInfo->groupId; adtId = vdata.areaInfo->adtId; rootId = vdata.areaInfo->rootId; flags = vdata.areaInfo->mogpFlags; }; auto useDyn = [&] { check_z = ddata.floorZ; groupId = ddata.areaInfo->groupId; adtId = ddata.areaInfo->adtId; rootId = ddata.areaInfo->rootId; flags = ddata.areaInfo->mogpFlags; }; if (hasVmapAreaInfo) @@ -1300,10 +1294,9 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, LiquidData liquidData; liquidData.Status = LIQUID_MAP_NO_WATER; - VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::AreaAndLiquidData vmapData; bool useGridLiquid = true; - if (vmgr->GetAreaAndLiquidData(GetId(), x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo) + if (_mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo) { useGridLiquid = !vmapData.areaInfo || !IsInWMOInterior(vmapData.areaInfo->mogpFlags); LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", vmapData.liquidInfo->level, vmapData.floorZ, vmapData.liquidInfo->type); @@ -1383,11 +1376,10 @@ void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y { GridTerrainData* gmap = GetGridTerrainData(x, y); - VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::AreaAndLiquidData vmapData; // VMAP::AreaAndLiquidData dynData; VMAP::AreaAndLiquidData* wmoData = nullptr; - vmgr->GetAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData); + _mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, reqLiquidType, vmapData); // _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData); uint32 gridAreaId = 0; @@ -1548,7 +1540,7 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa } } - if ((checks & LINEOFSIGHT_CHECK_VMAP) && !VMAP::VMapFactory::createOrGetVMapMgr()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags)) + if ((checks & LINEOFSIGHT_CHECK_VMAP) && !_mapCollisionData.GetStaticTree().isInLineOfSight(x1, y1, z1, x2, y2, z2, ignoreFlags)) { return false; } @@ -1561,7 +1553,7 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa ignoreFlags = VMAP::ModelIgnoreFlags::M2; } - if (!_dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask, ignoreFlags)) + if (!_mapCollisionData.GetDynamicTree().isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask, ignoreFlags)) { return false; } @@ -1570,25 +1562,11 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa return true; } -bool Map::GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) -{ - G3D::Vector3 startPos(x1, y1, z1); - G3D::Vector3 dstPos(x2, y2, z2); - - G3D::Vector3 resultPos; - bool result = _dynamicTree.GetObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist); - - rx = resultPos.x; - ry = resultPos.y; - rz = resultPos.z; - return result; -} - float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { float h1, h2; h1 = GetHeight(x, y, z, vmap, maxSearchDist); - h2 = _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask); + h2 = _mapCollisionData.GetDynamicTree().getHeight(x, y, z, maxSearchDist, phasemask); return std::max(h1, h2); } @@ -3050,8 +3028,7 @@ bool Map::CheckCollisionAndGetValidCoords(WorldObject const* source, float start // Unit is not on the ground, check for potential collision via vmaps if (notOnGround) { - bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(source->GetMapId(), - startX, startY, startZ + halfHeight, + bool col = _mapCollisionData.GetStaticTree().GetObjectHitPos(startX, startY, startZ + halfHeight, destX, destY, destZ + halfHeight, destX, destY, destZ, -CONTACT_DISTANCE); @@ -3065,7 +3042,7 @@ bool Map::CheckCollisionAndGetValidCoords(WorldObject const* source, float start } // check dynamic collision - bool col = source->GetMap()->GetObjectHitPos(source->GetPhaseMask(), + bool col = _mapCollisionData.GetDynamicTree().GetObjectHitPos(source->GetPhaseMask(), startX, startY, startZ + halfHeight, destX, destY, destZ + halfHeight, destX, destY, destZ, -CONTACT_DISTANCE); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 035ba0dce..e6027a717 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -27,6 +27,7 @@ #include "GameObjectModel.h" #include "GridDefines.h" #include "GridRefMgr.h" +#include "MapCollisionData.h" #include "MapGridManager.h" #include "MapRefMgr.h" #include "ObjectDefines.h" @@ -230,8 +231,6 @@ public: [[nodiscard]] Map const* GetParent() const { return m_parentMap; } - // pussywizard: movemaps, mmaps - [[nodiscard]] std::shared_mutex& GetMMapLock() const { return *(const_cast(&MMapLock)); } // pussywizard: std::unordered_set i_objectsForDelayedVisibility; void HandleDelayedVisibility(); @@ -389,15 +388,14 @@ public: bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const; bool CanReachPositionAndGetValidCoords(WorldObject const* source, float startX, float startY, float startZ, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const; bool CheckCollisionAndGetValidCoords(WorldObject const* source, float startX, float startY, float startZ, float &destX, float &destY, float &destZ, bool failOnCollision = true) const; - void Balance() { _dynamicTree.balance(); } - void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); } - void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); } - [[nodiscard]] bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);} - [[nodiscard]] DynamicMapTree const& GetDynamicMapTree() const { return _dynamicTree; } - bool GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist); + void Balance() { _mapCollisionData.GetDynamicTree().balance(); } + void RemoveGameObjectModel(const GameObjectModel& model) { _mapCollisionData.GetDynamicTree().remove(model); } + void InsertGameObjectModel(const GameObjectModel& model) { _mapCollisionData.GetDynamicTree().insert(model); } + [[nodiscard]] bool ContainsGameObjectModel(const GameObjectModel& model) const { return _mapCollisionData.GetDynamicTree().contains(model);} + [[nodiscard]] DynamicMapTree const& GetDynamicMapTree() const { return _mapCollisionData.GetDynamicTree(); } [[nodiscard]] float GetGameObjectFloor(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const { - return _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask); + return _mapCollisionData.GetDynamicTree().getHeight(x, y, z, maxSearchDist, phasemask); } /* RESPAWN TIMES @@ -524,6 +522,9 @@ public: return 0; }; + MapCollisionData& GetMapCollisionData() { return _mapCollisionData; } + MapCollisionData const& GetMapCollisionData() const { return _mapCollisionData; } + private: template void InitializeObject(T* obj); @@ -551,15 +552,14 @@ protected: void AddToGrid(T* object, Cell const& cell); std::mutex Lock; - std::shared_mutex MMapLock; MapGridManager _mapGridManager; MapEntry const* i_mapEntry; + MapCollisionData _mapCollisionData; uint8 i_spawnMode; uint32 i_InstanceId; uint32 m_unloadTimer; float m_VisibleDistance; - DynamicMapTree _dynamicTree; time_t _instanceResetPeriod; // pussywizard MapRefMgr m_mapRefMgr; diff --git a/src/server/game/Maps/MapCollisionData.cpp b/src/server/game/Maps/MapCollisionData.cpp new file mode 100644 index 000000000..bdce5edb2 --- /dev/null +++ b/src/server/game/Maps/MapCollisionData.cpp @@ -0,0 +1,183 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "DBCStores.h" +#include "DetourNavMeshQuery.h" +#include "DisableMgr.h" +#include "MapCollisionData.h" +#include "MapTree.h" +#include "ModelInstance.h" +#include "VMapFactory.h" +#include "VMapMgr2.h" +#include "World.h" +#include "WorldModel.h" + +#include + +MapCollisionData::MapCollisionData(Map const& map, Map const* parentMap) : + _map(map), _staticVMapData(map.GetId()) +{ + if (parentMap) + { + // If we have a parent map, point our static tree and mmap nav mesh to the parent maps + _staticVMapData._staticTree = parentMap->GetMapCollisionData().GetStaticTreeSharedPtr(); + _mmapData._navMesh = parentMap->GetMapCollisionData().GetMMapNavMeshSharedPtr(); + } + else + { + // If we are a base map create a new static tree and mmap nav mesh + std::string const mapFileName = VMAP::VMapMgr2::getMapFileName(map.GetId()); + std::shared_ptr newTree = std::make_shared(map.GetId(), (sWorld->GetDataPath() + "vmaps")); + if (newTree->InitMap(mapFileName)) + _staticVMapData._staticTree = newTree; + + _mmapData._navMesh = MMAP::MMapMgr::LoadNavMesh(map.GetId()); + } +} + +int MapCollisionData::LoadVMapTile(uint32 tileX, uint32 tileY) +{ + if (!VMAP::VMapFactory::createOrGetVMapMgr()->isMapLoadingEnabled() || !_staticVMapData._staticTree) + return VMAP::VMAP_LOAD_RESULT_IGNORED; + + if (!_staticVMapData._staticTree->LoadMapTile(tileX, tileY)) + return VMAP::VMAP_LOAD_RESULT_ERROR; + + return VMAP::VMAP_LOAD_RESULT_OK; +} + +int MapCollisionData::LoadMMapTile(uint32 tileX, uint32 tileY) +{ + if (!DisableMgr::IsPathfindingEnabled(&_map) || !_mmapData._navMesh) + return MMAP::MMAP_LOAD_RESULT_IGNORED; + + return MMAP::MMapMgr::LoadTile(_mmapData._navMesh.get(), _map.GetId(), tileX, tileY); +} + +bool StaticVMapCollisionData::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const +{ +#if defined(ENABLE_VMAP_CHECKS) + if (!sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_LOS) || DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LOS)) + return true; +#endif + + if (!_staticTree) + return true; + + G3D::Vector3 const pos1 = VMAP::VMapMgr2::convertPositionToInternalRep(x1, y1, z1); + G3D::Vector3 const pos2 = VMAP::VMapMgr2::convertPositionToInternalRep(x2, y2, z2); + if (pos1 != pos2) + return _staticTree->isInLineOfSight(pos1, pos2, ignoreFlags); + + return true; +} + +bool StaticVMapCollisionData::GetObjectHitPos(float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const +{ +#if defined(ENABLE_VMAP_CHECKS) + if (sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_LOS) && !DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LOS)) +#endif + { + if (_staticTree) + { + G3D::Vector3 const pos1 = VMAP::VMapMgr2::convertPositionToInternalRep(x1, y1, z1); + G3D::Vector3 const pos2 = VMAP::VMapMgr2::convertPositionToInternalRep(x2, y2, z2); + G3D::Vector3 resultPos; + bool result = _staticTree->GetObjectHitPos(pos1, pos2, resultPos, modifyDist); + resultPos = VMAP::VMapMgr2::convertPositionToInternalRep(resultPos.x, resultPos.y, resultPos.z); + rx = resultPos.x; + ry = resultPos.y; + rz = resultPos.z; + return result; + } + } + + rx = x2; + ry = y2; + rz = z2; + + return false; +} + +float StaticVMapCollisionData::getHeight(float x, float y, float z, float maxSearchDist) const +{ +#if defined(ENABLE_VMAP_CHECKS) + if (sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_HEIGHT) && !DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_HEIGHT)) +#endif + { + if (_staticTree) + { + G3D::Vector3 const pos = VMAP::VMapMgr2::convertPositionToInternalRep(x, y, z); + float height = _staticTree->getHeight(pos, maxSearchDist); + if (height >= G3D::finf()) + return VMAP_INVALID_HEIGHT_VALUE; // No height + + return height; + } + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + +bool StaticVMapCollisionData::GetAreaAndLiquidData(float x, float y, float z, Optional reqLiquidType, VMAP::AreaAndLiquidData& data) const +{ + if (_staticTree) + { + VMAP::LocationInfo info; + G3D::Vector3 const pos = VMAP::VMapMgr2::convertPositionToInternalRep(x, y, z); + if (_staticTree->GetLocationInfo(pos, info)) + { + data.floorZ = info.ground_Z; + if (!DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LIQUIDSTATUS)) + { + uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc + float liquidLevel; + if (!reqLiquidType || (GetLiquidFlags(liquidType) & *reqLiquidType)) + if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) + data.liquidInfo.emplace(liquidType, liquidLevel); + } + + if (!DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_AREAFLAG)) + data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID); + return true; + } + } + + return false; +} + +bool DynamicVMapCollisionData::GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const +{ + G3D::Vector3 startPos(x1, y1, z1); + G3D::Vector3 dstPos(x2, y2, z2); + + G3D::Vector3 resultPos; + bool result = DynamicMapTree::GetObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist); + + rx = resultPos.x; + ry = resultPos.y; + rz = resultPos.z; + return result; +} + +dtNavMeshQuery const* MMapData::GetNavMeshQuery() +{ + if (_navMesh && !_navMeshQuery) + _navMeshQuery = MMAP::MMapMgr::CreateNavMeshQuery(_navMesh.get()); + + return _navMeshQuery.get(); +} diff --git a/src/server/game/Maps/MapCollisionData.h b/src/server/game/Maps/MapCollisionData.h new file mode 100644 index 000000000..bb8a3cdac --- /dev/null +++ b/src/server/game/Maps/MapCollisionData.h @@ -0,0 +1,100 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef MAP_COLLISION_DATA_H +#define MAP_COLLISION_DATA_H + +#include "DynamicTree.h" +#include "MapTree.h" +#include "MMapMgr.h" +#include "IVMapMgr.h" + +class Map; + +namespace VMAP +{ + enum class ModelIgnoreFlags : uint32; +} + +// Simple wrappers for vmap static & dynamic trees to enable clear separation of use for increased readability +class StaticVMapCollisionData +{ + friend class MapCollisionData; + +public: + StaticVMapCollisionData(uint32 mapId) : _mapId(mapId) {} + + bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const; + bool GetObjectHitPos(float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const; + float getHeight(float x, float y, float z, float maxSearchDist) const; + bool GetAreaAndLiquidData(float x, float y, float z, Optional reqLiquidType, VMAP::AreaAndLiquidData& data) const; +protected: + // _staticTree is a shared_ptr as it will point to a parent maps static tree (if exists) to save on memory + std::shared_ptr _staticTree; + uint32 _mapId; +}; + +class DynamicVMapCollisionData : public DynamicMapTree +{ +public: + bool GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const; +}; + +class MMapData +{ + friend class MapCollisionData; + +public: + dtNavMesh const* GetNavMesh() const { return _navMesh.get(); } + dtNavMeshQuery const* GetNavMeshQuery(); + +protected: + // _navMesh is a shared_ptr as it will point to a parent maps nav mesh (if exists) to save on memory + std::shared_ptr _navMesh; + // navMeshQuery is not thread safe and needs its own instance per map + MMAP::ManagedNavMeshQuery _navMeshQuery; +}; + +// Map collision data holders (dynamic&static vmap, mmaps) +class MapCollisionData +{ +public: + MapCollisionData(Map const& map, Map const* parentMap); + ~MapCollisionData() = default; + + int LoadVMapTile(uint32 tileX, uint32 tileY); + int LoadMMapTile(uint32 tileX, uint32 tileY); + + DynamicVMapCollisionData& GetDynamicTree() { return _dynamicVMapData; } + DynamicVMapCollisionData const& GetDynamicTree() const { return _dynamicVMapData; } + StaticVMapCollisionData& GetStaticTree() { return _staticVMapData; } + StaticVMapCollisionData const& GetStaticTree() const { return _staticVMapData; } + MMapData& GetMMapData() { return _mmapData; } + MMapData const& GetMMapData() const { return _mmapData; } + + std::shared_ptr const GetStaticTreeSharedPtr() const { return _staticVMapData._staticTree; } + std::shared_ptr const GetMMapNavMeshSharedPtr() const { return _mmapData._navMesh; } + +private: + Map const& _map; + + DynamicVMapCollisionData _dynamicVMapData; + StaticVMapCollisionData _staticVMapData; + MMapData _mmapData; +}; + +#endif diff --git a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp index 5ddbc2c45..607428cb6 100644 --- a/src/server/game/Movement/MovementGenerators/PathGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PathGenerator.cpp @@ -20,7 +20,6 @@ #include "DetourCommon.h" #include "Geometry.h" #include "Log.h" -#include "MMapFactory.h" #include "MMapMgr.h" #include "Map.h" #include "Metric.h" @@ -34,12 +33,10 @@ PathGenerator::PathGenerator(WorldObject const* owner) : { memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs)); - uint32 mapId = _source->GetMapId(); //if (sDisableMgr->IsPathfindingEnabled(_sourceUnit->FindMap())) { - MMAP::MMapMgr* mmap = MMAP::MMapFactory::createOrGetMMapMgr(); - _navMesh = mmap->GetNavMesh(mapId); - _navMeshQuery = mmap->GetNavMeshQuery(mapId, _source->GetInstanceId()); + _navMesh = _source->GetMap()->GetMapCollisionData().GetMMapData().GetNavMesh(); + _navMeshQuery = _source->GetMap()->GetMapCollisionData().GetMMapData().GetNavMeshQuery(); } CreateFilter(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 4283d5a13..4830f5387 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1414,7 +1414,6 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici { float distance = m_spellInfo->Effects[effIndex].CalcRadius(m_caster); Map* map = m_caster->GetMap(); - uint32 mapid = m_caster->GetMapId(); uint32 phasemask = m_caster->GetPhaseMask(); float collisionHeight = m_caster->GetCollisionHeight(); float destz = 0.0f, startx = 0.0f, starty = 0.0f, startz = 0.0f, starto = 0.0f; @@ -1556,9 +1555,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici //LOG_ERROR("spells", "total path > than distance in 3D , need to move back a bit for save distance, total path = {}, overdistance = {}", totalpath, overdistance); } - bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); + bool col = m_caster->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos(prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); // check dynamic collision - bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); + bool dcol = m_caster->GetMap()->GetMapCollisionData().GetDynamicTree().GetObjectHitPos(phasemask, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f); // collision occured if (col || dcol || (overdistance > 0.0f && !map->IsInWater(phasemask, tstX, tstY, ground, collisionHeight)) || (fabs(prevZ - tstZ) > maxtravelDistZ && (tstZ > prevZ))) @@ -1620,9 +1619,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici else { float z = pos.GetPositionZ(); - bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f); + bool col = m_caster->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos(pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f); // check dynamic collision - bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f); + bool dcol = m_caster->GetMap()->GetMapCollisionData().GetDynamicTree().GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f); // collision occured if (col || dcol) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b11b77c60..2f87bbb00 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -60,7 +60,6 @@ #include "LootItemStorage.h" #include "LootMgr.h" #include "M2Stores.h" -#include "MMapFactory.h" #include "MapMgr.h" #include "Metric.h" #include "MotdMgr.h" @@ -139,7 +138,6 @@ World::~World() delete command; VMAP::VMapFactory::clear(); - MMAP::MMapFactory::clear(); } std::unique_ptr& getWorldInstance() @@ -284,9 +282,9 @@ void World::LoadConfigSettings(bool reload) } bool const enableIndoor = getBoolConfig(CONFIG_VMAP_INDOOR_CHECK); - bool const enableLOS = sConfigMgr->GetOption("vmap.enableLOS", true); + bool const enableLOS = getBoolConfig(CONFIG_VMAP_ENABLE_LOS); bool const enablePetLOS = getBoolConfig(CONFIG_PET_LOS); - bool const enableHeight = sConfigMgr->GetOption("vmap.enableHeight", true); + bool const enableHeight = getBoolConfig(CONFIG_VMAP_ENABLE_HEIGHT); if (!enableHeight) LOG_ERROR("server.loading", "VMap height checking disabled! Creatures movements and other various things WILL be broken! Expect no support."); @@ -294,8 +292,6 @@ void World::LoadConfigSettings(bool reload) VMAP::VMapFactory::createOrGetVMapMgr()->setEnableHeightCalc(enableHeight); LOG_INFO("server.loading", "WORLD: VMap support included. LineOfSight:{}, getHeight:{}, indoorCheck:{} PetLOS:{}", enableLOS, enableHeight, enableIndoor, enablePetLOS); - MMAP::MMapFactory::InitializeDisabledMaps(); - // call ScriptMgr if we're reloading the configuration sScriptMgr->OnAfterConfigLoad(reload); } @@ -392,17 +388,6 @@ void World::SetInitialWorldSettings() // Load IP Location Database sIPLocation->Load(); - std::vector mapIds; - for (auto const& map : sMapStore) - { - mapIds.emplace_back(map->MapID); - } - - vmmgr2->InitializeThreadUnsafe(mapIds); - - MMAP::MMapMgr* mmmgr = MMAP::MMapFactory::createOrGetMMapMgr(); - mmmgr->InitializeThreadUnsafe(mapIds); - LOG_INFO("server.loading", "Loading Game Graveyard..."); sGraveyard->LoadGraveyardFromDB(); diff --git a/src/server/game/World/WorldConfig.cpp b/src/server/game/World/WorldConfig.cpp index d754951d3..131f734ad 100644 --- a/src/server/game/World/WorldConfig.cpp +++ b/src/server/game/World/WorldConfig.cpp @@ -523,6 +523,8 @@ void WorldConfig::BuildConfigCache() SetConfigValue(CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT, "Respawn.DynamicMinimumGameObject", 10); SetConfigValue(CONFIG_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true); + SetConfigValue(CONFIG_VMAP_ENABLE_LOS, "vmap.enableLOS", true); + SetConfigValue(CONFIG_VMAP_ENABLE_HEIGHT, "vmap.enableHeight", true); SetConfigValue(CONFIG_PET_LOS, "vmap.petLOS", true); SetConfigValue(CONFIG_VMAP_BLIZZLIKE_PVP_LOS, "vmap.BlizzlikePvPLOS", true); diff --git a/src/server/game/World/WorldConfig.h b/src/server/game/World/WorldConfig.h index 6356e4111..9626be8bf 100644 --- a/src/server/game/World/WorldConfig.h +++ b/src/server/game/World/WorldConfig.h @@ -80,6 +80,8 @@ enum ServerConfigs CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN, CONFIG_CREATURE_REPOSITION_AGAINST_NPCS, CONFIG_VMAP_INDOOR_CHECK, + CONFIG_VMAP_ENABLE_LOS, + CONFIG_VMAP_ENABLE_HEIGHT, CONFIG_PET_LOS, CONFIG_START_CUSTOM_SPELLS, CONFIG_START_ALL_EXPLORED, diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index bfa883c25..bc7307086 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -36,7 +36,6 @@ #include "Language.h" #include "MapMgr.h" #include "MiscPackets.h" -#include "MMapFactory.h" #include "MovementGenerator.h" #include "ObjectAccessor.h" #include "Pet.h" @@ -630,7 +629,7 @@ public: uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0; uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0; - uint32 haveMMAP = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()) ? 1 : 0; + uint32 haveMMAP = handler->GetSession()->GetPlayer()->GetMap()->GetMapCollisionData().GetMMapData().GetNavMesh() ? 1 : 0; if (haveVMap) { diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index f41c9cb1e..91a164a11 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -28,7 +28,6 @@ #include "CommandScript.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" -#include "MMapFactory.h" #include "MMapMgr.h" #include "Map.h" #include "PathGenerator.h" @@ -62,7 +61,8 @@ public: static bool HandleMmapPathCommand(ChatHandler* handler, Optional param) { - if (!MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) + Map* map = handler->GetSession()->GetPlayer()->GetMap(); + if (!map->GetMapCollisionData().GetMMapData().GetNavMesh()) { handler->PSendSysMessage("NavMesh not loaded for current map."); return true; @@ -173,9 +173,11 @@ public: handler->PSendSysMessage("gridloc [{}, {}]", gridCoord.x_coord, gridCoord.y_coord); + Map* map = handler->GetSession()->GetPlayer()->GetMap(); + // calculate navmesh tile location - dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); - dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId()); + dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh(); + dtNavMeshQuery const* navmeshquery = map->GetMapCollisionData().GetMMapData().GetNavMeshQuery(); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); @@ -225,9 +227,9 @@ public: static bool HandleMmapLoadedTilesCommand(ChatHandler* handler) { - uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId(); - dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(mapid); - dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId()); + Map* map = handler->GetSession()->GetPlayer()->GetMap(); + dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh(); + dtNavMeshQuery const* navmeshquery = map->GetMapCollisionData().GetMMapData().GetNavMeshQuery(); if (!navmesh || !navmeshquery) { handler->PSendSysMessage("NavMesh not loaded for current map."); @@ -250,12 +252,14 @@ public: static bool HandleMmapStatsCommand(ChatHandler* handler) { - handler->PSendSysMessage("mmap stats:"); - //handler->PSendSysMessage(" global mmap pathfinding is {}abled", sDisableMgr->IsPathfindingEnabled(mapId) ? "en" : "dis"); - MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr(); - handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); + Map* map = handler->GetSession()->GetPlayer()->GetMap(); - dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); + //handler->PSendSysMessage("mmap stats:"); + //handler->PSendSysMessage(" global mmap pathfinding is {}abled", sDisableMgr->IsPathfindingEnabled(mapId) ? "en" : "dis"); + //MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr(); + //handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); + + dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh(); if (!navmesh) { handler->PSendSysMessage("NavMesh not loaded for current map."); diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp index d8fc79846..414d3467e 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp @@ -434,8 +434,7 @@ class spell_entropius_black_hole_effect : public SpellScript float targetX = baseX + maxDist * cos(angle); float targetY = baseY + maxDist * sin(angle); float hitX, hitY, hitZ; - if (VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos( - unit->GetMapId(), + if (unit->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos( baseX, baseY, z, targetX, targetY, z, hitX, hitY, hitZ, diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 6fb539b0f..c85a7933e 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -676,24 +676,20 @@ namespace MMAP /**************************************************************************/ bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData) { - IVMapMgr* vmapMgr = new VMapMgr2(); - int result = vmapMgr->loadMap(m_vmapsPath.c_str(), mapID, tileX, tileY); + std::string const mapFileName = VMapMgr2::getMapFileName(mapID); + std::unique_ptr staticTree = std::make_unique(mapID, m_vmapsPath); + if (!staticTree->InitMap(mapFileName)) + return false; + + staticTree->LoadMapTile(tileX, tileY); + bool retval = false; do { - if (result == VMAP_LOAD_RESULT_ERROR) - break; - - InstanceTreeMap instanceTrees; - ((VMapMgr2*)vmapMgr)->GetInstanceMapTree(instanceTrees); - - if (!instanceTrees[mapID]) - break; - ModelInstance* models = nullptr; uint32 count = 0; - instanceTrees[mapID]->GetModelInstances(models, count); + staticTree->GetModelInstances(models, count); if (!models) break; @@ -829,9 +825,6 @@ namespace MMAP } } while (false); - vmapMgr->unloadMap(mapID, tileX, tileY); - delete vmapMgr; - return retval; }