diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 4ab3d330a..6cdcf0d84 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -241,125 +241,27 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) recv_data >> movementInfo; /*----------------*/ - // ignore wrong guid (player attempt cheating own session for not own guid possible...) - if (guid != mover->GetObjectGuid()) + if (!VerifyMovementInfo(movementInfo,guid,mover)) return; - if (!MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - /* handle special cases */ - if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) - { - // transports size limited - // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) - if( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - if( !MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, - movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) - { - recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } - - // if we boarded a transport, add us to it - if (plMover && !plMover->m_transport) - { - // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list - for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) - { - if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) - { - plMover->m_transport = (*iter); - (*iter)->AddPassenger(plMover); - break; - } - } - } - } - else if (plMover && plMover->m_transport) // if we were on a transport, leave - { - plMover->m_transport->RemovePassenger(plMover); - plMover->m_transport = NULL; - movementInfo.ClearTransportData(); - } - // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->IsTaxiFlying()) plMover->HandleFall(movementInfo); - if (plMover && (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater())) - { - // now client not include swimming flag in case jumping under water - plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); - } - - /*----------------------*/ - /* process position-change */ - movementInfo.UpdateTime(getMSTime()); + HandleMoverRelocation(movementInfo,mover,plMover); - WorldPacket data(opcode, recv_data.size()); - data.appendPackGUID(mover->GetGUID()); // write guid - movementInfo.Write(data); // write data - mover->SendMessageToSetExcept(&data, _player); - - if(plMover) // nothing is charmed, or player charmed - { - plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); - plMover->m_movementInfo = movementInfo; + if (plMover) plMover->UpdateFallInformationIfNeed(movementInfo, opcode); - // after move info set - if ((opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE)) - plMover->UpdateWalkMode(plMover, false); + // after move info set + if (opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE) + mover->UpdateWalkMode(mover, false); - if(plMover->isMovingOrTurning()) - plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); - - if(movementInfo.GetPos()->z < -500.0f) - { - if(plMover->InBattleGround() - && plMover->GetBattleGround() - && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) - { - // do nothing, the handle already did if returned true - } - else - { - // NOTE: this is actually called many times while falling - // even after the player has been teleported away - // TODO: discard movement packets after the player is rooted - if(plMover->isAlive()) - { - plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); - // pl can be alive if GM/etc - if(!plMover->isAlive()) - { - // change the death state to CORPSE to prevent the death timer from - // starting in the next player update - plMover->KillPlayer(); - plMover->BuildPlayerRepop(); - } - } - - // cancel the death timer here if started - plMover->RepopAtGraveyard(); - } - } - } - else // creature charmed - { - if(mover->IsInWorld()) - mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); - } + WorldPacket data(opcode, recv_data.size()); + data << mover->GetPackGUID(); // write guid + movementInfo.Write(data); // write data + mover->SendMessageToSetExcept(&data, _player); } void WorldSession::HandleForceSpeedChangeAckOpcodes(WorldPacket &recv_data) @@ -513,12 +415,36 @@ void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data ) { DEBUG_LOG("CMSG_MOVE_KNOCK_BACK_ACK"); - ObjectGuid guid; // guid - unused + Unit *mover = _player->GetMover(); + Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; + + // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck + if(plMover && plMover->IsBeingTeleported()) + { + recv_data.rpos(recv_data.wpos()); // prevent warnings spam + return; + } + + ObjectGuid guid; MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); - recv_data >> Unused(); // unk + recv_data >> Unused(); // knockback packets counter recv_data >> movementInfo; + + if (!VerifyMovementInfo(movementInfo,guid,mover)) + return; + + HandleMoverRelocation(movementInfo, mover, plMover); + + WorldPacket data(MSG_MOVE_KNOCK_BACK, recv_data.size() + 15); + data << mover->GetPackGUID(); + data << movementInfo; + data << movementInfo.GetJumpInfo().sinAngle; + data << movementInfo.GetJumpInfo().cosAngle; + data << movementInfo.GetJumpInfo().xyspeed; + data << movementInfo.GetJumpInfo().velocity; + mover->SendMessageToSetExcept(&data, _player); } void WorldSession::HandleMoveHoverAck( WorldPacket& recv_data ) @@ -559,3 +485,102 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) _player->SummonIfPossible(agree); } + +bool WorldSession::VerifyMovementInfo(MovementInfo& movementInfo, ObjectGuid& guid, Unit* mover) const +{ + // ignore wrong guid (player attempt cheating own session for not own guid possible...) + if (guid != mover->GetObjectGuid()) + return false; + + if (!MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) + return false; + + if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) + { + // transports size limited + // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) + if( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) + return false; + + if( !MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, + movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) + { + return false; + } + } + + return true; +} + +void WorldSession::HandleMoverRelocation(MovementInfo& movementInfo, Unit* mover, Player* plMover) +{ + movementInfo.UpdateTime(getMSTime()); + + if (plMover) + { + if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT) && !plMover->m_transport) + { + // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list + for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) + { + if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) + { + plMover->m_transport = (*iter); + (*iter)->AddPassenger(plMover); + break; + } + } + } + else if (plMover->m_transport) // if we were on a transport, leave + { + plMover->m_transport->RemovePassenger(plMover); + plMover->m_transport = NULL; + movementInfo.ClearTransportData(); + } + + if (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater()) + { + // now client not include swimming flag in case jumping under water + plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); + } + + plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); + plMover->m_movementInfo = movementInfo; + + if(movementInfo.GetPos()->z < -500.0f) + { + if(plMover->InBattleGround() + && plMover->GetBattleGround() + && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) + { + // do nothing, the handle already did if returned true + } + else + { + // NOTE: this is actually called many times while falling + // even after the player has been teleported away + // TODO: discard movement packets after the player is rooted + if(plMover->isAlive()) + { + plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); + // pl can be alive if GM/etc + if(!plMover->isAlive()) + { + // change the death state to CORPSE to prevent the death timer from + // starting in the next player update + plMover->KillPlayer(); + plMover->BuildPlayerRepop(); + } + } + + // cancel the death timer here if started + plMover->RepopAtGraveyard(); + } + } + } + else // creature charmed + { + if (mover->IsInWorld()) + mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); + } +} diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 517e8cec4..33584ed4f 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -6042,6 +6042,8 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele else RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); + // move and update visible state if need m->PlayerRelocation(this, x, y, z, orientation); @@ -6056,7 +6058,7 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION); if (GetTrader() && !IsWithinDistInMap(GetTrader(), INTERACTION_DISTANCE)) - GetSession()->SendCancelTrade(); // will clode both side trade windows + GetSession()->SendCancelTrade(); // will close both side trade windows } // code block for underwater state update diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index ad3c956ee..612a79fba 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -101,10 +101,10 @@ void MovementInfo::Read(ByteBuffer &data) if(HasMovementFlag(MOVEFLAG_FALLING)) { - data >> j_velocity; - data >> j_sinAngle; - data >> j_cosAngle; - data >> j_xyspeed; + data >> jump.velocity; + data >> jump.sinAngle; + data >> jump.cosAngle; + data >> jump.xyspeed; } if(HasMovementFlag(MOVEFLAG_SPLINE_ELEVATION)) @@ -146,10 +146,10 @@ void MovementInfo::Write(ByteBuffer &data) const if(HasMovementFlag(MOVEFLAG_FALLING)) { - data << j_velocity; - data << j_sinAngle; - data << j_cosAngle; - data << j_xyspeed; + data << jump.velocity; + data << jump.sinAngle; + data << jump.cosAngle; + data << jump.xyspeed; } if(HasMovementFlag(MOVEFLAG_SPLINE_ELEVATION)) diff --git a/src/game/Unit.h b/src/game/Unit.h index 9b7aebadb..ddd82a3de 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -750,8 +750,7 @@ class MovementInfo { public: MovementInfo() : moveFlags(MOVEFLAG_NONE), moveFlags2(MOVEFLAG2_NONE), time(0), - t_time(0), t_seat(-1), t_time2(0), s_pitch(0.0f), fallTime(0), j_velocity(0.0f), j_sinAngle(0.0f), - j_cosAngle(0.0f), j_xyspeed(0.0f), u_unk1(0.0f) {} + t_time(0), t_seat(-1), t_time2(0), s_pitch(0.0f), fallTime(0), u_unk1(0.0f) {} // Read/Write methods void Read(ByteBuffer &data); @@ -795,6 +794,13 @@ class MovementInfo void ChangePosition(float x, float y, float z, float o) { pos.x = x; pos.y = y; pos.z = z; pos.o = o; } void UpdateTime(uint32 _time) { time = _time; } + struct JumpInfo + { + JumpInfo() : velocity(0.f), sinAngle(0.f), cosAngle(0.f), xyspeed(0.f) {} + float velocity, sinAngle, cosAngle, xyspeed; + }; + + JumpInfo const& GetJumpInfo() const { return jump; } private: // common uint32 moveFlags; // see enum MovementFlags @@ -812,7 +818,7 @@ class MovementInfo // last fall time uint32 fallTime; // jumping - float j_velocity, j_sinAngle, j_cosAngle, j_xyspeed; + JumpInfo jump; // spline float u_unk1; }; diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index e6ff09b79..e6d68259e 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -44,6 +44,7 @@ class QueryResult; class LoginQueryHolder; class CharacterHandler; class GMTicket; +class MovementInfo; struct OpcodeHandler; @@ -777,6 +778,8 @@ class MANGOS_DLL_SPEC WorldSession private: // private trade methods void moveItems(Item* myItems[], Item* hisItems[]); + bool VerifyMovementInfo(MovementInfo&,ObjectGuid&, Unit*) const; + void HandleMoverRelocation(MovementInfo&, Unit*, Player*); void ExecuteOpcode( OpcodeHandler const& opHandle, WorldPacket* packet ); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index ab962df17..a417cfaa3 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10652" + #define REVISION_NR "10653" #endif // __REVISION_NR_H__