Core/Movement: ported client control logic updates from 335 branch
This commit is contained in:
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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user