20#include "DetourCommon.h"
21#include "DetourNavMeshQuery.h"
23#include "G3DPosition.hpp"
34 _startPosition(PositionToVector3(owner->GetPosition())), _endPosition(
G3D::Vector3::zero()), _source(owner), _navMesh(nullptr),
35 _navMeshQuery(nullptr)
64 G3D::Vector3 dest(destX, destY, destZ);
67 G3D::Vector3 start(srcX, srcY, srcZ);
95 return CalculatePath(x, y, z, destX, destY, destZ, forceDest);
100 if (!polyPath || !polyPathSize)
104 float minDist = FLT_MAX;
106 for (
uint32 i = 0; i < polyPathSize; ++i)
109 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint,
nullptr)))
112 float d = dtVdistSqr(point, closestPoint);
116 nearestPoly = polyPath[i];
124 *distance = dtMathSqrtf(minDist);
142 float closestPoint[
VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
145 *distance = dtVdist(closestPoint, point);
156 *distance = dtVdist(closestPoint, point);
168 float distToStartPoly, distToEndPoly;
169 float startPoint[
VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
170 float endPoint[
VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
182 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)");
202 if (path || waterPath)
217 bool startFarFromPoly = distToStartPoly > 7.0f;
218 bool endFarFromPoly = distToEndPoly > 7.0f;
219 if (startFarFromPoly || endFarFromPoly)
221 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: farFromPoly distToStartPoly={:.3f} distToEndPoly={:.3f}", distToStartPoly, distToEndPoly);
223 bool buildShotrcut =
false;
225 G3D::Vector3
const& p = (distToStartPoly > 7.0f) ? startPos : endPos;
228 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: underWater case");
230 if (_sourceUnit->CanSwim())
231 buildShotrcut =
true;
235 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: flying case");
238 if (_sourceUnit->CanFly())
239 buildShotrcut =
true;
241 else if (_sourceUnit->IsFalling() && endPos.z < startPos.z)
242 buildShotrcut =
true;
259 if (dtStatusSucceed(
_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint,
nullptr)))
261 dtVcopy(endPoint, closestPoint);
277 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPoly == endPoly)");
282 if (startFarFromPoly || endFarFromPoly)
297 bool startPolyFound =
false;
298 bool endPolyFound =
false;
299 uint32 pathStartIndex = 0;
304 for (; pathStartIndex <
_polyLength; ++pathStartIndex)
309 TC_LOG_ERROR(
"maps.mmaps",
"Invalid poly ref in BuildPolyPath. _polyLength: {}, pathStartIndex: {},"
310 " startPos: {}, endPos: {}, mapid: {}",
311 _polyLength, pathStartIndex, startPos.toString(), endPos.toString(),
319 startPolyFound =
true;
324 for (pathEndIndex =
_polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex)
332 if (startPolyFound && endPolyFound)
334 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPolyFound && endPolyFound)");
343 else if (startPolyFound && !endPolyFound)
345 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPolyFound && !endPolyFound)");
362 dtPolyRef suffixStartPoly =
_pathPolyRefs[prefixPolyLength-1];
366 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,
nullptr)))
372 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,
nullptr)))
382 uint32 suffixPolyLength = 0;
401 (
int*)&suffixPolyLength,
405 if (!suffixPolyLength || dtStatusFailed(dtResult))
413 TC_LOG_DEBUG(
"maps.mmaps",
"++ m_polyLength={} prefixPolyLength={} suffixPolyLength={}",
_polyLength, prefixPolyLength, suffixPolyLength);
416 _polyLength = prefixPolyLength + suffixPolyLength - 1;
420 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (!startPolyFound && !endPolyFound)");
434 memset(hitNormal, 0,
sizeof(hitNormal));
462 dtVlerp(hitPos, startPoint, endPoint, hit);
470 _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]);
485 _pathPoints[1] = G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]);
488 if (startFarFromPoly || endFarFromPoly)
538 dtStatus dtResult = DT_FAILURE;
579 else if ( pointCount < 2 || dtStatusFailed(dtResult))
584 TC_LOG_DEBUG(
"maps.mmaps",
"++ PathGenerator::BuildPointPath FAILED! path sized {} returned\n", pointCount);
591 TC_LOG_DEBUG(
"maps.mmaps",
"++ PathGenerator::BuildPointPath FAILED! path sized {} returned, lower than limit set to {}", pointCount,
_pointPathLimit);
598 for (
uint32 i = 0; i < pointCount; ++i)
636 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildShortcut :: making shortcut");
673 _filter.setIncludeFlags(includeFlags);
674 _filter.setExcludeFlags(excludeFlags);
688 if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
695 _filter.setIncludeFlags(includedFlags);
699 if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
722 int tx = -1, ty = -1;
725 _navMesh->calcTileLoc(point, &tx, &ty);
730 if (tx < 0 || ty < 0)
733 return (
_navMesh->getTileAt(tx, ty, 0) !=
nullptr);
738 int32 furthestPath = -1;
739 int32 furthestVisited = -1;
742 for (
int32 i = npath-1; i >= 0; --i)
745 for (
int32 j = nvisited-1; j >= 0; --j)
747 if (path[i] == visited[j])
759 if (furthestPath == -1 || furthestVisited == -1)
765 uint32 req = nvisited - furthestVisited;
766 uint32 orig =
uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
767 uint32 size = npath > orig ? npath - orig : 0;
768 if (req + size > maxPath)
772 memmove(path + req, path + orig, size *
sizeof(dtPolyRef));
775 for (
uint32 i = 0; i < req; ++i)
776 path[i] = visited[(nvisited - 1) - i];
782 float minTargetDist, dtPolyRef
const* path,
uint32 pathSize,
783 float* steerPos,
unsigned char& steerPosFlag, dtPolyRef& steerPosRef)
786 static const uint32 MAX_STEER_POINTS = 3;
788 unsigned char steerPathFlags[MAX_STEER_POINTS];
789 dtPolyRef steerPathPolys[MAX_STEER_POINTS];
791 dtStatus dtResult =
_navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
792 steerPath, steerPathFlags, steerPathPolys, (
int*)&nsteerPath, MAX_STEER_POINTS);
793 if (!nsteerPath || dtStatusFailed(dtResult))
798 while (ns < nsteerPath)
801 if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
807 if (ns >= nsteerPath)
811 steerPos[1] = startPos[1];
812 steerPosFlag = steerPathFlags[ns];
813 steerPosRef = steerPathPolys[ns];
819 dtPolyRef
const* polyPath,
uint32 polyPathSize,
820 float* smoothPath,
int* smoothPathSize,
uint32 maxSmoothPathSize)
826 memcpy(polys, polyPath,
sizeof(dtPolyRef)*polyPathSize);
827 uint32 npolys = polyPathSize;
831 if (polyPathSize > 1)
834 if (dtStatusFailed(
_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
837 if (dtStatusFailed(
_navMeshQuery->closestPointOnPolyBoundary(polys[npolys - 1], endPos, targetPos)))
843 dtVcopy(iterPos, startPos);
844 dtVcopy(targetPos, endPos);
847 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
852 while (npolys && nsmoothPath < maxSmoothPathSize)
856 unsigned char steerPosFlag;
862 bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END) != 0;
863 bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0;
867 dtVsub(delta, steerPos, iterPos);
868 float len = dtMathSqrtf(dtVdot(delta, delta));
876 dtVmad(moveTgt, iterPos, delta, len);
880 const static uint32 MAX_VISIT_POLY = 16;
881 dtPolyRef visited[MAX_VISIT_POLY];
884 if (dtStatusFailed(
_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &
_filter, result, visited, (
int*)&nvisited, MAX_VISIT_POLY)))
888 if (dtStatusFailed(
_navMeshQuery->getPolyHeight(polys[0], result, &result[1])))
891 dtVcopy(iterPos, result);
897 dtVcopy(iterPos, targetPos);
898 if (nsmoothPath < maxSmoothPathSize)
900 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
909 dtPolyRef polyRef = polys[0];
911 while (npos < npolys && polyRef != steerPosRef)
914 polyRef = polys[npos];
918 for (
uint32 i = npos; i < npolys; ++i)
919 polys[i-npos] = polys[i];
925 if (dtStatusSucceed(
_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, connectionStartPos, connectionEndPos)))
927 if (nsmoothPath < maxSmoothPathSize)
929 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], connectionStartPos);
933 dtVcopy(iterPos, connectionEndPos);
934 if (dtStatusFailed(
_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1])))
941 if (nsmoothPath < maxSmoothPathSize)
943 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
948 *smoothPathSize = nsmoothPath;
956 const float dx =
v2[0] -
v1[0];
957 const float dy =
v2[1] -
v1[1];
958 const float dz =
v2[2] -
v1[2];
959 return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
964 G3D::Vector3 d = p1 - p2;
965 return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
970 return (p1 - p2).squaredLength();
976 for (std::size_t i = 0; i <
_pathPoints.size() - 1; ++i)
986 TC_LOG_ERROR(
"maps.mmaps",
"PathGenerator::ReducePathLengthByDist called before path was successfully built");
990 float const distSq = dist * dist;
994 if ((
_pathPoints[0] - target).squaredLength() < distSq)
998 if ((*
_pathPoints.rbegin() - target).squaredLength() >= distSq)
1010 if ((
_pathPoints[i-1] - target).squaredLength() >= distSq)
1045 if (startFarFromPoly)
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_METRIC_DETAILED_EVENT(category, title, description)
#define SMOOTH_PATH_STEP_SIZE
#define MAX_POINT_PATH_LENGTH
@ PATHFIND_FARFROMPOLY_END
@ PATHFIND_NOT_USING_PATH
@ PATHFIND_FARFROMPOLY_START
@ UNIT_STATE_IGNORE_PATHFINDING
ObjectGuid const & GetGUID() const
bool CanFly() const override
bool CanEnterWater() const override
constexpr bool HasFlag(T flag) const
static MMapManager * instance()
dtNavMesh * GetNavMesh(uint32 mapId, uint32 instanceId)
dtNavMeshQuery const * GetNavMeshQuery(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
ZLiquidStatus GetLiquidStatus(PhaseShift const &phaseShift, float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType={}, LiquidData *data=nullptr, float collisionHeight=2.03128f)
bool IsUnderWater(PhaseShift const &phaseShift, float x, float y, float z)
uint16 GetForceDisabledNavMeshFilterFlags() const
bool isInLineOfSight(PhaseShift const &phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
uint16 GetForceEnabledNavMeshFilterFlags() const
TerrainInfo * GetTerrain() const
std::string ToString() const
void ShortenPathUntilDist(G3D::Vector3 const &target, float dist)
G3D::Vector3 _startPosition
bool HaveTile(G3D::Vector3 const &p) const
void SetActualEndPosition(G3D::Vector3 const &point)
dtPolyRef GetPathPolyByPosition(dtPolyRef const *polyPath, uint32 polyPathSize, float const *Point, float *Distance=nullptr) const
G3D::Vector3 const & GetStartPosition() const
float Dist3DSqr(G3D::Vector3 const &p1, G3D::Vector3 const &p2) const
float GetPathLength() const
PathType GetPathType() const
void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly)
dtNavMeshQuery const * _navMeshQuery
WorldObject const *const _source
G3D::Vector3 const & GetEndPosition() const
dtStatus FindSmoothPath(float const *startPos, float const *endPos, dtPolyRef const *polyPath, uint32 polyPathSize, float *smoothPath, int *smoothPathSize, uint32 maxSmoothPathSize)
dtPolyRef GetPolyByLocation(float const *Point, float *Distance) const
PathGenerator(WorldObject const *owner)
bool CalculatePath(float srcX, float srcY, float srcZ, float destX, float destY, float destZ, bool forceDest=false)
void BuildPolyPath(G3D::Vector3 const &startPos, G3D::Vector3 const &endPos)
bool InRangeYZX(float const *v1, float const *v2, float r, float h) const
void SetStartPosition(G3D::Vector3 const &point)
bool IsInvalidDestinationZ(WorldObject const *target) const
uint32 FixupCorridor(dtPolyRef *path, uint32 npath, uint32 maxPath, dtPolyRef const *visited, uint32 nvisited)
dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]
Movement::PointsArray _pathPoints
bool InRange(G3D::Vector3 const &p1, G3D::Vector3 const &p2, float r, float h) const
void BuildPointPath(float const *startPoint, float const *endPoint)
dtNavMesh const * _navMesh
bool GetSteerTarget(float const *startPos, float const *endPos, float minTargetDist, dtPolyRef const *path, uint32 pathSize, float *steerPos, unsigned char &steerPosFlag, dtPolyRef &steerPosRef)
void SetEndPosition(G3D::Vector3 const &point)
NavTerrainFlag GetNavTerrain(float x, float y, float z) const
G3D::Vector3 const & GetActualEndPosition() const
static uint32 GetTerrainMapId(PhaseShift const &phaseShift, uint32 mapId, TerrainInfo const *terrain, float x, float y)
bool HasUnitState(const uint32 f) const
constexpr uint32 GetMapId() const
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
virtual float GetCollisionHeight() const
Position GetHitSpherePointFor(Position const &dest) const
std::string GetDebugInfo() const override
PhaseShift & GetPhaseShift()
uint32 GetInstanceId() const
bool IsPathfindingEnabled(uint32 mapId)
bool IsValidMapCoord(float c)
EnumFlag< map_liquidHeaderTypeFlags > type_flags
constexpr void GetPosition(float &x, float &y) const
constexpr float GetPositionZ() const