Core/Movement: ported client control logic updates from 335 branch

This commit is contained in:
Ovahlord committed 2021-11-06 23:41:34 +01:00
1 parent f5342061ba
commit edbbeba5a2
21 files changed
+464 -284

No files matched your search

@@ -3002,7 +3002,7 @@ float Creature::GetNativeObjectScale() const
void Creature::UpdateMovementFlags(bool initializeDBStates)
{
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
if (m_playerMovingMe)
if (IsMovedByClient())
return;
// Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
+42 -58
View File
@@ -46,6 +46,7 @@
#include "DB2Stores.h"
#include "DisableMgr.h"
#include "Formulas.h"
#include "GameClient.h"
#include "GameEventMgr.h"
#include "GameObjectAI.h"
#include "GameTime.h"
@@ -279,9 +280,6 @@ Player::Player(WorldSession* session): Unit(true)
m_itemUpdateQueueBlocked = false;
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
m_forced_speed_changes[i] = 0;
m_stableSlots = 0;
/////////////////// Instance System /////////////////////
@@ -317,8 +315,6 @@ Player::Player(WorldSession* session): Unit(true)
// Player summoning
m_summon_expire = 0;
m_unitMovedByMe = this;
m_playerMovingMe = this;
m_seer = this;
@@ -22928,7 +22924,7 @@ bool Player::IsNeverVisible() const
bool Player::CanAlwaysSee(WorldObject const* obj) const
{
// Always can see self
if (m_unitMovedByMe == obj)
if (GetCharmedOrSelf() == obj)
return true;
if (ObjectGuid guid = GetGuidValue(PLAYER_FARSIGHT))
@@ -23212,14 +23208,16 @@ Player* Player::GetSelectedPlayer() const
void Player::SendComboPoints()
{
Unit* combotarget = ObjectAccessor::GetUnit(*this, m_comboTarget);
if (combotarget)
{
WorldPacket data;
if (m_unitMovedByMe != this)
Player* movingMe = GetCharmerOrSelfPlayer();
if (movingMe != this)
{
data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, m_unitMovedByMe->GetPackGUID().size()+combotarget->GetPackGUID().size()+1);
data << m_unitMovedByMe->GetPackGUID();
data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, movingMe->GetPackGUID().size()+combotarget->GetPackGUID().size()+1);
data << movingMe->GetPackGUID();
}
else
data.Initialize(SMSG_UPDATE_COMBO_POINTS, combotarget->GetPackGUID().size()+1);
@@ -23415,10 +23413,7 @@ void Player::SendInitialPacketsBeforeAddToMap(bool firstLogin /*= false*/)
// SMSG_UPDATE_WORLD_STATE
// SMSG_POWER_UPDATE
// Not going with SetMover(this); because sniffs show no packet
m_unitMovedByMe->m_playerMovingMe = nullptr;
m_unitMovedByMe = this;
m_unitMovedByMe->m_playerMovingMe = this;
GetSession()->GetGameClient()->AddAllowedMover(this);
}
void Player::SendInitialPacketsAfterAddToMap()
@@ -24758,54 +24753,38 @@ void Player::ResurrectUsingRequestData()
void Player::SetClientControl(Unit* target, bool allowMove)
{
// still affected by some aura that shouldn't allow control, only allow on last such aura to be removed
if (allowMove && target->HasUnitState(UNIT_STATE_CANT_CLIENT_CONTROL))
// a player can never client control nothing
ASSERT(target);
// don't allow possession to be overridden
if (target->HasUnitState(UNIT_STATE_CHARMED) && (GetGUID() != target->GetCharmerGUID()))
{
// this should never happen, otherwise m_unitBeingMoved might be left dangling!
ASSERT(GetUnitBeingMoved() == target);
TC_LOG_ERROR("entities.player", "Player '%s' attempt to client control '%s', which is charmed by GUID %s",
GetName().c_str(), target->GetName().c_str(), target->GetCharmerGUID().ToString().c_str());
return;
}
// still affected by some aura that shouldn't allow control, only allow on last such aura to be removed
if (target->HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED))
allowMove = false;
WorldPacket data(SMSG_CLIENT_CONTROL_UPDATE, target->GetPackGUID().size()+1);
data << target->GetPackGUID();
data << uint8(allowMove ? 1 : 0);
SendDirectMessage(&data);
if (this != target)
SetViewpoint(target, allowMove);
WorldObject* viewpoint = GetViewpoint();
if (!viewpoint)
viewpoint = this;
if (target != viewpoint)
{
if (viewpoint != this)
SetViewpoint(viewpoint, false);
if (target != this)
SetViewpoint(target, true);
}
if (allowMove)
SetMover(target);
}
void Player::SetMover(Unit* target)
{
m_unitMovedByMe->m_playerMovingMe = nullptr;
m_unitMovedByMe = target;
m_unitMovedByMe->m_playerMovingMe = this;
ObjectGuid guid = target->GetGUID();
WorldPacket data(SMSG_MOVE_SET_ACTIVE_MOVER, 9);
data.WriteBit(guid[5]);
data.WriteBit(guid[7]);
data.WriteBit(guid[3]);
data.WriteBit(guid[6]);
data.WriteBit(guid[0]);
data.WriteBit(guid[4]);
data.WriteBit(guid[1]);
data.WriteBit(guid[2]);
data.WriteByteSeq(guid[6]);
data.WriteByteSeq(guid[2]);
data.WriteByteSeq(guid[3]);
data.WriteByteSeq(guid[0]);
data.WriteByteSeq(guid[5]);
data.WriteByteSeq(guid[7]);
data.WriteByteSeq(guid[1]);
data.WriteByteSeq(guid[4]);
SendDirectMessage(&data);
GetGameClient()->SetMovedUnit(target, allowMove);
}
void Player::UpdateZoneDependentAuras(uint32 newZone)
@@ -27834,7 +27813,7 @@ void Player::ValidateMovementInfo(MovementInfo* mi)
mi->RemoveMovementFlag((maskToRemove));
#endif
if (!m_unitMovedByMe->GetVehicleBase() || !(m_unitMovedByMe->GetVehicle()->GetVehicleInfo()->Flags & VEHICLE_FLAG_FIXED_POSITION))
if (!GetCharmedOrSelf()->GetVehicleBase() || !(GetCharmedOrSelf()->GetVehicle()->GetVehicleInfo()->Flags & VEHICLE_FLAG_FIXED_POSITION))
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT), MOVEMENTFLAG_ROOT);
/*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid
@@ -27845,7 +27824,7 @@ void Player::ValidateMovementInfo(MovementInfo* mi)
MOVEMENTFLAG_MASK_MOVING);
//! Cannot hover without SPELL_AURA_HOVER
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !m_unitMovedByMe->HasAuraType(SPELL_AURA_HOVER),
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetCharmedOrSelf()->HasAuraType(SPELL_AURA_HOVER),
MOVEMENTFLAG_HOVER);
//! Cannot ascend and descend at the same time
@@ -27870,12 +27849,12 @@ void Player::ValidateMovementInfo(MovementInfo* mi)
//! Cannot walk on water without SPELL_AURA_WATER_WALK except for ghosts
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) &&
!m_unitMovedByMe->HasAuraType(SPELL_AURA_WATER_WALK) &&
!m_unitMovedByMe->HasAuraType(SPELL_AURA_GHOST),
!GetCharmedOrSelf()->HasAuraType(SPELL_AURA_WATER_WALK) &&
!GetCharmedOrSelf()->HasAuraType(SPELL_AURA_GHOST),
MOVEMENTFLAG_WATERWALKING);
//! Cannot feather fall without SPELL_AURA_FEATHER_FALL
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !m_unitMovedByMe->HasAuraType(SPELL_AURA_FEATHER_FALL),
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !GetCharmedOrSelf()->HasAuraType(SPELL_AURA_FEATHER_FALL),
MOVEMENTFLAG_FALLING_SLOW);
/*! Cannot fly if no fly auras present. Exception is being a GM.
@@ -27885,8 +27864,8 @@ void Player::ValidateMovementInfo(MovementInfo* mi)
*/
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSession()->GetSecurity() == SEC_PLAYER &&
!m_unitMovedByMe->HasAuraType(SPELL_AURA_FLY) &&
!m_unitMovedByMe->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED),
!GetCharmedOrSelf()->HasAuraType(SPELL_AURA_FLY) &&
!GetCharmedOrSelf()->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED),
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY);
REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_CAN_FLY) && mi->HasMovementFlag(MOVEMENTFLAG_FALLING),
@@ -28284,3 +28263,8 @@ void Player::SendTamePetFailure(PetTameFailureReason reason)
data << uint8(reason);
SendDirectMessage(&data);
}
GameClient* Player::GetGameClient() const
{
return GetSession()->GetGameClient();
}
+3 -4
View File
@@ -65,6 +65,7 @@ class Channel;
class CharacterCreateInfo;
class Creature;
class DynamicObject;
class GameClient;
class Group;
class Guild;
class Item;
@@ -1837,6 +1838,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void RemovedInsignia(Player* looterPlr);
WorldSession* GetSession() const { return m_session; }
GameClient* GetGameClient() const;
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
void DestroyForPlayer(Player* target, bool onDeath = false) const override;
@@ -2138,16 +2140,13 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
/*** VARIOUS SYSTEMS ***/
/*********************************************************/
void UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode);
// only changed for direct client control (possess, vehicle etc.), not stuff you control using pet commands
Unit* m_unitMovedByMe;
WorldObject* m_seer;
void SetFallInformation(uint32 time, float z);
void HandleFall(MovementInfo const& movementInfo);
void SetClientControl(Unit* target, bool allowMove);
void SetMover(Unit* target);
void SetSeer(WorldObject* target) { m_seer = target; }
void SetViewpoint(WorldObject* target, bool apply);
WorldObject* GetViewpoint() const;
+42 -50
View File
@@ -34,6 +34,7 @@
#include "CreatureAIImpl.h"
#include "CreatureGroups.h"
#include "Formulas.h"
#include "GameClient.h"
#include "GameTime.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
@@ -325,7 +326,7 @@ bool DispelableAura::RollDispel() const
Unit::Unit(bool isWorldObject) :
WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0),
WorldObject(isWorldObject), m_lastSanctuaryTime(0),
LastCharmerGUID(), m_ControlledByPlayer(false), movespline(new Movement::MoveSpline()),
m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0),
m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
@@ -398,7 +399,11 @@ Unit::Unit(bool isWorldObject) :
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
m_speed_rate[i] = 1.0f;
for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
m_forced_speed_changes[i] = 0;
m_charmInfo = nullptr;
_gameClientMovingMe = nullptr;
// remove aurastates allowing special moves
for (uint8 i = 0; i < MAX_REACTIVE; ++i)
@@ -454,6 +459,7 @@ Unit::~Unit()
ASSERT(m_removedAuras.empty());
ASSERT(m_gameObj.empty());
ASSERT(m_dynObj.empty());
ASSERT(!_gameClientMovingMe || _gameClientMovingMe->GetBasePlayer() == this);
}
void Unit::Update(uint32 p_time)
@@ -5611,7 +5617,7 @@ Unit* Unit::getAttackerForHelper() const // If someone wants to
return nullptr;
if (Unit* victim = GetVictim())
if ((!IsPet() && !GetPlayerMovingMe()) || IsInCombatWith(victim))
if ((!IsPet() && !IsCharmerOrSelfPlayer()) || IsInCombatWith(victim))
return victim;
CombatManager const& mgr = GetCombatManager();
@@ -6430,6 +6436,14 @@ bool Unit::isPossessing() const
return false;
}
Unit* Unit::GetCharmerOrSelf() const
{
if (IsCharmed())
return GetCharmer();
else
return const_cast<Unit*>(this);
}
Unit* Unit::GetNextRandomRaidMemberOrPet(float radius)
{
Player* player = nullptr;
@@ -9052,18 +9066,14 @@ void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
{
// register forced speed changes for WorldSession::HandleForceSpeedChangeAck
// and do it only for real sent packets and use run for run/mounted as client expected
++ToPlayer()->m_forced_speed_changes[mtype];
if (!IsInCombat())
if (Pet* pet = ToPlayer()->GetPet())
pet->SetSpeedRate(mtype, m_speed_rate[mtype]);
++m_forced_speed_changes[mtype];
}
static MovementStatusElements const speedVal = MSEExtraFloat;
Movement::ExtraMovementStatusElement extra(&speedVal);
extra.Data.floatData = GetSpeed(mtype);
Movement::PacketSender(this, moveTypeToOpcode[mtype][0], moveTypeToOpcode[mtype][1], NULL_OPCODE, &extra).Send();
Movement::PacketSender(IsMovedByClient() ? GetGameClientMovingMe()->GetBasePlayer() : this, moveTypeToOpcode[mtype][0], moveTypeToOpcode[mtype][1], NULL_OPCODE, &extra).Send();
}
void Unit::FollowTarget(Unit* target)
@@ -10602,20 +10612,6 @@ void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state)
}
}
Unit* Unit::GetUnitBeingMoved() const
{
if (Player const* player = ToPlayer())
return player->m_unitMovedByMe;
return nullptr;
}
Player* Unit::GetPlayerBeingMoved() const
{
if (Unit* mover = GetUnitBeingMoved())
return mover->ToPlayer();
return nullptr;
}
bool Unit::isFrozen() const
{
return HasAuraState(AURA_STATE_FROZEN);
@@ -11999,11 +11995,8 @@ void Unit::SetFeared(bool apply)
}
// block / allow control to real player in control (eg charmer)
if (GetTypeId() == TYPEID_PLAYER)
{
if (m_playerMovingMe)
m_playerMovingMe->SetClientControl(this, !apply);
}
if (GetCharmerOrSelfPlayer())
GetCharmerOrSelfPlayer()->SetClientControl(this, !apply);
}
void Unit::SetConfused(bool apply)
@@ -12025,11 +12018,8 @@ void Unit::SetConfused(bool apply)
}
// block / allow control to real player in control (eg charmer)
if (GetTypeId() == TYPEID_PLAYER)
{
if (m_playerMovingMe)
m_playerMovingMe->SetClientControl(this, !apply);
}
if (GetCharmerOrSelfPlayer())
GetCharmerOrSelfPlayer()->SetClientControl(this, !apply);
}
bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
@@ -12679,27 +12669,16 @@ void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float
void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
{
Player* player = ToPlayer();
if (!player)
{
if (Unit* charmer = GetCharmer())
{
player = charmer->ToPlayer();
if (player && player->m_unitMovedByMe != this)
player = nullptr;
}
}
if (!player)
if (IsMovedByServer())
GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ);
else
{
float vcos, vsin;
GetSinCos(x, y, vsin, vcos);
SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
SendMoveKnockBack(GetGameClientMovingMe()->GetBasePlayer(), speedXY, -speedZ, vcos, vsin);
if (player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_FLY))
player->SetCanFly(true, false);
if (HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || HasAuraType(SPELL_AURA_FLY))
SetCanFly(true, false);
}
}
@@ -13733,8 +13712,9 @@ void Unit::SendTeleportPacket(Position const& pos)
{
// SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
// MSG_MOVE_TELEPORT is sent to self in order to trigger MSG_MOVE_TELEPORT_ACK and update the position server side
if (Player* playerMover = GetPlayerBeingMoved())
if (IsMovedByClient())
{
Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
float x, y, z, o;
pos.GetPosition(x, y, z, o);
if (TransportBase* transportBase = GetDirectTransport())
@@ -14102,10 +14082,14 @@ bool Unit::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool /*u
}
}
WorldPacket data;
if (disable)
Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_DISABLE, SMSG_MOVE_GRAVITY_DISABLE).Send();
data.Initialize(IsMovedByClient() ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_DISABLE);
else
Movement::PacketSender(this, SMSG_SPLINE_MOVE_GRAVITY_ENABLE, SMSG_MOVE_GRAVITY_ENABLE).Send();
data.Initialize(IsMovedByClient() ? SMSG_MOVE_GRAVITY_ENABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE);
WriteMovementInfo(data);
return true;
}
@@ -14976,3 +14960,11 @@ void Unit::ProcessItemCast(PendingSpellCastRequest const& castRequest, SpellCast
player->CastItemUseSpell(item, targets, castRequest.CastRequest.CastID, castRequest.CastRequest.Misc);
}
}
void Unit::SetGameClientMovingMe(GameClient* gameClientMovingMe)
{
_gameClientMovingMe = gameClientMovingMe;
Player* mover = _gameClientMovingMe->GetBasePlayer();
mover->SendDirectMessage(WorldPackets::Movement::MoveSetActiveMover(mover->GetGUID()).Write());
}
+18 -8
View File
@@ -75,6 +75,7 @@ class AuraApplication;
class AuraEffect;
class Creature;
class DynamicObject;
class GameClient;
class GameObject;
class Guardian;
class Item;
@@ -1258,6 +1259,7 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAllControlled();
bool IsCharmed() const { return !GetCharmerGUID().IsEmpty(); }
bool IsCharming() const { return !GetCharmedGUID().IsEmpty(); }
bool isPossessed() const { return HasUnitState(UNIT_STATE_POSSESSED); }
bool isPossessedByPlayer() const;
bool isPossessing() const;
@@ -1266,14 +1268,19 @@ class TC_GAME_API Unit : public WorldObject
CharmInfo* GetCharmInfo() { return m_charmInfo; }
CharmInfo* InitCharmInfo();
void DeleteCharmInfo();
// returns the unit that this player IS CONTROLLING
Unit* GetUnitBeingMoved() const;
// returns the player that this player IS CONTROLLING
Player* GetPlayerBeingMoved() const;
// returns the player that this unit is BEING CONTROLLED BY
Player* GetPlayerMovingMe() const { return m_playerMovingMe; }
// only set for direct client control (possess effects, vehicles and similar)
Player* m_playerMovingMe;
// base client control of this unit (possess effects, vehicles and similar). Not affected by temporary CC.
bool IsCharmerOrSelfPlayer() const { return GetCharmerOrSelf()->IsPlayer(); }
Unit* GetCharmerOrSelf() const;
Player* GetCharmerOrSelfPlayer() const { return GetCharmerOrSelf()->ToPlayer();}
Unit* GetCharmedOrSelf() const { return IsCharming() ? GetCharmed() : const_cast<Unit*>(this); }
// real time client control status of this unit (possess effects, vehicles and similar). For example, if this unit is a player temporarly under fear, it will return false.
bool IsMovedByClient() const { return _gameClientMovingMe != nullptr; }
bool IsMovedByServer() const { return !IsMovedByClient(); }
GameClient* GetGameClientMovingMe() const { return _gameClientMovingMe; }
void SetGameClientMovingMe(GameClient* gameClientMovingMe);
SharedVisionList const& GetSharedVisionList() { return m_sharedVision; }
void AddPlayerToVision(Player* player);
void RemovePlayerFromVision(Player* player);
@@ -1748,6 +1755,8 @@ class TC_GAME_API Unit : public WorldObject
// Movement info
Movement::MoveSpline * movespline;
uint8 m_forced_speed_changes[MAX_MOVE_TYPE];
// Part of Evade mechanics
time_t GetLastDamagedTime() const { return _lastDamagedTime; }
void UpdateLastDamagedTime(SpellInfo const* spellProto);
@@ -1838,6 +1847,7 @@ class TC_GAME_API Unit : public WorldObject
Unit* m_charmed; // Unit that is being charmed BY ME
CharmInfo* m_charmInfo;
SharedVisionList m_sharedVision;
GameClient* _gameClientMovingMe;
MotionMaster* i_motionMaster;
-69
View File
@@ -912,64 +912,6 @@ void WorldSession::HandleNextCinematicCamera(WorldPackets::Misc::NextCinematicCa
GetPlayer()->GetCinematicMgr()->BeginCinematic();
}
void WorldSession::HandleFeatherFallAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
// no used
recvData.rfinish(); // prevent warnings spam
}
void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData)
{
// no used
recvData.rfinish(); // prevent warnings spam
/*
uint64 guid;
recvData >> guid;
// now can skip not our packet
if (_player->GetGUID() != guid)
{
recvData.rfinish(); // prevent warnings spam
return;
}
TC_LOG_DEBUG("network", "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK");
recvData.read_skip<uint32>(); // unk
MovementInfo movementInfo;
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
recvData.read_skip<float>(); // unk2
*/
}
void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
{
// no used
recvData.rfinish(); // prevent warnings spam
/*
uint64 guid;
recvData >> guid;
// now can skip not our packet
if (_player->GetGUID() != guid)
{
recvData.rfinish(); // prevent warnings spam
return;
}
TC_LOG_DEBUG("network", "WORLD: CMSG_FORCE_MOVE_ROOT_ACK");
recvData.read_skip<uint32>(); // unk
MovementInfo movementInfo;
ReadMovementInfo(recvData, &movementInfo);
*/
}
void WorldSession::HandleSetActionBarToggles(WorldPacket& recvData)
{
uint8 actionBar;
@@ -1390,17 +1332,6 @@ void WorldSession::HandleCancelMountAuraOpcode(WorldPacket& /*recvData*/)
_player->RemoveAurasByType(SPELL_AURA_MOUNTED); // Calls Dismount()
}
void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData)
{
// fly mode on/off
TC_LOG_DEBUG("network", "WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
MovementInfo movementInfo;
_player->ReadMovementInfo(recvData, &movementInfo);
_player->m_unitMovedByMe->m_movementInfo.flags = movementInfo.GetMovementFlags();
}
void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_SET_TAXI_BENCHMARK_MODE");
+122 -48
View File
@@ -33,6 +33,7 @@
#include "ObjectMgr.h"
#include "Vehicle.h"
#include "GameTime.h"
#include "GameClient.h"
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include <boost/accumulators/statistics/variance.hpp>
@@ -235,15 +236,16 @@ void WorldSession::HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTok
void WorldSession::HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_TELEPORT_ACK: Guid: %s, Sequence: %u, Time: %u", packet.MoverGUID.ToString().c_str(), packet.AckIndex, packet.MoveTime);
if (!IsRightUnitBeingMoved(packet.MoverGUID))
return;
Player* plMover = _player->m_unitMovedByMe->ToPlayer();
GameClient* client = GetGameClient();
Unit* mover = client->GetActivelyMovedUnit();
Player* plMover = mover->ToPlayer();
if (!plMover || !plMover->IsBeingTeleportedNear())
return;
if (packet.MoverGUID != plMover->GetGUID())
return;
plMover->SetSemaphoreTeleportNear(false);
@@ -294,7 +296,11 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket)
void WorldSession::HandleMovementOpcode(uint16 opcode, MovementInfo& movementInfo)
{
Unit* mover = _player->m_unitMovedByMe;
if (!IsRightUnitBeingMoved(movementInfo.guid))
return;
GameClient* client = GetGameClient();
Unit* mover = client->GetActivelyMovedUnit();
// there must always be a mover
if (!mover)
@@ -459,12 +465,11 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData)
Movement::ExtraMovementStatusElement extras(&speedElement);
GetPlayer()->ReadMovementInfo(recvData, &movementInfo, &extras);
// now can skip not our packet
if (_player->GetGUID() != movementInfo.guid)
{
recvData.rfinish(); // prevent warnings spam
if (!IsRightUnitBeingMoved(movementInfo.guid))
return;
}
GameClient* client = GetGameClient();
Unit* mover = client->GetActivelyMovedUnit();
float newspeed = extras.Data.floatData;
/*----------------*/
@@ -533,24 +538,25 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData)
static MovementStatusElements const speedVal = MSEExtraFloat;
Movement::ExtraMovementStatusElement extra(&speedVal);
extra.Data.floatData = newspeed;
Movement::PacketSender(_player, NULL_OPCODE, NULL_OPCODE, moveUpdateOpcode, &extra).Send();
Movement::PacketSender(mover, NULL_OPCODE, NULL_OPCODE, moveUpdateOpcode, &extra).Send();
// 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[move_type] > 0)
if (mover->m_forced_speed_changes[move_type] > 0)
{
--_player->m_forced_speed_changes[move_type];
if (_player->m_forced_speed_changes[move_type] > 0)
--mover->m_forced_speed_changes[move_type];
if (mover->m_forced_speed_changes[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], mover->GetName().c_str(), mover->GetSpeed(move_type), newspeed);
mover->SetSpeedRate(move_type, mover->GetSpeedRate(move_type));
}
else // must be lesser - cheating
{
@@ -563,18 +569,41 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recvData)
void WorldSession::HandleSetActiveMoverOpcode(WorldPackets::Movement::SetActiveMover& packet)
{
if (GetPlayer()->IsInWorld())
if (_player->m_unitMovedByMe->GetGUID() != packet.ActiveMover)
TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s" , packet.ActiveMover.ToString().c_str(), _player->m_unitMovedByMe->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(packet.ActiveMover))
{
// @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(), packet.ActiveMover.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(), packet.ActiveMover.ToString().c_str());
Unit* newActivelyMovedUnit = ObjectAccessor::GetUnit(*_player, packet.ActiveMover);
client->SetActivelyMovedUnit(newActivelyMovedUnit);
}
void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData)
{
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER");
MovementInfo mi;
GetPlayer()->ReadMovementInfo(recvData, &mi);
_player->m_movementInfo = mi;
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
GameClient* client = GetGameClient();
if (client->GetActivelyMovedUnit() == nullptr || client->GetActivelyMovedUnit()->GetGUID() != movementInfo.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(), movementInfo.guid.ToString().c_str());
return;
}
TC_LOG_DEBUG("entities.unit", "unset active mover OK for client of player %s. GUID %s.", _player->GetName().c_str(), movementInfo.guid.ToString().c_str());
client->SetActivelyMovedUnit(nullptr);
}
void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvData*/)
@@ -585,6 +614,19 @@ void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvData*/)
GetPlayer()->SendMessageToSet(&data, false);
}
void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData)
{
if (!_player->IsAlive() || _player->IsInCombat())
return;
ObjectGuid summoner_guid;
bool agree;
recvData >> summoner_guid;
recvData >> agree;
_player->SummonIfPossible(agree);
}
void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_KNOCK_BACK_ACK");
@@ -592,23 +634,18 @@ void WorldSession::HandleMoveKnockBackAck(WorldPacket& recvData)
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
if (_player->m_unitMovedByMe->GetGUID() != movementInfo.guid)
if (!IsRightUnitBeingMoved(movementInfo.guid))
return;
_player->m_movementInfo = movementInfo;
GameClient* client = GetGameClient();
Unit* mover = client->GetActivelyMovedUnit();
mover->m_movementInfo = movementInfo;
WorldPacket data(SMSG_MOVE_UPDATE_KNOCK_BACK, 66);
_player->WriteMovementInfo(data);
_player->SendMessageToSet(&data, false);
}
void WorldSession::HandleGravityAckMessage(WorldPacket& recvData)
{
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
if (movementInfo.guid != _player->m_unitMovedByMe->GetGUID())
TC_LOG_ERROR("network", "HandleGravityAckMessage: incorrect mover guid: mover is %s and should be %s.", movementInfo.guid.ToString().c_str(), _player->m_unitMovedByMe->GetGUID().ToString().c_str());
mover->WriteMovementInfo(data);
client->GetBasePlayer()->SendMessageToSet(&data, false);
}
void WorldSession::HandleMoveHoverAck(WorldPacket& recvData)
@@ -625,17 +662,46 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recvData)
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData)
void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
{
if (!_player->IsAlive() || _player->IsInCombat())
return;
TC_LOG_DEBUG("network", "CMSG_FORCE_MOVE_ROOT_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
ObjectGuid summoner_guid;
bool agree;
recvData >> summoner_guid;
recvData >> agree;
void WorldSession::HandleFeatherFallAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_FEATHER_FALL_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
_player->SummonIfPossible(agree);
void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_FORCE_MOVE_UNROOT_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleMoveSetCanTransitionBetweenSwinAndFlyAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleMoveGravityDisableAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_GRAVITY_DISABLE_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleMoveGravityEnableAck(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_GRAVITY_ENABLE_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleSetCollisionHeightAck(WorldPacket& recvData)
@@ -644,10 +710,14 @@ void WorldSession::HandleSetCollisionHeightAck(WorldPacket& recvData)
static MovementStatusElements const heightElement = MSEExtraFloat;
Movement::ExtraMovementStatusElement extras(&heightElement);
GetPlayer()->ReadMovementInfo(recvData, &movementInfo, &extras);
Movement::PacketSender(_player, NULL_OPCODE, NULL_OPCODE, SMSG_MOVE_UPDATE_COLLISION_HEIGHT, &extras).Send();
}
void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "CMSG_MOVE_SET_CAN_FLY_ACK");
MovementInfo movementInfo;
GetPlayer()->ReadMovementInfo(recvData, &movementInfo);
}
void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_MOVE_TIME_SKIPPED");
@@ -674,7 +744,11 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData)
recvData.ReadByteSeq(guid[0]);
recvData.ReadByteSeq(guid[5]);
Unit* mover = GetPlayer()->m_unitMovedByMe;
if (!IsRightUnitBeingMoved(guid))
return;
GameClient* client = GetGameClient();
Unit* mover = client->GetActivelyMovedUnit();
if (!mover)
{
+10 -10
View File
@@ -93,7 +93,7 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet)
Player* user = _player;
// ignore for remote control state
if (user->m_unitMovedByMe != user)
if (user->IsCharming())
return;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.Cast.SpellID);
@@ -111,7 +111,7 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket)
Player* player = GetPlayer();
// ignore for remote control state
if (player->m_unitMovedByMe != player)
if (player->IsCharming())
return;
// additional check, client outputs message on its own
@@ -232,8 +232,8 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recvData)
if (GameObject* obj = GetPlayer()->GetGameObjectIfCanInteractWith(guid))
{
// ignore for remote control state
if (GetPlayer()->m_unitMovedByMe != GetPlayer())
if (!(GetPlayer()->IsOnVehicle(GetPlayer()->m_unitMovedByMe) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted())
if (GetPlayer()->IsCharming())
if (!(GetPlayer()->IsOnVehicle(GetPlayer()->GetCharmed()) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted())
return;
obj->Use(GetPlayer());
@@ -248,7 +248,7 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket)
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [%s]", guid.ToString().c_str());
// ignore for remote control state
if (_player->m_unitMovedByMe != _player)
if (_player->IsCharming())
return;
if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(guid))
@@ -263,7 +263,7 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket)
void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast)
{
// ignore for remote control state (for player case)
Unit* mover = _player->m_unitMovedByMe;
Unit* mover = _player->GetCharmedOrSelf();
if (mover != _player && mover->IsPlayer())
return;
@@ -402,8 +402,8 @@ void WorldSession::HandleCancelChanneling(WorldPacket& recvData)
return;
// ignore for remote control state (for player case)
Unit* mover = _player->m_unitMovedByMe;
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
Unit* mover = _player->GetCharmedOrSelf();
if (_player->GetCharmed() && _player->GetCharmed()->GetTypeId() == TYPEID_PLAYER)
return;
mover->InterruptSpell(CURRENT_CHANNELED_SPELL);
@@ -412,7 +412,7 @@ void WorldSession::HandleCancelChanneling(WorldPacket& recvData)
void WorldSession::HandleTotemDestroyed(WorldPacket& recvPacket)
{
// ignore for remote control state
if (_player->m_unitMovedByMe != _player)
if (_player->IsCharming())
return;
uint8 slotId;
@@ -601,7 +601,7 @@ void WorldSession::HandleRequestCategoryCooldowns(WorldPacket& /*recvPacket*/)
void WorldSession::HandleCancelQueuedSpellOpcode(WorldPackets::Spells::CancelQueuedSpell& /*cancelQueuedSpell*/)
{
Unit* mover = _player->m_unitMovedByMe;
Unit* mover = _player->GetCharmedOrSelf();
if (mover != _player && mover->IsPlayer())
return;
+3
View File
@@ -210,6 +210,9 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
MovementInfo movementInfo; // used only for proper packet read
_player->ReadMovementInfo(recvData, &movementInfo);
if (!IsRightUnitBeingMoved(movementInfo.guid))
return;
// in taxi flight packet received in 2 case:
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multim-map taxi path
@@ -5535,7 +5535,7 @@ bool Movement::PrintInvalidSequenceElement(MovementStatusElements const element,
Movement::PacketSender::PacketSender(Unit* unit, uint16 serverControl, uint16 playerControl, uint16 broadcast /*= SMSG_PLAYER_MOVE*/, ExtraMovementStatusElement* extras /*= nullptr*/)
: _extraElements(extras), _unit(unit)
{
if (unit->GetTypeId() == TYPEID_PLAYER && unit->ToPlayer()->m_unitMovedByMe->GetTypeId() == TYPEID_PLAYER)
if (unit->IsPlayer() && unit->IsMovedByClient())
{
_selfOpcode = playerControl;
_broadcast = broadcast;
@@ -5552,7 +5552,7 @@ void Movement::PacketSender::Send() const
bool isPlayerMovement = false;
if (Player* player = _unit->ToPlayer())
{
isPlayerMovement = player->m_unitMovedByMe->GetTypeId() == TYPEID_PLAYER;
isPlayerMovement = player->IsMovedByClient();
if (isPlayerMovement && _selfOpcode != NULL_OPCODE)
{
WorldPacket data(_selfOpcode);
+69
View File
@@ -0,0 +1,69 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GameClient.h"
#include "WorldSession.h"
#include "Unit.h"
#include "Player.h"
GameClient::GameClient(WorldSession* sessionToServer)
{
_sessionToServer = sessionToServer;
_activelyMovedUnit = nullptr;
}
void GameClient::AddAllowedMover(Unit* unit)
{
if (GameClient* previousController = unit->GetGameClientMovingMe())
previousController->RemoveAllowedMover(unit);
_allowedMovers.insert(unit->GetGUID());
unit->SetGameClientMovingMe(this);
}
void GameClient::RemoveAllowedMover(Unit* unit)
{
_allowedMovers.erase(unit->GetGUID());
if (unit->GetGameClientMovingMe() == this)
{
unit->SetGameClientMovingMe(nullptr);
SetActivelyMovedUnit(nullptr);
}
}
bool GameClient::IsAllowedToMove(Unit* unit) const
{
return _allowedMovers.count(unit->GetGUID());
}
bool GameClient::IsAllowedToMove(ObjectGuid guid) const
{
return _allowedMovers.count(guid);
}
void GameClient::SetMovedUnit(Unit* target, bool allowMove)
{
if (allowMove)
AddAllowedMover(target);
else
RemoveAllowedMover(target);
}
void GameClient::SendDirectMessage(WorldPacket const* data) const
{
GetBasePlayer()->SendDirectMessage(data);
}
+54
View File
@@ -0,0 +1,54 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GAMECLIENT_H
#define __GAMECLIENT_H
#include "WorldSession.h"
class Player;
class Unit;
class TC_GAME_API GameClient
{
public:
GameClient(WorldSession* sessionToServer);
void AddAllowedMover(Unit* unit);
void RemoveAllowedMover(Unit* unit);
bool IsAllowedToMove(Unit* unit) const;
bool IsAllowedToMove(ObjectGuid guid) const;
void SetMovedUnit(Unit* target, bool allowMove);
Unit* GetActivelyMovedUnit() const { return _activelyMovedUnit; }
void SetActivelyMovedUnit(Unit* activelyMovedUnit) { _activelyMovedUnit = activelyMovedUnit; }
Player* GetBasePlayer() const { return _sessionToServer->GetPlayer(); }
void SendDirectMessage(WorldPacket const* data) const;
private:
// describe all units that this client has direct control over. Example, a player on a vehicle has client control over himself and the vehicle at the same time.
GuidUnorderedSet _allowedMovers;
// set/unset upon receiving CMSG_SET_ACTIVE_MOVER and CMSG_MOVE_NOT_ACTIVE_MOVER by the client
// in other words, this field is set by the client (as long as the change is allowed by the server)
Unit* _activelyMovedUnit;
WorldSession* _sessionToServer;
};
#endif // __GAMECLIENT_H
@@ -539,3 +539,26 @@ ByteBuffer& WorldPackets::operator<<(ByteBuffer& data, Movement::MovementMonster
return data;
}
WorldPacket const* WorldPackets::Movement::MoveSetActiveMover::Write()
{
_worldPacket.WriteBit(MoverGUID[5]);
_worldPacket.WriteBit(MoverGUID[7]);
_worldPacket.WriteBit(MoverGUID[3]);
_worldPacket.WriteBit(MoverGUID[6]);
_worldPacket.WriteBit(MoverGUID[0]);
_worldPacket.WriteBit(MoverGUID[4]);
_worldPacket.WriteBit(MoverGUID[1]);
_worldPacket.WriteBit(MoverGUID[2]);
_worldPacket.WriteByteSeq(MoverGUID[6]);
_worldPacket.WriteByteSeq(MoverGUID[2]);
_worldPacket.WriteByteSeq(MoverGUID[3]);
_worldPacket.WriteByteSeq(MoverGUID[0]);
_worldPacket.WriteByteSeq(MoverGUID[5]);
_worldPacket.WriteByteSeq(MoverGUID[7]);
_worldPacket.WriteByteSeq(MoverGUID[1]);
_worldPacket.WriteByteSeq(MoverGUID[4]);
return &_worldPacket;
}
@@ -248,6 +248,16 @@ namespace WorldPackets
uint8 TransfertAbort = 0;
uint8 Arg = 0;
};
class MoveSetActiveMover final : public ServerPacket
{
public:
MoveSetActiveMover(ObjectGuid moverGuid) : ServerPacket(SMSG_FLIGHT_SPLINE_SYNC, 4 + 8), MoverGUID(moverGuid) { }
WorldPacket const* Write() override;
ObjectGuid MoverGUID;
};
}
ByteBuffer& operator<<(ByteBuffer& data, Movement::MovementSpline const& movementSpline);
+3 -3
View File
@@ -462,14 +462,14 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck );
DEFINE_HANDLER(CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck );
DEFINE_HANDLER(CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck );
DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleGravityAckMessage );
DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleGravityAckMessage );
DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveGravityDisableAck );
DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveGravityEnableAck );
DEFINE_HANDLER(CMSG_MOVE_HOVER_ACK, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMoveHoverAck );
DEFINE_HANDLER(CMSG_MOVE_KNOCK_BACK_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveKnockBackAck );
DEFINE_HANDLER(CMSG_MOVE_NOT_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveNotActiveMover );
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_FLY, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes );
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCanFlyAckOpcode );
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes );
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCanTransitionBetweenSwinAndFlyAck);
DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HEIGHT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleSetCollisionHeightAck );
DEFINE_HANDLER(CMSG_MOVE_SPLINE_DONE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSplineDoneOpcode );
DEFINE_HANDLER(CMSG_MOVE_TIME_SKIPPED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleMoveTimeSkippedOpcode );
+29 -1
View File
@@ -28,6 +28,7 @@
#include "Common.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "GameClient.h"
#include "GameTime.h"
#include "Group.h"
#include "Guild.h"
@@ -136,7 +137,8 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun
m_currentBankerGUID(),
_timeSyncClockDeltaQueue(6),
_timeSyncClockDelta(0),
_pendingTimeSyncRequests()
_pendingTimeSyncRequests(),
_gameClient(new GameClient(this))
{
memset(m_Tutorials, 0, sizeof(m_Tutorials));
@@ -174,6 +176,8 @@ WorldSession::~WorldSession()
delete _warden;
delete _RBACData;
delete _gameClient;
///- empty incoming packet queue
WorldPacket* packet = nullptr;
while (_recvQueue.next(packet))
@@ -1589,3 +1593,27 @@ void WorldSession::SendTimeSync()
_timeSyncTimer = 5000;
_timeSyncNextCounter++;
}
bool WorldSession::IsRightUnitBeingMoved(ObjectGuid guid)
{
GameClient* client = GetGameClient();
// the client is attempting to tamper movement data
// edit: this wouldn't happen in retail but it does in TC, even with a legitimate client.
if (!client->GetActivelyMovedUnit() || client->GetActivelyMovedUnit()->GetGUID() != guid)
{
TC_LOG_DEBUG("entities.unit", "Attempt at tampering movement data by Player %s", _player->GetName().c_str());
return false;
}
// This can happen if a legitimate client has lost control of a unit but hasn't received SMSG_CONTROL_UPDATE before
// sending this packet yet. The server should silently ignore all MOVE messages coming from the client as soon
// as control over that unit is revoked (through a 'SMSG_CONTROL_UPDATE allowMove=false' message).
if (!client->IsAllowedToMove(guid))
{
TC_LOG_DEBUG("entities.unit", "Bad or outdated movement data by Player %s", _player->GetName().c_str());
return false;
}
return true;
}
+18 -15
View File
@@ -35,6 +35,7 @@
class BigNumber;
class Creature;
class GameClient;
class GameObject;
class InstanceSave;
class Item;
@@ -471,6 +472,8 @@ class TC_GAME_API WorldSession
void InitializeSession();
void InitializeSessionCallback(CharacterDatabaseQueryHolder const& realmHolder);
GameClient* GetGameClient() const { return _gameClient; };
rbac::RBACData* GetRBACData();
bool HasPermission(uint32 permissionId);
void LoadPermissions();
@@ -670,11 +673,6 @@ class TC_GAME_API WorldSession
// played time
void HandlePlayedTime(WorldPacket& recvPacket);
// new
void HandleMoveUnRootAck(WorldPacket& recvPacket);
void HandleMoveRootAck(WorldPacket& recvPacket);
void HandleLookingForGroup(WorldPacket& recvPacket);
// cemetery/graveyard related
void HandleReturnToGraveyard(WorldPacket& recvPacket);
void HandleRequestCemeteryList(WorldPacket& recvPacket);
@@ -686,11 +684,19 @@ class TC_GAME_API WorldSession
void HandleRequestHonorStatsOpcode(WorldPackets::Inspect::RequestHonorStats& packet);
void HandleRequestInspectRatedBgStatsOpcode(WorldPackets::Inspect::RequestInspectRatedBgStats& packet);
void HandleForceSpeedChangeAck(WorldPacket& recvData);
void HandleMoveKnockBackAck(WorldPacket& recvPacket);
void HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet);
void HandleMoveWaterWalkAck(WorldPacket& recvPacket);
void HandleFeatherFallAck(WorldPacket& recvData);
void HandleMoveHoverAck(WorldPacket& recvData);
void HandleMoveUnRootAck(WorldPacket& recvPacket);
void HandleMoveRootAck(WorldPacket& recvPacket);
void HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData);
void HandleMoveSetCanTransitionBetweenSwinAndFlyAck(WorldPacket& recvData);
void HandleMoveGravityDisableAck(WorldPacket& recvData);
void HandleMoveGravityEnableAck(WorldPacket& recvData);
void HandleSetCollisionHeightAck(WorldPacket& recvData);
void HandleMountSpecialAnimOpcode(WorldPacket& recvdata);
@@ -701,13 +707,6 @@ class TC_GAME_API WorldSession
// repair
void HandleRepairItemOpcode(WorldPacket& recvPacket);
// Knockback
void HandleMoveKnockBackAck(WorldPacket& recvPacket);
void HandleGravityAckMessage(WorldPacket & recvData);
void HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet);
void HandleForceSpeedChangeAck(WorldPacket& recvData);
void HandleSetCollisionHeightAck(WorldPacket& recvData);
void HandlePingOpcode(WorldPacket& recvPacket);
void HandleRepopRequestOpcode(WorldPacket& recvPacket);
void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket);
@@ -1088,7 +1087,6 @@ class TC_GAME_API WorldSession
void HandleSetDungeonDifficultyOpcode(WorldPacket& recvData);
void HandleSetRaidDifficultyOpcode(WorldPacket& recvData);
void HandleChangePlayerDifficulty(WorldPacket& recvData);
void HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData);
void HandleSetTitleOpcode(WorldPacket& recvData);
void HandleRealmSplitOpcode(WorldPacket& recvData);
void HandleTimeSyncResp(WorldPacket& recvData);
@@ -1322,6 +1320,9 @@ class TC_GAME_API WorldSession
return _legitCharacters.find(lowGUID) != _legitCharacters.end();
}
// Movement helpers
bool IsRightUnitBeingMoved(ObjectGuid guid);
// this stores the GUIDs of the characters who can login
// characters who failed on Player::BuildEnumData shouldn't login
GuidSet _legitCharacters;
@@ -1395,6 +1396,8 @@ class TC_GAME_API WorldSession
ConnectToKey _instanceConnectKey;
GameClient* _gameClient;
WorldSession(WorldSession const& right) = delete;
WorldSession& operator=(WorldSession const& right) = delete;
};
+8 -6
View File
@@ -27,6 +27,7 @@
#include "DisableMgr.h"
#include "DynamicObject.h"
#include "G3DPosition.hpp"
#include "GameClient.h"
#include "GameObjectAI.h"
#include "GameTime.h"
#include "GridNotifiersImpl.h"
@@ -3288,7 +3289,7 @@ void Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggered
m_powerCost = m_CastItem ? 0 : m_spellInfo->CalcPowerCost(m_caster, m_spellSchoolMask, this);
// Set combo point requirement
if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->m_playerMovingMe)
if ((_triggeredCastFlags & TRIGGERED_IGNORE_COMBO_POINTS) || m_CastItem || !m_caster->IsMovedByClient())
m_needComboPoints = false;
MountResult mountResult = MountResult::Ok;
@@ -3898,18 +3899,19 @@ void Spell::_handle_immediate_phase()
void Spell::_handle_finish_phase()
{
if (m_caster->m_playerMovingMe)
if (m_caster->IsMovedByClient())
{
Player* mover = m_caster->GetGameClientMovingMe()->GetBasePlayer();
// Take for real after all targets are processed
if (m_needComboPoints)
m_caster->m_playerMovingMe->ClearComboPoints();
mover->ClearComboPoints();
// Real add combo points from effects
if (m_comboPointGain)
m_caster->m_playerMovingMe->GainSpellComboPoints(m_comboPointGain);
mover->GainSpellComboPoints(m_comboPointGain);
if (m_spellInfo->PowerType == POWER_HOLY_POWER && m_caster->m_playerMovingMe->getClass() == CLASS_PALADIN)
HandleHolyPower(m_caster->m_playerMovingMe);
if (m_spellInfo->PowerType == POWER_HOLY_POWER && mover->getClass() == CLASS_PALADIN)
HandleHolyPower(mover);
}
if (m_caster->m_extraAttacks && m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
+3 -2
View File
@@ -28,6 +28,7 @@
#include "Formulas.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "GameClient.h"
#include "GossipDef.h"
#include "GridNotifiers.h"
#include "Group.h"
@@ -3488,13 +3489,13 @@ void Spell::EffectAddComboPoints(SpellEffIndex /*effIndex*/)
if (!unitTarget)
return;
if (!m_caster->m_playerMovingMe)
if (!m_caster->IsMovedByClient())
return;
if (damage <= 0)
return;
m_caster->m_playerMovingMe->AddComboPoints(unitTarget, damage, this);
m_caster->GetGameClientMovingMe()->GetBasePlayer()->AddComboPoints(unitTarget, damage, this);
}
void Spell::EffectDuel(SpellEffIndex effIndex)
+4 -3
View File
@@ -20,6 +20,7 @@
#include "Corpse.h"
#include "Creature.h"
#include "DBCStores.h"
#include "GameClient.h"
#include "InstanceScript.h"
#include "Item.h"
#include "ItemTemplate.h"
@@ -528,8 +529,8 @@ int32 SpellEffectInfo::CalcValue(Unit const* caster, int32 const* bp, Unit const
if (caster)
{
// bonus amount from combo points
if (_spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DAMAGE) && caster->m_playerMovingMe && comboDamage)
if (uint8 comboPoints = caster->m_playerMovingMe->GetComboPoints())
if (_spellInfo->HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DAMAGE) && caster->IsMovedByClient() && comboDamage)
if (uint8 comboPoints = caster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints())
value += comboDamage * comboPoints;
value = caster->ApplyEffectModifiers(_spellInfo, _effIndex, value);
@@ -3370,7 +3371,7 @@ int32 SpellInfo::CalcDuration(Unit* caster, Spell* spell) const
// Increase duration based on combo points
if (HasAttribute(SPELL_ATTR1_FINISHING_MOVE_DURATION))
{
if (uint8 comboPoints = (caster && caster->m_playerMovingMe) ? caster->m_playerMovingMe->GetComboPoints() : 0)
if (uint8 comboPoints = (caster && caster->IsMovedByClient()) ? caster->GetGameClientMovingMe()->GetBasePlayer()->GetComboPoints() : 0)
{
if (GetDuration() != GetMaxDuration() && GetDuration() != -1)
duration += int32((GetMaxDuration() - GetDuration()) * comboPoints / 5);
@@ -221,17 +221,13 @@ struct npc_grim_batol_battered_red_drake: public VehicleAI
me->PlayOneShotAnimKitId(ANIM_KIT_ID_LIFTOFF);
me->SetAnimationTier(AnimationTier::Fly);
player->SetMover(me);
_playerGuid = player->GetGUID();
_events.ScheduleEvent(EVENT_SET_HOVERING, 2s);
_events.ScheduleEvent(EVENT_PREPARE_BOMBARDMENT, 1s);
}
else
{
player->SetMover(player);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
}
void UpdateAI(uint32 diff) override