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 995a443da2)
This commit is contained in:
Giacomo Pozzoni
2020-06-17 20:20:26 +00:00
committed by Shauren
parent bafd22104c
commit d58d0e895c
7 changed files with 46 additions and 38 deletions

View File

@@ -224,6 +224,9 @@ struct rcConfig
/// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees]
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
/// be considered walkable. [Limit: >= 3] [Units: vx]
int walkableHeight;
@@ -810,7 +813,7 @@ bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int heigh
/// @param[in] nt The number of triangles.
/// @param[out] areas The triangle area ids. [Length: >= @p nt]
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.
/// @ingroup recast

View File

@@ -334,7 +334,7 @@ static void calcTriNormal(const float* v0, const float* v1, const float* v2, flo
void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle,
const float* verts, int nv,
const int* tris, int nt,
unsigned char* areas)
unsigned char* areas, unsigned char areaType)
{
rcIgnoreUnused(ctx);
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);
// Check if the face is walkable.
if (norm[1] > walkableThr)
areas[i] = RC_WALKABLE_AREA;
areas[i] = areaType;
}
}

View File

@@ -51,17 +51,22 @@ enum NavArea
NAV_AREA_EMPTY = 0,
// 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)
NAV_AREA_GROUND = 63,
NAV_AREA_WATER = 62,
NAV_AREA_MAGMA_SLIME = 61 // don't need to differentiate between them
NAV_AREA_GROUND_STEEP = 11,
NAV_AREA_GROUND = 10,
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
{
NAV_EMPTY = 0x00,
NAV_GROUND = 1 << (63 - NAV_AREA_GROUND),
NAV_WATER = 1 << (63 - NAV_AREA_WATER),
NAV_MAGMA_SLIME = 1 << (63 - NAV_AREA_MAGMA_SLIME)
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 // MMapDefines_h__

View File

@@ -679,6 +679,7 @@ void PathGenerator::UpdateFilter()
// allow creatures to cheat and use different movement types if they are moved
// forcefully into terrain they can't normally move in
if (Unit const* _sourceUnit = _source->ToUnit())
{
if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
{
uint16 includedFlags = _filter.getIncludeFlags();
@@ -688,6 +689,11 @@ void PathGenerator::UpdateFilter()
_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)

View File

@@ -31,7 +31,7 @@
namespace MMAP
{
MapBuilder::MapBuilder(float maxWalkableAngle, bool skipLiquid,
MapBuilder::MapBuilder(bool skipLiquid,
bool skipContinents, bool skipJunkMaps, bool skipBattlegrounds,
bool debugOutput, bool bigBaseUnit, int mapid, char const* offMeshFilePath) :
m_terrainBuilder (nullptr),
@@ -40,7 +40,6 @@ namespace MMAP
m_skipContinents (skipContinents),
m_skipJunkMaps (skipJunkMaps),
m_skipBattlegrounds (skipBattlegrounds),
m_maxWalkableAngle (maxWalkableAngle),
m_bigBaseUnit (bigBaseUnit),
m_mapid (mapid),
m_totalTiles (0u),
@@ -588,16 +587,26 @@ 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_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);
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;
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);
// add liquid triangles
rcRasterizeTriangles(m_rcContext, lVerts, lVertCount, lTris, lTriFlags, lTriCount, *tile.solid, config.walkableClimb);
// compact heightfield spans
@@ -702,10 +711,10 @@ namespace MMAP
// 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 (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)
iv.polyMesh->flags[i] = 1 << (63 - area);
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
}
@@ -978,7 +987,8 @@ namespace MMAP
config.maxVertsPerPoly = DT_VERTS_PER_POLYGON;
config.cs = 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.walkableRadius = m_bigBaseUnit ? 1 : 2;
config.borderSize = config.walkableRadius + 3;

View File

@@ -96,8 +96,7 @@ namespace MMAP
class MapBuilder
{
public:
MapBuilder(float maxWalkableAngle = 70.f,
bool skipLiquid = false,
MapBuilder(bool skipLiquid = false,
bool skipContinents = false,
bool skipJunkMaps = true,
bool skipBattlegrounds = false,
@@ -164,7 +163,6 @@ namespace MMAP
bool m_skipJunkMaps;
bool m_skipBattlegrounds;
float m_maxWalkableAngle;
bool m_bigBaseUnit;
int32 m_mapid;

View File

@@ -99,7 +99,6 @@ bool handleArgs(int argc, char** argv,
int &mapnum,
int &tileX,
int &tileY,
float &maxAngle,
bool &skipLiquid,
bool &skipContinents,
bool &skipJunkMaps,
@@ -114,19 +113,7 @@ bool handleArgs(int argc, char** argv,
char* param = nullptr;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--maxAngle") == 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)
if (strcmp(argv[i], "--threads") == 0)
{
param = argv[++i];
if (!param)
@@ -353,7 +340,6 @@ int main(int argc, char** argv)
unsigned int threads = std::thread::hardware_concurrency();
int mapnum = -1;
float maxAngle = 70.0f;
int tileX = -1, tileY = -1;
bool skipLiquid = false,
skipContinents = false,
@@ -366,7 +352,7 @@ int main(int argc, char** argv)
char* file = nullptr;
bool validParam = handleArgs(argc, argv, mapnum,
tileX, tileY, maxAngle,
tileX, tileY,
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
@@ -400,7 +386,7 @@ int main(int argc, char** argv)
return itr != _liquidTypes.end() ? (1 << itr->second) : 0;
};
MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps,
MapBuilder builder(skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath);
uint32 start = getMSTime();