2010-10-07 15:35:36 +02:00
/*
2012-01-01 00:32:13 +01:00
* Copyright (C) 2008-2012 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>
2008-10-11 14:16:25 -05:00
#include "Common.h"
2010-06-08 17:01:03 -06:00
#include "DatabaseEnv.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"
2012-08-10 02:01:25 +01:00
#include <algorithm>
#include <vector>
#include <string>
2009-10-17 15:51:44 -07:00
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()
2011-11-20 18:28:18 +01:00
if ( opHandle -> packetProcessing == PROCESS_INPLACE )
2010-12-13 22:37:56 +01:00
return true ;
//we do not process thread-unsafe packets
2011-11-20 18:28:18 +01:00
if ( opHandle -> packetProcessing == 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
2011-11-20 18:28:18 +01:00
if ( opHandle -> packetProcessing == PROCESS_INPLACE )
2010-12-13 22:37:56 +01:00
return true ;
//thread-unsafe packets should be processed in World::UpdateSessions()
2011-11-20 18:28:18 +01:00
if ( opHandle -> packetProcessing == 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 ) :
2010-08-21 20:08:47 +02:00
m_muteTime ( mute_time ), m_timeOutTime ( 0 ), _player ( NULL ), m_Socket ( sock ),
_security ( sec ), _accountId ( id ), m_expansion ( expansion ), _logoutTime ( 0 ),
m_inQueue ( false ), m_playerLoading ( false ), m_playerLogout ( false ),
m_playerRecentlyLogout ( false ), m_playerSave ( false ),
2010-12-23 23:25:44 +01:00
m_sessionDbcLocale ( sWorld -> GetAvailableDbcLocale ( locale )),
2010-09-17 19:55:54 +02:00
m_sessionDbLocaleIndex ( locale ),
2011-08-03 09:28:12 -07:00
m_latency ( 0 ), m_TutorialsChanged ( false ), recruiterId ( recruiter ),
2012-01-06 19:36:17 +01:00
isRecruiter ( isARecruiter ), timeLastWhoCommand ( 0 )
2008-10-11 14:16:25 -05:00
{
2012-02-19 18:49:10 +01:00
_warden = NULL ;
2012-08-10 02:01:25 +01:00
_filterAddonMessages = false ;
2012-02-19 18:49:10 +01:00
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 )
{
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)" , z_res , zError ( z_res ));
2012-07-18 14:43:55 +02:00
return ;
}
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
2012-02-19 13:51:16 +01:00
if ( _warden )
delete _warden ;
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
{
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "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
return ;
}
delete _compressionStream ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2012-05-30 08:01:02 +02:00
void WorldSession :: SizeError ( WorldPacket const & packet , uint32 size ) const
2008-10-11 14:16:25 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt to crash server?), skipped" ,
2010-12-29 20:20:09 -08:00
GetAccountId (), LookupOpcodeName ( packet . GetOpcode ()), packet . GetOpcode (), packet . size (), size );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Get the player name
2011-09-15 14:08:17 +02:00
char const * WorldSession :: GetPlayerName () const
2008-10-11 14:16:25 -05:00
{
return GetPlayer () ? GetPlayer () -> GetName () : "<none>" ;
}
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
2011-11-27 20:49:07 +01:00
if ( packet -> GetOpcode () == NULL_OPCODE || packet -> GetOpcode () == UNKNOWN_OPCODE )
2011-11-20 18:28:18 +01:00
{
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Prevented sending of %s" , packet -> GetOpcode () == NULL_OPCODE ? "NULL_OPCODE" : "UNKNOWN_OPCODE" );
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
{
2012-08-03 18:54:37 +01:00
if ( ! opcodeTable [ packet -> GetOpcode ()])
{
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "Prevented sending disabled opcode %d (hex 0x%04X)" , packet -> GetOpcode (), packet -> GetOpcode ());
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 );
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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 ));
sLog -> outInfo ( LOG_FILTER_GENERAL , "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
{
2012-06-03 05:41:30 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "SESSION (account: %u, guidlow: %u, char: %s): received unexpected opcode %s (0x%.4X, status: %s) %s" ,
2011-02-27 18:34:24 +01:00
GetAccountId (), m_GUIDLow , _player ? _player -> GetName () : "<none>" ,
2011-02-17 19:47:08 +06:00
LookupOpcodeName ( packet -> GetOpcode ()), packet -> GetOpcode (), status , reason );
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
{
2012-06-03 05:41:30 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "SESSION: opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)" ,
2010-12-29 20:20:09 -08:00
LookupOpcodeName ( packet -> GetOpcode ()), packet -> GetOpcode (), uint32 ( packet -> rpos ()), uint32 ( packet -> wpos ()));
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.
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
{
2011-11-20 18:28:18 +01:00
const OpcodeHandler * opHandle = opcodeTable [ packet -> GetOpcode ()];
try
2008-10-11 14:16:25 -05:00
{
2011-11-20 18:28:18 +01:00
switch ( opHandle -> status )
2008-10-11 14:16:25 -05:00
{
2011-11-20 18:28:18 +01:00
case STATUS_LOGGEDIN :
if ( ! _player )
{
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
2011-12-27 10:05:49 +01:00
//! 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.
2011-11-20 18:28:18 +01:00
if ( ! m_playerRecentlyLogout )
2009-08-19 16:26:22 -05:00
{
2011-12-27 10:05:49 +01:00
//! Prevent infinite loop
if ( ! firstDelayedPacket )
firstDelayedPacket = packet ;
//! Because checking a bool is faster than reallocating memory
deletePacket = false ;
QueuePacket ( packet );
//! Log
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "Re-enqueueing packet with opcode %s (0x%.4X) with with status STATUS_LOGGEDIN. "
"Player is currently not in world yet." , opHandle -> name , packet -> GetOpcode ());
2009-08-19 16:26:22 -05:00
}
2011-11-20 18:28:18 +01:00
}
else if ( _player -> IsInWorld ())
{
2010-12-22 21:25:23 +01:00
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2011-11-20 18:28:18 +01:00
( this ->* opHandle -> handler )( * packet );
2012-08-03 14:20:18 +02:00
if ( sLog -> ShouldLog ( LOG_FILTER_NETWORKIO , LOG_LEVEL_TRACE ) && packet -> rpos () < packet -> wpos ())
2009-08-19 17:07:21 -05:00
LogUnprocessedTail ( packet );
2011-11-20 18:28:18 +01:00
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break ;
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT :
2012-05-30 08:01:02 +02:00
if ( ! _player && ! m_playerRecentlyLogout && ! m_playerLogout ) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
2011-11-20 18:28:18 +01:00
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 );
2012-08-07 13:44:22 -05:00
if ( sLog -> ShouldLog ( LOG_FILTER_NETWORKIO , LOG_LEVEL_TRACE ) && packet -> rpos () < packet -> wpos ())
2011-11-20 18:28:18 +01: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
{
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
( this ->* opHandle -> handler )( * packet );
2012-08-07 13:44:22 -05:00
if ( sLog -> ShouldLog ( LOG_FILTER_NETWORKIO , LOG_LEVEL_TRACE ) && packet -> rpos () < packet -> wpos ())
2011-11-20 18:28:18 +01:00
LogUnprocessedTail ( packet );
}
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 ;
2011-11-20 18:28:18 +01:00
}
2012-05-30 08:01:02 +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 )
2011-11-20 18:28:18 +01:00
m_playerRecentlyLogout = false ;
sScriptMgr -> OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
( this ->* opHandle -> handler )( * packet );
2012-08-07 13:44:22 -05:00
if ( sLog -> ShouldLog ( LOG_FILTER_NETWORKIO , LOG_LEVEL_TRACE ) && packet -> rpos () < packet -> wpos ())
2011-11-20 18:28:18 +01:00
LogUnprocessedTail ( packet );
break ;
case STATUS_NEVER :
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "SESSION (account: %u, guidlow: %u, char: %s): received not allowed opcode %s (0x%.4X)" ,
2011-11-20 18:28:18 +01:00
GetAccountId (), m_GUIDLow , _player ? _player -> GetName () : "<none>" ,
LookupOpcodeName ( packet -> GetOpcode ()), packet -> GetOpcode ());
break ;
case STATUS_UNHANDLED :
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "SESSION (account: %u, guidlow: %u, char: %s): received not handled opcode %s (0x%.4X)" ,
GetAccountId (), m_GUIDLow , _player ? _player -> GetName () : "<none>" ,
LookupOpcodeName ( packet -> GetOpcode ()), packet -> GetOpcode ());
break ;
2009-08-19 16:26:22 -05:00
}
2011-11-20 18:28:18 +01:00
}
catch ( ByteBufferException & )
{
2012-08-07 13:44:22 -05:00
sLog -> outError ( LOG_FILTER_NETWORKIO , "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet." ,
2011-11-20 18:28:18 +01:00
packet -> GetOpcode (), GetRemoteAddress (). c_str (), GetAccountId ());
2012-08-07 13:44:22 -05:00
if ( sLog -> ShouldLog ( LOG_FILTER_NETWORKIO , LOG_LEVEL_TRACE ))
2009-08-19 16:26:22 -05:00
{
2012-08-03 14:20:18 +02:00
sLog -> outTrace ( LOG_FILTER_NETWORKIO , "Dumping error causing packet:" );
2011-11-20 18:28:18 +01:00
packet -> hexlike ();
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2011-12-16 15:36:03 +01:00
if ( deletePacket )
delete packet ;
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
void WorldSession :: LogoutPlayer ( bool Save )
{
// 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 ;
2009-12-17 07:56:20 +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 ();
}
else if ( ! _player -> getAttackers (). empty ())
{
_player -> CombatStop ();
2010-03-09 11:11:10 +01:00
_player -> getHostileRefManager (). setOnlineOfflineState ( false );
2008-10-11 14:16:25 -05:00
_player -> RemoveAllAurasOnDeath ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// build set of player who attack _player or who have pet attacking of _player
2011-09-15 14:08:17 +02:00
std :: set < Player *> aset ;
2009-10-17 16:20:24 -07:00
for ( Unit :: AttackerSet :: const_iterator itr = _player -> getAttackers (). begin (); itr != _player -> getAttackers (). end (); ++ itr )
2008-10-11 14:16:25 -05:00
{
2011-09-15 14:08:17 +02:00
Unit * owner = ( * itr ) -> GetOwner (); // including player controlled case
2010-12-29 20:20:09 -08:00
if ( owner && owner -> GetTypeId () == TYPEID_PLAYER )
aset . insert ( owner -> ToPlayer ());
else if (( * itr ) -> GetTypeId () == TYPEID_PLAYER )
2008-10-11 14:16:25 -05:00
aset . insert (( Player * )( * itr ));
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
_player -> SetPvPDeath ( ! aset . empty ());
_player -> KillPlayer ();
_player -> BuildPlayerRepop ();
_player -> RepopAtGraveyard ();
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// give honor to all attackers from set like group case
2011-09-15 14:08:17 +02:00
for ( std :: set < Player *>:: const_iterator itr = aset . begin (); itr != aset . end (); ++ itr )
2010-12-29 20:20:09 -08:00
( * itr ) -> RewardHonor ( _player , aset . size ());
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
// give bg rewards and update counters like kill by first from attackers
// this can't be called for all attackers.
2010-04-07 19:14:10 +02:00
if ( ! aset . empty ())
2011-09-15 14:08:17 +02:00
if ( Battleground * bg = _player -> GetBattleground ())
2010-12-29 20:20:09 -08:00
bg -> HandleKillPlayer ( _player , * aset . begin ());
2008-10-11 14:16:25 -05:00
}
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
2010-04-07 19:14:10 +02:00
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 );
2010-12-22 21:25:23 +01:00
sBattlegroundMgr -> m_BattlegroundQueues [ bgQueueTypeId ]. 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
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)
2010-04-07 19:14:10 +02: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 ();
2012-08-06 12:10:33 +02:00
sLog -> outInfo ( LOG_FILTER_CHARACTER , "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d" , GetAccountId (), GetRemoteAddress (). c_str (), _player -> GetName (), _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 );
2012-05-30 08:01:02 +02:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "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 ;
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SESSION: received unhandled opcode %s (0x%.4X)" ,
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SESSION: received opcode %s (0x%.4X) that must be processed in WorldSocket::OnRead" ,
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SESSION: received server-side opcode %s (0x%.4X)" ,
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "SESSION: received deprecated opcode %s (0x%.4X)" ,
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
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 )
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "Table `%s` have invalid account data type (%u), ignore." ,
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "Table `%s` have non appropriate for table account data type (%u), ignore." ,
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
2011-02-24 23:39:45 +06:00
void WorldSession :: SetAccountData ( AccountDataType type , time_t tm , std :: string 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
{
2011-11-27 04:02:59 +01:00
WorldPacket data ( SMSG_ACCOUNT_DATA_TIMES , 4 + 1 + 4 + NUM_ACCOUNT_DATA_TYPES * 4 );
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
{
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "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
2012-05-30 08:01:02 +02:00
if ( uncompress ( const_cast < uint8 *> ( addonInfo . contents ()), & uSize , const_cast < uint8 *> ( 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
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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 )
{
bool match = true ;
if ( addon . CRC != savedAddon -> CRC )
match = false ;
if ( ! match )
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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
2010-01-15 19:50:27 +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 ;
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "ADDON: CurrentTime: %u" , currentTime );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( addonInfo . rpos () != addonInfo . size ())
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_NETWORKIO , "packet under-read!" );
2009-03-21 14:39:04 -06:00
}
else
2012-08-03 14:20:18 +02:00
sLog -> outError ( LOG_FILTER_GENERAL , "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)
{
2012-08-03 14:20:18 +02:00
sLog -> outInfo ( LOG_FILTER_GENERAL , "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 ));
}
2010-12-29 20:20:09 -08: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
2009-05-21 03:15:15 +02:00
uint8 unk3 = 0 ; // 0 is sent here
2009-03-21 14:39:04 -06:00
data << uint8 ( unk3 );
if ( unk3 )
{
2010-01-15 19:50:27 +01:00
// String, length 256 (null terminated)
2009-03-21 14:39:04 -06:00
data << uint8 ( 0 );
}
}
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
2010-12-29 20:20:09 -08:00
data << uint32 ( 0 ); // count for an unknown for loop
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 ;
std :: vector < std :: string >:: iterator itr = std :: find ( _registeredAddonPrefixes . begin (), _registeredAddonPrefixes . end (), prefix );
return itr != _registeredAddonPrefixes . end ();
}
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
void WorldSession :: InitWarden ( BigNumber * k , std :: string os )
{
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);
}
}