20#include "DetourCommon.h"
21#include "DetourNavMeshQuery.h"
34 _endPosition(
G3D::Vector3::zero()), _source(owner), _navMesh(nullptr),
35 _navMeshQuery(nullptr)
67 G3D::Vector3 dest(destX, destY, destZ);
70 G3D::Vector3 start(x, y, z);
96 if (!polyPath || !polyPathSize)
100 float minDist = FLT_MAX;
102 for (
uint32 i = 0; i < polyPathSize; ++i)
105 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint,
nullptr)))
108 float d = dtVdistSqr(point, closestPoint);
112 nearestPoly = polyPath[i];
120 *distance = dtMathSqrtf(minDist);
138 float closestPoint[
VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
141 *distance = dtVdist(closestPoint, point);
152 *distance = dtVdist(closestPoint, point);
164 float distToStartPoly, distToEndPoly;
165 float startPoint[
VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
166 float endPoint[
VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
178 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)");
198 if (path || waterPath)
213 bool startFarFromPoly = distToStartPoly > 7.0f;
214 bool endFarFromPoly = distToEndPoly > 7.0f;
215 if (startFarFromPoly || endFarFromPoly)
217 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: farFromPoly distToStartPoly={:.3f} distToEndPoly={:.3f}", distToStartPoly, distToEndPoly);
219 bool buildShotrcut =
false;
221 G3D::Vector3
const& p = (distToStartPoly > 7.0f) ? startPos : endPos;
224 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: underWater case");
226 if (_sourceUnit->CanSwim())
227 buildShotrcut =
true;
231 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: flying case");
234 if (_sourceUnit->CanFly())
235 buildShotrcut =
true;
237 else if (_sourceUnit->IsFalling() && endPos.z < startPos.z)
238 buildShotrcut =
true;
255 if (dtStatusSucceed(
_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint,
nullptr)))
257 dtVcopy(endPoint, closestPoint);
273 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPoly == endPoly)");
278 if (startFarFromPoly || endFarFromPoly)
293 bool startPolyFound =
false;
294 bool endPolyFound =
false;
295 uint32 pathStartIndex = 0;
300 for (; pathStartIndex <
_polyLength; ++pathStartIndex)
305 TC_LOG_ERROR(
"maps.mmaps",
"Invalid poly ref in BuildPolyPath. _polyLength: {}, pathStartIndex: {},"
306 " startPos: {}, endPos: {}, mapid: {}",
307 _polyLength, pathStartIndex, startPos.toString(), endPos.toString(),
315 startPolyFound =
true;
320 for (pathEndIndex =
_polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex)
328 if (startPolyFound && endPolyFound)
330 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPolyFound && endPolyFound)");
339 else if (startPolyFound && !endPolyFound)
341 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (startPolyFound && !endPolyFound)");
358 dtPolyRef suffixStartPoly =
_pathPolyRefs[prefixPolyLength-1];
362 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,
nullptr)))
368 if (dtStatusFailed(
_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint,
nullptr)))
378 uint32 suffixPolyLength = 0;
397 (
int*)&suffixPolyLength,
401 if (!suffixPolyLength || dtStatusFailed(dtResult))
409 TC_LOG_DEBUG(
"maps.mmaps",
"++ m_polyLength={} prefixPolyLength={} suffixPolyLength={}",
_polyLength, prefixPolyLength, suffixPolyLength);
412 _polyLength = prefixPolyLength + suffixPolyLength - 1;
416 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildPolyPath :: (!startPolyFound && !endPolyFound)");
430 memset(hitNormal, 0,
sizeof(hitNormal));
458 dtVlerp(hitPos, startPoint, endPoint, hit);
466 _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]);
481 _pathPoints[1] = G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]);
484 if (startFarFromPoly || endFarFromPoly)
534 dtStatus dtResult = DT_FAILURE;
575 else if ( pointCount < 2 || dtStatusFailed(dtResult))
580 TC_LOG_DEBUG(
"maps.mmaps",
"++ PathGenerator::BuildPointPath FAILED! path sized {} returned\n", pointCount);
587 TC_LOG_DEBUG(
"maps.mmaps",
"++ PathGenerator::BuildPointPath FAILED! path sized {} returned, lower than limit set to {}", pointCount,
_pointPathLimit);
594 for (
uint32 i = 0; i < pointCount; ++i)
632 TC_LOG_DEBUG(
"maps.mmaps",
"++ BuildShortcut :: making shortcut");
669 _filter.setIncludeFlags(includeFlags);
670 _filter.setExcludeFlags(excludeFlags);
684 if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
691 _filter.setIncludeFlags(includedFlags);
695 if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
718 int tx = -1, ty = -1;
721 _navMesh->calcTileLoc(point, &tx, &ty);
726 if (tx < 0 || ty < 0)
729 return (
_navMesh->getTileAt(tx, ty, 0) !=
nullptr);
734 int32 furthestPath = -1;
735 int32 furthestVisited = -1;
738 for (
int32 i = npath-1; i >= 0; --i)
741 for (
int32 j = nvisited-1; j >= 0; --j)
743 if (path[i] == visited[j])
755 if (furthestPath == -1 || furthestVisited == -1)
761 uint32 req = nvisited - furthestVisited;
762 uint32 orig =
uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
763 uint32 size = npath > orig ? npath - orig : 0;
764 if (req +
size > maxPath)
768 memmove(path + req, path + orig,
size *
sizeof(dtPolyRef));
771 for (
uint32 i = 0; i < req; ++i)
772 path[i] = visited[(nvisited - 1) - i];
779 float* steerPos,
unsigned char& steerPosFlag, dtPolyRef& steerPosRef)
782 static const uint32 MAX_STEER_POINTS = 3;
784 unsigned char steerPathFlags[MAX_STEER_POINTS];
785 dtPolyRef steerPathPolys[MAX_STEER_POINTS];
788 steerPath, steerPathFlags, steerPathPolys, (
int*)&nsteerPath, MAX_STEER_POINTS);
789 if (!nsteerPath || dtStatusFailed(dtResult))
794 while (ns < nsteerPath)
797 if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
803 if (ns >= nsteerPath)
807 steerPos[1] = startPos[1];
808 steerPosFlag = steerPathFlags[ns];
809 steerPosRef = steerPathPolys[ns];
815 dtPolyRef
const* polyPath,
uint32 polyPathSize,
816 float* smoothPath,
int* smoothPathSize,
uint32 maxSmoothPathSize)
822 memcpy(polys, polyPath,
sizeof(dtPolyRef)*polyPathSize);
823 uint32 npolys = polyPathSize;
827 if (polyPathSize > 1)
830 if (dtStatusFailed(
_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
833 if (dtStatusFailed(
_navMeshQuery->closestPointOnPolyBoundary(polys[npolys - 1], endPos, targetPos)))
839 dtVcopy(iterPos, startPos);
840 dtVcopy(targetPos, endPos);
843 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
848 while (npolys && nsmoothPath < maxSmoothPathSize)
852 unsigned char steerPosFlag;
858 bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END) != 0;
859 bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0;
863 dtVsub(delta, steerPos, iterPos);
864 float len = dtMathSqrtf(dtVdot(delta, delta));
872 dtVmad(moveTgt, iterPos, delta, len);
876 const static uint32 MAX_VISIT_POLY = 16;
877 dtPolyRef visited[MAX_VISIT_POLY];
880 if (dtStatusFailed(
_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &
_filter, result, visited, (
int*)&nvisited, MAX_VISIT_POLY)))
884 if (dtStatusFailed(
_navMeshQuery->getPolyHeight(polys[0], result, &result[1])))
887 dtVcopy(iterPos, result);
893 dtVcopy(iterPos, targetPos);
894 if (nsmoothPath < maxSmoothPathSize)
896 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
905 dtPolyRef polyRef = polys[0];
907 while (npos < npolys && polyRef != steerPosRef)
910 polyRef = polys[npos];
914 for (
uint32 i = npos; i < npolys; ++i)
915 polys[i-npos] = polys[i];
921 if (dtStatusSucceed(
_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, connectionStartPos, connectionEndPos)))
923 if (nsmoothPath < maxSmoothPathSize)
925 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], connectionStartPos);
929 dtVcopy(iterPos, connectionEndPos);
930 if (dtStatusFailed(
_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1])))
937 if (nsmoothPath < maxSmoothPathSize)
939 dtVcopy(&smoothPath[nsmoothPath*
VERTEX_SIZE], iterPos);
944 *smoothPathSize = nsmoothPath;
952 const float dx =
v2[0] -
v1[0];
953 const float dy =
v2[1] -
v1[1];
954 const float dz =
v2[2] -
v1[2];
955 return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
960 G3D::Vector3 d = p1 - p2;
961 return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
966 return (p1 - p2).squaredLength();
972 for (std::size_t i = 0; i <
_pathPoints.size() - 1; ++i)
982 TC_LOG_ERROR(
"maps.mmaps",
"PathGenerator::ReducePathLengthByDist called before path was successfully built");
986 float const distSq = dist * dist;
990 if ((
_pathPoints[0] - target).squaredLength() < distSq)
994 if ((*
_pathPoints.rbegin() - target).squaredLength() >= distSq)
1006 if ((
_pathPoints[i-1] - target).squaredLength() >= distSq)
1041 if (startFarFromPoly)
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
#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
bool CanFly() const override
bool CanEnterWater() const override
constexpr bool HasFlag(T flag) const
static MMapManager * createOrGetMMapManager()
dtNavMesh const * GetNavMesh(uint32 mapId)
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
static Creature * ToCreature(Object *o)
static Unit * ToUnit(Object *o)
static ObjectGuid GetGUID(Object const *o)
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
void ShortenPathUntilDist(G3D::Vector3 const &point, float dist)
float Dist3DSqr(G3D::Vector3 const &p1, G3D::Vector3 const &p2) const
float GetPathLength() const
PathType GetPathType() const
void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly)
dtStatus FindSmoothPath(float const *startPos, float const *endPos, dtPolyRef const *polyPath, uint32 polyPathSize, float *smoothPath, int *smoothPathSize, uint32 smoothPathMaxSize)
dtNavMeshQuery const * _navMeshQuery
WorldObject const *const _source
G3D::Vector3 const & GetEndPosition() const
dtPolyRef GetPolyByLocation(float const *Point, float *Distance) const
PathGenerator(WorldObject const *owner)
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 CalculatePath(float destX, float destY, float destZ, bool forceDest=false)
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)
constexpr std::size_t size()
EnumFlag< map_liquidHeaderTypeFlags > type_flags
constexpr float GetPositionX() const
constexpr float GetPositionY() const
constexpr void GetPosition(float &x, float &y) const
constexpr float GetPositionZ() const