2010-10-07 15:35:36 +02:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 TrinityCore <http://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
2014-07-07 22:03:41 +02:00
#include "WorldSocket.h"
2012-07-18 14:43:55 +02:00
#include <zlib.h>
2013-02-04 08:21:25 +01:00
#include "Config.h"
2008-10-11 14:16:25 -05:00
#include "Common.h"
2010-06-08 17:01:03 -06:00
#include "DatabaseEnv.h"
2013-02-25 10:47:50 +01:00
#include "AccountMgr.h"
2008-10-11 14:16:25 -05:00
#include "Log.h"
#include "Opcodes.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "Player.h"
2010-01-13 11:16:38 +01:00
#include "Vehicle.h"
2008-10-11 14:16:25 -05:00
#include "ObjectMgr.h"
2011-05-04 10:08:09 +02:00
#include "GuildMgr.h"
2008-10-11 14:16:25 -05:00
#include "Group.h"
#include "Guild.h"
#include "World.h"
#include "ObjectAccessor.h"
2010-08-08 04:37:24 +02:00
#include "BattlegroundMgr.h"
2008-10-14 11:57:03 -05:00
#include "OutdoorPvPMgr.h"
2009-06-16 11:19:59 -05:00
#include "MapManager.h"
2008-10-11 14:16:25 -05:00
#include "SocialMgr.h"
2010-06-07 16:21:52 -06:00
#include "zlib.h"
2010-01-19 11:36:05 +01:00
#include "ScriptMgr.h"
2010-07-30 21:54:46 -07:00
#include "Transport.h"
2012-02-19 13:51:16 +01:00
#include "WardenWin.h"
#include "WardenMac.h"
2014-10-17 22:48:06 +02:00
#include "BattlenetServerManager.h"
2014-11-03 19:11:14 +01:00
#include "CharacterPackets.h"
2014-11-04 00:01:09 +01:00
#include "ClientConfigPackets.h"
2009-10-17 15:51:44 -07: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-10-25 15:41:42 +01:00
OpcodeHandler 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-10-25 15:41:42 +01:00
OpcodeHandler 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
2014-07-19 03:38:57 +02:00
WorldSession :: WorldSession ( uint32 id , uint32 battlenetAccountId , std :: shared_ptr < WorldSocket > sock , AccountTypes sec , uint8 expansion , time_t mute_time , 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 ),
2014-06-08 17:58:28 +02:00
_battlenetAccountId ( battlenetAccountId ),
2012-11-16 09:51:44 +01:00
m_expansion ( expansion ),
_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 ),
2012-11-16 09:51:44 +01:00
m_TutorialsChanged ( false ),
_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 ),
2014-09-14 16:14:12 +02:00
m_currentBankerGUID ()
2008-10-11 14:16:25 -05:00
{
2013-12-14 18:41:26 +01:00
memset ( m_Tutorials , 0 , sizeof ( m_Tutorials ));
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 ;
2012-07-18 14:43:55 +02:00
2014-11-09 00:37:33 +01:00
InitializeQueryCallbackParameters ();
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
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
2014-09-14 17:29:13 +02:00
ss << "[Player: " << GetPlayerName () << " (" ;
if ( _player != NULL )
ss << _player -> GetGUID (). ToString () << ", " ;
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
{
2014-11-09 00:37:33 +01:00
if ( ! m_Socket [ packet -> GetConnection ()])
2008-10-11 14:16:25 -05:00
return ;
2009-10-17 15:51:44 -07: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 ;
}
2012-08-03 18:54:37 +01:00
if ( ! forced )
2012-07-11 23:29:33 +02:00
{
2014-10-25 15:41:42 +01:00
OpcodeHandler const * handler = opcodeTable [ static_cast < OpcodeServer > ( packet -> GetOpcode ())];
2012-09-11 15:59:45 +02:00
if ( ! handler || 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 );
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "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_INFO ( "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 );
2014-11-09 00:37:33 +01:00
m_Socket [ packet -> GetConnection ()] -> 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
2011-06-12 02:06:07 +02:00
void WorldSession :: LogUnprocessedTail ( WorldPacket * 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 ;
2011-12-19 21:12:35 +01:00
//! To prevent infinite loop
WorldPacket * firstDelayedPacket = NULL ;
//! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all
//! *properly timed* packets, and we're now at the part of the queue where we find
//! delayed packets that were re-enqueued due to improper timing. To prevent an infinite
//! loop caused by re-enqueueing the same packets over and over again, we stop updating this session
//! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session.
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
2014-11-09 21:36:06 +01:00
while ( m_Socket [ CONNECTION_TYPE_REALM ] && ! _recvQueue . empty () && _recvQueue . peek ( true ) != firstDelayedPacket && _recvQueue . next ( packet , updater ))
2008-10-11 14:16:25 -05:00
{
2014-05-24 22:04:03 +02:00
if ( ! AntiDOS . EvaluateOpcode ( * packet , currentTime ))
2013-08-29 16:43:37 +01:00
KickPlayer ();
2012-08-21 23:40:38 +01:00
2014-10-25 15:41:42 +01:00
OpcodeHandler 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
{
2013-09-01 23:48:40 +02:00
//! Prevent infinite loop
if ( ! firstDelayedPacket )
firstDelayedPacket = packet ;
//! Because checking a bool is faster than reallocating memory
deletePacket = false ;
QueuePacket ( packet );
//! Log
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
2014-10-25 15:41:42 +01:00
"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
}
else if ( _player -> IsInWorld ())
{
2014-08-12 00:44:26 +02:00
sScriptMgr -> OnPacketReceive ( this , * packet );
2014-11-03 02:11:15 +01:00
opHandle -> Call ( this , * packet );
2012-11-26 08:43:29 +01:00
LogUnprocessedTail ( 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" );
else
{
// 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
LogUnprocessedTail ( packet );
}
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" );
else
{
2014-08-11 17:28:10 +02:00
sScriptMgr -> OnPacketReceive ( this , * packet );
2014-11-03 02:11:15 +01:00
opHandle -> Call ( this , * packet );
2012-11-23 12:36:18 +01:00
LogUnprocessedTail ( 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.
if ( packet -> GetOpcode () == CMSG_CHAR_ENUM )
m_playerRecentlyLogout = false ;
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
LogUnprocessedTail ( packet );
break ;
case STATUS_NEVER :
2014-10-25 15:41:42 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not allowed opcode %s from %s" , GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str ()
2012-10-24 15:34:23 +02:00
, GetPlayerInfo (). c_str ());
2013-09-01 23:48:40 +02:00
break ;
case STATUS_UNHANDLED :
2014-10-25 15:41:42 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not handled opcode %s from %s" , GetOpcodeNameForLogging ( static_cast < OpcodeClient > ( packet -> GetOpcode ())). c_str ()
2012-10-24 15:34:23 +02:00
, 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
}
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
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!!!
2010-12-29 20:20:09 -08:00
if ( updater . ProcessLogout ())
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
{
2014-11-09 21:36:06 +01:00
m_Socket [ CONNECTION_TYPE_REALM ]. reset ();
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 ())
2008-10-11 14:16:25 -05:00
HandleMoveWorldportAckOpcode ();
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 )
{
2014-10-21 20:27:00 +02:00
ObjectGuid lguid = _player -> GetLootGUID ();
if ( ! lguid . IsEmpty ())
2008-10-21 13:19:26 -05:00
DoLootRelease ( lguid );
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 ())
2009-07-28 16:26:05 +02:00
HandleMoveWorldportAckOpcode ();
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 ;
2014-10-26 22:06:48 +01:00
_player -> SetGuidValue ( PLAYER_FIELD_INV_SLOT_HEAD + ( j * 4 ), ObjectGuid :: Empty );
2009-05-31 15:56:51 -05:00
_player -> SetUInt32Value ( PLAYER_FIELD_BUYBACK_PRICE_1 + eslot , 0 );
_player -> SetUInt32Value ( PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + 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 );
sSocialMgr -> RemovePlayerSocial ( _player -> GetGUID ());
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
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
sBattlenetServer . SendChangeToonOnlineState ( GetBattlenetAccountId (), GetAccountId (), _player -> GetGUID (), _player -> GetName (), false );
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
2011-12-25 18:12:58 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_UPD_ACCOUNT_ONLINE );
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
2011-04-29 20:47:02 +02:00
void WorldSession :: SendNotification ( const char * 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
2012-07-17 11:21:12 +02:00
size_t len = strlen ( szStr );
WorldPacket data ( SMSG_NOTIFICATION , 2 + len );
data . WriteBits ( len , 13 );
data . FlushBits ();
data . append ( szStr , len );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
void WorldSession :: SendNotification ( uint32 string_id , ...)
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
char const * format = GetTrinityString ( string_id );
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' ;
2008-10-19 17:27:18 -05:00
va_start ( ap , string_id );
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
2012-07-17 11:21:12 +02:00
size_t len = strlen ( szStr );
WorldPacket data ( SMSG_NOTIFICATION , 2 + len );
data . WriteBits ( len , 13 );
data . FlushBits ();
data . append ( szStr , len );
2008-10-11 14:16:25 -05:00
SendPacket ( & data );
}
}
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
2010-04-07 22:59:46 +02:00
void WorldSession :: Handle_NULL ( WorldPacket & recvPacket )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received unhandled opcode %s 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
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
2010-04-07 22:59:46 +02:00
void WorldSession :: Handle_ServerSide ( WorldPacket & recvPacket )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received server-side opcode %s 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
2010-04-07 22:59:46 +02:00
void WorldSession :: Handle_Deprecated ( WorldPacket & recvPacket )
2008-10-11 14:16:25 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received deprecated opcode %s 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
2009-09-01 16:47:49 -05:00
void WorldSession :: LoadGlobalAccountData ()
2008-12-24 09:58:26 -06:00
{
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_ACCOUNT_DATA );
2010-09-20 18:20:40 +02:00
stmt -> setUInt32 ( 0 , GetAccountId ());
LoadAccountData ( CharacterDatabase . Query ( stmt ), GLOBAL_CACHE_MASK );
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
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 ))
m_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
2011-01-19 02:53:44 +01:00
m_accountData [ type ]. Time = time_t ( fields [ 1 ]. GetUInt32 ());
2010-09-24 22:16:21 +02:00
m_accountData [ type ]. Data = fields [ 2 ]. GetString ();
}
while ( result -> NextRow ());
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2012-10-24 15:34:23 +02:00
void WorldSession :: SetAccountData ( AccountDataType type , time_t tm , 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 )
{
2014-10-23 21:34:03 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_REP_ACCOUNT_DATA );
stmt -> setUInt32 ( 0 , GetAccountId ());
stmt -> setUInt8 ( 1 , type );
stmt -> setUInt32 ( 2 , uint32 ( tm ));
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
2014-10-23 21:34:03 +02:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_REP_PLAYER_ACCOUNT_DATA );
stmt -> setUInt64 ( 0 , m_GUIDLow );
stmt -> setUInt8 ( 1 , type );
stmt -> setUInt32 ( 2 , uint32 ( tm ));
stmt -> setString ( 3 , data );
CharacterDatabase . Execute ( stmt );
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2011-02-24 23:39:45 +06:00
m_accountData [ type ]. Time = tm ;
2008-12-24 09:58:26 -06:00
m_accountData [ type ]. Data = data ;
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: LoadTutorialsData ()
{
2011-02-24 23:57:43 +06:00
memset ( m_Tutorials , 0 , sizeof ( uint32 ) * MAX_ACCOUNT_TUTORIAL_VALUES );
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_TUTORIALS );
2011-02-24 23:57:43 +06:00
stmt -> setUInt32 ( 0 , GetAccountId ());
if ( PreparedQueryResult result = CharacterDatabase . Query ( stmt ))
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
m_Tutorials [ i ] = ( * result )[ i ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
m_TutorialsChanged = false ;
}
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
void WorldSession :: SendTutorialsData ()
{
2011-02-24 23:57:43 +06:00
WorldPacket data ( SMSG_TUTORIAL_FLAGS , 4 * MAX_ACCOUNT_TUTORIAL_VALUES );
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
2009-06-11 00:45:59 -05:00
data << m_Tutorials [ i ];
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2010-12-29 20:20:09 -08:00
void WorldSession :: SaveTutorialsData ( SQLTransaction & trans )
2009-06-11 00:45:59 -05:00
{
2010-04-07 19:14:10 +02:00
if ( ! m_TutorialsChanged )
2009-06-11 00:45:59 -05:00
return ;
2009-10-17 15:51:44 -07:00
2012-01-01 01:09:38 +01:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( CHAR_SEL_HAS_TUTORIALS );
2011-02-24 23:57:43 +06:00
stmt -> setUInt32 ( 0 , GetAccountId ());
2014-07-06 13:26:29 -05:00
bool hasTutorials = bool ( CharacterDatabase . Query ( stmt ));
2011-02-24 23:57:43 +06:00
// Modify data in DB
2012-01-01 01:09:38 +01:00
stmt = CharacterDatabase . GetPreparedStatement ( hasTutorials ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS );
2011-02-24 23:57:43 +06:00
for ( uint8 i = 0 ; i < MAX_ACCOUNT_TUTORIAL_VALUES ; ++ i )
stmt -> setUInt32 ( i , m_Tutorials [ i ]);
stmt -> setUInt32 ( MAX_ACCOUNT_TUTORIAL_VALUES , GetAccountId ());
trans -> Append ( stmt );
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
m_TutorialsChanged = false ;
}
2009-10-17 15:51:44 -07:00
2014-10-31 01:20:53 +01:00
void WorldSession :: ReadAddonsInfo ( ByteBuffer & data )
2009-03-21 14:39:04 -06:00
{
2009-03-21 14:44:36 -06:00
if ( data . rpos () + 4 > data . size ())
return ;
2012-05-30 08:01:02 +02:00
2009-03-21 14:39:04 -06:00
uint32 size ;
data >> size ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! size )
2009-03-21 14:39:04 -06:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( size > 0xFFFFF )
2009-08-19 16:26:22 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "WorldSession::ReadAddonsInfo addon info too big, size %u" , size );
2009-08-19 16:26:22 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
uLongf uSize = size ;
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
uint32 pos = data . rpos ();
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
ByteBuffer addonInfo ;
addonInfo . resize ( size );
2009-10-17 15:51:44 -07:00
2014-11-04 00:01:09 +01:00
m_addonsList . clear ();
2013-01-30 08:39:06 +01:00
if ( uncompress ( addonInfo . contents (), & uSize , data . contents () + pos , data . size () - pos ) == Z_OK )
2009-03-21 14:39:04 -06:00
{
uint32 addonsCount ;
addonInfo >> addonsCount ; // addons count
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < addonsCount ; ++ i )
2009-03-21 14:39:04 -06:00
{
std :: string addonName ;
uint8 enabled ;
uint32 crc , unk1 ;
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
// check next addon data format correctness
2010-12-29 20:20:09 -08:00
if ( addonInfo . rpos () + 1 > addonInfo . size ())
2009-03-21 14:39:04 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
addonInfo >> addonName ;
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
addonInfo >> enabled >> crc >> unk1 ;
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "misc" , "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x" , addonName . c_str (), enabled , crc , unk1 );
2010-01-20 16:24:52 +01:00
AddonInfo addon ( addonName , enabled , crc , 2 , true );
2011-09-09 15:22:52 +02:00
SavedAddon const * savedAddon = AddonMgr :: GetAddonInfo ( addonName );
2010-01-20 16:24:52 +01:00
if ( savedAddon )
{
if ( addon . CRC != savedAddon -> CRC )
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "misc" , "ADDON: %s was known, but didn't match known CRC (0x%x)!" , addon . Name . c_str (), savedAddon -> CRC );
2010-01-20 16:24:52 +01:00
else
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "misc" , "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC) ;
2010-01-20 16:24:52 +01:00
}
else
{
2011-09-09 15:22:52 +02:00
AddonMgr :: SaveAddon ( addon );
2010-01-20 16:24:52 +01:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "misc" , "ADDON: %s (0x%x) was not known, saving..." , addon . Name . c_str (), addon . CRC );
2010-01-20 16:24:52 +01:00
}
2009-10-17 15:51:44 -07:00
2013-03-08 21:41:30 +01:00
/// @todo Find out when to not use CRC/pubkey, and other possible states.
2010-01-20 16:24:52 +01:00
m_addonsList . push_back ( addon );
2009-03-21 14:39:04 -06:00
}
2009-10-17 15:51:44 -07:00
2010-01-15 19:50:27 +01:00
uint32 currentTime ;
addonInfo >> currentTime ;
2013-11-08 10:50:51 +01:00
TC_LOG_DEBUG ( "network" , "ADDON: CurrentTime: %u" , currentTime );
2009-03-21 14:39:04 -06:00
}
else
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "misc" , "Addon packet uncompress error!" );
2009-03-21 14:39:04 -06:00
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
void WorldSession :: SendAddonsInfo ()
{
2014-11-04 00:01:09 +01:00
WorldPackets :: ClientConfig :: AddonInfo addonInfo ;
addonInfo . Addons = & m_addonsList ;
addonInfo . BannedAddons = AddonMgr :: GetBannedAddons ();
SendPacket ( addonInfo . Write ());
2009-03-21 14:39:04 -06: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 ();
}
2012-08-10 02:57:16 +01:00
void WorldSession :: HandleUnregisterAddonPrefixesOpcode ( WorldPacket & /*recvPacket*/ ) // empty packet
{
2013-11-08 11:12:17 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_UNREGISTER_ALL_ADDON_PREFIXES" );
2012-08-10 02:57:16 +01:00
_registeredAddonPrefixes . clear ();
}
void WorldSession :: HandleAddonRegisteredPrefixesOpcode ( WorldPacket & recvPacket )
{
2013-11-08 11:12:17 +01:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_ADDON_REGISTERED_PREFIXES" );
2012-08-10 02:57:16 +01:00
// This is always sent after CMSG_UNREGISTER_ALL_ADDON_PREFIXES
uint32 count = recvPacket . ReadBits ( 25 );
if ( count > REGISTERED_ADDON_PREFIX_SOFTCAP )
{
// if we have hit the softcap (64) nothing should be filtered
_filterAddonMessages = false ;
recvPacket . rfinish ();
return ;
}
std :: vector < uint8 > lengths ( count );
for ( uint32 i = 0 ; i < count ; ++ i )
lengths [ i ] = recvPacket . ReadBits ( 5 );
for ( uint32 i = 0 ; i < count ; ++ i )
_registeredAddonPrefixes . push_back ( recvPacket . ReadString ( lengths [ i ]));
if ( _registeredAddonPrefixes . size () > REGISTERED_ADDON_PREFIX_SOFTCAP ) // shouldn't happen
{
_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
}
void WorldSession :: InitializeQueryCallbackParameters ()
{
2011-06-23 09:13:58 +02:00
// Callback parameters that have pointers in them should be properly
2014-11-03 19:11:14 +01:00
// initialized to nullptr here.
_charRenameCallback . SetParam ( nullptr );
2009-10-17 16:20:24 -07:00
}
2010-08-18 19:48:51 +02:00
void WorldSession :: ProcessQueryCallbacks ()
{
2011-12-25 01:27:15 +01:00
PreparedQueryResult result ;
2010-08-18 19:48:51 +02:00
2014-11-03 19:11:14 +01:00
//! HandleCharEnumOpcode and HandleCharUndeleteEnumOpcode
if ( _charEnumCallback . IsReady ())
2010-08-18 19:48:51 +02:00
{
2014-11-03 19:11:14 +01:00
_charEnumCallback . GetResult ( result );
if ( bool undelete = _charEnumCallback . GetParam ())
HandleCharUndeleteEnum ( result );
else
HandleCharEnum ( result );
_charEnumCallback . FreeResult ();
2010-08-18 19:48:51 +02:00
}
2014-11-03 19:11:14 +01:00
//! HandleCharCreateOpcode
2011-06-22 14:20:42 +02:00
if ( _charCreateCallback . IsReady ())
{
2011-12-25 01:27:15 +01:00
_charCreateCallback . GetResult ( result );
2014-11-03 19:11:14 +01:00
HandleCharCreateCallback ( result , _charCreateCallback . GetParam (). get ());
2011-06-22 14:20:42 +02:00
}
2011-10-18 14:59:23 +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 )
2010-08-18 19:48:51 +02:00
{
2014-06-24 13:17:23 -05:00
SQLQueryHolder * param = _charLoginCallback . get ();
2010-08-18 19:48:51 +02:00
HandlePlayerLogin (( LoginQueryHolder * ) param );
}
//! HandleAddFriendOpcode
2011-06-22 14:20:42 +02:00
if ( _addFriendCallback . IsReady ())
2010-08-18 19:48:51 +02:00
{
2011-06-22 14:20:42 +02:00
std :: string param = _addFriendCallback . GetParam ();
_addFriendCallback . GetResult ( result );
2010-08-18 19:48:51 +02:00
HandleAddFriendOpcodeCallBack ( result , param );
2011-06-22 14:20:42 +02:00
_addFriendCallback . FreeResult ();
2010-08-18 19:48:51 +02:00
}
//- HandleCharRenameOpcode
2011-06-22 14:20:42 +02:00
if ( _charRenameCallback . IsReady ())
2010-08-18 19:48:51 +02:00
{
2011-06-22 14:20:42 +02:00
_charRenameCallback . GetResult ( result );
2014-11-03 19:11:14 +01:00
WorldPackets :: Character :: CharacterRenameInfo * renameInfo = _charRenameCallback . GetParam ();
HandleCharRenameCallBack ( result , renameInfo );
2014-10-19 15:12:20 +02:00
delete renameInfo ;
_charRenameCallback . Reset ();
2010-08-18 19:48:51 +02:00
}
2010-09-12 01:40:27 +02:00
2014-11-03 19:11:14 +01:00
/// HandleUndeleteCooldownStatusOpcode
/// wait until no char undelete is in progress
if ( ! _charUndeleteCallback . GetStage () && _undeleteCooldownStatusCallback . IsReady ())
{
_undeleteCooldownStatusCallback . GetResult ( result );
HandleUndeleteCooldownStatusCallback ( result );
}
/// HandleCharUndeleteOpcode
if ( _charUndeleteCallback . IsReady ())
{
_charUndeleteCallback . GetResult ( result );
HandleCharUndeleteCallback ( result , _charUndeleteCallback . GetParam (). get ());
}
2010-08-18 19:48:51 +02:00
//- HandleCharAddIgnoreOpcode
2014-07-02 21:56:40 -05:00
if ( _addIgnoreCallback . valid () && _addIgnoreCallback . wait_for ( std :: chrono :: seconds ( 0 )) == std :: future_status :: ready )
2010-08-18 19:48:51 +02:00
{
2014-06-24 13:17:23 -05:00
result = _addIgnoreCallback . get ();
2010-08-18 19:48:51 +02:00
HandleAddIgnoreOpcodeCallBack ( result );
}
2010-08-24 19:04:25 +02:00
//- SendStabledPet
2011-06-22 14:20:42 +02:00
if ( _sendStabledPetCallback . IsReady ())
2010-08-24 19:04:25 +02:00
{
2014-09-14 16:14:12 +02:00
ObjectGuid param = _sendStabledPetCallback . GetParam ();
2011-06-22 14:20:42 +02:00
_sendStabledPetCallback . GetResult ( result );
2010-08-25 19:12:53 +02:00
SendStablePetCallback ( result , param );
2011-06-22 14:20:42 +02:00
_sendStabledPetCallback . FreeResult ();
2010-08-24 19:04:25 +02:00
}
2010-08-25 21:03:28 +02:00
//- HandleStablePet
2014-07-02 21:56:40 -05:00
if ( _stablePetCallback . valid () && _stablePetCallback . wait_for ( std :: chrono :: seconds ( 0 )) == std :: future_status :: ready )
2010-08-25 21:03:28 +02:00
{
2014-06-24 13:17:23 -05:00
result = _stablePetCallback . get ();
2010-08-25 21:03:28 +02:00
HandleStablePetCallback ( result );
}
//- HandleUnstablePet
2011-06-22 14:20:42 +02:00
if ( _unstablePetCallback . IsReady ())
2010-08-25 21:03:28 +02:00
{
2011-06-22 14:20:42 +02:00
uint32 param = _unstablePetCallback . GetParam ();
_unstablePetCallback . GetResult ( result );
2010-08-25 21:03:28 +02:00
HandleUnstablePetCallback ( result , param );
2011-06-22 14:20:42 +02:00
_unstablePetCallback . FreeResult ();
2010-08-25 21:03:28 +02:00
}
//- HandleStableSwapPet
2011-06-22 14:20:42 +02:00
if ( _stableSwapCallback . IsReady ())
2010-08-25 21:03:28 +02:00
{
2011-06-22 14:20:42 +02:00
uint32 param = _stableSwapCallback . GetParam ();
_stableSwapCallback . GetResult ( result );
2010-08-25 21:03:28 +02:00
HandleStableSwapPetCallback ( result , param );
2011-06-22 14:20:42 +02:00
_stableSwapCallback . FreeResult ();
2010-08-25 21:03:28 +02:00
}
2010-08-21 20:08:47 +02:00
}
2012-02-19 13:51:16 +01:00
2012-10-24 15:34:23 +02:00
void WorldSession :: InitWarden ( BigNumber * k , std :: string const & os )
2012-02-19 13:51:16 +01:00
{
if ( os == "Win" )
{
2012-02-19 18:49:10 +01:00
_warden = new WardenWin ();
2012-02-19 13:51:16 +01:00
_warden -> Init ( this , k );
}
else if ( os == "OSX" )
{
// Disabled as it is causing the client to crash
2012-02-19 18:49:10 +01:00
// _warden = new WardenMac();
2012-02-19 13:51:16 +01:00
// _warden->Init(this, k);
}
}
2013-02-04 08:21:25 +01:00
void WorldSession :: LoadPermissions ()
{
uint32 id = GetAccountId ();
std :: string name ;
AccountMgr :: GetName ( id , name );
2013-09-27 13:25:48 +02:00
uint8 secLevel = GetSecurity ();
2013-02-04 08:21:25 +01:00
2014-10-17 22:48:06 +02:00
_RBACData = new rbac :: RBACData ( id , name , realmHandle . Index , secLevel );
2013-02-04 08:21:25 +01:00
_RBACData -> LoadFromDB ();
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]" ,
2014-10-17 22:48:06 +02:00
id , name . c_str (), realmHandle . Index , secLevel );
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]" ,
2014-10-17 22:48:06 +02:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realmHandle . Index );
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]" ,
2014-10-17 22:48:06 +02:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realmHandle . Index );
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 :
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "network" , "AntiDOS: Player kicked!" );
2013-08-30 15:44:17 +01:00
return false ;
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" );
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "network" , "AntiDOS: Player automatically banned for %u seconds." , duration );
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 )
{
2014-10-19 17:23:48 +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
case CMSG_NAME_QUERY: // 0 1
case CMSG_PET_NAME_QUERY: // 0 1
case CMSG_NPC_TEXT_QUERY: // 0 1
case CMSG_ATTACKSTOP: // 0 1
case CMSG_QUERY_QUESTS_COMPLETED: // 0 1
case CMSG_QUERY_TIME: // 0 1
case CMSG_CORPSE_MAP_POSITION_QUERY: // 0 1
case CMSG_MOVE_TIME_SKIPPED: // 0 1
case MSG_QUERY_NEXT_MAIL_TIME: // 0 1
case CMSG_SETSHEATHED: // 0 1
case MSG_RAID_TARGET_UPDATE: // 0 1
case CMSG_PLAYER_LOGOUT: // 0 1
case CMSG_LOGOUT_REQUEST: // 0 1
case CMSG_PET_RENAME: // 0 1
case CMSG_QUESTGIVER_REQUEST_REWARD: // 0 1
case CMSG_COMPLETE_CINEMATIC: // 0 1
case CMSG_BANKER_ACTIVATE: // 0 1
case CMSG_BUY_BANK_SLOT: // 0 1
case CMSG_OPT_OUT_OF_LOOT: // 0 1
case CMSG_DUEL_ACCEPTED: // 0 1
case CMSG_DUEL_CANCELLED: // 0 1
case CMSG_CALENDAR_COMPLAIN: // 0 1
case CMSG_QUEST_QUERY: // 0 1.5
case CMSG_GAMEOBJECT_QUERY: // 0 1.5
case CMSG_CREATURE_QUERY: // 0 1.5
case CMSG_QUESTGIVER_STATUS_QUERY: // 0 1.5
case CMSG_GUILD_QUERY: // 0 1.5
case CMSG_ARENA_TEAM_QUERY: // 0 1.5
case CMSG_TAXINODE_STATUS_QUERY: // 0 1.5
case CMSG_TAXIQUERYAVAILABLENODES: // 0 1.5
case CMSG_QUESTGIVER_QUERY_QUEST: // 0 1.5
case CMSG_PAGE_TEXT_QUERY: // 0 1.5
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_BANK_QUERY_TEXT: // 0 1.5
2014-06-09 21:35:59 +02:00
case MSG_CORPSE_QUERY: // 0 1.5
case MSG_MOVE_SET_FACING: // 0 1.5
case CMSG_REQUEST_PARTY_MEMBER_STATS: // 0 1.5
case CMSG_QUESTGIVER_COMPLETE_QUEST: // 0 1.5
case CMSG_SET_ACTION_BUTTON: // 0 1.5
case CMSG_RESET_INSTANCES: // 0 1.5
case CMSG_HEARTH_AND_RESURRECT: // 0 1.5
case CMSG_TOGGLE_PVP: // 0 1.5
case CMSG_PET_ABANDON: // 0 1.5
case CMSG_ACTIVATETAXIEXPRESS: // 0 1.5
case CMSG_ACTIVATETAXI: // 0 1.5
case CMSG_SELF_RES: // 0 1.5
case CMSG_UNLEARN_SKILL: // 0 1.5
case CMSG_EQUIPMENT_SET_SAVE: // 0 1.5
2014-06-15 19:36:30 +02:00
case CMSG_EQUIPMENT_SET_DELETE: // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_DISMISS_CRITTER: // 0 1.5
case CMSG_REPOP_REQUEST: // 0 1.5
case CMSG_GROUP_INVITE: // 0 1.5
2014-06-15 19:36:30 +02:00
case CMSG_GROUP_INVITE_RESPONSE: // 0 1.5
2014-06-09 21:35:59 +02:00
case CMSG_GROUP_UNINVITE_GUID: // 0 1.5
case CMSG_GROUP_DISBAND: // 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
case CMSG_GUILD_BANK_LOG_QUERY: // 0 2
2014-06-09 21:35:59 +02:00
case CMSG_LOGOUT_CANCEL: // 0 2
case CMSG_REALM_SPLIT: // 0 2
case CMSG_ALTER_APPEARANCE: // 0 2
case CMSG_QUEST_CONFIRM_ACCEPT: // 0 2
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_EVENT_LOG_QUERY: // 0 2.5
2014-06-09 21:35:59 +02:00
case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: // 0 2.5
case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: // 0 2.5
case CMSG_BEGIN_TRADE: // 0 2.5
case CMSG_INITIATE_TRADE: // 0 3
2014-06-15 19:36:30 +02:00
case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: // 0 3.5
case CMSG_MESSAGECHAT_ADDON_GUILD: // 0 3.5
case CMSG_MESSAGECHAT_ADDON_OFFICER: // 0 3.5
case CMSG_MESSAGECHAT_ADDON_PARTY: // 0 3.5
case CMSG_MESSAGECHAT_ADDON_RAID: // 0 3.5
case CMSG_MESSAGECHAT_ADDON_WHISPER: // 0 3.5
case CMSG_MESSAGECHAT_AFK: // 0 3.5
case CMSG_MESSAGECHAT_BATTLEGROUND: // 0 3.5
case CMSG_MESSAGECHAT_CHANNEL: // 0 3.5
case CMSG_MESSAGECHAT_DND: // 0 3.5
case CMSG_MESSAGECHAT_EMOTE: // 0 3.5
case CMSG_MESSAGECHAT_GUILD: // 0 3.5
case CMSG_MESSAGECHAT_OFFICER: // 0 3.5
case CMSG_MESSAGECHAT_PARTY: // 0 3.5
case CMSG_MESSAGECHAT_RAID: // 0 3.5
case CMSG_MESSAGECHAT_RAID_WARNING: // 0 3.5
case CMSG_MESSAGECHAT_SAY: // 0 3.5
case CMSG_MESSAGECHAT_WHISPER: // 0 3.5
case CMSG_MESSAGECHAT_YELL: // 0 3.5
2014-06-09 21:35:59 +02:00
case CMSG_INSPECT: // 0 3.5
case CMSG_AREA_SPIRIT_HEALER_QUERY: // not profiled
2014-08-04 18:43:15 +02:00
case CMSG_STANDSTATECHANGE: // not profiled
case MSG_RANDOM_ROLL: // not profiled
case CMSG_TIME_SYNC_RESP: // not profiled
case CMSG_TRAINER_BUY_SPELL: // 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;
}
2014-06-09 21:35:59 +02:00
case CMSG_QUESTGIVER_ACCEPT_QUEST: // 0 4
case CMSG_QUESTLOG_REMOVE_QUEST: // 0 4
case CMSG_QUESTGIVER_CHOOSE_REWARD: // 0 4
case CMSG_CONTACT_LIST: // 0 5
case CMSG_LEARN_PREVIEW_TALENTS: // 0 6
case CMSG_AUTOBANK_ITEM: // 0 6
case CMSG_AUTOSTORE_BANK_ITEM: // 0 6
case CMSG_WHO: // 0 7
case CMSG_PLAYER_VEHICLE_ENTER: // 0 8
case CMSG_LEARN_PREVIEW_TALENTS_PET: // not profiled
case MSG_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;
}
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_SET_NOTE: // 1 2 1 async db query
2014-06-09 21:35:59 +02:00
case CMSG_SET_CONTACT_NOTES: // 1 2.5 1 async db query
case CMSG_CALENDAR_GET_CALENDAR: // 0 1.5 medium upload bandwidth usage
case CMSG_GUILD_BANK_QUERY_TAB: // 0 3.5 medium upload bandwidth usage
case CMSG_QUERY_INSPECT_ACHIEVEMENTS: // 0 13 high upload bandwidth usage
2014-08-04 18:43:15 +02:00
case CMSG_GAMEOBJ_REPORT_USE: // not profiled
case CMSG_GAMEOBJ_USE: // not profiled
case MSG_PETITION_DECLINE: // 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;
}
2014-06-09 21:35:59 +02:00
case CMSG_GM_REPORT_LAG: // 1 3 1 async db query
case CMSG_SPELLCLICK: // not profiled
2014-08-04 18:43:15 +02:00
case CMSG_DISMISS_CONTROLLED_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;
}
2014-06-09 21:35:59 +02:00
case CMSG_PETITION_SIGN: // 9 4 2 sync 1 async db queries
case CMSG_TURN_IN_PETITION: // 8 5.5 2 sync db query
case CMSG_GROUP_CHANGE_SUB_GROUP: // 6 5 1 sync 1 async db queries
case CMSG_PETITION_QUERY: // 4 3.5 1 sync db query
case CMSG_CHAR_RACE_CHANGE: // 5 4 1 sync db query
case CMSG_CHAR_CUSTOMIZE: // 5 5 1 sync db query
case CMSG_CHAR_FACTION_CHANGE: // 5 5 1 sync db query
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
case CMSG_CHAR_RENAME: // 5 3 1 async db query
case CMSG_GMSURVEY_SUBMIT: // 2 3 1 async db query
case CMSG_BUG: // 1 1 1 async db query
case CMSG_GROUP_SET_LEADER: // 1 2 1 async db query
case CMSG_GROUP_RAID_CONVERT: // 1 5 1 async db query
case CMSG_GROUP_ASSISTANT_LEADER: // 1 2 1 async db query
case CMSG_CALENDAR_ADD_EVENT: // 21 10 2 async db query
case CMSG_PETITION_BUY: // not profiled 1 sync 1 async db queries
case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: // not profiled
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
2014-06-15 19:36:30 +02:00
case CMSG_EJECT_PASSENGER: // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_ITEM_REFUND: // not profiled
case CMSG_SOCKET_GEMS: // not profiled
case CMSG_WRAP_ITEM: // not profiled
case CMSG_REPORT_PVP_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;
}
2014-06-09 21:35:59 +02:00
case CMSG_CHAR_CREATE: // 7 5 3 async db queries
case CMSG_CHAR_ENUM: // 22 3 2 async db queries
case CMSG_GMTICKET_CREATE: // 1 25 1 async db query
case CMSG_GMTICKET_UPDATETEXT: // 0 15 1 async db query
case CMSG_GMTICKET_DELETETICKET: // 1 25 1 async db query
case CMSG_GMRESPONSE_RESOLVE: // 1 25 1 async db query
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_SIGNUP: // not profiled
case CMSG_CALENDAR_EVENT_RSVP: // not profiled
case CMSG_CALENDAR_EVENT_REMOVE_INVITE: // not profiled
case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: // not profiled
case CMSG_ARENA_TEAM_INVITE: // not profiled
case CMSG_ARENA_TEAM_ACCEPT: // not profiled
case CMSG_ARENA_TEAM_DECLINE: // not profiled
case CMSG_ARENA_TEAM_LEAVE: // not profiled
case CMSG_ARENA_TEAM_DISBAND: // not profiled
case CMSG_ARENA_TEAM_REMOVE: // not profiled
case CMSG_ARENA_TEAM_LEADER: // not profiled
case CMSG_LOOT_METHOD: // not profiled
case CMSG_GUILD_INVITE: // not profiled
case CMSG_GUILD_ACCEPT: // not profiled
case CMSG_GUILD_DECLINE: // not profiled
case CMSG_GUILD_LEAVE: // not profiled
case CMSG_GUILD_DISBAND: // not profiled
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_SET_GUILD_MASTER: // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_MOTD: // not profiled
2014-06-15 19:36:30 +02:00
case CMSG_GUILD_SET_RANK_PERMISSIONS: // not profiled
2014-06-09 21:35:59 +02:00
case CMSG_GUILD_ADD_RANK: // not profiled
case CMSG_GUILD_DEL_RANK: // not profiled
case CMSG_GUILD_INFO_TEXT: // not profiled
case CMSG_GUILD_BANK_DEPOSIT_MONEY: // not profiled
case CMSG_GUILD_BANK_WITHDRAW_MONEY: // not profiled
case CMSG_GUILD_BANK_BUY_TAB: // not profiled
case CMSG_GUILD_BANK_UPDATE_TAB: // not profiled
case CMSG_SET_GUILD_BANK_TEXT: // not profiled
case MSG_SAVE_GUILD_EMBLEM: // not profiled
case MSG_PETITION_RENAME: // not profiled
case MSG_TALENT_WIPE_CONFIRM: // not profiled
case MSG_SET_DUNGEON_DIFFICULTY: // not profiled
case MSG_SET_RAID_DIFFICULTY: // not profiled
case MSG_PARTY_ASSIGNMENT: // not profiled
case MSG_RAID_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;
}
2014-06-09 21:35:59 +02:00
case CMSG_ITEM_REFUND_INFO: // not profiled
2014-05-25 15:26:49 +02:00
{
maxPacketCounterAllowed = PLAYER_SLOTS_COUNT;
break;
}
2014-10-19 17:23:48 +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 ;
}