Handle different slopes in mmaps (#24765)
* Tools/MMAPs: Remove input argument --maxAngle Remove input argument --maxAngle . This should be just hardcoded in MapBuilder::GetMapSpecificConfig() so all settings are easily found in the same place instead of being spread around. * Tools/MMAPs: Add new area type NAV_AREA_GROUND_STEEP Add new area type NAV_AREA_GROUND_STEEP for ground with slope in the range (55, 70] . NAV_AREA_GROUND is used for ground with range [0, 55] . NAV_AREA_GROUND_STEEP takes priority over NAV_AREA_GROUND. * Tools/MMAPs: Fix NAV_GROUND_STEEP flag not being saved in the mmtile * Core/PathFinding: Implement NAV_GROUND_STEEP flag Implement NAV_GROUND_STEEP flag, used only by Creatures that are in combat or evading. * Distinguish between RC_WALKABLE_AREA and NAV_AREA_GROUND. * Allow mobs in combat to walk on steeps up to 80° * Allow mobs in combat to walk on steeps up to 85°. Disable rcFilterLedgeSpans() filter as it removed long steep spans. * Increase cost of steep spans to try making creatures walk around obstacles instead of walking on them * Revert last commit (cherry picked from commit 995a443da219ec773febd7dd29d18f3cefaa1f3b)
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,17 +51,22 @@ enum NavArea
|
|||||||
NAV_AREA_EMPTY = 0,
|
NAV_AREA_EMPTY = 0,
|
||||||
// areas 1-60 will be used for destructible areas (currently skipped in vmaps, WMO with flag 1)
|
// areas 1-60 will be used for destructible areas (currently skipped in vmaps, WMO with flag 1)
|
||||||
// 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)
|
// 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_AREA_GROUND = 63,
|
NAV_AREA_GROUND_STEEP = 11,
|
||||||
NAV_AREA_WATER = 62,
|
NAV_AREA_GROUND = 10,
|
||||||
NAV_AREA_MAGMA_SLIME = 61 // don't need to differentiate between them
|
NAV_AREA_WATER = 9,
|
||||||
|
NAV_AREA_MAGMA_SLIME = 8, // don't need to differentiate between them
|
||||||
|
NAV_AREA_MAX_VALUE = NAV_AREA_GROUND_STEEP,
|
||||||
|
NAV_AREA_MIN_VALUE = NAV_AREA_MAGMA_SLIME,
|
||||||
|
NAV_AREA_ALL_MASK = 0x3F // max allowed value
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NavTerrainFlag
|
enum NavTerrainFlag
|
||||||
{
|
{
|
||||||
NAV_EMPTY = 0x00,
|
NAV_EMPTY = 0x00,
|
||||||
NAV_GROUND = 1 << (63 - NAV_AREA_GROUND),
|
NAV_GROUND_STEEP = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_GROUND_STEEP),
|
||||||
NAV_WATER = 1 << (63 - NAV_AREA_WATER),
|
NAV_GROUND = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_GROUND),
|
||||||
NAV_MAGMA_SLIME = 1 << (63 - NAV_AREA_MAGMA_SLIME)
|
NAV_WATER = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_WATER),
|
||||||
|
NAV_MAGMA_SLIME = 1 << (NAV_AREA_MAX_VALUE - NAV_AREA_MAGMA_SLIME)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MMapDefines_h__
|
#endif // MMapDefines_h__
|
||||||
|
|||||||
@@ -679,6 +679,7 @@ void PathGenerator::UpdateFilter()
|
|||||||
// allow creatures to cheat and use different movement types if they are moved
|
// allow creatures to cheat and use different movement types if they are moved
|
||||||
// forcefully into terrain they can't normally move in
|
// forcefully into terrain they can't normally move in
|
||||||
if (Unit const* _sourceUnit = _source->ToUnit())
|
if (Unit const* _sourceUnit = _source->ToUnit())
|
||||||
|
{
|
||||||
if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
|
if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
|
||||||
{
|
{
|
||||||
uint16 includedFlags = _filter.getIncludeFlags();
|
uint16 includedFlags = _filter.getIncludeFlags();
|
||||||
@@ -688,6 +689,11 @@ void PathGenerator::UpdateFilter()
|
|||||||
|
|
||||||
_filter.setIncludeFlags(includedFlags);
|
_filter.setIncludeFlags(includedFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Creature const* _sourceCreature = _source->ToCreature())
|
||||||
|
if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
|
||||||
|
_filter.setIncludeFlags(_filter.getIncludeFlags() | NAV_GROUND_STEEP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NavTerrainFlag PathGenerator::GetNavTerrain(float x, float y, float z)
|
NavTerrainFlag PathGenerator::GetNavTerrain(float x, float y, float z)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
namespace MMAP
|
namespace MMAP
|
||||||
{
|
{
|
||||||
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
|
MapBuilder::MapBuilder(bool skipLiquid,
|
||||||
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
|
||||||
bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath) :
|
bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath) :
|
||||||
m_terrainBuilder (nullptr),
|
m_terrainBuilder (nullptr),
|
||||||
@@ -40,7 +40,6 @@ namespace MMAP
|
|||||||
m_skipContinents (skipContinents),
|
m_skipContinents (skipContinents),
|
||||||
m_skipJunkMaps (skipJunkMaps),
|
m_skipJunkMaps (skipJunkMaps),
|
||||||
m_skipBattlegrounds (skipBattlegrounds),
|
m_skipBattlegrounds (skipBattlegrounds),
|
||||||
m_maxWalkableAngle (maxWalkableAngle),
|
|
||||||
m_bigBaseUnit (bigBaseUnit),
|
m_bigBaseUnit (bigBaseUnit),
|
||||||
m_mapid (mapid),
|
m_mapid (mapid),
|
||||||
m_totalTiles (0u),
|
m_totalTiles (0u),
|
||||||
@@ -588,16 +587,26 @@ 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_AREA_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;
|
||||||
|
|
||||||
rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid);
|
rcFilterLowHangingWalkableObstacles(m_rcContext, config.walkableClimb, *tile.solid);
|
||||||
rcFilterLedgeSpans(m_rcContext, tileCfg.walkableHeight, tileCfg.walkableClimb, *tile.solid);
|
// disabled as it ignores walkableSlopeAngle settings
|
||||||
|
//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
|
||||||
@@ -702,10 +711,10 @@ namespace MMAP
|
|||||||
// 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 (uint8 area = iv.polyMesh->areas[i] & RC_WALKABLE_AREA)
|
if (uint8 area = iv.polyMesh->areas[i] & NAV_AREA_ALL_MASK)
|
||||||
{
|
{
|
||||||
if (area >= NAV_AREA_MAGMA_SLIME)
|
if (area >= NAV_AREA_MIN_VALUE)
|
||||||
iv.polyMesh->flags[i] = 1 << (63 - area);
|
iv.polyMesh->flags[i] = 1 << (NAV_AREA_MAX_VALUE - area);
|
||||||
else
|
else
|
||||||
iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future
|
iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future
|
||||||
}
|
}
|
||||||
@@ -978,7 +987,8 @@ 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;
|
config.walkableSlopeAngle = 85;
|
||||||
|
config.walkableSlopeAngleNotSteep = 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;
|
||||||
|
|||||||
@@ -96,8 +96,7 @@ namespace MMAP
|
|||||||
class MapBuilder
|
class MapBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MapBuilder(float maxWalkableAngle = 70.f,
|
MapBuilder(bool skipLiquid = false,
|
||||||
bool skipLiquid = false,
|
|
||||||
bool skipContinents = false,
|
bool skipContinents = false,
|
||||||
bool skipJunkMaps = true,
|
bool skipJunkMaps = true,
|
||||||
bool skipBattlegrounds = false,
|
bool skipBattlegrounds = false,
|
||||||
@@ -164,7 +163,6 @@ namespace MMAP
|
|||||||
bool m_skipJunkMaps;
|
bool m_skipJunkMaps;
|
||||||
bool m_skipBattlegrounds;
|
bool m_skipBattlegrounds;
|
||||||
|
|
||||||
float m_maxWalkableAngle;
|
|
||||||
bool m_bigBaseUnit;
|
bool m_bigBaseUnit;
|
||||||
|
|
||||||
int32 m_mapid;
|
int32 m_mapid;
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ bool handleArgs(int argc, char** argv,
|
|||||||
int &mapnum,
|
int &mapnum,
|
||||||
int &tileX,
|
int &tileX,
|
||||||
int &tileY,
|
int &tileY,
|
||||||
float &maxAngle,
|
|
||||||
bool &skipLiquid,
|
bool &skipLiquid,
|
||||||
bool &skipContinents,
|
bool &skipContinents,
|
||||||
bool &skipJunkMaps,
|
bool &skipJunkMaps,
|
||||||
@@ -114,19 +113,7 @@ bool handleArgs(int argc, char** argv,
|
|||||||
char* param = nullptr;
|
char* param = nullptr;
|
||||||
for (int i = 1; i < argc; ++i)
|
for (int i = 1; i < argc; ++i)
|
||||||
{
|
{
|
||||||
if (strcmp(argv[i], "--maxAngle") == 0)
|
if (strcmp(argv[i], "--threads") == 0)
|
||||||
{
|
|
||||||
param = argv[++i];
|
|
||||||
if (!param)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float maxangle = atof(param);
|
|
||||||
if (maxangle <= 90.f && maxangle >= 45.f)
|
|
||||||
maxAngle = maxangle;
|
|
||||||
else
|
|
||||||
printf("invalid option for '--maxAngle', using default\n");
|
|
||||||
}
|
|
||||||
else if (strcmp(argv[i], "--threads") == 0)
|
|
||||||
{
|
{
|
||||||
param = argv[++i];
|
param = argv[++i];
|
||||||
if (!param)
|
if (!param)
|
||||||
@@ -353,7 +340,6 @@ 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 = 70.0f;
|
|
||||||
int tileX = -1, tileY = -1;
|
int tileX = -1, tileY = -1;
|
||||||
bool skipLiquid = false,
|
bool skipLiquid = false,
|
||||||
skipContinents = false,
|
skipContinents = false,
|
||||||
@@ -366,7 +352,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,
|
||||||
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
|
||||||
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
|
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
|
||||||
|
|
||||||
@@ -400,7 +386,7 @@ int main(int argc, char** argv)
|
|||||||
return itr != _liquidTypes.end() ? (1 << itr->second) : 0;
|
return itr != _liquidTypes.end() ? (1 << itr->second) : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps,
|
MapBuilder builder(skipLiquid, skipContinents, skipJunkMaps,
|
||||||
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath);
|
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath);
|
||||||
|
|
||||||
uint32 start = getMSTime();
|
uint32 start = getMSTime();
|
||||||
|
|||||||
Reference in New Issue
Block a user