mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-28 04:42:10 +01:00
Core/Movement: Improve client control logic (#26348)
This commit is contained in:
@@ -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,12 @@ 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;
|
||||
@@ -610,6 +656,166 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recvData)
|
||||
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;
|
||||
ReadMovementInfo(recvData, &movementInfo);
|
||||
|
||||
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)
|
||||
if (!IsRightUnitBeingMoved(guid))
|
||||
{
|
||||
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())
|
||||
{
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user