aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Server
diff options
context:
space:
mode:
authorChaouki Dhib <chaodhib@gmail.com>2021-05-16 13:16:08 +0200
committerGitHub <noreply@github.com>2021-05-16 13:16:08 +0200
commit2d114ea560cd8716af2b0d12990fc3480ecaf2b7 (patch)
treeaaa711aa4d63e9b33d8e804d481425368ddcee18 /src/server/game/Server
parentedcaac6c959e944dc6d6dc224666b832521412b4 (diff)
Core/Movement: Improve client control logic (#26348)
Diffstat (limited to 'src/server/game/Server')
-rw-r--r--src/server/game/Server/GameClient.cpp63
-rw-r--r--src/server/game/Server/GameClient.h54
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp10
-rw-r--r--src/server/game/Server/WorldSession.cpp33
-rw-r--r--src/server/game/Server/WorldSession.h29
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;