refactor(Core/Collision): Store collision data on map context (#25049)
This commit is contained in:
parent
80b6984274
commit
27b0ecc6dc
32 changed files with 527 additions and 992 deletions
|
|
@ -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<uint8> reqLiquidType, AreaAndLiquidData& data) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MMapFactory.h"
|
||||
#include <cstring>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
|
|
@ -24,63 +24,8 @@
|
|||
namespace MMAP
|
||||
{
|
||||
// ######################## MMapMgr ########################
|
||||
MMapMgr::~MMapMgr()
|
||||
std::shared_ptr<dtNavMesh> 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<uint32>& 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<std::string>("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<dtNavMesh> navMesh = std::shared_ptr<dtNavMesh>(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<std::string>("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<uint32, dtTileRef>(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<uint32, dtNavMeshQuery*>(instanceId, query));
|
||||
}
|
||||
}
|
||||
|
||||
return mmap->navMeshQueries[instanceId];
|
||||
ManagedNavMeshQuery navMeshQuery = ManagedNavMeshQuery(query);
|
||||
return navMeshQuery;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@
|
|||
#include "DetourAlloc.h"
|
||||
#include "DetourExtended.h"
|
||||
#include "DetourNavMesh.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
// 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<uint32, dtTileRef> MMapTileSet;
|
||||
typedef std::unordered_map<uint32, dtNavMeshQuery*> 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<uint32, MMapData*> MMapDataSet;
|
||||
struct NavMeshQueryDeleter
|
||||
{
|
||||
void operator()(dtNavMeshQuery* query) noexcept { dtFreeNavMeshQuery(query); }
|
||||
};
|
||||
|
||||
using ManagedNavMeshQuery = std::unique_ptr<dtNavMeshQuery, NavMeshQueryDeleter>;
|
||||
|
||||
// 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<uint32>& 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<dtNavMesh> 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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <G3D/Vector3.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
|
@ -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<uint32>& 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<uint8> 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<std::mutex> 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<std::string, ManagedModel>(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<std::mutex> 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
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@
|
|||
#define _VMAPMANAGER2_H
|
||||
|
||||
#include "IVMapMgr.h"
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
//===========================================================
|
||||
|
||||
|
|
@ -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<uint32, StaticMapTree*> InstanceTreeMap;
|
||||
typedef std::unordered_map<std::string, ManagedModel> 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<uint32>& 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<uint8> 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;
|
||||
|
|
|
|||
43
src/common/Collision/Management/WorldModelStore.cpp
Normal file
43
src/common/Collision/Management/WorldModelStore.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "WorldModelStore.h"
|
||||
|
||||
std::shared_ptr<VMAP::WorldModel> 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<std::mutex> lock(_lock);
|
||||
|
||||
ModelFileMap::iterator model = _loadedModels.find(filename);
|
||||
if (model == _loadedModels.end())
|
||||
{
|
||||
std::shared_ptr<VMAP::WorldModel> worldmodel = std::make_shared<VMAP::WorldModel>();
|
||||
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<std::string, std::shared_ptr<VMAP::WorldModel>>(filename, worldmodel)).first;
|
||||
}
|
||||
|
||||
return model->second;
|
||||
}
|
||||
|
|
@ -15,32 +15,32 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _IMMAPMANAGER_H
|
||||
#define _IMMAPMANAGER_H
|
||||
#ifndef _WORLDMODELSTORE_H
|
||||
#define _WORLDMODELSTORE_H
|
||||
|
||||
// Interface for IMMapManger
|
||||
namespace MMAP
|
||||
#include "WorldModel.h"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
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<VMAP::WorldModel> AcquireModelInstance(std::string const& basepath, std::string const& filename, uint32 flags);
|
||||
|
||||
public:
|
||||
IMMapMgr() : iEnablePathFinding(true) {}
|
||||
virtual ~IMMapMgr(void) {}
|
||||
private:
|
||||
typedef std::unordered_map<std::string, std::shared_ptr<VMAP::WorldModel>> 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
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include "ModelInstance.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "VMapMgr2.h"
|
||||
#include "WorldModelStore.h"
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
|
@ -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<WorldModel> 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<WorldModel> 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",
|
||||
|
|
|
|||
|
|
@ -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 <tree_index, reference_count> 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);
|
||||
|
|
|
|||
|
|
@ -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<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath)
|
||||
{
|
||||
ModelList::const_iterator it = model_list.find(modelOwner->GetDisplayId());
|
||||
|
|
@ -125,7 +118,7 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> 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)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <G3D/Matrix3.h>
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Vector3.h>
|
||||
#include <memory>
|
||||
|
||||
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<VMAP::WorldModel> iModel;
|
||||
std::unique_ptr<GameObjectModelOwnerBase> owner;
|
||||
bool isWmo{false};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<WorldModel> 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;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <G3D/Matrix3.h>
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Vector3.h>
|
||||
#include <memory>
|
||||
|
||||
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<WorldModel> 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<WorldModel> iModel;
|
||||
};
|
||||
} // namespace VMAP
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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*>(_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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*>(_map->GetParent());
|
||||
parentMap->EnsureGridCreated(GridCoord(x, y));
|
||||
}
|
||||
|
||||
std::unique_ptr<MapGridType> grid = std::make_unique<MapGridType>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<GridTerrainData> 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<float>(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);
|
||||
|
|
|
|||
|
|
@ -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<std::shared_mutex*>(&MMapLock)); }
|
||||
// pussywizard:
|
||||
std::unordered_set<Unit*> 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<class T> 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;
|
||||
|
|
|
|||
183
src/server/game/Maps/MapCollisionData.cpp
Normal file
183
src/server/game/Maps/MapCollisionData.cpp
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <G3D/Vector3.h>
|
||||
|
||||
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<VMAP::StaticMapTree> newTree = std::make_shared<VMAP::StaticMapTree>(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<uint8> 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();
|
||||
}
|
||||
100
src/server/game/Maps/MapCollisionData.h
Normal file
100
src/server/game/Maps/MapCollisionData.h
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<uint8> 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<VMAP::StaticMapTree> _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<dtNavMesh> _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<VMAP::StaticMapTree> const GetStaticTreeSharedPtr() const { return _staticVMapData._staticTree; }
|
||||
std::shared_ptr<dtNavMesh> const GetMMapNavMeshSharedPtr() const { return _mmapData._navMesh; }
|
||||
|
||||
private:
|
||||
Map const& _map;
|
||||
|
||||
DynamicVMapCollisionData _dynamicVMapData;
|
||||
StaticVMapCollisionData _staticVMapData;
|
||||
MMapData _mmapData;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<IWorld>& getWorldInstance()
|
||||
|
|
@ -284,9 +282,9 @@ void World::LoadConfigSettings(bool reload)
|
|||
}
|
||||
|
||||
bool const enableIndoor = getBoolConfig(CONFIG_VMAP_INDOOR_CHECK);
|
||||
bool const enableLOS = sConfigMgr->GetOption<bool>("vmap.enableLOS", true);
|
||||
bool const enableLOS = getBoolConfig(CONFIG_VMAP_ENABLE_LOS);
|
||||
bool const enablePetLOS = getBoolConfig(CONFIG_PET_LOS);
|
||||
bool const enableHeight = sConfigMgr->GetOption<bool>("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<uint32> 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -523,6 +523,8 @@ void WorldConfig::BuildConfigCache()
|
|||
SetConfigValue<uint32>(CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT, "Respawn.DynamicMinimumGameObject", 10);
|
||||
|
||||
SetConfigValue<bool>(CONFIG_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true);
|
||||
SetConfigValue<bool>(CONFIG_VMAP_ENABLE_LOS, "vmap.enableLOS", true);
|
||||
SetConfigValue<bool>(CONFIG_VMAP_ENABLE_HEIGHT, "vmap.enableHeight", true);
|
||||
SetConfigValue<bool>(CONFIG_PET_LOS, "vmap.petLOS", true);
|
||||
|
||||
SetConfigValue<bool>(CONFIG_VMAP_BLIZZLIKE_PVP_LOS, "vmap.BlizzlikePvPLOS", true);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<std::string> 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.");
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<StaticMapTree> staticTree = std::make_unique<StaticMapTree>(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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue