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 "Metric.h"
|
||||||
#include "PhasingHandler.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::PathGenerator(WorldObject const* owner) :
|
PathGenerator::PathGenerator(WorldObject const* owner) :
|
||||||
_polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false),
|
_polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false),
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "MMapDefines.h"
|
#include "MMapDefines.h"
|
||||||
#include "MoveSplineInitArgs.h"
|
#include "MoveSplineInitArgs.h"
|
||||||
#include <G3D/Vector3.h>
|
#include <G3D/Vector3.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class Unit;
|
class Unit;
|
||||||
class WorldObject;
|
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
|
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
|
class TC_GAME_API PathGenerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -65,7 +94,13 @@ class TC_GAME_API PathGenerator
|
|||||||
PathGenerator& operator=(PathGenerator const& right) = delete;
|
PathGenerator& operator=(PathGenerator const& right) = delete;
|
||||||
PathGenerator& operator=(PathGenerator&& 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)
|
// 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(float destX, float destY, float destZ, bool forceDest = false);
|
||||||
bool CalculatePath(Position const& destination, bool forceDest = false);
|
bool CalculatePath(Position const& destination, bool forceDest = false);
|
||||||
|
|||||||
Reference in new issue
Block a user