diff --git a/main/source/detour/DetourNavMesh.cpp b/main/source/detour/DetourNavMesh.cpp index 0b3b2a93..4d4c2fcc 100644 --- a/main/source/detour/DetourNavMesh.cpp +++ b/main/source/detour/DetourNavMesh.cpp @@ -134,7 +134,6 @@ inline void freeLink(dtMeshTile* tile, unsigned int link) tile->linksFreeList = link; } - dtNavMesh* dtAllocNavMesh() { void* mem = dtAlloc(sizeof(dtNavMesh), DT_ALLOC_PERM); @@ -284,7 +283,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, false); + return addTile(data, dataSize, flags, 0, 0); } /// @par @@ -350,6 +349,169 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb, return n; } +void dtNavMesh::LinkOffMeshConnectionToTiles(dtOffMeshConnection* con) +{ + con->FromTileX = -1; + con->FromTileY = -1; + con->FromTileLayer = -1; + + con->ToTileX = -1; + con->ToTileY = -1; + con->ToTileLayer = -1; + + const float ext[3] = { con->rad, 18.0f, con->rad }; + + float bmin[3], bmax[3]; + dtVsub(bmin, &con->pos[0], ext); + dtVadd(bmax, &con->pos[0], 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]; + + float NearestDist = FLT_MAX; + + float nearestPt[3]; + + 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) + { + dtMeshTile* tile = neis[j]; + + dtPolyRef NearestPoly = findNearestPolyInTile(tile, &con->pos[0], ext, nearestPt); + + if (NearestPoly) + { + float thisDist = dtVdistSqr(nearestPt, &con->pos[0]); + + if (thisDist < NearestDist) + { + thisDist = NearestDist; + con->FromTileX = tile->header->x; + con->FromTileY = tile->header->y; + con->FromTileLayer = tile->header->layer; + } + } + } + } + } + + NearestDist = FLT_MAX; + + dtVsub(bmin, &con->pos[3], ext); + dtVadd(bmax, &con->pos[3], ext); + + this->calcTileLoc(bmin, &minx, &miny); + this->calcTileLoc(bmax, &maxx, &maxy); + + + 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) + { + dtMeshTile* tile = neis[j]; + + dtPolyRef NearestPoly = findNearestPolyInTile(tile, &con->pos[3], ext, nearestPt); + + if (NearestPoly) + { + float thisDist = dtVdistSqr(nearestPt, &con->pos[3]); + + if (thisDist < NearestDist) + { + thisDist = NearestDist; + con->ToTileX = tile->header->x; + con->ToTileY = tile->header->y; + con->ToTileLayer = tile->header->layer; + } + } + } + } + } +} + +void dtNavMesh::unconnectOffMeshLink(dtOffMeshConnection* con) +{ + if (!con || con->FromTileX < 0 || con->ToTileX < 0) + return; + + dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer); + dtMeshTile* target = this->getTileAt(con->ToTileX, con->ToTileY, con->ToTileLayer); + + if (!tile || !target) return; + + const unsigned int targetNum = decodePolyIdTile(getTileRef(target)); + + for (int i = 0; i < tile->header->polyCount; ++i) + { + dtPoly* poly = &tile->polys[i]; + unsigned int j = poly->firstLink; + unsigned int pj = DT_NULL_LINK; + while (j != DT_NULL_LINK) + { + if (decodePolyIdTile(tile->links[j].ref) == targetNum && tile->links[j].OffMeshID == con->userId) + { + // Remove link. + unsigned int nj = tile->links[j].next; + if (pj == DT_NULL_LINK) + poly->firstLink = nj; + else + tile->links[pj].next = nj; + freeLink(tile, j); + j = nj; + } + else + { + // Advance + pj = j; + j = tile->links[j].next; + } + } + } + + const unsigned int sourceNum = decodePolyIdTile(getTileRef(tile)); + + for (int i = 0; i < target->header->polyCount; ++i) + { + dtPoly* poly = &target->polys[i]; + unsigned int j = poly->firstLink; + unsigned int pj = DT_NULL_LINK; + while (j != DT_NULL_LINK) + { + if (decodePolyIdTile(target->links[j].ref) == sourceNum && target->links[j].OffMeshID == con->userId) + { + // Remove link. + unsigned int nj = target->links[j].next; + if (pj == DT_NULL_LINK) + poly->firstLink = nj; + else + target->links[pj].next = nj; + freeLink(target, j); + j = nj; + } + else + { + // Advance + pj = j; + j = target->links[j].next; + } + } + } +} + void dtNavMesh::unconnectLinks(dtMeshTile* tile, dtMeshTile* target) { if (!tile || !target) return; @@ -451,76 +613,6 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side) } } -void dtNavMesh::connectDistantExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side) -{ - if (!tile) return; - - // Connect off-mesh links. - // We are interested on links which land from target tile to this tile. - const unsigned char oppositeSide = (side == -1) ? 0xff : (unsigned char)dtOppositeTile(side); - - 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 halfExtents[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad }; - - // Find polygon to connect to. - const float* p = &targetCon->pos[3]; - float nearestPt[3]; - dtPolyRef ref = findNearestPolyInTile(tile, p, halfExtents, 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 = oppositeSide; - 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 = 0xff; - link->side = (unsigned char)(side == -1 ? 0xff : side); - link->bmin = link->bmax = 0; - // Add to linked list. - link->next = landPoly->firstLink; - landPoly->firstLink = tidx; - } - } - } -} - void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side) { if (!tile) return; @@ -531,7 +623,7 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int for (int i = 0; i < target->header->offMeshConCount; ++i) { - dtOffMeshConnection* targetCon = &target->offMeshCons[i]; + dtOffMeshConnection* targetCon = target->offMeshCons[i]; if (targetCon->side != oppositeSide) continue; @@ -541,7 +633,6 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int { continue; } - const float halfExtents[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad }; @@ -631,6 +722,67 @@ void dtNavMesh::connectIntLinks(dtMeshTile* tile) } } +void dtNavMesh::baseOffMeshLinks(dtOffMeshConnection* con) +{ + if (!con) return; + + dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer); + + if (!tile) { return; } + + dtPolyRef base = getPolyRefBase(tile); + + dtPoly* poly = &tile->polys[con->poly]; + + const float halfExtents[3] = { con->rad, tile->header->walkableClimb, con->rad }; + + // Find polygon to connect to. + const float* p = &con->pos[0]; // First vertex + float nearestPt[3]; + dtPolyRef ref = findNearestPolyInTile(tile, p, halfExtents, nearestPt); + if (!ref) return; + // findNearestPoly may return too optimistic results, further check to make sure. + if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(con->rad)) + return; + // Make sure the location is on current mesh. + float* v = &tile->verts[poly->verts[0] * 3]; + dtVcopy(v, nearestPt); + + // Link off-mesh connection to target poly. + unsigned int idx = allocLink(tile); + if (idx != DT_NULL_LINK) + { + dtLink* link = &tile->links[idx]; + link->OffMeshID = -1; + link->ref = ref; + link->edge = (unsigned char)0; + link->side = 0xff; + link->bmin = link->bmax = 0; + // Add to linked list. + link->next = poly->firstLink; + poly->firstLink = idx; + } + + // Start end-point is always connect back to off-mesh connection. + 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->OffMeshID = -1; + link->ref = base | (dtPolyRef)(con->poly); + link->edge = 0xff; + link->side = 0xff; + link->bmin = link->bmax = 0; + // Add to linked list. + link->next = landPoly->firstLink; + landPoly->firstLink = tidx; + } + + con->bBased = true; +} + void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile) { if (!tile) return; @@ -640,7 +792,7 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile) // Base off-mesh connection start points. for (int i = 0; i < tile->header->offMeshConCount; ++i) { - dtOffMeshConnection* con = &tile->offMeshCons[i]; + dtOffMeshConnection* con = tile->offMeshCons[i]; dtPoly* poly = &tile->polys[con->poly]; const float halfExtents[3] = { con->rad, tile->header->walkableClimb, con->rad }; @@ -943,7 +1095,7 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) continue; // Calc polygon bounds. - const float* v = &tile->verts[p->verts[0]*3]; + const float* v = &tile->verts[p->verts[0] * 3]; dtVcopy(bmin, v); dtVcopy(bmax, v); for (int j = 1; j < p->vertCount; ++j) @@ -979,7 +1131,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, bool bMarkOffMeshDirty) + dtTileRef lastRef, dtTileRef* result) { // Make sure the data is in right format. dtMeshHeader* header = (dtMeshHeader*)data; @@ -994,11 +1146,11 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, if (m_polyBits < dtIlog2(dtNextPow2((unsigned int)header->polyCount))) return DT_FAILURE | DT_INVALID_PARAM; #endif - + // Make sure the location is free. if (getTileAt(header->x, header->y, header->layer)) return DT_FAILURE | DT_ALREADY_OCCUPIED; - + // Allocate a tile. dtMeshTile* tile = 0; if (!lastRef) @@ -1041,23 +1193,22 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, // Make sure we could allocate a tile. if (!tile) return DT_FAILURE | DT_OUT_OF_MEMORY; - + // Insert tile into the position lut. int h = computeTileHash(header->x, header->y, m_tileLutMask); tile->next = m_posLookup[h]; m_posLookup[h] = tile; - + // Patch header pointers. const int headerSize = dtAlign4(sizeof(dtMeshHeader)); - const int vertsSize = dtAlign4(sizeof(float)*3*header->vertCount); - const int polysSize = dtAlign4(sizeof(dtPoly)*header->polyCount); - const int linksSize = dtAlign4(sizeof(dtLink)*(header->maxLinkCount)); - const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*header->detailMeshCount); - const int detailVertsSize = dtAlign4(sizeof(float)*3*header->detailVertCount); - 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); + const int vertsSize = dtAlign4(sizeof(float) * 3 * header->vertCount); + const int polysSize = dtAlign4(sizeof(dtPoly) * header->polyCount); + const int linksSize = dtAlign4(sizeof(dtLink) * (header->maxLinkCount)); + const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * header->detailMeshCount); + const int detailVertsSize = dtAlign4(sizeof(float) * 3 * header->detailVertCount); + 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); unsigned char* d = data + headerSize; tile->verts = dtGetThenAdvanceBufferPointer(d, vertsSize); @@ -1067,9 +1218,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, tile->detailVerts = dtGetThenAdvanceBufferPointer(d, detailVertsSize); tile->detailTris = dtGetThenAdvanceBufferPointer(d, detailTrisSize); tile->bvTree = dtGetThenAdvanceBufferPointer(d, bvtreeSize); - tile->offMeshCons = dtGetThenAdvanceBufferPointer(d, offMeshLinksSize); - tile->receivingOffMeshCons = dtGetThenAdvanceBufferPointer(d, receivingOffMeshLinksSize); - + tile->offMeshCons = dtGetThenAdvanceBufferPointer(d, offMeshLinksSize); // If there are no items in the bvtree, reset the tree pointer. if (!bvtreeSize) @@ -1077,9 +1226,9 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, // Build links freelist tile->linksFreeList = 0; - tile->links[header->maxLinkCount-1].next = DT_NULL_LINK; - for (int i = 0; i < header->maxLinkCount-1; ++i) - tile->links[i].next = i+1; + tile->links[header->maxLinkCount - 1].next = DT_NULL_LINK; + for (int i = 0; i < header->maxLinkCount - 1; ++i) + tile->links[i].next = i + 1; // Init tile. tile->header = header; @@ -1089,25 +1238,28 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, connectIntLinks(tile); - // Base off-mesh connections to their starting polygons and connect connections inside the tile. - baseOffMeshLinks(tile); + for (int i = 0; i < tile->header->offMeshConCount; i++) + { + baseOffMeshLinks(tile->offMeshCons[i]); + } // Create connections with neighbour tiles. static const int MAX_NEIS = 32; dtMeshTile* neis[MAX_NEIS]; int nneis; - + + // Connect with layers in current tile. nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS); for (int j = 0; j < nneis; ++j) { if (neis[j] == tile) continue; - + connectExtLinks(tile, neis[j], -1); connectExtLinks(neis[j], tile, -1); } - + // Connect with neighbour tiles. for (int i = 0; i < 8; ++i) { @@ -1119,115 +1271,101 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, } } - 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) *result = getTileRef(tile); return DT_SUCCESS; } -void dtNavMesh::GlobalOffMeshLinks(dtMeshTile* target) +void dtNavMesh::GlobalOffMeshLinks(dtOffMeshConnection* con) { - if (!target) + if (!con) return; - for (int i = 0; i < target->header->offMeshConCount; ++i) + dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer); + + if (!tile) { return; } + + dtPoly* targetPoly = &tile->polys[con->poly]; + // Skip off-mesh connections which start location could not be connected at all. + if (targetPoly->firstLink == DT_NULL_LINK) + return; + + dtMeshTile* TargetTile = this->getTileAt(con->ToTileX, con->ToTileY, con->ToTileLayer); + + if (!TargetTile) { return; } + + const float ext[3] = { con->rad, tile->header->walkableClimb, con->rad }; + + // Find polygon to connect to. + const float* p = &con->pos[3]; + float nearestPt[3]; + dtPolyRef ref = findNearestPolyInTile(TargetTile, p, ext, nearestPt); + if (!ref) + return; + // findNearestPoly may return too optimistic results, further check to make sure. + if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(con->rad)) + return; + // Make sure the location is on current mesh. + float* v = &tile->verts[targetPoly->verts[1] * 3]; + dtVcopy(v, nearestPt); + + // Link off-mesh connection to target poly. + unsigned int idx = allocLink(tile); + if (idx != DT_NULL_LINK) { - dtOffMeshConnection* targetCon = &target->offMeshCons[i]; + dtLink* link = &tile->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; + link->OffMeshID = con->userId; + targetPoly->firstLink = idx; + } - 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) + // Link target poly to off-mesh connection. + if (con->bBiDir) + { + unsigned int tidx = allocLink(TargetTile); + if (tidx != DT_NULL_LINK) { - 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 unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref); + dtPoly* landPoly = &TargetTile->polys[landPolyIdx]; + dtLink* link = &TargetTile->links[tidx]; + link->ref = getPolyRefBase(tile) | (dtPolyRef)(con->poly); + link->edge = (unsigned char)0xff; + link->side = (unsigned char)(0xff); + link->bmin = link->bmax = 0; + // Add to linked list. + link->next = landPoly->firstLink; + link->OffMeshID = con->userId; + landPoly->firstLink = tidx; } } } -const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const +const dtMeshTile* dtNavMesh::getTileAtConst(const int x, const int y, const int layer) const +{ + // Find tile based on hash. + int h = computeTileHash(x, y, m_tileLutMask); + dtMeshTile* tile = m_posLookup[h]; + while (tile) + { + if (tile->header && + tile->header->x == x && + tile->header->y == y && + tile->header->layer == layer) + { + return tile; + } + tile = tile->next; + } + return 0; +} + +dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) { // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); @@ -1693,7 +1831,7 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c const unsigned int idx = ip - tile->header->offMeshBase; dtAssert(idx < (unsigned int)tile->header->offMeshConCount); - return &tile->offMeshCons[idx]; + return tile->offMeshCons[idx]; } diff --git a/main/source/detour/DetourNavMeshBuilder.cpp b/main/source/detour/DetourNavMeshBuilder.cpp index fd245c41..744d09c7 100644 --- a/main/source/detour/DetourNavMeshBuilder.cpp +++ b/main/source/detour/DetourNavMeshBuilder.cpp @@ -289,109 +289,69 @@ 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) + + if (params->NumOffMeshConnections > 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->NumOffMeshConnections; i++) { - for (int i = 0; i < params->detailVertsCount; ++i) - { - 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 float h = params->bmin[1] + iv[1] * params->ch; - hmin = dtMin(hmin, h); - hmax = dtMax(hmax, h); - } - } - hmin -= params->walkableClimb; - hmax += params->walkableClimb; - float bmin[3], bmax[3]; - dtVcopy(bmin, params->bmin); - dtVcopy(bmax, params->bmax); - bmin[1] = hmin; - bmax[1] = hmax; + dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i]; - 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); + if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; } - // Zero out off-mesh start positions which are not even potentially touching the mesh. - if (offMeshConClass[i * 2 + 0] == 0xff) + bool bOriginates = (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer); + bool bTargets = (con->ToTileX == params->tileX && con->ToTileY == params->tileY && con->ToTileLayer == params->tileLayer); + + if (bOriginates) { - if (p0[1] < bmin[1] || p0[1] > bmax[1]) - offMeshConClass[i * 2 + 0] = 0; - } - - // Cound how many links should be allocated for off-mesh connections. - if (offMeshConClass[i * 2 + 0] == 0xff) + con->state = DT_OFFMESH_DIRTY; offMeshConLinkCount++; - if (offMeshConClass[i * 2 + 1] == 0xff) - offMeshConLinkCount++; - - if (offMeshConClass[i * 2 + 0] == 0xff) - { storedOffMeshConCount++; } - else if (offMeshConClass[i * 2 + 1] == 0xff) - { - receiveOffMeshConCount++; - } + if (bTargets) + { + con->state = DT_OFFMESH_DIRTY; + offMeshConLinkCount++; + } } } - + // 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; @@ -401,8 +361,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) { @@ -420,41 +380,40 @@ 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 receiveOffMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection) * receiveOffMeshConCount); - + 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 dataSize = headerSize + vertsSize + polysSize + linksSize + - detailMeshesSize + detailVertsSize + detailTrisSize + - bvTreeSize + offMeshConsSize + receiveOffMeshConsSize; - - unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char) * dataSize, DT_ALLOC_PERM); + detailMeshesSize + detailVertsSize + detailTrisSize + + bvTreeSize + offMeshConsSize; + + 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(d, headerSize); @@ -465,10 +424,9 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, float* navDVerts = dtGetThenAdvanceBufferPointer(d, detailVertsSize); unsigned char* navDTris = dtGetThenAdvanceBufferPointer(d, detailTrisSize); dtBVNode* navBvtree = dtGetThenAdvanceBufferPointer(d, bvTreeSize); - dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer(d, offMeshConsSize); - dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer(d, receiveOffMeshConsSize); - - + dtOffMeshConnection** offMeshCons = dtGetThenAdvanceBufferPointer(d, offMeshConsSize); + + // Store header header->magic = DT_NAVMESH_MAGIC; header->version = DT_NAVMESH_VERSION; @@ -489,38 +447,41 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, header->walkableHeight = params->walkableHeight; header->walkableRadius = params->walkableRadius; header->walkableClimb = params->walkableClimb; - header->offMeshConCount = storedOffMeshConCount; - header->receivingOffMeshConCount = receiveOffMeshConCount; - header->bvNodeCount = params->buildBvTree ? params->polyCount * 2 : 0; - + header->offMeshConCount = offMeshConLinkCount; + 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; } // Off-mesh link vertices. int n = 0; - for (int i = 0; i < params->offMeshConCount; ++i) + for (int i = 0; i < params->NumOffMeshConnections; i++) { + dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i]; + + if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; } + // Only store connections which start from this tile. - if (offMeshConClass[i * 2 + 0] == 0xff) + if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer) { - const float* linkv = ¶ms->offMeshConVerts[i * 2 * 3]; - float* v = &navVerts[(offMeshVertsBase + n * 2) * 3]; + const float* linkv = &con->pos[0]; + 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; @@ -535,10 +496,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- @@ -553,26 +514,30 @@ 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) + for (int i = 0; i < params->NumOffMeshConnections; i++) { + dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i]; + + if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; } + // Only store connections which start from this tile. - if (offMeshConClass[i * 2 + 0] == 0xff) + if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer) { - 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->flags = params->offMeshConFlags[i]; - p->setArea(params->offMeshConAreas[i]); + p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0); + p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1); + p->flags = con->flags; + p->setArea(con->area); p->setType(DT_POLYTYPE_OFFMESH_CONNECTION); n++; } @@ -587,22 +552,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 { @@ -615,18 +580,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++; } } @@ -635,63 +600,34 @@ 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) + for (int i = 0; i < params->NumOffMeshConnections; i++) { + dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i]; + + if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; } + // Only store connections which start from this tile. - if (offMeshConClass[i * 2 + 0] == 0xff) + if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer) { - dtOffMeshConnection* con = &offMeshCons[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 + 1]; - if (params->offMeshConUserID) - con->userId = params->offMeshConUserID[i]; + + offMeshCons[n] = con; + 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); - } - + header->offMeshConCount = n; + dtFree(offMeshConClass); - + *outData = data; *outDataSize = dataSize; - + return true; } @@ -724,7 +660,6 @@ 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); @@ -767,7 +702,6 @@ 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(d, vertsSize); @@ -780,7 +714,6 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/) //unsigned char* detailTris = dtGetThenAdvanceBufferPointer(d, detailTrisSize); dtBVNode* bvTree = dtGetThenAdvanceBufferPointer(d, bvtreeSize); dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer(d, offMeshLinksSize); - dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer(d, receiveOffMeshLinksSize); // Vertices for (int i = 0; i < header->vertCount*3; ++i) @@ -838,16 +771,6 @@ 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; } diff --git a/main/source/detour/DetourNavMeshQuery.cpp b/main/source/detour/DetourNavMeshQuery.cpp index 08332792..30a77b6b 100644 --- a/main/source/detour/DetourNavMeshQuery.cpp +++ b/main/source/detour/DetourNavMeshQuery.cpp @@ -347,7 +347,7 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircleIgnoreReachability(dtPolyRef int thisTileXIndex = StartTileX + tileX; int thisTileYIndex = StartTileY + tileY; - const dtMeshTile* t = m_nav->getTileAt(thisTileXIndex, thisTileYIndex, layer); + const dtMeshTile* t = m_nav->getTileAtConst(thisTileXIndex, thisTileYIndex, layer); if (!t || !t->header) continue; diff --git a/main/source/detour/DetourTileCache.cpp b/main/source/detour/DetourTileCache.cpp index 0f1d5a5f..ba74b935 100644 --- a/main/source/detour/DetourTileCache.cpp +++ b/main/source/detour/DetourTileCache.cpp @@ -74,10 +74,12 @@ dtTileCache::dtTileCache() : m_obstacles(0), m_nextFreeObstacle(0), m_nreqs(0), + m_nOffMeshReqs(0), m_nupdate(0) { memset(&m_params, 0, sizeof(m_params)); memset(m_reqs, 0, sizeof(ObstacleRequest) * MAX_REQUESTS); + memset(m_OffMeshReqs, 0, sizeof(OffMeshRequest) * MAX_REQUESTS); } dtTileCache::~dtTileCache() @@ -92,11 +94,14 @@ dtTileCache::~dtTileCache() } dtFree(m_obstacles); m_obstacles = 0; + dtFree(m_offMeshConnections); + m_offMeshConnections = 0; dtFree(m_posLookup); m_posLookup = 0; dtFree(m_tiles); m_tiles = 0; m_nreqs = 0; + m_nOffMeshReqs = 0; m_nupdate = 0; } @@ -138,6 +143,19 @@ dtStatus dtTileCache::init(const dtTileCacheParams* params, m_obstacles[i].next = m_nextFreeObstacle; m_nextFreeObstacle = &m_obstacles[i]; } + + // Alloc space for off-mesh connections. + m_offMeshConnections = (dtOffMeshConnection*)dtAlloc(sizeof(dtOffMeshConnection) * m_params.maxOffMeshConnections, DT_ALLOC_PERM); + if (!m_offMeshConnections) + return DT_FAILURE | DT_OUT_OF_MEMORY; + memset(m_offMeshConnections, 0, sizeof(dtOffMeshConnection) * m_params.maxOffMeshConnections); + m_nextFreeOffMeshConnection = 0; + for (int i = m_params.maxOffMeshConnections - 1; i >= 0; --i) + { + m_offMeshConnections[i].salt = 1; + m_offMeshConnections[i].next = m_nextFreeOffMeshConnection; + m_nextFreeOffMeshConnection = &m_offMeshConnections[i]; + } // Init tiles m_tileLutSize = dtNextPow2(m_params.maxTiles/4); @@ -225,6 +243,13 @@ dtObstacleRef dtTileCache::getObstacleRef(const dtTileCacheObstacle* ob) const return encodeObstacleId(ob->salt, idx); } +dtOffMeshConnectionRef dtTileCache::getOffMeshRef(const dtOffMeshConnection* con) const +{ + if (!con) return 0; + const unsigned int idx = (unsigned int)(con - m_offMeshConnections); + return encodeObstacleId(con->salt, idx); +} + const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref) { if (!ref) @@ -239,6 +264,20 @@ const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref) return ob; } +dtOffMeshConnection* dtTileCache::getOffMeshConnectionByRef(dtOffMeshConnectionRef ref) +{ + if (!ref) + return 0; + unsigned int idx = decodeOffMeshIdCon(ref); + if ((int)idx >= m_params.maxOffMeshConnections) + return 0; + dtOffMeshConnection* con = &m_offMeshConnections[idx]; + unsigned int salt = decodeOffMeshIdSalt(ref); + if (con->salt != salt) + return 0; + return con; +} + dtStatus dtTileCache::addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result) { // Make sure the data is in right format. @@ -350,6 +389,42 @@ dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data, return DT_SUCCESS; } +dtStatus dtTileCache::addOffMeshConnection(const float* spos, const float* epos, const float radius, const unsigned char area, const unsigned short flags, const bool bBiDirectional, dtOffMeshConnectionRef* result) +{ + if (m_nOffMeshReqs >= MAX_REQUESTS) + return DT_FAILURE | DT_BUFFER_TOO_SMALL; + + dtOffMeshConnection* con = 0; + if (m_nextFreeOffMeshConnection) + { + con = m_nextFreeOffMeshConnection; + m_nextFreeOffMeshConnection = con->next; + con->next = 0; + } + if (!con) + return DT_FAILURE | DT_OUT_OF_MEMORY; + + unsigned short salt = con->salt; + memset(con, 0, sizeof(dtOffMeshConnection)); + con->salt = salt; + con->state = DT_OFFMESH_NEW; + dtVcopy(&con->pos[0], spos); + dtVcopy(&con->pos[3], epos); + con->rad = radius; + con->area = area; + con->flags = flags; + con->bBiDir = bBiDirectional; + + OffMeshRequest* req = &m_OffMeshReqs[m_nOffMeshReqs++]; + memset(req, 0, sizeof(OffMeshRequest)); + req->action = REQUEST_OFFMESH_ADD; + req->ref = getOffMeshRef(con); + + if (result) + *result = req->ref; + + return DT_SUCCESS; +} dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const float height, const int area, dtObstacleRef* result) { @@ -387,7 +462,7 @@ dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const fl return DT_SUCCESS; } -dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const int area, dtObstacleRef* result) +dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result) { if (m_nreqs >= MAX_REQUESTS) return DT_FAILURE | DT_BUFFER_TOO_SMALL; @@ -409,7 +484,6 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const ob->type = DT_OBSTACLE_BOX; dtVcopy(ob->box.bmin, bmin); dtVcopy(ob->box.bmax, bmax); - ob->box.area = area; ObstacleRequest* req = &m_reqs[m_nreqs++]; memset(req, 0, sizeof(ObstacleRequest)); @@ -422,7 +496,7 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const return DT_SUCCESS; } -dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, const int area, dtObstacleRef* result) +dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result) { if (m_nreqs >= MAX_REQUESTS) return DT_FAILURE | DT_BUFFER_TOO_SMALL; @@ -449,7 +523,6 @@ dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExten float sinhalf = sinf(-0.5f*yRadians); ob->orientedBox.rotAux[0] = coshalf*sinhalf; ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f; - ob->orientedBox.area = area; ObstacleRequest* req = &m_reqs[m_nreqs++]; memset(req, 0, sizeof(ObstacleRequest)); @@ -477,6 +550,22 @@ dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref) return DT_SUCCESS; } +dtStatus dtTileCache::removeOffMeshConnection(const dtOffMeshConnectionRef ref) +{ + if (!ref) + return DT_SUCCESS; + + if (m_nOffMeshReqs >= MAX_REQUESTS) + return DT_FAILURE | DT_BUFFER_TOO_SMALL; + + OffMeshRequest* req = &m_OffMeshReqs[m_nOffMeshReqs++]; + memset(req, 0, sizeof(OffMeshRequest)); + req->action = REQUEST_OFFMESH_REMOVE; + req->ref = ref; + + return DT_SUCCESS; +} + dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax, dtCompressedTileRef* results, int* resultCount, const int maxResults) const { @@ -519,7 +608,7 @@ dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax, } dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, - bool* upToDate) + bool* upToDate) { if (m_nupdate == 0) { @@ -527,7 +616,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, for (int i = 0; i < m_nreqs; ++i) { ObstacleRequest* req = &m_reqs[i]; - + unsigned int idx = decodeObstacleIdObstacle(req->ref); if ((int)idx >= m_params.maxObstacles) continue; @@ -535,7 +624,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, unsigned int salt = decodeObstacleIdSalt(req->ref); if (ob->salt != salt) continue; - + if (req->action == REQUEST_ADD) { // Find touched tiles. @@ -574,20 +663,104 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, } } } - + m_nreqs = 0; + + for (int i = 0; i < m_nOffMeshReqs; ++i) + { + OffMeshRequest* req = &m_OffMeshReqs[i]; + + unsigned int idx = decodeOffMeshIdCon(req->ref); + if ((int)idx >= m_params.maxOffMeshConnections) + continue; + dtOffMeshConnection* con = &m_offMeshConnections[idx]; + unsigned int salt = decodeOffMeshIdSalt(req->ref); + if (con->salt != salt) + continue; + + if (req->action == REQUEST_OFFMESH_ADD) + { + con->state = DT_OFFMESH_DIRTY; + + // Find touched tiles. + float bmin[3], bmax[3]; + float ext[3] = { con->rad, 18.0f, con->rad }; + + dtVsub(bmin, &con->pos[0], ext); + dtVadd(bmax, &con->pos[0], ext); + + int ntouched = 0; + dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES]; + dtCompressedTileRef StartTileRef = 0; + dtCompressedTileRef EndTileRef = 0; + + queryTiles(bmin, bmax, touched, &ntouched, DT_MAX_TOUCHED_TILES); + + if (ntouched > 0) + { + StartTileRef = touched[0]; + } + + dtVsub(bmin, &con->pos[3], ext); + dtVadd(bmax, &con->pos[3], ext); + + queryTiles(bmin, bmax, touched, &ntouched, DT_MAX_TOUCHED_TILES); + + if (ntouched > 0) + { + EndTileRef = touched[0]; + } + + if (!StartTileRef || !EndTileRef) { continue; } + + const dtCompressedTile* StartTile = getTileByRef(StartTileRef); + const dtCompressedTile* EndTile = getTileByRef(EndTileRef); + + con->FromTileX = StartTile->header->tx; + con->FromTileY = StartTile->header->ty; + con->FromTileLayer = StartTile->header->tlayer; + + con->ToTileX = EndTile->header->tx; + con->ToTileY = EndTile->header->ty; + con->ToTileLayer = EndTile->header->tlayer; + + if (m_nupdate < MAX_UPDATE) + { + if (!contains(m_update, m_nupdate, StartTileRef)) + m_update[m_nupdate++] = StartTileRef; + } + } + else if (req->action == REQUEST_OFFMESH_REMOVE) + { + // Prepare to remove obstacle. + con->state = DT_OFFMESH_REMOVING; + // Add tiles to update list. + + navmesh->unconnectOffMeshLink(con); + + if (m_nupdate < MAX_UPDATE) + { + dtCompressedTile* Tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer); + dtCompressedTileRef TileRef = getTileRef(Tile); + + if (!contains(m_update, m_nupdate, TileRef)) + m_update[m_nupdate++] = TileRef; + } + } + } + + m_nOffMeshReqs = 0; } - + dtStatus status = DT_SUCCESS; // Process updates if (m_nupdate) { - // Build mesh const dtCompressedTileRef ref = m_update[0]; - status = buildNavMeshTile(ref, navmesh, true); + status = buildNavMeshTile(ref, navmesh); m_nupdate--; if (m_nupdate > 0) - memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef)); + memmove(m_update, m_update + 1, m_nupdate * sizeof(dtCompressedTileRef)); // Update obstacle states. for (int i = 0; i < m_params.maxObstacles; ++i) @@ -600,12 +773,12 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, { if (ob->pending[j] == ref) { - ob->pending[j] = ob->pending[(int)ob->npending-1]; + ob->pending[j] = ob->pending[(int)ob->npending - 1]; ob->npending--; break; } } - + // If all pending tiles processed, change state. if (ob->npending == 0) { @@ -617,7 +790,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, { ob->state = DT_OBSTACLE_EMPTY; // Update salt, salt should never be zero. - ob->salt = (ob->salt+1) & ((1<<16)-1); + ob->salt = (ob->salt + 1) & ((1 << 16) - 1); if (ob->salt == 0) ob->salt++; // Return obstacle to free list. @@ -627,74 +800,49 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, } } } + } - if (navmesh->GetNumPendingOffMeshConnections() > 0) + if (m_nupdate == 0) { - - for (int i = 0; i < navmesh->GetNumPendingOffMeshConnections(); i++) + for (int i = 0; i < m_params.maxOffMeshConnections; ++i) { - int NumTiles = 0; + dtOffMeshConnection* con = &m_offMeshConnections[i]; - 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++) + if (con->state == DT_OFFMESH_DIRTY) { - const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]); - - buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false); + navmesh->unconnectOffMeshLink(con); + navmesh->GlobalOffMeshLinks(con); + con->state = DT_OFFMESH_CLEAN; } - queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES); - - for (int i = 0; i < NumTiles; i++) + if (con->state == DT_OFFMESH_REMOVING) { - const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]); - - buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false); + con->state = DT_OFFMESH_EMPTY; + con->salt = (con->salt + 1) & ((1 << 16) - 1); + if (con->salt == 0) + con->salt++; + con->next = m_nextFreeOffMeshConnection; + m_nextFreeOffMeshConnection = con; } - } - - navmesh->ClearPendingOffMeshConnections(); } if (upToDate) - *upToDate = m_nupdate == 0 && m_nreqs == 0; + *upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0; return status; } - -dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh, bool bMarkOffMeshDirty) +dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh) { const int MAX_TILES = 32; dtCompressedTileRef tiles[MAX_TILES]; const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES); - + for (int i = 0; i < ntiles; ++i) { - dtStatus status = buildNavMeshTile(tiles[i], navmesh, bMarkOffMeshDirty); + dtStatus status = buildNavMeshTile(tiles[i], navmesh); if (dtStatusFailed(status)) return status; } @@ -702,7 +850,7 @@ dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* return DT_SUCCESS; } -dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh, bool bMarkOffMeshDirty) +dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh) { dtAssert(m_talloc); dtAssert(m_tcomp); @@ -720,7 +868,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* NavMeshTileBuildContext bc(m_talloc); const int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch); dtStatus status; - + // Decompress tile layer data. status = dtDecompressTileCacheLayer(m_talloc, m_tcomp, tile->data, tile->dataSize, &bc.layer); if (dtStatusFailed(status)) @@ -805,6 +953,9 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* { m_tmproc->process(¶ms, bc.lmesh->areas, bc.lmesh->flags); } + + params.GlobalOffMeshConnections = m_offMeshConnections; + params.NumOffMeshConnections = getOffMeshCount(); unsigned char* navData = 0; int navDataSize = 0; @@ -817,8 +968,9 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* // Add new tile, or leave the location empty. if (navData) { - // Let the navmesh own the data. - status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0, bMarkOffMeshDirty); + status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0); + + if (dtStatusFailed(status)) { dtFree(navData); diff --git a/main/source/detour/Include/DetourNavMesh.h b/main/source/detour/Include/DetourNavMesh.h index 0aa133b6..46dfc24a 100644 --- a/main/source/detour/Include/DetourNavMesh.h +++ b/main/source/detour/Include/DetourNavMesh.h @@ -149,6 +149,14 @@ enum dtPolyTypes DT_POLYTYPE_OFFMESH_CONNECTION = 1, }; +enum OffMeshState +{ + DT_OFFMESH_EMPTY, + DT_OFFMESH_NEW, + DT_OFFMESH_DIRTY, + DT_OFFMESH_CLEAN, + DT_OFFMESH_REMOVING, +}; /// Defines a polygon within a dtMeshTile object. /// @ingroup detour @@ -183,6 +191,8 @@ struct dtPoly /// Gets the user defined area id. inline unsigned char getArea() const { return areaAndtype & 0x3f; } + inline unsigned short getFlags() const { return flags; } + /// Gets the polygon type. (See: #dtPolyTypes) inline unsigned char getType() const { return areaAndtype >> 6; } }; @@ -207,6 +217,7 @@ struct dtLink unsigned char side; ///< If a boundary link, defines on which side the link is. unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area. unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area. + int OffMeshID = -1; ///< If an off-mesh connection, this will be the UserID of the connection that made this link }; /// Bounding volume node. @@ -224,24 +235,45 @@ struct dtBVNode struct dtOffMeshConnection { /// The endpoints of the connection. [(ax, ay, az, bx, by, bz)] - float pos[6]; + float pos[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; /// The radius of the endpoints. [Limit: >= 0] - float rad; + float rad = 0.0f; /// The polygon reference of the connection within the tile. - unsigned short poly; + unsigned short poly = 0; /// Link flags. /// @note These are not the connection's user defined flags. Those are assigned via the /// connection's dtPoly definition. These are link flags used for internal purposes. - unsigned char flags; + unsigned short flags = 0; + unsigned char area = 0; /// End point side. - unsigned char side; + unsigned char side = 0; + + bool bBiDir = false; /// The id of the offmesh connection. (User assigned when the navigation mesh is built.) - unsigned int userId; + unsigned int userId = 0; + + int FromTileX = -1; + int FromTileY = -1; + int FromTileLayer = -1; + + int ToTileX = -1; + int ToTileY = -1; + int ToTileLayer = -1; + + bool bPendingDelete = false; // This off-mesh needs to be removed completely + bool bDirty = false; // This off-mesh connection has had its from or to tile rebuilt recently so the links need to be re-established + bool bBased = false; // This off-mesh connection has had its links based in the source tile + + dtOffMeshConnection* next = nullptr; + OffMeshState state = DT_OFFMESH_EMPTY; + + unsigned short salt; + }; /// Provides high level information related to a dtMeshTile object. @@ -265,7 +297,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,9 +333,8 @@ struct dtMeshTile /// (Will be null if bounding volumes are disabled.) dtBVNode* bvTree; - dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount] - dtOffMeshConnection* receivingOffMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount] - + dtOffMeshConnection** offMeshCons; ///< 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. int flags; ///< Tile flags. (See: #dtTileFlags) @@ -369,7 +400,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, bool bMarkOffMeshDirty); + dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result); /// Removes the specified tile from the navigation mesh. /// @param[in] ref The reference of the tile to remove. @@ -378,6 +409,13 @@ public: /// @return The status flags for the operation. dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize); + void GlobalOffMeshLinks(dtOffMeshConnection* con); + + void baseOffMeshLinks(dtOffMeshConnection* Connection); + + void LinkOffMeshConnectionToTiles(dtOffMeshConnection* con); + void unconnectOffMeshLink(dtOffMeshConnection* con); + /// @} /// @{ @@ -394,7 +432,9 @@ public: /// @param[in] y The tile's y-location. (x, y, layer) /// @param[in] layer The tile's layer. (x, y, layer) /// @return The tile, or null if the tile does not exist. - const dtMeshTile* getTileAt(const int x, const int y, const int layer) const; + dtMeshTile* getTileAt(const int x, const int y, const int layer); + + const dtMeshTile* getTileAtConst(const int x, const int y, const int layer) const; /// Gets all tiles at the specified grid location. (All layers.) /// @param[in] x The tile's x-location. (x, y) @@ -467,10 +507,6 @@ 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]; } /// @} @@ -520,8 +556,6 @@ 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); /// @} @@ -642,11 +676,12 @@ private: /// Builds internal polygons links for a tile. void baseOffMeshLinks(dtMeshTile* tile); + + /// Builds external polygon links for a tile. void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side); /// Builds external polygon links for a tile. void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side); - void connectDistantExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side); /// Removes external links at specified side. void unconnectLinks(dtMeshTile* tile, dtMeshTile* target); @@ -670,10 +705,7 @@ private: int m_maxTiles; ///< Max number of tiles. 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. diff --git a/main/source/detour/Include/DetourNavMeshBuilder.h b/main/source/detour/Include/DetourNavMeshBuilder.h index 57cb1586..9cee9a6a 100644 --- a/main/source/detour/Include/DetourNavMeshBuilder.h +++ b/main/source/detour/Include/DetourNavMeshBuilder.h @@ -20,6 +20,9 @@ #define DETOURNAVMESHBUILDER_H #include "DetourAlloc.h" +#include "DetourNavMesh.h" + +#include /// Represents the source data used to build an navigation mesh tile. /// @ingroup detour @@ -102,6 +105,9 @@ struct dtNavMeshCreateParams /// @note The BVTree is not normally needed for layered navigation meshes. bool buildBvTree; + dtOffMeshConnection* GlobalOffMeshConnections; + int NumOffMeshConnections; + }; /// Builds navigation mesh tile data from the provided tile creation data. diff --git a/main/source/detour/Include/DetourTileCache.h b/main/source/detour/Include/DetourTileCache.h index 2a218fcb..83745e1d 100644 --- a/main/source/detour/Include/DetourTileCache.h +++ b/main/source/detour/Include/DetourTileCache.h @@ -2,10 +2,12 @@ #define DETOURTILECACHE_H #include "DetourStatus.h" +#include "DetourNavMesh.h" - +#include typedef unsigned int dtObstacleRef; +typedef unsigned int dtOffMeshConnectionRef; typedef unsigned int dtCompressedTileRef; @@ -96,6 +98,7 @@ struct dtTileCacheParams float maxSimplificationError; int maxTiles; int maxObstacles; + int maxOffMeshConnections; }; struct dtTileCacheMeshProcess @@ -104,6 +107,8 @@ struct dtTileCacheMeshProcess virtual void process(struct dtNavMeshCreateParams* params, unsigned char* polyAreas, unsigned short* polyFlags) = 0; + + }; @@ -122,12 +127,16 @@ public: inline int getTileCount() const { return m_params.maxTiles; } inline const dtCompressedTile* getTile(const int i) const { return &m_tiles[i]; } + inline int getOffMeshCount() const { return m_params.maxOffMeshConnections; } inline int getObstacleCount() const { return m_params.maxObstacles; } inline const dtTileCacheObstacle* getObstacle(const int i) const { return &m_obstacles[i]; } + inline const dtOffMeshConnection* getOffMeshConnection(const int i) const { return &m_offMeshConnections[i]; } const dtTileCacheObstacle* getObstacleByRef(dtObstacleRef ref); + dtOffMeshConnection* getOffMeshConnectionByRef(dtOffMeshConnectionRef ref); dtObstacleRef getObstacleRef(const dtTileCacheObstacle* obmin) const; + dtOffMeshConnectionRef getOffMeshRef(const dtOffMeshConnection* con) const; dtStatus init(const dtTileCacheParams* params, struct dtTileCacheAlloc* talloc, @@ -147,13 +156,16 @@ public: // Cylinder obstacle. dtStatus addObstacle(const float* pos, const float radius, const float height, const int area, dtObstacleRef* result); + dtStatus addOffMeshConnection(const float* spos, const float* epos, const float radius, const unsigned char area, const unsigned short flags, const bool bBiDirectional, dtOffMeshConnectionRef* result); + // Aabb obstacle. - dtStatus addBoxObstacle(const float* bmin, const float* bmax, const int area, dtObstacleRef* result); + dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result); // Box obstacle: can be rotated in Y. - dtStatus addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, const int area, dtObstacleRef* result); + dtStatus addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result); dtStatus removeObstacle(const dtObstacleRef ref); + dtStatus removeOffMeshConnection(const dtOffMeshConnectionRef ref); dtStatus queryTiles(const float* bmin, const float* bmax, dtCompressedTileRef* results, int* resultCount, const int maxResults) const; @@ -166,9 +178,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, bool bMarkOffMeshDirty); - - dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh, bool bMarkOffMeshDirty); + dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh); + + dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh); void calcTightTileBounds(const struct dtTileCacheLayerHeader* header, float* bmin, float* bmax) const; @@ -200,6 +212,12 @@ public: { return ((dtObstacleRef)salt << 16) | (dtObstacleRef)it; } + + /// Encodes an obstacle id. + inline dtOffMeshConnectionRef encodeOffMeshId(unsigned int salt, unsigned int it) const + { + return ((dtOffMeshConnectionRef)salt << 16) | (dtOffMeshConnectionRef)it; + } /// Decodes an obstacle salt. inline unsigned int decodeObstacleIdSalt(dtObstacleRef ref) const @@ -207,6 +225,12 @@ public: const dtObstacleRef saltMask = ((dtObstacleRef)1<<16)-1; return (unsigned int)((ref >> 16) & saltMask); } + + inline unsigned int decodeOffMeshIdSalt(dtOffMeshConnectionRef ref) const + { + const dtOffMeshConnectionRef saltMask = ((dtOffMeshConnectionRef)1 << 16) - 1; + return (unsigned int)((ref >> 16) & saltMask); + } /// Decodes an obstacle id. inline unsigned int decodeObstacleIdObstacle(dtObstacleRef ref) const @@ -214,6 +238,12 @@ public: const dtObstacleRef tileMask = ((dtObstacleRef)1<<16)-1; return (unsigned int)(ref & tileMask); } + + inline unsigned int decodeOffMeshIdCon(dtOffMeshConnectionRef ref) const + { + const dtOffMeshConnectionRef tileMask = ((dtOffMeshConnectionRef)1 << 16) - 1; + return (unsigned int)(ref & tileMask); + } private: @@ -226,12 +256,25 @@ private: REQUEST_ADD, REQUEST_REMOVE, }; + + enum OffMeshRequestAction + { + REQUEST_OFFMESH_ADD, + REQUEST_OFFMESH_REFRESH, + REQUEST_OFFMESH_REMOVE + }; struct ObstacleRequest { int action; dtObstacleRef ref; }; + + struct OffMeshRequest + { + int action; + dtOffMeshConnectionRef ref; + }; int m_tileLutSize; ///< Tile hash lookup size (must be pot). int m_tileLutMask; ///< Tile hash lookup mask. @@ -251,10 +294,16 @@ private: dtTileCacheObstacle* m_obstacles; dtTileCacheObstacle* m_nextFreeObstacle; + + dtOffMeshConnection* m_offMeshConnections; + dtOffMeshConnection* m_nextFreeOffMeshConnection; - static const int MAX_REQUESTS = 64; + static const int MAX_REQUESTS = 256; ObstacleRequest m_reqs[MAX_REQUESTS]; int m_nreqs; + + OffMeshRequest m_OffMeshReqs[MAX_REQUESTS]; + int m_nOffMeshReqs; static const int MAX_UPDATE = 64; dtCompressedTileRef m_update[MAX_UPDATE]; diff --git a/main/source/detour/Include/DetourTileCacheBuilder.h b/main/source/detour/Include/DetourTileCacheBuilder.h index da03a6df..547cc1b2 100644 --- a/main/source/detour/Include/DetourTileCacheBuilder.h +++ b/main/source/detour/Include/DetourTileCacheBuilder.h @@ -35,6 +35,7 @@ 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; struct dtTileCacheLayerHeader diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index 40d337b8..33f679df 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -171,7 +171,7 @@ typedef enum _STRUCTUREPURPOSE typedef struct _OFF_MESH_CONN { - int MeshConnectionIndex = -1; + unsigned int ConnectionRefs[2]; unsigned short ConnectionFlags = 0; Vector FromLocation = g_vecZero; Vector ToLocation = g_vecZero; diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index c3a735ef..86d358e1 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -72,23 +72,7 @@ struct TileCacheSetExportHeader int NumOffMeshCons; - int OffMeshConVertsOffset; - int OffMeshConVertsLength; - - int OffMeshConRadsOffset; - int OffMeshConRadsLength; - - int OffMeshConDirsOffset; - int OffMeshConDirsLength; - - int OffMeshConAreasOffset; - int OffMeshConAreasLength; - - int OffMeshConFlagsOffset; - int OffMeshConFlagsLength; - - int OffMeshConUserIDsOffset; - int OffMeshConUserIDsLength; + int OffMeshConsOffset; }; struct TileCacheTileHeader @@ -187,21 +171,6 @@ struct LinearAllocator : public dtTileCacheAlloc struct MeshProcess : public dtTileCacheMeshProcess { - int NumOffMeshConns = 0; - float OffMeshVerts[MAX_OFFMESH_CONNS * 6]; - float OffMeshRads[MAX_OFFMESH_CONNS]; - unsigned char OffMeshDirs[MAX_OFFMESH_CONNS]; - unsigned char OffMeshAreas[MAX_OFFMESH_CONNS]; - unsigned short OffMeshFlags[MAX_OFFMESH_CONNS]; - unsigned int OffMeshIDs[MAX_OFFMESH_CONNS]; - - bool bNavDataDirty = false; - - OffMeshConnectionDef ConnectionDefinitions[MAX_OFFMESH_CONNS]; - - vector OffMeshConnections; - - unsigned int NextUserID = 0; inline MeshProcess() {} @@ -211,197 +180,6 @@ struct MeshProcess : public dtTileCacheMeshProcess } - void AddOffMeshConnectionDef(Vector Start, Vector End, unsigned char area, unsigned short flag, bool bBiDirectional, AvHAIOffMeshConnection* ConnectionRef) - { - OffMeshConnectionDef NewDefinition; - NewDefinition.Area = area; - NewDefinition.bBiDir = bBiDirectional; - NewDefinition.spos[0] = Start.x; - NewDefinition.spos[1] = Start.z; - NewDefinition.spos[2] = -Start.y; - NewDefinition.epos[0] = End.x; - NewDefinition.epos[1] = End.z; - NewDefinition.epos[2] = -End.y; - NewDefinition.Flag = flag; - NewDefinition.Rad = 18.0f; - NewDefinition.UserID = NextUserID; - NewDefinition.bDirty = true; - - if (ConnectionRef) - { - ConnectionRef->MeshConnectionIndex = NextUserID; - } - - NextUserID++; - - OffMeshConnections.push_back(NewDefinition); - - bNavDataDirty = true; - }; - - void RemoveOffMeshConnectionDef(int UserID) - { - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - if (it->UserID == UserID) - { - it->bDirty = true; - it->bPendingDelete = true; - } - } - - bNavDataDirty = true; - } - - void PurgeDeletedConnections() - { - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end();) - { - if (it->bPendingDelete) - { - it = OffMeshConnections.erase(it); - } - else - { - it++; - } - } - } - - void UpdateOffMeshData() - { - int CurrIndex = 0; - int VertIndex = 0; - - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - if (!it->bPendingDelete) - { - OffMeshVerts[VertIndex++] = it->spos[0]; - OffMeshVerts[VertIndex++] = it->spos[1]; - OffMeshVerts[VertIndex++] = it->spos[2]; - OffMeshVerts[VertIndex++] = it->epos[0]; - OffMeshVerts[VertIndex++] = it->epos[1]; - OffMeshVerts[VertIndex++] = it->epos[2]; - - OffMeshRads[CurrIndex] = it->Rad; - OffMeshDirs[CurrIndex] = it->bBiDir; - OffMeshAreas[CurrIndex] = it->Area; - OffMeshFlags[CurrIndex] = it->Flag; - OffMeshIDs[CurrIndex] = it->UserID; - - CurrIndex++; - } - } - - NumOffMeshConns = CurrIndex; - - bNavDataDirty = false; - } - - void PopulateOffMeshConnectionVector() - { - OffMeshConnections.clear(); - - for (int i = 0; i < NumOffMeshConns; i++) - { - float* v = &OffMeshVerts[i*3*2]; - Vector StartPos = Vector(v[0], -v[2], v[1]); - Vector EndPos = Vector(v[3], -v[5], v[4]); - AddOffMeshConnectionDef(StartPos, EndPos, OffMeshAreas[i], OffMeshFlags[i], OffMeshDirs[i], nullptr); - } - - bNavDataDirty = false; - } - - void GetOffMeshConnectionPoints(int UserID, Vector& OutStartLoc, Vector& OutEndLoc) - { - OutStartLoc = ZERO_VECTOR; - OutEndLoc = ZERO_VECTOR; - - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - if (it->UserID == UserID) - { - OutStartLoc.x = it->spos[0]; - OutStartLoc.y = -it->spos[2]; - OutStartLoc.z = it->spos[1]; - - OutEndLoc.x = it->epos[0]; - OutEndLoc.y = -it->epos[2]; - OutEndLoc.z = it->epos[1]; - - return; - } - } - } - - vector GetOffMeshConnections() - { - return OffMeshConnections; - } - - void MarkOffMeshConnectionsClean() - { - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - it->bDirty = false; - } - } - - vector GetDirtyOffMeshConnections() - { - vector Result; - - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - if (it->bDirty || it->bPendingDelete) - { - Result.push_back(&(*it)); - } - } - - return Result; - } - - void DrawAllConnections(float DrawTime) - { - Vector StartLine = ZERO_VECTOR; - Vector EndLine = ZERO_VECTOR; - - for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++) - { - Vector StartLine = Vector(it->spos[0], -it->spos[2], it->spos[1]); - Vector EndLine = Vector(it->epos[0], -it->epos[2], it->epos[1]); - - switch (it->Flag) - { - 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_TEAM1PHASEGATE: - case SAMPLE_POLYFLAGS_TEAM2PHASEGATE: - 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) { @@ -455,32 +233,48 @@ struct MeshProcess : public dtTileCacheMeshProcess } } - if (bNavDataDirty) - { - UpdateOffMeshData(); - } - - params->offMeshConAreas = OffMeshAreas; - params->offMeshConCount = NumOffMeshConns; - params->offMeshConDir = OffMeshDirs; - params->offMeshConFlags = OffMeshFlags; - params->offMeshConRad = OffMeshRads; - params->offMeshConUserID = OffMeshIDs; - params->offMeshConVerts = OffMeshVerts; - } }; void AIDEBUG_DrawOffMeshConnections(float DrawTime) { - if (NavMeshes[0].tileCache) + if (NavMeshes[REGULAR_NAV_MESH].tileCache) { - MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess(); - - if (m_tmproc) + for (int i = 0; i < NavMeshes[REGULAR_NAV_MESH].tileCache->getOffMeshCount(); i++) { - m_tmproc->DrawAllConnections(DrawTime); + const dtOffMeshConnection* con = NavMeshes[REGULAR_NAV_MESH].tileCache->getOffMeshConnection(i); + + if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; } + + Vector StartLine = Vector(con->pos[0], -con->pos[2], con->pos[1]); + Vector EndLine = Vector(con->pos[3], -con->pos[5], con->pos[4]); + switch (con->flags) + { + 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_TEAM1PHASEGATE: + case SAMPLE_POLYFLAGS_TEAM2PHASEGATE: + UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 128, 128); + break; + default: + UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 255); + break; + } } + } } @@ -494,40 +288,7 @@ void UTIL_UpdateTileCache() { NavMeshes[i].tileCache->update(0.0f, NavMeshes[i].navMesh, &bUpToDate); } - } - - if (bUpToDate) - { - if (NavMeshes[0].tileCache) - { - MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess(); - - if (m_tmproc) - { - vector DirtyOffMeshConnections = m_tmproc->GetDirtyOffMeshConnections(); - - Vector StartPos, EndPos; - - if (DirtyOffMeshConnections.size() > 0) - { - m_tmproc->bNavDataDirty = true; - } - - for (auto it = DirtyOffMeshConnections.begin(); it != DirtyOffMeshConnections.end(); it++) - { - m_tmproc->GetOffMeshConnectionPoints((*it)->UserID, StartPos, EndPos); - - UTIL_OnOffMeshConnectionModified(StartPos, EndPos); - - (*it)->bDirty = false; - } - - m_tmproc->PurgeDeletedConnections(); - } - } - } - - + } } Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall) @@ -923,35 +684,12 @@ bool LoadNavMesh(const char* mapname) return false; } - int CurrFilePos = ftell(savedFile); LinearAllocator* m_talloc = new LinearAllocator(32000); FastLZCompressor* m_tcomp = new FastLZCompressor; MeshProcess* m_tmproc = new MeshProcess; - m_tmproc->NumOffMeshConns = header.NumOffMeshCons; - - fseek(savedFile, header.OffMeshConAreasOffset, SEEK_SET); - size_t ReadResult = fread(m_tmproc->OffMeshAreas, header.OffMeshConAreasLength, 1, savedFile); - - fseek(savedFile, header.OffMeshConDirsOffset, SEEK_SET); - ReadResult = fread(m_tmproc->OffMeshDirs, header.OffMeshConDirsLength, 1, savedFile); - - fseek(savedFile, header.OffMeshConFlagsOffset, SEEK_SET); - ReadResult = fread(m_tmproc->OffMeshFlags, header.OffMeshConFlagsLength, 1, savedFile); - - fseek(savedFile, header.OffMeshConRadsOffset, SEEK_SET); - ReadResult = fread(m_tmproc->OffMeshRads, header.OffMeshConRadsLength, 1, savedFile); - - fseek(savedFile, header.OffMeshConUserIDsOffset, SEEK_SET); - ReadResult = fread(m_tmproc->OffMeshIDs, header.OffMeshConUserIDsLength, 1, savedFile); - - fseek(savedFile, header.OffMeshConVertsOffset, SEEK_SET); - ReadResult = fread(m_tmproc->OffMeshVerts, header.OffMeshConVertsLength, 1, savedFile); - - m_tmproc->PopulateOffMeshConnectionVector(); - // TODO: Need to pass all off mesh connection verts, areas, flags etc as arrays to m_tmproc. Needs to be exported from recast as such status = NavMeshes[REGULAR_NAV_MESH].tileCache->init(&header.regularCacheParams, m_talloc, m_tcomp, m_tmproc); @@ -1020,7 +758,7 @@ bool LoadNavMesh(const char* mapname) } if (tile) - NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh, false); + NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh); } for (int i = 0; i < header.numOnosTiles; ++i) @@ -1059,7 +797,7 @@ bool LoadNavMesh(const char* mapname) } if (tile) - NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh, false); + NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh); } for (int i = 0; i < header.numBuildingTiles; ++i) @@ -1098,7 +836,21 @@ bool LoadNavMesh(const char* mapname) } if (tile) - NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh, false); + NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh); + } + + fseek(savedFile, header.OffMeshConsOffset, SEEK_SET); + + for (int i = 0; i < header.NumOffMeshCons; i++) + { + dtOffMeshConnection def; + + fread(&def, sizeof(dtOffMeshConnection), 1, savedFile); + + for (int ii = 0; ii < BUILDING_NAV_MESH; ii++) + { + NavMeshes[ii].tileCache->addOffMeshConnection(&def.pos[0], &def.pos[3], def.rad, def.area, def.flags, def.bBiDir, 0); + } } fclose(savedFile); @@ -1136,31 +888,21 @@ bool LoadNavMesh(const char* mapname) return false; } - UTIL_RefreshOffMeshConnections(); - return true; } -void UTIL_RefreshOffMeshConnections() +void OnOffMeshConnectionAdded(dtOffMeshConnection* NewConnection) { - MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess(); - - if (!m_tmproc) { return; } - - vector Connections = m_tmproc->GetOffMeshConnections(); - - for (auto it = Connections.begin(); it != Connections.end(); it++) + for (int i = 0; i <= BUILDING_NAV_MESH; i++) { - if (it->bPendingDelete) { continue; } + if (NavMeshes[i].navMesh && NavMeshes[i].tileCache) + { + NavMeshes[i].navMesh->LinkOffMeshConnectionToTiles(NewConnection); - Vector StartLoc, EndLoc; - - m_tmproc->GetOffMeshConnectionPoints(it->UserID, StartLoc, EndLoc); - - UTIL_OnOffMeshConnectionModified(StartLoc, EndLoc); + dtCompressedTile* ModifiedTile = NavMeshes[i].tileCache->getTileAt(NewConnection->FromTileX, NewConnection->FromTileY, NewConnection->FromTileLayer); + NavMeshes[i].tileCache->buildNavMeshTile(NavMeshes[i].tileCache->getTileRef(ModifiedTile), NavMeshes[i].navMesh); + } } - - m_tmproc->MarkOffMeshConnectionsClean(); } void UTIL_PopulateBaseNavProfiles() @@ -7347,7 +7089,7 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict) return nullptr; } -void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* NewConnectionDef) +void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* RemoveConnectionDef) { Vector ConnStart, ConnEnd; @@ -7360,132 +7102,29 @@ void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char are ConnEnd = (hit.flFraction < 1.0f) ? hit.vecEndPos : EndLoc; - if (NavMeshes[REGULAR_NAV_MESH].tileCache) - { - NewConnectionDef->MeshConnectionIndex = -1; - MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess(); + ConnStart = Vector(ConnStart.x, ConnStart.z, -ConnStart.y); + ConnEnd = Vector(ConnEnd.x, ConnEnd.z, -ConnEnd.y); - if (m_tmproc) - { - m_tmproc->AddOffMeshConnectionDef(ConnStart, ConnEnd, area, flags, bBiDirectional, NewConnectionDef); - } + for (int i = 0; i < BUILDING_NAV_MESH; i++) + { + dtOffMeshConnectionRef ref = 0; + + NavMeshes[i].tileCache->addOffMeshConnection(ConnStart, ConnEnd, 18.0f, area, flags, bBiDirectional, &ref); + + RemoveConnectionDef->ConnectionRefs[i] = (unsigned int)ref; } } -void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* NewConnectionDef) +void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef) { - if (NewConnectionDef->MeshConnectionIndex < 0) { return; } - - Vector StartLoc, EndLoc; - - if (NavMeshes[REGULAR_NAV_MESH].tileCache) + for (int i = 0; i < BUILDING_NAV_MESH; i++) { - MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess(); + dtOffMeshConnectionRef ref = 0; - if (m_tmproc) - { - m_tmproc->RemoveOffMeshConnectionDef(NewConnectionDef->MeshConnectionIndex); - } + NavMeshes[i].tileCache->removeOffMeshConnection(RemoveConnectionDef->ConnectionRefs[i]); + RemoveConnectionDef->ConnectionRefs[i] = 0; } - - NewConnectionDef->MeshConnectionIndex = -1; - -} - -void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc) -{ - float ext[3] = { 50.0f, 50.0f, 50.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); - } - } - - bNavMeshModified = true; } const nav_profile GetBaseNavProfile(const int index) diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index 68961d04..fa278c39 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -292,9 +292,8 @@ void UTIL_RemoveTemporaryObstacle(unsigned int ObstacleRef); void UTIL_RemoveTemporaryObstacles(unsigned int* ObstacleRefs); -void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* NewConnectionDef); -void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* NewConnectionDef); -void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc); +void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* RemoveConnectionDef); +void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef); /* @@ -465,7 +464,7 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis void UTIL_PopulateBaseNavProfiles(); -void UTIL_RefreshOffMeshConnections(); +void OnOffMeshConnectionAdded(dtOffMeshConnection* NewConnection); #endif // BOT_NAVIGATION_H diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index 34bdc318..b3380384 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -1567,7 +1567,7 @@ void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure) NewConnection.ToLocation = OtherPhaseGate->Location; NewConnection.ConnectionFlags = NewFlag; NewConnection.TargetObject = OtherPhaseGate->edict; - NewConnection.MeshConnectionIndex = -1; + memset(&NewConnection.ConnectionRefs[0], 0, sizeof(NewConnection.ConnectionRefs)); UTIL_AddOffMeshConnection(NewStructure->Location, OtherPhaseGate->Location, SAMPLE_POLYAREA_GROUND, NewFlag, true, &NewConnection); diff --git a/main/source/mod/AvHConsoleCommands.cpp b/main/source/mod/AvHConsoleCommands.cpp index 29eea07b..092ec2ec 100644 --- a/main/source/mod/AvHConsoleCommands.cpp +++ b/main/source/mod/AvHConsoleCommands.cpp @@ -1420,6 +1420,36 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) theSuccess = true; } + else if (FStrEq(pcmd, "refreshoffmesh")) + { + theSuccess = true; + } + else if (FStrEq(pcmd, "evolvelerk")) + { + vector AIPlayers = AIMGR_GetAllAIPlayers(); + + for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++) + { + AvHAIPlayer* thisBot = (*it); + + AITASK_SetEvolveTask(thisBot, &thisBot->PrimaryBotTask, thisBot->Edict->v.origin, ALIEN_LIFEFORM_THREE, true); + } + + theSuccess = true; + } + else if (FStrEq(pcmd, "evolvegorge")) + { + vector AIPlayers = AIMGR_GetAllAIPlayers(); + + for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++) + { + AvHAIPlayer* thisBot = (*it); + + AITASK_SetEvolveTask(thisBot, &thisBot->PrimaryBotTask, thisBot->Edict->v.origin, ALIEN_LIFEFORM_TWO, true); + } + + theSuccess = true; + } else if (FStrEq(pcmd, "tracedoor")) { Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs @@ -1435,6 +1465,14 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) if (Door) { + for (auto it = Door->TriggerEnts.begin(); it != Door->TriggerEnts.end(); it++) + { + const char* ButtonTarget = STRING(it->Edict->v.target); + const char* DoorTargetName = STRING(Door->DoorEdict->v.targetname); + + bool bThing = true; + } + DoorTrigger* Trigger = UTIL_GetNearestDoorTrigger(theAvHPlayer->pev->origin, Door, nullptr); if (Trigger) @@ -1448,11 +1486,11 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) } else if (FStrEq(pcmd, "cometome")) { - for (int i = 0; i < AIMGR_GetNumAIPlayers(); i++) - { - AvHAIPlayer* thisBot = AIMGR_GetAIPlayerAtIndex(i); + vector AIPlayers = AIMGR_GetAllAIPlayers(); - if (thisBot) + for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++) + { + AvHAIPlayer* thisBot = (*it); { AITASK_SetMoveTask(thisBot, &thisBot->PrimaryBotTask, theAvHPlayer->pev->origin, true); } @@ -1460,15 +1498,25 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) theSuccess = true; } - else if (FStrEq(pcmd, "aiteamstarts")) + else if (FStrEq(pcmd, "testpointadjust")) { - Vector TeamOneLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()); + Vector NewLoc = AdjustPointForPathfinding(theAvHPlayer->pev->origin); - UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamOneLoc, 10.0f, 0, 0, 255); + if (!vIsZero(NewLoc)) + { + UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, NewLoc, 10.0f); + } - Vector TeamTwoLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()); + theSuccess = true; + } + else if (FStrEq(pcmd, "testflightpath")) + { + vector path; + path.clear(); - UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamTwoLoc, 10.0f, 0, 128, 0); + FindFlightPathToPoint(GetBaseNavProfile(ALL_NAV_PROFILE), AITAC_GetTeamStartingLocation(TEAM_ONE) + Vector(0.0f, 0.0f, 50.0f), theAvHPlayer->pev->origin, path, 100.0f); + + AIDEBUG_DrawPath(path, 20.0f); theSuccess = true; }