2008-10-11 14:16:25 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2010-01-16 20:19:18 +03:00
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
2008-10-11 14:16:25 -05:00
*
* 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
2008-11-06 16:10:28 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-11 14:16:25 -05:00
* 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, write to the Free Software
2008-11-06 16:10:28 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
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"
#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-05-31 20:25:21 +02:00
#include "LFGMgr.h"
2010-07-30 21:54:46 -07:00
#include "Transport.h"
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// WorldSession constructor
2010-08-17 19:18:09 -07:00
WorldSession :: WorldSession ( uint32 id , WorldSocket * sock , AccountTypes sec , uint8 expansion , time_t mute_time , LocaleConstant locale , uint32 recruiter ) :
2010-08-11 13:25:14 +02:00
m_muteTime ( mute_time ), _player ( NULL ), m_Socket ( sock ), _security ( sec ), _accountId ( id ), m_expansion ( expansion ),
2010-08-08 05:25:45 +02:00
m_sessionDbcLocale ( sWorld . GetAvailableDbcLocale ( locale )), m_sessionDbLocaleIndex ( sObjectMgr . GetIndexForLocale ( locale )),
2009-12-17 07:56:20 +01:00
_logoutTime ( 0 ), m_inQueue ( false ), m_playerLoading ( false ), m_playerLogout ( false ), m_playerRecentlyLogout ( false ), m_playerSave ( false ),
2010-08-17 19:18:09 -07:00
m_latency ( 0 ), m_TutorialsChanged ( false ), m_timeOutTime ( 0 ), recruiterId ( recruiter )
2008-10-11 14:16:25 -05: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 ();
2010-05-08 05:03:32 +02:00
LoginDatabase . PExecute ( "UPDATE account SET online = 1 WHERE id = %u;" , GetAccountId ());
2008-11-06 16:10:28 -06:00
}
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
{
2008-11-06 16:10:28 -06:00
m_Socket -> CloseSocket ();
m_Socket -> RemoveReference ();
m_Socket = NULL ;
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- empty incoming packet queue
2009-09-11 13:42:39 -07:00
WorldPacket * packet ;
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
2010-05-08 05:03:32 +02:00
LoginDatabase . PExecute ( "UPDATE account SET online = 0 WHERE id = %u;" , GetAccountId ());
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 :: SizeError ( WorldPacket const & packet , uint32 size ) const
{
2009-07-12 17:52:27 +08:00
sLog . outError ( "Client (account %u) send packet %s (%u) with size " SIZEFMTD " but expected %u (attempt crash server?), skipped" ,
2008-10-11 14:16:25 -05:00
GetAccountId (), LookupOpcodeName ( packet . GetOpcode ()), packet . GetOpcode (), packet . size (), size );
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Get the player name
char const * WorldSession :: GetPlayerName () const
{
return GetPlayer () ? GetPlayer () -> GetName () : "<none>" ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
/// Send a packet to the client
void WorldSession :: SendPacket ( WorldPacket const * packet )
{
if ( ! m_Socket )
return ;
2009-10-17 15:51:44 -07:00
2008-10-14 11:57:03 -05:00
#ifdef TRINITY_DEBUG
2009-10-17 15:51:44 -07:00
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 );
2009-05-31 16:15:12 -05:00
sLog . outDetail ( "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 . outDetail ( "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
}
2009-10-17 15:51:44 -07:00
2009-05-04 13:13:07 -05:00
#endif // !TRINITY_DEBUG
2009-10-17 15:51:44 -07:00
2008-11-06 16:10:28 -06: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
void WorldSession :: QueuePacket ( WorldPacket * new_packet )
{
_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
2009-08-19 17:07:21 -05:00
void WorldSession :: LogUnexpectedOpcode ( WorldPacket * packet , const char * reason )
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received unexpected opcode %s (0x%.4X) %s" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( packet -> GetOpcode ()),
packet -> GetOpcode (),
reason );
}
2009-10-17 15:51:44 -07:00
2009-08-19 17:07:21 -05:00
/// Logging helper for unexpected opcodes
void WorldSession :: LogUnprocessedTail ( WorldPacket * packet )
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)" ,
2009-08-19 17:07:21 -05:00
LookupOpcodeName ( packet -> GetOpcode ()),
packet -> GetOpcode (),
packet -> rpos (), packet -> wpos ());
2009-10-17 16:20:24 -07:00
2009-10-11 21:11:59 +02: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-05-16 03:42:05 +02:00
bool WorldSession :: Update ( uint32 diff )
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
2008-12-12 11:21:28 -06:00
/// not proccess packets if socket already closed
2009-09-11 13:42:39 -07:00
WorldPacket * packet ;
2010-04-12 14:24:10 +02:00
while ( m_Socket && ! m_Socket -> IsClosed () && _recvQueue . next ( packet ))
2008-10-11 14:16:25 -05:00
{
/*#if 1
2010-04-07 22:59:46 +02:00
sLog.outError("MOEP: %s (0x%.4X)",
2008-10-11 14:16:25 -05:00
LookupOpcodeName(packet->GetOpcode()),
packet->GetOpcode());
#endif*/
2010-04-29 23:12:16 +02:00
2010-04-07 19:14:10 +02:00
if ( packet -> GetOpcode () >= NUM_MSG_TYPES )
2008-10-11 14:16:25 -05:00
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received non-existed opcode %s (0x%.4X)" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( packet -> GetOpcode ()),
packet -> GetOpcode ());
2010-08-06 19:23:43 +02:00
sScriptMgr . OnUnknownPacketReceive ( m_Socket , WorldPacket ( * packet ));
2008-10-11 14:16:25 -05:00
}
else
{
OpcodeHandler & opHandle = opcodeTable [ packet -> GetOpcode ()];
2009-08-19 16:26:22 -05:00
try
2008-10-11 14:16:25 -05:00
{
2009-08-19 16:26:22 -05:00
switch ( opHandle . status )
{
case STATUS_LOGGEDIN :
2010-04-07 19:14:10 +02:00
if ( ! _player )
2009-08-19 16:26:22 -05:00
{
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
2010-04-07 19:14:10 +02:00
if ( ! m_playerRecentlyLogout )
2009-08-19 17:07:21 -05:00
LogUnexpectedOpcode ( packet , "the player has not logged in yet" );
2009-08-19 16:26:22 -05:00
}
2010-04-07 19:14:10 +02:00
else if ( _player -> IsInWorld ())
2009-08-19 17:07:21 -05:00
{
2010-08-06 19:23:43 +02:00
sScriptMgr . OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2009-08-19 16:26:22 -05:00
( this ->* opHandle . handler )( * packet );
2009-08-19 17:07:21 -05:00
if ( sLog . IsOutDebug () && packet -> rpos () < packet -> wpos ())
LogUnprocessedTail ( packet );
}
2009-08-19 16:26:22 -05:00
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break ;
2009-09-01 16:47:49 -05:00
case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT :
2010-04-07 19:14:10 +02:00
if ( ! _player && ! m_playerRecentlyLogout )
2009-09-01 16:47:49 -05:00
{
LogUnexpectedOpcode ( packet , "the player has not logged in yet and not recently logout" );
}
else
{
// not expected _player or must checked in packet hanlder
2010-08-06 19:23:43 +02:00
sScriptMgr . OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2009-09-01 16:47:49 -05:00
( this ->* opHandle . handler )( * packet );
if ( sLog . IsOutDebug () && packet -> rpos () < packet -> wpos ())
LogUnprocessedTail ( packet );
}
break ;
2009-08-19 16:26:22 -05:00
case STATUS_TRANSFER :
2010-04-07 19:14:10 +02:00
if ( ! _player )
2009-08-19 17:07:21 -05:00
LogUnexpectedOpcode ( packet , "the player has not logged in yet" );
2010-04-07 19:14:10 +02:00
else if ( _player -> IsInWorld ())
2009-08-19 17:07:21 -05:00
LogUnexpectedOpcode ( packet , "the player is still in world" );
2009-08-19 16:26:22 -05:00
else
2009-08-19 17:07:21 -05:00
{
2010-08-06 19:23:43 +02:00
sScriptMgr . OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2009-08-19 16:26:22 -05:00
( this ->* opHandle . handler )( * packet );
2009-08-19 17:07:21 -05:00
if ( sLog . IsOutDebug () && packet -> rpos () < packet -> wpos ())
LogUnprocessedTail ( packet );
}
2009-08-19 16:26:22 -05:00
break ;
case STATUS_AUTHED :
// prevent cheating with skip queue wait
2010-04-07 19:14:10 +02:00
if ( m_inQueue )
2009-08-19 16:26:22 -05:00
{
2009-08-19 17:07:21 -05:00
LogUnexpectedOpcode ( packet , "the player not pass queue yet" );
2009-08-19 16:26:22 -05:00
break ;
}
2009-10-17 15:51:44 -07:00
2009-09-01 16:56:02 -05:00
// single from authed time opcodes send in to after logout time
// and before other STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes.
if ( packet -> GetOpcode () != CMSG_SET_ACTIVE_VOICE_CHANNEL )
m_playerRecentlyLogout = false ;
2010-08-08 19:45:53 +02:00
2010-08-06 19:23:43 +02:00
sScriptMgr . OnPacketReceive ( m_Socket , WorldPacket ( * packet ));
2008-10-11 14:16:25 -05:00
( this ->* opHandle . handler )( * packet );
2009-08-19 17:07:21 -05:00
if ( sLog . IsOutDebug () && packet -> rpos () < packet -> wpos ())
LogUnprocessedTail ( packet );
2008-11-30 12:47:26 -06:00
break ;
2009-08-19 16:26:22 -05:00
case STATUS_NEVER :
2010-04-19 09:26:37 +02:00
/*
2010-04-07 22:59:46 +02:00
sLog.outError("SESSION: received not allowed opcode %s (0x%.4X)",
2009-08-19 16:26:22 -05:00
LookupOpcodeName(packet->GetOpcode()),
packet->GetOpcode());
2010-04-19 09:26:37 +02:00
*/
2009-08-19 16:26:22 -05:00
break ;
}
}
2009-08-19 17:07:21 -05:00
catch ( ByteBufferException & )
2009-08-19 16:26:22 -05:00
{
sLog . outError ( "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet." ,
packet -> GetOpcode (), GetRemoteAddress (). c_str (), GetAccountId ());
2010-04-07 19:14:10 +02:00
if ( sLog . IsOutDebug ())
2009-08-19 16:26:22 -05:00
{
sLog . outDebug ( "Dumping error causing packet:" );
packet -> hexlike ();
}
2008-10-11 14:16:25 -05:00
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
delete packet ;
}
2009-10-17 15:51:44 -07:00
2010-08-18 19:48:51 +02:00
ProcessQueryCallbacks ();
2010-05-16 03:42:05 +02: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
2008-12-12 11:21:28 -06:00
///- Cleanup socket pointer if need
2010-05-05 22:56:02 +02:00
if ( m_Socket && m_Socket -> IsClosed ())
2008-12-12 11:21:28 -06:00
{
2010-05-05 22:56:02 +02:00
m_Socket -> RemoveReference ();
2008-12-12 11:21:28 -06:00
m_Socket = NULL ;
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
if ( ! m_Socket )
return false ; //Will remove this session from the world session map
2009-10-17 15:51:44 -07: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 )
{
2010-05-31 20:25:21 +02:00
sLFGMgr . Leave ( _player );
GetPlayer () -> GetSession () -> SendLfgUpdateParty ( LFG_UPDATETYPE_REMOVED_FROM_QUEUE );
GetPlayer () -> GetSession () -> SendLfgUpdatePlayer ( LFG_UPDATETYPE_REMOVED_FROM_QUEUE );
GetPlayer () -> GetSession () -> SendLfgUpdateSearch ( false );
2008-10-21 13:19:26 -05:00
if ( uint64 lguid = GetPlayer () -> GetLootGUID ())
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
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
{
Unit * owner = ( * itr ) -> GetOwner (); // including player controlled case
2010-04-07 19:14:10 +02:00
if ( owner )
2008-10-11 14:16:25 -05:00
{
2010-04-07 19:14:10 +02:00
if ( owner -> GetTypeId () == TYPEID_PLAYER )
2010-04-07 17:24:07 +02:00
aset . insert ( owner -> ToPlayer ());
2008-10-11 14:16:25 -05:00
}
else
2010-04-07 19:14:10 +02:00
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
2009-10-17 16:20:24 -07:00
for ( std :: set < Player *>:: const_iterator itr = aset . begin (); itr != aset . end (); ++ itr )
2008-11-06 16:10:28 -06: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 ())
2010-08-08 04:37:24 +02:00
if ( Battleground * bg = _player -> GetBattleground ())
2008-10-11 14:16:25 -05:00
bg -> HandleKillPlayer ( _player , * aset . begin ());
}
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->SetDeathPvP(*); set at SPELL_AURA_SPIRIT_OF_REDEMPTION apply time
_player -> KillPlayer ();
_player -> BuildPlayerRepop ();
_player -> RepopAtGraveyard ();
}
2009-03-02 16:46:43 -06:00
//drop a flag if player is carrying it
2010-08-08 04:37:24 +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
2008-10-14 11:57:03 -05: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 );
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
2010-08-08 05:25:45 +02:00
Guild * guild = sObjectMgr . GetGuildById ( _player -> GetGuildId ());
2010-04-07 19:14:10 +02:00
if ( guild )
2008-10-11 14:16:25 -05:00
{
2009-08-24 20:23:54 -05:00
guild -> SetMemberStats ( _player -> GetGUID ());
2008-10-11 14:16:25 -05:00
guild -> UpdateLogoutTime ( _player -> GetGUID ());
2009-10-17 15:51:44 -07:00
2010-04-11 11:06:51 +04:00
guild -> BroadcastEvent ( GE_SIGNED_OFF , _player -> GetGUID (), 1 , _player -> GetName (), "" , "" );
2008-10-11 14:16:25 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- Remove pet
_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
2010-05-21 22:45:47 +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
2008-10-11 14:16:25 -05:00
///- Broadcast a logout message to the player's friends
2008-11-05 20:10:19 -06:00
sSocialMgr . SendFriendStatus ( _player , FRIEND_OFFLINE , _player -> GetGUIDLow (), true );
2009-06-17 19:02:38 -05:00
sSocialMgr . RemovePlayerSocial ( _player -> GetGUIDLow ());
2009-10-17 15:51:44 -07:00
2009-06-17 19:02:38 -05:00
///- Remove the player from the world
// 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 ();
2010-05-15 01:26:28 +02:00
sLog . outChar ( "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u)" , GetAccountId (), GetRemoteAddress (). c_str (), _player -> GetName () , _player -> GetGUIDLow ());
2009-07-16 11:49:00 +08:00
Map * _map = _player -> GetMap ();
_map -> Remove ( _player , true );
2009-09-01 16:47:49 -05:00
SetPlayer ( NULL ); // deleted in Remove call
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- Send the 'logout complete' packet to the client
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_LOGOUT_COMPLETE , 0 );
SendPacket ( & data );
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
//No SQL injection as AccountId is uint32
2008-11-02 16:53:46 -06:00
CharacterDatabase . PExecute ( "UPDATE characters SET online = 0 WHERE account = '%u'" ,
2008-11-06 16:10:28 -06:00
GetAccountId ());
2010-04-07 22:59:46 +02:00
sLog . outDebug ( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" );
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 )
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
void WorldSession :: SendNotification ( const char * format ,...)
{
2010-04-07 19:14:10 +02:00
if ( format )
2008-10-11 14:16:25 -05:00
{
va_list ap ;
char szStr [ 1024 ];
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
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_NOTIFICATION , ( strlen ( szStr ) + 1 ));
data << szStr ;
SendPacket ( & data );
}
}
2009-10-17 15:51:44 -07:00
2008-10-11 14:16:25 -05:00
void WorldSession :: SendNotification ( int32 string_id ,...)
{
2008-10-14 11:57:03 -05: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 ;
char szStr [ 1024 ];
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
2008-10-11 14:16:25 -05:00
WorldPacket data ( SMSG_NOTIFICATION , ( strlen ( szStr ) + 1 ));
data << szStr ;
SendPacket ( & data );
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 22:59:46 +02:00
const char * WorldSession :: GetTrinityString ( int32 entry ) const
2008-10-11 14:16:25 -05:00
{
2010-08-08 05:25:45 +02: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
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received unhandled opcode %s (0x%.4X)" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
}
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
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received opcode %s (0x%.4X) that must be processed in WorldSocket::OnRead" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
}
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
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received server-side opcode %s (0x%.4X)" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
}
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
{
2010-04-07 22:59:46 +02:00
sLog . outError ( "SESSION: received deprecated opcode %s (0x%.4X)" ,
2008-10-11 14:16:25 -05:00
LookupOpcodeName ( recvPacket . GetOpcode ()),
recvPacket . GetOpcode ());
}
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 );
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 );
2010-04-07 22:59:46 +02:00
packet << uint8 ( AUTH_WAIT_QUEUE );
2010-04-28 08:55:07 +02:00
packet << uint32 ( position );
packet << uint8 ( 0 ); // unk
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
{
2009-09-01 16:47:49 -05:00
LoadAccountData (
CharacterDatabase . PQuery ( "SELECT type, time, data FROM account_data WHERE account='%u'" , GetAccountId ()),
GLOBAL_CACHE_MASK
2010-04-07 22:59:46 +02:00
);
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2010-01-23 14:45:58 +01:00
void WorldSession :: LoadAccountData ( QueryResult_AutoPtr 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
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
uint32 type = fields [ 0 ]. GetUInt32 ();
2009-09-01 16:47:49 -05:00
if ( type >= NUM_ACCOUNT_DATA_TYPES )
{
sLog . outError ( "Table `%s` have invalid account data type (%u), ignore." ,
2009-09-18 14:10:37 -07: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
{
2009-09-01 16:47:49 -05:00
sLog . outError ( "Table `%s` have non appropriate for table account data type (%u), ignore." ,
2009-09-18 14:10:37 -07: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
2009-09-01 16:47:49 -05:00
m_accountData [ type ]. Time = fields [ 1 ]. GetUInt32 ();
m_accountData [ type ]. Data = fields [ 2 ]. GetCppString ();
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
} while ( result -> NextRow ());
}
2009-10-17 15:51:44 -07:00
2009-09-01 16:47:49 -05:00
void WorldSession :: SetAccountData ( AccountDataType type , time_t time_ , std :: string data )
2008-12-24 09:58:26 -06:00
{
2009-09-01 16:47:49 -05:00
if (( 1 << type ) & GLOBAL_CACHE_MASK )
{
uint32 acc = GetAccountId ();
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM account_data WHERE account='%u' AND type='%u'" , acc , type );
2009-09-01 16:47:49 -05:00
CharacterDatabase . escape_string ( data );
2010-08-21 03:19:25 +02:00
trans -> PAppend ( "INSERT INTO account_data VALUES ('%u','%u','%u','%s')" , acc , type , ( uint32 ) time_ , data . c_str ());
CharacterDatabase . CommitTransaction ( trans );
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
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
trans -> PAppend ( "DELETE FROM character_account_data WHERE guid='%u' AND type='%u'" , m_GUIDLow , type );
2009-09-01 16:47:49 -05:00
CharacterDatabase . escape_string ( data );
2010-08-21 03:19:25 +02:00
trans -> PAppend ( "INSERT INTO character_account_data VALUES ('%u','%u','%u','%s')" , m_GUIDLow , type , ( uint32 ) time_ , data . c_str ());
CharacterDatabase . CommitTransaction ( trans );
2009-09-01 16:47:49 -05:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
m_accountData [ type ]. Time = time_ ;
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
{
2010-04-07 22:59:46 +02:00
WorldPacket data ( SMSG_ACCOUNT_DATA_TIMES , 4 + 1 + 4 + 8 * 4 ); // changed in WotLK
2009-12-24 10:20:15 +01:00
data << uint32 ( time ( NULL )); // unix time of something
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 ()
{
2010-04-07 22:59:46 +02:00
for ( int aX = 0 ; aX < 8 ; ++ aX )
2009-06-11 00:45:59 -05:00
m_Tutorials [ aX ] = 0 ;
2009-10-17 15:51:44 -07:00
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = CharacterDatabase . PQuery ( "SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u'" , GetAccountId ());
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( result )
2009-06-11 00:45:59 -05:00
{
do
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
for ( int iI = 0 ; iI < 8 ; ++ iI )
m_Tutorials [ iI ] = fields [ iI ]. GetUInt32 ();
}
2010-04-07 22:59:46 +02:00
while ( result -> NextRow ());
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 ()
{
WorldPacket data ( SMSG_TUTORIAL_FLAGS , 4 * 8 );
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < 8 ; ++ i )
2009-06-11 00:45:59 -05:00
data << m_Tutorials [ i ];
SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02: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
2009-06-11 00:45:59 -05:00
uint32 Rows = 0 ;
// it's better than rebuilding indexes multiple times
2010-01-23 14:45:58 +01:00
QueryResult_AutoPtr result = CharacterDatabase . PQuery ( "SELECT count(*) AS r FROM character_tutorial WHERE account = '%u'" , GetAccountId ());
2010-04-07 19:14:10 +02:00
if ( result )
2009-06-11 00:45:59 -05:00
Rows = result -> Fetch ()[ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-06-11 00:45:59 -05:00
if ( Rows )
2010-08-21 03:19:25 +02:00
trans -> PAppend ( "UPDATE character_tutorial SET tut0='%u', tut1='%u', tut2='%u', tut3='%u', tut4='%u', tut5='%u', tut6='%u', tut7='%u' WHERE account = '%u'" ,
2009-06-11 00:45:59 -05:00
m_Tutorials [ 0 ], m_Tutorials [ 1 ], m_Tutorials [ 2 ], m_Tutorials [ 3 ], m_Tutorials [ 4 ], m_Tutorials [ 5 ], m_Tutorials [ 6 ], m_Tutorials [ 7 ], GetAccountId ());
else
2010-08-21 03:19:25 +02:00
trans -> PAppend ( "INSERT INTO character_tutorial (account,tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7) VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')" , GetAccountId (), m_Tutorials [ 0 ], m_Tutorials [ 1 ], m_Tutorials [ 2 ], m_Tutorials [ 3 ], m_Tutorials [ 4 ], m_Tutorials [ 5 ], m_Tutorials [ 6 ], m_Tutorials [ 7 ]);
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
2008-12-24 09:58:26 -06:00
void WorldSession :: ReadMovementInfo ( WorldPacket & data , MovementInfo * mi )
{
data >> mi -> flags ;
2010-08-04 14:39:45 +02:00
data >> mi -> flags2 ;
2008-12-24 09:58:26 -06:00
data >> mi -> time ;
2010-08-04 14:39:45 +02:00
data >> mi -> pos . PositionXYZOStream ();
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( mi -> flags & MOVEMENTFLAG_ONTRANSPORT )
2008-12-24 09:58:26 -06:00
{
2010-08-08 20:32:14 +02:00
data . readPackGUID ( mi -> t_guid );
2009-10-17 15:51:44 -07:00
2010-08-04 14:39:45 +02:00
data >> mi -> t_pos . PositionXYZOStream ();
2008-12-24 09:58:26 -06:00
data >> mi -> t_time ;
data >> mi -> t_seat ;
2010-07-30 21:54:46 -07:00
2010-08-04 14:39:45 +02:00
if ( mi -> flags2 & MOVEMENTFLAG2_INTERPOLATED_MOVEMENT )
{
data >> mi -> t_time2 ;
}
if ( mi -> pos . m_positionX != mi -> t_pos . m_positionX )
2010-07-30 21:54:46 -07:00
if ( GetPlayer () -> GetTransport ())
GetPlayer () -> GetTransport () -> UpdatePosition ( mi );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2010-08-04 14:39:45 +02:00
if (( mi -> flags & ( MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING )) || ( mi -> flags2 & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING ))
2008-12-24 09:58:26 -06:00
{
2010-08-04 14:39:45 +02:00
data >> mi -> pitch ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
data >> mi -> fallTime ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( mi -> flags & MOVEMENTFLAG_JUMPING )
2008-12-24 09:58:26 -06:00
{
2009-04-22 17:50:26 -05:00
data >> mi -> j_zspeed ;
2008-12-24 09:58:26 -06:00
data >> mi -> j_sinAngle ;
data >> mi -> j_cosAngle ;
data >> mi -> j_xyspeed ;
}
2009-10-17 15:51:44 -07:00
2010-08-04 14:39:45 +02:00
if ( mi -> flags & MOVEMENTFLAG_SPLINE_ELEVATION )
2008-12-24 09:58:26 -06:00
{
2010-08-04 14:39:45 +02:00
data >> mi -> splineElevation ;
2009-02-18 22:39:00 +01:00
}
}
2009-10-17 15:51:44 -07:00
2009-12-17 12:36:55 +01:00
void WorldSession :: WriteMovementInfo ( WorldPacket * data , MovementInfo * mi )
{
data -> appendPackGUID ( mi -> guid );
* data << mi -> flags ;
2010-08-04 14:39:45 +02:00
* data << mi -> flags2 ;
2009-12-17 12:36:55 +01:00
* data << mi -> time ;
2010-08-04 14:39:45 +02:00
* data << mi -> pos . PositionXYZOStream ();
2009-12-17 12:36:55 +01:00
2010-04-07 19:14:10 +02:00
if ( mi -> HasMovementFlag ( MOVEMENTFLAG_ONTRANSPORT ))
2009-12-17 12:36:55 +01:00
{
data -> appendPackGUID ( mi -> t_guid );
2010-08-04 14:39:45 +02:00
* data << mi -> t_pos . PositionXYZOStream ();
* data << mi -> t_time ;
* data << mi -> t_seat ;
2009-12-17 12:36:55 +01:00
}
2010-08-04 14:39:45 +02:00
if (( mi -> HasMovementFlag ( MovementFlags ( MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING ))) || ( mi -> flags & MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING ))
2009-12-17 12:36:55 +01:00
{
2010-08-04 14:39:45 +02:00
* data << mi -> pitch ;
2009-12-17 12:36:55 +01:00
}
* data << mi -> fallTime ;
2010-04-07 19:14:10 +02:00
if ( mi -> HasMovementFlag ( MOVEMENTFLAG_JUMPING ))
2009-12-17 12:36:55 +01:00
{
* data << mi -> j_zspeed ;
* data << mi -> j_sinAngle ;
* data << mi -> j_cosAngle ;
* data << mi -> j_xyspeed ;
}
2010-08-04 14:39:45 +02:00
if ( mi -> HasMovementFlag ( MOVEMENTFLAG_SPLINE_ELEVATION ))
2009-12-17 12:36:55 +01:00
{
2010-08-04 14:39:45 +02:00
* data << mi -> splineElevation ;
2009-12-17 12:36:55 +01: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 ;
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
{
sLog . outError ( "WorldSession::ReadAddonsInfo addon info too big, size %u" , size );
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
2009-03-21 14:39:04 -06:00
if ( uncompress ( const_cast < uint8 *> ( addonInfo . contents ()), & uSize , const_cast < uint8 *> ( data . contents () + pos ), data . size () - pos ) == Z_OK )
{
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-04-07 19:14:10 +02: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
2010-01-20 16:24:52 +01:00
sLog . outDetail ( "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x" , addonName . c_str (), enabled , crc , unk1 );
AddonInfo addon ( addonName , enabled , crc , 2 , true );
SavedAddon const * savedAddon = sAddonMgr . GetAddonInfo ( addonName );
if ( savedAddon )
{
bool match = true ;
if ( addon . CRC != savedAddon -> CRC )
match = false ;
if ( ! match )
sLog . outDetail ( "ADDON: %s was known, but didn't match known CRC (0x%x)!" , addon . Name . c_str (), savedAddon -> CRC );
else
sLog . outDetail ( "ADDON: %s was known, CRC is correct (0x%x)" , addon . Name . c_str (), savedAddon -> CRC );
}
else
{
sAddonMgr . SaveAddon ( addon );
sLog . outDetail ( "ADDON: %s (0x%x) was not known, saving..." , addon . Name . c_str (), addon . CRC );
}
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 ;
sLog . outDebug ( "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 ())
2010-01-20 16:24:52 +01:00
sLog . outDebug ( "packet under-read!" );
2009-03-21 14:39:04 -06:00
}
else
sLog . outError ( "Addon packet uncompress error!" );
}
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)
{
2010-01-20 16:24:52 +01:00
sLog . outDetail ( "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 ));
}
data << uint32 ( /*itr->CRC*/ 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
2009-03-21 14:39:04 -06:00
uint32 count = 0 ;
data << uint32 ( count );
2009-10-17 16:20:24 -07:00
/*for (uint32 i = 0; i < count; ++i)
2009-03-21 14:39:04 -06:00
{
uint32
string (16 bytes)
string (16 bytes)
uint32
2010-01-20 16:24:52 +01:00
uint32
2009-03-21 14:39:04 -06:00
}*/
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
2010-04-07 22:59:46 +02:00
void WorldSession :: SetPlayer ( Player * plr )
2009-09-01 16:47:49 -05:00
{
_player = plr ;
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 ();
2009-10-17 16:20:24 -07:00
}
2010-08-18 19:48:51 +02:00
void WorldSession :: ProcessQueryCallbacks ()
{
QueryResult_AutoPtr result ;
//! HandleNameQueryOpcode
while ( ! m_nameQueryCallbacks . is_empty ())
{
QueryResultFuture lResult ;
ACE_Time_Value timeout = ACE_Time_Value :: zero ;
if ( m_nameQueryCallbacks . next_readable ( lResult , & timeout ) != 1 )
break ;
lResult . get ( result );
SendNameQueryOpcodeFromDBCallBack ( result );
}
//! HandleCharEnumOpcode
if ( m_charEnumCallback . ready ())
{
m_charEnumCallback . get ( result );
HandleCharEnum ( result );
m_charEnumCallback . cancel ();
}
//! HandlePlayerLoginOpcode
if ( m_charLoginCallback . ready ())
{
SQLQueryHolder * param ;
m_charLoginCallback . get ( param );
HandlePlayerLogin (( LoginQueryHolder * ) param );
m_charLoginCallback . cancel ();
}
//! HandleAddFriendOpcode
if ( m_addFriendCallback . IsReady ())
{
2010-08-21 03:19:25 +02:00
std :: string param = m_addFriendCallback . GetParam ();
2010-08-18 19:48:51 +02:00
m_addFriendCallback . GetResult ( result );
HandleAddFriendOpcodeCallBack ( result , param );
m_addFriendCallback . FreeResult ();
}
//- HandleCharRenameOpcode
if ( m_charRenameCallback . IsReady ())
{
2010-08-21 03:19:25 +02:00
std :: string param = m_charRenameCallback . GetParam ();
2010-08-18 19:48:51 +02:00
m_charRenameCallback . GetResult ( result );
HandleChangePlayerNameOpcodeCallBack ( result , param );
m_charRenameCallback . FreeResult ();
}
//- HandleCharAddIgnoreOpcode
if ( m_addIgnoreCallback . ready ())
{
m_addIgnoreCallback . get ( result );
HandleAddIgnoreOpcodeCallBack ( result );
m_addIgnoreCallback . cancel ();
}
}