28#include <boost/filesystem/directory.hpp>
32static boost::filesystem::path
tilelist =
".tilelist";
33static boost::filesystem::path
vmtile =
".vmtile";
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),
62 MapBuilder::MapBuilder(boost::filesystem::path
const& inputDirectory, boost::filesystem::path
const& outputDirectory,
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),
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),
79 m_totalTilesProcessed(0u),
80 _cancelationToken (false)
105 boost::filesystem::directory_iterator end;
106 for (
auto itr = boost::filesystem::directory_iterator(
m_inputDirectory /
"maps"); itr != end; ++itr)
108 if (!boost::filesystem::is_regular_file(*itr))
114 Optional<uint32> mapId = Trinity::StringTo<uint32>(std::string_view(itr->path().filename().string()).substr(0, 4));
121 if (
auto tileList = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(itr->path().string().c_str(),
"rb")))
124 uint32 versionMagic = { };
126 char tilesData[64 * 64] = { };
127 if (fread(mapMagic.data(), mapMagic.size(), 1, tileList.get()) == 1
129 && fread(&versionMagic,
sizeof(versionMagic), 1, tileList.get()) == 1
131 && fread(&build,
sizeof(build), 1, tileList.get()) == 1
132 && fread(std::data(tilesData), std::size(tilesData), 1, tileList.get()) == 1)
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')
144 for (
auto itr = boost::filesystem::directory_iterator(
m_inputDirectory /
"vmaps"); itr != end; ++itr)
146 if (!boost::filesystem::is_directory(*itr))
149 Optional<uint32> mapId = Trinity::StringTo<uint32>(itr->path().filename().string());
157 for (
auto fileItr = boost::filesystem::directory_iterator(*itr); fileItr != end; ++fileItr)
159 if (!boost::filesystem::is_regular_file(*fileItr))
165 std::string fileName = fileItr->path().filename().string();
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);
171 if (tiles.
insert(tileID).second)
184 if (offMeshFilePath ==
nullptr)
187 auto fp = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(offMeshFilePath,
"rb"));
190 TC_LOG_ERROR(
"maps.mmapgen",
"MapBuilder::loadOffMeshConnections:: input file {} not found!", offMeshFilePath);
195 while (fgets(buf, 512, fp.get()))
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));
237 dtNavMesh* navMesh = dtAllocNavMesh();
241 dtFreeNavMesh(navMesh);
247 dtFreeNavMesh(navMesh);
256 for (
unsigned int i = 0; i <
m_threads; ++i)
267 for (
auto& [mapId, _] :
m_tiles)
273 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
286 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(name,
"rb"));
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)
295 if (fread(&tileX,
sizeof(
int), 1, file.get()) != 1)
298 if (fread(&tileY,
sizeof(
int), 1, file.get()) != 1)
301 dtNavMesh* navMesh =
nullptr;
305 TC_LOG_ERROR(
"maps.mmapgen",
"Failed creating navmesh!");
309 uint32 verticesCount, indicesCount;
310 if (fread(&verticesCount,
sizeof(
uint32), 1, file.get()) != 1)
313 if (fread(&indicesCount,
sizeof(
uint32), 1, file.get()) != 1)
319 if (fread(data.
solidVerts.data(),
sizeof(
float), verticesCount, file.get()) != verticesCount)
323 if (fread(data.
solidTris.data(),
sizeof(
int), indicesCount, file.get()) != indicesCount)
328 float bmin[3], bmax[3];
342 dtNavMesh* navMesh =
nullptr;
346 TC_LOG_ERROR(
"maps.mmapgen",
"Failed creating navmesh!");
354 tileBuilder.
buildTile(mapID, tileX, tileY, navMesh);
355 dtFreeNavMesh(navMesh);
365 std::span<uint32 const> tiles =
getTileList(mapID);
370 dtNavMesh* navMesh =
nullptr;
374 TC_LOG_ERROR(
"maps.mmapgen",
"[Map {:04}] Failed creating navmesh!", mapID);
380 TC_LOG_INFO(
"maps.mmapgen",
"[Map {:04}] We have {} tiles.", mapID, tiles.size());
381 for (
uint32 packedTile : tiles)
392 memcpy(&tileInfo.
m_navMeshParams, navMesh->getParams(),
sizeof(dtNavMeshParams));
396 dtFreeNavMesh(navMesh);
404 int32 navMeshParamsMapId = mapID;
406 while (parentMapId != -1)
408 navMeshParamsMapId = parentMapId;
409 parentMapId =
sMapStore[parentMapId].ParentMapID;
412 std::span<uint32 const> tiles =
getTileList(navMeshParamsMapId);
420 int polyBits = DT_POLY_BITS;
422 int maxTiles = tiles.size();
423 int maxPolysPerTile = 1 << polyBits;
427 uint32 tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0, tileX, tileY;
428 for (
uint32 packedTile : tiles)
432 if (tileX > tileXMax)
434 else if (tileX < tileXMin)
437 if (tileY > tileYMax)
439 else if (tileY < tileYMin)
444 float bmin[3], bmax[3];
453 rcVcopy(fileHeader.
params.orig, bmin);
454 fileHeader.
params.maxTiles = maxTiles;
455 fileHeader.
params.maxPolys = maxPolysPerTile;
457 navMesh = dtAllocNavMesh();
458 TC_LOG_INFO(
"maps.mmapgen",
"[Map {:04}] Creating navMesh...", mapID);
459 if (!navMesh->init(&fileHeader.
params))
461 TC_LOG_ERROR(
"maps.mmapgen",
"[Map {:04}] Failed creating navmesh!", mapID);
467 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(),
"wb"));
470 dtFreeNavMesh(navMesh);
472 TC_LOG_ERROR(
"maps.mmapgen",
"{}: [Map {:04}] Failed to open {} for writing!\n", strerror(errno), mapID, fileName);
476 std::vector<OffMeshData> offMeshConnections;
483 fwrite(offMeshConnections.data(),
sizeof(
OffMeshData), offMeshConnections.size(), file.get());
494 if (
static_cast<uint32>(parentMapId) == mapID)
497 parentMapId =
sMapStore[parentMapId].ParentMapID;
499 }
while (parentMapId != -1);
530 return map->MapType == 3;
538 return (map->Flags & 0x2) != 0;
546 return map->InstanceType == 3;
575 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(),
"rb"));
580 int count = fread(&header,
sizeof(
MmapTileHeader), 1, file.get());
602 return totalTilesBuilt * 100 / totalTiles;
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
uint32 constexpr MMAP_VERSION
@ OFFMESH_CONNECTION_FLAG_BIDIRECTIONAL
uint32 constexpr MMAP_MAGIC
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)
std::optional< T > Optional
Optional helper class to wrap optional values within.
void buildMeshFromFile(char const *name)
std::vector< OffMeshData > m_offMeshConnections
void ParseOffMeshConnectionsFile(char const *offMeshFilePath)
void buildMaps(Optional< uint32 > mapID)
ProducerConsumerQueue< TileInfo > _queue
uint32 percentageDone(uint32 totalTiles, uint32 totalTilesDone) const
bool isDevMap(uint32 mapID) const
Optional< float > m_maxWalkableAngleNotSteep
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
bool isTransportMap(uint32 mapID) const
Optional< float > m_maxWalkableAngle
std::atomic< bool > _cancelationToken
bool isContinentMap(uint32 mapID) const
boost::filesystem::path m_inputDirectory
void buildMap(uint32 mapID)
std::atomic< uint32 > m_totalTilesProcessed
friend class MapTileBuilder
std::span< uint32 const > getTileList(uint32 mapID) const
bool isBattlegroundMap(uint32 mapID) const
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY)
std::vector< std::unique_ptr< TileBuilder > > m_tileBuilders
MapBuilder * m_mapBuilder
std::thread m_workerThread
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
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)
static uint32 packTileID(uint32 tileX, uint32 tileY)
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY)
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)
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
OffMeshConnectionFlag ConnectionFlags