2010-10-07 15:35:36 +02:00
/*
2019-01-01 10:13:49 +01:00
* Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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/>.
2008-10-11 14:16:25 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/** \file
\ingroup u2w
*/
2009-10-17 15:51:44 -07:00
2017-05-18 23:52:58 +02:00
#include "WorldSession.h"
2017-05-12 18:49:51 +02:00
#include "QueryHolder.h"
2013-02-25 10:47:50 +01:00
#include "AccountMgr.h"
2015-02-23 22:35:26 +01:00
#include "AuthenticationPackets.h"
2017-05-18 23:52:58 +02:00
#include "BattlePetMgr.h"
#include "BattlegroundMgr.h"
2016-03-28 17:12:57 +02:00
#include "BattlenetPackets.h"
2014-11-03 19:11:14 +01:00
#include "CharacterPackets.h"
2015-02-23 20:23:33 +01:00
#include "ChatPackets.h"
2017-05-18 23:52:58 +02:00
#include "DatabaseEnv.h"
#include "Group.h"
#include "Guild.h"
#include "GuildMgr.h"
2018-01-06 01:21:59 +01:00
#include "IpAddress.h"
2017-06-04 01:00:45 +02:00
#include "Map.h"
2016-06-04 11:26:57 +01:00
#include "Metric.h"
2017-05-18 23:52:58 +02:00
#include "MiscPackets.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
#include "PacketUtilities.h"
#include "Player.h"
#include "QueryHolder.h"
2017-05-11 22:29:51 +02:00
#include "Random.h"
2017-05-18 23:52:58 +02:00
#include "RBAC.h"
#include "Realm.h"
#include "ScriptMgr.h"
#include "SocialMgr.h"
#include "WardenWin.h"
#include "World.h"
#include "WorldSocket.h"
2015-07-25 17:34:41 +02:00
2012-10-24 15:34:23 +02:00
namespace {
std :: string const DefaultPlayerName = "<none>" ;
} // namespace
2011-06-12 02:06:07 +02:00
bool MapSessionFilter :: Process ( WorldPacket * packet )
2010-12-13 22:37:56 +01:00
{
2014-12-06 16:55:17 +02:00
ClientOpcodeHandler const * opHandle = opcodeTable [ static_cast < OpcodeClient > ( packet -> GetOpcode ())];
2010-12-29 20:20:09 -08:00
2010-12-13 22:37:56 +01:00
//let's check if our opcode can be really processed in Map::Update()
2012-09-11 15:59:45 +02:00
if ( opHandle -> ProcessingPlace == PROCESS_INPLACE )
2010-12-13 22:37:56 +01:00
return true ;
//we do not process thread-unsafe packets
2012-09-11 15:59:45 +02:00
if ( opHandle -> ProcessingPlace == PROCESS_THREADUNSAFE )
2010-12-13 22:37:56 +01:00
return false ;
2011-11-07 11:06:39 -06:00
Player * player = m_pSession -> GetPlayer ();
if ( ! player )
2010-12-13 22:37:56 +01:00
return false ;
//in Map::Update() we do not process packets where player is not in world!
2011-11-07 11:06:39 -06:00
return player -> IsInWorld ();
2010-12-13 22:37:56 +01:00
}
//we should process ALL packets when player is not in world/logged in
//OR packet handler is not thread-safe!
2011-06-12 02:06:07 +02:00
bool WorldSessionFilter :: Process ( WorldPacket * packet )
2010-12-13 22:37:56 +01:00
{
2014-12-06 16:55:17 +02:00
ClientOpcodeHandler const * opHandle = opcodeTable [ static_cast < OpcodeClient > ( packet -> GetOpcode ())];
2010-12-13 22:37:56 +01:00
//check if packet handler is supposed to be safe
2012-09-11 15:59:45 +02:00
if ( opHandle -> ProcessingPlace == PROCESS_INPLACE )
2010-12-13 22:37:56 +01:00
return true ;
//thread-unsafe packets should be processed in World::UpdateSessions()
2012-09-11 15:59:45 +02:00
if ( opHandle -> ProcessingPlace == PROCESS_THREADUNSAFE )
2010-12-13 22:37:56 +01:00
return true ;
//no player attached? -> our client! ^^
2011-11-07 11:06:39 -06:00
Player * player = m_pSession -> GetPlayer ();
if ( ! player )
2010-12-13 22:37:56 +01:00
return true ;
//lets process all packets for non-in-the-world player
2011-11-07 11:06:39 -06:00
return ( player -> IsInWorld () == false );
2010-12-13 22:37:56 +01:00
}
2008-10-11 14:16:25 -05:00
/// WorldSession constructor
2016-03-28 15:23:41 +02:00
WorldSession :: WorldSession ( uint32 id , std :: string && name , uint32 battlenetAccountId , std :: shared_ptr < WorldSocket > sock , AccountTypes sec , uint8 expansion , time_t mute_time ,
std :: string os , LocaleConstant locale , uint32 recruiter , bool isARecruiter ) :
2012-11-16 09:51:44 +01:00
m_muteTime ( mute_time ),
m_timeOutTime ( 0 ),
2013-08-30 16:03:37 +01:00
AntiDOS ( this ),
2014-10-25 17:11:35 +02:00
m_GUIDLow ( UI64LIT ( 0 )),
2012-11-16 09:51:44 +01:00
_player ( NULL ),
_security ( sec ),
_accountId ( id ),
2015-06-20 00:59:31 +02:00
_accountName ( std :: move ( name )),
2014-06-08 17:58:28 +02:00
_battlenetAccountId ( battlenetAccountId ),
2018-02-10 01:24:00 +01:00
m_accountExpansion ( expansion ),
m_expansion ( std :: min < uint8 > ( expansion , sWorld -> getIntConfig ( CONFIG_EXPANSION ))),
2016-03-28 15:23:41 +02:00
_os ( os ),
2016-06-06 09:16:59 +02:00
_battlenetRequestToken ( 0 ),
2012-11-16 09:51:44 +01:00
_warden ( NULL ),
_logoutTime ( 0 ),
m_inQueue ( false ),
m_playerLogout ( false ),
m_playerRecentlyLogout ( false ),
m_playerSave ( false ),
m_sessionDbcLocale ( sWorld -> GetAvailableDbcLocale ( locale )),
m_sessionDbLocaleIndex ( locale ),
m_latency ( 0 ),
2013-09-26 20:03:39 +02:00
m_clientTimeDelay ( 0 ),
2017-01-28 05:00:28 +01:00
_tutorialsChanged ( TUTORIALS_FLAG_NONE ),
2012-11-16 09:51:44 +01:00
_filterAddonMessages ( false ),
recruiterId ( recruiter ),
isRecruiter ( isARecruiter ),
2014-06-03 01:12:34 +01:00
_RBACData ( NULL ),
expireTime ( 60000 ), // 1 min after socket loss, session is deleted
2014-06-07 22:47:50 +02:00
forceExit ( false ),
2015-09-09 14:52:32 +02:00
m_currentBankerGUID (),
2015-09-14 11:29:57 +02:00
_battlePetMgr ( Trinity :: make_unique < BattlePetMgr > ( this )),
_collectionMgr ( Trinity :: make_unique < CollectionMgr > ( this ))
2008-10-11 14:16:25 -05:00
{
2014-11-19 03:42:38 +01:00
memset ( _tutorials , 0 , sizeof ( _tutorials ));
2013-12-14 18:41:26 +01:00
2008-11-06 16:10:28 -06:00
if ( sock )
{
2014-07-26 23:26:01 +02:00
m_Address = sock -> GetRemoteIpAddress (). to_string ();
2010-05-16 03:42:05 +02:00
ResetTimeOutTime ();
2011-12-31 00:32:05 +01:00
LoginDatabase . PExecute ( "UPDATE account SET online = 1 WHERE id = %u;" , GetAccountId ()); // One-time query
2008-11-06 16:10:28 -06:00
}
2011-06-22 18:03:07 +02:00
2014-11-09 21:36:06 +01:00
m_Socket [ CONNECTION_TYPE_REALM ] = sock ;
2015-12-29 21:22:31 +01:00
_instanceConnectKey . Raw = UI64LIT ( 0 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// WorldSession destructor
WorldSession ::~ WorldSession ()
{
///- unload player if not unloaded
2008-11-06 16:10:28 -06:00
if ( _player )
LogoutPlayer ( true );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// - If have unclosed socket, close it
2014-11-09 00:37:33 +01:00
for ( uint8 i = 0 ; i < 2 ; ++ i )
2008-10-11 14:16:25 -05:00
{
2014-11-09 00:37:33 +01:00
if ( m_Socket [ i ])
{
m_Socket [ i ] -> CloseSocket ();
m_Socket [ i ]. reset ();
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2013-02-04 08:21:25 +01:00
delete _warden ;
delete _RBACData ;
2012-02-19 13:51:16 +01:00
2008-10-11 14:16:25 -05:00
///- empty incoming packet queue
2011-06-12 02:06:07 +02:00
WorldPacket * packet = NULL ;
2010-04-07 19:13:19 +02:00
while ( _recvQueue . next ( packet ))
2008-10-11 14:16:25 -05:00
delete packet ;
2009-10-17 15:51:44 -07:00
2011-12-31 00:32:05 +01:00
LoginDatabase . PExecute ( "UPDATE account SET online = 0 WHERE id = %u;" , GetAccountId ()); // One-time query
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-09-25 15:57:23 +02:00
bool WorldSession :: PlayerDisconnected () const
{
return ! ( m_Socket [ CONNECTION_TYPE_REALM ] && m_Socket [ CONNECTION_TYPE_REALM ] -> IsOpen () &&
m_Socket [ CONNECTION_TYPE_INSTANCE ] && m_Socket [ CONNECTION_TYPE_INSTANCE ] -> IsOpen ());
}
2012-10-24 15:34:23 +02:00
std :: string const & WorldSession :: GetPlayerName () const
{
return _player != NULL ? _player -> GetName () : DefaultPlayerName ;
}
2012-08-21 23:40:38 +01:00
2012-10-24 15:34:23 +02:00
std :: string WorldSession :: GetPlayerInfo () const
{
std :: ostringstream ss ;
2012-08-21 23:40:38 +01:00
2015-06-21 02:15:13 +02:00
ss << "[Player: " ;
if ( ! m_playerLoading . IsEmpty ())
2015-02-23 22:35:26 +01:00
ss << "Logging in: " << m_playerLoading . ToString () << ", " ;
2015-06-21 02:15:13 +02:00
else if ( _player )
ss << _player -> GetName () << ' ' << _player -> GetGUID (). ToString () << ", " ;
2014-09-14 17:29:13 +02:00
2015-06-21 02:15:13 +02:00
ss << "Account: " << GetAccountId () << "]" ;
2012-08-21 23:40:38 +01:00
2012-10-24 15:34:23 +02:00
return ss . str ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Send a packet to the client
2014-11-03 20:23:21 +01:00
void WorldSession :: SendPacket ( WorldPacket const * packet , bool forced /*= false*/ )
2008-10-11 14:16:25 -05:00
{
2012-08-22 13:38:55 +02:00
if ( packet -> GetOpcode () == NULL_OPCODE )
2011-11-20 18:28:18 +01:00
{
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network.opcode" , "Prevented sending of NULL_OPCODE to %s" , GetPlayerInfo (). c_str ());
2012-08-22 13:38:55 +02:00
return ;
}
else if ( packet -> GetOpcode () == UNKNOWN_OPCODE )
{
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network.opcode" , "Prevented sending of UNKNOWN_OPCODE to %s" , GetPlayerInfo (). c_str ());
2011-11-20 18:28:18 +01:00
return ;
}
2014-12-06 16:55:17 +02:00
ServerOpcodeHandler const * handler = opcodeTable [ static_cast < OpcodeServer > ( packet -> GetOpcode ())];
if ( ! handler )
{
TC_LOG_ERROR ( "network.opcode" , "Prevented sending of opcode %u with non existing handler to %s" , packet -> GetOpcode (), GetPlayerInfo (). c_str ());
return ;
}
// Default connection index defined in Opcodes.cpp table
ConnectionType conIdx = handler -> ConnectionIndex ;
// Override connection index
if ( packet -> GetConnection () != CONNECTION_TYPE_DEFAULT )
{
if ( packet -> GetConnection () != CONNECTION_TYPE_INSTANCE && IsInstanceOnlyOpcode ( packet -> GetOpcode ()))
{
TC_LOG_ERROR ( "network.opcode" , "Prevented sending of instance only opcode %u with connection type %u to %s" , packet -> GetOpcode (), packet -> GetConnection (), GetPlayerInfo (). c_str ());
return ;
}
conIdx = packet -> GetConnection ();
}
if ( ! m_Socket [ conIdx ])
{
TC_LOG_ERROR ( "network.opcode" , "Prevented sending of %s to non existent socket %u to %s" , GetOpcodeNameForLogging ( static_cast < OpcodeServer > ( packet -> GetOpcode ())). c_str (), conIdx , GetPlayerInfo (). c_str ());
return ;
}
2012-08-03 18:54:37 +01:00
if ( ! forced )
2012-07-11 23:29:33 +02:00
{
2014-12-06 16:55:17 +02:00
if ( handler -> Status == STATUS_UNHANDLED )
2012-08-03 18:54:37 +01:00
{
2014-10-25 15:41:42 +01:00
TC_LOG_ERROR ( "network.opcode" , "Prevented sending disabled opcode %s to %s" , GetOpcodeNameForLogging ( static_cast < OpcodeServer > ( packet -> GetOpcode ())). c_str (), GetPlayerInfo (). c_str ());
2012-08-03 18:54:37 +01:00
return ;
}
2012-07-11 23:29:33 +02:00
}
2010-12-29 20:20:09 -08:00
#ifdef TRINITY_DEBUG
2008-10-11 14:16:25 -05:00
// Code for network use statistic
static uint64 sendPacketCount = 0 ;
static uint64 sendPacketBytes = 0 ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
static time_t firstTime = time ( NULL );
2008-10-11 14:16:25 -05:00
static time_t lastTime = firstTime ; // next 60 secs start time
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
static uint64 sendLastPacketCount = 0 ;
static uint64 sendLastPacketBytes = 0 ;
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
time_t cur_time = time ( NULL );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if (( cur_time - lastTime ) < 60 )
2008-10-11 14:16:25 -05:00
{
sendPacketCount += 1 ;
sendPacketBytes += packet -> size ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
sendLastPacketCount += 1 ;
sendLastPacketBytes += packet -> size ();
}
else
{
uint64 minTime = uint64 ( cur_time - lastTime );
uint64 fullTime = uint64 ( lastTime - firstTime );
2015-03-08 05:51:07 +01:00
TC_LOG_DEBUG ( "misc" , "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u" , sendPacketCount , sendPacketBytes , float ( sendPacketCount ) / fullTime , float ( sendPacketBytes ) / fullTime , uint32 ( fullTime ));
TC_LOG_DEBUG ( "misc" , "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f" , sendLastPacketCount , sendLastPacketBytes , float ( sendLastPacketCount ) / minTime , float ( sendLastPacketBytes ) / minTime );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
lastTime = cur_time ;
sendLastPacketCount = 1 ;
sendLastPacketBytes = packet -> wpos (); // wpos is real written size
}
2010-12-29 20:20:09 -08:00
#endif // !TRINITY_DEBUG
2009-10-17 15:51:44 -07:00
2014-08-11 17:28:10 +02:00
sScriptMgr -> OnPacketSend ( this , * packet );
2015-03-28 21:45:27 +01:00
TC_LOG_TRACE ( "network.opcode" , "S->C: %s %s" , GetPlayerInfo (). c_str (), GetOpcodeNameForLogging ( static_cast < OpcodeServer > ( packet -> GetOpcode ())). c_str ());
2014-12-06 16:55:17 +02:00
m_Socket [ conIdx ] -> SendPacket ( * packet );
2014-10-31 22:36:43 +01:00
}
2008-10-11 14:16:25 -05:00
/// Add an incoming packet to the queue
2011-09-15 14:08:17 +02:00
void WorldSession :: QueuePacket ( WorldPacket * new_packet )
2008-10-11 14:16:25 -05:00
{
_recvQueue . add ( new_packet );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Logging helper for unexpected opcodes
2011-06-12 02:06:07 +02:00
void WorldSession :: LogUnexpectedOpcode ( WorldPacket * packet , const char * status , const char * reason )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received unexpected opcode %s Status: %s Reason: %s from %s" ,
2014-10-25 15:41:42 +01:00
GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str (), status , reason , GetPlayerInfo (). c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2009-08-19 17:07:21 -05:00
/// Logging helper for unexpected opcodes
2016-10-25 19:13:32 +02:00
void WorldSession :: LogUnprocessedTail ( WorldPacket const * packet )
2009-08-19 17:07:21 -05:00
{
2013-11-08 10:50:51 +01:00
if ( ! sLog -> ShouldLog ( "network.opcode" , LOG_LEVEL_TRACE ) || packet -> rpos () >= packet -> wpos ())
2012-11-23 12:36:18 +01:00
return ;
2013-11-08 10:50:51 +01:00
TC_LOG_TRACE ( "network.opcode" , "Unprocessed tail data (read stop at %u from %u) Opcode %s from %s" ,
2014-10-25 15:41:42 +01:00
uint32 ( packet -> rpos ()), uint32 ( packet -> wpos ()), GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str (), GetPlayerInfo (). c_str ());
2010-12-29 20:20:09 -08:00
packet -> print_storage ();
2009-08-19 17:07:21 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Update the WorldSession (triggered by World update)
2010-12-13 22:37:56 +01:00
bool WorldSession :: Update ( uint32 diff , PacketFilter & updater )
2008-10-11 14:16:25 -05:00
{
2010-05-16 03:42:05 +02:00
/// Update Timeout timer.
UpdateTimeOutTime ( diff );
2010-08-08 19:45:53 +02:00
///- Before we process anything:
2010-05-16 03:42:05 +02:00
/// If necessary, kick the player from the character select screen
if ( IsConnectionIdle ())
2014-11-09 21:36:06 +01:00
m_Socket [ CONNECTION_TYPE_REALM ] -> CloseSocket ();
2010-08-08 19:45:53 +02:00
2008-10-11 14:16:25 -05:00
///- Retrieve packets from the receive queue and call the appropriate handlers
2010-12-13 22:37:56 +01:00
/// not process packets if socket already closed
2011-06-12 02:06:07 +02:00
WorldPacket * packet = NULL ;
2011-12-16 15:36:03 +01:00
//! Delete packet after processing by default
bool deletePacket = true ;
2016-02-22 20:02:26 +01:00
std :: vector < WorldPacket *> requeuePackets ;
2013-10-17 22:03:51 +02:00
uint32 processedPackets = 0 ;
2014-05-24 22:04:03 +02:00
time_t currentTime = time ( NULL );
2013-10-17 22:03:51 +02:00
2016-02-22 20:02:26 +01:00
while ( m_Socket [ CONNECTION_TYPE_REALM ] && _recvQueue . next ( packet , updater ))
2008-10-11 14:16:25 -05:00
{
2014-12-06 16:55:17 +02:00
ClientOpcodeHandler const * opHandle = opcodeTable [ static_cast < OpcodeClient > ( packet -> GetOpcode ())];
2013-09-01 23:48:40 +02:00
try
2008-10-11 14:16:25 -05:00
{
2013-09-01 23:48:40 +02:00
switch ( opHandle -> Status )
2008-10-11 14:16:25 -05:00
{
2013-09-01 23:48:40 +02:00
case STATUS_LOGGEDIN :
if ( ! _player )
{
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
//! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
//! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
if ( ! m_playerRecentlyLogout )
2009-09-01 16:47:49 -05:00
{
2016-02-22 20:02:26 +01:00
requeuePackets . push_back ( packet );
2013-09-01 23:48:40 +02:00
deletePacket = false ;
2016-02-22 20:02:26 +01:00
TC_LOG_DEBUG ( "network" , "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
"Player is currently not in world yet." , GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str ());
2009-09-01 16:47:49 -05:00
}
2013-09-01 23:48:40 +02:00
}
2014-12-27 15:48:29 +00:00
else if ( _player -> IsInWorld () && AntiDOS . EvaluateOpcode ( * packet , currentTime ))
2013-09-01 23:48:40 +02:00
{
2014-08-12 00:44:26 +02:00
sScriptMgr -> OnPacketReceive ( this , * packet );
2014-11-03 02:11:15 +01:00
opHandle -> Call ( this , * packet );
2013-09-01 23:48:40 +02:00
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break ;
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT :
if ( ! _player && ! m_playerRecentlyLogout && ! m_playerLogout ) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
LogUnexpectedOpcode ( packet , "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT" ,
"the player has not logged in yet and not recently logout" );
2014-12-27 15:48:29 +00:00
else if ( AntiDOS . EvaluateOpcode ( * packet , currentTime ))
2013-09-01 23:48:40 +02:00
{
// not expected _player or must checked in packet hanlder
2014-08-12 00:44:26 +02:00
sScriptMgr -> OnPacketReceive ( this , * packet );
2014-11-03 02:11:15 +01:00
opHandle -> Call ( this , * packet );
2013-09-01 23:48:40 +02:00
}
break ;
case STATUS_TRANSFER :
if ( ! _player )
LogUnexpectedOpcode ( packet , "STATUS_TRANSFER" , "the player has not logged in yet" );
else if ( _player -> IsInWorld ())
LogUnexpectedOpcode ( packet , "STATUS_TRANSFER" , "the player is still in world" );
2016-03-16 21:38:01 +01:00
else if ( AntiDOS . EvaluateOpcode ( * packet , currentTime ))
2013-09-01 23:48:40 +02:00
{
2014-08-11 17:28:10 +02:00
sScriptMgr -> OnPacketReceive ( this , * packet );
2014-11-03 02:11:15 +01:00
opHandle -> Call ( this , * packet );
2013-09-01 23:48:40 +02:00
}
break ;
case STATUS_AUTHED :
// prevent cheating with skip queue wait
if ( m_inQueue )
{
LogUnexpectedOpcode ( packet , "STATUS_AUTHED" , "the player not pass queue yet" );
2008-11-30 12:47:26 -06:00
break ;
2013-09-01 23:48:40 +02:00
}
// some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
// however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
2015-04-01 01:44:10 +02:00
if ( packet -> GetOpcode () == CMSG_ENUM_CHARACTERS )
2013-09-01 23:48:40 +02:00
m_playerRecentlyLogout = false ;
2014-12-27 15:48:29 +00:00
if ( AntiDOS . EvaluateOpcode ( * packet , currentTime ))
{
sScriptMgr -> OnPacketReceive ( this , * packet );
opHandle -> Call ( this , * packet );
}
2013-09-01 23:48:40 +02:00
break ;
case STATUS_NEVER :
2016-03-13 00:12:42 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not allowed opcode %s from %s" , GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str ()
, GetPlayerInfo (). c_str ());
2013-09-01 23:48:40 +02:00
break ;
case STATUS_UNHANDLED :
2016-03-13 00:12:42 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not handled opcode %s from %s" , GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str ()
, GetPlayerInfo (). c_str ());
2013-09-01 23:48:40 +02:00
break ;
2009-08-19 16:26:22 -05:00
}
2013-08-30 21:43:02 +02:00
}
2015-07-29 00:04:37 +02:00
catch ( WorldPackets :: PacketArrayMaxCapacityException const & pamce )
{
TC_LOG_ERROR ( "network" , "PacketArrayMaxCapacityException: %s while parsing %s from %s." ,
pamce . what (), GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str (), GetPlayerInfo (). c_str ());
}
2013-09-01 23:48:40 +02:00
catch ( ByteBufferException const & )
{
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network" , "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet." ,
2013-09-01 23:48:40 +02:00
packet -> GetOpcode (), GetRemoteAddress (). c_str (), GetAccountId ());
packet -> hexlike ();
}
2009-10-17 15:51:44 -07:00
2011-12-16 15:36:03 +01:00
if ( deletePacket )
delete packet ;
2013-09-01 17:48:47 +02:00
deletePacket = true ;
2013-10-17 22:03:51 +02:00
#define MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE 100
processedPackets ++ ;
//process only a max amout of packets in 1 Update() call.
//Any leftover will be processed in next update
if ( processedPackets > MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE )
break ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2016-06-04 11:26:57 +01:00
TC_METRIC_VALUE ( "processed_packets" , processedPackets );
2016-02-22 20:02:26 +01:00
_recvQueue . readd ( requeuePackets . begin (), requeuePackets . end ());
2014-11-09 21:36:06 +01:00
if ( m_Socket [ CONNECTION_TYPE_REALM ] && m_Socket [ CONNECTION_TYPE_REALM ] -> IsOpen () && _warden )
2012-02-19 13:51:16 +01:00
_warden -> Update ();
2010-08-18 19:48:51 +02:00
ProcessQueryCallbacks ();
2010-12-13 22:37:56 +01:00
//check if we are safe to proceed with logout
//logout procedure should happen only in World::UpdateSessions() method!!!
2015-05-01 15:44:43 +02:00
if ( updater . ProcessUnsafe ())
2010-12-13 22:37:56 +01:00
{
2010-12-29 20:20:09 -08:00
time_t currTime = time ( NULL );
///- If necessary, log the player out
2014-11-09 00:37:33 +01:00
if ( ShouldLogOut ( currTime ) && m_playerLoading . IsEmpty ())
2010-12-29 20:20:09 -08:00
LogoutPlayer ( true );
2010-05-05 22:56:02 +02:00
2014-11-09 21:36:06 +01:00
if ( m_Socket [ CONNECTION_TYPE_REALM ] && GetPlayer () && _warden )
2012-02-19 13:51:16 +01:00
_warden -> Update ();
2010-12-29 20:20:09 -08:00
///- Cleanup socket pointer if need
2014-11-09 21:36:06 +01:00
if (( m_Socket [ CONNECTION_TYPE_REALM ] && ! m_Socket [ CONNECTION_TYPE_REALM ] -> IsOpen ()) ||
( m_Socket [ CONNECTION_TYPE_INSTANCE ] && ! m_Socket [ CONNECTION_TYPE_INSTANCE ] -> IsOpen ()))
2010-12-29 20:20:09 -08:00
{
2014-06-03 01:12:34 +01:00
expireTime -= expireTime > diff ? diff : expireTime ;
2014-08-09 19:33:39 +02:00
if ( expireTime < diff || forceExit || ! GetPlayer ())
2014-06-03 01:12:34 +01:00
{
2016-05-09 00:08:18 +02:00
if ( m_Socket [ CONNECTION_TYPE_REALM ])
{
m_Socket [ CONNECTION_TYPE_REALM ] -> CloseSocket ();
m_Socket [ CONNECTION_TYPE_REALM ]. reset ();
}
if ( m_Socket [ CONNECTION_TYPE_INSTANCE ])
{
m_Socket [ CONNECTION_TYPE_INSTANCE ] -> CloseSocket ();
m_Socket [ CONNECTION_TYPE_INSTANCE ]. reset ();
}
2014-06-03 01:12:34 +01:00
}
2010-12-29 20:20:09 -08:00
}
2009-10-17 15:51:44 -07:00
2014-11-09 21:36:06 +01:00
if ( ! m_Socket [ CONNECTION_TYPE_REALM ])
2010-12-29 20:20:09 -08:00
return false ; //Will remove this session from the world session map
2010-12-13 22:37:56 +01:00
}
2011-12-16 15:36:03 +01:00
2008-10-11 14:16:25 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// %Log the player out
2013-02-20 20:52:58 +01:00
void WorldSession :: LogoutPlayer ( bool save )
2008-10-11 14:16:25 -05:00
{
// finish pending transfers before starting the logout
2010-04-07 19:13:19 +02:00
while ( _player && _player -> IsBeingTeleportedFar ())
2016-08-06 12:34:38 +02:00
HandleMoveWorldportAck ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
m_playerLogout = true ;
2013-02-20 20:52:58 +01:00
m_playerSave = save ;
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( _player )
{
2016-12-28 01:12:01 +01:00
if ( ! _player -> GetLootGUID (). IsEmpty ())
DoLootReleaseAll ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- If the player just died before logging out, make him appear as a ghost
if ( _player -> GetDeathTimer ())
{
2010-03-09 11:11:10 +01:00
_player -> getHostileRefManager (). deleteReferences ();
2008-10-11 14:16:25 -05:00
_player -> BuildPlayerRepop ();
_player -> RepopAtGraveyard ();
}
2010-04-07 19:14:10 +02:00
else if ( _player -> HasAuraType ( SPELL_AURA_SPIRIT_OF_REDEMPTION ))
2008-10-11 14:16:25 -05:00
{
// this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION
2009-04-06 13:31:14 +02:00
_player -> RemoveAurasByType ( SPELL_AURA_MOD_SHAPESHIFT );
2008-10-11 14:16:25 -05:00
_player -> KillPlayer ();
_player -> BuildPlayerRepop ();
_player -> RepopAtGraveyard ();
}
2011-01-24 11:38:59 +01:00
else if ( _player -> HasPendingBind ())
{
_player -> RepopAtGraveyard ();
2011-09-16 10:53:24 +02:00
_player -> SetPendingBind ( 0 , 0 );
2011-01-24 11:38:59 +01:00
}
2010-12-29 20:20:09 -08:00
2009-03-02 16:46:43 -06:00
//drop a flag if player is carrying it
2011-09-15 14:08:17 +02:00
if ( Battleground * bg = _player -> GetBattleground ())
2009-03-09 16:36:58 -06:00
bg -> EventPlayerLoggedOut ( _player );
2009-10-17 15:51:44 -07:00
2008-12-29 12:22:49 -06:00
///- Teleport to home if the player is in an invalid instance
2013-06-11 21:25:12 -02:30
if ( ! _player -> m_InstanceValid && ! _player -> IsGameMaster ())
2008-12-29 12:22:49 -06:00
_player -> TeleportTo ( _player -> m_homebindMapId , _player -> m_homebindX , _player -> m_homebindY , _player -> m_homebindZ , _player -> GetOrientation ());
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
sOutdoorPvPMgr -> HandlePlayerLeaveZone ( _player , _player -> GetZoneId ());
2009-10-17 15:51:44 -07:00
2009-04-29 00:26:07 -05:00
for ( int i = 0 ; i < PLAYER_MAX_BATTLEGROUND_QUEUES ; ++ i )
2008-10-11 14:16:25 -05:00
{
2010-08-08 04:37:24 +02:00
if ( BattlegroundQueueTypeId bgQueueTypeId = _player -> GetBattlegroundQueueTypeId ( i ))
2008-10-11 14:16:25 -05:00
{
2010-08-08 04:37:24 +02:00
_player -> RemoveBattlegroundQueueId ( bgQueueTypeId );
2012-10-04 10:39:37 +02:00
BattlegroundQueue & queue = sBattlegroundMgr -> GetBattlegroundQueue ( bgQueueTypeId );
queue . RemovePlayer ( _player -> GetGUID (), true );
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-07-28 16:26:05 +02:00
// Repop at GraveYard or other player far teleport will prevent saving player because of not present map
// Teleport player immediately for correct player save
2010-04-07 19:13:19 +02:00
while ( _player -> IsBeingTeleportedFar ())
2016-08-06 12:34:38 +02:00
HandleMoveWorldportAck ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
2011-10-07 10:54:53 -05:00
if ( Guild * guild = sGuildMgr -> GetGuildById ( _player -> GetGuildId ()))
guild -> HandleMemberLogout ( this );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- Remove pet
2011-04-29 20:47:02 +02:00
_player -> RemovePet ( NULL , PET_SAVE_AS_CURRENT , true );
2009-10-17 15:51:44 -07:00
2013-03-09 22:34:42 +01:00
///- Clear whisper whitelist
_player -> ClearWhisperWhiteList ();
2008-10-11 14:16:25 -05:00
///- empty buyback items and save the player in the database
// some save parts only correctly work in case player present in map/player_lists (pets, etc)
2013-02-20 20:52:58 +01:00
if ( save )
2008-10-11 14:16:25 -05:00
{
uint32 eslot ;
2009-10-17 16:20:24 -07:00
for ( int j = BUYBACK_SLOT_START ; j < BUYBACK_SLOT_END ; ++ j )
2008-10-11 14:16:25 -05:00
{
eslot = j - BUYBACK_SLOT_START ;
2019-06-03 20:40:34 +02:00
_player -> SetInvSlot ( j , ObjectGuid :: Empty );
_player -> SetBuybackPrice ( eslot , 0 );
_player -> SetBuybackTimestamp ( eslot , 0 );
2008-10-11 14:16:25 -05:00
}
_player -> SaveToDB ();
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- Leave all channels before player delete...
_player -> CleanupChannels ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.
_player -> UninviteFromGroup ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// remove player from the group if he is:
// a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected)
2014-11-09 21:36:06 +01:00
if ( _player -> GetGroup () && ! _player -> GetGroup () -> isRaidGroup () && m_Socket [ CONNECTION_TYPE_REALM ])
2008-10-11 14:16:25 -05:00
_player -> RemoveFromGroup ();
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
//! Send update to group and reset stored max enchanting level
2010-04-07 19:14:10 +02:00
if ( _player -> GetGroup ())
2010-05-21 22:45:47 +02:00
{
2008-10-11 14:16:25 -05:00
_player -> GetGroup () -> SendUpdate ();
2010-05-21 22:45:47 +02:00
_player -> GetGroup () -> ResetMaxEnchantingLevel ();
}
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
//! Broadcast a logout message to the player's friends
2014-10-22 12:52:12 +02:00
sSocialMgr -> SendFriendStatus ( _player , FRIEND_OFFLINE , _player -> GetGUID (), true );
2015-02-08 02:51:49 +01:00
_player -> RemoveSocial ();
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
//! Call script hook before deletion
sScriptMgr -> OnPlayerLogout ( _player );
2010-10-25 11:17:17 +02:00
2016-06-04 11:26:57 +01:00
TC_METRIC_EVENT ( "player_events" , "Logout" , _player -> GetName ());
2012-05-30 08:01:02 +02:00
//! Remove the player from the world
2009-06-17 19:02:38 -05:00
// the player may not be in the world when logging out
// e.g if he got disconnected during a transfer to another map
// calls to GetMap in this case may cause crashes
2009-08-10 23:32:20 -05:00
_player -> CleanupsBeforeDelete ();
2014-10-22 21:22:04 +02:00
TC_LOG_INFO ( "entities.player.character" , "Account: %u (IP: %s) Logout Character:[%s] (%s) Level: %d" ,
GetAccountId (), GetRemoteAddress (). c_str (), _player -> GetName (). c_str (), _player -> GetGUID (). ToString (). c_str (), _player -> getLevel ());
2014-10-17 22:48:06 +02:00
2012-02-10 12:43:13 +01:00
if ( Map * _map = _player -> FindMap ())
_map -> RemovePlayerFromMap ( _player , true );
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
SetPlayer ( NULL ); //! Pointer already deleted during RemovePlayerFromMap
//! Send the 'logout complete' packet to the client
//! Client will respond by sending 3x CMSG_CANCEL_TRADE, which we currently dont handle
2014-11-09 21:36:06 +01:00
SendPacket ( WorldPackets :: Character :: LogoutComplete (). Write ());
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" );
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
//! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_ACCOUNT_ONLINE );
2011-12-25 18:12:58 +01:00
stmt -> setUInt32 ( 0 , GetAccountId ());
CharacterDatabase . Execute ( stmt );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-09 21:36:06 +01:00
if ( m_Socket [ CONNECTION_TYPE_INSTANCE ])
{
m_Socket [ CONNECTION_TYPE_INSTANCE ] -> CloseSocket ();
m_Socket [ CONNECTION_TYPE_INSTANCE ]. reset ();
}
2008-10-11 14:16:25 -05:00
m_playerLogout = false ;
2009-12-17 07:56:20 +01:00
m_playerSave = false ;
2008-10-11 14:16:25 -05:00
m_playerRecentlyLogout = true ;
2014-11-09 21:36:06 +01:00
SetLogoutStartTime ( 0 );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Kick a player out of the World
void WorldSession :: KickPlayer ()
{
2014-11-09 00:37:33 +01:00
for ( uint8 i = 0 ; i < 2 ; ++ i )
2014-06-03 01:12:34 +01:00
{
2014-11-09 00:37:33 +01:00
if ( m_Socket [ i ])
{
m_Socket [ i ] -> CloseSocket ();
forceExit = true ;
}
2014-06-03 01:12:34 +01:00
}
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
void WorldSession :: SendNotification ( char const * format , ...)
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( format )
2008-10-11 14:16:25 -05:00
{
va_list ap ;
2010-12-29 20:20:09 -08:00
char szStr [ 1024 ];
2008-10-11 14:16:25 -05:00
szStr [ 0 ] = '\0' ;
va_start ( ap , format );
2010-04-07 22:59:46 +02:00
vsnprintf ( szStr , 1024 , format , ap );
2008-10-11 14:16:25 -05:00
va_end ( ap );
2009-10-17 15:51:44 -07:00
2015-02-23 20:23:33 +01:00
SendPacket ( WorldPackets :: Chat :: PrintNotification ( szStr ). Write ());
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2015-01-26 12:59:18 +01:00
void WorldSession :: SendNotification ( uint32 stringId , ...)
2008-10-11 14:16:25 -05:00
{
2015-01-26 12:59:18 +01:00
char const * format = GetTrinityString ( stringId );
2010-04-07 19:14:10 +02:00
if ( format )
2008-10-11 14:16:25 -05:00
{
va_list ap ;
2010-12-29 20:20:09 -08:00
char szStr [ 1024 ];
2008-10-11 14:16:25 -05:00
szStr [ 0 ] = '\0' ;
2015-01-26 12:59:18 +01:00
va_start ( ap , stringId );
2010-04-07 22:59:46 +02:00
vsnprintf ( szStr , 1024 , format , ap );
2008-10-11 14:16:25 -05:00
va_end ( ap );
2009-10-17 15:51:44 -07:00
2015-02-23 20:23:33 +01:00
SendPacket ( WorldPackets :: Chat :: PrintNotification ( szStr ). Write ());
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2014-09-18 02:36:28 +02:00
char const * WorldSession :: GetTrinityString ( uint32 entry ) const
2008-10-11 14:16:25 -05:00
{
2010-12-22 21:25:23 +01:00
return sObjectMgr -> GetTrinityString ( entry , GetSessionDbLocaleIndex ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2017-05-18 23:52:58 +02:00
void WorldSession :: ResetTimeOutTime ()
{
m_timeOutTime = int32 ( sWorld -> getIntConfig ( CONFIG_SOCKET_TIMEOUTTIME ));
}
2015-04-18 12:12:59 +02:00
void WorldSession :: Handle_NULL ( WorldPackets :: Null & null )
2008-10-11 14:16:25 -05:00
{
2015-04-18 12:12:59 +02:00
TC_LOG_ERROR ( "network.opcode" , "Received unhandled opcode %s from %s" , GetOpcodeNameForLogging ( null . GetOpcode ()). c_str (), GetPlayerInfo (). c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
void WorldSession :: Handle_EarlyProccess ( WorldPacket & recvPacket )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received opcode %s that must be processed in WorldSocket::OnRead from %s"
2014-10-25 15:41:42 +01:00
, GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( recvPacket . GetOpcode ())). c_str (), GetPlayerInfo (). c_str ());
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2015-02-23 22:35:26 +01:00
void WorldSession :: SendConnectToInstance ( WorldPackets :: Auth :: ConnectToSerial serial )
{
boost :: system :: error_code ignored_error ;
2018-01-06 01:21:59 +01:00
boost :: asio :: ip :: address instanceAddress = realm . GetAddressForClient ( Trinity :: Net :: make_address ( GetRemoteAddress (), ignored_error ));
2015-02-23 22:35:26 +01:00
2015-12-29 21:22:31 +01:00
_instanceConnectKey . Fields . AccountId = GetAccountId ();
_instanceConnectKey . Fields . ConnectionType = CONNECTION_TYPE_INSTANCE ;
_instanceConnectKey . Fields . Key = urand ( 0 , 0x7FFFFFFF );
2015-02-23 22:35:26 +01:00
WorldPackets :: Auth :: ConnectTo connectTo ;
2015-12-29 21:22:31 +01:00
connectTo . Key = _instanceConnectKey . Raw ;
2015-02-23 22:35:26 +01:00
connectTo . Serial = serial ;
2017-05-13 11:49:09 +02:00
connectTo . Payload . Port = sWorld -> getIntConfig ( CONFIG_PORT_INSTANCE );
if ( instanceAddress . is_v4 ())
{
2019-07-12 20:42:49 +02:00
memcpy ( connectTo . Payload . Where . Address . V4 . data (), instanceAddress . to_v4 (). to_bytes (). data (), 4 );
connectTo . Payload . Where . Type = WorldPackets :: Auth :: ConnectTo :: IPv4 ;
2017-05-13 11:49:09 +02:00
}
else
{
2019-07-12 20:42:49 +02:00
memcpy ( connectTo . Payload . Where . Address . V6 . data (), instanceAddress . to_v6 (). to_bytes (). data (), 16 );
connectTo . Payload . Where . Type = WorldPackets :: Auth :: ConnectTo :: IPv6 ;
2017-05-13 11:49:09 +02:00
}
2015-02-23 22:35:26 +01:00
connectTo . Con = CONNECTION_TYPE_INSTANCE ;
SendPacket ( connectTo . Write ());
}
2010-09-20 18:20:40 +02:00
void WorldSession :: LoadAccountData ( PreparedQueryResult result , uint32 mask )
2009-09-01 16:47:49 -05:00
{
for ( uint32 i = 0 ; i < NUM_ACCOUNT_DATA_TYPES ; ++ i )
if ( mask & ( 1 << i ))
2014-11-19 02:12:47 +01:00
_accountData [ i ] = AccountData ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! result )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-01-22 22:44:27 -06:00
do
2008-12-24 09:58:26 -06:00
{
2011-09-15 14:08:17 +02:00
Field * fields = result -> Fetch ();
2011-01-19 02:53:44 +01:00
uint32 type = fields [ 0 ]. GetUInt8 ();
2009-09-01 16:47:49 -05:00
if ( type >= NUM_ACCOUNT_DATA_TYPES )
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "Table `%s` have invalid account data type (%u), ignore." ,
2012-08-03 14:20:18 +02:00
mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data" , type );
2009-09-01 16:47:49 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if (( mask & ( 1 << type )) == 0 )
2008-12-24 09:58:26 -06:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "Table `%s` have non appropriate for table account data type (%u), ignore." ,
2012-08-03 14:20:18 +02:00
mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data" , type );
2009-09-01 16:47:49 -05:00
continue ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2014-11-19 02:12:47 +01:00
_accountData [ type ]. Time = time_t ( fields [ 1 ]. GetUInt32 ());
_accountData [ type ]. Data = fields [ 2 ]. GetString ();
2010-09-24 22:16:21 +02:00
}
while ( result -> NextRow ());
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2014-11-19 02:12:47 +01:00
void WorldSession :: SetAccountData ( AccountDataType type , uint32 time , std :: string const & data )
2008-12-24 09:58:26 -06:00
{
2009-09-01 16:47:49 -05:00
if (( 1 << type ) & GLOBAL_CACHE_MASK )
{
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_REP_ACCOUNT_DATA );
2014-10-23 21:34:03 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
stmt -> setUInt8 ( 1 , type );
2014-11-19 02:12:47 +01:00
stmt -> setUInt32 ( 2 , time );
2014-10-23 21:34:03 +02:00
stmt -> setString ( 3 , data );
CharacterDatabase . Execute ( stmt );
2009-09-01 16:47:49 -05:00
}
else
{
// _player can be NULL and packet received after logout but m_GUID still store correct guid
2010-04-07 19:14:10 +02:00
if ( ! m_GUIDLow )
2009-09-01 16:47:49 -05:00
return ;
2009-10-17 15:51:44 -07:00
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_REP_PLAYER_ACCOUNT_DATA );
2014-10-23 21:34:03 +02:00
stmt -> setUInt64 ( 0 , m_GUIDLow );
stmt -> setUInt8 ( 1 , type );
2014-11-19 02:12:47 +01:00
stmt -> setUInt32 ( 2 , time );
2014-10-23 21:34:03 +02:00
stmt -> setString ( 3 , data );
CharacterDatabase . Execute ( stmt );
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2014-11-19 02:12:47 +01:00
_accountData [ type ]. Time = time_t ( time );
_accountData [ type ]. Data = data ;
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2015-06-20 00:59:31 +02:00
void WorldSession :: LoadTutorialsData ( PreparedQueryResult result )
2009-06-11 00:45:59 -05:00
{
2014-11-19 02:12:47 +01:00
memset ( _tutorials , 0 , sizeof ( uint32 ) * MAX_ACCOUNT_TUTORIAL_VALUES );
2009-10-17 15:51:44 -07:00
2015-06-20 00:59:31 +02:00
if ( result )
2017-01-28 05:00:28 +01:00
{
2011-02-24 23:57:43 +06:00
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
2014-11-19 02:12:47 +01:00
_tutorials [ i ] = ( * result )[ i ]. GetUInt32 ();
2017-01-28 05:00:28 +01:00
_tutorialsChanged |= TUTORIALS_FLAG_LOADED_FROM_DB ;
}
2009-10-17 15:51:44 -07:00
2017-01-28 05:00:28 +01:00
_tutorialsChanged &= ~ TUTORIALS_FLAG_CHANGED ;
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: SendTutorialsData ()
{
2014-11-16 00:30:31 +02:00
WorldPackets :: Misc :: TutorialFlags packet ;
2014-11-19 02:12:47 +01:00
memcpy ( packet . TutorialData , _tutorials , sizeof ( _tutorials ));
2014-11-16 00:30:31 +02:00
SendPacket ( packet . Write ());
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2019-07-27 10:52:33 +02:00
void WorldSession :: SaveTutorialsData ( CharacterDatabaseTransaction & trans )
2009-06-11 00:45:59 -05:00
{
2017-01-28 05:00:28 +01:00
if ( ! ( _tutorialsChanged & TUTORIALS_FLAG_CHANGED ))
2009-06-11 00:45:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2017-01-28 05:00:28 +01:00
bool const hasTutorialsInDB = ( _tutorialsChanged & TUTORIALS_FLAG_LOADED_FROM_DB ) != 0 ;
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( hasTutorialsInDB ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS );
2011-02-24 23:57:43 +06:00
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
2014-11-19 02:12:47 +01:00
stmt -> setUInt32 ( i , _tutorials [ i ]);
2011-02-24 23:57:43 +06:00
stmt -> setUInt32 ( MAX_ACCOUNT_TUTORIAL_VALUES , GetAccountId ());
trans -> Append ( stmt );
2009-10-17 15:51:44 -07:00
2017-01-29 14:00:19 -03:00
// now has, set flag so next save uses update query
if ( ! hasTutorialsInDB )
_tutorialsChanged |= TUTORIALS_FLAG_LOADED_FROM_DB ;
2017-01-28 05:00:28 +01:00
_tutorialsChanged &= ~ TUTORIALS_FLAG_CHANGED ;
2009-06-11 00:45:59 -05:00
}
2009-10-17 15:51:44 -07:00
2012-08-10 02:01:25 +01:00
bool WorldSession :: IsAddonRegistered ( const std :: string & prefix ) const
{
if ( ! _filterAddonMessages ) // if we have hit the softcap (64) nothing should be filtered
return true ;
if ( _registeredAddonPrefixes . empty ())
return false ;
2012-08-10 02:57:16 +01:00
std :: vector < std :: string >:: const_iterator itr = std :: find ( _registeredAddonPrefixes . begin (), _registeredAddonPrefixes . end (), prefix );
2012-08-10 02:01:25 +01:00
return itr != _registeredAddonPrefixes . end ();
}
2015-05-24 19:49:44 +02:00
void WorldSession :: HandleUnregisterAllAddonPrefixesOpcode ( WorldPackets :: Chat :: ChatUnregisterAllAddonPrefixes & /*packet*/ ) // empty packet
2012-08-10 02:57:16 +01:00
{
_registeredAddonPrefixes . clear ();
}
2015-05-24 19:49:44 +02:00
void WorldSession :: HandleAddonRegisteredPrefixesOpcode ( WorldPackets :: Chat :: ChatRegisterAddonPrefixes & packet )
2012-08-10 02:57:16 +01:00
{
2015-05-24 19:49:44 +02:00
// This is always sent after CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES
_registeredAddonPrefixes . insert ( _registeredAddonPrefixes . end (), packet . Prefixes . begin (), packet . Prefixes . end ());
2015-09-24 18:47:33 +02:00
if ( _registeredAddonPrefixes . size () > WorldPackets :: Chat :: ChatRegisterAddonPrefixes :: MAX_PREFIXES )
2012-08-10 02:57:16 +01:00
{
_filterAddonMessages = false ;
return ;
}
_filterAddonMessages = true ;
}
2012-08-10 02:01:25 +01:00
2011-11-07 11:06:39 -06:00
void WorldSession :: SetPlayer ( Player * player )
2009-09-01 16:47:49 -05:00
{
2011-11-07 11:06:39 -06:00
_player = player ;
2009-10-17 15:51:44 -07:00
2009-09-01 16:47:49 -05:00
// set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
2010-04-07 19:14:10 +02:00
if ( _player )
2014-10-22 21:22:04 +02:00
m_GUIDLow = _player -> GetGUID (). GetCounter ();
2011-06-22 18:03:07 +02:00
}
2010-08-18 19:48:51 +02:00
void WorldSession :: ProcessQueryCallbacks ()
{
2017-01-13 21:38:03 +01:00
_queryProcessor . ProcessReadyQueries ();
2010-08-18 19:48:51 +02:00
2015-06-20 00:59:31 +02:00
if ( _realmAccountLoginCallback . valid () && _realmAccountLoginCallback . wait_for ( std :: chrono :: seconds ( 0 )) == std :: future_status :: ready &&
_accountLoginCallback . valid () && _accountLoginCallback . wait_for ( std :: chrono :: seconds ( 0 )) == std :: future_status :: ready )
2019-07-27 11:45:56 +02:00
InitializeSessionCallback ( static_cast < LoginDatabaseQueryHolder *> ( _realmAccountLoginCallback . get ()),
static_cast < CharacterDatabaseQueryHolder *> ( _accountLoginCallback . get ()));
2015-06-20 00:59:31 +02:00
2010-08-18 19:48:51 +02:00
//! HandlePlayerLoginOpcode
2014-07-02 21:56:40 -05:00
if ( _charLoginCallback . valid () && _charLoginCallback . wait_for ( std :: chrono :: seconds ( 0 )) == std :: future_status :: ready )
2017-01-13 21:38:03 +01:00
HandlePlayerLogin ( reinterpret_cast < LoginQueryHolder *> ( _charLoginCallback . get ()));
2010-08-21 20:08:47 +02:00
}
2012-02-19 13:51:16 +01:00
2016-03-28 15:23:41 +02:00
void WorldSession :: InitWarden ( BigNumber * k )
2012-02-19 13:51:16 +01:00
{
2016-03-28 15:23:41 +02:00
if ( _os == "Win" )
2012-02-19 13:51:16 +01:00
{
2012-02-19 18:49:10 +01:00
_warden = new WardenWin ();
2012-02-19 13:51:16 +01:00
_warden -> Init ( this , k );
}
2016-03-28 15:23:41 +02:00
else if ( _os == "Wn64" )
2015-06-21 02:15:13 +02:00
{
// Not implemented
}
2016-03-28 15:23:41 +02:00
else if ( _os == "Mc64" )
2015-06-21 02:15:13 +02:00
{
// Not implemented
}
2012-02-19 13:51:16 +01:00
}
2013-02-04 08:21:25 +01:00
void WorldSession :: LoadPermissions ()
{
uint32 id = GetAccountId ();
2013-09-27 13:25:48 +02:00
uint8 secLevel = GetSecurity ();
2013-02-04 08:21:25 +01:00
2015-06-20 00:59:31 +02:00
TC_LOG_DEBUG ( "rbac" , "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]" ,
2015-10-06 00:30:47 +02:00
id , _accountName . c_str (), realm . Id . Realm , secLevel );
2015-06-20 00:59:31 +02:00
2015-10-06 00:30:47 +02:00
_RBACData = new rbac :: RBACData ( id , _accountName , realm . Id . Realm , secLevel );
2013-02-04 08:21:25 +01:00
_RBACData -> LoadFromDB ();
2015-06-20 00:59:31 +02:00
}
2017-01-13 21:38:03 +01:00
QueryCallback WorldSession :: LoadPermissionsAsync ()
2015-06-20 00:59:31 +02:00
{
uint32 id = GetAccountId ();
uint8 secLevel = GetSecurity ();
2013-02-27 03:29:11 +01:00
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "rbac" , "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]" ,
2015-10-06 00:30:47 +02:00
id , _accountName . c_str (), realm . Id . Realm , secLevel );
2015-06-20 00:59:31 +02:00
2015-10-06 00:30:47 +02:00
_RBACData = new rbac :: RBACData ( id , _accountName , realm . Id . Realm , secLevel );
2015-06-20 00:59:31 +02:00
return _RBACData -> LoadFromDBAsync ();
}
2019-07-27 11:45:56 +02:00
class AccountInfoQueryHolderPerRealm : public CharacterDatabaseQueryHolder
2015-06-20 00:59:31 +02:00
{
public :
enum
{
GLOBAL_ACCOUNT_DATA = 0 ,
TUTORIALS ,
MAX_QUERIES
};
AccountInfoQueryHolderPerRealm () { SetSize ( MAX_QUERIES ); }
bool Initialize ( uint32 accountId , uint32 /*battlenetAccountId*/ )
{
bool ok = true ;
2019-07-27 01:00:37 +02:00
CharacterDatabasePreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ACCOUNT_DATA );
2015-06-20 00:59:31 +02:00
stmt -> setUInt32 ( 0 , accountId );
ok = SetPreparedQuery ( GLOBAL_ACCOUNT_DATA , stmt ) && ok ;
stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_TUTORIALS );
stmt -> setUInt32 ( 0 , accountId );
ok = SetPreparedQuery ( TUTORIALS , stmt ) && ok ;
return ok ;
}
};
2019-07-27 11:45:56 +02:00
class AccountInfoQueryHolder : public LoginDatabaseQueryHolder
2015-06-20 00:59:31 +02:00
{
public :
enum
{
2015-08-26 11:12:35 +02:00
GLOBAL_ACCOUNT_TOYS = 0 ,
2015-09-09 14:52:32 +02:00
BATTLE_PETS ,
BATTLE_PET_SLOTS ,
2015-10-16 22:54:46 +02:00
GLOBAL_ACCOUNT_HEIRLOOMS ,
2016-03-28 17:12:57 +02:00
GLOBAL_REALM_CHARACTER_COUNTS ,
2016-10-01 13:48:16 +02:00
MOUNTS ,
2016-07-05 22:07:35 +02:00
ITEM_APPEARANCES ,
ITEM_FAVORITE_APPEARANCES ,
2015-08-26 11:12:35 +02:00
2015-06-20 00:59:31 +02:00
MAX_QUERIES
};
AccountInfoQueryHolder () { SetSize ( MAX_QUERIES ); }
2016-03-28 17:12:57 +02:00
bool Initialize ( uint32 accountId , uint32 battlenetAccountId )
2015-06-20 00:59:31 +02:00
{
bool ok = true ;
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_TOYS );
2015-08-26 11:12:35 +02:00
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( GLOBAL_ACCOUNT_TOYS , stmt ) && ok ;
2015-09-09 14:52:32 +02:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BATTLE_PETS );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( BATTLE_PETS , stmt ) && ok ;
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BATTLE_PET_SLOTS );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( BATTLE_PET_SLOTS , stmt ) && ok ;
2015-10-16 22:54:46 +02:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_HEIRLOOMS );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( GLOBAL_ACCOUNT_HEIRLOOMS , stmt ) && ok ;
2016-10-01 13:48:16 +02:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_MOUNTS );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( MOUNTS , stmt ) && ok ;
2016-03-28 17:12:57 +02:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_ACCOUNT_ID );
stmt -> setUInt32 ( 0 , accountId );
ok = SetPreparedQuery ( GLOBAL_REALM_CHARACTER_COUNTS , stmt ) && ok ;
2016-07-05 22:07:35 +02:00
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BNET_ITEM_APPEARANCES );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( ITEM_APPEARANCES , stmt ) && ok ;
stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_BNET_ITEM_FAVORITE_APPEARANCES );
stmt -> setUInt32 ( 0 , battlenetAccountId );
ok = SetPreparedQuery ( ITEM_FAVORITE_APPEARANCES , stmt ) && ok ;
2015-06-20 00:59:31 +02:00
return ok ;
}
};
void WorldSession :: InitializeSession ()
{
AccountInfoQueryHolderPerRealm * realmHolder = new AccountInfoQueryHolderPerRealm ();
if ( ! realmHolder -> Initialize ( GetAccountId (), GetBattlenetAccountId ()))
{
delete realmHolder ;
2016-03-28 15:23:41 +02:00
SendAuthResponse ( ERROR_INTERNAL , false );
2015-06-20 00:59:31 +02:00
return ;
}
AccountInfoQueryHolder * holder = new AccountInfoQueryHolder ();
if ( ! holder -> Initialize ( GetAccountId (), GetBattlenetAccountId ()))
{
delete realmHolder ;
delete holder ;
2016-03-28 15:23:41 +02:00
SendAuthResponse ( ERROR_INTERNAL , false );
2015-06-20 00:59:31 +02:00
return ;
}
_realmAccountLoginCallback = CharacterDatabase . DelayQueryHolder ( realmHolder );
_accountLoginCallback = LoginDatabase . DelayQueryHolder ( holder );
}
2019-07-27 11:45:56 +02:00
void WorldSession :: InitializeSessionCallback ( LoginDatabaseQueryHolder * realmHolder , CharacterDatabaseQueryHolder * holder )
2015-06-20 00:59:31 +02:00
{
LoadAccountData ( realmHolder -> GetPreparedResult ( AccountInfoQueryHolderPerRealm :: GLOBAL_ACCOUNT_DATA ), GLOBAL_CACHE_MASK );
LoadTutorialsData ( realmHolder -> GetPreparedResult ( AccountInfoQueryHolderPerRealm :: TUTORIALS ));
2015-09-14 11:29:57 +02:00
_collectionMgr -> LoadAccountToys ( holder -> GetPreparedResult ( AccountInfoQueryHolder :: GLOBAL_ACCOUNT_TOYS ));
2015-10-16 22:54:46 +02:00
_collectionMgr -> LoadAccountHeirlooms ( holder -> GetPreparedResult ( AccountInfoQueryHolder :: GLOBAL_ACCOUNT_HEIRLOOMS ));
2016-10-01 13:48:16 +02:00
_collectionMgr -> LoadAccountMounts ( holder -> GetPreparedResult ( AccountInfoQueryHolder :: MOUNTS ));
2016-07-05 22:07:35 +02:00
_collectionMgr -> LoadAccountItemAppearances ( holder -> GetPreparedResult ( AccountInfoQueryHolder :: ITEM_APPEARANCES ), holder -> GetPreparedResult ( AccountInfoQueryHolder :: ITEM_FAVORITE_APPEARANCES ));
2015-06-20 00:59:31 +02:00
if ( ! m_inQueue )
2016-03-28 15:23:41 +02:00
SendAuthResponse ( ERROR_OK , false );
2015-06-20 00:59:31 +02:00
else
SendAuthWaitQue ( 0 );
SetInQueue ( false );
ResetTimeOutTime ();
SendSetTimeZoneInformation ();
SendFeatureSystemStatusGlueScreen ();
SendClientCacheVersion ( sWorld -> getIntConfig ( CONFIG_CLIENTCACHE_VERSION ));
2017-11-11 17:11:00 +01:00
SendAvailableHotfixes ( int32 ( sWorld -> getIntConfig ( CONFIG_HOTFIX_CACHE_VERSION )));
2015-06-20 00:59:31 +02:00
SendTutorialsData ();
2016-03-28 17:12:57 +02:00
if ( PreparedQueryResult characterCountsResult = holder -> GetPreparedResult ( AccountInfoQueryHolder :: GLOBAL_REALM_CHARACTER_COUNTS ))
{
do
{
Field * fields = characterCountsResult -> Fetch ();
_realmCharacterCounts [ Battlenet :: RealmHandle { fields [ 3 ]. GetUInt8 (), fields [ 4 ]. GetUInt8 (), fields [ 2 ]. GetUInt32 () }. GetAddress ()] = fields [ 1 ]. GetUInt8 ();
} while ( characterCountsResult -> NextRow ());
}
WorldPackets :: Battlenet :: SetSessionState bnetConnected ;
bnetConnected . State = 1 ;
SendPacket ( bnetConnected . Write ());
2015-09-09 14:52:32 +02:00
_battlePetMgr -> LoadFromDB ( holder -> GetPreparedResult ( AccountInfoQueryHolder :: BATTLE_PETS ),
holder -> GetPreparedResult ( AccountInfoQueryHolder :: BATTLE_PET_SLOTS ));
2015-06-20 00:59:31 +02:00
delete realmHolder ;
delete holder ;
2013-02-04 08:21:25 +01:00
}
2013-09-27 12:46:01 +02:00
rbac :: RBACData * WorldSession :: GetRBACData ()
2013-02-04 08:21:25 +01:00
{
return _RBACData ;
}
bool WorldSession :: HasPermission ( uint32 permission )
{
2013-02-26 22:35:55 +01:00
if ( ! _RBACData )
LoadPermissions ();
2013-02-27 03:29:11 +01:00
bool hasPermission = _RBACData -> HasPermission ( permission );
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "rbac" , "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]" ,
2015-10-06 00:30:47 +02:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realm . Id . Realm );
2013-02-27 03:29:11 +01:00
return hasPermission ;
}
void WorldSession :: InvalidateRBACData ()
{
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "rbac" , "WorldSession::Invalidaterbac::RBACData [AccountId: %u, Name: %s, realmId: %d]" ,
2015-10-06 00:30:47 +02:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realm . Id . Realm );
2013-02-27 03:29:11 +01:00
delete _RBACData ;
_RBACData = NULL ;
2013-02-04 08:21:25 +01:00
}
2013-08-30 15:44:17 +01:00
2014-05-24 22:04:03 +02:00
bool WorldSession :: DosProtection :: EvaluateOpcode ( WorldPacket & p , time_t time ) const
2013-08-30 15:44:17 +01:00
{
2014-06-09 21:35:59 +02:00
uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed ( p . GetOpcode ());
// Return true if there no limit for the opcode
if ( ! maxPacketCounterAllowed )
return true ;
2014-05-24 22:04:03 +02:00
PacketCounter & packetCounter = _PacketThrottlingMap [ p . GetOpcode ()];
if ( packetCounter . lastReceiveTime != time )
{
packetCounter . lastReceiveTime = time ;
packetCounter . amountCounter = 0 ;
}
// Check if player is flooding some packets
2014-06-11 19:28:25 +02:00
if ( ++ packetCounter . amountCounter <= maxPacketCounterAllowed )
2014-05-24 22:04:03 +02:00
return true ;
2013-08-30 15:44:17 +01:00
2014-06-11 19:28:25 +02:00
TC_LOG_WARN ( "network" , "AntiDOS: Account %u, IP: %s, Ping: %u, Character: %s, flooding packet (opc: %s (0x%X), count: %u)" ,
Session -> GetAccountId (), Session -> GetRemoteAddress (). c_str (), Session -> GetLatency (), Session -> GetPlayerName (). c_str (),
2014-10-25 15:41:42 +01:00
opcodeTable [ static_cast < OpcodeClient > ( p . GetOpcode ())] -> Name , p . GetOpcode (), packetCounter . amountCounter );
2014-06-07 23:56:13 +02:00
2013-08-30 15:44:17 +01:00
switch ( _policy )
{
case POLICY_LOG :
return true ;
case POLICY_KICK :
2014-12-27 15:48:29 +00:00
{
2015-03-08 05:51:07 +01:00
TC_LOG_WARN ( "network" , "AntiDOS: Player kicked!" );
2014-12-27 15:48:29 +00:00
Session -> KickPlayer ();
2013-08-30 15:44:17 +01:00
return false ;
2014-12-27 15:48:29 +00:00
}
2013-08-30 15:44:17 +01:00
case POLICY_BAN :
{
BanMode bm = ( BanMode ) sWorld -> getIntConfig ( CONFIG_PACKET_SPOOF_BANMODE );
2013-08-30 16:03:37 +01:00
uint32 duration = sWorld -> getIntConfig ( CONFIG_PACKET_SPOOF_BANDURATION ); // in seconds
2013-08-30 15:44:17 +01:00
std :: string nameOrIp = "" ;
switch ( bm )
{
case BAN_CHARACTER : // not supported, ban account
case BAN_ACCOUNT : ( void ) sAccountMgr -> GetName ( Session -> GetAccountId (), nameOrIp ); break ;
case BAN_IP : nameOrIp = Session -> GetRemoteAddress (); break ;
}
sWorld -> BanAccount ( bm , nameOrIp , duration , "DOS (Packet Flooding/Spoofing" , "Server: AutoDOS" );
2015-03-08 05:51:07 +01:00
TC_LOG_WARN ( "network" , "AntiDOS: Player automatically banned for %u seconds." , duration );
2014-12-27 15:48:29 +00:00
Session -> KickPlayer ();
2013-08-30 15:44:17 +01:00
return false ;
}
default : // invalid policy
return true ;
}
}
2014-05-24 22:04:03 +02:00
uint32 WorldSession :: DosProtection :: GetMaxPacketCounterAllowed ( uint16 opcode ) const
{
uint32 maxPacketCounterAllowed ;
switch ( opcode )
2015-03-29 03:28:29 +02:00
{
2014-06-09 21:35:59 +02:00
// CPU usage sending 2000 packets/second on a 3.70 GHz 4 cores on Win x64
// [% CPU mysqld] [%CPU worldserver RelWithDebInfo]
case CMSG_PLAYER_LOGIN : // 0 0.5
2015-04-01 01:44:10 +02:00
case CMSG_QUERY_PLAYER_NAME : // 0 1
case CMSG_QUERY_PET_NAME : // 0 1
case CMSG_QUERY_NPC_TEXT : // 0 1
case CMSG_ATTACK_STOP : // 0 1
case CMSG_QUERY_TIME : // 0 1
case CMSG_QUERY_CORPSE_TRANSPORT : // 0 1
2014-06-09 21:35:59 +02:00
case CMSG_MOVE_TIME_SKIPPED : // 0 1
2015-04-01 01:44:10 +02:00
case CMSG_QUERY_NEXT_MAIL_TIME : // 0 1
2015-02-01 20:52:05 +01:00
case CMSG_SET_SHEATHED : // 0 1
2015-04-01 01:44:10 +02:00
case CMSG_UPDATE_RAID_TARGET : // 0 1
2014-06-09 21:35:59 +02:00
case CMSG_LOGOUT_REQUEST : // 0 1
2015-04-01 01:44:10 +02:00
case CMSG_PET_RENAME : // 0 1
case CMSG_QUEST_GIVER_REQUEST_REWARD : // 0 1
case CMSG_COMPLETE_CINEMATIC : // 0 1
2014-06-09 21:35:59 +02:00
case CMSG_BANKER_ACTIVATE : // 0 1
case CMSG_BUY_BANK_SLOT : // 0 1
2015-04-01 01:44:10 +02:00
case CMSG_OPT_OUT_OF_LOOT : // 0 1
2015-01-10 20:57:53 +01:00
case CMSG_DUEL_RESPONSE : // 0 1
2015-04-01 01:44:10 +02:00
case CMSG_CALENDAR_COMPLAIN : // 0 1
case CMSG_QUERY_QUEST_INFO : // 0 1.5
case CMSG_QUERY_GAME_OBJECT : // 0 1.5
case CMSG_QUERY_CREATURE : // 0 1.5
case CMSG_QUEST_GIVER_STATUS_QUERY : // 0 1.5
case CMSG_QUERY_GUILD_INFO : // 0 1.5
2015-01-18 23:56:01 +01:00
case CMSG_TAXI_NODE_STATUS_QUERY : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_TAXI_QUERY_AVAILABLE_NODES : // 0 1.5
case CMSG_QUEST_GIVER_QUERY_QUEST : // 0 1.5
case CMSG_QUERY_PAGE_TEXT : // 0 1.5
case CMSG_GUILD_BANK_TEXT_QUERY : // 0 1.5
case CMSG_QUERY_CORPSE_LOCATION_FROM_CLIENT : // 0 1.5
2015-01-10 20:57:53 +01:00
case CMSG_MOVE_SET_FACING : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_REQUEST_PARTY_MEMBER_STATS : // 0 1.5
case CMSG_QUEST_GIVER_COMPLETE_QUEST : // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_SET_ACTION_BUTTON : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_RESET_INSTANCES : // 0 1.5
case CMSG_HEARTH_AND_RESURRECT : // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_TOGGLE_PVP : // 0 1.5
case CMSG_PET_ABANDON : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_ACTIVATE_TAXI : // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_SELF_RES : // 0 1.5
case CMSG_UNLEARN_SKILL : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_SAVE_EQUIPMENT_SET : // 0 1.5
2015-01-25 21:08:54 +01:00
case CMSG_DELETE_EQUIPMENT_SET : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_DISMISS_CRITTER : // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_REPOP_REQUEST : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_PARTY_INVITE : // 0 1.5
case CMSG_PARTY_INVITE_RESPONSE : // 0 1.5
case CMSG_PARTY_UNINVITE : // 0 1.5
case CMSG_LEAVE_GROUP : // 0 1.5
case CMSG_BATTLEMASTER_JOIN_ARENA : // 0 1.5
2014-06-15 19:36:30 +02:00
case CMSG_BATTLEFIELD_LEAVE : // 0 1.5
2015-04-01 01:44:10 +02:00
case CMSG_GUILD_BANK_LOG_QUERY : // 0 2
2014-06-09 21:35:59 +02:00
case CMSG_LOGOUT_CANCEL : // 0 2
case CMSG_ALTER_APPEARANCE : // 0 2
2015-04-01 01:44:10 +02:00
case CMSG_QUEST_CONFIRM_ACCEPT : // 0 2
case CMSG_GUILD_EVENT_LOG_QUERY : // 0 2.5
case CMSG_QUEST_GIVER_STATUS_MULTIPLE_QUERY : // 0 2.5
case CMSG_BEGIN_TRADE : // 0 2.5
case CMSG_INITIATE_TRADE : // 0 3
2018-10-01 21:01:10 +02:00
case CMSG_CHAT_ADDON_MESSAGE : // 0 3.5
case CMSG_CHAT_ADDON_MESSAGE_TARGETED : // 0 3.5
2015-04-01 01:44:10 +02:00
case CMSG_CHAT_MESSAGE_AFK : // 0 3.5
case CMSG_CHAT_MESSAGE_CHANNEL : // 0 3.5
case CMSG_CHAT_MESSAGE_DND : // 0 3.5
case CMSG_CHAT_MESSAGE_EMOTE : // 0 3.5
case CMSG_CHAT_MESSAGE_GUILD : // 0 3.5
case CMSG_CHAT_MESSAGE_OFFICER : // 0 3.5
case CMSG_CHAT_MESSAGE_PARTY : // 0 3.5
case CMSG_CHAT_MESSAGE_RAID : // 0 3.5
case CMSG_CHAT_MESSAGE_RAID_WARNING : // 0 3.5
case CMSG_CHAT_MESSAGE_SAY : // 0 3.5
case CMSG_CHAT_MESSAGE_WHISPER : // 0 3.5
case CMSG_CHAT_MESSAGE_YELL : // 0 3.5
2014-06-09 21:35:59 +02:00
case CMSG_INSPECT : // 0 3.5
2015-04-01 01:44:10 +02:00
case CMSG_AREA_SPIRIT_HEALER_QUERY : // not profiled
case CMSG_STAND_STATE_CHANGE : // not profiled
2015-01-10 20:57:53 +01:00
case CMSG_RANDOM_ROLL : // not profiled
2015-01-18 23:56:01 +01:00
case CMSG_TIME_SYNC_RESPONSE : // not profiled
2015-05-13 22:29:49 +02:00
case CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK : // not profiled
2014-05-25 20:14:59 +02:00
{
2014-06-09 21:35:59 +02:00
// "0" is a magic number meaning there's no limit for the opcode.
// All the opcodes above must cause little CPU usage and no sync/async database queries at all
maxPacketCounterAllowed = 0 ;
2014-05-25 20:14:59 +02:00
break ;
}
2015-04-01 01:44:10 +02:00
case CMSG_QUEST_GIVER_ACCEPT_QUEST : // 0 4
case CMSG_QUEST_LOG_REMOVE_QUEST : // 0 4
case CMSG_QUEST_GIVER_CHOOSE_REWARD : // 0 4
case CMSG_SEND_CONTACT_LIST : // 0 5
case CMSG_AUTOBANK_ITEM : // 0 6
case CMSG_AUTOSTORE_BANK_ITEM : // 0 6
2014-06-09 21:35:59 +02:00
case CMSG_WHO : // 0 7
2015-04-01 01:44:10 +02:00
case CMSG_RIDE_VEHICLE_INTERACT : // 0 8
2015-01-10 20:57:53 +01:00
case CMSG_MOVE_HEARTBEAT :
2014-05-26 20:13:04 +02:00
{
2014-06-09 21:35:59 +02:00
maxPacketCounterAllowed = 200 ;
2014-05-26 20:13:04 +02:00
break ;
}
2015-04-01 01:44:10 +02:00
case CMSG_GUILD_SET_MEMBER_NOTE : // 1 2 1 async db query
case CMSG_SET_CONTACT_NOTES : // 1 2.5 1 async db query
case CMSG_CALENDAR_GET : // 0 1.5 medium upload bandwidth usage
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_BANK_QUERY_TAB : // 0 3.5 medium upload bandwidth usage
2015-04-01 01:44:10 +02:00
case CMSG_QUERY_INSPECT_ACHIEVEMENTS : // 0 13 high upload bandwidth usage
case CMSG_GAME_OBJ_REPORT_USE : // not profiled
case CMSG_GAME_OBJ_USE : // not profiled
case CMSG_DECLINE_PETITION : // not profiled
2014-05-24 22:04:03 +02:00
{
2014-05-25 15:26:49 +02:00
maxPacketCounterAllowed = 50 ;
2014-05-24 22:04:03 +02:00
break ;
}
2014-06-09 21:35:59 +02:00
case CMSG_QUEST_POI_QUERY : // 0 25 very high upload bandwidth usage
2014-05-25 15:26:49 +02:00
{
2014-06-09 21:35:59 +02:00
maxPacketCounterAllowed = MAX_QUEST_LOG_SIZE ;
2014-05-25 15:26:49 +02:00
break ;
}
2015-04-01 01:44:10 +02:00
case CMSG_SPELL_CLICK : // not profiled
case CMSG_MOVE_DISMISS_VEHICLE : // not profiled
2014-05-25 15:26:49 +02:00
{
2014-05-26 20:13:04 +02:00
maxPacketCounterAllowed = 20 ;
2014-05-25 15:26:49 +02:00
break ;
}
2015-04-01 01:44:10 +02:00
case CMSG_SIGN_PETITION : // 9 4 2 sync 1 async db queries
case CMSG_TURN_IN_PETITION : // 8 5.5 2 sync db query
case CMSG_CHANGE_SUB_GROUP : // 6 5 1 sync 1 async db queries
case CMSG_QUERY_PETITION : // 4 3.5 1 sync db query
2014-06-09 21:35:59 +02:00
case CMSG_CHAR_CUSTOMIZE : // 5 5 1 sync db query
2015-03-29 03:47:26 +02:00
case CMSG_CHAR_RACE_OR_FACTION_CHANGE : // 5 5 1 sync db query
2014-06-09 21:35:59 +02:00
case CMSG_CHAR_DELETE : // 4 4 1 sync db query
case CMSG_DEL_FRIEND : // 7 5 1 async db query
case CMSG_ADD_FRIEND : // 6 4 1 async db query
2015-04-01 01:44:10 +02:00
case CMSG_CHARACTER_RENAME_REQUEST : // 5 3 1 async db query
case CMSG_BUG_REPORT : // 1 1 1 async db query
case CMSG_SET_PARTY_LEADER : // 1 2 1 async db query
case CMSG_CONVERT_RAID : // 1 5 1 async db query
case CMSG_SET_ASSISTANT_LEADER : // 1 2 1 async db query
case CMSG_CALENDAR_ADD_EVENT : // 21 10 2 async db query
case CMSG_MOVE_CHANGE_VEHICLE_SEATS : // not profiled
case CMSG_PETITION_BUY : // not profiled 1 sync 1 async db queries
case CMSG_REQUEST_VEHICLE_PREV_SEAT : // not profiled
case CMSG_REQUEST_VEHICLE_NEXT_SEAT : // not profiled
case CMSG_REQUEST_VEHICLE_SWITCH_SEAT : // not profiled
case CMSG_REQUEST_VEHICLE_EXIT : // not profiled
case CMSG_EJECT_PASSENGER : // not profiled
case CMSG_ITEM_PURCHASE_REFUND : // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_SOCKET_GEMS : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_WRAP_ITEM : // not profiled
case CMSG_REPORT_PVP_PLAYER_AFK : // not profiled
2014-05-24 22:04:03 +02:00
{
2014-06-09 21:35:59 +02:00
maxPacketCounterAllowed = 10 ;
2014-05-24 22:04:03 +02:00
break ;
}
2015-04-01 01:44:10 +02:00
case CMSG_CREATE_CHARACTER : // 7 5 3 async db queries
case CMSG_ENUM_CHARACTERS : // 22 3 2 async db queries
case CMSG_ENUM_CHARACTERS_DELETED_BY_CLIENT : // 22 3 2 async db queries
2015-04-25 21:24:39 +02:00
case CMSG_SUPPORT_TICKET_SUBMIT_BUG : // not profiled 1 async db query
case CMSG_SUPPORT_TICKET_SUBMIT_SUGGESTION : // not profiled 1 async db query
case CMSG_SUPPORT_TICKET_SUBMIT_COMPLAINT : // not profiled 1 async db query
2015-04-01 01:44:10 +02:00
case CMSG_CALENDAR_UPDATE_EVENT : // not profiled
case CMSG_CALENDAR_REMOVE_EVENT : // not profiled
case CMSG_CALENDAR_COPY_EVENT : // not profiled
case CMSG_CALENDAR_EVENT_INVITE : // not profiled
case CMSG_CALENDAR_EVENT_SIGN_UP : // not profiled
case CMSG_CALENDAR_EVENT_RSVP : // not profiled
case CMSG_CALENDAR_EVENT_MODERATOR_STATUS : // not profiled
case CMSG_CALENDAR_REMOVE_INVITE : // not profiled
case CMSG_SET_LOOT_METHOD : // not profiled
2015-02-13 18:31:50 +00:00
case CMSG_GUILD_INVITE_BY_NAME : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_ACCEPT_GUILD_INVITE : // not profiled
case CMSG_GUILD_DECLINE_INVITATION : // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_LEAVE : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_GUILD_DELETE : // not profiled
case CMSG_GUILD_SET_GUILD_MASTER : // not profiled
case CMSG_GUILD_UPDATE_MOTD_TEXT : // not profiled
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_SET_RANK_PERMISSIONS : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_GUILD_ADD_RANK : // not profiled
case CMSG_GUILD_DELETE_RANK : // not profiled
case CMSG_GUILD_UPDATE_INFO_TEXT : // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_BANK_DEPOSIT_MONEY : // not profiled
2015-02-13 18:31:50 +00:00
case CMSG_GUILD_BANK_WITHDRAW_MONEY : // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_BANK_BUY_TAB : // not profiled
2015-02-13 18:31:50 +00:00
case CMSG_GUILD_BANK_UPDATE_TAB : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_GUILD_BANK_SET_TAB_TEXT : // not profiled
2015-02-13 18:31:50 +00:00
case CMSG_SAVE_GUILD_EMBLEM : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_PETITION_RENAME_GUILD : // not profiled
case CMSG_CONFIRM_RESPEC_WIPE : // not profiled
2015-01-10 20:57:53 +01:00
case CMSG_SET_DUNGEON_DIFFICULTY : // not profiled
case CMSG_SET_RAID_DIFFICULTY : // not profiled
2015-04-01 01:44:10 +02:00
case CMSG_SET_PARTY_ASSIGNMENT : // not profiled
case CMSG_DO_READY_CHECK : // not profiled
2014-05-25 15:26:49 +02:00
{
2014-06-09 21:35:59 +02:00
maxPacketCounterAllowed = 3 ;
2014-05-25 15:26:49 +02:00
break ;
}
2015-02-01 20:52:05 +01:00
case CMSG_GET_ITEM_PURCHASE_DATA : // not profiled
2014-05-25 15:26:49 +02:00
{
maxPacketCounterAllowed = PLAYER_SLOTS_COUNT ;
break ;
2015-03-29 03:28:29 +02:00
}
2014-05-24 22:04:03 +02:00
default :
{
2014-05-25 15:26:49 +02:00
maxPacketCounterAllowed = 100 ;
2014-05-24 22:04:03 +02:00
break ;
}
}
return maxPacketCounterAllowed ;
}
2017-05-18 23:52:58 +02:00
WorldSession :: DosProtection :: DosProtection ( WorldSession * s ) : Session ( s ), _policy (( Policy ) sWorld -> getIntConfig ( CONFIG_PACKET_SPOOF_POLICY ))
{
}