Skip to content
This repository was archived by the owner on Dec 4, 2020. It is now read-only.

Commit 9e44ff0

Browse files
committed
Merge branch 'feature/navmesh_improvements' into canary
2 parents 82e30b5 + 6478257 commit 9e44ff0

File tree

4 files changed

+93
-34
lines changed

4 files changed

+93
-34
lines changed

navmeshes

Submodule navmeshes updated 267 files

src/map/ai/controllers/mob_controller.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ void CMobController::FollowRoamPath()
856856
PMob->PAI->PathFind->FollowPath();
857857

858858
CBattleEntity* PPet = PMob->PPet;
859-
if (PPet != nullptr && !PPet->PAI->IsEngaged())
859+
if (PPet != nullptr && PPet->PAI->IsSpawned() && !PPet->PAI->IsEngaged())
860860
{
861861
// pet should follow me if roaming
862862
position_t targetPoint = nearPosition(PMob->loc.p, 2.1f, (float)M_PI);

src/map/navmesh.cpp

+83-26
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@
2020
*/
2121

2222
#include "navmesh.h"
23-
#include "../common/detour/DetourNavMeshQuery.h"
24-
#include <float.h>
25-
#include <string.h>
23+
#include <cstring>
2624
#include <iostream>
2725
#include <fstream>
28-
#include "../common/utils.h"
2926
#include "../common/tpzrand.h"
3027

3128
const int8 CNavMesh::ERROR_NEARESTPOLY;
@@ -164,7 +161,6 @@ bool CNavMesh::load(const std::string& filename)
164161

165162
void CNavMesh::outputError(uint32 status)
166163
{
167-
168164
if (status & DT_WRONG_MAGIC)
169165
{
170166
ShowNavError("Detour wrong magic\n");
@@ -380,60 +376,121 @@ bool CNavMesh::validPosition(const position_t& position)
380376
return m_navMesh->isValidPolyRef(startRef);
381377
}
382378

379+
double CNavMesh::DistanceToWall(const position_t& start)
380+
{
381+
dtStatus status;
382+
float spos[3];
383+
ToDetourPos(&start, spos);
384+
float polyPickExt[3];
385+
polyPickExt[0] = 30;
386+
polyPickExt[1] = 60;
387+
polyPickExt[2] = 30;
388+
float snearest[3];
389+
dtQueryFilter filter;
390+
391+
// include walking
392+
filter.setIncludeFlags(0xFFE1);
393+
// exclude swim,jump,door
394+
filter.setExcludeFlags(0xE);
395+
396+
dtPolyRef startRef;
397+
status = m_navMeshQuery.findNearestPoly(spos, polyPickExt, &filter, &startRef, snearest);
398+
if (dtStatusFailed(status))
399+
{
400+
ShowNavError("CNavMesh::DistanceToWall findNearestPoly failed (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID);
401+
outputError(status);
402+
return 0.0;
403+
}
404+
405+
float distanceToWall = 0.0f;
406+
float hitPos[3];
407+
float hitNormal[3];
408+
int npolys;
409+
status = m_navMeshQuery.findDistanceToWall(startRef, snearest, 100.0f, &filter, &distanceToWall, hitPos, hitNormal);
410+
if (dtStatusFailed(status))
411+
{
412+
ShowNavError("CNavMesh::DistanceToWall findDistanceToWall failed (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID);
413+
outputError(status);
414+
return 0.0;
415+
}
416+
417+
return static_cast<double>(distanceToWall);
418+
}
419+
420+
// Recast Detour Docs:
421+
// Casts a 'walkability' ray along the surface of the navigation mesh from the start position toward the end position.
422+
// Note: This is not a point-to-point in 3D space calculation, it is 2D across the navmesh!
383423
bool CNavMesh::raycast(const position_t& start, const position_t& end)
384424
{
385425
if (start.x == end.x && start.y == end.y && start.z == end.z)
426+
{
386427
return true;
387-
dtStatus status;
428+
}
388429

430+
dtStatus status;
389431
float spos[3];
390-
CNavMesh::ToDetourPos(&start, spos);
432+
ToDetourPos(&start, spos);
391433

392434
float epos[3];
393-
CNavMesh::ToDetourPos(&end, epos);
435+
ToDetourPos(&end, epos);
394436

395437
float polyPickExt[3];
396438
polyPickExt[0] = 30;
397439
polyPickExt[1] = 60;
398440
polyPickExt[2] = 30;
399441

400442
float snearest[3];
401-
402443
dtQueryFilter filter;
403-
filter.setIncludeFlags(0xffff);
404-
filter.setExcludeFlags(0);
405444

445+
// include walking
446+
filter.setIncludeFlags(0xFFE1);
447+
// exclude swim,jump,door
448+
filter.setExcludeFlags(0xE);
406449
dtPolyRef startRef;
407450

408451
status = m_navMeshQuery.findNearestPoly(spos, polyPickExt, &filter, &startRef, snearest);
409-
410452
if (dtStatusFailed(status))
411453
{
412-
ShowNavError("CNavMesh::raycastPoint start point invalid (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID);
454+
ShowNavError("CNavMesh::raycast start point invalid (%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], m_zoneID);
413455
outputError(status);
414-
return true;
456+
return false;
415457
}
416458

417459
if (!m_navMesh->isValidPolyRef(startRef))
418460
{
419-
ShowNavError("CNavMesh::raycastPoint startRef is invalid (%f, %f, %f) (%u)\n", start.x, start.y, start.z, m_zoneID);
420-
return true;
461+
ShowNavError("CNavMesh::raycast startRef is invalid (%f, %f, %f) (%u)\n", start.x, start.y, start.z, m_zoneID);
462+
return false;
421463
}
422464

423-
status = m_navMeshQuery.raycast(startRef, spos, epos, &filter, 0, &m_hit);
424-
425-
if (dtStatusFailed(status))
465+
// There is a tiny strip of walkable map at the very edge of walls that
466+
// a player can use, but is not part of the navmesh. For a point to be
467+
// raycasted to - it needs to be on the navmesh. This will check to
468+
// see if the player is "off-mesh" and raycast to the nearest "on-mesh"
469+
// point instead.
470+
if (DistanceToWall(end) <= 2.0)
426471
{
427-
ShowNavError("CNavMesh::raycastPoint raycast failed (%f, %f, %f)->(%f, %f, %f) (%u)\n", spos[0], spos[1], spos[2], epos[0], epos[1], epos[2], m_zoneID);
428-
outputError(status);
429-
return true;
472+
float closest[3];
473+
status = m_navMeshQuery.closestPointOnPolyBoundary(startRef, epos, closest);
474+
if (dtStatusFailed(status))
475+
{
476+
ShowNavError("CNavMesh::raycast closestPointOnPolyBoundary failed (%u)\n", m_zoneID);
477+
outputError(status);
478+
return false;
479+
}
480+
481+
std::memcpy(epos, closest, sizeof(float) * 3);
430482
}
431483

432-
// no wall was hit
433-
if (m_hit.t == FLT_MAX)
484+
float t = 0;
485+
float hitNormal[3];
486+
int npolys = 0;
487+
status = m_navMeshQuery.raycast(startRef, spos, epos, &filter, &t, hitNormal, m_raycastVisitedPolys, &npolys, MAX_RAYCAST_POLYS);
488+
if (dtStatusFailed(status))
434489
{
435-
return true;
490+
ShowNavError("CNavMesh::raycast raycast failed (%u)\n", m_zoneID);
491+
outputError(status);
492+
return false;
436493
}
437494

438-
return false;
495+
return t > 1;
439496
}

src/map/navmesh.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ The NavMesh class will load and find paths given a start point and end point.
3434
#include <vector>
3535
#include <memory>
3636

37-
#define MAX_NAV_POLYS 256
38-
39-
static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET';
40-
static const int NAVMESHSET_VERSION = 1;
37+
static constexpr int MAX_NAV_POLYS = 256;
38+
static constexpr int MAX_RAYCAST_POLYS = 49152;
39+
static constexpr int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET';
40+
static constexpr int NAVMESHSET_VERSION = 1;
4141

4242
struct NavMeshSetHeader
4343
{
@@ -64,7 +64,6 @@ class CNavMesh
6464
static void ToDetourPos(float* out);
6565
static void ToDetourPos(position_t* out);
6666

67-
public:
6867
CNavMesh(uint16 zoneID);
6968
~CNavMesh();
7069

@@ -82,14 +81,17 @@ class CNavMesh
8281

8382
bool validPosition(const position_t& position);
8483

84+
double DistanceToWall(const position_t& start);
85+
8586
private:
8687
void outputError(uint32 status);
8788

8889
uint16 m_zoneID;
8990
dtRaycastHit m_hit;
90-
dtPolyRef m_hitPath[20];
91+
dtPolyRef m_hitPath[100];
9192
std::unique_ptr<dtNavMesh> m_navMesh;
9293
dtNavMeshQuery m_navMeshQuery;
94+
dtPolyRef m_raycastVisitedPolys[16384];
9395
};
9496

9597
#endif

0 commit comments

Comments
 (0)