TrinityCore
Loading...
Searching...
No Matches
MapBuilder.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "MapBuilder.h"
19#include "Log.h"
20#include "MapDefines.h"
21#include "MapTree.h"
22#include "MapUtils.h"
23#include "Memory.h"
24#include "MMapDefines.h"
25#include "PathCommon.h"
26#include "StringConvert.h"
27#include "StringFormat.h"
28#include <boost/filesystem/directory.hpp>
29
31{
32static boost::filesystem::path tilelist = ".tilelist";
33static boost::filesystem::path vmtile = ".vmtile";
34}
35
36namespace MMAP
37{
38 MapTileBuilder::MapTileBuilder(MapBuilder* mapBuilder, Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
39 bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector<OffMeshData> const* offMeshConnections) :
40 TileBuilder(mapBuilder->m_inputDirectory, mapBuilder->m_outputDirectory, maxWalkableAngle, maxWalkableAngleNotSteep, skipLiquid, bigBaseUnit, debugOutput, offMeshConnections),
41 m_mapBuilder(mapBuilder),
42 m_workerThread(&MapTileBuilder::WorkerThread, this)
43 {
44 }
45
50
52 {
53 if (m_workerThread.joinable())
54 m_workerThread.join();
55 }
56
61
62 MapBuilder::MapBuilder(boost::filesystem::path const& inputDirectory, boost::filesystem::path const& outputDirectory,
63 Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
64 bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
65 bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath, unsigned int threads) :
66 m_inputDirectory (inputDirectory),
67 m_outputDirectory (outputDirectory),
68 m_debugOutput (debugOutput),
69 m_threads (threads),
70 m_skipContinents (skipContinents),
71 m_skipJunkMaps (skipJunkMaps),
72 m_skipBattlegrounds (skipBattlegrounds),
73 m_skipLiquid (skipLiquid),
74 m_maxWalkableAngle (maxWalkableAngle),
75 m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep),
76 m_bigBaseUnit (bigBaseUnit),
77 m_mapid (mapid),
78 m_totalTiles (0u),
79 m_totalTilesProcessed(0u),
80 _cancelationToken (false)
81 {
82
83 // At least 1 thread is needed
84 m_threads = std::max(1u, m_threads);
85
87
88 ParseOffMeshConnectionsFile(offMeshFilePath);
89 }
90
91 /**************************************************************************/
93 {
94 _cancelationToken = true;
95
96 _queue.Cancel();
97
98 m_tileBuilders.clear();
99 m_tiles.clear();
100 }
101
102 /**************************************************************************/
104 {
105 boost::filesystem::directory_iterator end;
106 for (auto itr = boost::filesystem::directory_iterator(m_inputDirectory / "maps"); itr != end; ++itr)
107 {
108 if (!boost::filesystem::is_regular_file(*itr))
109 continue;
110
111 if (itr->path().extension() != FileExtensions::tilelist)
112 continue;
113
114 Optional<uint32> mapId = Trinity::StringTo<uint32>(std::string_view(itr->path().filename().string()).substr(0, 4));
115 if (!mapId)
116 continue;
117
118 if (shouldSkipMap(*mapId))
119 continue;
120
121 if (auto tileList = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(itr->path().string().c_str(), "rb")))
122 {
123 u_map_magic mapMagic = { };
124 uint32 versionMagic = { };
125 uint32 build;
126 char tilesData[64 * 64] = { };
127 if (fread(mapMagic.data(), mapMagic.size(), 1, tileList.get()) == 1
128 && mapMagic == MapMagic
129 && fread(&versionMagic, sizeof(versionMagic), 1, tileList.get()) == 1
130 && versionMagic == MapVersionMagic
131 && fread(&build, sizeof(build), 1, tileList.get()) == 1
132 && fread(std::data(tilesData), std::size(tilesData), 1, tileList.get()) == 1)
133 {
135 for (uint32 tileX = 0; tileX < 64; ++tileX)
136 for (uint32 tileY = 0; tileY < 64; ++tileY)
137 if (tilesData[std::size(tilesData) - 1 - (tileX * 64 + tileY)] == '1')
138 if (tiles.insert(VMAP::StaticMapTree::packTileID(tileX, tileY)).second)
139 ++m_totalTiles;
140 }
141 }
142 }
143
144 for (auto itr = boost::filesystem::directory_iterator(m_inputDirectory / "vmaps"); itr != end; ++itr)
145 {
146 if (!boost::filesystem::is_directory(*itr))
147 continue;
148
149 Optional<uint32> mapId = Trinity::StringTo<uint32>(itr->path().filename().string());
150 if (!mapId)
151 continue;
152
153 if (shouldSkipMap(*mapId))
154 continue;
155
157 for (auto fileItr = boost::filesystem::directory_iterator(*itr); fileItr != end; ++fileItr)
158 {
159 if (!boost::filesystem::is_regular_file(*fileItr))
160 continue;
161
162 if (fileItr->path().extension() != FileExtensions::vmtile)
163 continue;
164
165 std::string fileName = fileItr->path().filename().string();
166
167 uint32 tileX = Trinity::StringTo<uint32>(std::string_view(fileName).substr(5, 2)).value_or(0);
168 uint32 tileY = Trinity::StringTo<uint32>(std::string_view(fileName).substr(8, 2)).value_or(0);
169 uint32 tileID = VMAP::StaticMapTree::packTileID(tileX, tileY);
170
171 if (tiles.insert(tileID).second)
172 ++m_totalTiles;
173 }
174 }
175
176 TC_LOG_INFO("maps.mmapgen", "Discovering maps... found {}.", m_tiles.size());
177 TC_LOG_INFO("maps.mmapgen", "Discovering tiles... found {}.\n", m_totalTiles);
178 }
179
180 /**************************************************************************/
181 void MapBuilder::ParseOffMeshConnectionsFile(char const* offMeshFilePath)
182 {
183 // no meshfile input given?
184 if (offMeshFilePath == nullptr)
185 return;
186
187 auto fp = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(offMeshFilePath, "rb"));
188 if (!fp)
189 {
190 TC_LOG_ERROR("maps.mmapgen", "MapBuilder::loadOffMeshConnections:: input file {} not found!", offMeshFilePath);
191 return;
192 }
193
194 char buf[512] = { };
195 while (fgets(buf, 512, fp.get()))
196 {
197 OffMeshData offMesh;
198 int32 scanned = sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f %hhu %hu", &offMesh.MapId, &offMesh.TileX, &offMesh.TileY,
199 &offMesh.From[0], &offMesh.From[1], &offMesh.From[2], &offMesh.To[0], &offMesh.To[1], &offMesh.To[2],
200 &offMesh.Radius, &offMesh.AreaId, reinterpret_cast<std::underlying_type_t<NavTerrainFlag>*>(&offMesh.Flags));
201 if (scanned < 10)
202 continue;
203
205 if (scanned < 12)
206 offMesh.Flags = NAV_GROUND;
207
208 if (scanned < 11)
209 offMesh.AreaId = NAV_AREA_GROUND;
210
211 m_offMeshConnections.push_back(offMesh);
212 }
213 }
214
215 /**************************************************************************/
216 std::span<uint32 const> MapBuilder::getTileList(uint32 mapID) const
217 {
219 return *tiles;
220
221 return { };
222 }
223
224 /**************************************************************************/
225
227 {
228 while (true)
229 {
230 TileInfo tileInfo;
231
232 m_mapBuilder->_queue.WaitAndPop(tileInfo);
233
235 return;
236
237 dtNavMesh* navMesh = dtAllocNavMesh();
238 if (!navMesh->init(&tileInfo.m_navMeshParams))
239 {
240 TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh for tile {},{} !", tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY);
241 dtFreeNavMesh(navMesh);
242 return;
243 }
244
245 buildTile(tileInfo.m_mapId, tileInfo.m_tileX, tileInfo.m_tileY, navMesh);
246
247 dtFreeNavMesh(navMesh);
248 }
249 }
250
252 {
253 TC_LOG_INFO("maps.mmapgen", "Using {} threads to generate mmaps", m_threads);
254
256 for (unsigned int i = 0; i < m_threads; ++i)
259
260 if (mapID)
261 {
262 buildMap(*mapID);
263 }
264 else
265 {
266 // Build all maps if no map id has been specified
267 for (auto& [mapId, _] : m_tiles)
268 buildMap(mapId);
269 }
270
271 while (!_queue.Empty())
272 {
273 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
274 }
275
276 _cancelationToken = true;
277
278 _queue.Cancel();
279
280 m_tileBuilders.clear();
281 }
282
283 /**************************************************************************/
284 void MapBuilder::buildMeshFromFile(char const* name)
285 {
286 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(name, "rb"));
287 if (!file)
288 return;
289
290 TC_LOG_INFO("maps.mmapgen", "Building mesh from file");
291 int tileX, tileY, mapId;
292 if (fread(&mapId, sizeof(int), 1, file.get()) != 1)
293 return;
294
295 if (fread(&tileX, sizeof(int), 1, file.get()) != 1)
296 return;
297
298 if (fread(&tileY, sizeof(int), 1, file.get()) != 1)
299 return;
300
301 dtNavMesh* navMesh = nullptr;
302 buildNavMesh(mapId, navMesh);
303 if (!navMesh)
304 {
305 TC_LOG_ERROR("maps.mmapgen", "Failed creating navmesh!");
306 return;
307 }
308
309 uint32 verticesCount, indicesCount;
310 if (fread(&verticesCount, sizeof(uint32), 1, file.get()) != 1)
311 return;
312
313 if (fread(&indicesCount, sizeof(uint32), 1, file.get()) != 1)
314 return;
315
316 MeshData data;
317
318 data.solidVerts.resize(verticesCount);
319 if (fread(data.solidVerts.data(), sizeof(float), verticesCount, file.get()) != verticesCount)
320 return;
321
322 data.solidTris.resize(indicesCount);
323 if (fread(data.solidTris.data(), sizeof(int), indicesCount, file.get()) != indicesCount)
324 return;
325
327 // get bounds of current tile
328 float bmin[3], bmax[3];
329 TileBuilder::getTileBounds(tileX, tileY, data.solidVerts.data(), data.solidVerts.size() / 3, bmin, bmax);
330
331 // build navmesh tile
334 TileBuilder::TileResult tileResult = tileBuilder.buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh->getParams());
335 if (tileResult.data)
336 tileBuilder.saveMoveMapTileToFile(mapId, tileX, tileY, navMesh, tileResult);
337 }
338
339 /**************************************************************************/
341 {
342 dtNavMesh* navMesh = nullptr;
343 buildNavMesh(mapID, navMesh);
344 if (!navMesh)
345 {
346 TC_LOG_ERROR("maps.mmapgen", "Failed creating navmesh!");
347 return;
348 }
349
350 // ToDo: delete the old tile as the user clearly wants to rebuild it
351
354 tileBuilder.buildTile(mapID, tileX, tileY, navMesh);
355 dtFreeNavMesh(navMesh);
356
357 _cancelationToken = true;
358
359 _queue.Cancel();
360 }
361
362 /**************************************************************************/
364 {
365 std::span<uint32 const> tiles = getTileList(mapID);
366
367 if (!tiles.empty())
368 {
369 // build navMesh
370 dtNavMesh* navMesh = nullptr;
371 buildNavMesh(mapID, navMesh);
372 if (!navMesh)
373 {
374 TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh!", mapID);
375 m_totalTilesProcessed += tiles.size();
376 return;
377 }
378
379 // now start building mmtiles for each tile
380 TC_LOG_INFO("maps.mmapgen", "[Map {:04}] We have {} tiles.", mapID, tiles.size());
381 for (uint32 packedTile : tiles)
382 {
383 uint32 tileX, tileY;
384
385 // unpack tile coords
386 VMAP::StaticMapTree::unpackTileID(packedTile, tileX, tileY);
387
388 TileInfo tileInfo;
389 tileInfo.m_mapId = mapID;
390 tileInfo.m_tileX = tileX;
391 tileInfo.m_tileY = tileY;
392 memcpy(&tileInfo.m_navMeshParams, navMesh->getParams(), sizeof(dtNavMeshParams));
393 _queue.Push(tileInfo);
394 }
395
396 dtFreeNavMesh(navMesh);
397 }
398 }
399
400 /**************************************************************************/
401 void MapBuilder::buildNavMesh(uint32 mapID, dtNavMesh* &navMesh)
402 {
403 // if map has a parent we use that to generate dtNavMeshParams - worldserver will load all missing tiles from that map
404 int32 navMeshParamsMapId = mapID;
405 int32 parentMapId = sMapStore[mapID].ParentMapID;
406 while (parentMapId != -1)
407 {
408 navMeshParamsMapId = parentMapId;
409 parentMapId = sMapStore[parentMapId].ParentMapID;
410 }
411
412 std::span<uint32 const> tiles = getTileList(navMeshParamsMapId);
413
414 // old code for non-statically assigned bitmask sizes:
416 //int tileBits = dtIlog2(dtNextPow2(tiles->size()));
417 //if (tileBits < 1) tileBits = 1; // need at least one bit!
418 //int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits;
419
420 int polyBits = DT_POLY_BITS;
421
422 int maxTiles = tiles.size();
423 int maxPolysPerTile = 1 << polyBits;
424
425 /*** calculate bounds of map ***/
426
427 uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
428 for (uint32 packedTile : tiles)
429 {
430 VMAP::StaticMapTree::unpackTileID(packedTile, tileX, tileY);
431
432 if (tileX > tileXMax)
433 tileXMax = tileX;
434 else if (tileX < tileXMin)
435 tileXMin = tileX;
436
437 if (tileY > tileYMax)
438 tileYMax = tileY;
439 else if (tileY < tileYMin)
440 tileYMin = tileY;
441 }
442
443 // use Max because '32 - tileX' is negative for values over 32
444 float bmin[3], bmax[3];
445 TileBuilder::getTileBounds(tileXMax, tileYMax, nullptr, 0, bmin, bmax);
446
447 /*** now create the navmesh ***/
448
449 // navmesh creation params
450 MmapNavMeshHeader fileHeader;
451 fileHeader.params.tileWidth = GRID_SIZE;
452 fileHeader.params.tileHeight = GRID_SIZE;
453 rcVcopy(fileHeader.params.orig, bmin);
454 fileHeader.params.maxTiles = maxTiles;
455 fileHeader.params.maxPolys = maxPolysPerTile;
456
457 navMesh = dtAllocNavMesh();
458 TC_LOG_INFO("maps.mmapgen", "[Map {:04}] Creating navMesh...", mapID);
459 if (!navMesh->init(&fileHeader.params))
460 {
461 TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh!", mapID);
462 return;
463 }
464
465 std::string fileName = Trinity::StringFormat("{}/mmaps/{:04}.mmap", m_outputDirectory.generic_string(), mapID);
466
467 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb"));
468 if (!file)
469 {
470 dtFreeNavMesh(navMesh);
471 navMesh = nullptr;
472 TC_LOG_ERROR("maps.mmapgen", "{}: [Map {:04}] Failed to open {} for writing!\n", strerror(errno), mapID, fileName);
473 return;
474 }
475
476 std::vector<OffMeshData> offMeshConnections;
477 std::ranges::copy_if(m_offMeshConnections, std::back_inserter(offMeshConnections), [mapID](OffMeshData const& offMeshData) { return offMeshData.MapId == mapID; });
478
479 fileHeader.offmeshConnectionCount = offMeshConnections.size();
480
481 // now that we know navMesh params are valid, we can write them to file
482 fwrite(&fileHeader, sizeof(MmapNavMeshHeader), 1, file.get());
483 fwrite(offMeshConnections.data(), sizeof(OffMeshData), offMeshConnections.size(), file.get());
484 }
485
486 /**************************************************************************/
488 {
489 if (m_mapid >= 0)
490 {
491 int32 parentMapId = m_mapid;
492 do
493 {
494 if (static_cast<uint32>(parentMapId) == mapID)
495 return false;
496
497 parentMapId = sMapStore[parentMapId].ParentMapID;
498
499 } while (parentMapId != -1);
500
501 return true;
502 }
503
505 if (isContinentMap(mapID))
506 return true;
507
508 if (m_skipJunkMaps)
509 {
510 if (isDevMap(mapID))
511 return true;
512
513 if (isTransportMap(mapID))
514 return true;
515 }
516
518 {
519 if (isBattlegroundMap(mapID))
520 return true;
521 }
522
523 return false;
524 }
525
526 /**************************************************************************/
528 {
530 return map->MapType == 3;
531
532 return false;
533 }
534
535 bool MapBuilder::isDevMap(uint32 mapID) const
536 {
538 return (map->Flags & 0x2) != 0;
539
540 return false;
541 }
542
544 {
546 return map->InstanceType == 3;
547
548 return false;
549 }
550
552 {
553 switch (mapID)
554 {
555 case 0:
556 case 1:
557 case 530:
558 case 571:
559 case 870:
560 case 1116:
561 case 1220:
562 case 1642:
563 case 1643:
564 case 2222:
565 return true;
566 default:
567 return false;
568 }
569 }
570
571 /**************************************************************************/
572 bool MapTileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
573 {
574 std::string fileName = Trinity::StringFormat("{}/mmaps/{:04}_{:02}_{:02}.mmtile", m_outputDirectory.generic_string(), mapID, tileX, tileY);
575 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "rb"));
576 if (!file)
577 return false;
578
579 MmapTileHeader header;
580 int count = fread(&header, sizeof(MmapTileHeader), 1, file.get());
581 if (count != 1)
582 return false;
583
584 if (header.mmapMagic != MMAP_MAGIC || header.dtVersion != uint32(DT_NAVMESH_VERSION))
585 return false;
586
587 if (header.mmapVersion != MMAP_VERSION)
588 return false;
589
590 return TileBuilder::shouldSkipTile(mapID, tileX, tileY);
591 }
592
594 {
596 }
597
598 /**************************************************************************/
599 uint32 MapBuilder::percentageDone(uint32 totalTiles, uint32 totalTilesBuilt) const
600 {
601 if (totalTiles)
602 return totalTilesBuilt * 100 / totalTiles;
603
604 return 0;
605 }
606
611
612}
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
@ NAV_AREA_GROUND
Definition MMapDefines.h:61
uint32 constexpr MMAP_VERSION
Definition MMapDefines.h:25
@ OFFMESH_CONNECTION_FLAG_BIDIRECTIONAL
Definition MMapDefines.h:81
uint32 constexpr MMAP_MAGIC
Definition MMapDefines.h:24
@ NAV_GROUND
Definition MMapDefines.h:73
uint32 const MapVersionMagic
u_map_magic const MapMagic
std::array< char, 4 > u_map_magic
Represents a map magic value of 4 bytes (used in versions)
Definition MapDefines.h:27
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
void buildMeshFromFile(char const *name)
std::vector< OffMeshData > m_offMeshConnections
Definition MapBuilder.h:132
void ParseOffMeshConnectionsFile(char const *offMeshFilePath)
void buildMaps(Optional< uint32 > mapID)
ProducerConsumerQueue< TileInfo > _queue
Definition MapBuilder.h:149
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const
bool isDevMap(uint32 mapID) const
Optional< float > m_maxWalkableAngleNotSteep
Definition MapBuilder.h:140
MapBuilder(boost::filesystem::path const &inputDirectory, boost::filesystem::path const &outputDirectory, Optional< float > maxWalkableAngle, Optional< float > maxWalkableAngleNotSteep, bool skipLiquid, bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds, bool debugOutput, bool bigBaseUnit, int mapid, char const *offMeshFilePath, unsigned int threads)
uint32 currentPercentageDone() const
void buildNavMesh(uint32 mapID, dtNavMesh *&navMesh)
bool shouldSkipMap(uint32 mapID) const
boost::filesystem::path m_outputDirectory
Definition MapBuilder.h:129
bool isTransportMap(uint32 mapID) const
Optional< float > m_maxWalkableAngle
Definition MapBuilder.h:139
std::atomic< bool > _cancelationToken
Definition MapBuilder.h:150
bool isContinentMap(uint32 mapID) const
boost::filesystem::path m_inputDirectory
Definition MapBuilder.h:128
void buildMap(uint32 mapID)
std::atomic< uint32 > m_totalTilesProcessed
Definition MapBuilder.h:146
friend class MapTileBuilder
Definition MapBuilder.h:79
std::span< uint32 const > getTileList(uint32 mapID) const
bool isBattlegroundMap(uint32 mapID) const
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
unsigned int m_threads
Definition MapBuilder.h:133
std::vector< std::unique_ptr< TileBuilder > > m_tileBuilders
Definition MapBuilder.h:148
MapBuilder * m_mapBuilder
Definition MapBuilder.h:72
std::thread m_workerThread
Definition MapBuilder.h:73
std::string GetProgressText() const override
void OnTileDone() override
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const override
MapTileBuilder(MapBuilder *mapBuilder, Optional< float > maxWalkableAngle, Optional< float > maxWalkableAngleNotSteep, bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector< OffMeshData > const *offMeshConnections)
static void cleanVertices(std::vector< float > &verts, std::vector< int > &tris)
void saveMoveMapTileToFile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh *navMesh, TileResult const &tileResult, std::string_view fileNameSuffix=""sv)
TileResult buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, float(&bmin)[3], float(&bmax)[3], dtNavMeshParams const *navMeshParams, std::string_view fileNameSuffix=""sv)
boost::filesystem::path m_outputDirectory
Definition TileBuilder.h:87
virtual bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh *navMesh)
static void getTileBounds(uint32 tileX, uint32 tileY, float const *verts, std::size_t vertCount, float *bmin, float *bmax)
std::pair< iterator, bool > insert(Key const &key)
Definition FlatSet.h:82
static uint32 packTileID(uint32 tileX, uint32 tileY)
Definition MapTree.h:67
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY)
Definition MapTree.h:68
static boost::filesystem::path vmtile
static boost::filesystem::path tilelist
static const float GRID_SIZE
std::unordered_map< uint32, MapEntry > sMapStore
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
std::vector< float > solidVerts
std::vector< int > solidTris
dtNavMeshParams m_navMeshParams
Definition MapBuilder.h:44
dtNavMeshParams params
Definition MMapDefines.h:31
uint32 offmeshConnectionCount
Definition MMapDefines.h:32
uint32 mmapVersion
Definition MMapDefines.h:41
float From[3]
Definition MMapDefines.h:89
OffMeshConnectionFlag ConnectionFlags
Definition MMapDefines.h:92
uint32 MapId
Definition MMapDefines.h:86
uint32 TileX
Definition MMapDefines.h:87
NavTerrainFlag Flags
Definition MMapDefines.h:94
uint32 TileY
Definition MMapDefines.h:88
float To[3]
Definition MMapDefines.h:90