From 5b06a62d916dc05d767fd87465d20dde0fddbf27 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 03:30:24 -0700 Subject: [PATCH] game: fix Classic/TBC movement ACKs silently dropped by isClassicLikeExpansion guard Five movement control response handlers (speed change, move-root, move-flag change, knock-back, teleport) had guards of the form !isClassicLikeExpansion() or isClassicLikeExpansion() that prevented ACKs from ever being sent on Classic/Turtle. Each handler already contained correct legacyGuidAck logic (full uint64 for Classic/TBC, packed GUID for WotLK) that was unreachable due to the outer guard. Classic servers (CMaNGOS/VMaNGOS/ChromieCraft) expect all of these ACKs. Without them the server stalls the player's speed update, keeps root state desynced, or generates movement hacks. Fix by removing the erroneous expansion guard and relying on the existing legacyGuidAck path. Affected: handleForceSpeedChange, handleForceMoveRootState, handleForceMoveFlagChange, handleMoveKnockBack, handleTeleport. --- src/game/game_handler.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 192c213b..ae40b5e1 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -11063,7 +11063,8 @@ void GameHandler::handleForceSpeedChange(network::Packet& packet, const char* na if (guid != playerGuid) return; // Always ACK the speed change to prevent server stall. - if (socket && !isClassicLikeExpansion()) { + // Classic/TBC use full uint64 GUID; WotLK uses packed GUID. + if (socket) { network::Packet ack(wireOpcode(ackOpcode)); const bool legacyGuidAck = isActiveExpansion("classic") || isActiveExpansion("tbc") || isActiveExpansion("turtle"); @@ -11149,7 +11150,7 @@ void GameHandler::handleForceMoveRootState(network::Packet& packet, bool rooted) movementInfo.flags &= ~static_cast(MovementFlags::ROOT); } - if (!socket || isClassicLikeExpansion()) return; + if (!socket) return; uint16_t ackWire = wireOpcode(rooted ? Opcode::CMSG_FORCE_MOVE_ROOT_ACK : Opcode::CMSG_FORCE_MOVE_UNROOT_ACK); if (ackWire == 0xFFFF) return; @@ -11210,7 +11211,7 @@ void GameHandler::handleForceMoveFlagChange(network::Packet& packet, const char* } } - if (!socket || isClassicLikeExpansion()) return; + if (!socket) return; uint16_t ackWire = wireOpcode(ackOpcode); if (ackWire == 0xFFFF) return; @@ -11265,7 +11266,7 @@ void GameHandler::handleMoveKnockBack(network::Packet& packet) { if (guid != playerGuid) return; - if (!socket || isClassicLikeExpansion()) return; + if (!socket) return; uint16_t ackWire = wireOpcode(Opcode::CMSG_MOVE_KNOCK_BACK_ACK); if (ackWire == 0xFFFF) return; @@ -15467,12 +15468,13 @@ void GameHandler::handleTeleportAck(network::Packet& packet) { // Send the ack back to the server // Client→server MSG_MOVE_TELEPORT_ACK: u64 guid + u32 counter + u32 time - if (socket && !isClassicLikeExpansion()) { + // Classic/TBC use full uint64 GUID; WotLK uses packed GUID. + if (socket) { network::Packet ack(wireOpcode(Opcode::MSG_MOVE_TELEPORT_ACK)); const bool legacyGuidAck = isActiveExpansion("classic") || isActiveExpansion("tbc") || isActiveExpansion("turtle"); if (legacyGuidAck) { - ack.writeUInt64(playerGuid); // CMaNGOS expects full GUID for teleport ACK + ack.writeUInt64(playerGuid); // CMaNGOS/VMaNGOS expects full GUID for Classic/TBC } else { MovementPacket::writePackedGuid(ack, playerGuid); }