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
2009-03-08 13:05:56 -06:00
#include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it
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"
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
{
2011-11-20 18:28:18 +01:00
Opcodes opcode = DropHighBytes ( packet -> GetOpcode ());
2012-05-30 08:01:02 +02:00
OpcodeHandler const * opHandle = opcodeTable [ opcode ];
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
{
2011-11-20 18:28:18 +01:00
Opcodes opcode = DropHighBytes ( packet -> GetOpcode ());
2012-05-30 08:01:02 +02:00
OpcodeHandler const * opHandle = opcodeTable [ opcode ];
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
2011-09-15 14:08:17 +02:00
WorldSession :: WorldSession ( uint32 id , 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 ),
2013-12-14 18:41:26 +01:00
m_GUIDLow ( 0 ),
2012-11-16 09:51:44 +01:00
_player ( NULL ),
m_Socket ( sock ),
_security ( sec ),
_accountId ( id ),
m_expansion ( expansion ),
_warden ( NULL ),
_logoutTime ( 0 ),
m_inQueue ( false ),
m_playerLoading ( 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 ),
2013-02-04 08:21:25 +01:00
_RBACData ( NULL )
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 )
{
2010-08-17 19:18:09 -07:00
m_Address = sock -> GetRemoteAddress ();
sock -> AddReference ();
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
InitializeQueryCallbackParameters ();
2012-07-18 14:43:55 +02:00
_compressionStream = new z_stream ();
_compressionStream -> zalloc = ( alloc_func ) NULL ;
_compressionStream -> zfree = ( free_func ) NULL ;
_compressionStream -> opaque = ( voidpf ) NULL ;
_compressionStream -> avail_in = 0 ;
_compressionStream -> next_in = NULL ;
int32 z_res = deflateInit ( _compressionStream , sWorld -> getIntConfig ( CONFIG_COMPRESSION ));
if ( z_res != Z_OK )
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network" , "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)" , z_res , zError ( z_res ));
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
2008-11-06 16:10:28 -06:00
if ( m_Socket )
2008-10-11 14:16:25 -05:00
{
2012-05-30 08:01:02 +02:00
m_Socket -> CloseSocket ();
m_Socket -> RemoveReference ();
2008-11-06 16:10:28 -06:00
m_Socket = NULL ;
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
2012-07-18 14:43:55 +02:00
int32 z_res = deflateEnd ( _compressionStream );
if ( z_res != Z_OK && z_res != Z_DATA_ERROR ) // Z_DATA_ERROR signals that internal state was BUSY
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network" , "Can't close packet compression stream (zlib: deflateEnd) Error code: %i (%s)" , z_res , zError ( z_res ));
2012-07-18 14:43:55 +02:00
delete _compressionStream ;
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
2012-10-24 15:34:23 +02:00
ss << "[Player: " << GetPlayerName ()
<< " (Guid: " << ( _player != NULL ? _player -> GetGUID () : 0 )
<< ", 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
2012-02-19 13:51:16 +01:00
/// Get player guid if available. Use for logging purposes only
uint32 WorldSession :: GetGuidLow () const
{
return GetPlayer () ? GetPlayer () -> GetGUIDLow () : 0 ;
}
2008-10-11 14:16:25 -05:00
/// Send a packet to the client
2012-08-03 18:54:37 +01:00
void WorldSession :: SendPacket ( WorldPacket const * packet , bool forced /*= false*/ )
2008-10-11 14:16:25 -05:00
{
if ( ! m_Socket )
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-05-25 22:25:26 +02:00
OpcodeHandler const * handler = ]. name ;
2012-09-11 15:59:45 +02:00
if ( ! handler || handler -> Status == STATUS_UNHANDLED )
2012-08-03 18:54:37 +01:00
{
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network.opcode" , "Prevented sending disabled opcode %s to %s" , GetOpcodeNameForLogging ( 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
2012-05-30 08:01:02 +02:00
if ( m_Socket -> SendPacket ( * packet ) == - 1 )
m_Socket -> CloseSocket ();
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07: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" ,
2012-10-24 15:34:23 +02:00
GetOpcodeNameForLogging ( 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" ,
2012-10-24 15:34:23 +02:00
uint32 ( packet -> rpos ()), uint32 ( packet -> wpos ()), GetOpcodeNameForLogging ( 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 ())
m_Socket -> 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
2011-12-25 01:27:15 +01:00
while ( m_Socket && ! m_Socket -> IsClosed () &&
2011-12-19 21:12:35 +01:00
! _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
2013-09-01 23:48:40 +02:00
OpcodeHandler const * opHandle = opcodeTable [ packet -> GetOpcode ()];
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. "
2012-08-21 22:12:55 +02:00
"Player is currently not in world yet." , GetOpcodeNameForLogging ( packet -> GetOpcode ()). c_str ());
2009-09-01 16:47:49 -05:00
}
2013-09-01 23:48:40 +02:00
}
else if ( _player -> IsInWorld ())
{
2011-11-20 18:28:18 +01:00
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2012-09-11 15:59:45 +02:00
( this ->* opHandle -> Handler )( * 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
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
( this ->* opHandle -> Handler )( * packet );
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
{
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2013-09-01 23:48:40 +02:00
( this ->* opHandle -> Handler )( * 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 ;
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
( this ->* opHandle -> Handler )( * packet );
LogUnprocessedTail ( packet );
break ;
case STATUS_NEVER :
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not allowed opcode %s from %s" , GetOpcodeNameForLogging ( 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 :
2013-11-08 11:12:17 +01:00
TC_LOG_ERROR ( "network.opcode" , "Received not handled opcode %s from %s" , GetOpcodeNameForLogging ( 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
2012-02-19 13:51:16 +01:00
if ( m_Socket && ! m_Socket -> IsClosed () && _warden )
_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
if ( ShouldLogOut ( currTime ) && ! m_playerLoading )
LogoutPlayer ( true );
2010-05-05 22:56:02 +02:00
2012-02-19 13:51:16 +01:00
if ( m_Socket && GetPlayer () && _warden )
_warden -> Update ();
2010-12-29 20:20:09 -08:00
///- Cleanup socket pointer if need
if ( m_Socket && m_Socket -> IsClosed ())
{
m_Socket -> RemoveReference ();
m_Socket = NULL ;
}
2009-10-17 15:51:44 -07:00
2010-12-29 20:20:09 -08:00
if ( ! m_Socket )
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 )
{
2012-05-30 08:01:02 +02:00
if ( uint64 lguid = _player -> GetLootGUID ())
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
//FIXME: logout must be delayed in case lost connection with client in time of combat
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 ;
2009-05-31 15:56:51 -05:00
_player -> SetUInt64Value ( PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + ( eslot * 2 ), 0 );
_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)
2010-04-07 19:14:10 +02:00
if ( _player -> GetGroup () && ! _player -> GetGroup () -> isRaidGroup () && m_Socket )
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
2010-12-22 21:25:23 +01:00
sSocialMgr -> SendFriendStatus ( _player , FRIEND_OFFLINE , _player -> GetGUIDLow (), true );
2012-05-30 08:01:02 +02:00
sSocialMgr -> RemovePlayerSocial ( _player -> GetGUIDLow ());
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 ();
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "entities.player.character" , "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d" ,
2012-10-24 13:29:34 +02:00
GetAccountId (), GetRemoteAddress (). c_str (), _player -> GetName (). c_str (), _player -> GetGUIDLow (), _player -> getLevel ());
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
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_LOGOUT_COMPLETE , 0 );
SendPacket ( & data );
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
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 ;
2013-08-29 16:43:37 +01:00
AntiDOS . AllowOpcode ( CMSG_CHAR_ENUM , true );
2008-10-11 14:16:25 -05:00
LogoutRequest ( 0 );
}
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 ()
{
2008-11-06 16:10:28 -06:00
if ( m_Socket )
2010-12-29 20:20:09 -08:00
m_Socket -> CloseSocket ();
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
2010-12-29 20:20:09 -08:00
const char * WorldSession :: GetTrinityString ( int32 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"
2012-10-24 15:34:23 +02:00
, GetOpcodeNameForLogging ( 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"
2012-10-24 15:34:23 +02:00
, GetOpcodeNameForLogging ( 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"
2012-10-24 15:34:23 +02:00
, GetOpcodeNameForLogging ( 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"
2012-10-24 15:34:23 +02:00
, GetOpcodeNameForLogging ( recvPacket . GetOpcode ()). c_str (), GetPlayerInfo (). c_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
void WorldSession :: SendAuthWaitQue ( uint32 position )
2008-12-12 11:21:28 -06:00
{
2010-04-07 19:14:10 +02:00
if ( position == 0 )
2008-12-12 11:21:28 -06:00
{
2010-04-07 22:59:46 +02:00
WorldPacket packet ( SMSG_AUTH_RESPONSE , 1 );
2012-07-04 18:24:05 +02:00
packet . WriteBit ( 0 ); // has queue info
packet . WriteBit ( 0 ); // has account info
2012-08-04 19:11:13 +01:00
packet . FlushBits ();
2010-04-07 22:59:46 +02:00
packet << uint8 ( AUTH_OK );
2008-12-12 11:21:28 -06:00
SendPacket ( & packet );
}
else
{
2010-04-28 08:55:07 +02:00
WorldPacket packet ( SMSG_AUTH_RESPONSE , 6 );
2012-07-04 18:24:05 +02:00
packet . WriteBit ( 1 ); // has queue info
packet . WriteBit ( 0 ); // unk queue bool
packet . WriteBit ( 0 ); // has account info
2012-08-04 19:11:13 +01:00
packet . FlushBits ();
2010-04-07 22:59:46 +02:00
packet << uint8 ( AUTH_WAIT_QUEUE );
2010-04-28 08:55:07 +02:00
packet << uint32 ( position );
2008-12-12 11:21:28 -06:00
SendPacket ( & packet );
}
}
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
{
2011-02-24 23:39:45 +06:00
uint32 id = 0 ;
uint32 index = 0 ;
2009-09-01 16:47:49 -05:00
if (( 1 << type ) & GLOBAL_CACHE_MASK )
{
2011-02-24 23:39:45 +06:00
id = GetAccountId ();
2012-01-01 01:09:38 +01:00
index = CHAR_REP_ACCOUNT_DATA ;
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
2011-02-24 23:39:45 +06:00
id = m_GUIDLow ;
2012-01-01 01:09:38 +01:00
index = CHAR_REP_PLAYER_ACCOUNT_DATA ;
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2011-02-24 23:39:45 +06:00
PreparedStatement * stmt = CharacterDatabase . GetPreparedStatement ( index );
stmt -> setUInt32 ( 0 , id );
stmt -> setUInt8 ( 1 , type );
stmt -> setUInt32 ( 2 , uint32 ( tm ));
stmt -> setString ( 3 , data );
CharacterDatabase . Execute ( stmt );
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-12-17 12:36:55 +01:00
void WorldSession :: SendAccountDataTimes ( uint32 mask )
2009-09-01 16:47:49 -05:00
{
2013-01-16 11:17:14 +01:00
WorldPacket data ( SMSG_ACCOUNT_DATA_TIMES , 4 + 1 + 4 + NUM_ACCOUNT_DATA_TYPES * 4 );
2011-11-27 04:02:59 +01:00
data << uint32 ( time ( NULL )); // Server time
2009-09-01 16:47:49 -05:00
data << uint8 ( 1 );
2009-12-17 12:36:55 +01:00
data << uint32 ( mask ); // type mask
2010-04-07 19:12:44 +02:00
for ( uint32 i = 0 ; i < NUM_ACCOUNT_DATA_TYPES ; ++ i )
2010-04-07 19:14:10 +02:00
if ( mask & ( 1 << i ))
2009-12-17 12:36:55 +01:00
data << uint32 ( GetAccountData ( AccountDataType ( i )) -> Time ); // also unix time
2009-09-01 16:47:49 -05:00
SendPacket ( & data );
2008-12-24 09:58:26 -06: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 ());
2011-04-26 11:56:21 +02:00
bool hasTutorials = ! CharacterDatabase . Query ( stmt ). null ();
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
2009-03-21 14:39:04 -06:00
void WorldSession :: ReadAddonsInfo ( WorldPacket & data )
{
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
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 ()
{
2010-01-16 01:59:26 +01:00
uint8 addonPublicKey [ 256 ] =
2009-03-21 14:39:04 -06:00
{
0xC3 , 0x5B , 0x50 , 0x84 , 0xB9 , 0x3E , 0x32 , 0x42 , 0x8C , 0xD0 , 0xC7 , 0x48 , 0xFA , 0x0E , 0x5D , 0x54 ,
0x5A , 0xA3 , 0x0E , 0x14 , 0xBA , 0x9E , 0x0D , 0xB9 , 0x5D , 0x8B , 0xEE , 0xB6 , 0x84 , 0x93 , 0x45 , 0x75 ,
0xFF , 0x31 , 0xFE , 0x2F , 0x64 , 0x3F , 0x3D , 0x6D , 0x07 , 0xD9 , 0x44 , 0x9B , 0x40 , 0x85 , 0x59 , 0x34 ,
0x4E , 0x10 , 0xE1 , 0xE7 , 0x43 , 0x69 , 0xEF , 0x7C , 0x16 , 0xFC , 0xB4 , 0xED , 0x1B , 0x95 , 0x28 , 0xA8 ,
0x23 , 0x76 , 0x51 , 0x31 , 0x57 , 0x30 , 0x2B , 0x79 , 0x08 , 0x50 , 0x10 , 0x1C , 0x4A , 0x1A , 0x2C , 0xC8 ,
0x8B , 0x8F , 0x05 , 0x2D , 0x22 , 0x3D , 0xDB , 0x5A , 0x24 , 0x7A , 0x0F , 0x13 , 0x50 , 0x37 , 0x8F , 0x5A ,
0xCC , 0x9E , 0x04 , 0x44 , 0x0E , 0x87 , 0x01 , 0xD4 , 0xA3 , 0x15 , 0x94 , 0x16 , 0x34 , 0xC6 , 0xC2 , 0xC3 ,
0xFB , 0x49 , 0xFE , 0xE1 , 0xF9 , 0xDA , 0x8C , 0x50 , 0x3C , 0xBE , 0x2C , 0xBB , 0x57 , 0xED , 0x46 , 0xB9 ,
0xAD , 0x8B , 0xC6 , 0xDF , 0x0E , 0xD6 , 0x0F , 0xBE , 0x80 , 0xB3 , 0x8B , 0x1E , 0x77 , 0xCF , 0xAD , 0x22 ,
0xCF , 0xB7 , 0x4B , 0xCF , 0xFB , 0xF0 , 0x6B , 0x11 , 0x45 , 0x2D , 0x7A , 0x81 , 0x18 , 0xF2 , 0x92 , 0x7E ,
0x98 , 0x56 , 0x5D , 0x5E , 0x69 , 0x72 , 0x0A , 0x0D , 0x03 , 0x0A , 0x85 , 0xA2 , 0x85 , 0x9C , 0xCB , 0xFB ,
0x56 , 0x6E , 0x8F , 0x44 , 0xBB , 0x8F , 0x02 , 0x22 , 0x68 , 0x63 , 0x97 , 0xBC , 0x85 , 0xBA , 0xA8 , 0xF7 ,
0xB5 , 0x40 , 0x68 , 0x3C , 0x77 , 0x86 , 0x6F , 0x4B , 0xD7 , 0x88 , 0xCA , 0x8A , 0xD7 , 0xCE , 0x36 , 0xF0 ,
0x45 , 0x6E , 0xD5 , 0x64 , 0x79 , 0x0F , 0x17 , 0xFC , 0x64 , 0xDD , 0x10 , 0x6F , 0xF3 , 0xF5 , 0xE0 , 0xA6 ,
0xC3 , 0xFB , 0x1B , 0x8C , 0x29 , 0xEF , 0x8E , 0xE5 , 0x34 , 0xCB , 0xD1 , 0x2A , 0xCE , 0x79 , 0xC3 , 0x9A ,
0x0D , 0x36 , 0xEA , 0x01 , 0xE0 , 0xAA , 0x91 , 0x20 , 0x54 , 0xF0 , 0x72 , 0xD8 , 0x1E , 0xC7 , 0x89 , 0xD2
};
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
WorldPacket data ( SMSG_ADDON_INFO , 4 );
2009-10-17 15:51:44 -07:00
2009-10-17 16:20:24 -07:00
for ( AddonsList :: iterator itr = m_addonsList . begin (); itr != m_addonsList . end (); ++ itr )
2009-03-21 14:39:04 -06:00
{
2010-01-15 19:50:27 +01:00
data << uint8 ( itr -> State );
2009-10-17 15:51:44 -07:00
2010-01-15 19:50:27 +01:00
uint8 crcpub = itr -> UsePublicKeyOrCRC ;
data << uint8 ( crcpub );
if ( crcpub )
2009-03-21 14:39:04 -06:00
{
2010-01-15 19:50:27 +01:00
uint8 usepk = ( itr -> CRC != STANDARD_ADDON_CRC ); // If addon is Standard addon CRC
data << uint8 ( usepk );
if ( usepk ) // if CRC is wrong, add public key (client need it)
{
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "misc" , "ADDON: CRC (0x%x) for addon %s is wrong (does not match expected 0x%x), sending pubkey" ,
2010-01-16 12:26:52 +01:00
itr -> CRC , itr -> Name . c_str (), STANDARD_ADDON_CRC );
2009-10-17 15:51:44 -07:00
2010-01-15 19:50:27 +01:00
data . append ( addonPublicKey , sizeof ( addonPublicKey ));
}
2013-03-08 21:41:30 +01:00
data << uint32 ( 0 ); /// @todo Find out the meaning of this.
2009-03-21 14:39:04 -06:00
}
2009-10-17 15:51:44 -07:00
2013-04-05 15:06:35 +02:00
data << uint8 ( 0 ); // uses URL
//if (usesURL)
// data << uint8(0); // URL
2009-03-21 14:39:04 -06:00
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
m_addonsList . clear ();
2009-10-17 15:51:44 -07:00
2013-04-05 15:06:35 +02:00
AddonMgr :: BannedAddonList const * bannedAddons = AddonMgr :: GetBannedAddons ();
data << uint32 ( bannedAddons -> size ());
for ( AddonMgr :: BannedAddonList :: const_iterator itr = bannedAddons -> begin (); itr != bannedAddons -> end (); ++ itr )
{
data << uint32 ( itr -> Id );
data . append ( itr -> NameMD5 , sizeof ( itr -> NameMD5 ));
data . append ( itr -> VersionMD5 , sizeof ( itr -> VersionMD5 ));
data << uint32 ( itr -> Timestamp );
data << uint32 ( 1 ); // IsBanned
}
2009-10-17 15:51:44 -07:00
2009-03-21 14:39:04 -06:00
SendPacket ( & data );
}
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 )
2009-09-01 16:47:49 -05:00
m_GUIDLow = _player -> GetGUIDLow ();
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
2011-06-22 18:03:07 +02:00
// initialized to NULL here.
_charCreateCallback . SetParam ( NULL );
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
//! HandleCharEnumOpcode
2011-06-22 14:20:42 +02:00
if ( _charEnumCallback . ready ())
2010-08-18 19:48:51 +02:00
{
2011-06-22 14:20:42 +02:00
_charEnumCallback . get ( result );
2010-08-18 19:48:51 +02:00
HandleCharEnum ( result );
2011-06-22 14:20:42 +02:00
_charEnumCallback . cancel ();
2010-08-18 19:48:51 +02:00
}
2011-06-22 14:20:42 +02:00
if ( _charCreateCallback . IsReady ())
{
2011-12-25 01:27:15 +01:00
_charCreateCallback . GetResult ( result );
HandleCharCreateCallback ( result , _charCreateCallback . GetParam ());
2011-06-22 14:20:42 +02:00
// Don't call FreeResult() here, the callback handler will do that depending on the events in the callback chain
}
2011-10-18 14:59:23 +02:00
2010-08-18 19:48:51 +02:00
//! HandlePlayerLoginOpcode
2011-06-22 14:20:42 +02:00
if ( _charLoginCallback . ready ())
2010-08-18 19:48:51 +02:00
{
SQLQueryHolder * param ;
2011-06-22 14:20:42 +02:00
_charLoginCallback . get ( param );
2010-08-18 19:48:51 +02:00
HandlePlayerLogin (( LoginQueryHolder * ) param );
2011-06-22 14:20:42 +02:00
_charLoginCallback . cancel ();
2010-08-18 19:48:51 +02:00
}
//! 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
std :: string param = _charRenameCallback . GetParam ();
_charRenameCallback . GetResult ( result );
2010-08-18 19:48:51 +02:00
HandleChangePlayerNameOpcodeCallBack ( result , param );
2011-06-22 14:20:42 +02:00
_charRenameCallback . FreeResult ();
2010-08-18 19:48:51 +02:00
}
2010-09-12 01:40:27 +02:00
2010-08-18 19:48:51 +02:00
//- HandleCharAddIgnoreOpcode
2011-06-22 14:20:42 +02:00
if ( _addIgnoreCallback . ready ())
2010-08-18 19:48:51 +02:00
{
2011-06-22 14:20:42 +02:00
_addIgnoreCallback . get ( result );
2010-08-18 19:48:51 +02:00
HandleAddIgnoreOpcodeCallBack ( result );
2011-06-22 14:20:42 +02:00
_addIgnoreCallback . cancel ();
2010-08-18 19:48:51 +02:00
}
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
{
2011-06-22 14:20:42 +02:00
uint64 param = _sendStabledPetCallback . GetParam ();
_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
2011-06-22 14:20:42 +02:00
if ( _stablePetCallback . ready ())
2010-08-25 21:03:28 +02:00
{
2011-06-22 14:20:42 +02:00
_stablePetCallback . get ( result );
2010-08-25 21:03:28 +02:00
HandleStablePetCallback ( result );
2011-06-22 14:20:42 +02:00
_stablePetCallback . cancel ();
2010-08-25 21:03:28 +02:00
}
//- 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
2013-09-27 13:25:48 +02:00
_RBACData = new rbac :: RBACData ( id , name , realmID , 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]" ,
2013-09-27 13:25:48 +02:00
id , name . c_str (), realmID , 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]" ,
2013-02-27 03:29:11 +01:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realmID );
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]" ,
2013-02-27 03:29:11 +01:00
_RBACData -> GetId (), _RBACData -> GetName (). c_str (), realmID );
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-05-24 22:04:03 +02:00
PacketCounter & packetCounter = _PacketThrottlingMap [ p . GetOpcode ()];
if ( packetCounter . lastReceiveTime != time )
{
packetCounter . lastReceiveTime = time ;
packetCounter . amountCounter = 0 ;
}
uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed ( p . GetOpcode ());
bool dosTriggered = false ;
// Check if player is flooding some packets
if ( ++ packetCounter . amountCounter > maxPacketCounterAllowed )
{
dosTriggered = true ;
2014-05-25 22:25:26 +02:00
TC_LOG_WARN ( "network" , "AntiDOS: Account %u, IP: %s, flooding packet (opc: %s (0x%X), count: %u)" ,
Session -> GetAccountId (), Session -> GetRemoteAddress (). c_str (), opcodeTable [ p . GetOpcode ()] -> Name , p . GetOpcode (), packetCounter . amountCounter );
2014-05-24 22:04:03 +02:00
}
// Then check if player is sending packets not allowed
if ( ! IsOpcodeAllowed ( p . GetOpcode ()))
{
dosTriggered = true ;
// Opcode not allowed, let the punishment begin
TC_LOG_WARN ( "network" , "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)" ,
Session -> GetAccountId (), Session -> GetRemoteAddress (). c_str (), p . GetOpcode (), ( uint32 ) p . size ());
}
2013-08-30 15:44:17 +01:00
2014-05-24 22:04:03 +02:00
// Return true if everything is fine, otherwise apply the configured policy
if ( ! dosTriggered )
return true ;
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-05-25 21:52:27 +02:00
case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND :
case CMSG_MESSAGECHAT_ADDON_GUILD :
case CMSG_MESSAGECHAT_ADDON_OFFICER :
case CMSG_MESSAGECHAT_ADDON_PARTY :
case CMSG_MESSAGECHAT_ADDON_RAID :
case CMSG_MESSAGECHAT_ADDON_WHISPER :
case CMSG_MESSAGECHAT_AFK :
case CMSG_MESSAGECHAT_BATTLEGROUND :
case CMSG_MESSAGECHAT_CHANNEL :
case CMSG_MESSAGECHAT_DND :
case CMSG_MESSAGECHAT_EMOTE :
case CMSG_MESSAGECHAT_GUILD :
case CMSG_MESSAGECHAT_OFFICER :
case CMSG_MESSAGECHAT_PARTY :
case CMSG_MESSAGECHAT_RAID :
case CMSG_MESSAGECHAT_RAID_WARNING :
case CMSG_MESSAGECHAT_SAY :
case CMSG_MESSAGECHAT_WHISPER :
case CMSG_MESSAGECHAT_YELL :
2014-05-25 20:14:59 +02:00
{
maxPacketCounterAllowed = 500 ;
break ;
}
case CMSG_ATTACKSTOP :
2014-05-24 22:04:03 +02:00
case CMSG_GUILD_QUERY :
case CMSG_NAME_QUERY :
case CMSG_PET_NAME_QUERY :
case CMSG_GAMEOBJECT_QUERY :
case CMSG_CREATURE_QUERY :
case CMSG_NPC_TEXT_QUERY :
case CMSG_ARENA_TEAM_QUERY :
case CMSG_TAXINODE_STATUS_QUERY :
case CMSG_TAXIQUERYAVAILABLENODES :
case CMSG_QUESTGIVER_QUERY_QUEST :
case CMSG_QUEST_QUERY :
case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY :
case CMSG_QUERY_QUESTS_COMPLETED :
case CMSG_QUEST_POI_QUERY :
case CMSG_QUERY_TIME :
case CMSG_PAGE_TEXT_QUERY :
case CMSG_PETITION_QUERY :
case CMSG_QUERY_INSPECT_ACHIEVEMENTS :
case CMSG_AREA_SPIRIT_HEALER_QUERY :
case CMSG_CORPSE_MAP_POSITION_QUERY :
case CMSG_MOVE_TIME_SKIPPED :
case CMSG_GUILD_BANK_QUERY_TAB :
2014-05-25 21:52:27 +02:00
case CMSG_GUILD_BANK_LOG_QUERY :
case CMSG_GUILD_EVENT_LOG_QUERY :
2014-05-24 22:04:03 +02:00
case MSG_CORPSE_QUERY :
case MSG_QUERY_NEXT_MAIL_TIME :
case MSG_MOVE_SET_FACING :
{
maxPacketCounterAllowed = 200 ;
break ;
}
2014-05-25 20:14:59 +02:00
case CMSG_REQUEST_PARTY_MEMBER_STATS :
case CMSG_WHO :
2014-05-25 15:26:49 +02:00
{
maxPacketCounterAllowed = 50 ;
break ;
}
2014-05-25 20:14:59 +02:00
case CMSG_SETSHEATHED :
2014-05-25 15:26:49 +02:00
case CMSG_CONTACT_LIST :
{
maxPacketCounterAllowed = 10 ;
break ;
}
2014-05-24 22:04:03 +02:00
case CMSG_GAMEOBJ_USE :
case CMSG_GAMEOBJ_REPORT_USE :
case CMSG_SPELLCLICK :
case CMSG_PLAYER_LOGOUT :
case CMSG_LOGOUT_REQUEST :
case CMSG_LOGOUT_CANCEL :
case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE :
case CMSG_REQUEST_VEHICLE_PREV_SEAT :
case CMSG_REQUEST_VEHICLE_NEXT_SEAT :
case CMSG_REQUEST_VEHICLE_SWITCH_SEAT :
case CMSG_TOGGLE_PVP :
case CMSG_ADD_FRIEND :
case CMSG_DEL_FRIEND :
case CMSG_SET_CONTACT_NOTES :
case CMSG_RESET_INSTANCES :
case CMSG_HEARTH_AND_RESURRECT :
case CMSG_CHAR_CREATE :
case CMSG_READY_FOR_ACCOUNT_DATA_TIMES :
case CMSG_CHAR_ENUM :
case CMSG_REALM_SPLIT :
case CMSG_CHAR_DELETE :
case CMSG_PLAYER_LOGIN :
case CMSG_PET_ABANDON :
case CMSG_PET_RENAME :
case CMSG_CHAR_RENAME :
case CMSG_CHAR_CUSTOMIZE :
case CMSG_CHAR_RACE_CHANGE :
case CMSG_CHAR_FACTION_CHANGE :
case CMSG_GMTICKET_CREATE :
case CMSG_GMTICKET_UPDATETEXT :
case CMSG_GMTICKET_DELETETICKET :
case CMSG_GMSURVEY_SUBMIT :
case CMSG_GM_REPORT_LAG :
case CMSG_BUG :
case CMSG_GMRESPONSE_RESOLVE :
case CMSG_ACTIVATETAXIEXPRESS :
case CMSG_ACTIVATETAXI :
case CMSG_SELF_RES :
case CMSG_INITIATE_TRADE :
case CMSG_BEGIN_TRADE :
case CMSG_UNLEARN_SKILL :
case CMSG_DISMISS_CONTROLLED_VEHICLE :
case CMSG_REQUEST_VEHICLE_EXIT :
case CMSG_LEARN_PREVIEW_TALENTS :
case CMSG_LEARN_PREVIEW_TALENTS_PET :
case CMSG_PLAYER_VEHICLE_ENTER :
2014-05-25 21:52:27 +02:00
case CMSG_EJECT_PASSENGER :
2014-05-24 22:04:03 +02:00
case CMSG_EQUIPMENT_SET_SAVE :
2014-05-25 21:52:27 +02:00
case CMSG_EQUIPMENT_SET_DELETE :
2014-05-24 22:04:03 +02:00
case CMSG_ALTER_APPEARANCE :
case CMSG_QUESTGIVER_ACCEPT_QUEST :
case CMSG_QUESTGIVER_CHOOSE_REWARD :
case CMSG_QUESTGIVER_REQUEST_REWARD :
2014-05-25 21:52:27 +02:00
//case CMSG_QUESTGIVER_CANCEL:
2014-05-24 22:04:03 +02:00
case CMSG_QUESTLOG_REMOVE_QUEST :
case CMSG_QUEST_CONFIRM_ACCEPT :
case CMSG_QUESTGIVER_COMPLETE_QUEST :
case CMSG_DISMISS_CRITTER :
case CMSG_REPOP_REQUEST :
case CMSG_PETITION_BUY :
case CMSG_PETITION_SIGN :
case CMSG_TURN_IN_PETITION :
case CMSG_COMPLETE_CINEMATIC :
case CMSG_ITEM_REFUND :
case CMSG_SOCKET_GEMS :
case CMSG_WRAP_ITEM :
case CMSG_BUY_BANK_SLOT :
2014-05-25 21:52:27 +02:00
case CMSG_GROUP_INVITE_RESPONSE :
//case CMSG_GROUP_UNINVITE:
2014-05-24 22:04:03 +02:00
case CMSG_GROUP_UNINVITE_GUID :
case CMSG_GROUP_SET_LEADER :
case CMSG_GROUP_DISBAND :
case CMSG_GROUP_RAID_CONVERT :
case CMSG_GROUP_CHANGE_SUB_GROUP :
case CMSG_GROUP_ASSISTANT_LEADER :
case CMSG_OPT_OUT_OF_LOOT :
case CMSG_BATTLEMASTER_JOIN_ARENA :
2014-05-25 21:52:27 +02:00
case CMSG_BATTLEFIELD_LEAVE :
2014-05-24 22:04:03 +02:00
case CMSG_REPORT_PVP_AFK :
case CMSG_DUEL_ACCEPTED :
case CMSG_DUEL_CANCELLED :
case CMSG_CALENDAR_GET_CALENDAR :
case CMSG_CALENDAR_ADD_EVENT :
case CMSG_CALENDAR_UPDATE_EVENT :
case CMSG_CALENDAR_REMOVE_EVENT :
case CMSG_CALENDAR_COPY_EVENT :
case CMSG_CALENDAR_EVENT_INVITE :
case CMSG_CALENDAR_EVENT_SIGNUP :
case CMSG_CALENDAR_EVENT_RSVP :
case CMSG_CALENDAR_EVENT_REMOVE_INVITE :
case CMSG_CALENDAR_EVENT_MODERATOR_STATUS :
case CMSG_CALENDAR_COMPLAIN :
case CMSG_ARENA_TEAM_INVITE :
case CMSG_ARENA_TEAM_ACCEPT :
case CMSG_ARENA_TEAM_DECLINE :
case CMSG_ARENA_TEAM_LEAVE :
case CMSG_ARENA_TEAM_DISBAND :
case CMSG_ARENA_TEAM_REMOVE :
case CMSG_ARENA_TEAM_LEADER :
case CMSG_LOOT_METHOD :
case CMSG_GUILD_INVITE :
case CMSG_GUILD_ACCEPT :
case CMSG_GUILD_DECLINE :
case CMSG_GUILD_LEAVE :
case CMSG_GUILD_DISBAND :
2014-05-25 21:52:27 +02:00
case CMSG_GUILD_SET_GUILD_MASTER :
2014-05-24 22:04:03 +02:00
case CMSG_GUILD_MOTD :
2014-05-25 21:52:27 +02:00
case SMSG_GUILD_NEWS_UPDATE :
case CMSG_GUILD_QUERY_RANKS :
2014-05-24 22:04:03 +02:00
case CMSG_GUILD_ADD_RANK :
case CMSG_GUILD_DEL_RANK :
case CMSG_GUILD_INFO_TEXT :
case CMSG_GUILD_BANK_DEPOSIT_MONEY :
case CMSG_GUILD_BANK_WITHDRAW_MONEY :
case CMSG_GUILD_BANK_BUY_TAB :
case CMSG_GUILD_BANK_UPDATE_TAB :
case CMSG_SET_GUILD_BANK_TEXT :
case MSG_SAVE_GUILD_EMBLEM :
case MSG_PETITION_RENAME :
case MSG_PETITION_DECLINE :
case MSG_TALENT_WIPE_CONFIRM :
case MSG_SET_DUNGEON_DIFFICULTY :
case MSG_SET_RAID_DIFFICULTY :
case MSG_RANDOM_ROLL :
case MSG_RAID_TARGET_UPDATE :
case MSG_PARTY_ASSIGNMENT :
case MSG_RAID_READY_CHECK :
{
maxPacketCounterAllowed = 3 ;
break ;
}
2014-05-25 15:26:49 +02:00
case CMSG_SET_ACTION_BUTTON :
{
maxPacketCounterAllowed = MAX_ACTION_BUTTONS ;
break ;
}
case CMSG_ITEM_REFUND_INFO :
{
maxPacketCounterAllowed = PLAYER_SLOTS_COUNT ;
break ;
}
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 ;
}