diff options
| -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/server/scripts/Spells/spell_warrior.cpp | 10 | ||||
| -rw-r--r-- | src/tools/mmaps_generator/MapBuilder.cpp | 2 |
7 files changed, 106 insertions, 127 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 5e24ce2d606..0026d42a968 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -3211,10 +3211,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(); @@ -3224,7 +3225,9 @@ void WorldObject::MovePositionToFirstCollision(Position &pos, float dist, float // check static LOS float halfHeight = GetCollisionHeight() * 0.5f; - bool col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY), + bool col; + /* + col = VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(PhasingHandler::GetTerrainMapId(GetPhaseShift(), GetMap(), pos.m_positionX, pos.m_positionY), pos.m_positionX, pos.m_positionY, pos.m_positionZ + halfHeight, destx, desty, destz + halfHeight, destx, desty, destz, -0.5f); @@ -3238,6 +3241,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(GetPhaseShift(), diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 593a347f424..77d59afdbad 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -30,7 +30,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) { @@ -54,7 +54,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); @@ -71,7 +71,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()); @@ -156,6 +155,7 @@ dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) return polyRef; } + *distance = FLT_MAX; return INVALID_POLYREF; } @@ -170,6 +170,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 @@ -195,8 +197,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 @@ -234,10 +246,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; } @@ -253,10 +262,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); } } @@ -264,9 +270,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; @@ -274,10 +281,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; @@ -376,39 +380,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 { @@ -448,7 +425,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con Clear(); dtStatus dtResult; - if (_straightLine) + if (_useRaycast) { float hit = 0; float hitNormal[3]; @@ -465,24 +442,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 { @@ -513,10 +523,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); @@ -527,37 +534,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) { @@ -841,7 +824,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; @@ -1041,3 +1024,11 @@ bool PathGenerator::IsInvalidDestinationZ(WorldObject 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 769e396c3a1..64ad8393436 100644 --- a/src/server/game/Movement/PathGenerator.h +++ b/src/server/game/Movement/PathGenerator.h @@ -60,12 +60,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(WorldObject 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; } @@ -90,7 +91,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 @@ -136,6 +137,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 66ec7cbad4d..7632a0c6993 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1422,21 +1422,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectIn 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; } case TARGET_DEST_CASTER_GROUND: @@ -5757,7 +5743,7 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32 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 20213f392d2..04d14913170 100644 --- a/src/server/scripts/Commands/cs_mmaps.cpp +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -85,9 +85,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; @@ -96,11 +96,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/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 2376a3d13fe..d008fec0db8 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -283,17 +283,11 @@ public: PathGenerator generatedPath(GetCaster()); generatedPath.SetPathLengthLimit(range); - bool result = generatedPath.CalculatePath(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), false, true); + bool result = generatedPath.CalculatePath(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), false); if (generatedPath.GetPathType() & PATHFIND_SHORT) return SPELL_FAILED_OUT_OF_RANGE; else if (!result || generatedPath.GetPathType() & PATHFIND_NOPATH) - { - result = generatedPath.CalculatePath(dest->GetPositionX(), dest->GetPositionY(), dest->GetPositionZ(), false, false); - if (generatedPath.GetPathType() & PATHFIND_SHORT) - return SPELL_FAILED_OUT_OF_RANGE; - else if (!result || generatedPath.GetPathType() & PATHFIND_NOPATH) - return SPELL_FAILED_NOPATH; - } + return SPELL_FAILED_NOPATH; } else if (dest->GetPositionZ() > GetCaster()->GetPositionZ() + 4.0f) return SPELL_FAILED_NOPATH; diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index f75d571046c..6e3adc79a04 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -986,7 +986,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) |
