diff options
| author | Chaouki Dhib <chaodhib@gmail.com> | 2021-05-16 13:16:08 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-16 13:16:08 +0200 |
| commit | 2d114ea560cd8716af2b0d12990fc3480ecaf2b7 (patch) | |
| tree | aaa711aa4d63e9b33d8e804d481425368ddcee18 /src/server/game/Server | |
| parent | edcaac6c959e944dc6d6dc224666b832521412b4 (diff) | |
Core/Movement: Improve client control logic (#26348)
Diffstat (limited to 'src/server/game/Server')
| -rw-r--r-- | src/server/game/Server/GameClient.cpp | 63 | ||||
| -rw-r--r-- | src/server/game/Server/GameClient.h | 54 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 10 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 33 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.h | 29 |
5 files changed, 169 insertions, 20 deletions
diff --git a/src/server/game/Server/GameClient.cpp b/src/server/game/Server/GameClient.cpp new file mode 100644 index 00000000000..f2a662d63dd --- /dev/null +++ b/src/server/game/Server/GameClient.cpp @@ -0,0 +1,63 @@ +/* + * 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) +{ + _allowedMovers.insert(unit->GetGUID()); + unit->SetGameClientMovingMe(this); +} + +void GameClient::RemoveAllowedMover(Unit* unit) +{ + _allowedMovers.erase(unit->GetGUID()); + if (unit->GetGameClientMovingMe() == this) + unit->SetGameClientMovingMe(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); +} diff --git a/src/server/game/Server/GameClient.h b/src/server/game/Server/GameClient.h new file mode 100644 index 00000000000..4baf5015ddb --- /dev/null +++ b/src/server/game/Server/GameClient.h @@ -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 diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a8d84a8d0ea..0dff9c1ea93 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -960,7 +960,7 @@ void OpcodeTable::Initialize() /*0x33D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOTD, STATUS_NEVER); /*0x33E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_NEVER); /*0x33F*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_UNSET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_NEVER); - /*0x340*/ DEFINE_HANDLER(CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + /*0x340*/ DEFINE_HANDLER(CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCanTransitionBetweenSwinAndFlyAck); /*0x341*/ DEFINE_HANDLER(MSG_MOVE_START_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x342*/ DEFINE_HANDLER(MSG_MOVE_STOP_SWIM_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x343*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_CAN_FLY, STATUS_NEVER); @@ -1245,7 +1245,7 @@ void OpcodeTable::Initialize() /*0x45A*/ DEFINE_HANDLER(MSG_MOVE_SET_PITCH_RATE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x45B*/ DEFINE_HANDLER(MSG_MOVE_SET_PITCH_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x45C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_PITCH_RATE_CHANGE, STATUS_NEVER); - /*0x45D*/ DEFINE_HANDLER(CMSG_FORCE_PITCH_RATE_CHANGE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + /*0x45D*/ DEFINE_HANDLER(CMSG_FORCE_PITCH_RATE_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleForceSpeedChangeAck); /*0x45E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_SET_PITCH_RATE, STATUS_NEVER); /*0x45F*/ DEFINE_HANDLER(CMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x460*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_NEVER); @@ -1359,9 +1359,9 @@ void OpcodeTable::Initialize() /*0x4CC*/ DEFINE_HANDLER(CMSG_END_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x4CD*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_NEVER); /*0x4CE*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_DISABLE, STATUS_NEVER); - /*0x4CF*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + /*0x4CF*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveGravityDisableAck ); /*0x4D0*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_ENABLE, STATUS_NEVER); - /*0x4D1*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + /*0x4D1*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveGravityEnableAck); /*0x4D2*/ DEFINE_SERVER_OPCODE_HANDLER(MSG_MOVE_GRAVITY_CHNG, STATUS_NEVER); /*0x4D3*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER); /*0x4D4*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_ENABLE, STATUS_NEVER); @@ -1431,7 +1431,7 @@ void OpcodeTable::Initialize() /*0x514*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_ALL_COMBAT_LOG, STATUS_NEVER); /*0x515*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_NEVER); /*0x516*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER); - /*0x517*/ DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + /*0x517*/ DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveSetCollisionHgtAck ); /*0x518*/ DEFINE_HANDLER(MSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x519*/ DEFINE_HANDLER(CMSG_CLEAR_RANDOM_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x51A*/ DEFINE_HANDLER(CMSG_CLEAR_HOLIDAY_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 18b46ffd73e..2405631cd75 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -28,6 +28,7 @@ #include "Common.h" #include "DatabaseEnv.h" #include "DBCStructure.h" +#include "GameClient.h" #include "GameTime.h" #include "Group.h" #include "Guild.h" @@ -136,7 +137,8 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS _pendingTimeSyncRequests(), _timeSyncNextCounter(0), _timeSyncTimer(0), - _calendarEventCreationCooldown(0) + _calendarEventCreationCooldown(0), + _gameClient(new GameClient(this)) { memset(m_Tutorials, 0, sizeof(m_Tutorials)); @@ -165,6 +167,8 @@ WorldSession::~WorldSession() delete _RBACData; + delete _gameClient; + ///- empty incoming packet queue WorldPacket* packet = nullptr; while (_recvQueue.next(packet)) @@ -973,8 +977,8 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi) */ REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER && - !GetPlayer()->GetUnitBeingMoved()->HasAuraType(SPELL_AURA_FLY) && - !GetPlayer()->GetUnitBeingMoved()->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED), + !GetPlayer()->GetCharmedOrSelf()->HasAuraType(SPELL_AURA_FLY) && + !GetPlayer()->GetCharmedOrSelf()->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED), MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY); //! Cannot fly and fall at the same time @@ -1655,3 +1659,26 @@ void WorldSession::SendTimeSync() _timeSyncTimer = _timeSyncNextCounter == 0 ? 5000 : 10000; _timeSyncNextCounter++; } + +bool WorldSession::IsRightUnitBeingMoved(ObjectGuid guid) +{ + GameClient* client = GetGameClient(); + + // the client is attempting to tamper movement data + if (!client->GetActivelyMovedUnit() || client->GetActivelyMovedUnit()->GetGUID() != guid) + { + TC_LOG_INFO("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; +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index d2d31892004..582b083f2ff 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -37,6 +37,7 @@ #include <boost/circular_buffer.hpp> class Creature; +class GameClient; class GameObject; class InstanceSave; class Item; @@ -427,6 +428,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(); @@ -622,20 +625,25 @@ class TC_GAME_API WorldSession // played time void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet); - // new - void HandleMoveUnRootAck(WorldPacket& recvPacket); - void HandleMoveRootAck(WorldPacket& recvPacket); - // new inspect void HandleInspectOpcode(WorldPacket& recvPacket); // new party stats void HandleInspectHonorStatsOpcode(WorldPacket& recvPacket); + void HandleForceSpeedChangeAck(WorldPacket& recvData); + void HandleMoveKnockBackAck(WorldPacket& recvPacket); + void HandleMoveTeleportAck(WorldPacket& recvPacket); 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 HandleMoveSetCollisionHgtAck(WorldPacket& recvData); void HandleMountSpecialAnimOpcode(WorldPacket& recvdata); @@ -646,12 +654,6 @@ class TC_GAME_API WorldSession // repair void HandleRepairItemOpcode(WorldPacket& recvPacket); - // Knockback - void HandleMoveKnockBackAck(WorldPacket& recvPacket); - - void HandleMoveTeleportAck(WorldPacket& recvPacket); - void HandleForceSpeedChangeAck(WorldPacket& recvData); - void HandleRepopRequest(WorldPackets::Misc::RepopRequest& packet); void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket); void HandleLootMoneyOpcode(WorldPacket& recvPacket); @@ -987,7 +989,6 @@ class TC_GAME_API WorldSession void HandleFarSightOpcode(WorldPacket& recvData); void HandleSetDungeonDifficultyOpcode(WorldPacket& recvData); void HandleSetRaidDifficultyOpcode(WorldPacket& recvData); - void HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData); void HandleSetTitleOpcode(WorldPacket& recvData); void HandleRealmSplitOpcode(WorldPacket& recvData); void HandleTimeSyncResponse(WorldPacket& recvData); @@ -1170,6 +1171,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; @@ -1239,6 +1243,7 @@ class TC_GAME_API WorldSession // Packets cooldown time_t _calendarEventCreationCooldown; + GameClient* _gameClient; WorldSession(WorldSession const& right) = delete; WorldSession& operator=(WorldSession const& right) = delete; |
