implemented usage of virtual entry points when planning the travleroute
This commit is contained in:
1 parent
9d4a862b7d
commit
366615bcb9
2 files changed
+151
-1
No files matched your search
@@ -30,6 +30,121 @@
|
||||
#include "Metric.h"
|
||||
#include "PhasingHandler.h"
|
||||
|
||||
// VCORE_POSITION_MMAP_BEGIN
|
||||
VcorePositionPathResult PathGenerator::AnalyzePositions(uint32 meshMapId, uint32 instanceMapId,
|
||||
uint32 instanceId, Position const& start, Position const& destination, uint16 includeFlags)
|
||||
{
|
||||
VcorePositionPathResult result;
|
||||
G3D::Vector3 const startPos(start.GetPositionX(), start.GetPositionY(), start.GetPositionZ());
|
||||
G3D::Vector3 const endPos(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
|
||||
result.DirectDistance = (endPos - startPos).length();
|
||||
result.FinalDistance = result.DirectDistance;
|
||||
|
||||
if (!Trinity::IsValidMapCoord(startPos.x, startPos.y, startPos.z) ||
|
||||
!Trinity::IsValidMapCoord(endPos.x, endPos.y, endPos.z) || !includeFlags)
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::InvalidCoordinates;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!DisableMgr::IsPathfindingEnabled(meshMapId))
|
||||
return result; // NavMeshUnavailable
|
||||
|
||||
MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager();
|
||||
dtNavMeshQuery const* query = manager->GetNavMeshQuery(meshMapId, instanceMapId, instanceId);
|
||||
dtNavMesh const* mesh = query ? query->getAttachedNavMesh() : nullptr;
|
||||
if (!query || !mesh)
|
||||
return result;
|
||||
|
||||
// Detour uses Y,Z,X; world coordinates use X,Y,Z.
|
||||
float const from[3] = {startPos.y, startPos.z, startPos.x};
|
||||
float const to[3] = {endPos.y, endPos.z, endPos.x};
|
||||
for (float const* point : {from, to})
|
||||
{
|
||||
int tileX = -1, tileY = -1;
|
||||
mesh->calcTileLoc(point, &tileX, &tileY);
|
||||
if (tileX < 0 || tileY < 0 || !mesh->getTileAt(tileX, tileY, 0))
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::TileUnavailable;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
dtQueryFilter filter;
|
||||
filter.setIncludeFlags(includeFlags);
|
||||
filter.setExcludeFlags(0);
|
||||
float const extents[3] = {3.0f, 5.0f, 3.0f};
|
||||
float nearestStart[3] = {}, nearestEnd[3] = {};
|
||||
dtPolyRef startPoly = 0, endPoly = 0;
|
||||
if (dtStatusFailed(query->findNearestPoly(from, extents, &filter, &startPoly, nearestStart)) ||
|
||||
dtStatusFailed(query->findNearestPoly(to, extents, &filter, &endPoly, nearestEnd)) ||
|
||||
!startPoly || !endPoly)
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::NoPolygon;
|
||||
return result;
|
||||
}
|
||||
|
||||
// A distant projection is not proof that the requested world point is walkable.
|
||||
if (dtVdist(from, nearestStart) > 3.0f || dtVdist(to, nearestEnd) > 3.0f)
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::NoPolygon;
|
||||
return result;
|
||||
}
|
||||
|
||||
dtPolyRef polys[MAX_PATH_LENGTH] = {};
|
||||
int polyCount = 0;
|
||||
dtStatus const pathStatus = query->findPath(startPoly, endPoly, nearestStart, nearestEnd,
|
||||
&filter, polys, &polyCount, MAX_PATH_LENGTH);
|
||||
if (dtStatusFailed(pathStatus) || polyCount <= 0)
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::NoPath;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool const reachedEndPoly = polys[polyCount - 1] == endPoly;
|
||||
float reachableEnd[3] = {nearestEnd[0], nearestEnd[1], nearestEnd[2]};
|
||||
if (!reachedEndPoly &&
|
||||
dtStatusFailed(query->closestPointOnPoly(polys[polyCount - 1], nearestEnd, reachableEnd, nullptr)))
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::NoPath;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Use an explicit bounded straight-path representation, not a forced shortcut.
|
||||
constexpr int MaxPoints = 256;
|
||||
float straight[MaxPoints * 3] = {};
|
||||
int pointCount = 0;
|
||||
dtStatus const straightStatus = query->findStraightPath(nearestStart, reachableEnd, polys,
|
||||
polyCount, straight, nullptr, nullptr, &pointCount, MaxPoints);
|
||||
if (dtStatusFailed(straightStatus) || pointCount <= 0)
|
||||
{
|
||||
result.Result = VcorePositionPathResult::Status::NoPath;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Points.reserve(pointCount);
|
||||
for (int i = 0; i < pointCount; ++i)
|
||||
{
|
||||
G3D::Vector3 const p(straight[i * 3 + 2], straight[i * 3], straight[i * 3 + 1]);
|
||||
if (!result.Points.empty())
|
||||
result.PathLength += (p - result.Points.back()).length();
|
||||
result.Points.push_back(p);
|
||||
}
|
||||
result.FinalDistance = (endPos - result.Points.back()).length();
|
||||
|
||||
bool const truncated = (pathStatus & DT_BUFFER_TOO_SMALL) ||
|
||||
(straightStatus & DT_BUFFER_TOO_SMALL) || pointCount >= MaxPoints ||
|
||||
polyCount >= MAX_PATH_LENGTH;
|
||||
if (truncated)
|
||||
result.Result = VcorePositionPathResult::Status::Truncated;
|
||||
else if (reachedEndPoly && result.FinalDistance <= 1.5f)
|
||||
result.Result = VcorePositionPathResult::Status::Complete;
|
||||
else
|
||||
result.Result = VcorePositionPathResult::Status::Partial;
|
||||
return result;
|
||||
}
|
||||
// VCORE_POSITION_MMAP_END
|
||||
|
||||
////////////////// PathGenerator //////////////////
|
||||
PathGenerator::PathGenerator(WorldObject const* owner) :
|
||||
_polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false),
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "MMapDefines.h"
|
||||
#include "MoveSplineInitArgs.h"
|
||||
#include <G3D/Vector3.h>
|
||||
#include <vector>
|
||||
|
||||
class Unit;
|
||||
class WorldObject;
|
||||
@@ -54,6 +55,34 @@ enum PathType
|
||||
PATHFIND_FARFROMPOLY = PATHFIND_FARFROMPOLY_START | PATHFIND_FARFROMPOLY_END, // start or end positions are far from the mmap poligon
|
||||
};
|
||||
|
||||
// VCORE_POSITION_MMAP_BEGIN
|
||||
// Ground-only navmesh probe without a Player or WorldObject.
|
||||
// meshMapId may differ from instanceMapId for phased/terrain-swapped maps.
|
||||
// The caller must run this on the map/world thread that owns the navmesh query.
|
||||
struct VcorePositionPathResult
|
||||
{
|
||||
enum class Status : uint8
|
||||
{
|
||||
InvalidCoordinates,
|
||||
NavMeshUnavailable,
|
||||
TileUnavailable,
|
||||
NoPolygon,
|
||||
NoPath,
|
||||
Partial,
|
||||
Complete,
|
||||
Truncated
|
||||
};
|
||||
|
||||
Status Result = Status::NavMeshUnavailable;
|
||||
float DirectDistance = 0.0f;
|
||||
float PathLength = 0.0f;
|
||||
float FinalDistance = 0.0f;
|
||||
std::vector<G3D::Vector3> Points;
|
||||
|
||||
bool IsComplete() const { return Result == Status::Complete; }
|
||||
};
|
||||
// VCORE_POSITION_MMAP_END
|
||||
|
||||
class TC_GAME_API PathGenerator
|
||||
{
|
||||
public:
|
||||
@@ -65,7 +94,13 @@ class TC_GAME_API PathGenerator
|
||||
PathGenerator& operator=(PathGenerator const& right) = delete;
|
||||
PathGenerator& operator=(PathGenerator&& right) = delete;
|
||||
|
||||
// Calculate the path from owner to given destination
|
||||
// Vcore: query loaded MMAP data between arbitrary coordinates; no character required.
|
||||
// The result describes ground navmesh reachability, not dynamic world collision.
|
||||
static VcorePositionPathResult AnalyzePositions(uint32 meshMapId, uint32 instanceMapId,
|
||||
uint32 instanceId, Position const& start, Position const& destination,
|
||||
uint16 includeFlags = NAV_GROUND);
|
||||
|
||||
// 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 CalculatePath(Position const& destination, bool forceDest = false);
|
||||
|
||||
Reference in new issue
Block a user