mirror of
https://github.com/ENSL/NS.git
synced 2025-04-20 16:30:56 +00:00
Implemented long-range off-mesh connections and dynamic off-mesh connections
This commit is contained in:
parent
53b51d68a7
commit
46efcdaeda
9 changed files with 696 additions and 132 deletions
|
@ -284,7 +284,7 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int flag
|
|||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
|
||||
return addTile(data, dataSize, flags, 0, 0);
|
||||
return addTile(data, dataSize, flags, 0, 0, false);
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -979,7 +979,7 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
|
|||
///
|
||||
/// @see dtCreateNavMeshData, #removeTile
|
||||
dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
dtTileRef lastRef, dtTileRef* result)
|
||||
dtTileRef lastRef, dtTileRef* result, bool bMarkOffMeshDirty)
|
||||
{
|
||||
// Make sure the data is in right format.
|
||||
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||
|
@ -1057,7 +1057,8 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*header->detailTriCount);
|
||||
const int bvtreeSize = dtAlign4(sizeof(dtBVNode)*header->bvNodeCount);
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
|
||||
const int receivingOffMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->receivingOffMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
tile->verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
tile->polys = dtGetThenAdvanceBufferPointer<dtPoly>(d, polysSize);
|
||||
|
@ -1067,6 +1068,8 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
tile->detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
tile->bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
tile->offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
tile->receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receivingOffMeshLinksSize);
|
||||
|
||||
|
||||
// If there are no items in the bvtree, reset the tree pointer.
|
||||
if (!bvtreeSize)
|
||||
|
@ -1088,7 +1091,6 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
|
||||
// Base off-mesh connections to their starting polygons and connect connections inside the tile.
|
||||
baseOffMeshLinks(tile);
|
||||
connectExtOffMeshLinks(tile, tile, -1);
|
||||
|
||||
// Create connections with neighbour tiles.
|
||||
static const int MAX_NEIS = 32;
|
||||
|
@ -1104,8 +1106,6 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
|
||||
connectExtLinks(tile, neis[j], -1);
|
||||
connectExtLinks(neis[j], tile, -1);
|
||||
connectExtOffMeshLinks(tile, neis[j], -1);
|
||||
connectExtOffMeshLinks(neis[j], tile, -1);
|
||||
}
|
||||
|
||||
// Connect with neighbour tiles.
|
||||
|
@ -1116,10 +1116,19 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
{
|
||||
connectExtLinks(tile, neis[j], i);
|
||||
connectExtLinks(neis[j], tile, dtOppositeTile(i));
|
||||
connectExtOffMeshLinks(tile, neis[j], i);
|
||||
connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i));
|
||||
}
|
||||
}
|
||||
|
||||
GlobalOffMeshLinks(tile);
|
||||
|
||||
if (bMarkOffMeshDirty)
|
||||
{
|
||||
for (int i = 0; i < tile->header->receivingOffMeshConCount; i++)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &tile->receivingOffMeshCons[i];
|
||||
|
||||
m_PendingOffMeshs[m_NumPendingConnections++] = targetCon;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
|
@ -1128,6 +1137,96 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
void dtNavMesh::GlobalOffMeshLinks(dtMeshTile* target)
|
||||
{
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < target->header->offMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &target->offMeshCons[i];
|
||||
|
||||
dtPoly* targetPoly = &target->polys[targetCon->poly];
|
||||
// Skip off-mesh connections which start location could not be connected at all.
|
||||
if (targetPoly->firstLink == DT_NULL_LINK)
|
||||
continue;
|
||||
|
||||
const float ext[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad };
|
||||
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
dtVsub(bmin, &targetCon->pos[3], ext);
|
||||
dtVadd(bmax, &targetCon->pos[3], ext);
|
||||
|
||||
// Find tiles the query touches.
|
||||
int minx, miny, maxx, maxy;
|
||||
this->calcTileLoc(bmin, &minx, &miny);
|
||||
this->calcTileLoc(bmax, &maxx, &maxy);
|
||||
|
||||
static const int MAX_NEIS = 32;
|
||||
dtMeshTile* neis[MAX_NEIS];
|
||||
|
||||
for (int y = miny; y <= maxy; ++y)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
const int nneis = this->getTilesAt(x, y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
auto tile = neis[j];
|
||||
|
||||
|
||||
// Find polygon to connect to.
|
||||
const float* p = &targetCon->pos[3];
|
||||
float nearestPt[3];
|
||||
dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt);
|
||||
if (!ref)
|
||||
continue;
|
||||
// findNearestPoly may return too optimistic results, further check to make sure.
|
||||
if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(targetCon->rad))
|
||||
continue;
|
||||
// Make sure the location is on current mesh.
|
||||
float* v = &target->verts[targetPoly->verts[1] * 3];
|
||||
dtVcopy(v, nearestPt);
|
||||
|
||||
// Link off-mesh connection to target poly.
|
||||
unsigned int idx = allocLink(target);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
dtLink* link = &target->links[idx];
|
||||
link->ref = ref;
|
||||
link->edge = (unsigned char)1;
|
||||
link->side = (unsigned char)0xff;
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = targetPoly->firstLink;
|
||||
targetPoly->firstLink = idx;
|
||||
}
|
||||
|
||||
// Link target poly to off-mesh connection.
|
||||
if (targetCon->flags & DT_OFFMESH_CON_BIDIR)
|
||||
{
|
||||
unsigned int tidx = allocLink(tile);
|
||||
if (tidx != DT_NULL_LINK)
|
||||
{
|
||||
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
|
||||
dtPoly* landPoly = &tile->polys[landPolyIdx];
|
||||
dtLink* link = &tile->links[tidx];
|
||||
link->ref = getPolyRefBase(target) | (dtPolyRef)(targetCon->poly);
|
||||
link->edge = (unsigned char)0xff;
|
||||
link->side = (unsigned char)(0xff);
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = landPoly->firstLink;
|
||||
landPoly->firstLink = tidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const
|
||||
{
|
||||
// Find tile based on hash.
|
||||
|
|
|
@ -289,40 +289,41 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
return false;
|
||||
|
||||
const int nvp = params->nvp;
|
||||
|
||||
|
||||
// Classify off-mesh connection points. We store only the connections
|
||||
// whose start point is inside the tile.
|
||||
unsigned char* offMeshConClass = 0;
|
||||
int storedOffMeshConCount = 0;
|
||||
int receiveOffMeshConCount = 0;
|
||||
int offMeshConLinkCount = 0;
|
||||
|
||||
|
||||
if (params->offMeshConCount > 0)
|
||||
{
|
||||
offMeshConClass = (unsigned char*)dtAlloc(sizeof(unsigned char)*params->offMeshConCount*2, DT_ALLOC_TEMP);
|
||||
offMeshConClass = (unsigned char*)dtAlloc(sizeof(unsigned char) * params->offMeshConCount * 2, DT_ALLOC_TEMP);
|
||||
if (!offMeshConClass)
|
||||
return false;
|
||||
|
||||
// Find tight heigh bounds, used for culling out off-mesh start locations.
|
||||
float hmin = FLT_MAX;
|
||||
float hmax = -FLT_MAX;
|
||||
|
||||
|
||||
if (params->detailVerts && params->detailVertsCount)
|
||||
{
|
||||
for (int i = 0; i < params->detailVertsCount; ++i)
|
||||
{
|
||||
const float h = params->detailVerts[i*3+1];
|
||||
hmin = dtMin(hmin,h);
|
||||
hmax = dtMax(hmax,h);
|
||||
const float h = params->detailVerts[i * 3 + 1];
|
||||
hmin = dtMin(hmin, h);
|
||||
hmax = dtMax(hmax, h);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < params->vertCount; ++i)
|
||||
{
|
||||
const unsigned short* iv = ¶ms->verts[i*3];
|
||||
const unsigned short* iv = ¶ms->verts[i * 3];
|
||||
const float h = params->bmin[1] + iv[1] * params->ch;
|
||||
hmin = dtMin(hmin,h);
|
||||
hmax = dtMax(hmax,h);
|
||||
hmin = dtMin(hmin, h);
|
||||
hmax = dtMax(hmax, h);
|
||||
}
|
||||
}
|
||||
hmin -= params->walkableClimb;
|
||||
|
@ -335,55 +336,62 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
const float* p0 = ¶ms->offMeshConVerts[(i*2+0)*3];
|
||||
const float* p1 = ¶ms->offMeshConVerts[(i*2+1)*3];
|
||||
offMeshConClass[i*2+0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i*2+1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||
const float* p0 = ¶ms->offMeshConVerts[(i * 2 + 0) * 3];
|
||||
const float* p1 = ¶ms->offMeshConVerts[(i * 2 + 1) * 3];
|
||||
offMeshConClass[i * 2 + 0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||
|
||||
// Zero out off-mesh start positions which are not even potentially touching the mesh.
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
if (p0[1] < bmin[1] || p0[1] > bmax[1])
|
||||
offMeshConClass[i*2+0] = 0;
|
||||
offMeshConClass[i * 2 + 0] = 0;
|
||||
}
|
||||
|
||||
// Cound how many links should be allocated for off-mesh connections.
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
offMeshConLinkCount++;
|
||||
if (offMeshConClass[i*2+1] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 1] == 0xff)
|
||||
offMeshConLinkCount++;
|
||||
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
storedOffMeshConCount++;
|
||||
}
|
||||
else if (offMeshConClass[i * 2 + 1] == 0xff)
|
||||
{
|
||||
receiveOffMeshConCount++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Off-mesh connectionss are stored as polygons, adjust values.
|
||||
const int totPolyCount = params->polyCount + storedOffMeshConCount;
|
||||
const int totVertCount = params->vertCount + storedOffMeshConCount*2;
|
||||
|
||||
const int totVertCount = params->vertCount + storedOffMeshConCount * 2;
|
||||
|
||||
// Find portal edges which are at tile borders.
|
||||
int edgeCount = 0;
|
||||
int portalCount = 0;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i*2*nvp];
|
||||
const unsigned short* p = ¶ms->polys[i * 2 * nvp];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == MESH_NULL_IDX) break;
|
||||
edgeCount++;
|
||||
|
||||
if (p[nvp+j] & 0x8000)
|
||||
|
||||
if (p[nvp + j] & 0x8000)
|
||||
{
|
||||
unsigned short dir = p[nvp+j] & 0xf;
|
||||
unsigned short dir = p[nvp + j] & 0xf;
|
||||
if (dir != 0xf)
|
||||
portalCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int maxLinkCount = edgeCount + portalCount*2 + offMeshConLinkCount*2;
|
||||
|
||||
const int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2;
|
||||
|
||||
// Find unique detail vertices.
|
||||
int uniqueDetailVertCount = 0;
|
||||
int detailTriCount = 0;
|
||||
|
@ -393,8 +401,8 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
detailTriCount = params->detailTriCount;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||
int ndv = params->detailMeshes[i*4+1];
|
||||
const unsigned short* p = ¶ms->polys[i * nvp * 2];
|
||||
int ndv = params->detailMeshes[i * 4 + 1];
|
||||
int nv = 0;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
|
@ -412,40 +420,41 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
detailTriCount = 0;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||
const unsigned short* p = ¶ms->polys[i * nvp * 2];
|
||||
int nv = 0;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == MESH_NULL_IDX) break;
|
||||
nv++;
|
||||
}
|
||||
detailTriCount += nv-2;
|
||||
detailTriCount += nv - 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate data size
|
||||
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||
const int vertsSize = dtAlign4(sizeof(float)*3*totVertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly)*totPolyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount);
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
||||
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
|
||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
|
||||
|
||||
const int vertsSize = dtAlign4(sizeof(float) * 3 * totVertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly) * totPolyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink) * maxLinkCount);
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * params->polyCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float) * 3 * uniqueDetailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char) * 4 * detailTriCount);
|
||||
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode) * params->polyCount * 2) : 0;
|
||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection) * storedOffMeshConCount);
|
||||
const int receiveOffMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection) * receiveOffMeshConCount);
|
||||
|
||||
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
||||
detailMeshesSize + detailVertsSize + detailTrisSize +
|
||||
bvTreeSize + offMeshConsSize;
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char)*dataSize, DT_ALLOC_PERM);
|
||||
detailMeshesSize + detailVertsSize + detailTrisSize +
|
||||
bvTreeSize + offMeshConsSize + receiveOffMeshConsSize;
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char) * dataSize, DT_ALLOC_PERM);
|
||||
if (!data)
|
||||
{
|
||||
dtFree(offMeshConClass);
|
||||
return false;
|
||||
}
|
||||
memset(data, 0, dataSize);
|
||||
|
||||
|
||||
unsigned char* d = data;
|
||||
|
||||
dtMeshHeader* header = dtGetThenAdvanceBufferPointer<dtMeshHeader>(d, headerSize);
|
||||
|
@ -457,8 +466,9 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
unsigned char* navDTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* navBvtree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvTreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshConsSize);
|
||||
|
||||
|
||||
dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receiveOffMeshConsSize);
|
||||
|
||||
|
||||
// Store header
|
||||
header->magic = DT_NAVMESH_MAGIC;
|
||||
header->version = DT_NAVMESH_VERSION;
|
||||
|
@ -480,17 +490,18 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
header->walkableRadius = params->walkableRadius;
|
||||
header->walkableClimb = params->walkableClimb;
|
||||
header->offMeshConCount = storedOffMeshConCount;
|
||||
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
|
||||
|
||||
header->receivingOffMeshConCount = receiveOffMeshConCount;
|
||||
header->bvNodeCount = params->buildBvTree ? params->polyCount * 2 : 0;
|
||||
|
||||
const int offMeshVertsBase = params->vertCount;
|
||||
const int offMeshPolyBase = params->polyCount;
|
||||
|
||||
|
||||
// Store vertices
|
||||
// Mesh vertices
|
||||
for (int i = 0; i < params->vertCount; ++i)
|
||||
{
|
||||
const unsigned short* iv = ¶ms->verts[i*3];
|
||||
float* v = &navVerts[i*3];
|
||||
const unsigned short* iv = ¶ms->verts[i * 3];
|
||||
float* v = &navVerts[i * 3];
|
||||
v[0] = params->bmin[0] + iv[0] * params->cs;
|
||||
v[1] = params->bmin[1] + iv[1] * params->ch;
|
||||
v[2] = params->bmin[2] + iv[2] * params->cs;
|
||||
|
@ -500,16 +511,16 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
const float* linkv = ¶ms->offMeshConVerts[i*2*3];
|
||||
float* v = &navVerts[(offMeshVertsBase + n*2)*3];
|
||||
const float* linkv = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
float* v = &navVerts[(offMeshVertsBase + n * 2) * 3];
|
||||
dtVcopy(&v[0], &linkv[0]);
|
||||
dtVcopy(&v[3], &linkv[3]);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Store polygons
|
||||
// Mesh polys
|
||||
const unsigned short* src = params->polys;
|
||||
|
@ -524,10 +535,10 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
{
|
||||
if (src[j] == MESH_NULL_IDX) break;
|
||||
p->verts[j] = src[j];
|
||||
if (src[nvp+j] & 0x8000)
|
||||
if (src[nvp + j] & 0x8000)
|
||||
{
|
||||
// Border or portal edge.
|
||||
unsigned short dir = src[nvp+j] & 0xf;
|
||||
unsigned short dir = src[nvp + j] & 0xf;
|
||||
if (dir == 0xf) // Border
|
||||
p->neis[j] = 0;
|
||||
else if (dir == 0) // Portal x-
|
||||
|
@ -542,24 +553,24 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
else
|
||||
{
|
||||
// Normal connection
|
||||
p->neis[j] = src[nvp+j]+1;
|
||||
p->neis[j] = src[nvp + j] + 1;
|
||||
}
|
||||
|
||||
|
||||
p->vertCount++;
|
||||
}
|
||||
src += nvp*2;
|
||||
src += nvp * 2;
|
||||
}
|
||||
// Off-mesh connection vertices.
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
dtPoly* p = &navPolys[offMeshPolyBase+n];
|
||||
dtPoly* p = &navPolys[offMeshPolyBase + n];
|
||||
p->vertCount = 2;
|
||||
p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0);
|
||||
p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1);
|
||||
p->verts[0] = (unsigned short)(offMeshVertsBase + n * 2 + 0);
|
||||
p->verts[1] = (unsigned short)(offMeshVertsBase + n * 2 + 1);
|
||||
p->flags = params->offMeshConFlags[i];
|
||||
p->setArea(params->offMeshConAreas[i]);
|
||||
p->setType(DT_POLYTYPE_OFFMESH_CONNECTION);
|
||||
|
@ -576,22 +587,22 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
dtPolyDetail& dtl = navDMeshes[i];
|
||||
const int vb = (int)params->detailMeshes[i*4+0];
|
||||
const int ndv = (int)params->detailMeshes[i*4+1];
|
||||
const int vb = (int)params->detailMeshes[i * 4 + 0];
|
||||
const int ndv = (int)params->detailMeshes[i * 4 + 1];
|
||||
const int nv = navPolys[i].vertCount;
|
||||
dtl.vertBase = (unsigned int)vbase;
|
||||
dtl.vertCount = (unsigned char)(ndv-nv);
|
||||
dtl.triBase = (unsigned int)params->detailMeshes[i*4+2];
|
||||
dtl.triCount = (unsigned char)params->detailMeshes[i*4+3];
|
||||
dtl.vertCount = (unsigned char)(ndv - nv);
|
||||
dtl.triBase = (unsigned int)params->detailMeshes[i * 4 + 2];
|
||||
dtl.triCount = (unsigned char)params->detailMeshes[i * 4 + 3];
|
||||
// Copy vertices except the first 'nv' verts which are equal to nav poly verts.
|
||||
if (ndv-nv)
|
||||
if (ndv - nv)
|
||||
{
|
||||
memcpy(&navDVerts[vbase*3], ¶ms->detailVerts[(vb+nv)*3], sizeof(float)*3*(ndv-nv));
|
||||
vbase += (unsigned short)(ndv-nv);
|
||||
memcpy(&navDVerts[vbase * 3], ¶ms->detailVerts[(vb + nv) * 3], sizeof(float) * 3 * (ndv - nv));
|
||||
vbase += (unsigned short)(ndv - nv);
|
||||
}
|
||||
}
|
||||
// Store triangles.
|
||||
memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount);
|
||||
memcpy(navDTris, params->detailTris, sizeof(unsigned char) * 4 * params->detailTriCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -604,18 +615,18 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
dtl.vertBase = 0;
|
||||
dtl.vertCount = 0;
|
||||
dtl.triBase = (unsigned int)tbase;
|
||||
dtl.triCount = (unsigned char)(nv-2);
|
||||
dtl.triCount = (unsigned char)(nv - 2);
|
||||
// Triangulate polygon (local indices).
|
||||
for (int j = 2; j < nv; ++j)
|
||||
{
|
||||
unsigned char* t = &navDTris[tbase*4];
|
||||
unsigned char* t = &navDTris[tbase * 4];
|
||||
t[0] = 0;
|
||||
t[1] = (unsigned char)(j-1);
|
||||
t[1] = (unsigned char)(j - 1);
|
||||
t[2] = (unsigned char)j;
|
||||
// Bit for each edge that belongs to poly boundary.
|
||||
t[3] = (1<<2);
|
||||
if (j == 2) t[3] |= (1<<0);
|
||||
if (j == nv-1) t[3] |= (1<<4);
|
||||
t[3] = (1 << 2);
|
||||
if (j == 2) t[3] |= (1 << 0);
|
||||
if (j == nv - 1) t[3] |= (1 << 4);
|
||||
tbase++;
|
||||
}
|
||||
}
|
||||
|
@ -624,36 +635,63 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
// Store and create BVtree.
|
||||
if (params->buildBvTree)
|
||||
{
|
||||
createBVTree(params, navBvtree, 2*params->polyCount);
|
||||
createBVTree(params, navBvtree, 2 * params->polyCount);
|
||||
}
|
||||
|
||||
|
||||
// Store Off-Mesh connections.
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i*2+0] == 0xff)
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
dtOffMeshConnection* con = &offMeshCons[n];
|
||||
con->poly = (unsigned short)(offMeshPolyBase + n);
|
||||
// Copy connection end-points.
|
||||
const float* endPts = ¶ms->offMeshConVerts[i*2*3];
|
||||
const float* endPts = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
dtVcopy(&con->pos[0], &endPts[0]);
|
||||
dtVcopy(&con->pos[3], &endPts[3]);
|
||||
con->rad = params->offMeshConRad[i];
|
||||
con->flags = params->offMeshConDir[i] ? DT_OFFMESH_CON_BIDIR : 0;
|
||||
con->side = offMeshConClass[i*2+1];
|
||||
con->side = offMeshConClass[i * 2 + 1];
|
||||
if (params->offMeshConUserID)
|
||||
con->userId = params->offMeshConUserID[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i * 2 + 0] != 0xff && offMeshConClass[i * 2 + 1] == 0xff)
|
||||
{
|
||||
dtOffMeshConnection* con = &receivingOffMeshCons[n];
|
||||
con->poly = (unsigned short)(offMeshPolyBase + n);
|
||||
// Copy connection end-points.
|
||||
const float* endPts = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
dtVcopy(&con->pos[0], &endPts[0]);
|
||||
dtVcopy(&con->pos[3], &endPts[3]);
|
||||
con->rad = params->offMeshConRad[i];
|
||||
con->flags = params->offMeshConDir[i] ? DT_OFFMESH_CON_BIDIR : 0;
|
||||
con->side = offMeshConClass[i * 2 + 0];
|
||||
if (params->offMeshConUserID)
|
||||
con->userId = params->offMeshConUserID[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (header->offMeshConCount > 0)
|
||||
{
|
||||
int thing = 0;
|
||||
dtIgnoreUnused(thing);
|
||||
}
|
||||
|
||||
dtFree(offMeshConClass);
|
||||
|
||||
|
||||
*outData = data;
|
||||
*outDataSize = dataSize;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -686,6 +724,7 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
dtSwapEndian(&header->detailTriCount);
|
||||
dtSwapEndian(&header->bvNodeCount);
|
||||
dtSwapEndian(&header->offMeshConCount);
|
||||
dtSwapEndian(&header->receivingOffMeshConCount);
|
||||
dtSwapEndian(&header->offMeshBase);
|
||||
dtSwapEndian(&header->walkableHeight);
|
||||
dtSwapEndian(&header->walkableRadius);
|
||||
|
@ -728,6 +767,7 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*header->detailTriCount);
|
||||
const int bvtreeSize = dtAlign4(sizeof(dtBVNode)*header->bvNodeCount);
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
const int receiveOffMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->receivingOffMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
float* verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
|
@ -740,6 +780,7 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
//unsigned char* detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receiveOffMeshLinksSize);
|
||||
|
||||
// Vertices
|
||||
for (int i = 0; i < header->vertCount*3; ++i)
|
||||
|
@ -797,6 +838,16 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
dtSwapEndian(&con->rad);
|
||||
dtSwapEndian(&con->poly);
|
||||
}
|
||||
|
||||
// Receiving Off-mesh Connections.
|
||||
for (int i = 0; i < header->receivingOffMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* con = &receivingOffMeshCons[i];
|
||||
for (int j = 0; j < 6; ++j)
|
||||
dtSwapEndian(&con->pos[j]);
|
||||
dtSwapEndian(&con->rad);
|
||||
dtSwapEndian(&con->poly);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -584,7 +584,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
{
|
||||
// Build mesh
|
||||
const dtCompressedTileRef ref = m_update[0];
|
||||
status = buildNavMeshTile(ref, navmesh);
|
||||
status = buildNavMeshTile(ref, navmesh, true);
|
||||
m_nupdate--;
|
||||
if (m_nupdate > 0)
|
||||
memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
|
||||
|
@ -628,6 +628,56 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (navmesh->GetNumPendingOffMeshConnections() > 0)
|
||||
{
|
||||
|
||||
for (int i = 0; i < navmesh->GetNumPendingOffMeshConnections(); i++)
|
||||
{
|
||||
int NumTiles = 0;
|
||||
|
||||
float* connspos = &navmesh->GetPendingConnection(i)->pos[0];
|
||||
float* connepos = &navmesh->GetPendingConnection(i)->pos[3];
|
||||
|
||||
float ext[3] = { 10.0f, 10.0f, 10.0f };
|
||||
|
||||
float searchsposMin[3];
|
||||
float searchsposMax[3];
|
||||
|
||||
float searcheposMin[3];
|
||||
float searcheposMax[3];
|
||||
|
||||
dtVsub(searchsposMin, connspos, ext);
|
||||
dtVadd(searchsposMax, connspos, ext);
|
||||
|
||||
dtVsub(searcheposMin, connepos, ext);
|
||||
dtVadd(searcheposMax, connepos, ext);
|
||||
|
||||
dtCompressedTileRef AffectedTiles[DT_MAX_TOUCHED_TILES];
|
||||
|
||||
|
||||
queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]);
|
||||
|
||||
buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false);
|
||||
}
|
||||
|
||||
queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]);
|
||||
|
||||
buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
navmesh->ClearPendingOffMeshConnections();
|
||||
}
|
||||
|
||||
if (upToDate)
|
||||
*upToDate = m_nupdate == 0 && m_nreqs == 0;
|
||||
|
@ -636,7 +686,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
}
|
||||
|
||||
|
||||
dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh)
|
||||
dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh, bool bMarkOffMeshDirty)
|
||||
{
|
||||
const int MAX_TILES = 32;
|
||||
dtCompressedTileRef tiles[MAX_TILES];
|
||||
|
@ -644,7 +694,7 @@ dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh*
|
|||
|
||||
for (int i = 0; i < ntiles; ++i)
|
||||
{
|
||||
dtStatus status = buildNavMeshTile(tiles[i], navmesh);
|
||||
dtStatus status = buildNavMeshTile(tiles[i], navmesh, bMarkOffMeshDirty);
|
||||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
}
|
||||
|
@ -652,7 +702,7 @@ dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh*
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh)
|
||||
dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh, bool bMarkOffMeshDirty)
|
||||
{
|
||||
dtAssert(m_talloc);
|
||||
dtAssert(m_tcomp);
|
||||
|
@ -768,7 +818,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
|||
if (navData)
|
||||
{
|
||||
// Let the navmesh own the data.
|
||||
status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0);
|
||||
status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0, bMarkOffMeshDirty);
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
dtFree(navData);
|
||||
|
|
|
@ -265,6 +265,7 @@ struct dtMeshHeader
|
|||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||
int offMeshConCount; ///< The number of off-mesh connections.
|
||||
int receivingOffMeshConCount;
|
||||
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||
float walkableHeight; ///< The height of the agents using the tile.
|
||||
float walkableRadius; ///< The radius of the agents using the tile.
|
||||
|
@ -301,6 +302,7 @@ struct dtMeshTile
|
|||
dtBVNode* bvTree;
|
||||
|
||||
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
dtOffMeshConnection* receivingOffMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
|
||||
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||
int dataSize; ///< Size of the tile data.
|
||||
|
@ -367,7 +369,7 @@ public:
|
|||
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result, bool bMarkOffMeshDirty);
|
||||
|
||||
/// Removes the specified tile from the navigation mesh.
|
||||
/// @param[in] ref The reference of the tile to remove.
|
||||
|
@ -465,6 +467,10 @@ public:
|
|||
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||
|
||||
int GetNumPendingOffMeshConnections() { return m_NumPendingConnections; }
|
||||
void ClearPendingOffMeshConnections() { m_NumPendingConnections = 0; }
|
||||
dtOffMeshConnection* GetPendingConnection(int index) { return m_PendingOffMeshs[index]; }
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -514,6 +520,8 @@ public:
|
|||
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||
|
||||
void GlobalOffMeshLinks(dtMeshTile* target);
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -663,6 +671,9 @@ private:
|
|||
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||
|
||||
dtOffMeshConnection* m_PendingOffMeshs[1024];
|
||||
int m_NumPendingConnections = 0;
|
||||
|
||||
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||
dtMeshTile* m_tiles; ///< List of tiles.
|
||||
|
|
|
@ -166,9 +166,9 @@ public:
|
|||
/// otherwise another call will continue processing obstacle requests and tile rebuilds.
|
||||
dtStatus update(const float dt, class dtNavMesh* navmesh, bool* upToDate = 0);
|
||||
|
||||
dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh);
|
||||
dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh, bool bMarkOffMeshDirty);
|
||||
|
||||
dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh);
|
||||
dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh, bool bMarkOffMeshDirty);
|
||||
|
||||
void calcTightTileBounds(const struct dtTileCacheLayerHeader* header, float* bmin, float* bmax) const;
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ static const int DT_TILECACHE_VERSION = 1;
|
|||
|
||||
static const unsigned char DT_TILECACHE_NULL_AREA = 0;
|
||||
static const unsigned char DT_TILECACHE_CROUCH_AREA = 1;
|
||||
static const unsigned char DT_TILECACHE_BLOCKED_AREA = 3;
|
||||
static const unsigned char DT_TILECACHE_CLIMBABLE_AREA = 4;
|
||||
static const unsigned char DT_TILECACHE_LADDER_AREA = 5;
|
||||
static const unsigned char DT_TILECACHE_MSTRUCTURE_AREA = 12;
|
||||
static const unsigned char DT_TILECACHE_ASTRUCTURE_AREA = 13;
|
||||
static const unsigned char DT_TILECACHE_WELD_AREA = 15;
|
||||
static const unsigned char DT_TILECACHE_BLOCKED_AREA = 2;
|
||||
static const unsigned char DT_TILECACHE_WALLCLIMB_AREA = 3;
|
||||
static const unsigned char DT_TILECACHE_LADDER_AREA = 4;
|
||||
static const unsigned char DT_TILECACHE_TEAM1STRUCTURE_AREA = 5;
|
||||
static const unsigned char DT_TILECACHE_TEAM2STRUCTURE_AREA = 6;
|
||||
static const unsigned char DT_TILECACHE_WELD_AREA = 7;
|
||||
static const unsigned char DT_TILECACHE_DOOR_AREA = 8;
|
||||
static const unsigned char DT_TILECACHE_WALKABLE_AREA = 63;
|
||||
static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff;
|
||||
|
||||
|
|
|
@ -272,6 +272,9 @@ void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot)
|
|||
case SAMPLE_POLYFLAGS_BLOCKED:
|
||||
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 128, 128, 128);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_PHASEGATE:
|
||||
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 128, 128);
|
||||
break;
|
||||
default:
|
||||
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc);
|
||||
break;
|
||||
|
|
|
@ -236,6 +236,62 @@ struct MeshProcess : public dtTileCacheMeshProcess
|
|||
}
|
||||
}
|
||||
|
||||
void GetOffMeshConnectionPoints(int Index, Vector& OutStartLoc, Vector& OutEndLoc)
|
||||
{
|
||||
OutStartLoc = ZERO_VECTOR;
|
||||
OutEndLoc = ZERO_VECTOR;
|
||||
|
||||
if (Index > -1 && Index < MAX_OFFMESH_CONNS)
|
||||
{
|
||||
float* src = &OffMeshVerts[Index * 3 * 2];
|
||||
|
||||
OutStartLoc.x = src[0];
|
||||
OutStartLoc.y = -src[2];
|
||||
OutStartLoc.z = src[1];
|
||||
|
||||
OutEndLoc.x = src[3];
|
||||
OutEndLoc.y = -src[5];
|
||||
OutEndLoc.z = src[4];
|
||||
}
|
||||
}
|
||||
|
||||
void DrawAllConnections(float DrawTime)
|
||||
{
|
||||
Vector StartLine = ZERO_VECTOR;
|
||||
Vector EndLine = ZERO_VECTOR;
|
||||
|
||||
for (int i = 0; i < NumOffMeshConns; i++)
|
||||
{
|
||||
Vector StartLine = Vector(OffMeshVerts[i * 6], -OffMeshVerts[(i * 6) + 2], OffMeshVerts[(i * 6) + 1]);
|
||||
Vector EndLine = Vector(OffMeshVerts[(i * 6) + 3], -OffMeshVerts[(i * 6) + 5], OffMeshVerts[(i * 6) + 4]);
|
||||
|
||||
switch (OffMeshFlags[i])
|
||||
{
|
||||
case SAMPLE_POLYFLAGS_WALK:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_JUMP:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_FALL:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 0, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_LADDER:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 0, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_PHASEGATE:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 128, 128);
|
||||
break;
|
||||
default:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void process(struct dtNavMeshCreateParams* params,
|
||||
unsigned char* polyAreas, unsigned short* polyFlags)
|
||||
{
|
||||
|
@ -300,6 +356,19 @@ struct MeshProcess : public dtTileCacheMeshProcess
|
|||
}
|
||||
};
|
||||
|
||||
void AIDEBUG_DrawOffMeshConnections(float DrawTime)
|
||||
{
|
||||
if (NavMeshes[0].tileCache)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess();
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
m_tmproc->DrawAllConnections(DrawTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UTIL_UpdateTileCache()
|
||||
{
|
||||
for (int i = 0; i < MAX_NAV_MESHES; i++)
|
||||
|
@ -799,7 +868,7 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh);
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.numOnosTiles; ++i)
|
||||
|
@ -838,7 +907,7 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh);
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.numBuildingTiles; ++i)
|
||||
|
@ -877,7 +946,7 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh);
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
fclose(savedFile);
|
||||
|
@ -949,7 +1018,6 @@ void UTIL_PopulateBaseNavProfiles()
|
|||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
|
||||
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_LADDER);
|
||||
|
||||
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
|
||||
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].bFlyingProfile = false;
|
||||
|
@ -2882,8 +2950,17 @@ void NewMove(AvHAIPlayer* pBot)
|
|||
}
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_LADDER:
|
||||
LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, NextArea);
|
||||
break;
|
||||
{
|
||||
if (IsPlayerSkulk(pBot->Edict))
|
||||
{
|
||||
SkulkLadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, NextArea);
|
||||
}
|
||||
else
|
||||
{
|
||||
LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, NextArea);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_PHASEGATE:
|
||||
PhaseGateMove(pBot, MoveFrom, MoveTo);
|
||||
break;
|
||||
|
@ -3081,8 +3158,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
edict_t* pEdict = pBot->Edict;
|
||||
AvHPlayer* AIPlayer = pBot->Player;
|
||||
|
||||
|
||||
|
||||
const Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
|
||||
|
||||
bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z);
|
||||
|
@ -3346,6 +3421,131 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
}
|
||||
}
|
||||
|
||||
void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea)
|
||||
{
|
||||
edict_t* pEdict = pBot->Edict;
|
||||
AvHPlayer* AIPlayer = pBot->Player;
|
||||
|
||||
const Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
|
||||
|
||||
bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z);
|
||||
|
||||
Vector LadderNormal = UTIL_GetNearestLadderNormal(pBot->Edict);
|
||||
|
||||
const Vector LadderRightNormal = UTIL_GetVectorNormal(UTIL_GetCrossProduct(LadderNormal, UP_VECTOR));
|
||||
|
||||
Vector ClimbRightNormal = LadderRightNormal;
|
||||
|
||||
if (bIsGoingUpLadder)
|
||||
{
|
||||
pBot->Button &= ~IN_DUCK;
|
||||
|
||||
ClimbRightNormal = -LadderRightNormal;
|
||||
|
||||
Vector HullTraceTo = EndPoint;
|
||||
HullTraceTo.z = pBot->CollisionHullBottomLocation.z;
|
||||
|
||||
// We have reached our desired climb height and want to get off the ladder
|
||||
if ((pBot->Edict->v.origin.z >= RequiredClimbHeight) && UTIL_QuickHullTrace(pEdict, pEdict->v.origin, Vector(EndPoint.x, EndPoint.y, pEdict->v.origin.z), head_hull))
|
||||
{
|
||||
// Move directly towards the desired get-off point, looking slightly up still
|
||||
pBot->desiredMovementDir = vForward;
|
||||
|
||||
Vector LookLocation = EndPoint;
|
||||
LookLocation.z = pBot->CurrentEyePosition.z + 64.0f;
|
||||
|
||||
BotMoveLookAt(pBot, LookLocation);
|
||||
|
||||
// If the get-off point is opposite the ladder, then jump to get to it
|
||||
if (UTIL_GetDotProduct(pBot->CurrentLadderNormal, vForward) > 0.75f)
|
||||
{
|
||||
BotJump(pBot);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is for cases where the ladder physically doesn't reach the desired get-off point and the bot kind of has to "jump" up off the ladder.
|
||||
if (pBot->CollisionHullTopLocation.z >= UTIL_GetNearestLadderTopPoint(pEdict).z)
|
||||
{
|
||||
pBot->desiredMovementDir = vForward;
|
||||
// We look up really far to get maximum launch
|
||||
BotMoveLookAt(pBot, EndPoint + Vector(0.0f, 0.0f, 100.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
// Still climbing the ladder. Look up, and move left/right on the ladder to avoid any blockages
|
||||
|
||||
Vector StartLeftTrace = pBot->CollisionHullTopLocation - (ClimbRightNormal * GetPlayerRadius(pBot->Player));
|
||||
Vector StartRightTrace = pBot->CollisionHullTopLocation + (ClimbRightNormal * GetPlayerRadius(pBot->Player));
|
||||
|
||||
bool bBlockedLeft = !UTIL_QuickTrace(pEdict, StartLeftTrace, StartLeftTrace + Vector(0.0f, 0.0f, 32.0f));
|
||||
bool bBlockedRight = !UTIL_QuickTrace(pEdict, StartRightTrace, StartRightTrace + Vector(0.0f, 0.0f, 32.0f));
|
||||
|
||||
// Look up at the top of the ladder
|
||||
|
||||
// If we are blocked going up the ladder, face the ladder and slide left/right to avoid blockage
|
||||
if (bBlockedLeft && !bBlockedRight)
|
||||
{
|
||||
Vector LookLocation = pBot->Edict->v.origin - (pBot->CurrentLadderNormal * 50.0f);
|
||||
LookLocation.z = RequiredClimbHeight + 100.0f;
|
||||
BotMoveLookAt(pBot, LookLocation);
|
||||
|
||||
pBot->desiredMovementDir = ClimbRightNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bBlockedRight && !bBlockedLeft)
|
||||
{
|
||||
Vector LookLocation = pBot->Edict->v.origin - (pBot->CurrentLadderNormal * 50.0f);
|
||||
LookLocation.z = RequiredClimbHeight + 100.0f;
|
||||
BotMoveLookAt(pBot, LookLocation);
|
||||
|
||||
pBot->desiredMovementDir = -ClimbRightNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector LookLocation = UTIL_GetNearestLadderTopPoint(pBot->Edict);
|
||||
|
||||
LookLocation.z = RequiredClimbHeight + 100.0f;
|
||||
BotMoveLookAt(pBot, LookLocation);
|
||||
|
||||
pBot->desiredMovementDir = -UTIL_GetNearestLadderNormal(pBot->Edict);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// We're going down the ladder
|
||||
|
||||
Vector StartLeftTrace = pBot->CollisionHullBottomLocation - (LadderRightNormal * (GetPlayerRadius(pBot->Player) + 2.0f));
|
||||
Vector StartRightTrace = pBot->CollisionHullBottomLocation + (LadderRightNormal * (GetPlayerRadius(pBot->Player) + 2.0f));
|
||||
|
||||
bool bBlockedLeft = !UTIL_QuickTrace(pEdict, StartLeftTrace, StartLeftTrace - Vector(0.0f, 0.0f, 32.0f));
|
||||
bool bBlockedRight = !UTIL_QuickTrace(pEdict, StartRightTrace, StartRightTrace - Vector(0.0f, 0.0f, 32.0f));
|
||||
|
||||
if (bBlockedLeft)
|
||||
{
|
||||
pBot->desiredMovementDir = LadderRightNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
if (bBlockedRight)
|
||||
{
|
||||
pBot->desiredMovementDir = -LadderRightNormal;
|
||||
return;
|
||||
}
|
||||
|
||||
pBot->desiredMovementDir = pBot->CurrentLadderNormal;
|
||||
|
||||
BotMoveLookAt(pBot, EndPoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
|
||||
{
|
||||
DeployableSearchFilter PGFilter;
|
||||
|
@ -4465,27 +4665,41 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination)
|
|||
{
|
||||
if (bReverseCourse)
|
||||
{
|
||||
LadderMove(pBot, MoveTo, MoveFrom, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
// We're going DOWN the ladder
|
||||
if (MoveTo.z > MoveFrom.z)
|
||||
if (IsPlayerSkulk(pBot->Edict))
|
||||
{
|
||||
if (pBot->Edict->v.origin.z - MoveFrom.z < 150.0f)
|
||||
SkulkLadderMove(pBot, MoveTo, MoveFrom, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
LadderMove(pBot, MoveTo, MoveFrom, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
// We're going DOWN the ladder
|
||||
if (MoveTo.z > MoveFrom.z)
|
||||
{
|
||||
BotJump(pBot);
|
||||
if (pBot->Edict->v.origin.z - MoveFrom.z < 150.0f)
|
||||
{
|
||||
BotJump(pBot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
// We're going DOWN the ladder
|
||||
if (MoveFrom.z > MoveTo.z)
|
||||
if (IsPlayerSkulk(pBot->Edict))
|
||||
{
|
||||
if (pBot->Edict->v.origin.z - MoveTo.z < 150.0f)
|
||||
SkulkLadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
}
|
||||
else
|
||||
{
|
||||
LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, (unsigned char)SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
// We're going DOWN the ladder
|
||||
if (MoveFrom.z > MoveTo.z)
|
||||
{
|
||||
BotJump(pBot);
|
||||
if (pBot->Edict->v.origin.z - MoveFrom.z < 150.0f)
|
||||
{
|
||||
BotJump(pBot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6959,4 +7173,130 @@ unsigned char UTIL_GetNextBotCurrentPathArea(AvHAIPlayer* pBot)
|
|||
if (pBot->BotNavInfo.PathSize == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.PathSize - 1) { return SAMPLE_POLYAREA_GROUND; }
|
||||
|
||||
return pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area;
|
||||
}
|
||||
|
||||
int UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned char flags, bool bBiDirectional)
|
||||
{
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess();
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
return m_tmproc->AddOffMeshConnectionDef(StartLoc, EndLoc, area, flags, bBiDirectional);
|
||||
UTIL_OnOffMeshConnectionModified(StartLoc, EndLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UTIL_RemoveOffMeshConnection(int ConnectionIndex)
|
||||
{
|
||||
Vector StartLoc, EndLoc;
|
||||
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess();
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
m_tmproc->GetOffMeshConnectionPoints(ConnectionIndex, StartLoc, EndLoc);
|
||||
m_tmproc->RemoveOffMeshConnectionDef(ConnectionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_OnOffMeshConnectionModified(StartLoc, EndLoc);
|
||||
}
|
||||
|
||||
void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc)
|
||||
{
|
||||
float ext[3] = { 10.0f, 10.0f, 10.0f };
|
||||
|
||||
float spos[3] = { StartLoc.x, StartLoc.z, -StartLoc.y };
|
||||
float epos[3] = { EndLoc.x, EndLoc.z, -EndLoc.y };
|
||||
|
||||
float searchsposMin[3];
|
||||
float searchsposMax[3];
|
||||
|
||||
float searcheposMin[3];
|
||||
float searcheposMax[3];
|
||||
|
||||
dtVsub(searchsposMin, spos, ext);
|
||||
dtVadd(searchsposMax, spos, ext);
|
||||
|
||||
dtVsub(searcheposMin, epos, ext);
|
||||
dtVadd(searcheposMax, epos, ext);
|
||||
|
||||
int NumTiles = 0;
|
||||
dtCompressedTileRef AffectedTiles[DT_MAX_TOUCHED_TILES];
|
||||
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache && NavMeshes[REGULAR_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[REGULAR_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[REGULAR_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (NavMeshes[ONOS_NAV_MESH].tileCache && NavMeshes[ONOS_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[ONOS_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[ONOS_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (NavMeshes[BUILDING_NAV_MESH].tileCache && NavMeshes[BUILDING_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[BUILDING_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[BUILDING_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -236,6 +236,8 @@ void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoi
|
|||
void FallMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint);
|
||||
// Called by NewMove, determines the movement direction and inputs required to climb a ladder to reach endpoint
|
||||
void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea);
|
||||
// Called by NewMove, determines the movement direction and inputs required to climb a ladder to reach endpoint as skulk, which requires different movement
|
||||
void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight, unsigned char NextArea);
|
||||
// Called by NewMove, determines the movement direction and inputs required to climb a wall to reach endpoint
|
||||
void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight);
|
||||
void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight);
|
||||
|
@ -269,6 +271,8 @@ bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination);
|
|||
// Called every bot frame (default is 60fps). Ensures the tile cache is updated after obstacles are placed
|
||||
void UTIL_UpdateTileCache();
|
||||
|
||||
void AIDEBUG_DrawOffMeshConnections(float DrawTime);
|
||||
|
||||
Vector UTIL_GetNearestPointOnNavWall(AvHAIPlayer* pBot, const float MaxRadius);
|
||||
Vector UTIL_GetNearestPointOnNavWall(const nav_profile& NavProfile, const Vector Location, const float MaxRadius);
|
||||
|
||||
|
@ -289,6 +293,11 @@ void UTIL_RemoveTemporaryObstacle(unsigned int ObstacleRef);
|
|||
|
||||
void UTIL_RemoveTemporaryObstacles(unsigned int* ObstacleRefs);
|
||||
|
||||
int UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned char flags, bool bBiDirectional);
|
||||
void UTIL_RemoveOffMeshConnection(int ConnectionIndex);
|
||||
void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc);
|
||||
|
||||
|
||||
/*
|
||||
Safely aborts the current movement the bot is performing. Returns true if the bot has successfully aborted, and is ready to calculate a new path.
|
||||
|
||||
|
|
Loading…
Reference in a new issue