From c6e0cc9cef629e15272c86f94a89550321171745 Mon Sep 17 00:00:00 2001 From: bash Date: Sun, 31 May 2026 15:38:45 +0200 Subject: [PATCH] refactor(Core/Travel): Simplify transport config to TransportSkipRide bool; drop mode-0 deck-walk approximations --- conf/playerbots.conf.dist | 15 +- src/Ai/Base/Actions/MovementActions.cpp | 183 +++++------------------- src/Mgr/Travel/TravelNode.cpp | 14 +- src/PlayerbotAIConfig.cpp | 2 +- src/PlayerbotAIConfig.h | 11 +- 5 files changed, 59 insertions(+), 166 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 84dd0c852..ab503ded5 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1065,14 +1065,15 @@ AiPlayerbot.EnableNewRpgStrategy = 1 # Default: 0 (disabled) AiPlayerbot.EnableTravelNodes = 0 -# Transport handling mode (travel node graph only): -# 0 = bot walks to dock, boards transport, rides, walks off (fully physical) -# 1 = same as 0, but if walk-on/off fails the boarding teleports the bot -# 2 = bot teleports across the route, skipping the ride entirely -# Reference default is 0; raise only if invisible/random-bot mass travel -# performance becomes an issue. +# Transport ride mode (travel node graph only): +# 0 = bot walks to dock, teleport-snaps onto transport, rides, teleport-snaps off +# 1 = bot teleports directly across the transport route, skipping the ride +# Default 0 is the visible behavior. Set to 1 for invisible/random-bot mass +# travel performance — the bot never actually boards anything. +# (AC has no transport-surface mmap, so an on-deck walking mode can't be +# faithfully implemented; the on-board phase always teleport-snaps.) # Default: 0 -AiPlayerbot.TransportTeleportType = 0 +AiPlayerbot.TransportSkipRide = 0 # Control probability weights for RPG status of bots. Takes effect only when the status meets its premise.​ # Sum of weights need not be 100. Set to 0 to disable the status. diff --git a/src/Ai/Base/Actions/MovementActions.cpp b/src/Ai/Base/Actions/MovementActions.cpp index 515c0ac86..540a54801 100644 --- a/src/Ai/Base/Actions/MovementActions.cpp +++ b/src/Ai/Base/Actions/MovementActions.cpp @@ -3145,47 +3145,20 @@ bool MovementAction::WaitForTransport() return false; // Disembark: head is the transport node where we should get off, - // next is the world-position dock to land at. Reference UseTransport - // with doTeleport=(transportTeleportType > 0) routes to either - // MoveOffTransport-teleport (mode 1+) or MoveOffTransport-walk (mode 0). - PathNodePoint const& dock = path[0]; + // next is the world-position dock to land at. if (path.size() < 2) return true; // no telePoint to land at; keep waiting PathNodePoint const& tele = path[1]; - (void)dock; // kept for reference parity (UseTransport signature) transport->RemovePassenger(bot); - - if (sPlayerbotAIConfig.transportTeleportType > 0) - { - // Mode 1+: teleport directly to exit. - bot->StopMovingOnCurrentPos(); - bool const teleported = bot->TeleportTo(tele.point.GetMapId(), - tele.point.GetPositionX(), - tele.point.GetPositionY(), - tele.point.GetPositionZ(), - bot->GetOrientation()); - if (!teleported) - return true; // try again next tick - lastMove.lastTransportEntry = 0; - return false; - } - - // Mode 0: NearTeleportTo current world position (drops bot off - // transport plane to world coords without unloading client), then - // walk to the exit position. Matches reference MoveOffTransport - // with doTeleport=false. - bot->NearTeleportTo(bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), bot->GetOrientation()); - - if (MotionMaster* mm = bot->GetMotionMaster()) - { - mm->Clear(); - mm->MovePoint(0, tele.point.GetPositionX(), - tele.point.GetPositionY(), - tele.point.GetPositionZ(), - FORCED_MOVEMENT_RUN, 0.0f, 0.0f, true, false); - } + bot->StopMovingOnCurrentPos(); + bool const teleported = bot->TeleportTo(tele.point.GetMapId(), + tele.point.GetPositionX(), + tele.point.GetPositionY(), + tele.point.GetPositionZ(), + bot->GetOrientation()); + if (!teleported) + return true; // try again next tick lastMove.lastTransportEntry = 0; return false; @@ -3274,10 +3247,7 @@ bool MovementAction::HandleSpecialMovement(TravelPath& path) case PathNodeType::NODE_TRANSPORT: { // Disembark: head is a transport node and bot is on one. - // Reference dispatch: MoveOffTransport(exit, doTeleport) where - // doTeleport = (transportTeleportType > 0). Mode 1+ teleports - // straight to exit; mode 0 NearTeleports off transport plane - // then walks to exit. + // RemovePassenger + TeleportTo the next-step world position. if (!hasNext) return false; @@ -3287,35 +3257,14 @@ bool MovementAction::HandleSpecialMovement(TravelPath& path) PathNodePoint const& dst = path[1]; transport->RemovePassenger(bot); - - if (sPlayerbotAIConfig.transportTeleportType > 0) - { - bot->StopMovingOnCurrentPos(); - bool const teleported = bot->TeleportTo(dst.point.GetMapId(), - dst.point.GetPositionX(), - dst.point.GetPositionY(), - dst.point.GetPositionZ(), - bot->GetOrientation()); - AI_VALUE(LastMovement&, "last movement").lastTransportEntry = 0; - return teleported; - } - - // Mode 0: NearTeleportTo current world pos (drops bot off - // transport plane without unloading the client), then walk - // to the exit. - bot->NearTeleportTo(bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), bot->GetOrientation()); - - if (MotionMaster* mm = bot->GetMotionMaster()) - { - mm->Clear(); - mm->MovePoint(0, dst.point.GetPositionX(), - dst.point.GetPositionY(), - dst.point.GetPositionZ(), - FORCED_MOVEMENT_RUN, 0.0f, 0.0f, true, false); - } + bot->StopMovingOnCurrentPos(); + bool const teleported = bot->TeleportTo(dst.point.GetMapId(), + dst.point.GetPositionX(), + dst.point.GetPositionY(), + dst.point.GetPositionZ(), + bot->GetOrientation()); AI_VALUE(LastMovement&, "last movement").lastTransportEntry = 0; - return true; + return teleported; } default: @@ -3527,87 +3476,29 @@ bool MovementAction::BoardTransport(Transport* transport) return true; } - // Teleport-onto mode (transportTeleportType >= 1): skip the walk-toward - // phase and jump directly to a boarding edge. Matches reference's - // MoveOnTransport(doTeleport=true) — PlayerRelocation + AddPassenger. - if (sPlayerbotAIConfig.transportTeleportType >= 1) - { - float edgeX, edgeY, edgeZ; - if (FindBoardingPointOnTransport(map, transport, transport, - transport->GetPositionX(), transport->GetPositionY(), - transport->GetPositionZ(), - bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), - edgeX, edgeY, edgeZ)) - { - if (bot->TeleportTo(map->GetId(), edgeX, edgeY, edgeZ, bot->GetOrientation())) - { - transport->AddPassenger(bot, true); - bot->StopMovingOnCurrentPos(); - EmitDebugMove("Transport:board", "teleport-skip-walk", - edgeX, edgeY, edgeZ); - return true; - } - } - // Fall through to mode-0 if no boarding point — better than refusing. - } - - // Mode 0: reference MoveOnTransport(doTeleport=false) — AddPassenger - // FIRST (snaps bot onto transport plane), then walk a path on deck. - // We don't have RandomPointOnTrans / transport-surface mmap, so when - // the bot is within INTERACTION_DISTANCE of the transport's boarding - // edge we approximate: AddPassenger + MovePoint toward the transport - // center as a "deck destination." Bot motion is then transport- - // relative because of the AddPassenger. - float boardX = transport->GetPositionX(); - float boardY = transport->GetPositionY(); - float boardZ = transport->GetPositionZ(); - + // Bot off transport: find a boarding edge and teleport-snap directly + // onto it, then AddPassenger. We can't walk on the deck (no transport- + // surface mmap), so the snap-board is the only universal approach. float edgeX, edgeY, edgeZ; - bool haveEdge = FindBoardingPointOnTransport(map, transport, transport, - transport->GetPositionX(), transport->GetPositionY(), - transport->GetPositionZ(), bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), edgeX, edgeY, edgeZ); - if (haveEdge) + if (!FindBoardingPointOnTransport(map, transport, transport, + transport->GetPositionX(), transport->GetPositionY(), + transport->GetPositionZ(), + bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), + edgeX, edgeY, edgeZ)) { - boardX = edgeX; - boardY = edgeY; - boardZ = edgeZ; + // No boarding edge found — wait a tick. Caller's WaitForReach + // upstream throttles the retry. + EmitDebugMove("Transport:board", "no-edge", + transport->GetPositionX(), transport->GetPositionY(), + transport->GetPositionZ()); + return false; } - float const dxBoard = bot->GetPositionX() - boardX; - float const dyBoard = bot->GetPositionY() - boardY; - bool const nearBoardingPoint = - (dxBoard * dxBoard + dyBoard * dyBoard) < - INTERACTION_DISTANCE * INTERACTION_DISTANCE; + if (!bot->TeleportTo(map->GetId(), edgeX, edgeY, edgeZ, bot->GetOrientation())) + return false; - if (nearBoardingPoint) - { - // Snap onto transport plane, then walk a short deck path so the - // bot is visibly on the boat (mirrors reference mode-0 deck walk). - transport->AddPassenger(bot, true); - if (MotionMaster* mm = bot->GetMotionMaster()) - { - if (!bot->IsStandState()) - bot->SetStandState(UNIT_STAND_STATE_STAND); - mm->Clear(); - mm->MovePoint(0, transport->GetPositionX(), transport->GetPositionY(), - transport->GetPositionZ(), - FORCED_MOVEMENT_RUN, 0.0f, 0.0f, false, false); - } - EmitDebugMove("Transport:board", "snap-and-deck-walk", - boardX, boardY, boardZ); - return true; - } - - // Too far to snap — walk toward boarding edge. - if (MotionMaster* mm = bot->GetMotionMaster()) - { - if (!bot->IsStandState()) - bot->SetStandState(UNIT_STAND_STATE_STAND); - mm->MovePoint(0, boardX, boardY, boardZ, - FORCED_MOVEMENT_NONE, 0.0f, 0.0f, false, false); - EmitDebugMove("Transport:walk", "approach-boarding", boardX, boardY, boardZ); - } - - return false; + transport->AddPassenger(bot, true); + bot->StopMovingOnCurrentPos(); + EmitDebugMove("Transport:board", "snap", edgeX, edgeY, edgeZ); + return true; } diff --git a/src/Mgr/Travel/TravelNode.cpp b/src/Mgr/Travel/TravelNode.cpp index a68109986..6afed6a5b 100644 --- a/src/Mgr/Travel/TravelNode.cpp +++ b/src/Mgr/Travel/TravelNode.cpp @@ -927,9 +927,9 @@ bool TravelPath::UpcommingSpecialMovement(WorldPosition startPos, return true; } - // Walk-on / teleport-to-transport boarding mode (modes 0 and 1). - // Cut to dock if off-transport, traverse to disembark if on-transport. - if (sPlayerbotAIConfig.transportTeleportType < 2 && + // Board-and-ride mode (transportSkipRide == false). Cut to dock if + // off-transport, traverse to disembark if on-transport. + if (!sPlayerbotAIConfig.transportSkipRide && startP->type == PathNodeType::NODE_TRANSPORT) { uint32 const entry = nextP->entry; @@ -954,11 +954,11 @@ bool TravelPath::UpcommingSpecialMovement(WorldPosition startPos, } } - // Teleport-across mode (mode 2): bot is approaching a transport - // node — walk forward to find the first non-transport node (the - // disembark side), cut to prevP (last transport node) so + // Skip-ride mode (transportSkipRide == true): bot is approaching a + // transport node — walk forward to find the first non-transport node + // (the disembark side), cut to prevP (last transport node) so // HandleSpecialMovement teleports the bot across directly. - if (sPlayerbotAIConfig.transportTeleportType == 2 && + if (sPlayerbotAIConfig.transportSkipRide && nextP->type == PathNodeType::NODE_TRANSPORT) { for (auto p = std::next(startP); p != fullPath.end(); ++p) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index e2b7c5390..ee98ae3ed 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -88,7 +88,7 @@ bool PlayerbotAIConfig::Initialize() farDistance = sConfigMgr->GetOption("AiPlayerbot.FarDistance", 20.0f); sightDistance = sConfigMgr->GetOption("AiPlayerbot.SightDistance", 100.0f); - transportTeleportType = sConfigMgr->GetOption("AiPlayerbot.TransportTeleportType", 0); + transportSkipRide = sConfigMgr->GetOption("AiPlayerbot.TransportSkipRide", false); spellDistance = sConfigMgr->GetOption("AiPlayerbot.SpellDistance", 28.5f); shootDistance = sConfigMgr->GetOption("AiPlayerbot.ShootDistance", 5.0f); healDistance = sConfigMgr->GetOption("AiPlayerbot.HealDistance", 38.5f); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 7fff4b661..5fbd014ed 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -93,11 +93,12 @@ public: bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat; uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, expireActionTime, dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay; - // Transport handling mode (matches reference `transportTeleportType`): - // 0 = walk on board, walk off (default, fully physical) - // 1 = walk on board, but UseTransport teleports on/off if walk fails - // 2 = skip the ride entirely — teleport directly across the route - uint32 transportTeleportType; + // Transport handling: + // false (default) = teleport-board, ride the transport, teleport-disembark + // true = skip the ride entirely (teleport directly across) + // AC has no transport-surface mmap so an in-deck walking mode can't be + // faithfully implemented — the on-board phase always teleport-snaps. + bool transportSkipRide; bool dynamicReactDelay; float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance, tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance, aoeRadius, rpgDistance,