Skip to content

Instantly share code, notes, and snippets.

@vermie
Created September 9, 2010 03:14
Show Gist options
  • Save vermie/571299 to your computer and use it in GitHub Desktop.
Save vermie/571299 to your computer and use it in GitHub Desktop.
diff --git a/contrib/mmap/src/generator.cpp b/contrib/mmap/src/generator.cpp
index 33f2686..4cc5e94 100644
--- a/contrib/mmap/src/generator.cpp
+++ b/contrib/mmap/src/generator.cpp
@@ -66,6 +66,12 @@ void handleArgs(int argc, char** argv,
if(strcmp(argv[i], "--maxAngle") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
float maxangle = atof(param);
if(maxangle <= 90.f && maxangle >= 45.f)
maxAngle = maxangle;
@@ -75,6 +81,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--tile") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
char* stileX = strtok(param, ",");
char* stileY = strtok(NULL, ",");
int tilex = atoi(stileX);
@@ -94,6 +106,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--skipLiquid") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
skipLiquid = true;
else if(strcmp(param, "false") == 0)
@@ -104,6 +122,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--skipContinents") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
skipContinents = true;
else if(strcmp(param, "false") == 0)
@@ -114,6 +138,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--skipJunkMaps") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
skipJunkMaps = true;
else if(strcmp(param, "false") == 0)
@@ -124,6 +154,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--skipBattlegrounds") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
skipBattlegrounds = true;
else if(strcmp(param, "false") == 0)
@@ -134,6 +170,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--hiResHeightmaps") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
hiResHeightmaps = true;
else if(strcmp(param, "false") == 0)
@@ -144,6 +186,12 @@ void handleArgs(int argc, char** argv,
else if(strcmp(argv[i], "--debugOutput") == 0)
{
param = argv[++i];
+ if(!param)
+ {
+ badParam = true;
+ return;
+ }
+
if(strcmp(param, "true") == 0)
debugOutput = true;
else if(strcmp(param, "false") == 0)
diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp
index a73d727..8eeed7d 100644
--- a/src/game/HomeMovementGenerator.cpp
+++ b/src/game/HomeMovementGenerator.cpp
@@ -48,49 +48,31 @@ HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z))
owner.GetRespawnCoord(x, y, z);
- if(!i_path)
- i_path = new PathInfo(&owner, x, y, z);
- else
- i_path->Update(x, y, z);
+ CreatureTraveller traveller(owner);
+ i_destinationHolder.SetDestination(traveller, x, y, z, false);
- // we always have a path to the target - shortcut in worst case
- // even is this map don't have mmaps at all
- i_path->getNextPosition(x, y, z);
+ PathInfo i_path(&owner, x, y, z);
+ PointPath myPath = i_path.getFullPath();
- CreatureTraveller traveller(owner);
- i_destinationHolder.SetDestination(traveller, x, y, z);
+ float speed = traveller.Speed()*0.001f; // in ms
+ uint32 traveltime = uint32(myPath.GetTotalLength()/speed);
+ modifyTravelTime(traveltime);
+
+ owner.SendMonsterMoveByPath(myPath, 0, myPath.size(), owner.GetSplineFlags(), traveltime);
owner.clearUnitState(UNIT_STAT_ALL_STATE);
}
bool
HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff)
{
- CreatureTraveller traveller( owner);
- bool reachedHome = false;
-
+ CreatureTraveller traveller(owner);
if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
{
if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list)
return true; // not expire now, but already lost
-
- bool needNewDest = false;
- if(i_path && i_destinationHolder.HasArrived())
- {
- float end_x, end_y, end_z, next_x, next_y, next_z, cur_x, cur_y, cur_z;
- float dist = owner.GetObjectBoundingRadius();
- i_path->getNextPosition(next_x, next_y, next_z);
- i_path->getEndPosition(end_x, end_y, end_z);
- i_destinationHolder.GetLocationNow(owner.GetBaseMap(), cur_x, cur_y, cur_z);
-
- reachedHome = isSamePoint(dist, cur_x, cur_y, cur_z, end_x, end_y, end_z);
- needNewDest = !isSamePoint(dist, next_x, next_y, next_z, end_x, end_y, end_z);
- }
-
- if (!i_path || needNewDest)
- _setTargetLocation(owner);
}
- if (reachedHome)
+ if (time_diff > i_travel_timer)
{
owner.AddSplineFlag(SPLINEFLAG_WALKMODE);
@@ -111,5 +93,7 @@ HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff
return false;
}
+ i_travel_timer -= time_diff;
+
return true;
}
diff --git a/src/game/HomeMovementGenerator.h b/src/game/HomeMovementGenerator.h
index 7b9d04c..af9ded0 100644
--- a/src/game/HomeMovementGenerator.h
+++ b/src/game/HomeMovementGenerator.h
@@ -35,14 +35,15 @@ class MANGOS_DLL_SPEC HomeMovementGenerator<Creature>
{
public:
- HomeMovementGenerator():i_path(NULL){}
- ~HomeMovementGenerator() { delete i_path; }
+ HomeMovementGenerator(){}
+ ~HomeMovementGenerator(){}
void Initialize(Creature &);
void Finalize(Creature &) {}
void Interrupt(Creature &) {}
void Reset(Creature &);
bool Update(Creature &, const uint32 &);
+ void modifyTravelTime(uint32 travel_time) { i_travel_timer = travel_time; }
MovementGeneratorType GetMovementGeneratorType() const { return HOME_MOTION_TYPE; }
bool GetDestination(float& x, float& y, float& z) const { i_destinationHolder.GetDestination(x,y,z); return true; }
@@ -50,6 +51,6 @@ class MANGOS_DLL_SPEC HomeMovementGenerator<Creature>
void _setTargetLocation(Creature &);
DestinationHolder< Traveller<Creature> > i_destinationHolder;
- PathInfo* i_path;
+ uint32 i_travel_timer;
};
#endif
diff --git a/src/game/PathFinder.cpp b/src/game/PathFinder.cpp
index 9731875..a7b8c9d 100644
--- a/src/game/PathFinder.cpp
+++ b/src/game/PathFinder.cpp
@@ -24,11 +24,10 @@
////////////////// PathInfo //////////////////
PathInfo::PathInfo(const WorldObject* from, const float x, const float y, const float z) :
- m_navMesh(NULL), m_navMeshQuery(NULL),
- m_polyLength(0), m_pathPolyRefs(NULL), m_pointLength(0), m_pathPoints(NULL),
+ m_navMesh(NULL), m_navMeshQuery(NULL), m_polyLength(0), m_pathPolyRefs(NULL),
m_pointPathPointer(0), m_sourceObject(from), m_type(PATHFIND_BLANK)
{
- setEndPosition(x, y, z);
+ setEndPosition(PathNode(x, y, z));
if(m_navMesh = m_sourceObject->GetMap()->GetNavMesh())
{
@@ -38,16 +37,13 @@ PathInfo::PathInfo(const WorldObject* from, const float x, const float y, const
BuildFreshPath();
}
else
- {
- setNextPosition(x, y, z);
- m_type = PATHFIND_SHORTCUT;
- }
+ shortcut();
}
PathInfo::~PathInfo()
{
- delete [] m_pathPolyRefs;
- delete [] m_pathPoints;
+ if(m_pathPolyRefs)
+ delete [] m_pathPolyRefs;
if(m_navMesh && m_navMeshQuery)
dtFreeNavMeshQuery(m_navMeshQuery);
@@ -55,7 +51,7 @@ PathInfo::~PathInfo()
dtPolyRef PathInfo::getPathPolyByPosition(float x, float y, float z)
{
- if(!m_navMesh)
+ if(!m_navMesh || !m_pathPolyRefs)
return 0; // navmesh isn't loaded
float distance; // not used
@@ -121,7 +117,7 @@ void PathInfo::BuildFreshPath()
float x, y, z;
// set start and a default next position
m_sourceObject->GetPosition(x, y, z);
- setStartPosition(x, y, z);
+ setStartPosition(PathNode(x, y, z));
float extents[VERTEX_SIZE] = {2.0f, 4.0f, 2.0f}; // defines bounds of box for search area
dtQueryFilter filter = dtQueryFilter(); // use general filter so we know if we are near navmesh
@@ -158,17 +154,13 @@ void PathInfo::BuildPath(dtPolyRef startPoly, float* startPos, dtPolyRef endPoly
if(startPoly == endPoly)
{
//printf("++ PathInfo::BuildPath :: (startPoly == endPoly) %u\n",m_sourceObject->GetGUID());
+ shortcut();
- // PATHFIND TODO: prevent walking/swimming mobs from flying into the air
- clear();
m_pathPolyRefs = new dtPolyRef[1];
m_pathPolyRefs[0] = startPoly;
m_polyLength = 1;
- float x,y,z;
- getEndPosition(x, y, z);
- setNextPosition(x, y, z);
- m_type = PathType(PATHFIND_NORMAL);
+ m_type = PATHFIND_NORMAL;
return;
}
@@ -312,20 +304,17 @@ void PathInfo::BuildPath(dtPolyRef startPoly, float* startPos, dtPolyRef endPoly
memcpy(m_pathPolyRefs, pathPolys, m_polyLength*sizeof(dtPolyRef));
}
- if(m_polyLength >= MAX_PATH_LENGTH)
- m_type = PathType(m_type | PATHFIND_INCOMPLETE);
-
// generate the point-path out of our up-to-date poly-path
updateNextPosition();
}
void PathInfo::Update(const float destX, const float destY, const float destZ)
{
- // make sure navMesh works - we can run on map w/o mmap
+ // make sure navMesh works - we can run on map w/o mmap
// can we switch map/get different mesh?
if(!m_navMesh || m_navMesh != m_sourceObject->GetMap()->GetNavMesh())
{
- setEndPosition(destX, destY, destZ);
+ setEndPosition(PathNode(destX, destY, destZ));
shortcut();
return;
}
@@ -341,15 +330,16 @@ void PathInfo::Update(const float destX, const float destY, const float destZ)
float x, y, z;
m_sourceObject->GetPosition(x, y, z);
- setStartPosition(x, y, z);
+ setStartPosition(PathNode(x, y, z));
// check if destination moved - if not we can optimize something here
// we are following old, precalculated path?
float dist = m_sourceObject->GetObjectBoundingRadius();
- float oldEnd_x, oldEnd_y, oldEnd_z;
- getEndPosition(oldEnd_x, oldEnd_y, oldEnd_z);
- if(isSamePoint(dist, oldEnd_x, oldEnd_y, oldEnd_z, destX, destY, destZ)
- && m_pointLength > 2 && m_pointPathPointer < m_pointLength)
+ PathNode oldDest = getEndPosition();
+ PathNode newDest = PathNode(destX, destY, destZ);
+
+ if(inRange(oldDest, newDest, dist, 2*dist)
+ && m_pathPoints.size() > 2 && m_pointPathPointer+1 < m_pathPoints.size())
{
// our target is not moving - we just coming closer
if(!m_pointPathPointer)
@@ -364,7 +354,7 @@ void PathInfo::Update(const float destX, const float destY, const float destZ)
else
{
m_pointPathPointer = 0;
- setEndPosition(destX, destY, destZ);
+ setEndPosition(newDest);
}
if(!m_pointPathPointer)
@@ -404,9 +394,7 @@ void PathInfo::updateNextPosition()
if(m_pointPathPointer)
{
//printf("++ PathInfo::updateNextPosition :: precalculated path %u\n",m_sourceObject->GetGUID());
- setNextPosition(m_pathPoints[m_pointPathPointer*VERTEX_SIZE+2],
- m_pathPoints[m_pointPathPointer*VERTEX_SIZE],
- m_pathPoints[m_pointPathPointer*VERTEX_SIZE+1]);
+ setNextPosition(m_pathPoints[m_pointPathPointer]);
return;
}
@@ -417,7 +405,9 @@ void PathInfo::updateNextPosition()
getEndPosition(x, y, z);
float endPos[VERTEX_SIZE] = {y, z, x};
- float* pathPoints = new float[MAX_PATH_LENGTH*VERTEX_SIZE];
+#ifndef _USE_SMOOTH_PATH_
+
+ float pathPoints[MAX_PATH_LENGTH*VERTEX_SIZE];
uint32 pointCount = m_navMeshQuery->findStraightPath(
startPos, // start position
endPos, // end position
@@ -428,50 +418,64 @@ void PathInfo::updateNextPosition()
0, // [out] shortened path PATHFIND TODO: see if this is usable (IE, doesn't leave gaps in path)
MAX_PATH_LENGTH); // maximum number of points/polygons to use
- // TODO: imitate PATHFIND_ITER code from RecastDemo so that terrain following is smoother
- // example in NavMeshTesterTool::recalc()
- // but it is pretty costy
+#else
- if(pointCount == 0)
- {
- delete [] pathPoints;
+ float pathPoints[MAX_SMOOTH_PATH_LENGTH*VERTEX_SIZE];
+ uint32 pointCount = findSmoothPath(
+ startPos, // start position
+ endPos, // end position
+ m_pathPolyRefs, // current path
+ m_polyLength, // lenth of current path
+ pathPoints, // [out] path corner points
+ MAX_SMOOTH_PATH_LENGTH); // maximum number of points/polygons to use
+
+#endif
+ if(pointCount < 2)
+ {
// only happens if pass bad data to findStraightPath or navmesh is broken
- sLog.outError("%u's UpdateNextPosition failed: 0 length path", m_sourceObject->GetGUID());
+ sLog.outError("%u's UpdateNextPosition failed: %u length path", m_sourceObject->GetGUID(), pointCount);
shortcut();
return;
}
- // first point is always our current location - we need the next one
- setNextPosition(pathPoints[VERTEX_SIZE+2], pathPoints[VERTEX_SIZE], pathPoints[VERTEX_SIZE+1]);
+ m_pathPoints.clear();
+ m_pathPoints.resize(pointCount);
+ for(uint32 i = 0; i < pointCount; ++i)
+ m_pathPoints.set(i, PathNode(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]));
- delete [] m_pathPoints;
- m_pathPoints = pathPoints;
- m_pointLength = pointCount;
m_pointPathPointer = 0;
- m_type = PathType(m_type | PATHFIND_NORMAL);
-
- // place we want to go, there is likely no complete path
- // findStraightPath() will always return the closest location
- // to our destination, if not rechable
- // we used shortcut() if no path at all found.
- endPos[0] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE+2];
- endPos[1] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE];
- endPos[2] = m_pathPoints[(m_pointLength-1)*VERTEX_SIZE+1];
+ // first point is always our current location - we need the next one
+ setNextPosition(m_pathPoints[1]);
+ // if our destination, if not rechable due to lenght limit or something else
+ // last point in outpur array is the closest we can get
float dist = 2*m_sourceObject->GetObjectBoundingRadius();
- if(!isSamePoint(dist, endPos, m_endPosition))
- m_type = PathType(m_type | PATHFIND_INCOMPLETE);
+ if(inRange(m_pathPoints[pointCount-1], m_endPosition, dist, 2*dist))
+ m_type = PATHFIND_NORMAL;
+ else if(pointCount < MAX_SMOOTH_PATH_LENGTH)
+ m_type = PATHFIND_NOPATH;
+ else
+ m_type = PATHFIND_INCOMPLETE;
}
void PathInfo::shortcut()
{
clear();
+ // make two point path, our curr pos is the start, and dest is the end
+ m_pathPoints.resize(2);
+
float x, y, z;
+ // set start and a default next position
+ m_sourceObject->GetPosition(x, y, z);
+ m_pathPoints.set(0, PathNode(x,y,z));
+
getEndPosition(x, y, z);
- setNextPosition(x, y, z);
+ m_pathPoints.set(1, PathNode(x,y,z));
+
+ setNextPosition(m_pathPoints[1]);
m_type = PATHFIND_SHORTCUT;
}
@@ -526,11 +530,7 @@ bool PathInfo::canSwim()
NavTerrain PathInfo::getNavTerrain(float x, float y, float z)
{
GridMapLiquidData data;
- m_sourceObject->GetMap()->getLiquidStatus(x,
- y,
- z,
- MAP_ALL_LIQUIDS,
- &data);
+ m_sourceObject->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
switch(data.type)
{
@@ -548,7 +548,218 @@ NavTerrain PathInfo::getNavTerrain(float x, float y, float z)
bool PathInfo::noPath()
{
- // basically:
- // endOfPath != destination && completePath
return (m_type & PATHFIND_NOPATH) && !(m_type & PATHFIND_INCOMPLETE);
}
+
+uint32 PathInfo::fixupCorridor(dtPolyRef* path, const uint32 npath, const uint32 maxPath,
+ const dtPolyRef* visited, const uint32 nvisited)
+{
+ int32 furthestPath = -1;
+ int32 furthestVisited = -1;
+
+ // Find furthest common polygon.
+ for (int32 i = npath-1; i >= 0; --i)
+ {
+ bool found = false;
+ for (int32 j = nvisited-1; j >= 0; --j)
+ {
+ if (path[i] == visited[j])
+ {
+ furthestPath = i;
+ furthestVisited = j;
+ found = true;
+ }
+ }
+ if (found)
+ break;
+ }
+
+ // If no intersection found just return current path.
+ if (furthestPath == -1 || furthestVisited == -1)
+ return npath;
+
+ // Concatenate paths.
+
+ // Adjust beginning of the buffer to include the visited.
+ uint32 req = nvisited - furthestVisited;
+ uint32 orig = uint32(furthestPath+1) < npath ? furthestPath+1 : npath;
+ uint32 size = npath-orig > 0 ? npath-orig : 0;
+ if (req+size > maxPath)
+ size = maxPath-req;
+
+ if (size)
+ memmove(path+req, path+orig, size*sizeof(dtPolyRef));
+
+ // Store visited
+ for (uint32 i = 0; i < req; ++i)
+ path[i] = visited[(nvisited-1)-i];
+
+ return req+size;
+}
+
+bool PathInfo::getSteerTarget(const float* startPos, const float* endPos,
+ const float minTargetDist, const dtPolyRef* path, const uint32 pathSize,
+ float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef,
+ float* outPoints, uint32* outPointCount)
+{
+ // Find steer target.
+ static const uint32 MAX_STEER_POINTS = 3;
+ float steerPath[MAX_STEER_POINTS*VERTEX_SIZE];
+ unsigned char steerPathFlags[MAX_STEER_POINTS];
+ dtPolyRef steerPathPolys[MAX_STEER_POINTS];
+ uint32 nsteerPath = m_navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
+ steerPath, steerPathFlags, steerPathPolys, MAX_STEER_POINTS);
+ if (!nsteerPath)
+ return false;
+
+ if (outPoints && outPointCount)
+ {
+ *outPointCount = nsteerPath;
+ for (uint32 i = 0; i < nsteerPath; ++i)
+ dtVcopy(&outPoints[i*VERTEX_SIZE], &steerPath[i*VERTEX_SIZE]);
+ }
+
+ // Find vertex far enough to steer to.
+ uint32 ns = 0;
+ while (ns < nsteerPath)
+ {
+ // Stop at Off-Mesh link or when point is further than slop away.
+ if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
+ !inRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f))
+ break;
+ ns++;
+ }
+ // Failed to find good point to steer to.
+ if (ns >= nsteerPath)
+ return false;
+
+ dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]);
+ steerPos[1] = startPos[1];
+ steerPosFlag = steerPathFlags[ns];
+ steerPosRef = steerPathPolys[ns];
+
+ return true;
+}
+
+uint32 PathInfo::findSmoothPath(const float* startPos, const float* endPos,
+ const dtPolyRef* path, const uint32 pathSize,
+ float* smoothPath, const uint32 maxSmoothPathSize)
+{
+ uint32 m_nsmoothPath = 0;
+
+ dtPolyRef polys[MAX_PATH_LENGTH];
+ memcpy(polys, path, sizeof(dtPolyRef)*pathSize);
+ uint32 npolys = pathSize;
+
+ float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE];
+ m_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos);
+ m_navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos);
+
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos);
+ m_nsmoothPath++;
+
+ // Move towards target a small advancement at a time until target reached or
+ // when ran out of memory to store the path.
+ while (npolys && m_nsmoothPath < maxSmoothPathSize)
+ {
+ // Find location to steer towards.
+ float steerPos[VERTEX_SIZE];
+ unsigned char steerPosFlag;
+ dtPolyRef steerPosRef;
+
+ if (!getSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef))
+ break;
+
+ bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END);
+ bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION);
+
+ // Find movement delta.
+ float delta[VERTEX_SIZE], len = 0.0f;
+ dtVsub(delta, steerPos, iterPos);
+ len = dtSqrt(dtVdot(delta,delta));
+ // If the steer target is end of path or off-mesh link, do not move past the location.
+ if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
+ len = 1.0f;
+ else
+ len = SMOOTH_PATH_STEP_SIZE / len;
+
+ float moveTgt[VERTEX_SIZE];
+ dtVmad(moveTgt, iterPos, delta, len);
+
+ // Move
+ float result[VERTEX_SIZE];
+ dtPolyRef visited[16];
+ dtQueryFilter filter = createFilter();
+
+ uint32 nvisited = m_navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &filter, result, visited, 16);
+
+ npolys = fixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited);
+ float h = 0;
+ m_navMeshQuery->getPolyHeight(polys[0], result, &h);
+ result[1] = h;
+ dtVcopy(iterPos, result);
+
+ // Handle end of path and off-mesh links when close enough.
+ if (endOfPath && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f))
+ {
+ // Reached end of path.
+ dtVcopy(iterPos, targetPos);
+ if (m_nsmoothPath < MAX_SMOOTH_PATH_LENGTH)
+ {
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos);
+ m_nsmoothPath++;
+ }
+ break;
+ }
+ else if (offMeshConnection && inRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 2.0f))
+ {
+ // Reached off-mesh connection.
+ float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
+
+ // Advance the path up to and over the off-mesh connection.
+ dtPolyRef prevRef = 0, polyRef = polys[0];
+ uint32 npos = 0;
+ while (npos < npolys && polyRef != steerPosRef)
+ {
+ prevRef = polyRef;
+ polyRef = polys[npos];
+ npos++;
+ }
+
+ for (uint32 i = npos; i < npolys; ++i)
+ polys[i-npos] = polys[i];
+
+ npolys -= npos;
+
+ // Handle the connection.
+ if (m_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos))
+ {
+ if (m_nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], startPos);
+ m_nsmoothPath++;
+ // Hack to make the dotted path not visible during off-mesh connection.
+ if (m_nsmoothPath & 1)
+ {
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], startPos);
+ m_nsmoothPath++;
+ }
+ }
+ // Move position at the other side of the off-mesh link.
+ dtVcopy(iterPos, endPos);
+ float h;
+ m_navMeshQuery->getPolyHeight(polys[0], iterPos, &h);
+ iterPos[1] = h;
+ }
+ }
+
+ // Store results.
+ if (m_nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[m_nsmoothPath*VERTEX_SIZE], iterPos);
+ m_nsmoothPath++;
+ }
+ }
+
+ return m_nsmoothPath;
+}
diff --git a/src/game/PathFinder.h b/src/game/PathFinder.h
index 8340cd5..edec62b 100644
--- a/src/game/PathFinder.h
+++ b/src/game/PathFinder.h
@@ -28,6 +28,11 @@ class WorldObject;
#define MAX_PATH_LENGTH 256
#define VERTEX_SIZE 3
+#define _USE_SMOOTH_PATH_
+#define MAX_SMOOTH_PATH_LENGTH 2048
+#define SMOOTH_PATH_STEP_SIZE 8.0f
+#define SMOOTH_PATH_SLOP 0.5f
+
// see contrib/mmap/src/TileBuilder.h
enum NavTerrain
{
@@ -49,17 +54,31 @@ enum PathType
PATHFIND_NOPATH = 0x0010 // could not find a path
};
+struct PathNode
+{
+ PathNode():x(0.0f), y(0.0f), z(0.0f){}
+ PathNode(float _x, float _y, float _z) : x(_x), y(_y), z(_z){}
+ float x,y,z;
+};
+
+typedef Path<PathNode> PointPath;
+
class PathInfo
{
public:
PathInfo(const WorldObject* from, const float x, const float y, const float z);
~PathInfo();
- inline void getStartPosition(float &x, float &y, float &z) { x = m_startPosition[0]; y = m_startPosition[1]; z = m_startPosition[2]; }
- inline void getNextPosition(float &x, float &y, float &z) { x = m_nextPosition[0]; y = m_nextPosition[1]; z = m_nextPosition[2]; }
- inline void getEndPosition(float &x, float &y, float &z) { x = m_endPosition[0]; y = m_endPosition[1]; z = m_endPosition[2]; }
+ inline void getStartPosition(float &x, float &y, float &z) { x = m_startPosition.x; y = m_startPosition.y; z = m_startPosition.z; }
+ inline void getNextPosition(float &x, float &y, float &z) { x = m_nextPosition.x; y = m_nextPosition.y; z = m_nextPosition.z; }
+ inline void getEndPosition(float &x, float &y, float &z) { x = m_endPosition.x; y = m_endPosition.y; z = m_endPosition.z; }
+
+ inline PathNode getStartPosition() { return m_startPosition; }
+ inline PathNode getNextPosition() { return m_nextPosition; }
+ inline PathNode getEndPosition() { return m_endPosition; }
- inline uint32 getFullPath(float **pathPoints) { *pathPoints = m_pathPoints; return m_pointLength; };
+ inline uint32 getPathPointer() { return (m_pointPathPointer ? m_pointPathPointer-1 : 0);}
+ inline PointPath& getFullPath() { return m_pathPoints; }
void Update(const float x, const float y, const float z);
bool noPath();
@@ -75,33 +94,29 @@ class PathInfo
dtPolyRef * m_pathPolyRefs; // array of detour polygon references
uint32 m_polyLength; // number of polygons in the path
- float * m_pathPoints; // array of float[3] for (x, y, z) coords
- uint32 m_pointLength; // number of points in the path
+ PointPath m_pathPoints; // out actual (x,y,z) path to the target
uint32 m_pointPathPointer; // points to current triple in m_pathPoints - used when dest do not change
- float m_startPosition[VERTEX_SIZE]; // {x, y, z} of current location
- float m_nextPosition[VERTEX_SIZE]; // {x, y, z} of next location on the path
- float m_endPosition[VERTEX_SIZE]; // {x, y, z} of the destination
+ PathNode m_startPosition; // {x, y, z} of current location
+ PathNode m_nextPosition; // {x, y, z} of next location on the path
+ PathNode m_endPosition; // {x, y, z} of the destination
const WorldObject * m_sourceObject; // the object that is moving (safe pointer because PathInfo is only accessed from the mover?)
dtNavMesh * m_navMesh; // the nav mesh
dtNavMeshQuery* m_navMeshQuery; // the nav mesh query used to find the path
PathType m_type; // tells what kind of path this is
- inline void setNextPosition(float x, float y, float z) { m_nextPosition[0] = x; m_nextPosition[1] = y; m_nextPosition[2] = z; }
- inline void setStartPosition(float x, float y, float z) { m_startPosition[0] = x; m_startPosition[1] = y; m_startPosition[2] = z; }
- inline void setEndPosition(float x, float y, float z) { m_endPosition[0] = x; m_endPosition[1] = y; m_endPosition[2] = z; }
+ inline void setNextPosition(PathNode point) { m_nextPosition = point; }
+ inline void setStartPosition(PathNode point) { m_startPosition = point; }
+ inline void setEndPosition(PathNode point) { m_endPosition = point; }
inline void clear()
{
delete [] m_pathPolyRefs;
m_pathPolyRefs = NULL;
-
- delete [] m_pathPoints;
- m_pathPoints = NULL;
-
m_polyLength = 0;
- m_pointLength = 0;
+
+ m_pathPoints.clear();
m_pointPathPointer = 0;
}
@@ -120,22 +135,34 @@ class PathInfo
bool canFly();
bool canSwim();
NavTerrain getNavTerrain(float x, float y, float z);
+
+
+ uint32 fixupCorridor(dtPolyRef* path, const uint32 npath, const uint32 maxPath,
+ const dtPolyRef* visited, const uint32 nvisited);
+ bool getSteerTarget(const float* startPos, const float* endPos, const float minTargetDist,
+ const dtPolyRef* path, const uint32 pathSize, float* steerPos,
+ unsigned char& steerPosFlag, dtPolyRef& steerPosRef,
+ float* outPoints = 0, uint32* outPointCount = 0);
+ uint32 findSmoothPath(const float* startPos, const float* endPos,
+ const dtPolyRef* path, const uint32 pathSize,
+ float* smoothPath, const uint32 maxSmoothPathSize);
};
-// using == for two float numbers wont do us much good, use diff
-inline bool isSamePoint(const float diff, const float* point1, const float* point2)
+inline bool inRangeYZX(const float* v1, const float* v2, const float r, const float h)
{
- return (abs(point1[0] - point2[0]) <= diff &&
- abs(point1[1] - point2[1]) <= diff &&
- abs(point1[2] - point2[2]) <= diff);
+ const float dx = v2[0] - v1[0];
+ const float dy = v2[1] - v1[1];
+ const float dz = v2[2] - v1[2];
+ return (dx*dx + dz*dz) < r*r && fabsf(dy) < h;
}
-inline bool isSamePoint(const float diff, const float x1, const float y1, const float z1,
- const float x2, const float y2, const float z2)
+inline bool inRange(const PathNode p1, const PathNode p2,
+ const float r, const float h)
{
- return (abs(x1 - x2) <= diff &&
- abs(y1 - y2) <= diff &&
- abs(z1 - z2) <= diff);
+ const float dx = p2.x - p1.x;
+ const float dy = p2.y - p1.y;
+ const float dz = p2.z - p1.z;
+ return (dx*dx + dy*dy) < r*r && fabsf(dz) < h;
}
#endif
diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp
index ebf3878..f7bb443 100644
--- a/src/game/TargetedMovementGenerator.cpp
+++ b/src/game/TargetedMovementGenerator.cpp
@@ -79,18 +79,34 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
// and then has the wrong z to use when creature try follow unit in the air.
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
z = i_target->GetPositionZ();
-
+
if(!i_path)
i_path = new PathInfo(&owner, x, y, z);
else
i_path->Update(x, y, z);
- // we always have a path to the target - shortcut in worst case
- // even is this map don't have mmaps at all
i_path->getNextPosition(x, y, z);
+
+ PointPath myPath = i_path->getFullPath();
+ uint32 pathStartPointer = i_path->getPathPointer();
+ uint32 actualPathLength = myPath.size() - pathStartPointer;
+ if(pathPointsSent > 0)
+ --pathPointsSent;
+
+ bool sendPath = (actualPathLength > 5 && !pathPointsSent);
Traveller<T> traveller(owner);
- i_destinationHolder.SetDestination(traveller, x, y, z);
+ i_destinationHolder.SetDestination(traveller, x, y, z, !sendPath);
+
+ if(sendPath)
+ {
+ uint32 pathEndPointer = pathStartPointer + uint32(actualPathLength*0.6f + 0.6f);
+ float speed = traveller.Speed()*0.001f; // in ms
+ uint32 traveltime = uint32(myPath.GetTotalLength(pathStartPointer, pathEndPointer)/speed);
+ SplineFlags flags = (owner.GetTypeId() == TYPEID_UNIT) ? ((Creature*)&owner)->GetSplineFlags() : SPLINEFLAG_WALKMODE;
+ owner.SendMonsterMoveByPath(myPath, pathStartPointer, pathEndPointer, flags, traveltime);
+ pathPointsSent = pathEndPointer - pathStartPointer;
+ }
D::_addUnitStateMove(owner);
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
@@ -174,25 +190,28 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_
// put targeted movement generators on a higher priority
if (owner.GetObjectBoundingRadius())
- i_destinationHolder.ResetUpdate(100);
+ i_destinationHolder.ResetUpdate(50);
float dist = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
bool targetMoved = false, needNewDest = false;
- float end_x, end_y, end_z;
- float next_x = i_target->GetPositionX();
- float next_y = i_target->GetPositionY();
- float next_z = i_target->GetPositionZ();
+ PathNode next_point(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ());
if(i_path)
{
- i_path->getNextPosition(next_x, next_y, next_z);
- i_path->getEndPosition(end_x, end_y, end_z);
-
- needNewDest = i_destinationHolder.HasArrived() && !isSamePoint(dist, next_x, next_y, next_z, end_x, end_y, end_z);
- targetMoved = i_target->GetDistanceSqr(end_x, end_y, end_z) >= dist*dist;
+ PathNode end_point = i_path->getEndPosition();
+ next_point = i_path->getNextPosition();
+
+ needNewDest = i_destinationHolder.HasArrived() && !inRange(next_point, end_point, dist, 2*dist);
+
+ // current code in GetClosePoint() will always return ground level for non-flying creatures
+ // if the the target is flying, targetMoved will always be set due to 3d out of range check
+ if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly())
+ targetMoved = i_target->GetDistanceSqr(end_point.x, end_point.y, end_point.z) >= dist*dist;
+ else
+ targetMoved = i_target->GetDistance2d(end_point.x, end_point.y) >= dist;
}
if (!i_path || targetMoved || needNewDest)
@@ -202,22 +221,22 @@ bool TargetedMovementGeneratorMedium<T,D>::Update(T &owner, const uint32 & time_
if(i_path)
{
- i_path->getNextPosition(next_x, next_y, next_z);
+ next_point = i_path->getNextPosition();
// Set new Angle For Map::
- owner.SetOrientation(owner.GetAngle(next_x, next_y));
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
}
}
// Update the Angle of the target only for Map::, no need to send packet for player
- else if (!i_angle && !owner.HasInArc(0.01f, next_x, next_y))
- owner.SetOrientation(owner.GetAngle(next_x, next_y));
+ else if (!i_angle && !owner.HasInArc(0.01f, next_point.x, next_point.y))
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
if ((owner.IsStopped() && !i_destinationHolder.HasArrived()) || i_recalculateTravel)
{
i_recalculateTravel = false;
//Angle update will take place into owner.StopMoving()
- owner.SetOrientation(owner.GetAngle(next_x, next_y));
+ owner.SetOrientation(owner.GetAngle(next_point.x, next_point.y));
owner.StopMoving();
static_cast<D*>(this)->_reachTarget(owner);
diff --git a/src/game/TargetedMovementGenerator.h b/src/game/TargetedMovementGenerator.h
index 8a8d918..d0423f8 100644
--- a/src/game/TargetedMovementGenerator.h
+++ b/src/game/TargetedMovementGenerator.h
@@ -40,11 +40,11 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
{
protected:
TargetedMovementGeneratorMedium()
- : TargetedMovementGeneratorBase(), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL) {}
+ : TargetedMovementGeneratorBase(), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {}
TargetedMovementGeneratorMedium(Unit &target)
- : TargetedMovementGeneratorBase(target), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL) {}
+ : TargetedMovementGeneratorBase(target), i_offset(0), i_angle(0), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {}
TargetedMovementGeneratorMedium(Unit &target, float offset, float angle)
- : TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), i_recalculateTravel(false), i_path(NULL) {}
+ : TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), i_recalculateTravel(false), i_path(NULL), pathPointsSent(0) {}
~TargetedMovementGeneratorMedium() { delete i_path; }
public:
@@ -71,6 +71,7 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
bool i_recalculateTravel;
PathInfo* i_path;
+ uint32 pathPointsSent;
};
template<class T>
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 4fda849..30f3200 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -1429,7 +1429,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
template<typename PathElem, typename PathNode>
- void SendMonsterMoveByPath(Path<PathElem,PathNode> const& path, uint32 start, uint32 end, SplineFlags flags);
+ void SendMonsterMoveByPath(Path<PathElem,PathNode> const& path, uint32 start, uint32 end, SplineFlags flags, uint32 traveltime);
void SendHighestThreatUpdate(HostileReference* pHostileReference);
void SendThreatClear();
@@ -2029,11 +2029,20 @@ bool Unit::CheckAllControlledUnits(Func const& func, bool withTotems, bool withG
}
template<typename Elem, typename Node>
-inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 start, uint32 end, SplineFlags flags)
+inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 start, uint32 end, SplineFlags flags, uint32 traveltime)
{
- uint32 traveltime = uint32(path.GetTotalLength(start, end) * 32);
-
uint32 pathSize = end - start;
+ if(!pathSize || !traveltime)
+ {
+ SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_STOP, flags, 0);
+ return;
+ }
+
+ if(pathSize < 3)
+ {
+ SendMonsterMove(path[pathSize-1].x, path[pathSize-1].y, path[pathSize-1].z, SPLINETYPE_NORMAL, flags, traveltime);
+ return;
+ }
WorldPacket data( SMSG_MONSTER_MOVE, (GetPackGUID().size()+1+4+4+4+4+1+4+4+4+pathSize*4*3) );
data << GetPackGUID();
@@ -2047,12 +2056,18 @@ inline void Unit::SendMonsterMoveByPath(Path<Elem,Node> const& path, uint32 star
data << uint32(traveltime);
data << uint32(pathSize);
- for(uint32 i = start; i < end; ++i)
- {
- data << float(path[i].x);
- data << float(path[i].y);
- data << float(path[i].z);
- }
+ // destination
+ data << path[end-1].x;
+ data << path[end-1].y;
+ data << path[end-1].z;
+
+ // all other points are relative
+ float mid_X = (path[start].x + path[end-1].x ) * 0.5f;
+ float mid_Y = (path[start].y + path[end-1].y ) * 0.5f;
+ float mid_Z = (path[start].z + path[end-1].z ) * 0.5f;
+
+ for(uint32 i = start; i < end-1; ++i)
+ data.appendPackXYZ(mid_X - path[i].x, mid_Y - path[i].y, mid_Z - path[i].z);
SendMessageToSet(&data, true);
}
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 6a9aa05..ddbf992 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -368,7 +368,10 @@ void FlightPathMovementGenerator::Reset(Player & player)
// do not send movement, it was sent already
i_destinationHolder.SetDestination(traveller, (*i_path)[i_currentNode].x, (*i_path)[i_currentNode].y, (*i_path)[i_currentNode].z, false);
- player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(), SplineFlags(SPLINEFLAG_WALKMODE|SPLINEFLAG_FLYING));
+ TaxiPathNodeList path = GetPath();
+ uint32 pathEndPoint = GetPathAtMapEnd();
+ uint32 traveltime = uint32(32.0f*path.GetTotalLength(GetCurrentNode(),pathEndPoint));
+ player.SendMonsterMoveByPath(path,GetCurrentNode(),pathEndPoint, SplineFlags(SPLINEFLAG_WALKMODE|SPLINEFLAG_FLYING), traveltime );
}
bool FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment