AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
PathGenerator Class Reference

#include "PathGenerator.h"

Public Member Functions

 PathGenerator (WorldObject const *owner)
 
 ~PathGenerator ()
 
bool CalculatePath (float destX, float destY, float destZ, bool forceDest=false)
 
bool CalculatePath (float x, float y, float z, float destX, float destY, float destZ, bool forceDest)
 
bool IsInvalidDestinationZ (Unit const *target) const
 
bool IsWalkableClimb (float const *v1, float const *v2) const
 
bool IsWalkableClimb (float x, float y, float z, float destX, float destY, float destZ) const
 
bool IsWaterPath (Movement::PointsArray pathPoints) const
 
bool IsSwimmableSegment (float const *v1, float const *v2, bool checkSwim=true) const
 predict if a certain segment is underwater and the unit can swim Must only be used for very short segments since this check doesn't work on long paths that alternate terrain and water.
 
bool IsSwimmableSegment (float x, float y, float z, float destX, float destY, float destZ, bool checkSwim=true) const
 predict if a certain segment is underwater and the unit can swim Must only be used for very short segments since this check doesn't work on long paths that alternate terrain and water.
 
void SetSlopeCheck (bool checkSlope)
 
void SetUseStraightPath (bool useStraightPath)
 
void SetPathLengthLimit (float distance)
 
void SetUseRaycast (bool useRaycast)
 
G3D::Vector3 const & GetStartPosition () const
 
G3D::Vector3 const & GetEndPosition () const
 
G3D::Vector3 const & GetActualEndPosition () const
 
Movement::PointsArray const & GetPath () const
 
PathType GetPathType () const
 
void ShortenPathUntilDist (G3D::Vector3 const &point, float dist)
 
float getPathLength () const
 
void Clear ()
 

Static Public Member Functions

static bool IsWalkableClimb (float x, float y, float z, float destX, float destY, float destZ, float sourceHeight)
 Check if a slope can be climbed based on source height This method is meant for short distances or linear paths.
 
static float GetRequiredHeightToClimb (float x, float y, float z, float destX, float destY, float destZ, float sourceHeight)
 Return the height of a slope that can be climbed based on source height This method is meant for short distances or linear paths.
 

Private Member Functions

void SetStartPosition (G3D::Vector3 const &point)
 
void SetEndPosition (G3D::Vector3 const &point)
 
void SetActualEndPosition (G3D::Vector3 const &point)
 
void NormalizePath ()
 
bool InRange (G3D::Vector3 const &p1, G3D::Vector3 const &p2, float r, float h) const
 
float Dist3DSqr (G3D::Vector3 const &p1, G3D::Vector3 const &p2) const
 
bool InRangeYZX (float const *v1, float const *v2, float r, float h) const
 
dtPolyRef GetPathPolyByPosition (dtPolyRef const *polyPath, uint32 polyPathSize, float const *Point, float *Distance=nullptr) const
 
dtPolyRef GetPolyByLocation (float const *Point, float *Distance) const
 
bool HaveTile (G3D::Vector3 const &p) const
 
void BuildPolyPath (G3D::Vector3 const &startPos, G3D::Vector3 const &endPos)
 
void BuildPointPath (float const *startPoint, float const *endPoint)
 
void BuildShortcut ()
 
NavTerrain GetNavTerrain (float x, float y, float z) const
 
void CreateFilter ()
 
void UpdateFilter ()
 
uint32 FixupCorridor (dtPolyRef *path, uint32 npath, uint32 maxPath, dtPolyRef const *visited, uint32 nvisited)
 
bool GetSteerTarget (float const *startPos, float const *endPos, float minTargetDist, dtPolyRef const *path, uint32 pathSize, float *steerPos, unsigned char &steerPosFlag, dtPolyRef &steerPosRef)
 
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)
 

Private Attributes

dtPolyRef _pathPolyRefs [MAX_PATH_LENGTH]
 
uint32 _polyLength
 
Movement::PointsArray _pathPoints
 
PathType _type
 
bool _useStraightPath
 
bool _forceDestination
 
bool _slopeCheck
 
uint32 _pointPathLimit
 
bool _useRaycast
 
G3D::Vector3 _startPosition
 
G3D::Vector3 _endPosition
 
G3D::Vector3 _actualEndPosition
 
WorldObject const *const _source
 
dtNavMesh const * _navMesh
 
dtNavMeshQuery const * _navMeshQuery
 
dtQueryFilterExt _filter
 

Detailed Description

Constructor & Destructor Documentation

◆ PathGenerator()

PathGenerator::PathGenerator ( WorldObject const *  owner)
explicit
29 :
32 _endPosition(G3D::Vector3::zero()), _source(owner), _navMesh(nullptr),
33 _navMeshQuery(nullptr)
34{
35 memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs));
36
37 uint32 mapId = _source->GetMapId();
38 //if (DisableMgr::IsPathfindingEnabled(_sourceUnit->FindMap()))
39 {
41 _navMesh = mmap->GetNavMesh(mapId);
43 }
44
46}
std::uint32_t uint32
Definition: Define.h:108
#define MAX_POINT_PATH_LENGTH
Definition: PathGenerator.h:37
@ PATHFIND_BLANK
Definition: PathGenerator.h:47
static MMapMgr * createOrGetMMapMgr()
Definition: MMapFactory.cpp:29
Definition: MMapMgr.h:75
dtNavMesh const * GetNavMesh(uint32 mapId)
Definition: MMapMgr.cpp:306
dtNavMeshQuery const * GetNavMeshQuery(uint32 mapId, uint32 instanceId)
Definition: MMapMgr.cpp:317
uint32 GetInstanceId() const
Definition: Object.h:431
uint32 GetMapId() const
Definition: Position.h:276
PathType _type
Definition: PathGenerator.h:136
bool _useRaycast
Definition: PathGenerator.h:142
bool _slopeCheck
Definition: PathGenerator.h:140
uint32 _pointPathLimit
Definition: PathGenerator.h:141
bool _useStraightPath
Definition: PathGenerator.h:138
dtNavMeshQuery const * _navMeshQuery
Definition: PathGenerator.h:150
WorldObject const *const _source
Definition: PathGenerator.h:148
uint32 _polyLength
Definition: PathGenerator.h:133
bool _forceDestination
Definition: PathGenerator.h:139
void CreateFilter()
Definition: PathGenerator.cpp:634
dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]
Definition: PathGenerator.h:132
dtNavMesh const * _navMesh
Definition: PathGenerator.h:149
G3D::Vector3 _endPosition
Definition: PathGenerator.h:145

References _navMesh, _navMeshQuery, _pathPolyRefs, _source, CreateFilter(), MMAP::MMapFactory::createOrGetMMapMgr(), WorldObject::GetInstanceId(), WorldLocation::GetMapId(), MMAP::MMapMgr::GetNavMesh(), and MMAP::MMapMgr::GetNavMeshQuery().

◆ ~PathGenerator()

PathGenerator::~PathGenerator ( )
49{
50}

Member Function Documentation

◆ AddFarFromPolyFlags()

void PathGenerator::AddFarFromPolyFlags ( bool  startFarFromPoly,
bool  endFarFromPoly 
)
private
1089{
1090 if (startFarFromPoly)
1091 {
1093 }
1094 if (endFarFromPoly)
1095 {
1097 }
1098}
PathType
Definition: PathGenerator.h:46
@ PATHFIND_FARFROMPOLY_END
Definition: PathGenerator.h:55
@ PATHFIND_FARFROMPOLY_START
Definition: PathGenerator.h:54

References _type, PATHFIND_FARFROMPOLY_END, and PATHFIND_FARFROMPOLY_START.

Referenced by BuildPolyPath().

◆ BuildPointPath()

void PathGenerator::BuildPointPath ( float const *  startPoint,
float const *  endPoint 
)
private
Todo:
check the exact cases
521{
522 float pathPoints[MAX_POINT_PATH_LENGTH * VERTEX_SIZE];
523 uint32 pointCount = 0;
524 dtStatus dtResult = DT_FAILURE;
525 if (_useRaycast)
526 {
527 // _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
528 LOG_ERROR("movement", "PathGenerator::BuildPointPath() called with _useRaycast for unit {}", _source->GetGUID().ToString());
531 return;
532 }
533 else if (_useStraightPath)
534 {
535 dtResult = _navMeshQuery->findStraightPath(
536 startPoint, // start position
537 endPoint, // end position
538 _pathPolyRefs, // current path
539 _polyLength, // lenth of current path
540 pathPoints, // [out] path corner points
541 nullptr, // [out] flags
542 nullptr, // [out] shortened path
543 (int*)&pointCount,
544 _pointPathLimit); // maximum number of points/polygons to use
545 }
546 else
547 {
548 dtResult = FindSmoothPath(
549 startPoint, // start position
550 endPoint, // end position
551 _pathPolyRefs, // current path
552 _polyLength, // length of current path
553 pathPoints, // [out] path corner points
554 (int*)&pointCount,
555 _pointPathLimit); // maximum number of points
556 }
557
558 // Special case with start and end positions very close to each other
559 if (_polyLength == 1 && pointCount == 1)
560 {
561 // First point is start position, append end position
562 dtVcopy(&pathPoints[1 * VERTEX_SIZE], endPoint);
563 pointCount++;
564 }
565 else if (pointCount < 2 || dtStatusFailed(dtResult))
566 {
567 // only happens if pass bad data to findStraightPath or navmesh is broken
568 // single point paths can be generated here
572 return;
573 }
574 else if (pointCount >= _pointPathLimit)
575 {
578 return;
579 }
580
581 _pathPoints.resize(pointCount);
582 for (uint32 i = 0; i < pointCount; ++i)
583 _pathPoints[i] = G3D::Vector3(pathPoints[i * VERTEX_SIZE + 2], pathPoints[i * VERTEX_SIZE], pathPoints[i * VERTEX_SIZE + 1]);
584
586
587 // first point is always our current location - we need the next one
588 SetActualEndPosition(_pathPoints[pointCount - 1]);
589
590 // force the given destination, if needed
591 if (_forceDestination &&
593 {
594 // we may want to keep partial subpath
596 {
598 _pathPoints[_pathPoints.size() - 1] = GetEndPosition();
599 }
600 else
601 {
604 }
605
607 }
608}
#define LOG_ERROR(filterType__,...)
Definition: Log.h:159
#define VERTEX_SIZE
Definition: PathGenerator.h:42
@ PATHFIND_NOT_USING_PATH
Definition: PathGenerator.h:52
@ PATHFIND_NORMAL
Definition: PathGenerator.h:48
@ PATHFIND_NOPATH
Definition: PathGenerator.h:51
@ PATHFIND_SHORT
Definition: PathGenerator.h:53
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:106
std::string ToString() const
Definition: ObjectGuid.cpp:47
void SetActualEndPosition(G3D::Vector3 const &point)
Definition: PathGenerator.h:156
G3D::Vector3 const & GetStartPosition() const
Definition: PathGenerator.h:87
float Dist3DSqr(G3D::Vector3 const &p1, G3D::Vector3 const &p2) const
Definition: PathGenerator.cpp:1017
dtStatus FindSmoothPath(float const *startPos, float const *endPos, dtPolyRef const *polyPath, uint32 polyPathSize, float *smoothPath, int *smoothPathSize, uint32 smoothPathMaxSize)
Definition: PathGenerator.cpp:801
G3D::Vector3 const & GetEndPosition() const
Definition: PathGenerator.h:88
void BuildShortcut()
Definition: PathGenerator.cpp:618
void NormalizePath()
Definition: PathGenerator.cpp:610
Movement::PointsArray _pathPoints
Definition: PathGenerator.h:135
bool InRange(G3D::Vector3 const &p1, G3D::Vector3 const &p2, float r, float h) const
Definition: PathGenerator.cpp:1011
G3D::Vector3 const & GetActualEndPosition() const
Definition: PathGenerator.h:89

References _forceDestination, _navMeshQuery, _pathPoints, _pathPolyRefs, _pointPathLimit, _polyLength, _source, _type, _useRaycast, _useStraightPath, BuildShortcut(), Dist3DSqr(), FindSmoothPath(), GetActualEndPosition(), GetEndPosition(), Object::GetGUID(), GetStartPosition(), InRange(), LOG_ERROR, MAX_POINT_PATH_LENGTH, NormalizePath(), PATHFIND_NOPATH, PATHFIND_NORMAL, PATHFIND_NOT_USING_PATH, PATHFIND_SHORT, SetActualEndPosition(), ObjectGuid::ToString(), and VERTEX_SIZE.

Referenced by BuildPolyPath().

◆ BuildPolyPath()

void PathGenerator::BuildPolyPath ( G3D::Vector3 const &  startPos,
G3D::Vector3 const &  endPos 
)
private
Todo:
we can merge it with getPathPolyByPosition() loop
Todo:
play with the values here
163{
164 // *** getting start/end poly logic ***
165
166 float distToStartPoly, distToEndPoly;
167 float startPoint[VERTEX_SIZE] = { startPos.y, startPos.z, startPos.x };
168 float endPoint[VERTEX_SIZE] = { endPos.y, endPos.z, endPos.x };
169
170 dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
171 dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
172
174
175 Creature const* creature = _source->ToCreature();
176
177 // we have a hole in our mesh
178 // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
179 // its up to caller how he will use this info
180 if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
181 {
183
184 bool canSwim = creature ? creature->CanSwim() : true;
185 bool path = creature ? creature->CanFly() : true;
186 bool waterPath = IsWaterPath(_pathPoints);
187 if (path || (waterPath && canSwim))
188 {
190 return;
191 }
192
193 // raycast doesn't need endPoly to be valid
194 if (!_useRaycast)
195 {
197 return;
198 }
199 }
200
201 // we may need a better number here
202 bool startFarFromPoly = distToStartPoly > 7.0f;
203 bool endFarFromPoly = distToEndPoly > 7.0f;
204
205 // create a shortcut if the path begins or end too far
206 // away from the desired path points.
207 // swimming creatures should not use a shortcut
208 // because exiting the water must be done following a proper path
209 // we just need to remove/normalize paths between 2 adjacent points
210 if (startFarFromPoly || endFarFromPoly)
211 {
212 bool buildShortcut = false;
213
214 auto liquidDataStart = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
215 auto liquidDataEnd = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
216
217 bool startUnderWaterEndInWater = liquidDataStart.Status == LIQUID_MAP_UNDER_WATER &&
218 (liquidDataEnd.Status & MAP_LIQUID_STATUS_IN_CONTACT) != 0;
219 bool startInWaterEndUnderWater = (liquidDataStart.Status & MAP_LIQUID_STATUS_IN_CONTACT) != 0 &&
220 liquidDataEnd.Status == LIQUID_MAP_UNDER_WATER;
221 bool waterPath = startUnderWaterEndInWater || startInWaterEndUnderWater;
222 Unit const* _sourceUnit = _source->ToUnit();
223
224 if (_sourceUnit)
225 {
226 bool isWater = (_sourceUnit->CanSwim() && waterPath);
227
228 if (isWater || _sourceUnit->CanFly() || (_sourceUnit->IsFalling() && endPos.z < startPos.z))
229 {
230 buildShortcut = true;
231 }
232 }
233
234 if (buildShortcut)
235 {
238
239 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
240
241 return;
242 }
243 else
244 {
245 float closestPoint[VERTEX_SIZE];
246 // we may want to use closestPointOnPolyBoundary instead
247 if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint, nullptr)))
248 {
249 dtVcopy(endPoint, closestPoint);
250 SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
251 }
252
254
255 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
256 }
257 }
258
259 // *** poly path generating logic ***
260
261 // start and end are on same polygon
262 // handle this case as if they were 2 different polygons, building a line path split in some few points
263 if (startPoly == endPoly && !_useRaycast)
264 {
265 _pathPolyRefs[0] = startPoly;
266 _polyLength = 1;
267
268 if (startFarFromPoly || endFarFromPoly)
269 {
271
272 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
273 }
274 else
276
277 BuildPointPath(startPoint, endPoint);
278 return;
279 }
280
281 // look for startPoly/endPoly in current path
283 bool startPolyFound = false;
284 bool endPolyFound = false;
285 uint32 pathStartIndex = 0;
286 uint32 pathEndIndex = 0;
287
288 if (_polyLength)
289 {
290 for (; pathStartIndex < _polyLength; ++pathStartIndex)
291 {
292 // here to catch few bugs
293 if (_pathPolyRefs[pathStartIndex] == INVALID_POLYREF)
294 {
295 break;
296 }
297
298 if (_pathPolyRefs[pathStartIndex] == startPoly)
299 {
300 startPolyFound = true;
301 break;
302 }
303 }
304
305 for (pathEndIndex = _polyLength - 1; pathEndIndex > pathStartIndex; --pathEndIndex)
306 {
307 if (_pathPolyRefs[pathEndIndex] == endPoly)
308 {
309 endPolyFound = true;
310 break;
311 }
312 }
313 }
314
315 if (startPolyFound && endPolyFound)
316 {
317 // we moved along the path and the target did not move out of our old poly-path
318 // our path is a simple subpath case, we have all the data we need
319 // just "cut" it out
320
321 _polyLength = pathEndIndex - pathStartIndex + 1;
322 memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, _polyLength * sizeof(dtPolyRef));
323 }
324 else if (startPolyFound && !endPolyFound)
325 {
326 // we are moving on the old path but target moved out
327 // so we have atleast part of poly-path ready
328
329 _polyLength -= pathStartIndex;
330
331 // try to adjust the suffix of the path instead of recalculating entire length
332 // at given interval the target cannot get too far from its last location
333 // thus we have less poly to cover
334 // sub-path of optimal path is optimal
335
336 // take ~80% of the original length
338 uint32 prefixPolyLength = uint32(_polyLength * 0.8f + 0.5f);
339 memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, prefixPolyLength * sizeof(dtPolyRef));
340
341 dtPolyRef suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];
342
343 // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
344 float suffixEndPoint[VERTEX_SIZE];
345 if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, nullptr)))
346 {
347 // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
348 // try to recover by using prev polyref
349 --prefixPolyLength;
350 suffixStartPoly = _pathPolyRefs[prefixPolyLength - 1];
351 if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint, nullptr)))
352 {
353 // suffixStartPoly is still invalid, error state
356 return;
357 }
358 }
359
360 // generate suffix
361 uint32 suffixPolyLength = 0;
362
363 dtStatus dtResult;
364 if (_useRaycast)
365 {
368 return;
369 }
370 else
371 {
372 dtResult = _navMeshQuery->findPath(
373 suffixStartPoly, // start polygon
374 endPoly, // end polygon
375 suffixEndPoint, // start position
376 endPoint, // end position
377 &_filter, // polygon search filter
378 _pathPolyRefs + prefixPolyLength - 1, // [out] path
379 (int*)&suffixPolyLength,
380 MAX_PATH_LENGTH - prefixPolyLength); // max number of polygons in output path
381 }
382
383 if (!suffixPolyLength || dtStatusFailed(dtResult))
384 {
385 // this is probably an error state, but we'll leave it
386 // and hopefully recover on the next Update
387 // we still need to copy our preffix
388 LOG_ERROR("movement", "PathGenerator::BuildPolyPath: Path Build failed {}", _source->GetGUID().ToString());
389 }
390
391 // new path = prefix + suffix - overlap
392 _polyLength = prefixPolyLength + suffixPolyLength - 1;
393 }
394 else
395 {
396 // either we have no path at all -> first run
397 // or something went really wrong -> we aren't moving along the path to the target
398 // just generate new path
399
400 // free and invalidate old path data
401 Clear();
402
403 dtStatus dtResult;
404 if (_useRaycast)
405 {
406 float hit = 0;
407 float hitNormal[3];
408 memset(hitNormal, 0, sizeof(hitNormal));
409
410 dtResult = _navMeshQuery->raycast(
411 startPoly,
412 startPoint,
413 endPoint,
414 &_filter,
415 &hit,
416 hitNormal,
418 (int*)&_polyLength,
420
421 if (!_polyLength || dtStatusFailed(dtResult))
422 {
425 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
426 return;
427 }
428
429 // raycast() sets hit to FLT_MAX if there is a ray between start and end
430 if (hit != FLT_MAX)
431 {
432 float hitPos[3];
433
434 // 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)
435 hit *= 0.99f;
436 dtVlerp(hitPos, startPoint, endPoint, hit);
437
438 // if it fails again, clamp to poly boundary
439 if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], hitPos, &hitPos[1])))
440 _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], hitPos, hitPos);
441
442 _pathPoints.resize(2);
444 _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]);
445
448 AddFarFromPolyFlags(startFarFromPoly, false);
449 return;
450 }
451 else
452 {
453 // clamp to poly boundary if we fail to get the height
454 if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, &endPoint[1])))
455 _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], endPoint, endPoint);
456
457 _pathPoints.resize(2);
459 _pathPoints[1] = G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]);
460
462 if (startFarFromPoly || endFarFromPoly)
463 {
465
466 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
467 }
468 else
470 return;
471 }
472 }
473 else
474 {
475 dtResult = _navMeshQuery->findPath(
476 startPoly, // start polygon
477 endPoly, // end polygon
478 startPoint, // start position
479 endPoint, // end position
480 &_filter, // polygon search filter
481 _pathPolyRefs, // [out] path
482 (int*)&_polyLength,
483 MAX_PATH_LENGTH); // max number of polygons in output path
484 }
485
486 if (!_polyLength || dtStatusFailed(dtResult))
487 {
488 // only happens if we passed bad data to findPath(), or navmesh is messed up
489 LOG_ERROR("movement", "PathGenerator::BuildPolyPath: {} Path Build failed: 0 length path", _source->GetGUID().ToString());
492 return;
493 }
494 }
495
496 if (!_polyLength)
497 {
498 LOG_ERROR("movement", "PathGenerator::BuildPolyPath: {} Path Build failed: 0 length path", _source->GetGUID().ToString());
501 return;
502 }
503
504 // by now we know what type of path we can get
505 if (_pathPolyRefs[_polyLength - 1] == endPoly && !(_type & PATHFIND_INCOMPLETE))
506 {
508 }
509 else
510 {
512 }
513
514 AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
515
516 // generate the point-path out of our up-to-date poly-path
517 BuildPointPath(startPoint, endPoint);
518}
@ LIQUID_MAP_UNDER_WATER
Definition: Map.h:147
#define MAP_LIQUID_STATUS_IN_CONTACT
Definition: Map.h:151
#define MAP_ALL_LIQUIDS
Definition: Map.h:159
#define INVALID_POLYREF
Definition: PathGenerator.h:43
#define MAX_PATH_LENGTH
Definition: PathGenerator.h:36
@ PATHFIND_INCOMPLETE
Definition: PathGenerator.h:50
Definition: Creature.h:46
bool CanSwim() const override
This method check the current flag/status of a creature and its inhabit type.
Definition: Creature.cpp:3147
bool CanFly() const override
Definition: Creature.h:83
Creature * ToCreature()
Definition: Object.h:197
Unit * ToUnit()
Definition: Object.h:200
uint32 GetPhaseMask() const
Definition: Object.h:434
Map * GetMap() const
Definition: Object.h:517
virtual float GetCollisionHeight() const
Definition: Object.h:608
Definition: Unit.h:1290
LiquidStatus Status
Definition: Map.h:177
LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType)
Definition: Map.cpp:2204
void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly)
Definition: PathGenerator.cpp:1088
dtQueryFilterExt _filter
Definition: PathGenerator.h:152
dtPolyRef GetPolyByLocation(float const *Point, float *Distance) const
Definition: PathGenerator.cpp:127
bool IsWaterPath(Movement::PointsArray pathPoints) const
Definition: PathGenerator.cpp:1138
void BuildPointPath(float const *startPoint, float const *endPoint)
Definition: PathGenerator.cpp:520
void Clear()
Definition: PathGenerator.h:125

References _filter, _navMeshQuery, _pathPoints, _pathPolyRefs, _polyLength, _source, _type, _useRaycast, AddFarFromPolyFlags(), BuildPointPath(), BuildShortcut(), Creature::CanFly(), Creature::CanSwim(), Clear(), WorldObject::GetCollisionHeight(), Object::GetGUID(), Map::GetLiquidData(), WorldObject::GetMap(), WorldObject::GetPhaseMask(), GetPolyByLocation(), GetStartPosition(), INVALID_POLYREF, IsWaterPath(), LIQUID_MAP_UNDER_WATER, LOG_ERROR, MAP_ALL_LIQUIDS, MAP_LIQUID_STATUS_IN_CONTACT, MAX_PATH_LENGTH, NormalizePath(), PATHFIND_INCOMPLETE, PATHFIND_NOPATH, PATHFIND_NORMAL, PATHFIND_NOT_USING_PATH, SetActualEndPosition(), LiquidData::Status, Object::ToCreature(), ObjectGuid::ToString(), Object::ToUnit(), and VERTEX_SIZE.

Referenced by CalculatePath().

◆ BuildShortcut()

void PathGenerator::BuildShortcut ( )
private
619{
620 Clear();
621
622 // make two point path, our curr pos is the start, and dest is the end
623 _pathPoints.resize(2);
624
625 // set start and a default next position
628
630
632}
@ PATHFIND_SHORTCUT
Definition: PathGenerator.h:49

References _pathPoints, _type, Clear(), GetActualEndPosition(), GetStartPosition(), NormalizePath(), and PATHFIND_SHORTCUT.

Referenced by BuildPointPath(), BuildPolyPath(), and CalculatePath().

◆ CalculatePath() [1/2]

bool PathGenerator::CalculatePath ( float  destX,
float  destY,
float  destZ,
bool  forceDest = false 
)
53{
54 float x, y, z;
55 _source->GetPosition(x, y, z);
56
57 return CalculatePath(x, y, z, destX, destY, destZ, forceDest);
58}
void GetPosition(float &x, float &y) const
Definition: Position.h:122
bool CalculatePath(float destX, float destY, float destZ, bool forceDest=false)
Definition: PathGenerator.cpp:52

References _source, CalculatePath(), and Position::GetPosition().

Referenced by CalculatePath(), Map::CheckCollisionAndGetValidCoords(), mmaps_commandscript::HandleMmapPathCommand(), mmaps_commandscript::HandleMmapTestArea(), and Movement::MoveSplineInit::MoveTo().

◆ CalculatePath() [2/2]

bool PathGenerator::CalculatePath ( float  x,
float  y,
float  z,
float  destX,
float  destY,
float  destZ,
bool  forceDest 
)
61{
62 if (!Acore::IsValidMapCoord(destX, destY, destZ) || !Acore::IsValidMapCoord(x, y, z))
63 return false;
64
65 METRIC_DETAILED_EVENT("mmap_events", "CalculatePath", "");
66
67 G3D::Vector3 dest(destX, destY, destZ);
68 SetEndPosition(dest);
69
70 G3D::Vector3 start(x, y, z);
71 SetStartPosition(start);
72
73 _forceDestination = forceDest;
74
75 // make sure navMesh works - we can run on map w/o mmap
76 // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
77 Unit const* _sourceUnit = _source->ToUnit();
78 if (!_navMesh || !_navMeshQuery || (_sourceUnit && _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING)) ||
79 !HaveTile(start) || !HaveTile(dest))
80 {
83 return true;
84 }
85
87
88 BuildPolyPath(start, dest);
89 return true;
90}
#define METRIC_DETAILED_EVENT(category, title, description)
Definition: Metric.h:220
@ UNIT_STATE_IGNORE_PATHFINDING
Definition: Unit.h:352
bool IsValidMapCoord(float c)
Definition: GridDefines.h:216
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1398
bool HaveTile(G3D::Vector3 const &p) const
Definition: PathGenerator.cpp:702
void BuildPolyPath(G3D::Vector3 const &startPos, G3D::Vector3 const &endPos)
Definition: PathGenerator.cpp:162
void SetStartPosition(G3D::Vector3 const &point)
Definition: PathGenerator.h:154
void UpdateFilter()
Definition: PathGenerator.cpp:661
void SetEndPosition(G3D::Vector3 const &point)
Definition: PathGenerator.h:155

References _forceDestination, _navMesh, _navMeshQuery, _source, _type, BuildPolyPath(), BuildShortcut(), Unit::HasUnitState(), HaveTile(), Acore::IsValidMapCoord(), METRIC_DETAILED_EVENT, PATHFIND_NORMAL, PATHFIND_NOT_USING_PATH, SetEndPosition(), SetStartPosition(), Object::ToUnit(), UNIT_STATE_IGNORE_PATHFINDING, and UpdateFilter().

◆ Clear()

void PathGenerator::Clear ( )
inline
126 {
127 _polyLength = 0;
128 _pathPoints.clear();
129 }

References _pathPoints, and _polyLength.

Referenced by BuildPolyPath(), and BuildShortcut().

◆ CreateFilter()

void PathGenerator::CreateFilter ( )
private
635{
636 uint16 includeFlags = 0;
637 uint16 excludeFlags = 0;
638
639 if (_source->GetTypeId() == TYPEID_UNIT)
640 {
641 Creature* creature = (Creature*)_source;
642 if (creature->CanWalk())
643 includeFlags |= NAV_GROUND; // walk
644
645 // creatures don't take environmental damage
646 if (creature->CanEnterWater())
647 includeFlags |= (NAV_WATER | NAV_MAGMA);
648 }
649 else // assume Player
650 {
651 // perfect support not possible, just stay 'safe'
652 includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA);
653 }
654
655 _filter.setIncludeFlags(includeFlags);
656 _filter.setExcludeFlags(excludeFlags);
657
658 UpdateFilter();
659}
@ NAV_MAGMA
Definition: MapDefines.h:43
@ NAV_GROUND
Definition: MapDefines.h:42
@ NAV_WATER
Definition: MapDefines.h:45
std::uint16_t uint16
Definition: Define.h:109
@ TYPEID_UNIT
Definition: ObjectGuid.h:37
bool CanWalk() const
Definition: Creature.h:80
bool CanEnterWater() const override
Definition: Creature.cpp:3158
TypeID GetTypeId() const
Definition: Object.h:121

References _filter, _source, Creature::CanEnterWater(), Creature::CanWalk(), Object::GetTypeId(), NAV_GROUND, NAV_MAGMA, NAV_WATER, TYPEID_UNIT, and UpdateFilter().

Referenced by PathGenerator().

◆ Dist3DSqr()

float PathGenerator::Dist3DSqr ( G3D::Vector3 const &  p1,
G3D::Vector3 const &  p2 
) const
private
1018{
1019 return (p1 - p2).squaredLength();
1020}

Referenced by BuildPointPath().

◆ FindSmoothPath()

dtStatus PathGenerator::FindSmoothPath ( float const *  startPos,
float const *  endPos,
dtPolyRef const *  polyPath,
uint32  polyPathSize,
float *  smoothPath,
int *  smoothPathSize,
uint32  smoothPathMaxSize 
)
private
804{
805 *smoothPathSize = 0;
806 uint32 nsmoothPath = 0;
807
808 dtPolyRef polys[MAX_PATH_LENGTH];
809 memcpy(polys, polyPath, sizeof(dtPolyRef) * polyPathSize);
810 uint32 npolys = polyPathSize;
811
812 float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE];
813
814 if (polyPathSize > 1)
815 {
816 // Pick the closest points on poly border
817 if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
818 {
819 return DT_FAILURE;
820 }
821
822 if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[npolys - 1], endPos, targetPos)))
823 {
824 return DT_FAILURE;
825 }
826 }
827 else
828 {
829 // Case where the path is on the same poly
830 dtVcopy(iterPos, startPos);
831 dtVcopy(targetPos, endPos);
832 }
833
834 dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], iterPos);
835 nsmoothPath++;
836
837 // Move towards target a small advancement at a time until target reached or
838 // when ran out of memory to store the path.
839 while (npolys && nsmoothPath < maxSmoothPathSize)
840 {
841 // Find location to steer towards.
842 float steerPos[VERTEX_SIZE];
843 unsigned char steerPosFlag;
844 dtPolyRef steerPosRef = INVALID_POLYREF;
845
846 if (!GetSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef))
847 break;
848
849 bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END) != 0;
850 bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0;
851
852 // Find movement delta.
853 float delta[VERTEX_SIZE];
854 dtVsub(delta, steerPos, iterPos);
855 float len = dtMathSqrtf(dtVdot(delta, delta));
856 // If the steer target is end of path or off-mesh link, do not move past the location.
857 if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
858 len = 1.0f;
859 else
860 len = SMOOTH_PATH_STEP_SIZE / len;
861
862 float moveTgt[VERTEX_SIZE];
863 dtVmad(moveTgt, iterPos, delta, len);
864
865 // Move
866 float result[VERTEX_SIZE];
867 const static uint32 MAX_VISIT_POLY = 16;
868 dtPolyRef visited[MAX_VISIT_POLY];
869
870 uint32 nvisited = 0;
871 if (dtStatusFailed(_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY)))
872 {
873 return DT_FAILURE;
874 }
875 npolys = FixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited);
876
877 if (dtStatusFailed(_navMeshQuery->getPolyHeight(polys[0], result, &result[1])))
878 LOG_DEBUG("maps", "PathGenerator::FindSmoothPath: Cannot find height at position X: {} Y: {} Z: {} for {}",
879 result[2], result[0], result[1], _source->GetGUID().ToString());
880 result[1] += 0.5f;
881 dtVcopy(iterPos, result);
882
883 bool canCheckSlope = _slopeCheck && (GetPathType() & ~(PATHFIND_NOT_USING_PATH));
884
885 if (canCheckSlope && !IsSwimmableSegment(iterPos, steerPos) && !IsWalkableClimb(iterPos, steerPos))
886 {
887 return DT_FAILURE;
888 }
889
890 // Handle end of path and off-mesh links when close enough.
891 if (endOfPath && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
892 {
893 // Reached end of path.
894 dtVcopy(iterPos, targetPos);
895 if (nsmoothPath < maxSmoothPathSize)
896 {
897 dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], iterPos);
898 nsmoothPath++;
899 }
900 break;
901 }
902 else if (offMeshConnection && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
903 {
904 // Advance the path up to and over the off-mesh connection.
905 dtPolyRef prevRef = INVALID_POLYREF;
906 dtPolyRef polyRef = polys[0];
907 uint32 npos = 0;
908 while (npos < npolys && polyRef != steerPosRef)
909 {
910 prevRef = polyRef;
911 polyRef = polys[npos];
912 npos++;
913 }
914
915 for (uint32 i = npos; i < npolys; ++i)
916 polys[i - npos] = polys[i];
917
918 npolys -= npos;
919
920 // Handle the connection.
921 float connectionStartPos[VERTEX_SIZE], connectionEndPos[VERTEX_SIZE];
922 if (dtStatusSucceed(_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, connectionStartPos, connectionEndPos)))
923 {
924 if (nsmoothPath < maxSmoothPathSize)
925 {
926 dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], connectionStartPos);
927 nsmoothPath++;
928 }
929 // Move position at the other side of the off-mesh link.
930 dtVcopy(iterPos, connectionEndPos);
931 if (dtStatusFailed(_navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1])))
932 return DT_FAILURE;
933 iterPos[1] += 0.5f;
934 }
935 }
936
937 // Store results.
938 if (nsmoothPath < maxSmoothPathSize)
939 {
940 dtVcopy(&smoothPath[nsmoothPath * VERTEX_SIZE], iterPos);
941 nsmoothPath++;
942 }
943 }
944
945 *smoothPathSize = nsmoothPath;
946
947 // this is most likely a loop
948 return nsmoothPath < MAX_POINT_PATH_LENGTH ? DT_SUCCESS : DT_FAILURE;
949}
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:171
#define SMOOTH_PATH_SLOP
Definition: PathGenerator.h:40
#define SMOOTH_PATH_STEP_SIZE
Definition: PathGenerator.h:39
PathType GetPathType() const
Definition: PathGenerator.h:93
bool IsWalkableClimb(float const *v1, float const *v2) const
Definition: PathGenerator.cpp:951
bool InRangeYZX(float const *v1, float const *v2, float r, float h) const
Definition: PathGenerator.cpp:1003
uint32 FixupCorridor(dtPolyRef *path, uint32 npath, uint32 maxPath, dtPolyRef const *visited, uint32 nvisited)
Definition: PathGenerator.cpp:718
bool IsSwimmableSegment(float const *v1, float const *v2, bool checkSwim=true) const
predict if a certain segment is underwater and the unit can swim Must only be used for very short seg...
Definition: PathGenerator.cpp:1110
bool GetSteerTarget(float const *startPos, float const *endPos, float minTargetDist, dtPolyRef const *path, uint32 pathSize, float *steerPos, unsigned char &steerPosFlag, dtPolyRef &steerPosRef)
Definition: PathGenerator.cpp:763

References _filter, _navMesh, _navMeshQuery, _slopeCheck, _source, FixupCorridor(), Object::GetGUID(), GetPathType(), GetSteerTarget(), InRangeYZX(), INVALID_POLYREF, IsSwimmableSegment(), IsWalkableClimb(), LOG_DEBUG, MAX_PATH_LENGTH, MAX_POINT_PATH_LENGTH, PATHFIND_NOT_USING_PATH, SMOOTH_PATH_SLOP, SMOOTH_PATH_STEP_SIZE, ObjectGuid::ToString(), and VERTEX_SIZE.

Referenced by BuildPointPath().

◆ FixupCorridor()

uint32 PathGenerator::FixupCorridor ( dtPolyRef *  path,
uint32  npath,
uint32  maxPath,
dtPolyRef const *  visited,
uint32  nvisited 
)
private
719{
720 int32 furthestPath = -1;
721 int32 furthestVisited = -1;
722
723 // Find furthest common polygon.
724 for (int32 i = npath - 1; i >= 0; --i)
725 {
726 bool found = false;
727 for (int32 j = nvisited - 1; j >= 0; --j)
728 {
729 if (path[i] == visited[j])
730 {
731 furthestPath = i;
732 furthestVisited = j;
733 found = true;
734 }
735 }
736 if (found)
737 break;
738 }
739
740 // If no intersection found just return current path.
741 if (furthestPath == -1 || furthestVisited == -1)
742 return npath;
743
744 // Concatenate paths.
745
746 // Adjust beginning of the buffer to include the visited.
747 uint32 req = nvisited - furthestVisited;
748 uint32 orig = uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
749 uint32 size = npath > orig ? npath - orig : 0;
750 if (req + size > maxPath)
751 size = maxPath - req;
752
753 if (size)
754 memmove(path + req, path + orig, size * sizeof(dtPolyRef));
755
756 // Store visited
757 for (uint32 i = 0; i < req; ++i)
758 path[i] = visited[(nvisited - 1) - i];
759
760 return req + size;
761}
std::int32_t int32
Definition: Define.h:104

Referenced by FindSmoothPath().

◆ GetActualEndPosition()

G3D::Vector3 const & PathGenerator::GetActualEndPosition ( ) const
inline

◆ GetEndPosition()

G3D::Vector3 const & PathGenerator::GetEndPosition ( ) const
inline

◆ GetNavTerrain()

NavTerrain PathGenerator::GetNavTerrain ( float  x,
float  y,
float  z 
) const
private
684{
686 if (liquidData.Status == LIQUID_MAP_NO_WATER)
687 return NAV_GROUND;
688
689 switch (liquidData.Flags)
690 {
693 return NAV_WATER;
696 return NAV_MAGMA;
697 default:
698 return NAV_GROUND;
699 }
700}
#define MAP_LIQUID_TYPE_MAGMA
Definition: Map.h:156
@ LIQUID_MAP_NO_WATER
Definition: Map.h:143
#define MAP_LIQUID_TYPE_WATER
Definition: Map.h:154
#define MAP_LIQUID_TYPE_OCEAN
Definition: Map.h:155
#define MAP_LIQUID_TYPE_SLIME
Definition: Map.h:157
Definition: Map.h:170
uint32 Flags
Definition: Map.h:174

References _source, LiquidData::Flags, WorldObject::GetCollisionHeight(), Map::GetLiquidData(), WorldObject::GetMap(), WorldObject::GetPhaseMask(), LIQUID_MAP_NO_WATER, MAP_ALL_LIQUIDS, MAP_LIQUID_TYPE_MAGMA, MAP_LIQUID_TYPE_OCEAN, MAP_LIQUID_TYPE_SLIME, MAP_LIQUID_TYPE_WATER, NAV_GROUND, NAV_MAGMA, NAV_WATER, and LiquidData::Status.

Referenced by IsWaterPath(), and UpdateFilter().

◆ GetPath()

◆ getPathLength()

float PathGenerator::getPathLength ( ) const
inline
99 {
100 float len = 0.0f;
101 float dx, dy, dz;
102 uint32 size = _pathPoints.size();
103 if (size)
104 {
105 dx = _pathPoints[0].x - _startPosition.x;
106 dy = _pathPoints[0].y - _startPosition.y;
107 dz = _pathPoints[0].z - _startPosition.z;
108 len += std::sqrt( dx * dx + dy * dy + dz * dz );
109 }
110 else
111 {
112 return len;
113 }
114
115 for (uint32 i = 1; i < size; ++i)
116 {
117 dx = _pathPoints[i].x - _pathPoints[i - 1].x;
118 dy = _pathPoints[i].y - _pathPoints[i - 1].y;
119 dz = _pathPoints[i].z - _pathPoints[i - 1].z;
120 len += std::sqrt( dx * dx + dy * dy + dz * dz );
121 }
122 return len;
123 }
G3D::Vector3 _startPosition
Definition: PathGenerator.h:144

References _pathPoints, and _startPosition.

◆ GetPathPolyByPosition()

dtPolyRef PathGenerator::GetPathPolyByPosition ( dtPolyRef const *  polyPath,
uint32  polyPathSize,
float const *  Point,
float *  Distance = nullptr 
) const
private
93{
94 if (!polyPath || !polyPathSize)
95 return INVALID_POLYREF;
96
97 dtPolyRef nearestPoly = INVALID_POLYREF;
98 float minDist = FLT_MAX;
99
100 for (uint32 i = 0; i < polyPathSize; ++i)
101 {
102 float closestPoint[VERTEX_SIZE];
103 if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint, nullptr)))
104 continue;
105
106 float d = dtVdistSqr(point, closestPoint);
107 if (d < minDist)
108 {
109 minDist = d;
110 nearestPoly = polyPath[i];
111 }
112
113 if (minDist < 1.0f) // shortcut out - close enough for us
114 {
115 break;
116 }
117 }
118
119 if (distance)
120 {
121 *distance = dtMathSqrtf(minDist);
122 }
123
124 return (minDist < 3.0f) ? nearestPoly : INVALID_POLYREF;
125}

References _navMeshQuery, INVALID_POLYREF, and VERTEX_SIZE.

Referenced by GetPolyByLocation().

◆ GetPathType()

◆ GetPolyByLocation()

dtPolyRef PathGenerator::GetPolyByLocation ( float const *  Point,
float *  Distance 
) const
private
128{
129 // first we check the current path
130 // if the current path doesn't contain the current poly,
131 // we need to use the expensive navMesh.findNearestPoly
132 dtPolyRef polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, distance);
133 if (polyRef != INVALID_POLYREF)
134 return polyRef;
135
136 // we don't have it in our old path
137 // try to get it by findNearestPoly()
138 // first try with low search box
139 float extents[VERTEX_SIZE] = { 3.0f, 5.0f, 3.0f }; // bounds of poly search area
140 float closestPoint[VERTEX_SIZE] = { 0.0f, 0.0f, 0.0f };
141 if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
142 {
143 *distance = dtVdist(closestPoint, point);
144 return polyRef;
145 }
146
147 // still nothing ..
148 // try with bigger search box
149 // Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly)
150 extents[1] = 50.0f;
151
152 if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
153 {
154 *distance = dtVdist(closestPoint, point);
155 return polyRef;
156 }
157
158 *distance = FLT_MAX;
159 return INVALID_POLYREF;
160}
dtPolyRef GetPathPolyByPosition(dtPolyRef const *polyPath, uint32 polyPathSize, float const *Point, float *Distance=nullptr) const
Definition: PathGenerator.cpp:92

References _filter, _navMeshQuery, _pathPolyRefs, _polyLength, GetPathPolyByPosition(), INVALID_POLYREF, and VERTEX_SIZE.

Referenced by BuildPolyPath().

◆ GetRequiredHeightToClimb()

float PathGenerator::GetRequiredHeightToClimb ( float  x,
float  y,
float  z,
float  destX,
float  destY,
float  destZ,
float  sourceHeight 
)
static

Return the height of a slope that can be climbed based on source height This method is meant for short distances or linear paths.

Parameters
xstart x coord
ystart y coord
zstart z coord
destXdestination x coord
destYdestination y coord
destZdestination z coord
sourceHeightheight of the source
Returns
float the maximum height that a source can climb based on slope angle
996{
997 float slopeAngle = getSlopeAngleAbs(x, y, z, destX, destY, destZ);
998 float slopeAngleDegree = (slopeAngle * 180.0f / M_PI);
999 float climbableHeight = sourceHeight - (sourceHeight * (slopeAngleDegree / 100));
1000 return climbableHeight;
1001}
float getSlopeAngleAbs(float startX, float startY, float startZ, float destX, float destY, float destZ)
Definition: Geometry.h:48

References getSlopeAngleAbs().

Referenced by IsWalkableClimb().

◆ GetStartPosition()

G3D::Vector3 const & PathGenerator::GetStartPosition ( ) const
inline

◆ GetSteerTarget()

bool PathGenerator::GetSteerTarget ( float const *  startPos,
float const *  endPos,
float  minTargetDist,
dtPolyRef const *  path,
uint32  pathSize,
float *  steerPos,
unsigned char &  steerPosFlag,
dtPolyRef &  steerPosRef 
)
private
766{
767 // Find steer target.
768 static const uint32 MAX_STEER_POINTS = 3;
769 float steerPath[MAX_STEER_POINTS * VERTEX_SIZE];
770 unsigned char steerPathFlags[MAX_STEER_POINTS];
771 dtPolyRef steerPathPolys[MAX_STEER_POINTS];
772 uint32 nsteerPath = 0;
773 dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
774 steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
775 if (!nsteerPath || dtStatusFailed(dtResult))
776 return false;
777
778 // Find vertex far enough to steer to.
779 uint32 ns = 0;
780 while (ns < nsteerPath)
781 {
782 // Stop at Off-Mesh link or when point is further than slop away.
783 if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
784 !InRangeYZX(&steerPath[ns * VERTEX_SIZE], startPos, minTargetDist, 1000.0f))
785 break;
786
787 ns++;
788 }
789 // Failed to find good point to steer to.
790 if (ns >= nsteerPath)
791 return false;
792
793 dtVcopy(steerPos, &steerPath[ns * VERTEX_SIZE]);
794 steerPos[1] = startPos[1]; // keep Z value
795 steerPosFlag = steerPathFlags[ns];
796 steerPosRef = steerPathPolys[ns];
797
798 return true;
799}

References _navMeshQuery, InRangeYZX(), and VERTEX_SIZE.

Referenced by FindSmoothPath().

◆ HaveTile()

bool PathGenerator::HaveTile ( G3D::Vector3 const &  p) const
private

Workaround For some reason, often the tx and ty variables wont get a valid value Use this check to prevent getting negative tile coords and crashing on getTileAt

703{
704 int tx = -1, ty = -1;
705 float point[VERTEX_SIZE] = { p.y, p.z, p.x };
706
707 _navMesh->calcTileLoc(point, &tx, &ty);
708
712 if (tx < 0 || ty < 0)
713 return false;
714
715 return (_navMesh->getTileAt(tx, ty, 0) != nullptr);
716}

References _navMesh, and VERTEX_SIZE.

Referenced by CalculatePath().

◆ InRange()

bool PathGenerator::InRange ( G3D::Vector3 const &  p1,
G3D::Vector3 const &  p2,
float  r,
float  h 
) const
private
1012{
1013 G3D::Vector3 d = p1 - p2;
1014 return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
1015}

Referenced by BuildPointPath().

◆ InRangeYZX()

bool PathGenerator::InRangeYZX ( float const *  v1,
float const *  v2,
float  r,
float  h 
) const
private
1004{
1005 const float dx = v2[0] - v1[0];
1006 const float dy = v2[1] - v1[1]; // elevation
1007 const float dz = v2[2] - v1[2];
1008 return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
1009}

Referenced by FindSmoothPath(), and GetSteerTarget().

◆ IsInvalidDestinationZ()

bool PathGenerator::IsInvalidDestinationZ ( Unit const *  target) const
1084{
1085 return (target->GetPositionZ() - GetActualEndPosition().z) > 5.0f;
1086}

References GetActualEndPosition(), and Position::GetPositionZ().

◆ IsSwimmableSegment() [1/2]

bool PathGenerator::IsSwimmableSegment ( float const *  v1,
float const *  v2,
bool  checkSwim = true 
) const

predict if a certain segment is underwater and the unit can swim Must only be used for very short segments since this check doesn't work on long paths that alternate terrain and water.

Parameters
v1
v2
Returns
true
false
1111{
1112 return IsSwimmableSegment(v1[2], v1[0], v1[1], v2[2], v2[0], v2[1], checkSwim);
1113}

References IsSwimmableSegment().

Referenced by FindSmoothPath(), IsSwimmableSegment(), and ShortenPathUntilDist().

◆ IsSwimmableSegment() [2/2]

bool PathGenerator::IsSwimmableSegment ( float  x,
float  y,
float  z,
float  destX,
float  destY,
float  destZ,
bool  checkSwim = true 
) const

predict if a certain segment is underwater and the unit can swim Must only be used for very short segments since this check doesn't work on long paths that alternate terrain and water.

Parameters
x
y
z
destX
destY
destZ
checkSwimalso check if the unit can swim
Returns
true if there's water at the end AND at the start of the segment
false if there's no water at the end OR at the start of the segment
1131{
1132 Creature const* _sourceCreature = _source->ToCreature();
1134 _source->GetMap()->IsInWater(_source->GetPhaseMask(), destX, destY, destZ, _source->GetCollisionHeight()) &&
1135 (!checkSwim || !_sourceCreature || _sourceCreature->CanSwim());
1136}
bool IsInWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) const
Definition: Map.cpp:2495

References _source, Creature::CanSwim(), WorldObject::GetCollisionHeight(), WorldObject::GetMap(), WorldObject::GetPhaseMask(), Map::IsInWater(), and Object::ToCreature().

◆ IsWalkableClimb() [1/3]

bool PathGenerator::IsWalkableClimb ( float const *  v1,
float const *  v2 
) const
952{
953 return IsWalkableClimb(v1[2], v1[0], v1[1], v2[2], v2[0], v2[1]);
954}

References IsWalkableClimb().

Referenced by Map::CanReachPositionAndGetValidCoords(), FindSmoothPath(), IsWalkableClimb(), and ShortenPathUntilDist().

◆ IsWalkableClimb() [2/3]

bool PathGenerator::IsWalkableClimb ( float  x,
float  y,
float  z,
float  destX,
float  destY,
float  destZ 
) const
957{
958 return IsWalkableClimb(x, y, z, destX, destY, destZ, _source->GetCollisionHeight());
959}

References _source, WorldObject::GetCollisionHeight(), and IsWalkableClimb().

◆ IsWalkableClimb() [3/3]

bool PathGenerator::IsWalkableClimb ( float  x,
float  y,
float  z,
float  destX,
float  destY,
float  destZ,
float  sourceHeight 
)
static

Check if a slope can be climbed based on source height This method is meant for short distances or linear paths.

Parameters
xstart x coord
ystart y coord
zstart z coord
destXdestination x coord
destYdestination y coord
destZdestination z coord
sourceHeightheight of the source
Returns
bool check if you can climb the path
975{
976 float diffHeight = std::abs(destZ - z);
977 float reqHeight = GetRequiredHeightToClimb(x, y, z, destX, destY, destZ, sourceHeight);
978 // check walkable slopes, based on unit height
979 return diffHeight <= reqHeight;
980}
static float GetRequiredHeightToClimb(float x, float y, float z, float destX, float destY, float destZ, float sourceHeight)
Return the height of a slope that can be climbed based on source height This method is meant for shor...
Definition: PathGenerator.cpp:995

References GetRequiredHeightToClimb().

◆ IsWaterPath()

bool PathGenerator::IsWaterPath ( Movement::PointsArray  pathPoints) const
1139{
1140 bool waterPath = true;
1141 // Check both start and end points, if they're both in water, then we can *safely* let the creature move
1142 for (uint32 i = 0; i < pathPoints.size(); ++i)
1143 {
1144 NavTerrain terrain = GetNavTerrain(pathPoints[i].x, pathPoints[i].y, pathPoints[i].z);
1145 // One of the points is not in the water
1146 if (terrain != NAV_MAGMA && terrain != NAV_WATER)
1147 {
1148 waterPath = false;
1149 break;
1150 }
1151 }
1152
1153 return waterPath;
1154}
NavTerrain
Definition: MapDefines.h:40
NavTerrain GetNavTerrain(float x, float y, float z) const
Definition: PathGenerator.cpp:683

References GetNavTerrain(), NAV_MAGMA, and NAV_WATER.

Referenced by BuildPolyPath().

◆ NormalizePath()

void PathGenerator::NormalizePath ( )
private
611{
612 for (uint32 i = 0; i < _pathPoints.size(); ++i)
613 {
615 }
616}
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1554

References _pathPoints, _source, and WorldObject::UpdateAllowedPositionZ().

Referenced by BuildPointPath(), BuildPolyPath(), and BuildShortcut().

◆ SetActualEndPosition()

void PathGenerator::SetActualEndPosition ( G3D::Vector3 const &  point)
inlineprivate
156{ _actualEndPosition = point; }

References _actualEndPosition.

Referenced by BuildPointPath(), and BuildPolyPath().

◆ SetEndPosition()

void PathGenerator::SetEndPosition ( G3D::Vector3 const &  point)
inlineprivate
155{ _actualEndPosition = point; _endPosition = point; }

References _actualEndPosition, and _endPosition.

Referenced by CalculatePath().

◆ SetPathLengthLimit()

void PathGenerator::SetPathLengthLimit ( float  distance)
inline

◆ SetSlopeCheck()

void PathGenerator::SetSlopeCheck ( bool  checkSlope)
inline
81{ _slopeCheck = checkSlope; }

References _slopeCheck.

◆ SetStartPosition()

void PathGenerator::SetStartPosition ( G3D::Vector3 const &  point)
inlineprivate
154{ _startPosition = point; }

References _startPosition.

Referenced by CalculatePath().

◆ SetUseRaycast()

void PathGenerator::SetUseRaycast ( bool  useRaycast)
inline

◆ SetUseStraightPath()

void PathGenerator::SetUseStraightPath ( bool  useStraightPath)
inline
82{ _useStraightPath = useStraightPath; }

References _useStraightPath.

Referenced by mmaps_commandscript::HandleMmapPathCommand().

◆ ShortenPathUntilDist()

void PathGenerator::ShortenPathUntilDist ( G3D::Vector3 const &  point,
float  dist 
)
1023{
1024 if (GetPathType() == PATHFIND_BLANK || _pathPoints.size() < 2)
1025 {
1026 LOG_ERROR("movement", "PathGenerator::ReducePathLengthByDist called before path was successfully built");
1027 return;
1028 }
1029
1030 float const distSq = dist * dist;
1031
1032 // the first point of the path must be outside the specified range
1033 // (this should have really been checked by the caller...)
1034 if ((_pathPoints[0] - target).squaredLength() < distSq)
1035 return;
1036
1037 // check if we even need to do anything
1038 if ((*_pathPoints.rbegin() - target).squaredLength() >= distSq)
1039 return;
1040
1041 size_t i = _pathPoints.size() - 1;
1042 float x, y, z, collisionHeight = _source->GetCollisionHeight();
1043 // find the first i s.t.:
1044 // - _pathPoints[i] is still too close
1045 // - _pathPoints[i-1] is too far away
1046 // => the end point is somewhere on the line between the two
1047 while (1)
1048 {
1049 // we know that pathPoints[i] is too close already (from the previous iteration)
1050 if ((_pathPoints[i - 1] - target).squaredLength() >= distSq)
1051 break; // bingo!
1052
1053 bool canCheckSlope = _slopeCheck && (GetPathType() & ~(PATHFIND_NOT_USING_PATH));
1054
1055 // check if the shortened path is still in LoS with the target and it is walkable
1056 _source->GetHitSpherePointFor({ _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z + collisionHeight }, x, y, z);
1057 if (!_source->GetMap()->isInLineOfSight(x, y, z, _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z + collisionHeight,
1061 {
1062 // whenver we find a point that is not valid anymore, simply use last valid path
1063 _pathPoints.resize(i + 1);
1064 return;
1065 }
1066
1067 if (!--i)
1068 {
1069 // no point found that fulfills the condition
1070 _pathPoints[0] = _pathPoints[1];
1071 _pathPoints.resize(2);
1072 return;
1073 }
1074 }
1075
1076 // ok, _pathPoints[i] is too close, _pathPoints[i-1] is not, so our target point is somewhere between the two...
1077 // ... settle for a guesstimate since i'm not confident in doing trig on every chase motion tick...
1078 // (@todo review this)
1079 _pathPoints[i] += (_pathPoints[i - 1] - _pathPoints[i]).direction() * (dist - (_pathPoints[i] - target).length());
1080 _pathPoints.resize(i + 1);
1081}
@ LINEOFSIGHT_ALL_CHECKS
Definition: Map.h:197
Position GetHitSpherePointFor(Position const &dest, Optional< float > collisionHeight={ }, Optional< float > combatReach={ }) const
Definition: Object.cpp:1236
float GetPositionZ() const
Definition: Position.h:119
float GetPositionX() const
Definition: Position.h:117
float GetPositionY() const
Definition: Position.h:118
bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition: Map.cpp:2441

References _pathPoints, _slopeCheck, _source, WorldObject::GetCollisionHeight(), WorldObject::GetHitSpherePointFor(), WorldObject::GetMap(), GetPathType(), WorldObject::GetPhaseMask(), Position::GetPositionX(), Position::GetPositionY(), Position::GetPositionZ(), Map::isInLineOfSight(), IsSwimmableSegment(), IsWalkableClimb(), LINEOFSIGHT_ALL_CHECKS, LOG_ERROR, VMAP::Nothing, PATHFIND_BLANK, and PATHFIND_NOT_USING_PATH.

◆ UpdateFilter()

void PathGenerator::UpdateFilter ( )
private
662{
663 // allow creatures to cheat and use different movement types if they are moved
664 // forcefully into terrain they can't normally move in
665 if (Unit const* _sourceUnit = _source->ToUnit())
666 {
667 if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
668 {
669 uint16 includedFlags = _filter.getIncludeFlags();
670 includedFlags |= GetNavTerrain(_source->GetPositionX(),
673
674 _filter.setIncludeFlags(includedFlags);
675 }
676
677 /*if (Creature const* _sourceCreature = _source->ToCreature())
678 if (_sourceCreature->IsInCombat() || _sourceCreature->IsInEvadeMode())
679 _filter.setIncludeFlags(_filter.getIncludeFlags() | NAV_GROUND_STEEP);*/
680 }
681}

References _filter, _source, GetNavTerrain(), Position::GetPositionX(), Position::GetPositionY(), Position::GetPositionZ(), and Object::ToUnit().

Referenced by CalculatePath(), and CreateFilter().

Member Data Documentation

◆ _actualEndPosition

G3D::Vector3 PathGenerator::_actualEndPosition
private

◆ _endPosition

G3D::Vector3 PathGenerator::_endPosition
private

Referenced by GetEndPosition(), and SetEndPosition().

◆ _filter

◆ _forceDestination

bool PathGenerator::_forceDestination
private

Referenced by BuildPointPath(), and CalculatePath().

◆ _navMesh

dtNavMesh const* PathGenerator::_navMesh
private

◆ _navMeshQuery

dtNavMeshQuery const* PathGenerator::_navMeshQuery
private

◆ _pathPoints

◆ _pathPolyRefs

dtPolyRef PathGenerator::_pathPolyRefs[MAX_PATH_LENGTH]
private

◆ _pointPathLimit

uint32 PathGenerator::_pointPathLimit
private

◆ _polyLength

uint32 PathGenerator::_polyLength
private

◆ _slopeCheck

bool PathGenerator::_slopeCheck
private

◆ _source

◆ _startPosition

G3D::Vector3 PathGenerator::_startPosition
private

◆ _type

◆ _useRaycast

bool PathGenerator::_useRaycast
private

◆ _useStraightPath

bool PathGenerator::_useStraightPath
private