AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
VMAP::StaticMapTree Class Reference

#include "MapTree.h"

Public Member Functions

 StaticMapTree (uint32 mapID, const std::string &basePath)
 
 ~StaticMapTree ()
 Make sure to call unloadMap() to unregister acquired model references before destroying.
 
bool isInLineOfSight (const G3D::Vector3 &pos1, const G3D::Vector3 &pos2, ModelIgnoreFlags ignoreFlags) const
 
bool GetObjectHitPos (const G3D::Vector3 &pos1, const G3D::Vector3 &pos2, G3D::Vector3 &pResultHitPos, float pModifyDist) const
 
float getHeight (const G3D::Vector3 &pPos, float maxSearchDist) const
 
bool GetLocationInfo (const G3D::Vector3 &pos, LocationInfo &info) const
 
bool InitMap (const std::string &fname)
 
void UnloadMap ()
 
bool LoadMapTile (uint32 tileX, uint32 tileY)
 
void UnloadMapTile (uint32 tileX, uint32 tileY)
 
bool isTiled () const
 
uint32 numLoadedTiles () const
 
void GetModelInstances (ModelInstance *&models, uint32 &count)
 

Static Public Member Functions

static std::string getTileFileName (uint32 mapID, uint32 tileX, uint32 tileY)
 
static uint32 packTileID (uint32 tileX, uint32 tileY)
 
static void unpackTileID (uint32 ID, uint32 &tileX, uint32 &tileY)
 
static LoadResult CanLoadMap (const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY)
 

Private Types

typedef std::unordered_map< uint32, bool > loadedTileMap
 
typedef std::unordered_map< uint32, uint32loadedSpawnMap
 

Private Member Functions

bool GetIntersectionTime (const G3D::Ray &pRay, float &pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
 

Private Attributes

uint32 iMapID
 
bool iIsTiled
 
BIH iTree
 
ModelInstanceiTreeValues
 
uint32 iNTreeValues
 
loadedTileMap iLoadedTiles
 
std::string iBasePath
 

Detailed Description

Member Typedef Documentation

◆ loadedSpawnMap

typedef std::unordered_map<uint32, uint32> VMAP::StaticMapTree::loadedSpawnMap
private

◆ loadedTileMap

typedef std::unordered_map<uint32, bool> VMAP::StaticMapTree::loadedTileMap
private

Constructor & Destructor Documentation

◆ StaticMapTree()

VMAP::StaticMapTree::StaticMapTree ( uint32  mapID,
const std::string &  basePath 
)
95 : iMapID(mapID), iIsTiled(false), iTreeValues(0), iBasePath(basePath)
96 {
97 if (iBasePath.length() > 0 && iBasePath[iBasePath.length() - 1] != '/' && iBasePath[iBasePath.length() - 1] != '\\')
98 {
99 iBasePath.push_back('/');
100 }
101 }
uint32 iMapID
Definition MapTree.h:53
bool iIsTiled
Definition MapTree.h:54
std::string iBasePath
Definition MapTree.h:63
ModelInstance * iTreeValues
Definition MapTree.h:56

References iBasePath.

◆ ~StaticMapTree()

VMAP::StaticMapTree::~StaticMapTree ( )

Make sure to call unloadMap() to unregister acquired model references before destroying.

106 {
107 delete[] iTreeValues;
108 }

References iTreeValues.

Member Function Documentation

◆ CanLoadMap()

LoadResult VMAP::StaticMapTree::CanLoadMap ( const std::string &  basePath,
uint32  mapID,
uint32  tileX,
uint32  tileY 
)
static
217 {
218 std::string basePath = vmapPath;
219 if (basePath.length() > 0 && basePath[basePath.length() - 1] != '/' && basePath[basePath.length() - 1] != '\\')
220 {
221 basePath.push_back('/');
222 }
223 std::string fullname = basePath + VMapMgr2::getMapFileName(mapID);
224
226
227 FILE* rf = fopen(fullname.c_str(), "rb");
228 if (!rf)
229 {
231 }
232
233 char tiled;
234 char chunk[8];
235 if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1)
236 {
237 fclose(rf);
239 }
240 if (tiled)
241 {
242 std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
243 FILE* tf = fopen(tilefile.c_str(), "rb");
244 if (!tf)
245 {
247 }
248 else
249 {
250 if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
251 {
253 }
254 fclose(tf);
255 }
256 }
257 fclose(rf);
258 return result;
259 }
static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY)
Definition MapTree.cpp:77
static std::string getMapFileName(unsigned int mapId)
Definition VMapMgr2.cpp:53
bool readChunk(FILE *rf, char *dest, const char *compare, uint32 len)
Definition TileAssembler.cpp:40
LoadResult
Definition IVMapMgr.h:44
const char VMAP_MAGIC[]
Definition VMapDefinitions.h:25

References VMAP::FileNotFound, VMAP::VMapMgr2::getMapFileName(), getTileFileName(), VMAP::readChunk(), VMAP::Success, VMAP::VersionMismatch, and VMAP::VMAP_MAGIC.

Referenced by VMAP::VMapMgr2::existsMap().

◆ getHeight()

float VMAP::StaticMapTree::getHeight ( const G3D::Vector3 &  pPos,
float  maxSearchDist 
) const
202 {
203 float height = G3D::finf();
204 Vector3 dir = Vector3(0, 0, -1);
205 G3D::Ray ray(pPos, dir); // direction with length of 1
206 float maxDist = maxSearchDist;
207 if (GetIntersectionTime(ray, maxDist, false, ModelIgnoreFlags::Nothing))
208 {
209 height = pPos.z - maxDist;
210 }
211 return (height);
212 }
bool GetIntersectionTime(const G3D::Ray &pRay, float &pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
Definition MapTree.cpp:116

References GetIntersectionTime(), and VMAP::Nothing.

◆ GetIntersectionTime()

bool VMAP::StaticMapTree::GetIntersectionTime ( const G3D::Ray &  pRay,
float &  pMaxDist,
bool  StopAtFirstHit,
ModelIgnoreFlags  ignoreFlags 
) const
private

If intersection is found within pMaxDist, sets pMaxDist to intersection distance and returns true. Else, pMaxDist is not modified and returns false;

117 {
118 float distance = pMaxDist;
119 MapRayCallback intersectionCallBack(iTreeValues, ignoreFlags);
120 iTree.intersectRay(pRay, intersectionCallBack, distance, StopAtFirstHit);
121 if (intersectionCallBack.didHit())
122 {
123 pMaxDist = distance;
124 }
125 return intersectionCallBack.didHit();
126 }
void intersectRay(const G3D::Ray &r, RayCallback &intersectCallback, float &maxDist, bool stopAtFirstHit) const
Definition BoundingIntervalHierarchy.h:123
BIH iTree
Definition MapTree.h:55

References VMAP::MapRayCallback::didHit(), BIH::intersectRay(), iTree, and iTreeValues.

Referenced by getHeight(), GetObjectHitPos(), and isInLineOfSight().

◆ GetLocationInfo()

bool VMAP::StaticMapTree::GetLocationInfo ( const G3D::Vector3 &  pos,
LocationInfo info 
) const
88 {
89 LocationInfoCallback intersectionCallBack(iTreeValues, info);
90 iTree.intersectPoint(pos, intersectionCallBack);
91 return intersectionCallBack.result;
92 }
void intersectPoint(const G3D::Vector3 &p, IsectCallback &intersectCallback) const
Definition BoundingIntervalHierarchy.h:286

References BIH::intersectPoint(), iTree, iTreeValues, and VMAP::LocationInfoCallback::result.

◆ GetModelInstances()

void VMAP::StaticMapTree::GetModelInstances ( ModelInstance *&  models,
uint32 count 
)
438 {
439 models = iTreeValues;
440 count = iNTreeValues;
441 }
uint32 iNTreeValues
Definition MapTree.h:57

References iNTreeValues, and iTreeValues.

◆ GetObjectHitPos()

bool VMAP::StaticMapTree::GetObjectHitPos ( const G3D::Vector3 &  pos1,
const G3D::Vector3 &  pos2,
G3D::Vector3 &  pResultHitPos,
float  pModifyDist 
) const

When moving from pos1 to pos2 check if we hit an object. Return true and the position if we hit one Return the hit pos or the original dest pos

157 {
158 bool result = false;
159 float maxDist = (pPos2 - pPos1).magnitude();
160 // valid map coords should *never ever* produce float overflow, but this would produce NaNs too
161 ASSERT(maxDist < std::numeric_limits<float>::max());
162 // prevent NaN values which can cause BIH intersection to enter infinite loop
163 if (maxDist < 1e-10f)
164 {
165 pResultHitPos = pPos2;
166 return false;
167 }
168 Vector3 dir = (pPos2 - pPos1) / maxDist; // direction with length of 1
169 G3D::Ray ray(pPos1, dir);
170 float dist = maxDist;
171 if (GetIntersectionTime(ray, dist, false, ModelIgnoreFlags::Nothing))
172 {
173 pResultHitPos = pPos1 + dir * dist;
174 if (pModifyDist < 0)
175 {
176 if ((pResultHitPos - pPos1).magnitude() > -pModifyDist)
177 {
178 pResultHitPos = pResultHitPos + dir * pModifyDist;
179 }
180 else
181 {
182 pResultHitPos = pPos1;
183 }
184 }
185 else
186 {
187 pResultHitPos = pResultHitPos + dir * pModifyDist;
188 }
189 result = true;
190 }
191 else
192 {
193 pResultHitPos = pPos2;
194 result = false;
195 }
196 return result;
197 }
#define ASSERT
Definition Errors.h:68

References ASSERT, GetIntersectionTime(), and VMAP::Nothing.

◆ getTileFileName()

std::string VMAP::StaticMapTree::getTileFileName ( uint32  mapID,
uint32  tileX,
uint32  tileY 
)
static
78 {
79 std::stringstream tilefilename;
80 tilefilename.fill('0');
81 tilefilename << std::setw(3) << mapID << '_';
82 //tilefilename << std::setw(2) << tileX << '_' << std::setw(2) << tileY << ".vmtile";
83 tilefilename << std::setw(2) << tileY << '_' << std::setw(2) << tileX << ".vmtile";
84 return tilefilename.str();
85 }

Referenced by CanLoadMap(), and LoadMapTile().

◆ InitMap()

bool VMAP::StaticMapTree::InitMap ( const std::string &  fname)
264 {
265 //VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '{}'", fname);
266 bool success = false;
267 std::string fullname = iBasePath + fname;
268 FILE* rf = fopen(fullname.c_str(), "rb");
269 if (!rf)
270 {
271 return false;
272 }
273
274 char chunk[8];
275 char tiled = '\0';
276
277 if (readChunk(rf, chunk, VMAP_MAGIC, 8) && fread(&tiled, sizeof(char), 1, rf) == 1 &&
278 readChunk(rf, chunk, "NODE", 4) && iTree.readFromFile(rf))
279 {
281 iTreeValues = new ModelInstance[iNTreeValues];
282 success = readChunk(rf, chunk, "GOBJ", 4);
283 }
284
285 iIsTiled = bool(tiled);
286
287 // global model spawns
288 // only non-tiled maps have them, and if so exactly one (so far at least...)
289 ModelSpawn spawn;
290#ifdef VMAP_DEBUG
291 //LOG_DEBUG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : map isTiled: {}", static_cast<uint32>(iIsTiled));
292#endif
293 if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn))
294 {
295 std::shared_ptr<WorldModel> model = sWorldModelStore->AcquireModelInstance(iBasePath, spawn.name, spawn.flags);
296 //VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading {}", spawn.name);
297 if (model)
298 {
299 // assume that global model always is the first and only tree value (could be improved...)
300 iTreeValues[0] = ModelInstance(spawn, model);
301 }
302 else
303 {
304 success = false;
305 //VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '{}'", spawn.name);
306 }
307 }
308
309 fclose(rf);
310 return success;
311 }
#define sWorldModelStore
Definition WorldModelStore.h:44
uint32 primCount() const
Definition BoundingIntervalHierarchy.h:119
bool readFromFile(FILE *rf)
Definition BoundingIntervalHierarchy.cpp:287
static bool readFromFile(FILE *rf, ModelSpawn &spawn)
Definition ModelInstance.cpp:125

References VMAP::ModelSpawn::flags, iBasePath, iIsTiled, iNTreeValues, iTree, iTreeValues, VMAP::ModelSpawn::name, BIH::primCount(), VMAP::readChunk(), BIH::readFromFile(), VMAP::ModelSpawn::readFromFile(), sWorldModelStore, and VMAP::VMAP_MAGIC.

◆ isInLineOfSight()

bool VMAP::StaticMapTree::isInLineOfSight ( const G3D::Vector3 &  pos1,
const G3D::Vector3 &  pos2,
ModelIgnoreFlags  ignoreFlags 
) const
130 {
131 float maxDist = (pos2 - pos1).magnitude();
132 // return false if distance is over max float, in case of cheater teleporting to the end of the universe
133 if (maxDist == std::numeric_limits<float>::max() || !std::isfinite(maxDist))
134 {
135 return false;
136 }
137
138 // valid map coords should *never ever* produce float overflow, but this would produce NaNs too
139 ASSERT(maxDist < std::numeric_limits<float>::max());
140 // prevent NaN values which can cause BIH intersection to enter infinite loop
141 if (maxDist < 1e-10f)
142 {
143 return true;
144 }
145 // direction with length of 1
146 G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1) / maxDist);
147
148 return !GetIntersectionTime(ray, maxDist, true, ignoreFlags);
149 }

References ASSERT, and GetIntersectionTime().

◆ isTiled()

bool VMAP::StaticMapTree::isTiled ( ) const
inline
86{ return iIsTiled; }

References iIsTiled.

◆ LoadMapTile()

bool VMAP::StaticMapTree::LoadMapTile ( uint32  tileX,
uint32  tileY 
)
323 {
324 if (!iIsTiled)
325 {
326 // currently, core creates grids for all maps, whether it has terrain tiles or not
327 // so we need "fake" tile loads to know when we can unload map geometry
328 iLoadedTiles[packTileID(tileX, tileY)] = false;
329 return true;
330 }
331 if (!iTreeValues)
332 {
333 LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : tree has not been initialized [{}, {}]", tileX, tileY);
334 return false;
335 }
336 bool result = true;
337
338 std::string tilefile = iBasePath + getTileFileName(iMapID, tileX, tileY);
339 FILE* tf = fopen(tilefile.c_str(), "rb");
340 if (tf)
341 {
342 char chunk[8];
343
344 if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
345 {
346 result = false;
347 }
348 uint32 numSpawns = 0;
349 if (result && fread(&numSpawns, sizeof(uint32), 1, tf) != 1)
350 {
351 result = false;
352 }
353 for (uint32 i = 0; i < numSpawns && result; ++i)
354 {
355 // read model spawns
356 ModelSpawn spawn;
357 result = ModelSpawn::readFromFile(tf, spawn);
358 if (result)
359 {
360 // acquire model instance
361 std::shared_ptr<WorldModel> model = sWorldModelStore->AcquireModelInstance(iBasePath, spawn.name, spawn.flags);
362 if (!model)
363 {
364 LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [{}, {}]", tileX, tileY);
365 // why do we continue to try to load if the model was unsuccessful here?
366 }
367
368 // update tree
369 uint32 referencedVal;
370
371 if (fread(&referencedVal, sizeof(uint32), 1, tf) == 1)
372 {
373 if (referencedVal >= iNTreeValues)
374 {
375 LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : invalid tree element ({}/{})", referencedVal, iNTreeValues);
376 continue;
377 }
378
379 // This looks odd and is confusing, took some research to figure it out:
380 // the first WorldModel will create a "groupmodel" of all other same-models in the tile
381 // we don't actually care about anything else
382 if (!iTreeValues[referencedVal].getWorldModel())
383 {
384 iTreeValues[referencedVal] = ModelInstance(spawn, model);
385 }
386#if defined(VMAP_DEBUG)
387 else
388 {
389 if (iTreeValues[referencedVal].ID != spawn.ID)
390 {
391 LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : trying to load wrong spawn in node");
392 }
393 else if (iTreeValues[referencedVal].name != spawn.name)
394 {
395 LOG_DEBUG("maps", "StaticMapTree::LoadMapTile() : name collision on GUID={}", spawn.ID);
396 }
397 }
398#endif
399 }
400 else
401 {
402 result = false;
403 }
404 }
405 }
406 iLoadedTiles[packTileID(tileX, tileY)] = true;
407 fclose(tf);
408 }
409 else
410 {
411 iLoadedTiles[packTileID(tileX, tileY)] = false;
412 }
413
414 METRIC_EVENT("map_events", "LoadMapTile",
415 "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY));
416
417 return result;
418 }
std::uint32_t uint32
Definition Define.h:107
#define LOG_ERROR(filterType__,...)
Definition Log.h:158
#define LOG_DEBUG(filterType__,...)
Definition Log.h:170
#define METRIC_EVENT(category, title, description)
Definition Metric.h:189
std::string name
Definition ModelInstance.h:53
uint32 ID
Definition ModelInstance.h:48
static uint32 packTileID(uint32 tileX, uint32 tileY)
Definition MapTree.h:70
loadedTileMap iLoadedTiles
Definition MapTree.h:62

References VMAP::ModelSpawn::flags, getTileFileName(), iBasePath, VMAP::ModelSpawn::ID, iIsTiled, iLoadedTiles, iMapID, iNTreeValues, iTreeValues, LOG_DEBUG, LOG_ERROR, METRIC_EVENT, VMAP::ModelSpawn::name, packTileID(), VMAP::readChunk(), VMAP::ModelSpawn::readFromFile(), sWorldModelStore, and VMAP::VMAP_MAGIC.

◆ numLoadedTiles()

uint32 VMAP::StaticMapTree::numLoadedTiles ( ) const
inline
87{ return iLoadedTiles.size(); }

References iLoadedTiles.

◆ packTileID()

static uint32 VMAP::StaticMapTree::packTileID ( uint32  tileX,
uint32  tileY 
)
inlinestatic

◆ UnloadMap()

void VMAP::StaticMapTree::UnloadMap ( )
316 {
317 iLoadedTiles.clear();
318 }

References iLoadedTiles.

◆ UnloadMapTile()

void VMAP::StaticMapTree::UnloadMapTile ( uint32  tileX,
uint32  tileY 
)
423 {
424 uint32 tileID = packTileID(tileX, tileY);
425 loadedTileMap::iterator tile = iLoadedTiles.find(tileID);
426 if (tile == iLoadedTiles.end())
427 {
428 LOG_ERROR("maps", "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:{} X:{} Y:{}", iMapID, tileX, tileY);
429 return;
430 }
431 iLoadedTiles.erase(tile);
432
433 METRIC_EVENT("map_events", "UnloadMapTile",
434 "Map: " + std::to_string(iMapID) + " TileX: " + std::to_string(tileX) + " TileY: " + std::to_string(tileY));
435 }

References iLoadedTiles, iMapID, LOG_ERROR, METRIC_EVENT, and packTileID().

◆ unpackTileID()

static void VMAP::StaticMapTree::unpackTileID ( uint32  ID,
uint32 tileX,
uint32 tileY 
)
inlinestatic
71{ tileX = ID >> 16; tileY = ID & 0xFF; }

Referenced by MMAP::MapBuilder::buildMap(), MMAP::MapBuilder::buildNavMesh(), and VMAP::TileAssembler::convertWorld2().

Member Data Documentation

◆ iBasePath

std::string VMAP::StaticMapTree::iBasePath
private

Referenced by InitMap(), LoadMapTile(), and StaticMapTree().

◆ iIsTiled

bool VMAP::StaticMapTree::iIsTiled
private

Referenced by InitMap(), isTiled(), and LoadMapTile().

◆ iLoadedTiles

loadedTileMap VMAP::StaticMapTree::iLoadedTiles
private

◆ iMapID

uint32 VMAP::StaticMapTree::iMapID
private

Referenced by LoadMapTile(), and UnloadMapTile().

◆ iNTreeValues

uint32 VMAP::StaticMapTree::iNTreeValues
private

◆ iTree

BIH VMAP::StaticMapTree::iTree
private

◆ iTreeValues

ModelInstance* VMAP::StaticMapTree::iTreeValues
private

The documentation for this class was generated from the following files: