diff options
-rw-r--r-- | src/common/Collision/Maps/MapDefines.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Movement/PathGenerator.cpp | 175 | ||||
-rw-r--r-- | src/server/game/Movement/PathGenerator.h | 7 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 18 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_mmaps.cpp | 11 | ||||
-rw-r--r-- | src/tools/mmaps_generator/MapBuilder.cpp | 2 |
7 files changed, 105 insertions, 120 deletions
diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h index 50f7e93e4c3..d433b381cc8 100644 --- a/src/common/Collision/Maps/MapDefines.h +++ b/src/common/Collision/Maps/MapDefines.h @@ -22,7 +22,7 @@ #include "DetourNavMesh.h" const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP' -#define MMAP_VERSION 9 +#define MMAP_VERSION 10 struct MmapTileHeader { diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index c6597a22e5f..3d132c31679 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3272,10 +3272,11 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float // Use a detour raycast to get our first collision point PathGenerator path(this); - path.CalculatePath(destx, desty, destz, false, true); + path.SetUseRaycast(true); + path.CalculatePath(destx, desty, destz, false); // We have a invalid path result. Skip further processing. - if (path.GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END)) + if (path.GetPathType() & ~(PATHFIND_NORMAL | PATHFIND_SHORTCUT | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END | PATHFIND_NOT_USING_PATH)) return; G3D::Vector3 result = path.GetPath().back(); @@ -3285,7 +3286,9 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float // check static LOS float halfHeight = GetCollisionHeight() * 0.5f; - bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(), + bool col; + /* + col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(), pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight, destx, desty, destz + halfHeight, destx, desty, destz, -0.5f); @@ -3299,6 +3302,7 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float desty -= CONTACT_DISTANCE * std::sin(angle); dist = std::sqrt((pos.m_positionX - destx) * (pos.m_positionX - destx) + (pos.m_positionY - desty) * (pos.m_positionY - desty)); } + */ // check dynamic collision col = GetMap()->getObjectHitPos(GetPhaseMask(), diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 5402cb8e33a..af6b8b0b30c 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -29,7 +29,7 @@ ////////////////// PathGenerator ////////////////// PathGenerator::PathGenerator(WorldObject const* owner) : _polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false), - _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH), _straightLine(false), + _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH), _useRaycast(false), _endPosition(G3D::Vector3::zero()), _source(owner), _navMesh(nullptr), _navMeshQuery(nullptr) { @@ -53,7 +53,7 @@ PathGenerator::~PathGenerator() TC_LOG_DEBUG("maps.mmaps", "++ PathGenerator::~PathGenerator() for %s", _source->GetGUID().ToString().c_str()); } -bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest, bool straightLine) +bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest) { float x, y, z; _source->GetPosition(x, y, z); @@ -70,7 +70,6 @@ bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool fo SetStartPosition(start); _forceDestination = forceDest; - _straightLine = straightLine; TC_LOG_DEBUG("maps.mmaps", "++ PathGenerator::CalculatePath() for %s", _source->GetGUID().ToString().c_str()); @@ -155,6 +154,7 @@ dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) return polyRef; } + *distance = FLT_MAX; return INVALID_POLYREF; } @@ -169,6 +169,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly); dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly); + _type = PathType(PATHFIND_NORMAL); + // we have a hole in our mesh // make shortcut path and mark it as NOPATH ( with flying and swimming exception ) // its up to caller how he will use this info @@ -194,8 +196,18 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con } } - _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; - return; + if (path || waterPath) + { + _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); + return; + } + + // raycast doesn't need endPoly to be valid + if (!_useRaycast) + { + _type = PATHFIND_NOPATH; + return; + } } // we may need a better number here @@ -233,10 +245,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con BuildShortcut(); _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); - if (startFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_START); - if (endFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_END); + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); return; } @@ -252,10 +261,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con _type = PathType(PATHFIND_INCOMPLETE); - if (startFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_START); - if (endFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_END); + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); } } @@ -263,9 +269,10 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con // start and end are on same polygon // handle this case as if they were 2 different polygons, building a line path split in some few points - if (startPoly == endPoly) + if (startPoly == endPoly && !_useRaycast) { TC_LOG_DEBUG("maps.mmaps", "++ BuildPolyPath :: (startPoly == endPoly)"); + _pathPolyRefs[0] = startPoly; _polyLength = 1; @@ -273,10 +280,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con { _type = PathType(PATHFIND_INCOMPLETE); - if (startFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_START); - if (endFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_END); + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); } else _type = PATHFIND_NORMAL; @@ -375,39 +379,12 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con uint32 suffixPolyLength = 0; dtStatus dtResult; - if (_straightLine) + if (_useRaycast) { - float hit = 0; - float hitNormal[3]; - memset(hitNormal, 0, sizeof(hitNormal)); - - dtResult = _navMeshQuery->raycast( - suffixStartPoly, - suffixEndPoint, - endPoint, - &_filter, - &hit, - hitNormal, - _pathPolyRefs + prefixPolyLength - 1, - (int*)&suffixPolyLength, - MAX_PATH_LENGTH - prefixPolyLength); - - // raycast() sets hit to FLT_MAX if there is a ray between start and end - if (hit != FLT_MAX) - { - // the ray hit something, return no path instead of the incomplete one - Clear(); - _polyLength = 2; - _pathPoints.resize(2); - _pathPoints[0] = GetStartPosition(); - float hitPos[3]; - dtVlerp(hitPos, startPoint, endPoint, hit); - _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]); - - NormalizePath(); - _type = PATHFIND_INCOMPLETE; - return; - } + TC_LOG_ERROR("maps.mmaps", "PathGenerator::BuildPolyPath() called with _useRaycast with a previous path for unit %s", _source->GetGUID().ToString().c_str()); + BuildShortcut(); + _type = PATHFIND_NOPATH; + return; } else { @@ -447,7 +424,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con Clear(); dtStatus dtResult; - if (_straightLine) + if (_useRaycast) { float hit = 0; float hitNormal[3]; @@ -464,24 +441,57 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con (int*)&_polyLength, MAX_PATH_LENGTH); + if (!_polyLength || dtStatusFailed(dtResult)) + { + BuildShortcut(); + _type = PATHFIND_NOPATH; + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); + return; + } + // raycast() sets hit to FLT_MAX if there is a ray between start and end if (hit != FLT_MAX) { - // the ray hit something, return no path instead of the incomplete one - Clear(); - _polyLength = 2; - _pathPoints.resize(2); - _pathPoints[0] = GetStartPosition(); float hitPos[3]; + + // Walk back a bit from the hit point to make sure it's in the mesh (sometimes the point is actually outside of the polygons due to float precision issues) + hit *= 0.99f; dtVlerp(hitPos, startPoint, endPoint, hit); + + // if it fails again, clamp to poly boundary + if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], hitPos, &hitPos[1]))) + _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], hitPos, hitPos); + + _pathPoints.resize(2); + _pathPoints[0] = GetStartPosition(); _pathPoints[1] = G3D::Vector3(hitPos[2], hitPos[0], hitPos[1]); NormalizePath(); _type = PATHFIND_INCOMPLETE; + AddFarFromPolyFlags(startFarFromPoly, false); return; } else - _navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, &endPoint[1]); + { + // clamp to poly boundary if we fail to get the height + if (dtStatusFailed(_navMeshQuery->getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, &endPoint[1]))) + _navMeshQuery->closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], endPoint, endPoint); + + _pathPoints.resize(2); + _pathPoints[0] = GetStartPosition(); + _pathPoints[1] = G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]); + + NormalizePath(); + if (startFarFromPoly || endFarFromPoly) + { + _type = PathType(PATHFIND_INCOMPLETE); + + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); + } + else + _type = PATHFIND_NORMAL; + return; + } } else { @@ -512,10 +522,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con else _type = PATHFIND_INCOMPLETE; - if (startFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_START); - if (endFarFromPoly) - _type = PathType(_type | PATHFIND_FARFROMPOLY_END); + AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly); // generate the point-path out of our up-to-date poly-path BuildPointPath(startPoint, endPoint); @@ -526,37 +533,13 @@ void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoin float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE]; uint32 pointCount = 0; dtStatus dtResult = DT_FAILURE; - if (_straightLine) + if (_useRaycast) { - dtResult = DT_SUCCESS; - pointCount = 1; - memcpy(&pathPoints[VERTEX_SIZE * 0], startPoint, sizeof(float)* 3); // first point - - // path has to be split into polygons with dist SMOOTH_PATH_STEP_SIZE between them - G3D::Vector3 startVec = G3D::Vector3(startPoint[0], startPoint[1], startPoint[2]); - G3D::Vector3 endVec = G3D::Vector3(endPoint[0], endPoint[1], endPoint[2]); - G3D::Vector3 diffVec = (endVec - startVec); - G3D::Vector3 prevVec = startVec; - float len = diffVec.length(); - diffVec *= SMOOTH_PATH_STEP_SIZE / len; - - // If the path is short PATHFIND_SHORT will be set as type - while (len > SMOOTH_PATH_STEP_SIZE && pointCount < MAX_POINT_PATH_LENGTH) - { - len -= SMOOTH_PATH_STEP_SIZE; - prevVec += diffVec; - pathPoints[VERTEX_SIZE * pointCount + 0] = prevVec.x; - pathPoints[VERTEX_SIZE * pointCount + 1] = prevVec.y; - pathPoints[VERTEX_SIZE * pointCount + 2] = prevVec.z; - ++pointCount; - } - - // If the path is short PATHFIND_SHORT will be set as type - if (pointCount < MAX_POINT_PATH_LENGTH) - { - memcpy(&pathPoints[VERTEX_SIZE * pointCount], endPoint, sizeof(float) * 3); // last point - ++pointCount; - } + // _straightLine uses raycast and it currently doesn't support building a point path, only a 2-point path with start and hitpoint/end is returned + TC_LOG_ERROR("maps.mmaps", "PathGenerator::BuildPointPath() called with _useRaycast for unit %s", _source->GetGUID().ToString().c_str()); + BuildShortcut(); + _type = PATHFIND_NOPATH; + return; } else if (_useStraightPath) { @@ -839,7 +822,7 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo if (polyPathSize > 1) { - // Pick the closest poitns on poly border + // Pick the closest points on poly border if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos))) return DT_FAILURE; @@ -1039,3 +1022,11 @@ bool PathGenerator::IsInvalidDestinationZ(Unit const* target) const { return (target->GetPositionZ() - GetActualEndPosition().z) > 5.0f; } + +void PathGenerator::AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly) +{ + if (startFarFromPoly) + _type = PathType(_type | PATHFIND_FARFROMPOLY_START); + if (endFarFromPoly) + _type = PathType(_type | PATHFIND_FARFROMPOLY_END); +} diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h index d739dd19872..5c518100d6a 100644 --- a/src/server/game/Movement/PathGenerator.h +++ b/src/server/game/Movement/PathGenerator.h @@ -61,12 +61,13 @@ class TC_GAME_API PathGenerator // Calculate the path from owner to given destination // return: true if new path was calculated, false otherwise (no change needed) - bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false, bool straightLine = false); + bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false); bool IsInvalidDestinationZ(Unit const* target) const; // option setters - use optional void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; } void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); } + void SetUseRaycast(bool useRaycast) { _useRaycast = useRaycast; } // result getters G3D::Vector3 const& GetStartPosition() const { return _startPosition; } @@ -91,7 +92,7 @@ class TC_GAME_API PathGenerator bool _useStraightPath; // type of path will be generated bool _forceDestination; // when set, we will always arrive at given point uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH) - bool _straightLine; // use raycast if true for a straight line path + bool _useRaycast; // use raycast if true for a straight line path G3D::Vector3 _startPosition; // {x, y, z} of current location G3D::Vector3 _endPosition; // {x, y, z} of the destination @@ -137,6 +138,8 @@ class TC_GAME_API PathGenerator dtStatus FindSmoothPath(float const* startPos, float const* endPos, dtPolyRef const* polyPath, uint32 polyPathSize, float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize); + + void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly); }; #endif diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 537a5971a32..60e09ef0753 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1356,21 +1356,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici Position pos = dest._position; unitCaster->MovePositionToFirstCollision(pos, dist, angle); - // Generate path to that point. - if (!m_preGeneratedPath) - m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster); - - m_preGeneratedPath->SetPathLengthLimit(dist); - - // Should we use straightline here ? What do we do when we don't have a full path ? - bool pathResult = m_preGeneratedPath->CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false, true); - if (pathResult && m_preGeneratedPath->GetPathType() & (PATHFIND_NORMAL | PATHFIND_SHORTCUT)) - { - pos.m_positionX = m_preGeneratedPath->GetActualEndPosition().x; - pos.m_positionY = m_preGeneratedPath->GetActualEndPosition().y; - pos.m_positionZ = m_preGeneratedPath->GetActualEndPosition().z; - dest.Relocate(pos); - } + dest.Relocate(pos); break; } default: @@ -5537,7 +5523,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint m_preGeneratedPath->SetPathLengthLimit(range); // first try with raycast, if it fails fall back to normal path - bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false, false); + bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false); if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT) return SPELL_FAILED_NOPATH; else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE)) diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp index 25929e5a77f..b9c2cb2591f 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -83,9 +83,9 @@ public: if (para && strcmp(para, "true") == 0) useStraightPath = true; - bool useStraightLine = false; - if (para && strcmp(para, "line") == 0) - useStraightLine = true; + bool useRaycast = false; + if (para && (strcmp(para, "line") == 0 || strcmp(para, "ray") == 0 || strcmp(para, "raycast") == 0)) + useRaycast = true; // unit locations float x, y, z; @@ -94,11 +94,12 @@ public: // path PathGenerator path(target); path.SetUseStraightPath(useStraightPath); - bool result = path.CalculatePath(x, y, z, false, useStraightLine); + path.SetUseRaycast(useRaycast); + bool result = path.CalculatePath(x, y, z, false); Movement::PointsArray const& pointPath = path.GetPath(); handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str()); - handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath"); + handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : useRaycast ? "Raycast" : "SmoothPath"); handler->PSendSysMessage("Result: %s - Length: %zu - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType()); G3D::Vector3 const& start = path.GetStartPosition(); diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index f8b4518e641..eaa60819258 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -1015,7 +1015,7 @@ namespace MMAP config.walkableHeight = m_bigBaseUnit ? 3 : 6; // a value >= 3|6 allows npcs to walk over some fences // a value >= 4|8 allows npcs to walk over all fences - config.walkableClimb = m_bigBaseUnit ? 4 : 8; + config.walkableClimb = m_bigBaseUnit ? 3 : 6; config.minRegionArea = rcSqr(60); config.mergeRegionArea = rcSqr(50); config.maxSimplificationError = 1.8f; // eliminates most jagged edges (tiny polygons) |