feat(Core/Mmaps): Handle different slopes in mmaps and Add some more input parameters to improve (#10974)
This commit is contained in:
committed by
GitHub
parent
090cc5e2c6
commit
b544eb420e
+4
-1
@@ -224,6 +224,9 @@ struct rcConfig
|
|||||||
/// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
|
/// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
|
||||||
float walkableSlopeAngle;
|
float walkableSlopeAngle;
|
||||||
|
|
||||||
|
/// The maximum slope that is considered walkable but not steep. It should be lower/equal than walkableSlopeAngle. [Limits: 0 <= value < 90] [Units: Degrees]
|
||||||
|
float walkableSlopeAngleNotSteep;
|
||||||
|
|
||||||
/// Minimum floor to 'ceiling' height that will still allow the floor area to
|
/// Minimum floor to 'ceiling' height that will still allow the floor area to
|
||||||
/// be considered walkable. [Limit: >= 3] [Units: vx]
|
/// be considered walkable. [Limit: >= 3] [Units: vx]
|
||||||
int walkableHeight;
|
int walkableHeight;
|
||||||
@@ -810,7 +813,7 @@ bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int heigh
|
|||||||
/// @param[in] nt The number of triangles.
|
/// @param[in] nt The number of triangles.
|
||||||
/// @param[out] areas The triangle area ids. [Length: >= @p nt]
|
/// @param[out] areas The triangle area ids. [Length: >= @p nt]
|
||||||
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
|
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv,
|
||||||
const int* tris, int nt, unsigned char* areas);
|
const int* tris, int nt, unsigned char* areas, unsigned char areaType = RC_WALKABLE_AREA);
|
||||||
|
|
||||||
/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA.
|
/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA.
|
||||||
/// @ingroup recast
|
/// @ingroup recast
|
||||||
|
|||||||
+2
-2
@@ -334,7 +334,7 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
|
|||||||
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
||||||
const float* verts, int nv,
|
const float* verts, int nv,
|
||||||
const int* tris, int nt,
|
const int* tris, int nt,
|
||||||
unsigned char* areas)
|
unsigned char* areas, unsigned char areaType)
|
||||||
{
|
{
|
||||||
rcIgnoreUnused(ctx);
|
rcIgnoreUnused(ctx);
|
||||||
rcIgnoreUnused(nv);
|
rcIgnoreUnused(nv);
|
||||||
@@ -349,7 +349,7 @@ void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
|
|||||||
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
|
calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm);
|
||||||
// Check if the face is walkable.
|
// Check if the face is walkable.
|
||||||
if (norm[1] > walkableThr)
|
if (norm[1] > walkableThr)
|
||||||
areas[i] = RC_WALKABLE_AREA;
|
areas[i] = areaType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,18 +36,27 @@ static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) +
|
|||||||
sizeof(MmapTileHeader::usesLiquids) +
|
sizeof(MmapTileHeader::usesLiquids) +
|
||||||
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
|
sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields");
|
||||||
|
|
||||||
enum NavTerrain
|
enum NavArea
|
||||||
{
|
{
|
||||||
NAV_EMPTY = 0x00,
|
NAV_AREA_EMPTY = 0,
|
||||||
NAV_GROUND = 0x01,
|
// areas 1-60 will be used for destructible areas (currently skipped in vmaps, WMO with flag 1)
|
||||||
NAV_MAGMA = 0x02,
|
// ground is the highest value to make recast choose ground over water when merging surfaces very close to each other (shallow water would be walkable)
|
||||||
NAV_SLIME = 0x04,
|
NAV_AREA_GROUND_STEEP = 11,
|
||||||
NAV_WATER = 0x08,
|
NAV_AREA_GROUND = 10,
|
||||||
NAV_UNUSED1 = 0x10,
|
NAV_AREA_WATER = 9,
|
||||||
NAV_UNUSED2 = 0x20,
|
NAV_AREA_MAGMA_SLIME = 8, // don't need to differentiate between them
|
||||||
NAV_UNUSED3 = 0x40,
|
NAV_AREA_MAX_VALUE = NAV_AREA_GROUND_STEEP,
|
||||||
NAV_UNUSED4 = 0x80
|
NAV_AREA_MIN_VALUE = NAV_AREA_MAGMA_SLIME,
|
||||||
// we only have 8 bits
|
NAV_AREA_ALL_MASK = 0x3F // max allowed value
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NavTerrainFlag
|
||||||
|
{
|
||||||
|
NAV_EMPTY = 0x00,
|
||||||
|
NAV_GROUND_STEEP = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_GROUND_STEEP),
|
||||||
|
NAV_GROUND = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_GROUND),
|
||||||
|
NAV_WATER = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_WATER),
|
||||||
|
NAV_MAGMA_SLIME = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_MAGMA_SLIME)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -641,12 +641,12 @@ void PathGenerator::CreateFilter()
|
|||||||
|
|
||||||
// creatures don't take environmental damage
|
// creatures don't take environmental damage
|
||||||
if (creature->CanEnterWater())
|
if (creature->CanEnterWater())
|
||||||
includeFlags |= (NAV_WATER | NAV_MAGMA);
|
includeFlags |= (NAV_WATER | NAV_MAGMA_SLIME);
|
||||||
}
|
}
|
||||||
else // assume Player
|
else // assume Player
|
||||||
{
|
{
|
||||||
// perfect support not possible, just stay 'safe'
|
// perfect support not possible, just stay 'safe'
|
||||||
includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA);
|
includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA_SLIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
_filter.setIncludeFlags(includeFlags);
|
_filter.setIncludeFlags(includeFlags);
|
||||||
@@ -671,13 +671,17 @@ void PathGenerator::UpdateFilter()
|
|||||||
_filter.setIncludeFlags(includedFlags);
|
_filter.setIncludeFlags(includedFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (Creature const* _sourceCreature = _source->ToCreature())
|
if (Creature const* _sourceCreature = _source->ToCreature())
|
||||||
|
{
|
||||||
if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
|
if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
|
||||||
_filter.setIncludeFlags(_filter.getIncludeFlags() | NAV_GROUND_STEEP);*/
|
{
|
||||||
|
_filter.setIncludeFlags(_filter.getIncludeFlags() | NAV_GROUND_STEEP);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
|
NavTerrainFlag PathGenerator::GetNavTerrain(float x, float y, float z) const
|
||||||
{
|
{
|
||||||
LiquidData data;
|
LiquidData data;
|
||||||
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||||
@@ -691,7 +695,7 @@ NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
|
|||||||
return NAV_WATER;
|
return NAV_WATER;
|
||||||
case MAP_LIQUID_TYPE_MAGMA:
|
case MAP_LIQUID_TYPE_MAGMA:
|
||||||
case MAP_LIQUID_TYPE_SLIME:
|
case MAP_LIQUID_TYPE_SLIME:
|
||||||
return NAV_MAGMA;
|
return NAV_MAGMA_SLIME;
|
||||||
default:
|
default:
|
||||||
return NAV_GROUND;
|
return NAV_GROUND;
|
||||||
}
|
}
|
||||||
@@ -1139,9 +1143,9 @@ bool PathGenerator::IsWaterPath(Movement::PointsArray pathPoints) const
|
|||||||
// Check both start and end points, if they're both in water, then we can *safely* let the creature move
|
// Check both start and end points, if they're both in water, then we can *safely* let the creature move
|
||||||
for (uint32 i = 0; i < pathPoints.size(); ++i)
|
for (uint32 i = 0; i < pathPoints.size(); ++i)
|
||||||
{
|
{
|
||||||
NavTerrain terrain = GetNavTerrain(pathPoints[i].x, pathPoints[i].y, pathPoints[i].z);
|
NavTerrainFlag terrain = GetNavTerrain(pathPoints[i].x, pathPoints[i].y, pathPoints[i].z);
|
||||||
// One of the points is not in the water
|
// One of the points is not in the water
|
||||||
if (terrain != NAV_MAGMA && terrain != NAV_WATER)
|
if (terrain != NAV_MAGMA_SLIME && terrain != NAV_WATER)
|
||||||
{
|
{
|
||||||
waterPath = false;
|
waterPath = false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ class PathGenerator
|
|||||||
void BuildPointPath(float const* startPoint, float const* endPoint);
|
void BuildPointPath(float const* startPoint, float const* endPoint);
|
||||||
void BuildShortcut();
|
void BuildShortcut();
|
||||||
|
|
||||||
[[nodiscard]] NavTerrain GetNavTerrain(float x, float y, float z) const;
|
[[nodiscard]] NavTerrainFlag GetNavTerrain(float x, float y, float z) const;
|
||||||
void CreateFilter();
|
void CreateFilter();
|
||||||
void UpdateFilter();
|
void UpdateFilter();
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
namespace MMAP
|
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 skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
||||||
bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath) :
|
bool debugOutput, bool bigBaseUnit, int mapid, const char* offMeshFilePath) :
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@ namespace MMAP
|
|||||||
m_skipJunkMaps (skipJunkMaps),
|
m_skipJunkMaps (skipJunkMaps),
|
||||||
m_skipBattlegrounds (skipBattlegrounds),
|
m_skipBattlegrounds (skipBattlegrounds),
|
||||||
m_maxWalkableAngle (maxWalkableAngle),
|
m_maxWalkableAngle (maxWalkableAngle),
|
||||||
|
m_maxWalkableAngleNotSteep (maxWalkableAngleNotSteep),
|
||||||
m_bigBaseUnit (bigBaseUnit),
|
m_bigBaseUnit (bigBaseUnit),
|
||||||
m_mapid (mapid),
|
m_mapid (mapid),
|
||||||
m_totalTiles (0u),
|
m_totalTiles (0u),
|
||||||
@@ -587,9 +588,17 @@ namespace MMAP
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mark all walkable tiles, both liquids and solids
|
// 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];
|
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);
|
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);
|
rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb);
|
||||||
delete[] triFlags;
|
delete[] triFlags;
|
||||||
|
|
||||||
@@ -597,6 +606,7 @@ namespace MMAP
|
|||||||
rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
|
rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
|
||||||
rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid);
|
rcFilterWalkableLowHeightSpans(m_rcContext, tileCfg.walkableHeight, *tile.solid);
|
||||||
|
|
||||||
|
// add liquid triangles
|
||||||
rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
|
rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
|
||||||
|
|
||||||
// compact heightfield spans
|
// compact heightfield spans
|
||||||
@@ -694,8 +704,15 @@ namespace MMAP
|
|||||||
// set polygons as walkable
|
// set polygons as walkable
|
||||||
// TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
|
// TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off
|
||||||
for (int i = 0; i < iv.polyMesh->npolys; ++i)
|
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
|
// setup mesh parameters
|
||||||
dtNavMeshCreateParams params;
|
dtNavMeshCreateParams params;
|
||||||
@@ -984,7 +1001,10 @@ namespace MMAP
|
|||||||
config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
|
config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
|
||||||
config.cs = tileConfig.BASE_UNIT_DIM;
|
config.cs = tileConfig.BASE_UNIT_DIM;
|
||||||
config.ch = 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.tileSize = tileConfig.VERTEX_PER_TILE;
|
||||||
config.walkableRadius = m_bigBaseUnit ? 1 : 2;
|
config.walkableRadius = m_bigBaseUnit ? 1 : 2;
|
||||||
config.borderSize = config.walkableRadius + 3;
|
config.borderSize = config.walkableRadius + 3;
|
||||||
@@ -992,7 +1012,7 @@ namespace MMAP
|
|||||||
config.walkableHeight = m_bigBaseUnit ? 3 : 6;
|
config.walkableHeight = m_bigBaseUnit ? 3 : 6;
|
||||||
// a value >= 3|6 allows npcs to walk over some fences
|
// a value >= 3|6 allows npcs to walk over some fences
|
||||||
// a value >= 4|8 allows npcs to walk over all 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.minRegionArea = rcSqr(60);
|
||||||
config.mergeRegionArea = rcSqr(50);
|
config.mergeRegionArea = rcSqr(50);
|
||||||
config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
|
config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons)
|
||||||
@@ -1003,8 +1023,14 @@ namespace MMAP
|
|||||||
{
|
{
|
||||||
// Blade's Edge Arena
|
// Blade's Edge Arena
|
||||||
case 562:
|
case 562:
|
||||||
|
// This allows to walk on the ropes to the pillars
|
||||||
config.walkableRadius = 0;
|
config.walkableRadius = 0;
|
||||||
break;
|
break;
|
||||||
|
// Blackfathom Deeps
|
||||||
|
case 48:
|
||||||
|
// Reduce the chance to have underground levels
|
||||||
|
config.ch *= 2;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "IntermediateValues.h"
|
#include "IntermediateValues.h"
|
||||||
|
#include "Optional.h"
|
||||||
#include "TerrainBuilder.h"
|
#include "TerrainBuilder.h"
|
||||||
|
|
||||||
#include "DetourNavMesh.h"
|
#include "DetourNavMesh.h"
|
||||||
@@ -96,7 +97,8 @@ namespace MMAP
|
|||||||
class MapBuilder
|
class MapBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapBuilder(float maxWalkableAngle = 60.f,
|
MapBuilder(Optional<float> maxWalkableAngle,
|
||||||
|
Optional<float> maxWalkableAngleNotSteep,
|
||||||
bool skipLiquid = false,
|
bool skipLiquid = false,
|
||||||
bool skipContinents = false,
|
bool skipContinents = false,
|
||||||
bool skipJunkMaps = true,
|
bool skipJunkMaps = true,
|
||||||
@@ -161,7 +163,8 @@ namespace MMAP
|
|||||||
bool m_skipJunkMaps;
|
bool m_skipJunkMaps;
|
||||||
bool m_skipBattlegrounds;
|
bool m_skipBattlegrounds;
|
||||||
|
|
||||||
float m_maxWalkableAngle;
|
Optional<float> m_maxWalkableAngle;
|
||||||
|
Optional<float> m_maxWalkableAngleNotSteep;
|
||||||
bool m_bigBaseUnit;
|
bool m_bigBaseUnit;
|
||||||
int32 m_mapid;
|
int32 m_mapid;
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ namespace MMAP
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
if ((dp = readdir(dirp)) != nullptr)
|
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);
|
fileList.emplace_back(dp->d_name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -18,9 +18,24 @@
|
|||||||
#include "MapBuilder.h"
|
#include "MapBuilder.h"
|
||||||
#include "PathCommon.h"
|
#include "PathCommon.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
#include "DBCFileLoader.h"
|
||||||
|
#include "PathCommon.h"
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace MMAP;
|
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)
|
bool checkDirectories(bool debugOutput)
|
||||||
{
|
{
|
||||||
std::vector<std::string> dirFiles;
|
std::vector<std::string> dirFiles;
|
||||||
@@ -62,7 +77,8 @@ bool handleArgs(int argc, char** argv,
|
|||||||
int& mapnum,
|
int& mapnum,
|
||||||
int& tileX,
|
int& tileX,
|
||||||
int& tileY,
|
int& tileY,
|
||||||
float& maxAngle,
|
Optional<float>& maxAngle,
|
||||||
|
Optional<float>& maxAngleNotSteep,
|
||||||
bool& skipLiquid,
|
bool& skipLiquid,
|
||||||
bool& skipContinents,
|
bool& skipContinents,
|
||||||
bool& skipJunkMaps,
|
bool& skipJunkMaps,
|
||||||
@@ -84,11 +100,23 @@ bool handleArgs(int argc, char** argv,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
float maxangle = atof(param);
|
float maxangle = atof(param);
|
||||||
if (maxangle <= 90.f && maxangle >= 45.f)
|
if (maxangle <= 90.f && maxangle >= 0.f)
|
||||||
maxAngle = maxangle;
|
maxAngle = maxangle;
|
||||||
else
|
else
|
||||||
printf("invalid option for '--maxAngle', using default\n");
|
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)
|
else if (strcmp(argv[i], "--threads") == 0)
|
||||||
{
|
{
|
||||||
param = argv[++i];
|
param = argv[++i];
|
||||||
@@ -238,12 +266,29 @@ int finish(const char* message, int returnValue)
|
|||||||
return 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)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
unsigned int threads = std::thread::hardware_concurrency();
|
unsigned int threads = std::thread::hardware_concurrency();
|
||||||
int mapnum = -1;
|
int mapnum = -1;
|
||||||
float maxAngle = 60.0f;
|
|
||||||
int tileX = -1, tileY = -1;
|
int tileX = -1, tileY = -1;
|
||||||
|
Optional<float> maxAngle, maxAngleNotSteep;
|
||||||
bool skipLiquid = false,
|
bool skipLiquid = false,
|
||||||
skipContinents = false,
|
skipContinents = false,
|
||||||
skipJunkMaps = true,
|
skipJunkMaps = true,
|
||||||
@@ -255,7 +300,7 @@ int main(int argc, char** argv)
|
|||||||
char* file = nullptr;
|
char* file = nullptr;
|
||||||
|
|
||||||
bool validParam = handleArgs(argc, argv, mapnum,
|
bool validParam = handleArgs(argc, argv, mapnum,
|
||||||
tileX, tileY, maxAngle,
|
tileX, tileY, maxAngle, maxAngleNotSteep,
|
||||||
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
||||||
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
|
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
|
||||||
|
|
||||||
@@ -277,7 +322,13 @@ int main(int argc, char** argv)
|
|||||||
if (!checkDirectories(debugOutput))
|
if (!checkDirectories(debugOutput))
|
||||||
return silent ? -3 : finish("Press ENTER to close...", -3);
|
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);
|
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath);
|
||||||
|
|
||||||
uint32 start = getMSTime();
|
uint32 start = getMSTime();
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ struct map_liquidHeader
|
|||||||
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
||||||
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
||||||
|
|
||||||
|
uint32 GetLiquidFlags(uint32 liquidId);
|
||||||
|
|
||||||
namespace MMAP
|
namespace MMAP
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -392,31 +394,29 @@ namespace MMAP
|
|||||||
|
|
||||||
// if there is no liquid, don't use liquid
|
// if there is no liquid, don't use liquid
|
||||||
if (!meshData.liquidVerts.size() || !ltriangles.size())
|
if (!meshData.liquidVerts.size() || !ltriangles.size())
|
||||||
|
{
|
||||||
useLiquid = false;
|
useLiquid = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
liquidType = getLiquidType(i, liquid_type);
|
liquidType = getLiquidType(i, liquid_type);
|
||||||
switch (liquidType)
|
if (liquidType & MAP_LIQUID_TYPE_DARK_WATER)
|
||||||
{
|
{
|
||||||
default:
|
// players should not be here, so logically neither should creatures
|
||||||
useLiquid = false;
|
useTerrain = false;
|
||||||
break;
|
useLiquid = false;
|
||||||
case MAP_LIQUID_TYPE_WATER:
|
}
|
||||||
case MAP_LIQUID_TYPE_OCEAN:
|
else if ((liquidType & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0)
|
||||||
// merge different types of water
|
{
|
||||||
liquidType = NAV_WATER;
|
liquidType = NAV_AREA_WATER;
|
||||||
break;
|
}
|
||||||
case MAP_LIQUID_TYPE_MAGMA:
|
else if ((liquidType & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0)
|
||||||
liquidType = NAV_MAGMA;
|
{
|
||||||
break;
|
liquidType = NAV_AREA_MAGMA_SLIME;
|
||||||
case MAP_LIQUID_TYPE_SLIME:
|
}
|
||||||
liquidType = NAV_SLIME;
|
else
|
||||||
break;
|
{
|
||||||
case MAP_LIQUID_TYPE_DARK_WATER:
|
useLiquid = false;
|
||||||
// players should not be here, so logically neither should creatures
|
|
||||||
useTerrain = false;
|
|
||||||
useLiquid = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,21 +719,17 @@ namespace MMAP
|
|||||||
vertsY = tilesY + 1;
|
vertsY = tilesY + 1;
|
||||||
uint8* flags = liquid->GetFlagsStorage();
|
uint8* flags = liquid->GetFlagsStorage();
|
||||||
float* data = liquid->GetHeightStorage();
|
float* data = liquid->GetHeightStorage();
|
||||||
uint8 type = NAV_EMPTY;
|
uint8 type = NAV_AREA_EMPTY;
|
||||||
|
|
||||||
// convert liquid type to NavTerrain
|
// 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)
|
||||||
{
|
{
|
||||||
case 0:
|
type = NAV_AREA_WATER;
|
||||||
case 1:
|
}
|
||||||
type = NAV_WATER;
|
else if ((liquidFlags & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0)
|
||||||
break;
|
{
|
||||||
case 2:
|
type = NAV_AREA_MAGMA_SLIME;
|
||||||
type = NAV_MAGMA;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
type = NAV_SLIME;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexing is weird...
|
// indexing is weird...
|
||||||
|
|||||||
Reference in New Issue
Block a user