diff options
Diffstat (limited to 'src/server/game/Handlers/MovementHandler.cpp')
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 311 |
1 files changed, 255 insertions, 56 deletions
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 7b7ccf8771c..a292db59548 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -15,23 +15,25 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "Battleground.h" #include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Opcodes.h" -#include "Log.h" #include "Corpse.h" -#include "Player.h" +#include "GameTime.h" +#include "GameClient.h" +#include "InstanceSaveMgr.h" +#include "Log.h" #include "MapManager.h" #include "MotionMaster.h" #include "MovementGenerator.h" #include "MoveSpline.h" -#include "Transport.h" -#include "Battleground.h" -#include "InstanceSaveMgr.h" +#include "ObjectAccessor.h" #include "ObjectMgr.h" +#include "Opcodes.h" +#include "Player.h" +#include "Transport.h" #include "Vehicle.h" -#include "GameTime.h" +#include "WorldPacket.h" +#include "WorldSession.h" #include <boost/accumulators/statistics/variance.hpp> #include <boost/accumulators/accumulators.hpp> #include <boost/accumulators/statistics.hpp> @@ -212,17 +214,22 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) recvData >> guid.ReadAsPacked(); + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + uint32 sequenceIndex, time; recvData >> sequenceIndex >> time; - Player* plMover = _player->GetUnitBeingMoved()->ToPlayer(); + GameClient* client = GetGameClient(); + Unit* mover = client->GetActivelyMovedUnit(); + Player* plMover = mover->ToPlayer(); if (!plMover || !plMover->IsBeingTeleportedNear()) return; - if (guid != plMover->GetGUID()) - return; - plMover->SetSemaphoreTeleportNear(false); uint32 old_zone = plMover->GetZoneId(); @@ -259,10 +266,17 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { uint16 opcode = recvData.GetOpcode(); - Unit* mover = _player->GetUnitBeingMoved(); + ObjectGuid guid; + recvData >> guid.ReadAsPacked(); - ASSERT(mover != nullptr); // there must always be a mover + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + GameClient* client = GetGameClient(); + Unit* mover = client->GetActivelyMovedUnit(); Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck @@ -273,9 +287,6 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) } /* extract packet */ - ObjectGuid guid; - - recvData >> guid.ReadAsPacked(); MovementInfo movementInfo; movementInfo.guid = guid; @@ -283,10 +294,6 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) recvData.rfinish(); // prevent warnings spam - // prevent tampered movement data - if (guid != mover->GetGUID()) - return; - if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam @@ -416,7 +423,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY())) { - if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) + if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(plrMover))) { // NOTE: this is actually called many times while falling // even after the player has been teleported away @@ -448,13 +455,15 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData) recvData >> guid.ReadAsPacked(); - // now can skip not our packet - if (_player->GetGUID() != guid) + if (!IsRightUnitBeingMoved(guid)) { - recvData.rfinish(); // prevent warnings spam + recvData.rfinish(); // prevent warnings spam return; } + GameClient* client = GetGameClient(); + Unit* mover = client->GetActivelyMovedUnit(); + // continue parse packet recvData >> unk1; // counter or moveEvent @@ -491,25 +500,25 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData) // skip all forced speed changes except last and unexpected // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. - if (_player->m_forced_speed_changes[force_move_type] > 0) + if (mover->m_forced_speed_changes[force_move_type] > 0) { - --_player->m_forced_speed_changes[force_move_type]; - if (_player->m_forced_speed_changes[force_move_type] > 0) + --mover->m_forced_speed_changes[force_move_type]; + if (mover->m_forced_speed_changes[force_move_type] > 0) return; } - if (!_player->GetTransport() && std::fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) + if (!mover->GetTransport() && std::fabs(mover->GetSpeed(move_type) - newspeed) > 0.01f) { - if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct + if (mover->GetSpeed(move_type) > newspeed) // must be greater - just correct { TC_LOG_ERROR("network", "%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", - move_type_name[move_type], _player->GetName().c_str(), _player->GetSpeed(move_type), newspeed); - _player->SetSpeedRate(move_type, _player->GetSpeedRate(move_type)); + move_type_name[move_type], _player->GetName().c_str(), mover->GetSpeed(move_type), newspeed); + mover->SetSpeedRate(move_type, mover->GetSpeedRate(move_type)); } else // must be lesser - cheating { TC_LOG_DEBUG("misc", "Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", - _player->GetName().c_str(), _player->GetSession()->GetAccountId(), _player->GetSpeed(move_type), newspeed); + _player->GetName().c_str(), _player->GetSession()->GetAccountId(), mover->GetSpeed(move_type), newspeed); _player->GetSession()->KickPlayer("WorldSession::HandleForceSpeedChangeAck Incorrect speed"); } } @@ -522,9 +531,21 @@ void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recvData) ObjectGuid guid; recvData >> guid; - if (GetPlayer()->IsInWorld()) - if (_player->GetUnitBeingMoved()->GetGUID() != guid) - TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s" , guid.ToString().c_str(), _player->GetUnitBeingMoved()->GetGUID().ToString().c_str()); + GameClient* client = GetGameClient(); + + // step 1: look at the list of units that this client is allowed to move. check if the client is allowed to even move the + // unit that is mentioned in the packet. if not, either silently ignore, log this event or kick the client. + if (!client->IsAllowedToMove(guid)) + { + // @todo log or kick or do nothing depending on configuration + TC_LOG_DEBUG("entities.unit", "set active mover FAILED for client of player %s. GUID %s.", _player->GetName().c_str(), guid.ToString().c_str()); + return; + } + + // step 2: + TC_LOG_DEBUG("entities.unit", "set active mover OK for client of player %s. GUID %s.", _player->GetName().c_str(), guid.ToString().c_str()); + Unit* newActivelyMovedUnit = ObjectAccessor::GetUnit(*_player, guid); + client->SetActivelyMovedUnit(newActivelyMovedUnit); } void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData) @@ -533,13 +554,20 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData) ObjectGuid old_mover_guid; recvData >> old_mover_guid.ReadAsPacked(); + recvData.rfinish(); // prevent warnings spam. + // the movement info in this kind of packet is ignored for now. It's unclear if it should be used. - MovementInfo mi; - ReadMovementInfo(recvData, &mi); + GameClient* client = GetGameClient(); - mi.guid = old_mover_guid; + if (client->GetActivelyMovedUnit() == nullptr || client->GetActivelyMovedUnit()->GetGUID() != old_mover_guid) + { + // this shouldn't never happen in theory + TC_LOG_WARN("entities.unit", "unset active mover FAILED for client of player %s. GUID %s.", _player->GetName().c_str(), old_mover_guid.ToString().c_str()); + return; + } - _player->m_movementInfo = mi; + TC_LOG_DEBUG("entities.unit", "unset active mover OK for client of player %s. GUID %s.", _player->GetName().c_str(), old_mover_guid.ToString().c_str()); + client->SetActivelyMovedUnit(nullptr); } void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvData*/) @@ -557,19 +585,25 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData) ObjectGuid guid; recvData >> guid.ReadAsPacked(); - if (_player->GetUnitBeingMoved()->GetGUID() != guid) + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam return; + } recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; ReadMovementInfo(recvData, &movementInfo); - _player->m_movementInfo = movementInfo; + GameClient* client = GetGameClient(); + Unit* mover = client->GetActivelyMovedUnit(); + + mover->m_movementInfo = movementInfo; WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); data << guid.WriteAsPacked(); - _player->BuildMovementPacket(&data); + mover->BuildMovementPacket(&data); // knockback specific info data << movementInfo.jump.sinAngle; @@ -577,7 +611,7 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData) data << movementInfo.jump.xyspeed; data << movementInfo.jump.zspeed; - _player->SendMessageToSet(&data, false); + client->GetBasePlayer()->SendMessageToSet(&data, false); } void WorldSession::HandleMoveHoverAck(WorldPacket& recvData) @@ -587,6 +621,12 @@ void WorldSession::HandleMoveHoverAck(WorldPacket& recvData) ObjectGuid guid; // guid - unused recvData >> guid.ReadAsPacked(); + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -602,6 +642,113 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recvData) ObjectGuid guid; // guid - unused recvData >> guid.ReadAsPacked(); + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); + + recvData.read_skip<uint32>(); // unk2 +} + +void WorldSession::HandleMoveRootAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "CMSG_FORCE_MOVE_ROOT_ACK"); + + ObjectGuid guid; // guid - unused + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); +} + +void WorldSession::HandleFeatherFallAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_FEATHER_FALL_ACK"); + + ObjectGuid guid; // guid - unused + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); + + recvData.read_skip<uint32>(); // unk2 +} + +void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK"); + + ObjectGuid guid; // guid - unused + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); +} + +void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); + + ObjectGuid guid; // guid - unused + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); + + recvData.read_skip<uint32>(); // unk2 +} + +void WorldSession::HandleMoveSetCanTransitionBetweenSwinAndFlyAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK"); + + ObjectGuid guid; + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -610,6 +757,65 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recvData) recvData.read_skip<uint32>(); // unk2 } +void WorldSession::HandleMoveGravityDisableAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_GRAVITY_DISABLE_ACK"); + + ObjectGuid guid; + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); +} + +void WorldSession::HandleMoveGravityEnableAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_GRAVITY_ENABLE_ACK"); + + ObjectGuid guid; + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // unk + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); +} + +void WorldSession::HandleMoveSetCollisionHgtAck(WorldPacket& recvData) +{ + TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_SET_COLLISION_HGT_ACK"); + + ObjectGuid guid; + float newValue; + recvData >> guid.ReadAsPacked(); + + if (!IsRightUnitBeingMoved(guid)) + { + recvData.rfinish(); // prevent warnings spam + return; + } + + recvData.read_skip<uint32>(); // movement counter + recvData >> newValue; + + MovementInfo movementInfo; + ReadMovementInfo(recvData, &movementInfo); +} + void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData) { if (!_player->IsAlive() || _player->IsInCombat()) @@ -632,21 +838,14 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) recvData >> guid.ReadAsPacked(); recvData >> timeSkipped; - Unit* mover = GetPlayer()->m_unitMovedByMe; - - if (!mover) - { - TC_LOG_WARN("entities.player", "WorldSession::HandleMoveTimeSkippedOpcode wrong mover state from the unit moved by the player %s", GetPlayer()->GetGUID().ToString().c_str()); - return; - } - - // prevent tampered movement data - if (guid != mover->GetGUID()) + if (!IsRightUnitBeingMoved(guid)) { - TC_LOG_WARN("entities.player", "WorldSession::HandleMoveTimeSkippedOpcode wrong guid from the unit moved by the player %s", GetPlayer()->GetGUID().ToString().c_str()); + recvData.rfinish(); // prevent warnings spam return; } + GameClient* client = GetGameClient(); + Unit* mover = client->GetActivelyMovedUnit(); mover->m_movementInfo.time += timeSkipped; WorldPacket data(MSG_MOVE_TIME_SKIPPED, recvData.size()); |