Core/MMaps: updated detour to be current with tc (still doesn't find the right path sometimes)
This commit is contained in:
@@ -35,12 +35,11 @@ using dtTileRef = System.UInt64;
|
|||||||
|
|
||||||
public static partial class Detour
|
public static partial class Detour
|
||||||
{
|
{
|
||||||
public const uint DT_SALT_BITS = 16;
|
public const uint DT_SALT_BITS = 12;
|
||||||
public const uint DT_TILE_BITS = 28;
|
public const uint DT_TILE_BITS = 21;
|
||||||
public const uint DT_POLY_BITS = 20;
|
public const uint DT_POLY_BITS = 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static partial class Detour
|
public static partial class Detour
|
||||||
{
|
{
|
||||||
public static bool overlapSlabs(float[] amin, float[] amax, float[] bmin, float[] bmax, float px, float py)
|
public static bool overlapSlabs(float[] amin, float[] amax, float[] bmin, float[] bmax, float px, float py)
|
||||||
@@ -85,6 +84,7 @@ public static partial class Detour
|
|||||||
return va[2];
|
return va[2];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float getSlabCoord(float[] va, int vaStart, int side)
|
public static float getSlabCoord(float[] va, int vaStart, int side)
|
||||||
{
|
{
|
||||||
if (side == 0 || side == 4)
|
if (side == 0 || side == 4)
|
||||||
@@ -94,7 +94,6 @@ public static partial class Detour
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void calcSlabEndPoints(float[] va, int vaStart, float[] vb, int vbStart, float[] bmin, float[] bmax, int side)
|
public static void calcSlabEndPoints(float[] va, int vaStart, float[] vb, int vbStart, float[] bmin, float[] bmax, int side)
|
||||||
{
|
{
|
||||||
if (side == 0 || side == 4)
|
if (side == 0 || side == 4)
|
||||||
@@ -157,28 +156,6 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dtNavMesh* dtAllocNavMesh()
|
|
||||||
{
|
|
||||||
void* mem = dtAlloc(sizeof(dtNavMesh), DT_ALLOC_PERM);
|
|
||||||
if (!mem) return 0;
|
|
||||||
return new(mem) dtNavMesh;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// @par
|
|
||||||
///
|
|
||||||
/// This function will only free the memory for tiles with the #DT_TILE_FREE_DATA
|
|
||||||
/// flag set.
|
|
||||||
/*
|
|
||||||
void dtFreeNavMesh(dtNavMesh* navmesh)
|
|
||||||
{
|
|
||||||
if (!navmesh) return;
|
|
||||||
navmesh.~dtNavMesh();
|
|
||||||
dtFree(navmesh);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/**
|
|
||||||
@class dtNavMesh
|
@class dtNavMesh
|
||||||
|
|
||||||
The navigation mesh consists of one or more tiles defining three primary types of structural data:
|
The navigation mesh consists of one or more tiles defining three primary types of structural data:
|
||||||
@@ -207,7 +184,7 @@ public static partial class Detour
|
|||||||
|
|
||||||
@see dtNavMeshQuery, dtCreateNavMeshData, dtNavMeshCreateParams, #dtAllocNavMesh, #dtFreeNavMesh
|
@see dtNavMeshQuery, dtCreateNavMeshData, dtNavMeshCreateParams, #dtAllocNavMesh, #dtFreeNavMesh
|
||||||
*/
|
*/
|
||||||
/// A navigation mesh based on tiles of convex polygons.
|
// A navigation mesh based on tiles of convex polygons.
|
||||||
// @ingroup detour
|
// @ingroup detour
|
||||||
public class dtNavMesh
|
public class dtNavMesh
|
||||||
{
|
{
|
||||||
@@ -276,7 +253,7 @@ public static partial class Detour
|
|||||||
{
|
{
|
||||||
dtPolyRef saltMask = (dtPolyRef)(1 << (int)DT_SALT_BITS) - 1;
|
dtPolyRef saltMask = (dtPolyRef)(1 << (int)DT_SALT_BITS) - 1;
|
||||||
dtPolyRef tileMask = (dtPolyRef)((1 << (int)DT_TILE_BITS) - 1);
|
dtPolyRef tileMask = (dtPolyRef)((1 << (int)DT_TILE_BITS) - 1);
|
||||||
dtPolyRef polyMask = (dtPolyRef)((1 << (int)DT_POLY_BITS) - 1);
|
dtPolyRef polyMask = (dtPolyRef)((1ul << (int)DT_POLY_BITS) - 1);
|
||||||
salt = (uint)((polyRef >> (int)(DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
salt = (uint)((polyRef >> (int)(DT_POLY_BITS + DT_TILE_BITS)) & saltMask);
|
||||||
it = (uint)((polyRef >> (int)DT_POLY_BITS) & tileMask);
|
it = (uint)((polyRef >> (int)DT_POLY_BITS) & tileMask);
|
||||||
ip = (uint)(polyRef & polyMask);
|
ip = (uint)(polyRef & polyMask);
|
||||||
@@ -308,7 +285,7 @@ public static partial class Detour
|
|||||||
/// @see #encodePolyId
|
/// @see #encodePolyId
|
||||||
public uint decodePolyIdPoly(dtPolyRef polyRef)
|
public uint decodePolyIdPoly(dtPolyRef polyRef)
|
||||||
{
|
{
|
||||||
dtPolyRef polyMask = (dtPolyRef)((1 << (int)DT_POLY_BITS) - 1);
|
dtPolyRef polyMask = (dtPolyRef)((1ul << (int)DT_POLY_BITS) - 1);
|
||||||
return (uint)(polyRef & polyMask);
|
return (uint)(polyRef & polyMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1110,7 +1087,10 @@ public static partial class Detour
|
|||||||
tile.flags = flags;
|
tile.flags = flags;
|
||||||
|
|
||||||
connectIntLinks(tile);
|
connectIntLinks(tile);
|
||||||
|
|
||||||
|
// Base off-mesh connections to their starting polygons and connect connections inside the tile.
|
||||||
baseOffMeshLinks(tile);
|
baseOffMeshLinks(tile);
|
||||||
|
connectExtOffMeshLinks(tile, tile, -1);
|
||||||
|
|
||||||
// Create connections with neighbour tiles.
|
// Create connections with neighbour tiles.
|
||||||
const int MAX_NEIS = 32;
|
const int MAX_NEIS = 32;
|
||||||
@@ -1121,11 +1101,11 @@ public static partial class Detour
|
|||||||
nneis = getTilesAt(header.x, header.y, neis, MAX_NEIS);
|
nneis = getTilesAt(header.x, header.y, neis, MAX_NEIS);
|
||||||
for (int j = 0; j < nneis; ++j)
|
for (int j = 0; j < nneis; ++j)
|
||||||
{
|
{
|
||||||
if (neis[j] != tile)
|
if (neis[j] == tile)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
connectExtLinks(tile, neis[j], -1);
|
connectExtLinks(tile, neis[j], -1);
|
||||||
connectExtLinks(neis[j], tile, -1);
|
connectExtLinks(neis[j], tile, -1);
|
||||||
}
|
|
||||||
connectExtOffMeshLinks(tile, neis[j], -1);
|
connectExtOffMeshLinks(tile, neis[j], -1);
|
||||||
connectExtOffMeshLinks(neis[j], tile, -1);
|
connectExtOffMeshLinks(neis[j], tile, -1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,18 @@ public static partial class Detour
|
|||||||
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, //< Add a vertex at every polygon edge crossing.
|
DT_STRAIGHTPATH_ALL_CROSSINGS = 0x02, //< Add a vertex at every polygon edge crossing.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::initSlicedFindPath and updateSlicedFindPath
|
||||||
|
enum dtFindPathOptions
|
||||||
|
{
|
||||||
|
DT_FINDPATH_ANY_ANGLE = 0x02, ///< use raycasts during pathfind to "shortcut" (raycast still consider costs)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Options for dtNavMeshQuery::raycast
|
||||||
|
enum dtRaycastOptions
|
||||||
|
{
|
||||||
|
DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost
|
||||||
|
};
|
||||||
|
|
||||||
/// Flags representing the type of a navigation mesh polygon.
|
/// Flags representing the type of a navigation mesh polygon.
|
||||||
public enum dtPolyTypes
|
public enum dtPolyTypes
|
||||||
{
|
{
|
||||||
@@ -85,31 +97,11 @@ public static partial class Detour
|
|||||||
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
/// Index to first link in linked list. (Or #DT_NULL_LINK if there is no link.)
|
||||||
public uint firstLink;
|
public uint firstLink;
|
||||||
|
|
||||||
/// The indices of the polygon's vertices.
|
// The indices of the polygon's vertices.
|
||||||
/// The actual vertices are located in dtMeshTile::verts.
|
// The actual vertices are located in dtMeshTile::verts.
|
||||||
public ushort[] verts = new ushort[DT_VERTS_PER_POLYGON];
|
public ushort[] verts = new ushort[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
/// Packed data representing neighbor polygons references and flags for each edge.
|
// Packed data representing neighbor polygons references and flags for each edge.
|
||||||
/*
|
|
||||||
@var ushort dtPoly::neis[DT_VERTS_PER_POLYGON]
|
|
||||||
@par
|
|
||||||
|
|
||||||
Each entry represents data for the edge starting at the vertex of the same index.
|
|
||||||
E.g. The entry at index n represents the edge data for vertex[n] to vertex[n+1].
|
|
||||||
|
|
||||||
A value of zero indicates the edge has no polygon connection. (It makes up the
|
|
||||||
border of the navigation mesh.)
|
|
||||||
|
|
||||||
The information can be extracted as follows:
|
|
||||||
@code
|
|
||||||
neighborRef = neis[n] & 0xff; // Get the neighbor polygon reference.
|
|
||||||
|
|
||||||
if (neis[n] & #DT_EX_LINK)
|
|
||||||
{
|
|
||||||
// The edge is an external (portal) edge.
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
* */
|
|
||||||
public ushort[] neis = new ushort[DT_VERTS_PER_POLYGON];
|
public ushort[] neis = new ushort[DT_VERTS_PER_POLYGON];
|
||||||
|
|
||||||
/// The user defined polygon flags.
|
/// The user defined polygon flags.
|
||||||
@@ -380,23 +372,6 @@ public static partial class Detour
|
|||||||
public float[] bmax = new float[3]; //< The maximum bounds of the tile's AABB. [(x, y, z)]
|
public float[] bmax = new float[3]; //< The maximum bounds of the tile's AABB. [(x, y, z)]
|
||||||
|
|
||||||
/// The bounding volume quantization factor.
|
/// The bounding volume quantization factor.
|
||||||
/*
|
|
||||||
@var float dtMeshHeader::bvQuantFactor
|
|
||||||
@par
|
|
||||||
|
|
||||||
This value is used for converting between world and bounding volume coordinates.
|
|
||||||
For example:
|
|
||||||
@code
|
|
||||||
const float cs = 1.0f / tile.header.bvQuantFactor;
|
|
||||||
const dtBVNode* n = &tile.bvTree[i];
|
|
||||||
if (n.i >= 0)
|
|
||||||
{
|
|
||||||
// This is a leaf node.
|
|
||||||
float worldMinX = tile.header.bmin[0] + n.bmin[0]*cs;
|
|
||||||
float worldMinY = tile.header.bmin[0] + n.bmin[1]*cs;
|
|
||||||
// Etc...
|
|
||||||
}
|
|
||||||
@endcode */
|
|
||||||
public float bvQuantFactor;
|
public float bvQuantFactor;
|
||||||
|
|
||||||
public int FromBytes(byte[] array, int start)
|
public int FromBytes(byte[] array, int start)
|
||||||
@@ -557,8 +532,6 @@ public static partial class Detour
|
|||||||
offMeshCons[i] = new dtOffMeshConnection();
|
offMeshCons[i] = new dtOffMeshConnection();
|
||||||
start = offMeshCons[i].FromBytes(array, start);
|
start = offMeshCons[i].FromBytes(array, start);
|
||||||
}
|
}
|
||||||
//flags = BitConverter.ToInt32(array, start);
|
|
||||||
//start += sizeof(int);
|
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,7 +572,6 @@ public static partial class Detour
|
|||||||
{
|
{
|
||||||
bytes.AddRange(offMeshCons[i].ToBytes());
|
bytes.AddRange(offMeshCons[i].ToBytes());
|
||||||
}
|
}
|
||||||
bytes.AddRange(BitConverter.GetBytes(flags));
|
|
||||||
|
|
||||||
return bytes.ToArray();
|
return bytes.ToArray();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using dtPolyRef = System.UInt64;
|
using dtPolyRef = System.UInt64;
|
||||||
using dtStatus = System.UInt32;
|
using dtStatus = System.UInt32;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
// Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
|
||||||
// On certain platforms indirect or virtual function call is expensive. The default
|
// On certain platforms indirect or virtual function call is expensive. The default
|
||||||
@@ -46,7 +47,7 @@ using dtStatus = System.UInt32;
|
|||||||
|
|
||||||
public static partial class Detour
|
public static partial class Detour
|
||||||
{
|
{
|
||||||
const float H_SCALE = 0.999f; // Search heuristic scale.
|
const float H_SCALE = 2.0f; // Search heuristic scale.
|
||||||
|
|
||||||
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
/// Defines polygon filtering and traversal costs for navigation mesh query operations.
|
||||||
// @ingroup detour
|
// @ingroup detour
|
||||||
@@ -141,6 +142,33 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides information about raycast hit
|
||||||
|
/// filled by dtNavMeshQuery::raycast
|
||||||
|
/// @ingroup detour
|
||||||
|
public class dtRaycastHit
|
||||||
|
{
|
||||||
|
/// The hit parameter. (FLT_MAX if no wall hit.)
|
||||||
|
public float t;
|
||||||
|
|
||||||
|
/// hitNormal The normal of the nearest wall hit. [(x, y, z)]
|
||||||
|
public float[] hitNormal = new float[3];
|
||||||
|
|
||||||
|
/// The index of the edge on the final polygon where the wall was hit.
|
||||||
|
public int hitEdgeIndex;
|
||||||
|
|
||||||
|
/// Pointer to an array of reference ids of the visited polygons. [opt]
|
||||||
|
public dtPolyRef[] path;
|
||||||
|
|
||||||
|
/// The number of visited polygons. [opt]
|
||||||
|
public int pathCount;
|
||||||
|
|
||||||
|
/// The maximum number of polygons the @p path array can hold.
|
||||||
|
public int maxPath;
|
||||||
|
|
||||||
|
/// The cost of the path until hit.
|
||||||
|
public float pathCost;
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// @class dtNavMeshQuery
|
// @class dtNavMeshQuery
|
||||||
@@ -175,6 +203,8 @@ public static partial class Detour
|
|||||||
public float[] startPos = new float[3];
|
public float[] startPos = new float[3];
|
||||||
public float[] endPos = new float[3];
|
public float[] endPos = new float[3];
|
||||||
public dtQueryFilter filter;
|
public dtQueryFilter filter;
|
||||||
|
public uint options;
|
||||||
|
public float raycastLimitSqr;
|
||||||
|
|
||||||
public void dtcsClear()
|
public void dtcsClear()
|
||||||
{
|
{
|
||||||
@@ -185,10 +215,12 @@ public static partial class Detour
|
|||||||
endRef = 0;
|
endRef = 0;
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
startPos[i] = .0f;
|
startPos[i] = 0f;
|
||||||
endPos[i] = .0f;
|
endPos[i] = 0f;
|
||||||
}
|
}
|
||||||
filter = null;
|
filter = null;
|
||||||
|
options = 0;
|
||||||
|
raycastLimitSqr = 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private dtQueryData m_query = new dtQueryData(); //< Sliced query state.
|
private dtQueryData m_query = new dtQueryData(); //< Sliced query state.
|
||||||
@@ -853,61 +885,31 @@ public static partial class Detour
|
|||||||
|
|
||||||
nearestRef = 0;
|
nearestRef = 0;
|
||||||
|
|
||||||
// Get nearby polygons from proximity grid.
|
dtFindNearestPolyQuery query = new dtFindNearestPolyQuery(this, center);
|
||||||
dtPolyRef[] polys = new dtPolyRef[128];
|
|
||||||
int polyCount = 0;
|
|
||||||
if (dtStatusFailed(queryPolygons(center, extents, filter, polys, ref polyCount, 128)))
|
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
|
||||||
|
|
||||||
// Find nearest polygon amongst the nearby polygons.
|
dtStatus status = queryPolygons(center, extents, filter, query);
|
||||||
dtPolyRef nearest = 0;
|
if (dtStatusFailed(status))
|
||||||
float nearestDistanceSqr = float.MaxValue;
|
return status;
|
||||||
for (int i = 0; i < polyCount; ++i)
|
|
||||||
{
|
|
||||||
dtPolyRef polyRef = polys[i];
|
|
||||||
float[] closestPtPoly = new float[3];
|
|
||||||
float[] diff = new float[3];
|
|
||||||
bool posOverPoly = false;
|
|
||||||
float d = 0;
|
|
||||||
closestPointOnPoly(polyRef, center, closestPtPoly, ref posOverPoly);
|
|
||||||
|
|
||||||
// If a point is directly over a polygon and closer than
|
nearestRef = query.nearestRef();
|
||||||
// climb height, favor that instead of straight line nearest point.
|
// Only override nearestPt if we actually found a poly so the nearest point
|
||||||
dtVsub(diff, center, closestPtPoly);
|
// is valid.
|
||||||
if (posOverPoly)
|
if (nearestRef != 0)
|
||||||
{
|
dtVcopy(nearestPt, query.nearestPoint());
|
||||||
dtMeshTile tile = null;
|
|
||||||
dtPoly poly = null;
|
|
||||||
m_nav.getTileAndPolyByRefUnsafe(polys[i], ref tile, ref poly);
|
|
||||||
d = (float)(Math.Abs(diff[1]) - tile.header.walkableClimb);
|
|
||||||
d = d > 0 ? d * d : 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d = dtVlenSqr(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d < nearestDistanceSqr)
|
|
||||||
{
|
|
||||||
//if (nearestPt != null)
|
|
||||||
dtVcopy(nearestPt, closestPtPoly);
|
|
||||||
|
|
||||||
nearestDistanceSqr = d;
|
|
||||||
nearest = polyRef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (nearestRef)
|
|
||||||
nearestRef = nearest;
|
|
||||||
|
|
||||||
return DT_SUCCESS;
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries polygons within a tile.
|
/// Queries polygons within a tile.
|
||||||
public int queryPolygonsInTile(dtMeshTile tile, float[] qmin, float[] qmax, dtQueryFilter filter, dtPolyRef[] polys, int polyStart, int maxPolys)
|
public void queryPolygonsInTile(dtMeshTile tile, float[] qmin, float[] qmax, dtQueryFilter filter, dtFindNearestPolyQuery query)
|
||||||
{
|
{
|
||||||
Debug.Assert(m_nav != null);
|
Debug.Assert(m_nav != null);
|
||||||
|
|
||||||
|
const int batchSize = 32;
|
||||||
|
dtPolyRef[] polyRefs = new dtPolyRef[batchSize];
|
||||||
|
dtPoly[] polys = new dtPoly[batchSize];
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
if (tile.bvTree != null)
|
if (tile.bvTree != null)
|
||||||
{
|
{
|
||||||
dtBVNode node = tile.bvTree[0];
|
dtBVNode node = tile.bvTree[0];
|
||||||
@@ -918,7 +920,7 @@ public static partial class Detour
|
|||||||
float qfac = tile.header.bvQuantFactor;
|
float qfac = tile.header.bvQuantFactor;
|
||||||
|
|
||||||
// Calculate quantized box
|
// Calculate quantized box
|
||||||
ushort[] bmin = new ushort[3];//, bmax[3];
|
ushort[] bmin = new ushort[3];
|
||||||
ushort[] bmax = new ushort[3];
|
ushort[] bmax = new ushort[3];
|
||||||
// dtClamp query box to world box.
|
// dtClamp query box to world box.
|
||||||
float minx = dtClamp(qmin[0], tbmin[0], tbmax[0]) - tbmin[0];
|
float minx = dtClamp(qmin[0], tbmin[0], tbmax[0]) - tbmin[0];
|
||||||
@@ -937,7 +939,6 @@ public static partial class Detour
|
|||||||
|
|
||||||
// Traverse tree
|
// Traverse tree
|
||||||
dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
|
dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
|
||||||
int n = 0;
|
|
||||||
int nodeIndex = 0;
|
int nodeIndex = 0;
|
||||||
while (nodeIndex < endIndex)
|
while (nodeIndex < endIndex)
|
||||||
{
|
{
|
||||||
@@ -951,8 +952,18 @@ public static partial class Detour
|
|||||||
dtPolyRef polyRef = polyRefBase | (uint)node.i;
|
dtPolyRef polyRef = polyRefBase | (uint)node.i;
|
||||||
if (filter.passFilter(polyRef, tile, tile.polys[node.i]))
|
if (filter.passFilter(polyRef, tile, tile.polys[node.i]))
|
||||||
{
|
{
|
||||||
if (n < maxPolys)
|
polyRefs[n] = polyRef;
|
||||||
polys[polyStart + n++] = polyRef;
|
polys[n] = tile.polys[node.i];
|
||||||
|
|
||||||
|
if (n == batchSize - 1)
|
||||||
|
{
|
||||||
|
query.process(tile, polys, polyRefs, batchSize);
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -966,14 +977,11 @@ public static partial class Detour
|
|||||||
nodeIndex += escapeIndex;
|
nodeIndex += escapeIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float[] bmin = new float[3];//, bmax[3];
|
float[] bmin = new float[3];
|
||||||
float[] bmax = new float[3];
|
float[] bmax = new float[3];
|
||||||
int n = 0;
|
|
||||||
dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
|
dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
|
||||||
for (int i = 0; i < tile.header.polyCount; ++i)
|
for (int i = 0; i < tile.header.polyCount; ++i)
|
||||||
{
|
{
|
||||||
@@ -999,14 +1007,28 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
if (dtOverlapBounds(qmin, qmax, bmin, bmax))
|
if (dtOverlapBounds(qmin, qmax, bmin, bmax))
|
||||||
{
|
{
|
||||||
if (n < maxPolys)
|
polyRefs[n] = polyRef;
|
||||||
polys[polyStart + n++] = polyRef;
|
polys[n] = p;
|
||||||
|
|
||||||
|
if (n == batchSize - 1)
|
||||||
|
{
|
||||||
|
query.process(tile, polys, polyRefs, batchSize);
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Process the last polygons that didn't make a full batch.
|
||||||
|
if (n > 0)
|
||||||
|
query.process(tile, polys, polyRefs, n);
|
||||||
|
}
|
||||||
|
|
||||||
/// Finds polygons that overlap the search box.
|
/// Finds polygons that overlap the search box.
|
||||||
/// @param[in] center The center of the search box. [(x, y, z)]
|
/// @param[in] center The center of the search box. [(x, y, z)]
|
||||||
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
/// @param[in] extents The search distance along each axis. [(x, y, z)]
|
||||||
@@ -1024,11 +1046,11 @@ public static partial class Detour
|
|||||||
/// be filled to capacity. The method of choosing which polygons from the
|
/// be filled to capacity. The method of choosing which polygons from the
|
||||||
/// full set are included in the partial result set is undefined.
|
/// full set are included in the partial result set is undefined.
|
||||||
///
|
///
|
||||||
public dtStatus queryPolygons(float[] center, float[] extents, dtQueryFilter filter, dtPolyRef[] polys, ref int polyCount, int maxPolys)
|
public dtStatus queryPolygons(float[] center, float[] extents, dtQueryFilter filter, dtFindNearestPolyQuery query)
|
||||||
{
|
{
|
||||||
Debug.Assert(m_nav != null);
|
Debug.Assert(m_nav != null);
|
||||||
|
|
||||||
float[] bmin = new float[3];//, bmax[3];
|
float[] bmin = new float[3];
|
||||||
float[] bmax = new float[3];
|
float[] bmax = new float[3];
|
||||||
dtVsub(bmin, center, extents);
|
dtVsub(bmin, center, extents);
|
||||||
dtVadd(bmax, center, extents);
|
dtVadd(bmax, center, extents);
|
||||||
@@ -1041,7 +1063,6 @@ public static partial class Detour
|
|||||||
int MAX_NEIS = 32;
|
int MAX_NEIS = 32;
|
||||||
dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
|
dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
|
||||||
|
|
||||||
int n = 0;
|
|
||||||
for (int y = miny; y <= maxy; ++y)
|
for (int y = miny; y <= maxy; ++y)
|
||||||
{
|
{
|
||||||
for (int x = minx; x <= maxx; ++x)
|
for (int x = minx; x <= maxx; ++x)
|
||||||
@@ -1049,16 +1070,10 @@ public static partial class Detour
|
|||||||
int nneis = m_nav.getTilesAt(x, y, neis, MAX_NEIS);
|
int nneis = m_nav.getTilesAt(x, y, neis, MAX_NEIS);
|
||||||
for (int j = 0; j < nneis; ++j)
|
for (int j = 0; j < nneis; ++j)
|
||||||
{
|
{
|
||||||
n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys, n, maxPolys - n);
|
queryPolygonsInTile(neis[j], bmin, bmax, filter, query);
|
||||||
if (n >= maxPolys)
|
|
||||||
{
|
|
||||||
polyCount = n;
|
|
||||||
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
polyCount = n;
|
|
||||||
|
|
||||||
return DT_SUCCESS;
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -1092,14 +1107,12 @@ public static partial class Detour
|
|||||||
|
|
||||||
pathCount = 0;
|
pathCount = 0;
|
||||||
|
|
||||||
if (startRef == 0 || endRef == 0)
|
if (maxPath <= 0)
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
|
||||||
|
|
||||||
if (maxPath == 0)
|
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
// Validate input
|
// Validate input
|
||||||
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef))
|
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef) ||
|
||||||
|
startPos == null || endPos == null || filter == null || maxPath <= 0 || path == null)
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
if (startRef == endRef)
|
if (startRef == endRef)
|
||||||
@@ -1124,7 +1137,7 @@ public static partial class Detour
|
|||||||
dtNode lastBestNode = startNode;
|
dtNode lastBestNode = startNode;
|
||||||
float lastBestNodeCost = startNode.total;
|
float lastBestNodeCost = startNode.total;
|
||||||
|
|
||||||
dtStatus status = DT_SUCCESS;
|
bool outOfNodes = false;
|
||||||
|
|
||||||
while (!m_openList.empty())
|
while (!m_openList.empty())
|
||||||
{
|
{
|
||||||
@@ -1176,10 +1189,15 @@ public static partial class Detour
|
|||||||
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly))
|
if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dtNode neighbourNode = m_nodePool.getNode(neighbourRef);
|
// deal explicitly with crossing tile boundaries
|
||||||
|
byte crossSide = 0;
|
||||||
|
if (bestTile.links[i].side != 0xff)
|
||||||
|
crossSide = (byte)(bestTile.links[i].side >> 1);
|
||||||
|
|
||||||
|
dtNode neighbourNode = m_nodePool.getNode(neighbourRef, crossSide);
|
||||||
if (neighbourNode == null)
|
if (neighbourNode == null)
|
||||||
{
|
{
|
||||||
status |= DT_OUT_OF_NODES;
|
outOfNodes = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,7 +1254,7 @@ public static partial class Detour
|
|||||||
neighbourNode.id = neighbourRef;
|
neighbourNode.id = neighbourRef;
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
neighbourNode.flags = (byte)(neighbourNode.flags & (byte)~dtNodeFlags.DT_NODE_CLOSED);
|
neighbourNode.flags = (byte)(neighbourNode.flags & ~(byte)dtNodeFlags.DT_NODE_CLOSED);
|
||||||
}
|
}
|
||||||
neighbourNode.cost = cost;
|
neighbourNode.cost = cost;
|
||||||
neighbourNode.total = total;
|
neighbourNode.total = total;
|
||||||
@@ -1262,41 +1280,58 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtStatus status = getPathToNode(lastBestNode, path, ref pathCount, maxPath);
|
||||||
|
|
||||||
if (lastBestNode.id != endRef)
|
if (lastBestNode.id != endRef)
|
||||||
status |= DT_PARTIAL_RESULT;
|
status |= DT_PARTIAL_RESULT;
|
||||||
|
|
||||||
// Reverse the path.
|
if (outOfNodes)
|
||||||
dtNode prev = null;
|
status |= DT_OUT_OF_NODES;
|
||||||
dtNode node = lastBestNode;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
|
||||||
node.pidx = m_nodePool.getNodeIdx(prev);
|
|
||||||
prev = node;
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
while (node != null);
|
|
||||||
|
|
||||||
// Store path
|
|
||||||
node = prev;
|
|
||||||
int n = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
path[n++] = node.id;
|
|
||||||
if (n >= maxPath)
|
|
||||||
{
|
|
||||||
status |= DT_BUFFER_TOO_SMALL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
node = m_nodePool.getNodeAtIdx(node.pidx);
|
|
||||||
}
|
|
||||||
while (node != null);
|
|
||||||
|
|
||||||
pathCount = (uint)n;
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtStatus getPathToNode(dtNode endNode, dtPolyRef[] path, ref uint pathCount, int maxPath)
|
||||||
|
{
|
||||||
|
// Find the length of the entire path.
|
||||||
|
dtNode curNode = endNode;
|
||||||
|
int length = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
length++;
|
||||||
|
curNode = m_nodePool.getNodeAtIdx(curNode.pidx);
|
||||||
|
} while (curNode != null);
|
||||||
|
|
||||||
|
// If the path cannot be fully stored then advance to the last node we will be able to store.
|
||||||
|
curNode = endNode;
|
||||||
|
int writeCount;
|
||||||
|
for (writeCount = length; writeCount > maxPath; writeCount--)
|
||||||
|
{
|
||||||
|
//dtAssert(curNode);
|
||||||
|
|
||||||
|
curNode = m_nodePool.getNodeAtIdx(curNode.pidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write path
|
||||||
|
for (int i = writeCount - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
//dtAssert(curNode);
|
||||||
|
|
||||||
|
path[i] = curNode.id;
|
||||||
|
curNode = m_nodePool.getNodeAtIdx(curNode.pidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//dtAssert(!curNode);
|
||||||
|
|
||||||
|
|
||||||
|
pathCount = (uint)Math.Min(length, maxPath);
|
||||||
|
|
||||||
|
if (length > maxPath)
|
||||||
|
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
// @name Sliced Pathfinding Functions
|
// @name Sliced Pathfinding Functions
|
||||||
/// Common use case:
|
/// Common use case:
|
||||||
@@ -1320,7 +1355,7 @@ public static partial class Detour
|
|||||||
/// The @p filter pointer is stored and used for the duration of the sliced
|
/// The @p filter pointer is stored and used for the duration of the sliced
|
||||||
/// path query.
|
/// path query.
|
||||||
///
|
///
|
||||||
public dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef, float[] startPos, float[] endPos, dtQueryFilter filter)
|
public dtStatus initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef, float[] startPos, float[] endPos, dtQueryFilter filter, uint options)
|
||||||
{
|
{
|
||||||
Debug.Assert(m_nav != null);
|
Debug.Assert(m_nav != null);
|
||||||
Debug.Assert(m_nodePool != null);
|
Debug.Assert(m_nodePool != null);
|
||||||
@@ -1335,6 +1370,8 @@ public static partial class Detour
|
|||||||
dtVcopy(m_query.startPos, startPos);
|
dtVcopy(m_query.startPos, startPos);
|
||||||
dtVcopy(m_query.endPos, endPos);
|
dtVcopy(m_query.endPos, endPos);
|
||||||
m_query.filter = filter;
|
m_query.filter = filter;
|
||||||
|
m_query.options = options;
|
||||||
|
m_query.raycastLimitSqr = float.MaxValue;
|
||||||
|
|
||||||
if (startRef == 0 || endRef == 0)
|
if (startRef == 0 || endRef == 0)
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
@@ -1343,6 +1380,16 @@ public static partial class Detour
|
|||||||
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef))
|
if (!m_nav.isValidPolyRef(startRef) || !m_nav.isValidPolyRef(endRef))
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
|
// trade quality with performance?
|
||||||
|
if ((options & (int)dtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
||||||
|
{
|
||||||
|
// limiting to several times the character radius yields nice results. It is not sensitive
|
||||||
|
// so it is enough to compute it from the first tile.
|
||||||
|
dtMeshTile tile = m_nav.getTileByRef(startRef);
|
||||||
|
float agentRadius = tile.header.walkableRadius;
|
||||||
|
m_query.raycastLimitSqr = dtSqr(agentRadius * 50.0f); //DT_RAY_CAST_LIMIT_PROPORTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
if (startRef == endRef)
|
if (startRef == endRef)
|
||||||
{
|
{
|
||||||
m_query.status = DT_SUCCESS;
|
m_query.status = DT_SUCCESS;
|
||||||
@@ -1384,6 +1431,9 @@ public static partial class Detour
|
|||||||
return DT_FAILURE;
|
return DT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtRaycastHit rayHit = new dtRaycastHit();
|
||||||
|
rayHit.maxPath = 0;
|
||||||
|
|
||||||
int iter = 0;
|
int iter = 0;
|
||||||
while (iter < maxIter && !m_openList.empty())
|
while (iter < maxIter && !m_openList.empty())
|
||||||
{
|
{
|
||||||
@@ -1421,13 +1471,21 @@ public static partial class Detour
|
|||||||
|
|
||||||
// Get parent poly and tile.
|
// Get parent poly and tile.
|
||||||
dtPolyRef parentRef = 0;
|
dtPolyRef parentRef = 0;
|
||||||
|
dtPolyRef grandpaRef = 0;
|
||||||
dtMeshTile parentTile = null;
|
dtMeshTile parentTile = null;
|
||||||
dtPoly parentPoly = null;
|
dtPoly parentPoly = null;
|
||||||
|
dtNode parentNode = null;
|
||||||
if (bestNode.pidx != 0)
|
if (bestNode.pidx != 0)
|
||||||
parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id;
|
{
|
||||||
|
parentNode = m_nodePool.getNodeAtIdx(bestNode.pidx);
|
||||||
|
parentRef = parentNode.id;
|
||||||
|
if (parentNode.pidx != 0)
|
||||||
|
grandpaRef = m_nodePool.getNodeAtIdx(parentNode.pidx).id;
|
||||||
|
}
|
||||||
if (parentRef != 0)
|
if (parentRef != 0)
|
||||||
{
|
{
|
||||||
if (dtStatusFailed(m_nav.getTileAndPolyByRef(parentRef, ref parentTile, ref parentPoly)))
|
bool invalidParent = dtStatusFailed(m_nav.getTileAndPolyByRef(parentRef, ref parentTile, ref parentPoly));
|
||||||
|
if (invalidParent || (grandpaRef != 0 && !m_nav.isValidPolyRef(grandpaRef)))
|
||||||
{
|
{
|
||||||
// The polygon has disappeared during the sliced query, fail.
|
// The polygon has disappeared during the sliced query, fail.
|
||||||
m_query.status = DT_FAILURE;
|
m_query.status = DT_FAILURE;
|
||||||
@@ -1437,6 +1495,14 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decide whether to test raycast to previous nodes
|
||||||
|
bool tryLOS = false;
|
||||||
|
if ((m_query.options & (int)dtFindPathOptions.DT_FINDPATH_ANY_ANGLE) != 0)
|
||||||
|
{
|
||||||
|
if ((parentRef != 0) && (dtVdistSqr(parentNode.pos, bestNode.pos) < m_query.raycastLimitSqr))
|
||||||
|
tryLOS = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint i = bestPoly.firstLink; i != DT_NULL_LINK; i = bestTile.links[i].next)
|
for (uint i = bestPoly.firstLink; i != DT_NULL_LINK; i = bestTile.links[i].next)
|
||||||
{
|
{
|
||||||
dtPolyRef neighbourRef = bestTile.links[i].polyRef;
|
dtPolyRef neighbourRef = bestTile.links[i].polyRef;
|
||||||
@@ -1461,6 +1527,10 @@ public static partial class Detour
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do not expand to nodes that were already visited from the same parent
|
||||||
|
if (neighbourNode.pidx != 0 && neighbourNode.pidx == bestNode.pidx)
|
||||||
|
continue;
|
||||||
|
|
||||||
// If the node is visited the first time, calculate node position.
|
// If the node is visited the first time, calculate node position.
|
||||||
if (neighbourNode.flags == 0)
|
if (neighbourNode.flags == 0)
|
||||||
{
|
{
|
||||||
@@ -1473,30 +1543,44 @@ public static partial class Detour
|
|||||||
float cost = 0;
|
float cost = 0;
|
||||||
float heuristic = 0;
|
float heuristic = 0;
|
||||||
|
|
||||||
// Special case for last node.
|
// raycast parent
|
||||||
if (neighbourRef == m_query.endRef)
|
bool foundShortCut = false;
|
||||||
|
rayHit.pathCost = rayHit.t = 0;
|
||||||
|
if (tryLOS)
|
||||||
{
|
{
|
||||||
// Cost
|
raycast(parentRef, parentNode.pos, neighbourNode.pos, m_query.filter, (int)dtRaycastOptions.DT_RAYCAST_USE_COSTS, rayHit, grandpaRef);
|
||||||
float curCost = m_query.filter.getCost(bestNode.pos, neighbourNode.pos,
|
foundShortCut = rayHit.t >= 1.0f;
|
||||||
parentRef, parentTile, parentPoly,
|
}
|
||||||
bestRef, bestTile, bestPoly,
|
|
||||||
neighbourRef, neighbourTile, neighbourPoly);
|
|
||||||
float endCost = m_query.filter.getCost(neighbourNode.pos, m_query.endPos,
|
|
||||||
bestRef, bestTile, bestPoly,
|
|
||||||
neighbourRef, neighbourTile, neighbourPoly,
|
|
||||||
0, null, null);
|
|
||||||
|
|
||||||
cost = bestNode.cost + curCost + endCost;
|
// update move cost
|
||||||
heuristic = 0;
|
if (foundShortCut)
|
||||||
|
{
|
||||||
|
// shortcut found using raycast. Using shorter cost instead
|
||||||
|
cost = parentNode.cost + rayHit.pathCost;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cost
|
// No shortcut found.
|
||||||
float curCost = m_query.filter.getCost(bestNode.pos, neighbourNode.pos,
|
float curCost = m_query.filter.getCost(bestNode.pos, neighbourNode.pos,
|
||||||
parentRef, parentTile, parentPoly,
|
parentRef, parentTile, parentPoly,
|
||||||
bestRef, bestTile, bestPoly,
|
bestRef, bestTile, bestPoly,
|
||||||
neighbourRef, neighbourTile, neighbourPoly);
|
neighbourRef, neighbourTile, neighbourPoly);
|
||||||
cost = bestNode.cost + curCost;
|
cost = bestNode.cost + curCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case for last node.
|
||||||
|
if (neighbourRef == m_query.endRef)
|
||||||
|
{
|
||||||
|
float endCost = m_query.filter.getCost(neighbourNode.pos, m_query.endPos,
|
||||||
|
bestRef, bestTile, bestPoly,
|
||||||
|
neighbourRef, neighbourTile, neighbourPoly,
|
||||||
|
0, null, null);
|
||||||
|
|
||||||
|
cost = cost + endCost;
|
||||||
|
heuristic = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
heuristic = dtVdist(neighbourNode.pos, m_query.endPos) * H_SCALE;
|
heuristic = dtVdist(neighbourNode.pos, m_query.endPos) * H_SCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1510,12 +1594,13 @@ public static partial class Detour
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Add or update the node.
|
// Add or update the node.
|
||||||
neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode);
|
neighbourNode.pidx = foundShortCut ? bestNode.pidx : m_nodePool.getNodeIdx(bestNode);
|
||||||
neighbourNode.id = neighbourRef;
|
neighbourNode.id = neighbourRef;
|
||||||
//neighbourNode.flags = (neighbourNode.flags & ~DT_NODE_CLOSED);
|
neighbourNode.flags = (byte)(neighbourNode.flags & ~(byte)(dtNodeFlags.DT_NODE_CLOSED | dtNodeFlags.DT_NODE_PARENT_DETACHED));
|
||||||
neighbourNode.dtcsClearFlag(dtNodeFlags.DT_NODE_CLOSED);
|
|
||||||
neighbourNode.cost = cost;
|
neighbourNode.cost = cost;
|
||||||
neighbourNode.total = total;
|
neighbourNode.total = total;
|
||||||
|
if (foundShortCut)
|
||||||
|
neighbourNode.flags = (byte)(neighbourNode.flags | (byte)dtNodeFlags.DT_NODE_PARENT_DETACHED);
|
||||||
|
|
||||||
if ((neighbourNode.flags & (byte)dtNodeFlags.DT_NODE_OPEN) != 0)
|
if ((neighbourNode.flags & (byte)dtNodeFlags.DT_NODE_OPEN) != 0)
|
||||||
{
|
{
|
||||||
@@ -1587,11 +1672,15 @@ public static partial class Detour
|
|||||||
|
|
||||||
dtNode prev = null;
|
dtNode prev = null;
|
||||||
dtNode node = m_query.lastBestNode;
|
dtNode node = m_query.lastBestNode;
|
||||||
|
int prevRay = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||||
node.pidx = m_nodePool.getNodeIdx(prev);
|
node.pidx = m_nodePool.getNodeIdx(prev);
|
||||||
prev = node;
|
prev = node;
|
||||||
|
int nextRay = node.flags & (byte)dtNodeFlags.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent (i.e. due to raycast shortcut)
|
||||||
|
node.flags = (byte)((node.flags & ~(byte)dtNodeFlags.DT_NODE_PARENT_DETACHED) | prevRay); // and store it in the reversed path's node
|
||||||
|
prevRay = nextRay;
|
||||||
node = next;
|
node = next;
|
||||||
}
|
}
|
||||||
while (node != null);
|
while (node != null);
|
||||||
@@ -1599,14 +1688,38 @@ public static partial class Detour
|
|||||||
// Store path
|
// Store path
|
||||||
node = prev;
|
node = prev;
|
||||||
do
|
do
|
||||||
|
{
|
||||||
|
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||||
|
dtStatus status = 0;
|
||||||
|
if ((node.flags & (byte)dtNodeFlags.DT_NODE_PARENT_DETACHED) != 0)
|
||||||
|
{
|
||||||
|
float t = 0;
|
||||||
|
float[] normal = new float[3];
|
||||||
|
uint m = 0;
|
||||||
|
dtPolyRef[] temp = new dtPolyRef[path.Length];
|
||||||
|
status = raycast(node.id, node.pos, next.pos, m_query.filter, ref t, normal, temp, ref m, maxPath - n);
|
||||||
|
|
||||||
|
for (var i = 0; i < path.Length - n; ++i)
|
||||||
|
path[n + i] = temp[i];
|
||||||
|
|
||||||
|
n += (int)m;
|
||||||
|
// raycast ends on poly boundary and the path might include the next poly boundary.
|
||||||
|
if (path[n - 1] == next.id)
|
||||||
|
n--; // remove to avoid duplicates
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
path[n++] = node.id;
|
path[n++] = node.id;
|
||||||
if (n >= maxPath)
|
if (n >= maxPath)
|
||||||
|
status = DT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status & DT_STATUS_DETAIL_MASK) != 0)
|
||||||
{
|
{
|
||||||
m_query.status |= DT_BUFFER_TOO_SMALL;
|
m_query.status |= status & DT_STATUS_DETAIL_MASK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
node = m_nodePool.getNodeAtIdx(node.pidx);
|
node = next;
|
||||||
}
|
}
|
||||||
while (node != null);
|
while (node != null);
|
||||||
}
|
}
|
||||||
@@ -1675,11 +1788,15 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the path.
|
// Reverse the path.
|
||||||
|
int prevRay = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||||
node.pidx = m_nodePool.getNodeIdx(prev);
|
node.pidx = m_nodePool.getNodeIdx(prev);
|
||||||
prev = node;
|
prev = node;
|
||||||
|
int nextRay = node.flags & (byte)dtNodeFlags.DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent (i.e. due to raycast shortcut)
|
||||||
|
node.flags = (byte)((node.flags & ~(byte)dtNodeFlags.DT_NODE_PARENT_DETACHED) | prevRay); // and store it in the reversed path's node
|
||||||
|
prevRay = nextRay;
|
||||||
node = next;
|
node = next;
|
||||||
}
|
}
|
||||||
while (node != null);
|
while (node != null);
|
||||||
@@ -1687,14 +1804,37 @@ public static partial class Detour
|
|||||||
// Store path
|
// Store path
|
||||||
node = prev;
|
node = prev;
|
||||||
do
|
do
|
||||||
|
{
|
||||||
|
dtNode next = m_nodePool.getNodeAtIdx(node.pidx);
|
||||||
|
dtStatus status = 0;
|
||||||
|
if ((node.flags & (byte)dtNodeFlags.DT_NODE_PARENT_DETACHED) != 0)
|
||||||
|
{
|
||||||
|
float t = 0;
|
||||||
|
float[] normal = new float[3];
|
||||||
|
uint m = 0;
|
||||||
|
dtPolyRef[] temp = new dtPolyRef[path.Length - n];
|
||||||
|
status = raycast(node.id, node.pos, next.pos, m_query.filter, ref t, normal, temp, ref m, maxPath - n);
|
||||||
|
for (var i = 0; i < path.Length - n; ++i)
|
||||||
|
path[n + i] = temp[i];
|
||||||
|
|
||||||
|
n += (int)m;
|
||||||
|
// raycast ends on poly boundary and the path might include the next poly boundary.
|
||||||
|
if (path[n - 1] == next.id)
|
||||||
|
n--; // remove to avoid duplicates
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
path[n++] = node.id;
|
path[n++] = node.id;
|
||||||
if (n >= maxPath)
|
if (n >= maxPath)
|
||||||
|
status = DT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status & DT_STATUS_DETAIL_MASK) != 0)
|
||||||
{
|
{
|
||||||
m_query.status |= DT_BUFFER_TOO_SMALL;
|
m_query.status |= status & DT_STATUS_DETAIL_MASK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
node = m_nodePool.getNodeAtIdx(node.pidx);
|
node = next;
|
||||||
}
|
}
|
||||||
while (node != null);
|
while (node != null);
|
||||||
}
|
}
|
||||||
@@ -1730,10 +1870,17 @@ public static partial class Detour
|
|||||||
if (straightPathRefs != null)
|
if (straightPathRefs != null)
|
||||||
straightPathRefs[straightPathCount] = polyRef;
|
straightPathRefs[straightPathCount] = polyRef;
|
||||||
straightPathCount++;
|
straightPathCount++;
|
||||||
// If reached end of path or there is no space to append more vertices, return.
|
|
||||||
if (flags == (byte)dtStraightPathFlags.DT_STRAIGHTPATH_END || straightPathCount >= maxStraightPath)
|
// If there is no space to append more vertices, return.
|
||||||
|
if (straightPathCount >= maxStraightPath)
|
||||||
{
|
{
|
||||||
return DT_SUCCESS | ((straightPathCount >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0);
|
return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If reached end of path or there is no space to append more vertices, return.
|
||||||
|
if (flags == (byte)dtStraightPathFlags.DT_STRAIGHTPATH_END)
|
||||||
|
{
|
||||||
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return DT_IN_PROGRESS;
|
return DT_IN_PROGRESS;
|
||||||
@@ -2392,6 +2539,60 @@ public static partial class Detour
|
|||||||
return DT_SUCCESS;
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @par
|
||||||
|
///
|
||||||
|
/// This method is meant to be used for quick, short distance checks.
|
||||||
|
///
|
||||||
|
/// If the path array is too small to hold the result, it will be filled as
|
||||||
|
/// far as possible from the start postion toward the end position.
|
||||||
|
///
|
||||||
|
/// <b>Using the Hit Parameter (t)</b>
|
||||||
|
///
|
||||||
|
/// If the hit parameter is a very high value (FLT_MAX), then the ray has hit
|
||||||
|
/// the end position. In this case the path represents a valid corridor to the
|
||||||
|
/// end position and the value of @p hitNormal is undefined.
|
||||||
|
///
|
||||||
|
/// If the hit parameter is zero, then the start position is on the wall that
|
||||||
|
/// was hit and the value of @p hitNormal is undefined.
|
||||||
|
///
|
||||||
|
/// If 0 < t < 1.0 then the following applies:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// distanceToHitBorder = distanceToEndPosition * t
|
||||||
|
/// hitPoint = startPos + (endPos - startPos) * t
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// <b>Use Case Restriction</b>
|
||||||
|
///
|
||||||
|
/// The raycast ignores the y-value of the end position. (2D check.) This
|
||||||
|
/// places significant limits on how it can be used. For example:
|
||||||
|
///
|
||||||
|
/// Consider a scene where there is a main floor with a second floor balcony
|
||||||
|
/// that hangs over the main floor. So the first floor mesh extends below the
|
||||||
|
/// balcony mesh. The start position is somewhere on the first floor. The end
|
||||||
|
/// position is on the balcony.
|
||||||
|
///
|
||||||
|
/// The raycast will search toward the end position along the first floor mesh.
|
||||||
|
/// If it reaches the end position's xz-coordinates it will indicate FLT_MAX
|
||||||
|
/// (no wall hit), meaning it reached the end position. This is one example of why
|
||||||
|
/// this method is meant for short distance checks.
|
||||||
|
///
|
||||||
|
public dtStatus raycast(dtPolyRef startRef, float[] startPos, float[] endPos, dtQueryFilter filter, ref float t, float[] hitNormal, dtPolyRef[] path, ref uint pathCount, int maxPath)
|
||||||
|
{
|
||||||
|
|
||||||
|
dtRaycastHit hit = new dtRaycastHit();
|
||||||
|
hit.path = path;
|
||||||
|
hit.maxPath = maxPath;
|
||||||
|
|
||||||
|
dtStatus status = raycast(startRef, startPos, endPos, filter, 0, hit);
|
||||||
|
|
||||||
|
t = hit.t;
|
||||||
|
dtVcopy(hitNormal, hit.hitNormal);
|
||||||
|
pathCount = (uint)hit.pathCount;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
/// Casts a 'walkability' ray along the surface of the navigation mesh from
|
||||||
/// the start position toward the end position.
|
/// the start position toward the end position.
|
||||||
/// @param[in] startRef The reference id of the start polygon.
|
/// @param[in] startRef The reference id of the start polygon.
|
||||||
@@ -2443,37 +2644,53 @@ public static partial class Detour
|
|||||||
/// (no wall hit), meaning it reached the end position. This is one example of why
|
/// (no wall hit), meaning it reached the end position. This is one example of why
|
||||||
/// this method is meant for short distance checks.
|
/// this method is meant for short distance checks.
|
||||||
///
|
///
|
||||||
public dtStatus raycast(dtPolyRef startRef, float[] startPos, float[] endPos, dtQueryFilter filter, ref float t, float[] hitNormal, dtPolyRef[] path, ref uint pathCount, int maxPath)
|
public dtStatus raycast(dtPolyRef startRef, float[] startPos, float[] endPos, dtQueryFilter filter, uint options, dtRaycastHit hit, dtPolyRef prevRef = 0)
|
||||||
{
|
{
|
||||||
Debug.Assert(m_nav != null);
|
Debug.Assert(m_nav != null);
|
||||||
|
|
||||||
t = 0;
|
hit.t = 0;
|
||||||
//if (pathCount)
|
hit.pathCount = 0;
|
||||||
pathCount = 0;
|
hit.pathCost = 0;
|
||||||
|
|
||||||
// Validate input
|
// Validate input
|
||||||
if (startRef == 0 || !m_nav.isValidPolyRef(startRef))
|
if (startRef == 0 || !m_nav.isValidPolyRef(startRef))
|
||||||
return DT_FAILURE | DT_INVALID_PARAM;
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
dtPolyRef curRef = startRef;
|
if (prevRef != 0 && !m_nav.isValidPolyRef(prevRef))
|
||||||
float[] verts = new float[DT_VERTS_PER_POLYGON * 3];
|
return DT_FAILURE | DT_INVALID_PARAM;
|
||||||
|
|
||||||
|
float[] dir = new float[3];
|
||||||
|
float[] curPos = new float[3];
|
||||||
|
float[] lastPos = new float[3];
|
||||||
|
float[] verts = new float[DT_VERTS_PER_POLYGON * 3 + 3];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
hitNormal[0] = 0;
|
dtVcopy(curPos, startPos);
|
||||||
hitNormal[1] = 0;
|
dtVsub(dir, endPos, startPos);
|
||||||
hitNormal[2] = 0;
|
dtVset(hit.hitNormal, 0, 0, 0);
|
||||||
|
|
||||||
dtStatus status = DT_SUCCESS;
|
dtStatus status = DT_SUCCESS;
|
||||||
|
|
||||||
|
dtMeshTile prevTile = new dtMeshTile();
|
||||||
|
dtMeshTile nextTile;
|
||||||
|
dtPoly prevPoly = new dtPoly();
|
||||||
|
dtPoly nextPoly;
|
||||||
|
dtPolyRef curRef;
|
||||||
|
|
||||||
|
// The API input has been checked already, skip checking internal data.
|
||||||
|
curRef = startRef;
|
||||||
|
dtMeshTile tile = new dtMeshTile();
|
||||||
|
dtPoly poly = new dtPoly();
|
||||||
|
m_nav.getTileAndPolyByRefUnsafe(curRef, ref tile, ref poly);
|
||||||
|
nextTile = prevTile = tile;
|
||||||
|
nextPoly = prevPoly = poly;
|
||||||
|
if (prevRef != 0)
|
||||||
|
m_nav.getTileAndPolyByRefUnsafe(prevRef, ref prevTile, ref prevPoly);
|
||||||
|
|
||||||
while (curRef != 0)
|
while (curRef != 0)
|
||||||
{
|
{
|
||||||
// Cast ray against current polygon.
|
// Cast ray against current polygon.
|
||||||
|
|
||||||
// The API input has been cheked already, skip checking internal data.
|
|
||||||
dtMeshTile tile = null;
|
|
||||||
dtPoly poly = null;
|
|
||||||
m_nav.getTileAndPolyByRefUnsafe(curRef, ref tile, ref poly);
|
|
||||||
|
|
||||||
// Collect vertices.
|
// Collect vertices.
|
||||||
int nv = 0;
|
int nv = 0;
|
||||||
for (int i = 0; i < (int)poly.vertCount; ++i)
|
for (int i = 0; i < (int)poly.vertCount; ++i)
|
||||||
@@ -2487,25 +2704,31 @@ public static partial class Detour
|
|||||||
if (!dtIntersectSegmentPoly2D(startPos, endPos, verts, nv, ref tmin, ref tmax, ref segMin, ref segMax))
|
if (!dtIntersectSegmentPoly2D(startPos, endPos, verts, nv, ref tmin, ref tmax, ref segMin, ref segMax))
|
||||||
{
|
{
|
||||||
// Could not hit the polygon, keep the old t and report hit.
|
// Could not hit the polygon, keep the old t and report hit.
|
||||||
pathCount = (uint)n;
|
hit.pathCount = n;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hit.hitEdgeIndex = segMax;
|
||||||
|
|
||||||
// Keep track of furthest t so far.
|
// Keep track of furthest t so far.
|
||||||
if (tmax > t)
|
if (tmax > hit.t)
|
||||||
t = tmax;
|
hit.t = tmax;
|
||||||
|
|
||||||
// Store visited polygons.
|
// Store visited polygons.
|
||||||
if (n < maxPath)
|
if (n < hit.maxPath)
|
||||||
path[n++] = curRef;
|
hit.path[n++] = curRef;
|
||||||
else
|
else
|
||||||
status |= DT_BUFFER_TOO_SMALL;
|
status |= DT_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
// Ray end is completely inside the polygon.
|
// Ray end is completely inside the polygon.
|
||||||
if (segMax == -1)
|
if (segMax == -1)
|
||||||
{
|
{
|
||||||
t = float.MaxValue;
|
hit.t = float.MaxValue;
|
||||||
//if (pathCount)
|
hit.pathCount = n;
|
||||||
pathCount = (uint)n;
|
|
||||||
|
// add the cost
|
||||||
|
if ((options & (int)dtRaycastOptions.DT_RAYCAST_USE_COSTS) != 0)
|
||||||
|
hit.pathCost += filter.getCost(curPos, endPos, prevRef, prevTile, prevPoly, curRef, tile, poly, curRef, tile, poly);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2521,8 +2744,8 @@ public static partial class Detour
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Get pointer to the next polygon.
|
// Get pointer to the next polygon.
|
||||||
dtMeshTile nextTile = null;
|
nextTile = new dtMeshTile();
|
||||||
dtPoly nextPoly = null;
|
nextPoly = new dtPoly();
|
||||||
m_nav.getTileAndPolyByRefUnsafe(link.polyRef, ref nextTile, ref nextPoly);
|
m_nav.getTileAndPolyByRefUnsafe(link.polyRef, ref nextTile, ref nextPoly);
|
||||||
|
|
||||||
// Skip off-mesh connections.
|
// Skip off-mesh connections.
|
||||||
@@ -2594,6 +2817,25 @@ public static partial class Detour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add the cost
|
||||||
|
if ((options & (int)dtRaycastOptions.DT_RAYCAST_USE_COSTS) != 0)
|
||||||
|
{
|
||||||
|
// compute the intersection point at the furthest end of the polygon
|
||||||
|
// and correct the height (since the raycast moves in 2d)
|
||||||
|
dtVcopy(lastPos, curPos);
|
||||||
|
dtVmad(curPos, startPos, dir, hit.t);
|
||||||
|
int e1Start = segMax * 3;
|
||||||
|
int e2Start = ((segMax + 1) % nv) * 3;
|
||||||
|
float[] eDir = new float[3];
|
||||||
|
float[] diff = new float[3];
|
||||||
|
dtVsub(eDir, 0, verts, e2Start, verts, e1Start);
|
||||||
|
dtVsub(diff, 0, curPos, 0, verts, e1Start);
|
||||||
|
float s = dtSqr(eDir[0]) > dtSqr(eDir[2]) ? diff[0] / eDir[0] : diff[2] / eDir[2];
|
||||||
|
curPos[1] = verts[e1Start + 1] + eDir[1] * s;
|
||||||
|
|
||||||
|
hit.pathCost += filter.getCost(lastPos, curPos, prevRef, prevTile, prevPoly, curRef, tile, poly, nextRef, nextTile, nextPoly);
|
||||||
|
}
|
||||||
|
|
||||||
if (nextRef == 0)
|
if (nextRef == 0)
|
||||||
{
|
{
|
||||||
// No neighbour, we hit a wall.
|
// No neighbour, we hit a wall.
|
||||||
@@ -2607,22 +2849,25 @@ public static partial class Detour
|
|||||||
int vbStart = b * 3;
|
int vbStart = b * 3;
|
||||||
float dx = verts[vbStart + 0] - verts[vaStart + 0];
|
float dx = verts[vbStart + 0] - verts[vaStart + 0];
|
||||||
float dz = verts[vbStart + 2] - verts[vaStart + 2];
|
float dz = verts[vbStart + 2] - verts[vaStart + 2];
|
||||||
hitNormal[0] = dz;
|
hit.hitNormal[0] = dz;
|
||||||
hitNormal[1] = 0;
|
hit.hitNormal[1] = 0;
|
||||||
hitNormal[2] = -dx;
|
hit.hitNormal[2] = -dx;
|
||||||
dtVnormalize(hitNormal);
|
dtVnormalize(hit.hitNormal);
|
||||||
|
|
||||||
//if (pathCount)
|
hit.pathCount = n;
|
||||||
pathCount = (uint)n;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No hit, advance to neighbour polygon.
|
// No hit, advance to neighbour polygon.
|
||||||
|
prevRef = curRef;
|
||||||
curRef = nextRef;
|
curRef = nextRef;
|
||||||
|
prevTile = tile;
|
||||||
|
tile = nextTile;
|
||||||
|
prevPoly = poly;
|
||||||
|
poly = nextPoly;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (pathCount)
|
hit.pathCount = n;
|
||||||
pathCount = (uint)n;
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -3686,6 +3931,60 @@ public static partial class Detour
|
|||||||
return m_nav;
|
return m_nav;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class dtFindNearestPolyQuery
|
||||||
|
{
|
||||||
|
dtNavMeshQuery m_query;
|
||||||
|
float[] m_center;
|
||||||
|
float m_nearestDistanceSqr;
|
||||||
|
dtPolyRef m_nearestRef;
|
||||||
|
float[] m_nearestPoint = new float[3];
|
||||||
|
|
||||||
|
public dtFindNearestPolyQuery(dtNavMeshQuery query, float[] center)
|
||||||
|
{
|
||||||
|
m_query = query;
|
||||||
|
m_center = center;
|
||||||
|
m_nearestDistanceSqr = float.MaxValue;
|
||||||
|
m_nearestRef = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dtPolyRef nearestRef() { return m_nearestRef; }
|
||||||
|
public float[] nearestPoint() { return m_nearestPoint; }
|
||||||
|
|
||||||
|
public void process(dtMeshTile tile, dtPoly[] polys, dtPolyRef[] refs, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
dtPolyRef refe = refs[i];
|
||||||
|
float[] closestPtPoly = new float[3];
|
||||||
|
float[] diff = new float[3];
|
||||||
|
bool posOverPoly = false;
|
||||||
|
float d;
|
||||||
|
m_query.closestPointOnPoly(refe, m_center, closestPtPoly, ref posOverPoly);
|
||||||
|
|
||||||
|
// If a point is directly over a polygon and closer than
|
||||||
|
// climb height, favor that instead of straight line nearest point.
|
||||||
|
dtVsub(diff, m_center, closestPtPoly);
|
||||||
|
if (posOverPoly)
|
||||||
|
{
|
||||||
|
d = Math.Abs(diff[1]) - tile.header.walkableClimb;
|
||||||
|
d = d > 0 ? d * d : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = dtVlenSqr(diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d < m_nearestDistanceSqr)
|
||||||
|
{
|
||||||
|
dtVcopy(m_nearestPoint, closestPtPoly);
|
||||||
|
|
||||||
|
m_nearestDistanceSqr = d;
|
||||||
|
m_nearestRef = refe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public partial class Detour
|
|||||||
{
|
{
|
||||||
DT_NODE_OPEN = 0x01,
|
DT_NODE_OPEN = 0x01,
|
||||||
DT_NODE_CLOSED = 0x02,
|
DT_NODE_CLOSED = 0x02,
|
||||||
|
DT_NODE_PARENT_DETACHED = 0x04, // parent of the node is not adjacent. Found using raycast.
|
||||||
};
|
};
|
||||||
|
|
||||||
public const dtNodeIndex DT_NULL_IDX = dtNodeIndex.MaxValue; //(dtNodeIndex)~0;
|
public const dtNodeIndex DT_NULL_IDX = dtNodeIndex.MaxValue; //(dtNodeIndex)~0;
|
||||||
@@ -32,8 +33,9 @@ public partial class Detour
|
|||||||
public float[] pos = new float[3]; //< Position of the node.
|
public float[] pos = new float[3]; //< Position of the node.
|
||||||
public float cost; //< Cost from previous node to current node.
|
public float cost; //< Cost from previous node to current node.
|
||||||
public float total; //< Cost up to the node.
|
public float total; //< Cost up to the node.
|
||||||
public uint pidx;// : 30; //< Index to parent node.
|
public uint pidx;// : 24; //< Index to parent node.
|
||||||
public byte flags;// : 2; //< Node flags 0/open/closed.
|
public uint state;// : 2; ///< extra state information. A polyRef can have multiple nodes with different extra info. see DT_MAX_STATES_PER_NODE
|
||||||
|
public byte flags;// : 3; //< Node flags 0/open/closed.
|
||||||
public dtPolyRef id; //< Polygon ref the node corresponds to.
|
public dtPolyRef id; //< Polygon ref the node corresponds to.
|
||||||
///
|
///
|
||||||
public static int getSizeOf()
|
public static int getSizeOf()
|
||||||
@@ -73,7 +75,6 @@ public partial class Detour
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
public dtNodePool(int maxNodes, int hashSize)
|
public dtNodePool(int maxNodes, int hashSize)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_maxNodes = maxNodes;
|
m_maxNodes = maxNodes;
|
||||||
m_hashSize = hashSize;
|
m_hashSize = hashSize;
|
||||||
@@ -164,14 +165,14 @@ public partial class Detour
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public dtNode getNode(dtPolyRef id)
|
public dtNode getNode(dtPolyRef id, byte state = 0)
|
||||||
{
|
{
|
||||||
uint bucket = (uint)(dtHashRef(id) & (m_hashSize - 1));
|
uint bucket = (uint)(dtHashRef(id) & (m_hashSize - 1));
|
||||||
dtNodeIndex i = m_first[bucket];
|
dtNodeIndex i = m_first[bucket];
|
||||||
dtNode node = null;
|
dtNode node = null;
|
||||||
while (i != DT_NULL_IDX)
|
while (i != DT_NULL_IDX)
|
||||||
{
|
{
|
||||||
if (m_nodes[i].id == id)
|
if (m_nodes[i].id == id && m_nodes[i].state == state)
|
||||||
return m_nodes[i];
|
return m_nodes[i];
|
||||||
i = m_next[i];
|
i = m_next[i];
|
||||||
}
|
}
|
||||||
@@ -188,6 +189,7 @@ public partial class Detour
|
|||||||
node.cost = 0;
|
node.cost = 0;
|
||||||
node.total = 0;
|
node.total = 0;
|
||||||
node.id = id;
|
node.id = id;
|
||||||
|
node.state = state;
|
||||||
node.flags = 0;
|
node.flags = 0;
|
||||||
|
|
||||||
m_next[i] = m_first[bucket];
|
m_next[i] = m_first[bucket];
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ namespace Game.Chat
|
|||||||
for (int i = 0; i < navmesh.getMaxTiles(); ++i)
|
for (int i = 0; i < navmesh.getMaxTiles(); ++i)
|
||||||
{
|
{
|
||||||
Detour.dtMeshTile tile = navmesh.getTile(i);
|
Detour.dtMeshTile tile = navmesh.getTile(i);
|
||||||
if (tile == null)
|
if (tile.header == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
handler.SendSysMessage("[{0:D2}, {1:D2}]", tile.header.x, tile.header.y);
|
handler.SendSysMessage("[{0:D2}, {1:D2}]", tile.header.x, tile.header.y);
|
||||||
|
|||||||
@@ -16,12 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using Framework.Constants;
|
using Framework.Constants;
|
||||||
using Game.DataStorage;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
@@ -152,13 +149,12 @@ namespace Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
var bytes = reader.ReadBytes((int)fileHeader.size);
|
var bytes = reader.ReadBytes((int)fileHeader.size);
|
||||||
|
|
||||||
Detour.dtRawTileData data = new Detour.dtRawTileData();
|
Detour.dtRawTileData data = new Detour.dtRawTileData();
|
||||||
data.FromBytes(bytes, 0);
|
data.FromBytes(bytes, 0);
|
||||||
|
|
||||||
ulong tileRef = 0;
|
ulong tileRef = 0;
|
||||||
// memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
|
// memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
|
||||||
if (Detour.dtStatusSucceed(mmap.navMesh.addTile(data, 0, 0, ref tileRef)))
|
if (Detour.dtStatusSucceed(mmap.navMesh.addTile(data, 1, 0, ref tileRef)))
|
||||||
{
|
{
|
||||||
mmap.loadedTileRefs.Add(packedGridPos, tileRef);
|
mmap.loadedTileRefs.Add(packedGridPos, tileRef);
|
||||||
++loadedTiles;
|
++loadedTiles;
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ namespace Game.Movement
|
|||||||
|
|
||||||
// generate suffix
|
// generate suffix
|
||||||
uint suffixPolyLength = 0;
|
uint suffixPolyLength = 0;
|
||||||
|
ulong[] tempPolyRefs = new ulong[_pathPolyRefs.Length];
|
||||||
|
|
||||||
uint dtResult;
|
uint dtResult;
|
||||||
if (_straightLine)
|
if (_straightLine)
|
||||||
@@ -354,7 +355,7 @@ namespace Game.Movement
|
|||||||
_filter,
|
_filter,
|
||||||
ref hit,
|
ref hit,
|
||||||
hitNormal,
|
hitNormal,
|
||||||
_pathPolyRefs,
|
tempPolyRefs,
|
||||||
ref suffixPolyLength,
|
ref suffixPolyLength,
|
||||||
74 - (int)prefixPolyLength);
|
74 - (int)prefixPolyLength);
|
||||||
|
|
||||||
@@ -374,7 +375,7 @@ namespace Game.Movement
|
|||||||
suffixEndPoint, // start position
|
suffixEndPoint, // start position
|
||||||
endPoint, // end position
|
endPoint, // end position
|
||||||
_filter, // polygon search filter
|
_filter, // polygon search filter
|
||||||
_pathPolyRefs,
|
tempPolyRefs,
|
||||||
ref suffixPolyLength,
|
ref suffixPolyLength,
|
||||||
74 - (int)prefixPolyLength);
|
74 - (int)prefixPolyLength);
|
||||||
}
|
}
|
||||||
@@ -389,6 +390,9 @@ namespace Game.Movement
|
|||||||
|
|
||||||
Log.outDebug(LogFilter.Maps, "m_polyLength={0} prefixPolyLength={1} suffixPolyLength={2} \n", _polyLength, prefixPolyLength, suffixPolyLength);
|
Log.outDebug(LogFilter.Maps, "m_polyLength={0} prefixPolyLength={1} suffixPolyLength={2} \n", _polyLength, prefixPolyLength, suffixPolyLength);
|
||||||
|
|
||||||
|
for (var i = 0; i < _pathPolyRefs.Length - (prefixPolyLength - 1); ++i)
|
||||||
|
_pathPolyRefs[(prefixPolyLength - 1) + i] = tempPolyRefs[i];
|
||||||
|
|
||||||
// new path = prefix + suffix - overlap
|
// new path = prefix + suffix - overlap
|
||||||
_polyLength = prefixPolyLength + suffixPolyLength - 1;
|
_polyLength = prefixPolyLength + suffixPolyLength - 1;
|
||||||
}
|
}
|
||||||
@@ -797,21 +801,21 @@ namespace Game.Movement
|
|||||||
|
|
||||||
void CreateFilter()
|
void CreateFilter()
|
||||||
{
|
{
|
||||||
NavArea includeFlags = 0;
|
NavTerrainFlag includeFlags = 0;
|
||||||
NavArea excludeFlags = 0;
|
NavTerrainFlag excludeFlags = 0;
|
||||||
|
|
||||||
if (_sourceUnit.IsTypeId(TypeId.Unit))
|
if (_sourceUnit.IsTypeId(TypeId.Unit))
|
||||||
{
|
{
|
||||||
Creature creature = _sourceUnit.ToCreature();
|
Creature creature = _sourceUnit.ToCreature();
|
||||||
if (creature.CanWalk())
|
if (creature.CanWalk())
|
||||||
includeFlags |= NavArea.Ground;
|
includeFlags |= NavTerrainFlag.Ground;
|
||||||
|
|
||||||
// creatures don't take environmental damage
|
// creatures don't take environmental damage
|
||||||
if (creature.CanSwim())
|
if (creature.CanSwim())
|
||||||
includeFlags |= (NavArea.Water | NavArea.MagmaSlime);
|
includeFlags |= (NavTerrainFlag.Water | NavTerrainFlag.MagmaSlime);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
includeFlags = (NavArea.Ground | NavArea.Water | NavArea.MagmaSlime);
|
includeFlags = (NavTerrainFlag.Ground | NavTerrainFlag.Water | NavTerrainFlag.MagmaSlime);
|
||||||
|
|
||||||
_filter.setIncludeFlags((ushort)includeFlags);
|
_filter.setIncludeFlags((ushort)includeFlags);
|
||||||
_filter.setExcludeFlags((ushort)excludeFlags);
|
_filter.setExcludeFlags((ushort)excludeFlags);
|
||||||
|
|||||||
Reference in New Issue
Block a user