From 6e17dedff2c13bcfab5ccabf380d5d00e7a8f034 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 16 Oct 2026 22:28:22 +0000 Subject: [PATCH] fix in MMAP navigation when traveling to portal node --- src/server/game/World/ClientlessTravelMgr.cpp | 58 ++++++++++++++++++- .../adventure/overrides/arthoran.lua | 2 +- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/src/server/game/World/ClientlessTravelMgr.cpp b/src/server/game/World/ClientlessTravelMgr.cpp index 773cefaaa5..f5be4e2a9f 100644 --- a/src/server/game/World/ClientlessTravelMgr.cpp +++ b/src/server/game/World/ClientlessTravelMgr.cpp @@ -125,10 +125,22 @@ bool ClientlessTravelMgr::AnalyzePath( diagnostics.FinalDistance = diagnostics.DirectDistance; uint32 const pathType = diagnostics.PathType; + // VCORE_C814A_NAVIGATION_FIX: narrowly accept a short incomplete MMAP path + // only when its actual points reach the target without unsafe segments. + bool const shortEndReached = + diagnostics.Calculated && + (pathType & uint32(PATHFIND_INCOMPLETE)) != 0 && + (pathType & uint32(PATHFIND_NOPATH)) == 0 && + diagnostics.PointCount >= 2 && + diagnostics.DirectDistance <= 25.0f && + diagnostics.PathLength <= 40.0f && + diagnostics.FinalDistance <= 0.25f && + diagnostics.MaxSegmentLength <= 6.0f && + diagnostics.MaxZDelta <= 4.0f; diagnostics.Complete = diagnostics.Calculated && (pathType & uint32(PATHFIND_NOPATH)) == 0 && - (pathType & uint32(PATHFIND_INCOMPLETE)) == 0; + ((pathType & uint32(PATHFIND_INCOMPLETE)) == 0 || shortEndReached); auto addReason = [&](char const* reason) { @@ -196,6 +208,19 @@ bool ClientlessTravelMgr::LaunchPath(Player* player, TravelRecord& record) Position const& target = record.Status.Target; + // VCORE_C814A_NAVIGATION_FIX: an already reached node is not a failed spline. + if (Distance3D(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), + target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()) <= ARRIVAL_DISTANCE) + { + record.Status.State = ClientlessTravelState::Arrived; + record.Status.RemainingDistance = 0.0f; + record.Status.NoProgressMs = 0; + TC_LOG_INFO("server.adventurebot.navigation", + "NAV_ALREADY_ARRIVED guid=%u name='%s' map=%u", + player->GetGUID().GetCounter(), player->GetName().c_str(), player->GetMapId()); + return true; + } + AnalyzePath(player, target, record.Status.Path); ClientlessPathDiagnostics const& nav = record.Status.Path; record.Status.NavSequence = _nextNavSequence++; @@ -245,9 +270,38 @@ bool ClientlessTravelMgr::LaunchPath(Player* player, TravelRecord& record) auto const& points = path.GetPath(); uint32 const executionType = uint32(path.GetPathType()); + // VCORE_C814A_NAVIGATION_FIX: confirm the execution path independently. + float executionLength = 0.0f; + float executionMaxSegment = 0.0f; + float executionMaxZ = 0.0f; + for (std::size_t i = 1; i < points.size(); ++i) + { + float const segment = Distance3D(points[i-1].x, points[i-1].y, points[i-1].z, + points[i].x, points[i].y, points[i].z); + executionLength += segment; + executionMaxSegment = std::max(executionMaxSegment, segment); + executionMaxZ = std::max(executionMaxZ, std::fabs(points[i].z - points[i-1].z)); + } + float const executionFinalDistance = points.empty() ? nav.DirectDistance : + Distance3D(points.back().x, points.back().y, points.back().z, + target.GetPositionX(), target.GetPositionY(), target.GetPositionZ()); + bool const executionShortEndReached = + (executionType & uint32(PATHFIND_INCOMPLETE)) != 0 && + (executionType & uint32(PATHFIND_NOPATH)) == 0 && + points.size() >= 2 && + nav.DirectDistance <= 25.0f && + executionLength <= 40.0f && + executionFinalDistance <= 0.25f && + executionMaxSegment <= 6.0f && + executionMaxZ <= 4.0f; + if (executionShortEndReached) + TC_LOG_INFO("server.adventurebot.navigation", + "NAV_SHORT_INCOMPLETE_ACCEPT guid=%u name='%s' path=%.2f final=%.2f", + player->GetGUID().GetCounter(), player->GetName().c_str(), + executionLength, executionFinalDistance); if (points.size() < 2 || (executionType & uint32(PATHFIND_NOPATH)) != 0 || - (executionType & uint32(PATHFIND_INCOMPLETE)) != 0) + ((executionType & uint32(PATHFIND_INCOMPLETE)) != 0 && !executionShortEndReached)) { record.Status.State = ClientlessTravelState::PathRejected; TC_LOG_WARN("server.adventurebot.navigation", diff --git a/src/server/scripts/Custom/clientless/adventure/overrides/arthoran.lua b/src/server/scripts/Custom/clientless/adventure/overrides/arthoran.lua index 4fa368de31..5f23650e5a 100644 --- a/src/server/scripts/Custom/clientless/adventure/overrides/arthoran.lua +++ b/src/server/scripts/Custom/clientless/adventure/overrides/arthoran.lua @@ -12,7 +12,7 @@ log("Arthoran C8.13b bridge test loaded") --}) queue_action("travel_to_node", { - node = "portal_at_2173_target", + node = "lakeshire", bridge_radius = 400, bridge_path_max = 600 }) \ No newline at end of file