aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Collision/Management/MMapManager.cpp79
-rw-r--r--src/common/Collision/Management/MMapManager.h3
-rw-r--r--src/common/Collision/Maps/MMapDefines.h51
-rw-r--r--src/server/scripts/Commands/cs_mmaps.cpp2
-rw-r--r--src/tools/mmaps_generator/Info/readme.txt6
-rw-r--r--src/tools/mmaps_generator/IntermediateValues.cpp16
-rw-r--r--src/tools/mmaps_generator/IntermediateValues.h14
-rw-r--r--src/tools/mmaps_generator/MapBuilder.cpp44
-rw-r--r--src/tools/mmaps_generator/MapBuilder.h9
-rw-r--r--src/tools/mmaps_generator/PathCommon.h110
-rw-r--r--src/tools/mmaps_generator/PathGenerator.cpp99
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.cpp185
-rw-r--r--src/tools/mmaps_generator/TerrainBuilder.h21
-rw-r--r--src/tools/mmaps_generator/TileBuilder.cpp31
-rw-r--r--src/tools/mmaps_generator/TileBuilder.h17
15 files changed, 376 insertions, 311 deletions
diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp
index c10d64bfd36..d0862a49156 100644
--- a/src/common/Collision/Management/MMapManager.cpp
+++ b/src/common/Collision/Management/MMapManager.cpp
@@ -26,7 +26,7 @@
namespace MMAP
{
constexpr char MAP_FILE_NAME_FORMAT[] = "{}mmaps/{:04}.mmap";
- constexpr char TILE_FILE_NAME_FORMAT[] = "{}mmaps/{:04}{:02}{:02}.mmtile";
+ constexpr char TILE_FILE_NAME_FORMAT[] = "{}mmaps/{:04}_{:02}_{:02}.mmtile";
using NavMeshPtr = std::unique_ptr<dtNavMesh, decltype(Trinity::unique_ptr_deleter<dtNavMesh*, &::dtFreeNavMesh>())>;
using NavMeshQueryPtr = std::unique_ptr<dtNavMeshQuery, decltype(Trinity::unique_ptr_deleter<dtNavMeshQuery*, &::dtFreeNavMeshQuery>())>;
@@ -97,6 +97,28 @@ namespace MMAP
}
// load and init dtNavMesh - read parameters from file
+ dtNavMeshParams params;
+ if (LoadResult paramsResult = parseNavMeshParamsFile(basePath, mapId, &params); paramsResult != LoadResult::Success)
+ return paramsResult;
+
+ NavMeshPtr mesh(dtAllocNavMesh());
+ ASSERT(mesh);
+ if (dtStatusFailed(mesh->init(&params)))
+ {
+ TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {:04}", mapId);
+ return LoadResult::LibraryError;
+ }
+
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded {:04}.mmap", mapId);
+
+ // store inside our map list
+ itr->second.reset(new MMapData(std::move(mesh)));
+ return LoadResult::Success;
+ }
+
+ LoadResult MMapManager::parseNavMeshParamsFile(std::string_view basePath, uint32 mapId, dtNavMeshParams* params,
+ std::vector<OffMeshData>* offmeshConnections /*= nullptr*/)
+ {
std::string fileName = Trinity::StringFormat(MAP_FILE_NAME_FORMAT, basePath, mapId);
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "rb"));
if (!file)
@@ -105,26 +127,39 @@ namespace MMAP
return LoadResult::FileNotFound;
}
- dtNavMeshParams params;
- uint32 count = uint32(fread(&params, sizeof(dtNavMeshParams), 1, file.get()));
- if (count != 1)
+ MmapNavMeshHeader fileHeader;
+ if (fread(&fileHeader, sizeof(MmapNavMeshHeader), 1, file.get()) != 1)
{
TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '{}'", fileName);
return LoadResult::ReadFromFileFailed;
}
- NavMeshPtr mesh(dtAllocNavMesh());
- ASSERT(mesh);
- if (dtStatusFailed(mesh->init(&params)))
+ if (fileHeader.mmapMagic != MMAP_MAGIC)
{
- TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {:04} from file {}", mapId, fileName);
- return LoadResult::LibraryError;
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap {:04}.mmap", mapId);
+ return LoadResult::VersionMismatch;
}
- TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded {:04}.mmap", mapId);
+ if (fileHeader.mmapVersion != MMAP_VERSION)
+ {
+ TC_LOG_ERROR("maps", "MMAP:loadMap: {:04}.mmap was built with generator v{}, expected v{}",
+ mapId, fileHeader.mmapVersion, MMAP_VERSION);
+ return LoadResult::VersionMismatch;
+ }
+
+ memcpy(params, &fileHeader.params, sizeof(dtNavMeshParams));
+
+ if (offmeshConnections)
+ {
+ offmeshConnections->resize(fileHeader.offmeshConnectionCount);
+ if (fread(offmeshConnections->data(), sizeof(OffMeshData), offmeshConnections->size(), file.get()) != offmeshConnections->size())
+ {
+ offmeshConnections->clear();
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read offmesh connections from file '{}'", fileName);
+ return LoadResult::ReadFromFileFailed;
+ }
+ }
- // store inside our map list
- itr->second.reset(new MMapData(std::move(mesh)));
return LoadResult::Success;
}
@@ -154,7 +189,7 @@ namespace MMAP
if (mmap->loadedTileRefs.contains(packedGridPos))
return LoadResult::AlreadyLoaded;
- // load this tile :: mmaps/MMMMXXYY.mmtile
+ // load this tile :: mmaps/MMMM_XX_YY.mmtile
std::string fileName = Trinity::StringFormat(TILE_FILE_NAME_FORMAT, basePath, mapId, x, y);
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "rb"));
if (!file)
@@ -177,19 +212,19 @@ namespace MMAP
MmapTileHeader fileHeader;
if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file.get()) != 1)
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap {:04}{:02}{:02}.mmtile", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap {:04}_{:02}_{:02}.mmtile", mapId, x, y);
return LoadResult::ReadFromFileFailed;
}
if (fileHeader.mmapMagic != MMAP_MAGIC)
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap {:04}{:02}{:02}.mmtile", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap {:04}_{:02}_{:02}.mmtile", mapId, x, y);
return LoadResult::VersionMismatch;
}
if (fileHeader.mmapVersion != MMAP_VERSION)
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: {:04}{:02}{:02}.mmtile was built with generator v{}, expected v{}",
+ TC_LOG_ERROR("maps", "MMAP:loadMap: {:04}_{:02}_{:02}.mmtile was built with generator v{}, expected v{}",
mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
return LoadResult::VersionMismatch;
}
@@ -198,7 +233,7 @@ namespace MMAP
fseek(file.get(), 0, SEEK_END);
if (pos < 0 || static_cast<int32>(fileHeader.size) > ftell(file.get()) - pos)
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: {:04}{:02}{:02}.mmtile has corrupted data size", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: {:04}_{:02}_{:02}.mmtile has corrupted data size", mapId, x, y);
return LoadResult::ReadFromFileFailed;
}
@@ -210,7 +245,7 @@ namespace MMAP
size_t result = fread(data.get(), fileHeader.size, 1, file.get());
if (!result)
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap {:04}{:02}{:02}.mmtile", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap {:04}_{:02}_{:02}.mmtile", mapId, x, y);
return LoadResult::ReadFromFileFailed;
}
@@ -227,7 +262,7 @@ namespace MMAP
}
else
{
- TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load {:04}{:02}{:02}.mmtile into navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load {:04}_{:02}_{:02}.mmtile into navmesh", mapId, x, y);
return LoadResult::LibraryError;
}
}
@@ -270,7 +305,7 @@ namespace MMAP
if (itr == loadedMMaps.end())
{
// file may not exist, therefore not loaded
- TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. {:04}{:02}{:02}.mmtile", mapId, x, y);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. {:04}_{:02}_{:02}.mmtile", mapId, x, y);
return false;
}
@@ -292,7 +327,7 @@ namespace MMAP
// 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
- TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}{:02}{:02}.mmtile from navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
ABORT();
}
else
@@ -322,7 +357,7 @@ namespace MMAP
uint32 x = (tileId >> 16);
uint32 y = (tileId & 0x0000FFFF);
if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, nullptr, nullptr)))
- TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}{:02}{:02}.mmtile from navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload {:04}_{:02}_{:02}.mmtile from navmesh", mapId, x, y);
else
{
--loadedTiles;
diff --git a/src/common/Collision/Management/MMapManager.h b/src/common/Collision/Management/MMapManager.h
index 9973f37d51c..b48b773555b 100644
--- a/src/common/Collision/Management/MMapManager.h
+++ b/src/common/Collision/Management/MMapManager.h
@@ -19,7 +19,7 @@
#define _MMAP_MANAGER_H
#include "Define.h"
-#include <DetourNavMesh.h>
+#include "MMapDefines.h"
#include <DetourNavMeshQuery.h>
#include <memory>
#include <string_view>
@@ -58,6 +58,7 @@ namespace MMAP
static MMapManager* instance();
void InitializeThreadUnsafe(std::unordered_map<uint32, std::vector<uint32>> const& mapData);
+ static LoadResult parseNavMeshParamsFile(std::string_view basePath, uint32 mapId, dtNavMeshParams* params, std::vector<OffMeshData>* offmeshConnections = nullptr);
LoadResult loadMap(std::string_view basePath, uint32 mapId, int32 x, int32 y);
bool loadMapInstance(std::string_view basePath, uint32 meshMapId, uint32 instanceMapId, uint32 instanceId);
bool unloadMap(uint32 mapId, int32 x, int32 y);
diff --git a/src/common/Collision/Maps/MMapDefines.h b/src/common/Collision/Maps/MMapDefines.h
index 368281543a2..522112ebe62 100644
--- a/src/common/Collision/Maps/MMapDefines.h
+++ b/src/common/Collision/Maps/MMapDefines.h
@@ -19,22 +19,29 @@
#define MMapDefines_h__
#include "Define.h"
-#include "DetourNavMesh.h"
+#include <DetourNavMesh.h>
-const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
-#define MMAP_VERSION 15
+inline uint32 constexpr MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
+inline uint32 constexpr MMAP_VERSION = 16;
-struct MmapTileHeader
+struct MmapNavMeshHeader
{
- uint32 mmapMagic;
- uint32 dtVersion;
- uint32 mmapVersion;
- uint32 size;
- char usesLiquids;
- char padding[3];
+ uint32 mmapMagic = MMAP_MAGIC;
+ uint32 mmapVersion = MMAP_VERSION;
+ dtNavMeshParams params = { };
+ uint32 offmeshConnectionCount = 0;
+};
+
+static_assert(sizeof(MmapNavMeshHeader) == 40);
- MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
- mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() { }
+struct MmapTileHeader
+{
+ uint32 mmapMagic = MMAP_MAGIC;
+ uint32 dtVersion = DT_NAVMESH_VERSION;
+ uint32 mmapVersion = MMAP_VERSION;
+ uint32 size = 0;
+ char usesLiquids = true;
+ char padding[3] = { };
};
// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files
@@ -60,7 +67,7 @@ enum NavArea
NAV_AREA_ALL_MASK = 0x3F // max allowed value
};
-enum NavTerrainFlag
+enum NavTerrainFlag : uint16
{
NAV_EMPTY = 0x00,
NAV_GROUND = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_GROUND),
@@ -69,4 +76,22 @@ enum NavTerrainFlag
NAV_MAGMA_SLIME = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_MAGMA_SLIME)
};
+enum OffMeshConnectionFlag : uint8
+{
+ OFFMESH_CONNECTION_FLAG_BIDIRECTIONAL = 0x01
+};
+
+struct OffMeshData
+{
+ uint32 MapId;
+ uint32 TileX;
+ uint32 TileY;
+ float From[3];
+ float To[3];
+ float Radius;
+ OffMeshConnectionFlag ConnectionFlags;
+ uint8 AreaId;
+ NavTerrainFlag Flags;
+};
+
#endif // MMapDefines_h__
diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp
index d30bfcdc746..b7734a8c505 100644
--- a/src/server/scripts/Commands/cs_mmaps.cpp
+++ b/src/server/scripts/Commands/cs_mmaps.cpp
@@ -141,7 +141,7 @@ public:
// calculate navmesh tile location
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(player->GetPhaseShift(), player->GetMapId(), player->GetMap()->GetTerrain(), x, y);
- handler->PSendSysMessage("%04u%02i%02i.mmtile", terrainMapId, gx, gy);
+ handler->PSendSysMessage("%04u_%02i_%02i.mmtile", terrainMapId, gx, gy);
handler->PSendSysMessage("tileloc [%i, %i]", gy, gx);
dtNavMesh const* navmesh = MMAP::MMapManager::instance()->GetNavMesh(terrainMapId);
diff --git a/src/tools/mmaps_generator/Info/readme.txt b/src/tools/mmaps_generator/Info/readme.txt
index 5178138c65f..dcd3e635913 100644
--- a/src/tools/mmaps_generator/Info/readme.txt
+++ b/src/tools/mmaps_generator/Info/readme.txt
@@ -1,5 +1,11 @@
R"(Generator command line args
+--input [path] Directory to use for reading maps and vmaps
+ Default: current_directory
+
+--output [path] Directory to write generated data to
+ Default: current_directory
+
--threads [#] Max number of threads used by the generator
Default: Same as CPU cores
diff --git a/src/tools/mmaps_generator/IntermediateValues.cpp b/src/tools/mmaps_generator/IntermediateValues.cpp
index bb88f1f9c72..858ac25d418 100644
--- a/src/tools/mmaps_generator/IntermediateValues.cpp
+++ b/src/tools/mmaps_generator/IntermediateValues.cpp
@@ -31,16 +31,16 @@ namespace MMAP
rcFreePolyMeshDetail(polyMeshDetail);
}
- void IntermediateValues::writeIV(uint32 mapID, uint32 tileX, uint32 tileY)
+ void IntermediateValues::writeIV(boost::filesystem::path const& outputDirectory, std::string_view fileNameSuffix, uint32 mapID, uint32 tileX, uint32 tileY)
{
TC_LOG_INFO("maps.mmapgen.debug", "[Map {:04}] [{:02},{:02}]: Writing debug output intermediate values...", mapID, tileX, tileY);
- auto debugWrite = [&](char const* extension, auto const* data)
+ auto debugWrite = [=, outputDirectory = outputDirectory.generic_string()](char const* extension, auto const* data)
{
- std::string fileName = Trinity::StringFormat("meshes/{:04}{:02}{:02}.{}", mapID, tileX, tileY, extension);
+ std::string fileName = Trinity::StringFormat("{}/meshes/{:04}_{:02}_{:02}{}.{}", outputDirectory, mapID, tileX, tileY, fileNameSuffix, extension);
if (auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb")))
{
- this->debugWrite(file.get(), data);
+ IntermediateValues::debugWrite(file.get(), data);
}
else
TC_LOG_ERROR("maps.mmapgen.debug", "{}: [{:04}-{:02},{:02}] Failed to open {} for writing!", strerror(errno), mapID, tileX, tileY, fileName);
@@ -188,10 +188,10 @@ namespace MMAP
fwrite(mesh->meshes, sizeof(int), mesh->nmeshes*4, file);
}
- void IntermediateValues::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData)
+ void IntermediateValues::generateObjFile(boost::filesystem::path const& outputDirectory, std::string_view fileNameSuffix, uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData)
{
std::string objFileName;
- objFileName = Trinity::StringFormat("meshes/map{:04}{:02}{:02}.obj", mapID, tileX, tileY);
+ objFileName = Trinity::StringFormat("{}/meshes/map{:04}_{:02}_{:02}{}.obj", outputDirectory.generic_string(), mapID, tileX, tileY, fileNameSuffix);
auto objFile = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(objFileName.c_str(), "wb"));
if (!objFile)
@@ -221,7 +221,7 @@ namespace MMAP
TC_LOG_INFO("maps.mmapgen.debug", "[Map {:04}] [{:02},{:02}]: Writing debug output object file...", mapID, tileX, tileY);
- objFileName = Trinity::StringFormat("meshes/map{:04}.map", mapID);
+ objFileName = Trinity::StringFormat("{}/meshes/map{:04}.map", outputDirectory.generic_string(), mapID);
objFile.reset(fopen(objFileName.c_str(), "wb"));
if (!objFile)
@@ -233,7 +233,7 @@ namespace MMAP
char b = '\0';
fwrite(&b, sizeof(char), 1, objFile.get());
- objFileName = Trinity::StringFormat("meshes/map{:04}{:02}{:02}.mesh", mapID, tileX, tileY);
+ objFileName = Trinity::StringFormat("{}/meshes/map{:04}_{:02}_{:02}{}.mesh", outputDirectory.generic_string(), mapID, tileX, tileY, fileNameSuffix);
objFile.reset(fopen(objFileName.c_str(), "wb"));
if (!objFile)
{
diff --git a/src/tools/mmaps_generator/IntermediateValues.h b/src/tools/mmaps_generator/IntermediateValues.h
index 75ade2259e3..f8578683e61 100644
--- a/src/tools/mmaps_generator/IntermediateValues.h
+++ b/src/tools/mmaps_generator/IntermediateValues.h
@@ -64,15 +64,15 @@ namespace MMAP
return *this;
}
- void writeIV(uint32 mapID, uint32 tileX, uint32 tileY);
+ void writeIV(boost::filesystem::path const& outputDirectory, std::string_view fileNameSuffix, uint32 mapID, uint32 tileX, uint32 tileY);
- void debugWrite(FILE* file, rcHeightfield const* mesh);
- void debugWrite(FILE* file, rcCompactHeightfield const* chf);
- void debugWrite(FILE* file, rcContourSet const* cs);
- void debugWrite(FILE* file, rcPolyMesh const* mesh);
- void debugWrite(FILE* file, rcPolyMeshDetail const* mesh);
+ static void debugWrite(FILE* file, rcHeightfield const* mesh);
+ static void debugWrite(FILE* file, rcCompactHeightfield const* chf);
+ static void debugWrite(FILE* file, rcContourSet const* cs);
+ static void debugWrite(FILE* file, rcPolyMesh const* mesh);
+ static void debugWrite(FILE* file, rcPolyMeshDetail const* mesh);
- void generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData);
+ void generateObjFile(boost::filesystem::path const& outputDirectory, std::string_view fileNameSuffix, uint32 mapID, uint32 tileX, uint32 tileY, MeshData const& meshData);
};
}
#endif
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp
index f6bc2ed47cb..65a41d7216c 100644
--- a/src/tools/mmaps_generator/MapBuilder.cpp
+++ b/src/tools/mmaps_generator/MapBuilder.cpp
@@ -37,7 +37,7 @@ namespace MMAP
{
MapTileBuilder::MapTileBuilder(MapBuilder* mapBuilder, Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector<OffMeshData> const* offMeshConnections) :
- TileBuilder(maxWalkableAngle, maxWalkableAngleNotSteep, skipLiquid, bigBaseUnit, debugOutput, offMeshConnections),
+ TileBuilder(mapBuilder->m_inputDirectory, mapBuilder->m_outputDirectory, maxWalkableAngle, maxWalkableAngleNotSteep, skipLiquid, bigBaseUnit, debugOutput, offMeshConnections),
m_mapBuilder(mapBuilder),
m_workerThread(&MapTileBuilder::WorkerThread, this)
{
@@ -59,9 +59,12 @@ namespace MMAP
++m_mapBuilder->m_totalTilesProcessed;
}
- MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid,
+ MapBuilder::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) :
+ m_inputDirectory (inputDirectory),
+ m_outputDirectory (outputDirectory),
m_debugOutput (debugOutput),
m_threads (threads),
m_skipContinents (skipContinents),
@@ -100,7 +103,7 @@ namespace MMAP
void MapBuilder::discoverTiles()
{
boost::filesystem::directory_iterator end;
- for (auto itr = boost::filesystem::directory_iterator("maps"); itr != end; ++itr)
+ for (auto itr = boost::filesystem::directory_iterator(m_inputDirectory / "maps"); itr != end; ++itr)
{
if (!boost::filesystem::is_regular_file(*itr))
continue;
@@ -138,7 +141,7 @@ namespace MMAP
}
}
- for (auto itr = boost::filesystem::directory_iterator("vmaps"); itr != end; ++itr)
+ for (auto itr = boost::filesystem::directory_iterator(m_inputDirectory / "vmaps"); itr != end; ++itr)
{
if (!boost::filesystem::is_directory(*itr))
continue;
@@ -194,11 +197,11 @@ namespace MMAP
OffMeshData offMesh;
int32 scanned = sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f %hhu %hu", &offMesh.MapId, &offMesh.TileX, &offMesh.TileY,
&offMesh.From[0], &offMesh.From[1], &offMesh.From[2], &offMesh.To[0], &offMesh.To[1], &offMesh.To[2],
- &offMesh.Radius, &offMesh.AreaId, &offMesh.Flags);
+ &offMesh.Radius, &offMesh.AreaId, reinterpret_cast<std::underlying_type_t<NavTerrainFlag>*>(&offMesh.Flags));
if (scanned < 10)
continue;
- offMesh.Bidirectional = true;
+ offMesh.ConnectionFlags = OFFMESH_CONNECTION_FLAG_BIDIRECTIONAL;
if (scanned < 12)
offMesh.Flags = NAV_GROUND;
@@ -278,7 +281,7 @@ namespace MMAP
}
/**************************************************************************/
- void MapBuilder::buildMeshFromFile(char* name)
+ void MapBuilder::buildMeshFromFile(char const* name)
{
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(name, "rb"));
if (!file)
@@ -444,23 +447,22 @@ namespace MMAP
/*** now create the navmesh ***/
// navmesh creation params
- dtNavMeshParams navMeshParams;
- memset(&navMeshParams, 0, sizeof(dtNavMeshParams));
- navMeshParams.tileWidth = GRID_SIZE;
- navMeshParams.tileHeight = GRID_SIZE;
- rcVcopy(navMeshParams.orig, bmin);
- navMeshParams.maxTiles = maxTiles;
- navMeshParams.maxPolys = maxPolysPerTile;
+ MmapNavMeshHeader fileHeader;
+ fileHeader.params.tileWidth = GRID_SIZE;
+ fileHeader.params.tileHeight = GRID_SIZE;
+ rcVcopy(fileHeader.params.orig, bmin);
+ fileHeader.params.maxTiles = maxTiles;
+ fileHeader.params.maxPolys = maxPolysPerTile;
navMesh = dtAllocNavMesh();
TC_LOG_INFO("maps.mmapgen", "[Map {:04}] Creating navMesh...", mapID);
- if (!navMesh->init(&navMeshParams))
+ if (!navMesh->init(&fileHeader.params))
{
TC_LOG_ERROR("maps.mmapgen", "[Map {:04}] Failed creating navmesh!", mapID);
return;
}
- std::string fileName = Trinity::StringFormat("mmaps/{:04}.mmap", mapID);
+ std::string fileName = Trinity::StringFormat("{}/mmaps/{:04}.mmap", m_outputDirectory.generic_string(), mapID);
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb"));
if (!file)
@@ -471,8 +473,14 @@ namespace MMAP
return;
}
+ std::vector<OffMeshData> offMeshConnections;
+ std::ranges::copy_if(m_offMeshConnections, std::back_inserter(offMeshConnections), [mapID](OffMeshData const& offMeshData) { return offMeshData.MapId == mapID; });
+
+ fileHeader.offmeshConnectionCount = offMeshConnections.size();
+
// now that we know navMesh params are valid, we can write them to file
- fwrite(&navMeshParams, sizeof(dtNavMeshParams), 1, file.get());
+ fwrite(&fileHeader, sizeof(MmapNavMeshHeader), 1, file.get());
+ fwrite(offMeshConnections.data(), sizeof(OffMeshData), offMeshConnections.size(), file.get());
}
/**************************************************************************/
@@ -563,7 +571,7 @@ namespace MMAP
/**************************************************************************/
bool MapTileBuilder::shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const
{
- std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileX, tileY);
+ std::string fileName = Trinity::StringFormat("{}/mmaps/{:04}_{:02}_{:02}.mmtile", m_outputDirectory.generic_string(), mapID, tileX, tileY);
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "rb"));
if (!file)
return false;
diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h
index 68ba4c77eff..d475280b577 100644
--- a/src/tools/mmaps_generator/MapBuilder.h
+++ b/src/tools/mmaps_generator/MapBuilder.h
@@ -23,6 +23,7 @@
#include "ProducerConsumerQueue.h"
#include "TerrainBuilder.h"
#include "TileBuilder.h"
+#include <boost/filesystem/path.hpp>
#include <DetourNavMesh.h>
#include <atomic>
#include <span>
@@ -78,7 +79,9 @@ namespace MMAP
friend class MapTileBuilder;
public:
- MapBuilder(Optional<float> maxWalkableAngle,
+ MapBuilder(boost::filesystem::path const& inputDirectory,
+ boost::filesystem::path const& outputDirectory,
+ Optional<float> maxWalkableAngle,
Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid,
bool skipContinents,
@@ -92,7 +95,7 @@ namespace MMAP
~MapBuilder();
- void buildMeshFromFile(char* name);
+ void buildMeshFromFile(char const* name);
// builds an mmap tile for the specified map and its mesh
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY);
@@ -122,6 +125,8 @@ namespace MMAP
TileList m_tiles;
+ boost::filesystem::path m_inputDirectory;
+ boost::filesystem::path m_outputDirectory;
bool m_debugOutput;
std::vector<OffMeshData> m_offMeshConnections;
diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h
index b0761cc2d9a..3ab2c43afda 100644
--- a/src/tools/mmaps_generator/PathCommon.h
+++ b/src/tools/mmaps_generator/PathCommon.h
@@ -15,64 +15,49 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _MMAP_COMMON_H
-#define _MMAP_COMMON_H
+#ifndef TRINITYCORE_MMAP_COMMON_H
+#define TRINITYCORE_MMAP_COMMON_H
-#include "Define.h"
-#include <memory>
-#include <string>
+#include "Common.h"
+#include <boost/filesystem/directory.hpp>
+#include <string_view>
#include <unordered_map>
-#include <vector>
-
-#ifndef _WIN32
- #include <cstddef>
- #include <cstring>
- #include <dirent.h>
-#else
- #include <Windows.h>
-#endif
-
-#ifndef _WIN32
- #include <cerrno>
-#endif
-
-namespace VMAP
-{
- class VMapManager;
-}
namespace MMAP
{
- inline bool matchWildcardFilter(char const* filter, char const* str)
+ inline bool matchWildcardFilter(std::string_view filter, std::string_view str)
{
- if (!filter || !str)
+ if (filter.empty() || str.empty())
return false;
+ auto filterItr = filter.begin();
+ auto filterEnd = filter.end();
+ auto strItr = str.begin();
+ auto strEnd = str.end();
+
// end on null character
- while (*filter && *str)
+ while (filterItr != filterEnd && strItr != strEnd)
{
- if (*filter == '*')
+ if (*filterItr == '*')
{
- if (*++filter == '\0') // wildcard at end of filter means all remaing chars match
+ if (++filterItr == filterEnd) // wildcard at end of filter means all remaing chars match
return true;
- for (;;)
+ while (*filterItr != *strItr)
{
- if (*filter == *str)
- break;
- if (*str == '\0')
+ if (strItr == strEnd)
return false; // reached end of string without matching next filter character
- str++;
+ ++strItr;
}
}
- else if (*filter != *str)
+ else if (*filterItr != *strItr)
return false; // mismatch
- filter++;
- str++;
+ ++filterItr;
+ ++strItr;
}
- return ((*filter == '\0' || (*filter == '*' && *++filter == '\0')) && *str == '\0');
+ return (filterItr == filterEnd || (*filterItr == '*' && filterItr + 1 == filterEnd)) && strItr == strEnd;
}
enum ListFilesResult
@@ -81,51 +66,26 @@ namespace MMAP
LISTFILE_OK = 1
};
- inline ListFilesResult getDirContents(std::vector<std::string> &fileList, std::string dirpath = ".", std::string filter = "*")
+ inline ListFilesResult getDirContents(std::vector<std::string>& fileList, boost::filesystem::path const& dirpath,
+ boost::filesystem::file_type type = boost::filesystem::regular_file, std::string_view filter = "*"sv)
{
- #ifdef WIN32
- HANDLE hFind;
- WIN32_FIND_DATAA findFileInfo;
- std::string directory;
-
- directory = dirpath + "/" + filter;
-
- hFind = FindFirstFileA(directory.c_str(), &findFileInfo);
-
- if (hFind == INVALID_HANDLE_VALUE)
+ boost::system::error_code ec;
+ boost::filesystem::directory_iterator dirItr(dirpath, ec);
+ if (ec)
return LISTFILE_DIRECTORY_NOT_FOUND;
- do
- {
- if (strcmp(findFileInfo.cFileName, ".") != 0 && strcmp(findFileInfo.cFileName, "..") != 0)
- fileList.push_back(std::string(findFileInfo.cFileName));
- }
- while (FindNextFileA(hFind, &findFileInfo));
- FindClose(hFind);
+ for (boost::filesystem::directory_entry const& dirEntry : dirItr)
+ {
+ if (dirEntry.status(ec).type() != type || ec)
+ continue;
- #else
- const char *p = dirpath.c_str();
- DIR * dirp = opendir(p);
- struct dirent * dp;
+ std::string fileName = dirEntry.path().filename().string();
+ if (!matchWildcardFilter(filter, fileName))
+ continue;
- while (dirp)
- {
- errno = 0;
- if ((dp = readdir(dirp)) != nullptr)
- {
- if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 && matchWildcardFilter(filter.c_str(), dp->d_name))
- fileList.push_back(std::string(dp->d_name));
- }
- else
- break;
+ fileList.push_back(std::move(fileName));
}
- if (dirp)
- closedir(dirp);
- else
- return LISTFILE_DIRECTORY_NOT_FOUND;
- #endif
-
return LISTFILE_OK;
}
diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp
index af4eb816626..452c63855fc 100644
--- a/src/tools/mmaps_generator/PathGenerator.cpp
+++ b/src/tools/mmaps_generator/PathGenerator.cpp
@@ -87,9 +87,10 @@ void SetupLogging(Trinity::Asio::IoContext* ioContext)
log->CreateLoggerFromConfigLine("Logger.maps.mmapgen", "2,Console"); // LOG_LEVEL_DEBUG | Console appender
}
-bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
+bool checkDirectories(boost::filesystem::path const& inputDirectory, boost::filesystem::path const& outputDirectory,
+ bool debugOutput, std::vector<std::string>& dbcLocales)
{
- if (MMAP::getDirContents(dbcLocales, "dbc") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dbcLocales.empty())
+ if (MMAP::getDirContents(dbcLocales, inputDirectory / "dbc", boost::filesystem::directory_file) == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dbcLocales.empty())
{
TC_LOG_ERROR("tool.mmapgen", "'dbc' directory is empty or does not exist");
return false;
@@ -97,39 +98,32 @@ bool checkDirectories(bool debugOutput, std::vector<std::string>& dbcLocales)
std::vector<std::string> dirFiles;
- if (MMAP::getDirContents(dirFiles, "maps") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
+ if (MMAP::getDirContents(dirFiles, inputDirectory / "maps") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
TC_LOG_ERROR("tool.mmapgen", "'maps' directory is empty or does not exist");
return false;
}
dirFiles.clear();
- if (MMAP::getDirContents(dirFiles, "vmaps/0000", "*.vmtree") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
+ if (MMAP::getDirContents(dirFiles, inputDirectory / "vmaps" / "0000", boost::filesystem::regular_file, "*.vmtree") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
TC_LOG_ERROR("tool.mmapgen", "'vmaps' directory is empty or does not exist");
return false;
}
- dirFiles.clear();
- if (MMAP::getDirContents(dirFiles, "mmaps") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND)
+ boost::system::error_code ec;
+ if (!boost::filesystem::create_directories(outputDirectory / "mmaps", ec) && ec)
{
- if (!boost::filesystem::create_directory("mmaps"))
- {
- TC_LOG_ERROR("tool.mmapgen", "'mmaps' directory does not exist and failed to create it");
- return false;
- }
+ TC_LOG_ERROR("tool.mmapgen", "'mmaps' directory does not exist and failed to create it");
+ return false;
}
- dirFiles.clear();
if (debugOutput)
{
- if (MMAP::getDirContents(dirFiles, "meshes") == MMAP::LISTFILE_DIRECTORY_NOT_FOUND)
+ if (!boost::filesystem::create_directories(outputDirectory / "meshes", ec) && ec)
{
- if (!boost::filesystem::create_directory("meshes"))
- {
- TC_LOG_ERROR("tool.mmapgen", "'meshes' directory does not exist and failed to create it (no place to put debugOutput files)");
- return false;
- }
+ TC_LOG_ERROR("tool.mmapgen", "'meshes' directory does not exist and failed to create it (no place to put debugOutput files)");
+ return false;
}
}
@@ -144,21 +138,23 @@ int finish(char const* message, int returnValue)
}
bool handleArgs(int argc, char** argv,
- int &mapnum,
- int &tileX,
- int &tileY,
+ int& mapnum,
+ int& tileX,
+ int& tileY,
Optional<float>& maxAngle,
Optional<float>& maxAngleNotSteep,
- bool &skipLiquid,
- bool &skipContinents,
- bool &skipJunkMaps,
- bool &skipBattlegrounds,
- bool &debugOutput,
- bool &silent,
- bool &bigBaseUnit,
- char* &offMeshInputPath,
- char* &file,
- unsigned int& threads)
+ bool& skipLiquid,
+ bool& skipContinents,
+ bool& skipJunkMaps,
+ bool& skipBattlegrounds,
+ bool& debugOutput,
+ bool& silent,
+ bool& bigBaseUnit,
+ char const*& offMeshInputPath,
+ char const*& file,
+ unsigned int& threads,
+ boost::filesystem::path& inputDirectory,
+ boost::filesystem::path& outputDirectory)
{
char* param = nullptr;
[[maybe_unused]] bool allowDebug = false;
@@ -314,6 +310,22 @@ bool handleArgs(int argc, char** argv,
offMeshInputPath = param;
}
+ else if (strcmp(argv[i], "--input") == 0)
+ {
+ param = argv[++i];
+ if (!param)
+ return false;
+
+ inputDirectory = param;
+ }
+ else if (strcmp(argv[i], "--output") == 0)
+ {
+ param = argv[++i];
+ if (!param)
+ return false;
+
+ outputDirectory = param;
+ }
else if (strcmp(argv[i], "--allowDebug") == 0)
{
allowDebug = true;
@@ -349,11 +361,11 @@ bool handleArgs(int argc, char** argv,
return true;
}
-std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale, bool silent, int32 errorExitCode)
+std::unordered_map<uint32, uint8> LoadLiquid(boost::filesystem::path const& inputDirectory, std::string const& locale, bool silent, int32 errorExitCode)
{
DB2FileLoader liquidDb2;
std::unordered_map<uint32, uint8> liquidData;
- DB2FileSystemSource liquidTypeSource((boost::filesystem::path("dbc") / locale / "LiquidType.db2").string());
+ DB2FileSystemSource liquidTypeSource((inputDirectory / "dbc" / locale / "LiquidType.db2").string());
try
{
liquidDb2.Load(&liquidTypeSource, &LiquidTypeLoadInfo::Instance);
@@ -377,10 +389,10 @@ std::unordered_map<uint32, uint8> LoadLiquid(std::string const& locale, bool sil
return liquidData;
}
-void LoadMap(std::string const& locale, bool silent, int32 errorExitCode)
+void LoadMap(boost::filesystem::path const& inputDirectory, std::string const& locale, bool silent, int32 errorExitCode)
{
DB2FileLoader mapDb2;
- DB2FileSystemSource mapSource((boost::filesystem::path("dbc") / locale / "Map.db2").string());
+ DB2FileSystemSource mapSource((inputDirectory / "dbc" / locale / "Map.db2").string());
try
{
mapDb2.Load(&mapSource, &MapLoadInfo::Instance);
@@ -442,13 +454,16 @@ int main(int argc, char** argv)
debugOutput = false,
silent = false,
bigBaseUnit = false;
- char* offMeshInputPath = nullptr;
- char* file = nullptr;
+ char const* offMeshInputPath = nullptr;
+ char const* file = nullptr;
+ boost::filesystem::path inputDirectory = boost::filesystem::current_path();
+ boost::filesystem::path outputDirectory = boost::filesystem::current_path();
bool validParam = handleArgs(argc, argv, mapnum,
tileX, tileY, maxAngle, maxAngleNotSteep,
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
- debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
+ debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads,
+ inputDirectory, outputDirectory);
if (!validParam)
return silent ? -1 : finish("You have specified invalid parameters", -1);
@@ -466,14 +481,14 @@ int main(int argc, char** argv)
}
std::vector<std::string> dbcLocales;
- if (!checkDirectories(debugOutput, dbcLocales))
+ if (!checkDirectories(inputDirectory, outputDirectory, debugOutput, dbcLocales))
return silent ? -3 : finish("Press ENTER to close...", -3);
- _liquidTypes = LoadLiquid(dbcLocales[0], silent, -5);
+ _liquidTypes = LoadLiquid(inputDirectory, dbcLocales[0], silent, -5);
- LoadMap(dbcLocales[0], silent, -4);
+ LoadMap(inputDirectory, dbcLocales[0], silent, -4);
- MMAP::MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps,
+ MMAP::MapBuilder builder(inputDirectory, outputDirectory, maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath, threads);
uint32 start = getMSTime();
diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp
index 241a724a46f..e93f2b5a57d 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.cpp
+++ b/src/tools/mmaps_generator/TerrainBuilder.cpp
@@ -29,7 +29,11 @@
namespace MMAP
{
- TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
+ TerrainBuilder::TerrainBuilder(boost::filesystem::path const& inputDirectory, bool skipLiquid) :
+ m_inputDirectory(inputDirectory),
+ m_skipLiquid (skipLiquid)
+ {
+ }
/**************************************************************************/
void TerrainBuilder::getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc)
@@ -79,7 +83,7 @@ namespace MMAP
/**************************************************************************/
bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager, Spot portion)
{
- std::string mapFileName = Trinity::StringFormat("maps/{:04}_{:02}_{:02}.map", mapID, tileX, tileY);
+ std::string mapFileName = Trinity::StringFormat("{}/maps/{:04}_{:02}_{:02}.map", m_inputDirectory.generic_string(), mapID, tileX, tileY);
auto mapFile = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(mapFileName.c_str(), "rb"));
if (!mapFile)
@@ -87,7 +91,7 @@ namespace MMAP
int32 parentMapId = vmapManager->getParentMapId(mapID);
while (!mapFile && parentMapId != -1)
{
- mapFileName = Trinity::StringFormat("maps/{:04}_{:02}_{:02}.map", parentMapId, tileX, tileY);
+ mapFileName = Trinity::StringFormat("{}/maps/{:04}_{:02}_{:02}.map", m_inputDirectory.generic_string(), parentMapId, tileX, tileY);
mapFile.reset(fopen(mapFileName.c_str(), "rb"));
parentMapId = vmapManager->getParentMapId(parentMapId);
}
@@ -563,7 +567,7 @@ namespace MMAP
/**************************************************************************/
bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager)
{
- VMAP::LoadResult result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
+ VMAP::LoadResult result = vmapManager->loadMap((m_inputDirectory / "vmaps").string(), mapID, tileX, tileY);
if (result != VMAP::LoadResult::Success)
return false;
@@ -588,106 +592,109 @@ namespace MMAP
// now we have a model to add to the meshdata
retval = true;
- std::vector<VMAP::GroupModel> const& groupModels = worldModel->getGroupModels();
-
- // all M2s need to have triangle indices reversed
- bool isM2 = worldModel->IsM2();
-
- // transform data
- float scale = instance.iScale;
- G3D::Matrix3 const& rotation = instance.GetInvRot();
G3D::Vector3 position = instance.iPos;
position.x -= 32 * GRID_SIZE;
position.y -= 32 * GRID_SIZE;
+ loadVMapModel(worldModel, position, instance.GetInvRot(), instance.iScale, meshData, vmapManager);
+ }
+
+ return retval;
+ }
+
+ void TerrainBuilder::loadVMapModel(VMAP::WorldModel const* worldModel, G3D::Vector3 const& position, G3D::Matrix3 const& rotation, float scale,
+ MeshData& meshData, VMAP::VMapManager* vmapManager)
+ {
+ std::vector<VMAP::GroupModel> const& groupModels = worldModel->getGroupModels();
- for (std::vector<VMAP::GroupModel>::const_iterator it = groupModels.begin(); it != groupModels.end(); ++it)
+ // all M2s need to have triangle indices reversed
+ bool isM2 = worldModel->IsM2();
+
+ // transform data
+ for (std::vector<VMAP::GroupModel>::const_iterator it = groupModels.begin(); it != groupModels.end(); ++it)
+ {
+ // first handle collision mesh
+ int offset = meshData.solidVerts.size() / 3;
+ transformVertices(it->GetVertices(), meshData.solidVerts, scale, rotation, position);
+ copyIndices(it->GetTriangles(), meshData.solidTris, offset, isM2);
+
+ // now handle liquid data
+ VMAP::WmoLiquid const* liquid = it->GetLiquid();
+ if (liquid && liquid->GetFlagsStorage())
{
- // first handle collision mesh
- int offset = meshData.solidVerts.size() / 3;
- transformVertices(it->GetVertices(), meshData.solidVerts, scale, rotation, position);
- copyIndices(it->GetTriangles(), meshData.solidTris, offset, isM2);
-
- // now handle liquid data
- VMAP::WmoLiquid const* liquid = it->GetLiquid();
- if (liquid && liquid->GetFlagsStorage())
+ uint32 tilesX, tilesY;
+ G3D::Vector3 corner;
+ liquid->getPosInfo(tilesX, tilesY, corner);
+ uint32 vertsX = tilesX + 1;
+ uint32 vertsY = tilesY + 1;
+ uint8 const* flags = liquid->GetFlagsStorage();
+ float const* data = liquid->GetHeightStorage();
+ uint8 type = NAV_AREA_EMPTY;
+
+ // convert liquid type to NavTerrain
+ EnumFlag<map_liquidHeaderTypeFlags> liquidFlags = map_liquidHeaderTypeFlags(vmapManager->GetLiquidFlagsPtr(liquid->GetType()));
+ if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Water | map_liquidHeaderTypeFlags::Ocean))
+ type = NAV_AREA_WATER;
+ else if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Magma | map_liquidHeaderTypeFlags::Slime))
+ type = NAV_AREA_MAGMA_SLIME;
+
+ // indexing is weird...
+ // after a lot of trial and error, this is what works:
+ // vertex = y*vertsX+x
+ // tile = x*tilesY+y
+ // flag = y*tilesY+x
+
+ uint32 liqOffset = meshData.liquidVerts.size() / 3;
+ meshData.liquidVerts.resize(meshData.liquidVerts.size() + vertsX * vertsY * 3);
+ float* liquidVerts = meshData.liquidVerts.data();
+ for (uint32 x = 0; x < vertsX; ++x)
{
- uint32 tilesX, tilesY;
- G3D::Vector3 corner;
- liquid->getPosInfo(tilesX, tilesY, corner);
- uint32 vertsX = tilesX + 1;
- uint32 vertsY = tilesY + 1;
- uint8 const* flags = liquid->GetFlagsStorage();
- float const* data = liquid->GetHeightStorage();
- uint8 type = NAV_AREA_EMPTY;
-
- // convert liquid type to NavTerrain
- EnumFlag<map_liquidHeaderTypeFlags> liquidFlags = map_liquidHeaderTypeFlags(vmapManager->GetLiquidFlagsPtr(liquid->GetType()));
- if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Water | map_liquidHeaderTypeFlags::Ocean))
- type = NAV_AREA_WATER;
- else if (liquidFlags.HasFlag(map_liquidHeaderTypeFlags::Magma | map_liquidHeaderTypeFlags::Slime))
- type = NAV_AREA_MAGMA_SLIME;
-
- // indexing is weird...
- // after a lot of trial and error, this is what works:
- // vertex = y*vertsX+x
- // tile = x*tilesY+y
- // flag = y*tilesY+x
-
- uint32 liqOffset = meshData.liquidVerts.size() / 3;
- meshData.liquidVerts.resize(meshData.liquidVerts.size() + vertsX * vertsY * 3);
- float* liquidVerts = meshData.liquidVerts.data();
- for (uint32 x = 0; x < vertsX; ++x)
+ for (uint32 y = 0; y < vertsY; ++y)
{
- for (uint32 y = 0; y < vertsY; ++y)
- {
- G3D::Vector3 vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y * vertsX + x]);
- vert = vert * rotation * scale + position;
- vert.x *= -1.f;
- vert.y *= -1.f;
- liquidVerts[(liqOffset + x * vertsY + y) * 3 + 0] = vert.y;
- liquidVerts[(liqOffset + x * vertsY + y) * 3 + 1] = vert.z;
- liquidVerts[(liqOffset + x * vertsY + y) * 3 + 2] = vert.x;
- }
+ G3D::Vector3 vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y * vertsX + x]);
+ vert = vert * rotation * scale + position;
+ vert.x *= -1.f;
+ vert.y *= -1.f;
+ liquidVerts[(liqOffset + x * vertsY + y) * 3 + 0] = vert.y;
+ liquidVerts[(liqOffset + x * vertsY + y) * 3 + 1] = vert.z;
+ liquidVerts[(liqOffset + x * vertsY + y) * 3 + 2] = vert.x;
}
+ }
- std::size_t liquidSquares = 0;
- for (uint32 x = 0; x < tilesX; ++x)
+ std::size_t liquidSquares = 0;
+ for (uint32 x = 0; x < tilesX; ++x)
+ {
+ for (uint32 y = 0; y < tilesY; ++y)
{
- for (uint32 y = 0; y < tilesY; ++y)
+ if ((flags[x + y * tilesX] & 0x0f) != 0x0f)
{
- if ((flags[x + y * tilesX] & 0x0f) != 0x0f)
- {
- uint32 square = x * tilesY + y;
- int idx1 = square + x;
- int idx2 = square + 1 + x;
- int idx3 = square + tilesY + 1 + 1 + x;
- int idx4 = square + tilesY + 1 + x;
-
- std::size_t liquidTriOffset = meshData.liquidTris.size();
- meshData.liquidTris.resize(liquidTriOffset + 6);
- int* liquidTris = meshData.liquidTris.data() + liquidTriOffset;
-
- // top triangle
- liquidTris[0] = idx2 + liqOffset;
- liquidTris[1] = idx1 + liqOffset;
- liquidTris[2] = idx3 + liqOffset;
-
- // bottom triangle
- liquidTris[3] = idx3 + liqOffset;
- liquidTris[4] = idx1 + liqOffset;
- liquidTris[5] = idx4 + liqOffset;
-
- ++liquidSquares;
- }
+ uint32 square = x * tilesY + y;
+ int idx1 = square + x;
+ int idx2 = square + 1 + x;
+ int idx3 = square + tilesY + 1 + 1 + x;
+ int idx4 = square + tilesY + 1 + x;
+
+ std::size_t liquidTriOffset = meshData.liquidTris.size();
+ meshData.liquidTris.resize(liquidTriOffset + 6);
+ int* liquidTris = meshData.liquidTris.data() + liquidTriOffset;
+
+ // top triangle
+ liquidTris[0] = idx2 + liqOffset;
+ liquidTris[1] = idx1 + liqOffset;
+ liquidTris[2] = idx3 + liqOffset;
+
+ // bottom triangle
+ liquidTris[3] = idx3 + liqOffset;
+ liquidTris[4] = idx1 + liqOffset;
+ liquidTris[5] = idx4 + liqOffset;
+
+ ++liquidSquares;
}
}
-
- meshData.liquidType.resize(meshData.liquidType.size() + liquidSquares * 2, type);
}
+
+ meshData.liquidType.resize(meshData.liquidType.size() + liquidSquares * 2, type);
}
}
-
- return retval;
}
/**************************************************************************/
@@ -793,7 +800,7 @@ namespace MMAP
meshData.offMeshConnections.push_back(offMeshConnection.To[2]);
meshData.offMeshConnections.push_back(offMeshConnection.To[0]);
- meshData.offMeshConnectionDirs.push_back(offMeshConnection.Bidirectional ? 1 : 0);
+ meshData.offMeshConnectionDirs.push_back(offMeshConnection.ConnectionFlags & OFFMESH_CONNECTION_FLAG_BIDIRECTIONAL);
meshData.offMeshConnectionRads.push_back(offMeshConnection.Radius); // agent size equivalent
// can be used same way as polygon flags
meshData.offMeshConnectionsAreas.push_back(offMeshConnection.AreaId);
diff --git a/src/tools/mmaps_generator/TerrainBuilder.h b/src/tools/mmaps_generator/TerrainBuilder.h
index c1c01e2d0db..65ebe4508a9 100644
--- a/src/tools/mmaps_generator/TerrainBuilder.h
+++ b/src/tools/mmaps_generator/TerrainBuilder.h
@@ -18,8 +18,10 @@
#ifndef _MMAP_TERRAIN_BUILDER_H
#define _MMAP_TERRAIN_BUILDER_H
+#include "MMapDefines.h"
#include "WorldModel.h"
#include <G3D/Vector3.h>
+#include <boost/filesystem/path.hpp>
namespace VMAP
{
@@ -60,19 +62,6 @@ namespace MMAP
// contrib/extractor/system.cpp
// src/game/Map.cpp
- struct OffMeshData
- {
- uint32 MapId;
- uint32 TileX;
- uint32 TileY;
- float From[3];
- float To[3];
- bool Bidirectional;
- float Radius;
- uint8 AreaId;
- uint16 Flags;
- };
-
struct MeshData
{
std::vector<float> solidVerts;
@@ -93,10 +82,12 @@ namespace MMAP
class TerrainBuilder
{
public:
- explicit TerrainBuilder(bool skipLiquid);
+ explicit TerrainBuilder(boost::filesystem::path const& inputDirectory, bool skipLiquid);
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager);
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, VMAP::VMapManager* vmapManager);
+ void loadVMapModel(VMAP::WorldModel const* worldModel, G3D::Vector3 const& position, G3D::Matrix3 const& rotation, float scale,
+ MeshData& meshData, VMAP::VMapManager* vmapManager);
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData& meshData, std::vector<OffMeshData> const& offMeshConnections);
bool usesLiquids() const { return !m_skipLiquid; }
@@ -114,6 +105,8 @@ namespace MMAP
/// Sets loop variables for selecting only certain parts of a map's terrain
static void getLoopVars(Spot portion, int& loopStart, int& loopEnd, int& loopInc);
+ boost::filesystem::path m_inputDirectory;
+
/// Controls whether liquids are loaded
bool m_skipLiquid;
diff --git a/src/tools/mmaps_generator/TileBuilder.cpp b/src/tools/mmaps_generator/TileBuilder.cpp
index eff2f7bcf59..5654a14183c 100644
--- a/src/tools/mmaps_generator/TileBuilder.cpp
+++ b/src/tools/mmaps_generator/TileBuilder.cpp
@@ -69,13 +69,15 @@ namespace MMAP
int TILES_PER_MAP;
};
- TileBuilder::TileBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
+ TileBuilder::TileBuilder(boost::filesystem::path const& inputDirectory, boost::filesystem::path const& outputDirectory,
+ Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid, bool bigBaseUnit, bool debugOutput, std::vector<OffMeshData> const* offMeshConnections) :
+ m_outputDirectory(outputDirectory),
m_maxWalkableAngle(maxWalkableAngle),
m_maxWalkableAngleNotSteep(maxWalkableAngleNotSteep),
m_bigBaseUnit(bigBaseUnit),
m_debugOutput(debugOutput),
- m_terrainBuilder(skipLiquid),
+ m_terrainBuilder(inputDirectory, skipLiquid),
m_rcContext(false),
m_offMeshConnections(offMeshConnections)
{
@@ -123,9 +125,8 @@ namespace MMAP
// gather all mesh data for final data check, and bounds calculation
std::vector<float> allVerts(meshData.liquidVerts.size() + meshData.solidVerts.size());
- auto allVertsOutput = allVerts.begin();
- allVertsOutput = std::ranges::copy(meshData.liquidVerts, allVertsOutput).out;
- allVertsOutput = std::ranges::copy(meshData.solidVerts, allVertsOutput).out;
+ std::ranges::copy(meshData.liquidVerts, allVerts.begin());
+ std::ranges::copy(meshData.solidVerts, allVerts.begin() + std::ssize(meshData.liquidVerts));
// get bounds of current tile
float bmin[3], bmax[3];
@@ -145,7 +146,7 @@ namespace MMAP
/**************************************************************************/
TileBuilder::TileResult TileBuilder::buildMoveMapTile(uint32 mapID, uint32 tileX, uint32 tileY,
MeshData& meshData, float (&bmin)[3], float (&bmax)[3],
- dtNavMeshParams const* navMeshParams)
+ dtNavMeshParams const* navMeshParams, std::string_view fileNameSuffix)
{
// console output
std::string tileString = Trinity::StringFormat("[Map {:04}] [{:02},{:02}]:", mapID, tileX, tileY);
@@ -375,7 +376,10 @@ namespace MMAP
// will hold final navmesh
unsigned char* navData = nullptr;
- auto debugOutputWriter = Trinity::make_unique_ptr_with_deleter(m_debugOutput ? &iv : nullptr, [=, borderSize = static_cast<unsigned short>(config.borderSize), &meshData](IntermediateValues* intermediate)
+ auto debugOutputWriter = Trinity::make_unique_ptr_with_deleter(m_debugOutput ? &iv : nullptr,
+ [borderSize = static_cast<unsigned short>(config.borderSize),
+ outputDir = &m_outputDirectory, fileNameSuffix,
+ mapID, tileX, tileY, &meshData](IntermediateValues* intermediate)
{
// restore padding so that the debug visualization is correct
for (std::ptrdiff_t i = 0; i < intermediate->polyMesh->nverts; ++i)
@@ -385,8 +389,8 @@ namespace MMAP
v[2] += borderSize;
}
- intermediate->generateObjFile(mapID, tileX, tileY, meshData);
- intermediate->writeIV(mapID, tileX, tileY);
+ intermediate->generateObjFile(*outputDir, fileNameSuffix, mapID, tileX, tileY, meshData);
+ intermediate->writeIV(*outputDir, fileNameSuffix, mapID, tileX, tileY);
});
// these values are checked within dtCreateNavMeshData - handle them here
@@ -438,7 +442,8 @@ namespace MMAP
return tileResult;
}
- void TileBuilder::saveMoveMapTileToFile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh, TileResult const& tileResult)
+ void TileBuilder::saveMoveMapTileToFile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh,
+ TileResult const& tileResult, std::string_view fileNameSuffix)
{
dtTileRef tileRef = 0;
auto navMeshTile = Trinity::make_unique_ptr_with_deleter<dtTileRef*>(nullptr, [navMesh](dtTileRef const* ref)
@@ -462,7 +467,7 @@ namespace MMAP
}
// file output
- std::string fileName = Trinity::StringFormat("mmaps/{:04}{:02}{:02}.mmtile", mapID, tileX, tileY);
+ std::string fileName = Trinity::StringFormat("{}/mmaps/{:04}_{:02}_{:02}{}.mmtile", m_outputDirectory.generic_string(), mapID, tileX, tileY, fileNameSuffix);
auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(), "wb"));
if (!file)
{
@@ -483,11 +488,11 @@ namespace MMAP
}
/**************************************************************************/
- void TileBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax)
+ void TileBuilder::getTileBounds(uint32 tileX, uint32 tileY, float const* verts, std::size_t vertCount, float* bmin, float* bmax)
{
// this is for elevation
if (verts && vertCount)
- rcCalcBounds(verts, vertCount, bmin, bmax);
+ rcCalcBounds(verts, int(vertCount), bmin, bmax);
else
{
bmin[1] = FLT_MIN;
diff --git a/src/tools/mmaps_generator/TileBuilder.h b/src/tools/mmaps_generator/TileBuilder.h
index f533a3d1afa..f7c4806c515 100644
--- a/src/tools/mmaps_generator/TileBuilder.h
+++ b/src/tools/mmaps_generator/TileBuilder.h
@@ -18,7 +18,7 @@
#ifndef TRINITYCORE_TILE_BUILDER_H
#define TRINITYCORE_TILE_BUILDER_H
-#include "Define.h"
+#include "Common.h"
#include "Memory.h"
#include "StringFormat.h"
#include "TerrainBuilder.h"
@@ -34,7 +34,9 @@ using detour_unique_ptr = std::unique_ptr<unsigned char, decltype(Trinity::uniqu
class TileBuilder
{
public:
- TileBuilder(Optional<float> maxWalkableAngle,
+ TileBuilder(boost::filesystem::path const& inputDirectory,
+ boost::filesystem::path const& outputDirectory,
+ Optional<float> maxWalkableAngle,
Optional<float> maxWalkableAngleNotSteep,
bool skipLiquid,
bool bigBaseUnit,
@@ -63,14 +65,16 @@ public:
MeshData& meshData,
float (&bmin)[3],
float (&bmax)[3],
- dtNavMeshParams const* navMeshParams);
+ dtNavMeshParams const* navMeshParams,
+ std::string_view fileNameSuffix = ""sv);
- void saveMoveMapTileToFile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh, TileResult const& tileResult);
+ void saveMoveMapTileToFile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh,
+ TileResult const& tileResult, std::string_view fileNameSuffix = ""sv);
virtual bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY) const;
static void getTileBounds(uint32 tileX, uint32 tileY,
- float* verts, int vertCount,
+ float const* verts, std::size_t vertCount,
float* bmin, float* bmax);
rcConfig GetMapSpecificConfig(uint32 mapID, float const (&bmin)[3], float const (&bmax)[3], TileConfig const& tileConfig) const;
@@ -79,7 +83,8 @@ public:
virtual void OnTileDone() { }
-private:
+protected:
+ boost::filesystem::path m_outputDirectory;
Optional<float> m_maxWalkableAngle;
Optional<float> m_maxWalkableAngleNotSteep;
bool m_bigBaseUnit;