aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/Collision/Maps/MapDefines.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp10
-rw-r--r--src/server/game/Movement/PathGenerator.cpp175
-rw-r--r--src/server/game/Movement/PathGenerator.h7
-rw-r--r--src/server/game/Spells/Spell.cpp18
-rw-r--r--src/server/scripts/Commands/cs_mmaps.cpp11
-rw-r--r--src/tools/mmaps_generator/MapBuilder.cpp2
7 files changed, 105 insertions, 120 deletions
diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h
index 50f7e93e4c3..d433b381cc8 100644
--- a/src/common/Collision/Maps/MapDefines.h
+++ b/src/common/Collision/Maps/MapDefines.h
@@ -22,7 +22,7 @@
#include "DetourNavMesh.h"
const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
-#define MMAP_VERSION 9
+#define MMAP_VERSION 10
struct MmapTileHeader
{
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index c6597a22e5f..3d132c31679 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -3272,10 +3272,11 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float
// Use a detour raycast to get our first collision point
PathGenerator path(this);
- path.CalculatePath(destx, desty, destz, false, true);
+ path.SetUseRaycast(true);
+ path.CalculatePath(destx, desty, destz, false);
// We have a invalid path result. Skip further processing.
- if (path.GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END))
+ if (path.GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END | PATHFIND_NOT_USING_PATH))
return;
G3D::Vector3 result = path.GetPath().back();
@@ -3285,7 +3286,9 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float
// check static LOS
float halfHeight = GetCollisionHeight() * 0.5f;
- bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(),
+ bool col;
+ /*
+ col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(),
pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight,
destx, desty, destz + halfHeight,
destx, desty, destz, -0.5f);
@@ -3299,6 +3302,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float
desty -= CONTACT_DISTANCE * std::sin(angle);
dist = std::sqrt((pos.m_positionX - destx) * (pos.m_positionX - destx) + (pos.m_positionY - desty) * (pos.m_positionY - desty));
}
+ */
// check dynamic collision
col = GetMap()->getObjectHitPos(GetPhaseMask(),
diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp
index 5402cb8e33a..af6b8b0b30c 100644
--- a/src/server/game/Movement/PathGenerator.cpp
+++ b/src/server/game/Movement/PathGenerator.cpp
@@ -29,7 +29,7 @@
////////////////// PathGenerator //////////////////
PathGenerator::PathGenerator(WorldObject const* owner) :
_polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false),
- _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH), _straightLine(false),
+ _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH), _useRaycast(false),
_endPosition(G3D::Vector3::zero()), _source(owner), _navMesh(nullptr),
_navMeshQuery(nullptr)
{
@@ -53,7 +53,7 @@ PathGenerator::~PathGenerator()
TC_LOG_DEBUG("maps.mmaps", "++ PathGenerator::~PathGenerator() for %s", _source->GetGUID().ToString().c_str());
}
-bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest, bool straightLine)
+bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest)
{
float x, y, z;
_source->GetPosition(x, y, z);
@@ -70,7 +70,6 @@ bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool fo
SetStartPosition(start);
_forceDestination = forceDest;
- _straightLine = straightLine;
TC_LOG_DEBUG("maps.mmaps", "++ PathGenerator::CalculatePath() for %s", _source->GetGUID().ToString().c_str());
@@ -155,6 +154,7 @@ dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance)
return polyRef;
}
+ *distance = FLT_MAX;
return INVALID_POLYREF;
}
@@ -169,6 +169,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
+ _type = PathType(PATHFIND_NORMAL);
+
// we have a hole in our mesh
// make shortcut path and mark it as NOPATH ( with flying and swimming exception )
// its up to caller how he will use this info
@@ -194,8 +196,18 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
}
}
- _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
- return;
+ if (path || waterPath)
+ {
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return;
+ }
+
+ // raycast doesn't need endPoly to be valid
+ if (!_useRaycast)
+ {
+ _type = PATHFIND_NOPATH;
+ return;
+ }
}
// we may need a better number here
@@ -233,10 +245,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
BuildShortcut();
_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
- if (startFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_START);
- if (endFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_END);
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
return;
}
@@ -252,10 +261,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
_type = PathType(PATHFIND_INCOMPLETE);
- if (startFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_START);
- if (endFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_END);
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
}
}
@@ -263,9 +269,10 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
// start and end are on same polygon
// handle this case as if they were 2 different polygons, building a line path split in some few points
- if (startPoly == endPoly)
+ if (startPoly == endPoly && !_useRaycast)
{
TC_LOG_DEBUG("maps.mmaps", "++ BuildPolyPath :: (startPoly == endPoly)");
+
_pathPolyRefs[0] = startPoly;
_polyLength = 1;
@@ -273,10 +280,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
{
_type = PathType(PATHFIND_INCOMPLETE);
- if (startFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_START);
- if (endFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_END);
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
}
else
_type = PATHFIND_NORMAL;
@@ -375,39 +379,12 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
uint32 suffixPolyLength = 0;
dtStatus dtResult;
- if (_straightLine)
+ if (_useRaycast)
{
- float hit = 0;
- float hitNormal[3];
- memset(hitNormal, 0, sizeof(hitNormal));
-
- dtResult = _navMeshQuery->raycast(
- suffixStartPoly,
- suffixEndPoint,
- endPoint,
- &_filter,
- &hit,
- hitNormal,
- _pathPolyRefs + prefixPolyLength - 1,
- (int*)&suffixPolyLength,
- MAX_PATH_LENGTH - prefixPolyLength);
-
- // raycast() sets hit to FLT_MAX if there is a ray between start and end
- if (hit != FLT_MAX)
- {
- // the ray hit something, return no path instead of the incomplete one
- Clear();
- _polyLength = 2;
- _pathPoints.resize(2);
- _pathPoints[0] = GetStartPosition();
- float hitPos[3];
- dtVlerp(hitPos, startPoint, endPoint, hit);
- _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]);
-
- NormalizePath();
- _type = PATHFIND_INCOMPLETE;
- return;
- }
+ TC_LOG_ERROR("maps.mmaps", "PathGenerator::BuildPolyPath() called with _useRaycast with a previous path for unit %s", _source->GetGUID().ToString().c_str());
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
}
else
{
@@ -447,7 +424,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
Clear();
dtStatus dtResult;
- if (_straightLine)
+ if (_useRaycast)
{
float hit = 0;
float hitNormal[3];
@@ -464,24 +441,57 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
(int*)&_polyLength,
MAX_PATH_LENGTH);
+ if (!_polyLength || dtStatusFailed(dtResult))
+ {
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
+ return;
+ }
+
// raycast() sets hit to FLT_MAX if there is a ray between start and end
if (hit != FLT_MAX)
{
- // the ray hit something, return no path instead of the incomplete one
- Clear();
- _polyLength = 2;
- _pathPoints.resize(2);
- _pathPoints[0] = GetStartPosition();
float hitPos[3];
+
+ // Walk back a bit from the hit point to make sure it's in the mesh (sometimes the point is actually outside of the polygons due to float precision issues)
+ hit *= 0.99f;
dtVlerp(hitPos, startPoint, endPoint, hit);
+
+ // if it fails again, clamp to poly boundary
+ if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], hitPos, &hitPos[1])))
+ _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], hitPos, hitPos);
+
+ _pathPoints.resize(2);
+ _pathPoints[0] = GetStartPosition();
_pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]);
NormalizePath();
_type = PATHFIND_INCOMPLETE;
+ AddFarFromPolyFlags(startFarFromPoly, false);
return;
}
else
- _navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, &endPoint[1]);
+ {
+ // clamp to poly boundary if we fail to get the height
+ if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, &endPoint[1])))
+ _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], endPoint, endPoint);
+
+ _pathPoints.resize(2);
+ _pathPoints[0] = GetStartPosition();
+ _pathPoints[1] = G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]);
+
+ NormalizePath();
+ if (startFarFromPoly || endFarFromPoly)
+ {
+ _type = PathType(PATHFIND_INCOMPLETE);
+
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
+ }
+ else
+ _type = PATHFIND_NORMAL;
+ return;
+ }
}
else
{
@@ -512,10 +522,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
else
_type = PATHFIND_INCOMPLETE;
- if (startFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_START);
- if (endFarFromPoly)
- _type = PathType(_type | PATHFIND_FARFROMPOLY_END);
+ AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
// generate the point-path out of our up-to-date poly-path
BuildPointPath(startPoint, endPoint);
@@ -526,37 +533,13 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin
float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
uint32 pointCount = 0;
dtStatus dtResult = DT_FAILURE;
- if (_straightLine)
+ if (_useRaycast)
{
- dtResult = DT_SUCCESS;
- pointCount = 1;
- memcpy(&pathPoints[VERTEX_SIZE * 0], startPoint, sizeof(float)* 3); // first point
-
- // path has to be split into polygons with dist SMOOTH_PATH_STEP_SIZE between them
- G3D::Vector3 startVec = G3D::Vector3(startPoint[0], startPoint[1], startPoint[2]);
- G3D::Vector3 endVec = G3D::Vector3(endPoint[0], endPoint[1], endPoint[2]);
- G3D::Vector3 diffVec = (endVec - startVec);
- G3D::Vector3 prevVec = startVec;
- float len = diffVec.length();
- diffVec *= SMOOTH_PATH_STEP_SIZE / len;
-
- // If the path is short PATHFIND_SHORT will be set as type
- while (len > SMOOTH_PATH_STEP_SIZE && pointCount < MAX_POINT_PATH_LENGTH)
- {
- len -= SMOOTH_PATH_STEP_SIZE;
- prevVec += diffVec;
- pathPoints[VERTEX_SIZE * pointCount + 0] = prevVec.x;
- pathPoints[VERTEX_SIZE * pointCount + 1] = prevVec.y;
- pathPoints[VERTEX_SIZE * pointCount + 2] = prevVec.z;
- ++pointCount;
- }
-
- // If the path is short PATHFIND_SHORT will be set as type
- if (pointCount < MAX_POINT_PATH_LENGTH)
- {
- memcpy(&pathPoints[VERTEX_SIZE * pointCount], endPoint, sizeof(float) * 3); // last point
- ++pointCount;
- }
+ // _straightLine uses raycast and it currently doesn't support building a point path, only a 2-point path with start and hitpoint/end is returned
+ TC_LOG_ERROR("maps.mmaps", "PathGenerator::BuildPointPath() called with _useRaycast for unit %s", _source->GetGUID().ToString().c_str());
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
}
else if (_useStraightPath)
{
@@ -839,7 +822,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo
if (polyPathSize > 1)
{
- // Pick the closest poitns on poly border
+ // Pick the closest points on poly border
if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
return DT_FAILURE;
@@ -1039,3 +1022,11 @@ bool PathGenerator::IsInvalidDestinationZ(Unit const* target) const
{
return (target->GetPositionZ() - GetActualEndPosition().z) > 5.0f;
}
+
+void PathGenerator::AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly)
+{
+ if (startFarFromPoly)
+ _type = PathType(_type | PATHFIND_FARFROMPOLY_START);
+ if (endFarFromPoly)
+ _type = PathType(_type | PATHFIND_FARFROMPOLY_END);
+}
diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h
index d739dd19872..5c518100d6a 100644
--- a/src/server/game/Movement/PathGenerator.h
+++ b/src/server/game/Movement/PathGenerator.h
@@ -61,12 +61,13 @@ class TC_GAME_API PathGenerator
// Calculate the path from owner to given destination
// return: true if new path was calculated, false otherwise (no change needed)
- bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false, bool straightLine = false);
+ bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false);
bool IsInvalidDestinationZ(Unit const* target) const;
// option setters - use optional
void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; }
void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); }
+ void SetUseRaycast(bool useRaycast) { _useRaycast = useRaycast; }
// result getters
G3D::Vector3 const& GetStartPosition() const { return _startPosition; }
@@ -91,7 +92,7 @@ class TC_GAME_API PathGenerator
bool _useStraightPath; // type of path will be generated
bool _forceDestination; // when set, we will always arrive at given point
uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH)
- bool _straightLine; // use raycast if true for a straight line path
+ bool _useRaycast; // use raycast if true for a straight line path
G3D::Vector3 _startPosition; // {x, y, z} of current location
G3D::Vector3 _endPosition; // {x, y, z} of the destination
@@ -137,6 +138,8 @@ class TC_GAME_API PathGenerator
dtStatus FindSmoothPath(float const* startPos, float const* endPos,
dtPolyRef const* polyPath, uint32 polyPathSize,
float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize);
+
+ void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly);
};
#endif
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 537a5971a32..60e09ef0753 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1356,21 +1356,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
Position pos = dest._position;
unitCaster->MovePositionToFirstCollision(pos, dist, angle);
- // Generate path to that point.
- if (!m_preGeneratedPath)
- m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
-
- m_preGeneratedPath->SetPathLengthLimit(dist);
-
- // Should we use straightline here ? What do we do when we don't have a full path ?
- bool pathResult = m_preGeneratedPath->CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false, true);
- if (pathResult && m_preGeneratedPath->GetPathType() & (PATHFIND_NORMAL | PATHFIND_SHORTCUT))
- {
- pos.m_positionX = m_preGeneratedPath->GetActualEndPosition().x;
- pos.m_positionY = m_preGeneratedPath->GetActualEndPosition().y;
- pos.m_positionZ = m_preGeneratedPath->GetActualEndPosition().z;
- dest.Relocate(pos);
- }
+ dest.Relocate(pos);
break;
}
default:
@@ -5537,7 +5523,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
m_preGeneratedPath->SetPathLengthLimit(range);
// first try with raycast, if it fails fall back to normal path
- bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false, false);
+ bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
return SPELL_FAILED_NOPATH;
else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp
index 25929e5a77f..b9c2cb2591f 100644
--- a/src/server/scripts/Commands/cs_mmaps.cpp
+++ b/src/server/scripts/Commands/cs_mmaps.cpp
@@ -83,9 +83,9 @@ public:
if (para && strcmp(para, "true") == 0)
useStraightPath = true;
- bool useStraightLine = false;
- if (para && strcmp(para, "line") == 0)
- useStraightLine = true;
+ bool useRaycast = false;
+ if (para && (strcmp(para, "line") == 0 || strcmp(para, "ray") == 0 || strcmp(para, "raycast") == 0))
+ useRaycast = true;
// unit locations
float x, y, z;
@@ -94,11 +94,12 @@ public:
// path
PathGenerator path(target);
path.SetUseStraightPath(useStraightPath);
- bool result = path.CalculatePath(x, y, z, false, useStraightLine);
+ path.SetUseRaycast(useRaycast);
+ bool result = path.CalculatePath(x, y, z, false);
Movement::PointsArray const& pointPath = path.GetPath();
handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str());
- handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath");
+ handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useRaycast ? "Raycast" : "SmoothPath");
handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType());
G3D::Vector3 const& start = path.GetStartPosition();
diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp
index f8b4518e641..eaa60819258 100644
--- a/src/tools/mmaps_generator/MapBuilder.cpp
+++ b/src/tools/mmaps_generator/MapBuilder.cpp
@@ -1015,7 +1015,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)