diff options
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/mmaps_generator/MapBuilder.cpp | 38 | ||||
-rw-r--r-- | src/tools/mmaps_generator/MapBuilder.h | 7 | ||||
-rw-r--r-- | src/tools/mmaps_generator/PathCommon.h | 2 | ||||
-rw-r--r-- | src/tools/mmaps_generator/PathGenerator.cpp | 61 | ||||
-rw-r--r-- | src/tools/mmaps_generator/TerrainBuilder.cpp | 60 |
5 files changed, 122 insertions, 46 deletions
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 089e81970c..dcf7f05c50 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -26,7 +26,7 @@ namespace MMAP { - MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid, + MapBuilder::MapBuilder(Optional<float> maxWalkableAngle, Optional<float> maxWalkableAngleNotSteep, bool skipLiquid, bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds, bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath) : @@ -36,6 +36,7 @@ namespace MMAP m_skipJunkMaps (skipJunkMaps), m_skipBattlegrounds (skipBattlegrounds), m_maxWalkableAngle (maxWalkableAngle), + m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep), m_bigBaseUnit (bigBaseUnit), m_mapid (mapid), m_totalTiles (0u), @@ -587,9 +588,17 @@ namespace MMAP } // mark all walkable tiles, both liquids and solids + + /* we want to have triangles with slope less than walkableSlopeAngleNotSteep (<= 55) to have NAV_AREA_GROUND + * and with slope between walkableSlopeAngleNotSteep and walkableSlopeAngle (55 < .. <= 70) to have NAV_AREA_GROUND_STEEP. + * we achieve this using recast API: memset everything to NAV_AREA_GROUND_STEEP, call rcClearUnwalkableTriangles with 70 so + * any area above that will get RC_NULL_AREA (unwalkable), then call rcMarkWalkableTriangles with 55 to set NAV_AREA_GROUND + * on anything below 55 . Players and idle Creatures can use NAV_AREA_GROUND, while Creatures in combat can use NAV_AREA_GROUND_STEEP. + */ unsigned char* triFlags = new unsigned char[tTriCount]; - memset(triFlags, NAV_GROUND, tTriCount * sizeof(unsigned char)); + memset(triFlags, NAV_AREA_GROUND_STEEP, tTriCount * sizeof(unsigned char)); rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags); + rcMarkWalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngleNotSteep, tVerts, tVertCount, tTris, tTriCount, triFlags, NAV_AREA_GROUND); rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb); delete[] triFlags; @@ -597,6 +606,7 @@ namespace MMAP rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid); rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid); + // add liquid triangles rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb); // compact heightfield spans @@ -694,8 +704,15 @@ namespace MMAP // set polygons as walkable // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off for (int i = 0; i < iv.polyMesh->npolys; ++i) - if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA) - iv.polyMesh->flags[i] = iv.polyMesh->areas[i]; + { + if (uint8 area = iv.polyMesh->areas[i] & NAV_AREA_ALL_MASK) + { + if (area >= NAV_AREA_MIN_VALUE) + iv.polyMesh->flags[i] = 1 << (NAV_AREA_MAX_VALUE - area); + else + iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future + } + } // setup mesh parameters dtNavMeshCreateParams params; @@ -984,7 +1001,10 @@ namespace MMAP config.maxVertsPerPoly = DT_VERTS_PER_POLYGON; config.cs = tileConfig.BASE_UNIT_DIM; config.ch = tileConfig.BASE_UNIT_DIM; - config.walkableSlopeAngle = m_maxWalkableAngle; + // Keeping these 2 slope angles the same reduces a lot the number of polys. + // 55 should be the minimum, maybe 70 is ok (keep in mind blink uses mmaps), 85 is too much for players + config.walkableSlopeAngle = m_maxWalkableAngle ? *m_maxWalkableAngle : 55; + config.walkableSlopeAngleNotSteep = m_maxWalkableAngleNotSteep ? *m_maxWalkableAngleNotSteep : 55; config.tileSize = tileConfig.VERTEX_PER_TILE; config.walkableRadius = m_bigBaseUnit ? 1 : 2; config.borderSize = config.walkableRadius + 3; @@ -992,7 +1012,7 @@ namespace MMAP config.walkableHeight = m_bigBaseUnit ? 3 : 6; // a value >= 3|6 allows npcs to walk over some fences // a value >= 4|8 allows npcs to walk over all fences - config.walkableClimb = m_bigBaseUnit ? 4 : 8; + config.walkableClimb = m_bigBaseUnit ? 3 : 6; config.minRegionArea = rcSqr(60); config.mergeRegionArea = rcSqr(50); config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons) @@ -1003,8 +1023,14 @@ namespace MMAP { // Blade's Edge Arena case 562: + // This allows to walk on the ropes to the pillars config.walkableRadius = 0; break; + // Blackfathom Deeps + case 48: + // Reduce the chance to have underground levels + config.ch *= 2; + break; default: break; } diff --git a/src/tools/mmaps_generator/MapBuilder.h b/src/tools/mmaps_generator/MapBuilder.h index d7c43a6460..239553891d 100644 --- a/src/tools/mmaps_generator/MapBuilder.h +++ b/src/tools/mmaps_generator/MapBuilder.h @@ -26,6 +26,7 @@ #include <vector> #include "IntermediateValues.h" +#include "Optional.h" #include "TerrainBuilder.h" #include "DetourNavMesh.h" @@ -96,7 +97,8 @@ namespace MMAP class MapBuilder { public: - MapBuilder(float maxWalkableAngle = 60.f, + MapBuilder(Optional<float> maxWalkableAngle, + Optional<float> maxWalkableAngleNotSteep, bool skipLiquid = false, bool skipContinents = false, bool skipJunkMaps = true, @@ -161,7 +163,8 @@ namespace MMAP bool m_skipJunkMaps; bool m_skipBattlegrounds; - float m_maxWalkableAngle; + Optional<float> m_maxWalkableAngle; + Optional<float> m_maxWalkableAngleNotSteep; bool m_bigBaseUnit; int32 m_mapid; diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h index 483b4783d9..36743eedb0 100644 --- a/src/tools/mmaps_generator/PathCommon.h +++ b/src/tools/mmaps_generator/PathCommon.h @@ -105,7 +105,7 @@ namespace MMAP errno = 0; if ((dp = readdir(dirp)) != nullptr) { - if (matchWildcardFilter(filter.c_str(), dp->d_name)) + if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 && matchWildcardFilter(filter.c_str(), dp->d_name)) fileList.emplace_back(dp->d_name); } else diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp index 62e10c13e6..1e59a3d201 100644 --- a/src/tools/mmaps_generator/PathGenerator.cpp +++ b/src/tools/mmaps_generator/PathGenerator.cpp @@ -18,9 +18,24 @@ #include "MapBuilder.h" #include "PathCommon.h" #include "Timer.h" +#include "DBCFileLoader.h" +#include "PathCommon.h" +#include <boost/filesystem.hpp> +#include <unordered_map> using namespace MMAP; +namespace +{ + std::unordered_map<uint32, uint8> _liquidTypes; +} + +uint32 GetLiquidFlags(uint32 liquidId) +{ + auto itr = _liquidTypes.find(liquidId); + return itr != _liquidTypes.end() ? (1 << itr->second) : 0; +} + bool checkDirectories(bool debugOutput) { std::vector<std::string> dirFiles; @@ -62,7 +77,8 @@ bool handleArgs(int argc, char** argv, int& mapnum, int& tileX, int& tileY, - float& maxAngle, + Optional<float>& maxAngle, + Optional<float>& maxAngleNotSteep, bool& skipLiquid, bool& skipContinents, bool& skipJunkMaps, @@ -84,11 +100,23 @@ bool handleArgs(int argc, char** argv, return false; float maxangle = atof(param); - if (maxangle <= 90.f && maxangle >= 45.f) + if (maxangle <= 90.f && maxangle >= 0.f) maxAngle = maxangle; else printf("invalid option for '--maxAngle', using default\n"); } + else if (strcmp(argv[i], "--maxAngleNotSteep") == 0) + { + param = argv[++i]; + if (!param) + return false; + + float maxangle = atof(param); + if (maxangle <= 90.f && maxangle >= 0.f) + maxAngleNotSteep = maxangle; + else + printf("invalid option for '--maxAngleNotSteep', using default\n"); + } else if (strcmp(argv[i], "--threads") == 0) { param = argv[++i]; @@ -238,12 +266,29 @@ int finish(const char* message, int returnValue) return returnValue; } +std::unordered_map<uint32, uint8> LoadLiquid() +{ + DBCFileLoader liquidDbc; + std::unordered_map<uint32, uint8> liquidData; + // format string doesnt matter as long as it has correct length (only used for mapping to structures in worldserver) + if (liquidDbc.Load((boost::filesystem::path("dbc") / "LiquidType.dbc").string().c_str(), "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + { + for (uint32 x = 0; x < liquidDbc.GetNumRows(); ++x) + { + DBCFileLoader::Record record = liquidDbc.getRecord(x); + liquidData[record.getUInt(0)] = record.getUInt(3); + } + } + + return liquidData; +} + int main(int argc, char** argv) { unsigned int threads = std::thread::hardware_concurrency(); int mapnum = -1; - float maxAngle = 60.0f; int tileX = -1, tileY = -1; + Optional<float> maxAngle, maxAngleNotSteep; bool skipLiquid = false, skipContinents = false, skipJunkMaps = true, @@ -255,7 +300,7 @@ int main(int argc, char** argv) char* file = nullptr; bool validParam = handleArgs(argc, argv, mapnum, - tileX, tileY, maxAngle, + tileX, tileY, maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds, debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads); @@ -277,7 +322,13 @@ int main(int argc, char** argv) if (!checkDirectories(debugOutput)) return silent ? -3 : finish("Press ENTER to close...", -3); - MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps, + _liquidTypes = LoadLiquid(); + if (_liquidTypes.empty()) + { + return silent ? -5 : finish("Failed to load LiquidType.dbc", -5); + } + + MapBuilder builder(maxAngle, maxAngleNotSteep, skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath); uint32 start = getMSTime(); diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index d5e2a9a4c3..fa0581f98c 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -77,6 +77,8 @@ struct map_liquidHeader #define MAP_LIQUID_TYPE_DARK_WATER 0x10 #define MAP_LIQUID_TYPE_WMO_WATER 0x20 +uint32 GetLiquidFlags(uint32 liquidId); + namespace MMAP { @@ -392,31 +394,29 @@ namespace MMAP // if there is no liquid, don't use liquid if (!meshData.liquidVerts.size() || !ltriangles.size()) + { useLiquid = false; + } else { liquidType = getLiquidType(i, liquid_type); - switch (liquidType) + if (liquidType & MAP_LIQUID_TYPE_DARK_WATER) { - default: - useLiquid = false; - break; - case MAP_LIQUID_TYPE_WATER: - case MAP_LIQUID_TYPE_OCEAN: - // merge different types of water - liquidType = NAV_WATER; - break; - case MAP_LIQUID_TYPE_MAGMA: - liquidType = NAV_MAGMA; - break; - case MAP_LIQUID_TYPE_SLIME: - liquidType = NAV_SLIME; - break; - case MAP_LIQUID_TYPE_DARK_WATER: - // players should not be here, so logically neither should creatures - useTerrain = false; - useLiquid = false; - break; + // players should not be here, so logically neither should creatures + useTerrain = false; + useLiquid = false; + } + else if ((liquidType & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0) + { + liquidType = NAV_AREA_WATER; + } + else if ((liquidType & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0) + { + liquidType = NAV_AREA_MAGMA_SLIME; + } + else + { + useLiquid = false; } } @@ -719,21 +719,17 @@ namespace MMAP vertsY = tilesY + 1; uint8* flags = liquid->GetFlagsStorage(); float* data = liquid->GetHeightStorage(); - uint8 type = NAV_EMPTY; + uint8 type = NAV_AREA_EMPTY; // convert liquid type to NavTerrain - switch (liquid->GetType() & 3) + uint32 liquidFlags = GetLiquidFlags(liquid->GetType()); + if ((liquidFlags & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0) + { + type = NAV_AREA_WATER; + } + else if ((liquidFlags & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0) { - case 0: - case 1: - type = NAV_WATER; - break; - case 2: - type = NAV_MAGMA; - break; - case 3: - type = NAV_SLIME; - break; + type = NAV_AREA_MAGMA_SLIME; } // indexing is weird... |