27#include <DetourNavMesh.h>
28#include <DetourNavMeshBuilder.h>
34 m_bigBaseUnit(bigBaseUnit),
35 m_debugOutput(debugOutput),
36 m_mapBuilder(mapBuilder),
37 m_terrainBuilder(nullptr),
60 bool skipContinents,
bool skipJunkMaps,
bool skipBattlegrounds,
61 bool debugOutput,
bool bigBaseUnit,
int mapid,
char const* offMeshFilePath,
unsigned int threads) :
62 m_terrainBuilder (nullptr),
63 m_debugOutput (debugOutput),
65 m_skipContinents (skipContinents),
66 m_skipJunkMaps (skipJunkMaps),
67 m_skipBattlegrounds (skipBattlegrounds),
68 m_skipLiquid (skipLiquid),
69 m_maxWalkableAngle (maxWalkableAngle),
70 m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep),
71 m_bigBaseUnit (bigBaseUnit),
74 m_totalTilesProcessed(0u),
75 m_rcContext (nullptr),
76 _cancelationToken (false)
102 for (TileList::iterator it =
m_tiles.begin(); it !=
m_tiles.end(); ++it)
104 (*it).m_tiles->clear();
105 delete (*it).m_tiles;
115 std::vector<std::string> files;
116 uint32 mapID, tileX, tileY, tileID, count = 0;
118 printf(
"Discovering maps... ");
120 for (
uint32 i = 0; i < files.size(); ++i)
122 mapID =
uint32(atoi(files[i].substr(0, 4).c_str()));
132 for (
uint32 i = 0; i < files.size(); ++i)
134 mapID =
uint32(atoi(files[i].substr(0, 4).c_str()));
141 printf(
"found %u.\n", count);
144 printf(
"Discovering tiles... ");
145 for (TileList::iterator itr =
m_tiles.begin(); itr !=
m_tiles.end(); ++itr)
147 std::set<uint32>* tiles = (*itr).m_tiles;
148 mapID = (*itr).m_mapId;
152 for (
uint32 i = 0; i < files.size(); ++i)
154 tileX =
uint32(atoi(files[i].substr(8, 2).c_str()));
155 tileY =
uint32(atoi(files[i].substr(5, 2).c_str()));
156 tileID = StaticMapTree::packTileID(tileY, tileX);
158 tiles->insert(tileID);
164 for (
uint32 i = 0; i < files.size(); ++i)
166 tileY =
uint32(atoi(files[i].substr(5, 2).c_str()));
167 tileX =
uint32(atoi(files[i].substr(8, 2).c_str()));
168 tileID = StaticMapTree::packTileID(tileX, tileY);
170 if (tiles->insert(tileID).second)
178 uint32 minX, minY, maxX, maxY;
182 for (
uint32 i = minX; i <= maxX; ++i)
183 for (
uint32 j = minY; j <= maxY; ++j)
184 if (tiles->insert(StaticMapTree::packTileID(i, j)).second)
188 printf(
"found %u.\n\n", count);
191 for (TileList::iterator it =
m_tiles.begin(); it !=
m_tiles.end(); ++it)
202 if (offMeshFilePath ==
nullptr)
208 printf(
" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
213 while (fgets(buf, 512, fp.get()))
216 int32 scanned = sscanf(buf,
"%u %u,%u (%f %f %f) (%f %f %f) %f %hhu %hu", &offMesh.
MapId, &offMesh.
TileX, &offMesh.
TileY,
217 &offMesh.
From[0], &offMesh.
From[1], &offMesh.
From[2], &offMesh.
To[0], &offMesh.
To[1], &offMesh.
To[2],
236 TileList::iterator itr = std::find(
m_tiles.begin(),
m_tiles.end(), mapID);
238 return (*itr).m_tiles;
240 std::set<uint32>* tiles =
new std::set<uint32>();
258 dtNavMesh* navMesh = dtAllocNavMesh();
261 printf(
"[Map %04i] Failed creating navmesh for tile %i,%i !\n", tileInfo.
m_mapId, tileInfo.
m_tileX, tileInfo.
m_tileY);
262 dtFreeNavMesh(navMesh);
268 dtFreeNavMesh(navMesh);
274 printf(
"Using %u threads to generate mmaps\n",
m_threads);
276 for (
unsigned int i = 0; i <
m_threads; ++i)
288 for (TileList::iterator it =
m_tiles.begin(); it !=
m_tiles.end(); ++it)
297 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
318 float bmin[3] = { 0, 0, 0 };
319 float bmax[3] = { 0, 0, 0 };
320 float lmin[3] = { 0, 0, 0 };
321 float lmax[3] = { 0, 0, 0 };
355 FILE* file = fopen(name,
"rb");
359 printf(
"Building mesh from file\n");
360 int tileX, tileY, mapId;
361 if (fread(&mapId,
sizeof(
int), 1, file) != 1)
366 if (fread(&tileX,
sizeof(
int), 1, file) != 1)
371 if (fread(&tileY,
sizeof(
int), 1, file) != 1)
377 dtNavMesh* navMesh =
nullptr;
381 printf(
"Failed creating navmesh! \n");
386 uint32 verticesCount, indicesCount;
387 if (fread(&verticesCount,
sizeof(
uint32), 1, file) != 1)
393 if (fread(&indicesCount,
sizeof(
uint32), 1, file) != 1)
399 float* verts =
new float[verticesCount];
400 int* inds =
new int[indicesCount];
402 if (fread(verts,
sizeof(
float), verticesCount, file) != verticesCount)
410 if (fread(inds,
sizeof(
int), indicesCount, file) != indicesCount)
420 for (
uint32 i = 0; i < verticesCount; ++i)
424 for (
uint32 i = 0; i < indicesCount; ++i)
430 float bmin[3], bmax[3];
435 tileBuilder.
buildMoveMapTile(mapId, tileX, tileY, data, bmin, bmax, navMesh);
442 dtNavMesh* navMesh =
nullptr;
446 printf(
"Failed creating navmesh! \n");
453 tileBuilder.
buildTile(mapID, tileX, tileY, navMesh);
454 dtFreeNavMesh(navMesh);
469 dtNavMesh* navMesh =
nullptr;
473 printf(
"[Map %04i] Failed creating navmesh!\n", mapID);
479 printf(
"[Map %04i] We have %u tiles. \n", mapID, (
unsigned int)tiles->size());
480 for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
485 StaticMapTree::unpackTileID((*it), tileX, tileY);
491 memcpy(&tileInfo.
m_navMeshParams, navMesh->getParams(),
sizeof(dtNavMeshParams));
495 dtFreeNavMesh(navMesh);
530 G3D::Array<float> allVerts;
534 if (!allVerts.size())
541 float bmin[3], bmax[3];
556 int32 navMeshParamsMapId = mapID;
558 while (parentMapId != -1)
560 navMeshParamsMapId = parentMapId;
561 parentMapId =
sMapStore[parentMapId].ParentMapID;
564 std::set<uint32>* tiles =
getTileList(navMeshParamsMapId);
572 int polyBits = DT_POLY_BITS;
574 int maxTiles = tiles->size();
575 int maxPolysPerTile = 1 << polyBits;
579 uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
580 for (std::set<uint32>::iterator it = tiles->begin(); it != tiles->end(); ++it)
582 StaticMapTree::unpackTileID(*it, tileX, tileY);
584 if (tileX > tileXMax)
586 else if (tileX < tileXMin)
589 if (tileY > tileYMax)
591 else if (tileY < tileYMin)
596 float bmin[3], bmax[3];
602 dtNavMeshParams navMeshParams;
603 memset(&navMeshParams, 0,
sizeof(dtNavMeshParams));
606 rcVcopy(navMeshParams.orig, bmin);
607 navMeshParams.maxTiles = maxTiles;
608 navMeshParams.maxPolys = maxPolysPerTile;
610 navMesh = dtAllocNavMesh();
611 printf(
"[Map %04u] Creating navMesh...\n", mapID);
612 if (!navMesh->init(&navMeshParams))
614 printf(
"[Map %04u] Failed creating navmesh! \n", mapID);
620 FILE* file = fopen(fileName.c_str(),
"wb");
623 dtFreeNavMesh(navMesh);
625 perror(
Trinity::StringFormat(
"[Map {:04}] Failed to open {} for writing!\n", mapID, fileName).c_str());
630 fwrite(&navMeshParams,
sizeof(dtNavMeshParams), 1, file);
636 MeshData &meshData,
float bmin[3],
float bmax[3],
641 printf(
"%s Building movemap tiles...\n", tileString.c_str());
645 float* tVerts = meshData.
solidVerts.getCArray();
646 int tVertCount = meshData.
solidVerts.size() / 3;
647 int* tTris = meshData.
solidTris.getCArray();
648 int tTriCount = meshData.
solidTris.size() / 3;
653 int lTriCount = meshData.
liquidTris.size() / 3;
662 rcCalcGridSize(config.bmin, config.bmax, config.cs, &config.width, &config.height);
665 Tile* tiles =
new Tile[TILES_PER_MAP * TILES_PER_MAP];
668 rcConfig tileCfg = config;
669 tileCfg.width = config.tileSize + config.borderSize*2;
670 tileCfg.height = config.tileSize + config.borderSize*2;
673 rcPolyMesh** pmmerge =
new rcPolyMesh*[TILES_PER_MAP * TILES_PER_MAP];
674 rcPolyMeshDetail** dmmerge =
new rcPolyMeshDetail*[TILES_PER_MAP * TILES_PER_MAP];
677 for (
int y = 0; y < TILES_PER_MAP; ++y)
679 for (
int x = 0; x < TILES_PER_MAP; ++x)
681 Tile& tile = tiles[x + y * TILES_PER_MAP];
684 tileCfg.bmin[0] = config.bmin[0] + x * float(config.tileSize * config.cs);
685 tileCfg.bmin[2] = config.bmin[2] + y * float(config.tileSize * config.cs);
686 tileCfg.bmax[0] = config.bmin[0] + (x + 1) *
float(config.tileSize * config.cs);
687 tileCfg.bmax[2] = config.bmin[2] + (y + 1) *
float(config.tileSize * config.cs);
689 tileCfg.bmin[0] -= tileCfg.borderSize * tileCfg.cs;
690 tileCfg.bmin[2] -= tileCfg.borderSize * tileCfg.cs;
691 tileCfg.bmax[0] += tileCfg.borderSize * tileCfg.cs;
692 tileCfg.bmax[2] += tileCfg.borderSize * tileCfg.cs;
695 tile.
solid = rcAllocHeightfield();
696 if (!tile.
solid || !rcCreateHeightfield(
m_rcContext, *tile.
solid, tileCfg.width, tileCfg.height, tileCfg.bmin, tileCfg.bmax, tileCfg.cs, tileCfg.ch))
698 printf(
"%s Failed building heightfield! \n", tileString.c_str());
710 unsigned char* triFlags =
new unsigned char[tTriCount];
712 rcClearUnwalkableTriangles(
m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags);
713 rcMarkWalkableTriangles(
m_rcContext, tileCfg.walkableSlopeAngleNotSteep, tVerts, tVertCount, tTris, tTriCount, triFlags,
NAV_AREA_GROUND);
714 rcRasterizeTriangles(
m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.
solid, config.walkableClimb);
717 rcFilterLowHangingWalkableObstacles(
m_rcContext, config.walkableClimb, *tile.
solid);
718 rcFilterLedgeSpans(
m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.
solid);
719 rcFilterWalkableLowHeightSpans(
m_rcContext, tileCfg.walkableHeight, *tile.
solid);
722 rcRasterizeTriangles(
m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.
solid, config.walkableClimb);
725 tile.
chf = rcAllocCompactHeightfield();
726 if (!tile.
chf || !rcBuildCompactHeightfield(
m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.
solid, *tile.
chf))
728 printf(
"%s Failed compacting heightfield! \n", tileString.c_str());
733 if (!rcErodeWalkableArea(
m_rcContext, config.walkableRadius, *tile.
chf))
735 printf(
"%s Failed eroding area! \n", tileString.c_str());
741 printf(
"%s Failed filtering area! \n", tileString.c_str());
747 printf(
"%s Failed building distance field! \n", tileString.c_str());
751 if (!rcBuildRegions(
m_rcContext, *tile.
chf, tileCfg.borderSize, tileCfg.minRegionArea, tileCfg.mergeRegionArea))
753 printf(
"%s Failed building regions! \n", tileString.c_str());
757 tile.
cset = rcAllocContourSet();
758 if (!tile.
cset || !rcBuildContours(
m_rcContext, *tile.
chf, tileCfg.maxSimplificationError, tileCfg.maxEdgeLen, *tile.
cset))
760 printf(
"%s Failed building contours! \n", tileString.c_str());
765 tile.
pmesh = rcAllocPolyMesh();
768 printf(
"%s Failed building polymesh! \n", tileString.c_str());
772 tile.
dmesh = rcAllocPolyMeshDetail();
773 if (!tile.
dmesh || !rcBuildPolyMeshDetail(
m_rcContext, *tile.
pmesh, *tile.
chf, tileCfg.detailSampleDist, tileCfg.detailSampleMaxError, *tile.
dmesh))
775 printf(
"%s Failed building polymesh detail! \n", tileString.c_str());
782 rcFreeHeightField(tile.
solid);
783 tile.
solid =
nullptr;
784 rcFreeCompactHeightfield(tile.
chf);
786 rcFreeContourSet(tile.
cset);
789 pmmerge[nmerge] = tile.
pmesh;
790 dmmerge[nmerge] = tile.
dmesh;
798 printf(
"%s alloc iv.polyMesh FAILED!\n", tileString.c_str());
809 printf(
"%s alloc m_dmesh FAILED!\n", tileString.c_str());
824 for (
int i = 0; i < iv.
polyMesh->npolys; ++i)
836 dtNavMeshCreateParams
params;
858 params.walkableHeight = BASE_UNIT_DIM*config.walkableHeight;
859 params.walkableRadius = BASE_UNIT_DIM*config.walkableRadius;
860 params.walkableClimb = BASE_UNIT_DIM*config.walkableClimb;
861 params.tileX = (((bmin[0] + bmax[0]) / 2) - navMesh->getParams()->orig[0]) /
GRID_SIZE;
862 params.tileY = (((bmin[2] + bmax[2]) / 2) - navMesh->getParams()->orig[2]) /
GRID_SIZE;
863 rcVcopy(
params.bmin, bmin);
864 rcVcopy(
params.bmax, bmax);
868 params.buildBvTree =
true;
871 unsigned char* navData =
nullptr;
878 if (
params.nvp > DT_VERTS_PER_POLYGON)
880 printf(
"%s Invalid verts-per-polygon value! \n", tileString.c_str());
883 if (
params.vertCount >= 0xffff)
885 printf(
"%s Too many vertices! \n", tileString.c_str());
901 printf(
"%s No polygons to build on tile! \n", tileString.c_str());
906 printf(
"%s No detail mesh to build tile! \n", tileString.c_str());
910 printf(
"%s Building navmesh tile...\n", tileString.c_str());
911 if (!dtCreateNavMeshData(&
params, &navData, &navDataSize))
913 printf(
"%s Failed building navmesh tile! \n", tileString.c_str());
917 dtTileRef tileRef = 0;
918 printf(
"%s Adding tile to navmesh...\n", tileString.c_str());
921 dtStatus dtResult = navMesh->addTile(navData, navDataSize, DT_TILE_FREE_DATA, 0, &tileRef);
922 if (!tileRef || dtResult != DT_SUCCESS)
924 printf(
"%s Failed adding tile to navmesh! \n", tileString.c_str());
930 FILE* file = fopen(fileName.c_str(),
"wb");
933 perror(
Trinity::StringFormat(
"[Map {:04}] Failed to open {} for writing!\n", mapID, fileName).c_str());
934 navMesh->removeTile(tileRef,
nullptr,
nullptr);
938 printf(
"%s Writing to file...\n", tileString.c_str());
952 fwrite(navData,
sizeof(
unsigned char), navDataSize, file);
956 navMesh->removeTile(tileRef,
nullptr,
nullptr);
963 for (
int i = 0; i < iv.
polyMesh->nverts; ++i)
965 unsigned short* v = &iv.
polyMesh->verts[i*3];
966 v[0] += (
unsigned short)config.borderSize;
967 v[2] += (
unsigned short)config.borderSize;
971 iv.
writeIV(mapID, tileX, tileY);
979 if (verts && vertCount)
980 rcCalcBounds(verts, vertCount, bmin, bmax);
1026 return map->MapType == 3;
1034 return (map->Flags & 0x2) != 0;
1042 return map->InstanceType == 3;
1071 FILE* file = fopen(fileName.c_str(),
"rb");
1093 memset(&config, 0,
sizeof(rcConfig));
1095 rcVcopy(config.bmin, bmin);
1096 rcVcopy(config.bmax, bmax);
1098 config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
1107 config.borderSize = config.walkableRadius + 3;
1113 config.minRegionArea = rcSqr(60);
1114 config.mergeRegionArea = rcSqr(50);
1115 config.maxSimplificationError = 1.8f;
1116 config.detailSampleDist = config.cs * 16;
1117 config.detailSampleMaxError = config.ch * 1;
1124 config.walkableRadius = 0;
1142 return totalTilesBuilt * 100 / totalTiles;
std::unordered_set< uint32 > params[2]
std::optional< T > Optional
Optional helper class to wrap optional values within.
std::vector< OffMeshData > m_offMeshConnections
void ParseOffMeshConnectionsFile(char const *offMeshFilePath)
void buildMaps(Optional< uint32 > mapID)
ProducerConsumerQueue< TileInfo > _queue
std::vector< TileBuilder * > m_tileBuilders
void buildMeshFromFile(char *name)
std::set< uint32 > * getTileList(uint32 mapID)
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const
bool isDevMap(uint32 mapID) const
Optional< float > m_maxWalkableAngleNotSteep
uint32 currentPercentageDone() const
void buildNavMesh(uint32 mapID, dtNavMesh *&navMesh)
bool shouldSkipMap(uint32 mapID) const
std::atomic< uint32 > m_totalTiles
rcConfig GetMapSpecificConfig(uint32 mapID, float bmin[3], float bmax[3], const TileConfig &tileConfig) const
bool isTransportMap(uint32 mapID) const
Optional< float > m_maxWalkableAngle
std::atomic< bool > _cancelationToken
bool isContinentMap(uint32 mapID) const
void getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY)
void buildMap(uint32 mapID)
MapBuilder(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)
void getTileBounds(uint32 tileX, uint32 tileY, float *verts, int vertCount, float *bmin, float *bmax) const
std::atomic< uint32 > m_totalTilesProcessed
bool isBattlegroundMap(uint32 mapID) const
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
TerrainBuilder * m_terrainBuilder
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, std::vector< OffMeshData > const &offMeshConnections)
static void cleanVertices(G3D::Array< float > &verts, G3D::Array< int > &tris)
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
std::thread m_workerThread
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
MapBuilder * m_mapBuilder
void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh *navMesh)
TileBuilder(MapBuilder *mapBuilder, bool skipLiquid, bool bigBaseUnit, bool debugOutput)
void buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, float bmin[3], float bmax[3], dtNavMesh *navMesh)
TerrainBuilder * m_terrainBuilder
static const float GRID_SIZE
ListFilesResult getDirContents(std::vector< std::string > &fileList, std::string dirpath=".", std::string filter="*")
std::unordered_map< uint32, MapEntry > sMapStore
auto MapGetValuePtr(M &map, typename M::key_type const &key)
auto make_unique_ptr_with_deleter(T ptr, Del &&deleter)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
G3D::Array< float > liquidVerts
G3D::Array< float > offMeshConnectionRads
G3D::Array< unsigned char > offMeshConnectionDirs
G3D::Array< float > offMeshConnections
G3D::Array< unsigned short > offMeshConnectionsFlags
G3D::Array< float > solidVerts
G3D::Array< int > liquidTris
G3D::Array< int > solidTris
G3D::Array< unsigned char > offMeshConnectionsAreas
G3D::Array< uint8 > liquidType
dtNavMeshParams m_navMeshParams
rcCompactHeightfield * chf