From 88016789ba6633a67be574df6142f65c75d6d340 Mon Sep 17 00:00:00 2001 From: privatecore Date: Thu, 25 Dec 2025 00:01:42 +0100 Subject: [PATCH] Quick fix for CMSG_FORCE_MOVE_ROOT_ACK and CMSG_FORCE_MOVE_UNROOT_ACK (#1937) **Original issue:** https://github.com/mod-playerbots/mod-playerbots/issues/1902 **Original cause:** charmed bot (with lost client control) got rooted at the same time. **How to reproduce:** 1. Spawn creatures 11350 (x3) and 11830 (x3) using the command: `.npc add ` in a quiet place. 2. Create any party with random bots or alt bots (should be 60-65 levels), make sure there is at least one healer. 3. Set the healer's mana to a high value, like 100M, using command: `.mod mana `. 4. Start the fight while continuously respawning creatures with: `.resp all`. 5. When console starts to spam 'heartbeat' messages, check your party members' movement flags to identify which one has `MOVEMENTFLAG_ROOT` 0x00000800 (2048) using the command: `.debug move`. This PR will not fix ALL 'heartbeat' issues, as `ServerFacade::SetFacingTo` still sends `SendMovementFlagUpdate` while bots can have the `MOVEMENTFLAG_ROOT` flag. --- src/PlayerbotAI.cpp | 27 +++++++++++++++---- .../actions/AcceptResurrectAction.cpp | 2 -- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 3dc85e0b..e926c68b 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -1179,7 +1179,26 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet) return; } - case SMSG_MOVE_KNOCK_BACK: // handle knockbacks + case SMSG_FORCE_MOVE_ROOT: // CMSG_FORCE_MOVE_ROOT_ACK + case SMSG_FORCE_MOVE_UNROOT: // CMSG_FORCE_MOVE_UNROOT_ACK + { + // Quick fix for CMSG_FORCE_MOVE_ROOT_ACK and CMSG_FORCE_MOVE_UNROOT_ACK: + // this should resolve issues with MOVEMENTFLAG_ROOT being permanently set + // when rooted during lost client control (charm + root effects) + // @see https://github.com/azerothcore/azerothcore-wotlk/pull/23147 + bool forceRoot = (packet.GetOpcode() == SMSG_FORCE_MOVE_ROOT); + if (forceRoot) + { + bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_MASK_MOVING_FLY); + bot->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ROOT); + bot->StopMoving(); + } + else + bot->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ROOT); + + return; + } + case SMSG_MOVE_KNOCK_BACK: // CMSG_MOVE_KNOCK_BACK_ACK { WorldPacket p(packet); p.rpos(0); @@ -1351,10 +1370,6 @@ void PlayerbotAI::DoNextAction(bool min) bool isBotAlive = bot->IsAlive(); if (currentEngine != engines[BOT_STATE_DEAD] && !isBotAlive) { - bot->StopMoving(); - bot->GetMotionMaster()->Clear(); - bot->GetMotionMaster()->MoveIdle(); - // Death Count to prevent skeleton piles // Player* master = GetMaster(); // warning here - whipowill if (!HasActivePlayerMaster() && !bot->InBattleground()) @@ -1375,6 +1390,8 @@ void PlayerbotAI::DoNextAction(bool min) // Change engine if just ressed if (currentEngine == engines[BOT_STATE_DEAD] && isBotAlive) { + bot->SendMovementFlagUpdate(); + ChangeEngine(BOT_STATE_NON_COMBAT); return; } diff --git a/src/strategy/actions/AcceptResurrectAction.cpp b/src/strategy/actions/AcceptResurrectAction.cpp index 6e2178a8..a1cfc1de 100644 --- a/src/strategy/actions/AcceptResurrectAction.cpp +++ b/src/strategy/actions/AcceptResurrectAction.cpp @@ -23,7 +23,5 @@ bool AcceptResurrectAction::Execute(Event event) packet << uint8(1); // accept bot->GetSession()->HandleResurrectResponseOpcode(packet); // queue the packet to get around race condition - botAI->ChangeEngine(BOT_STATE_NON_COMBAT); - return true; }