2015-01-19 00:06:15 +00:00
/*
2020-01-02 06:44:10 +01:00
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
2015-01-19 00:06:15 +00: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 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/>.
*/
2017-05-18 23:52:58 +02:00
#include "WorldSession.h"
#include "AccountMgr.h"
#include "AchievementPackets.h"
#include "AreaTriggerPackets.h"
#include "Battleground.h"
#include "CharacterPackets.h"
#include "Chat.h"
2017-06-04 01:00:45 +02:00
#include "CinematicMgr.h"
2017-05-18 23:52:58 +02:00
#include "ClientConfigPackets.h"
2015-01-19 00:06:15 +00:00
#include "Common.h"
2021-10-12 00:16:20 +02:00
#include "Conversation.h"
2017-06-04 01:00:45 +02:00
#include "Corpse.h"
2015-01-19 00:06:15 +00:00
#include "DatabaseEnv.h"
2017-06-04 01:00:45 +02:00
#include "DB2Stores.h"
2017-03-02 02:19:25 +01:00
#include "GameTime.h"
2015-01-19 00:06:15 +00:00
#include "GossipDef.h"
2017-05-18 23:52:58 +02:00
#include "Group.h"
#include "Guild.h"
2015-01-19 00:06:15 +00:00
#include "GuildMgr.h"
2017-05-18 23:52:58 +02:00
#include "InstancePackets.h"
#include "InstanceScript.h"
#include "Language.h"
#include "Log.h"
#include "MapManager.h"
#include "MiscPackets.h"
2015-01-19 00:06:15 +00:00
#include "Object.h"
2017-05-18 23:52:58 +02:00
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
2015-01-19 00:06:15 +00:00
#include "OutdoorPvP.h"
2017-05-18 23:52:58 +02:00
#include "Player.h"
2017-06-04 16:51:47 +02:00
#include "RestMgr.h"
2015-01-19 00:06:15 +00:00
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellPackets.h"
2017-01-29 04:59:17 +01:00
#include "WhoListStorage.h"
2015-02-05 20:18:32 +01:00
#include "WhoPackets.h"
2017-05-18 23:52:58 +02:00
#include "World.h"
#include "WorldPacket.h"
2017-05-11 22:29:51 +02:00
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/locks.hpp>
2017-10-26 00:04:57 +02:00
#include <cstdarg>
2017-05-18 23:52:58 +02:00
#include <zlib.h>
2015-01-19 00:06:15 +00:00
2015-03-22 13:47:55 +01:00
void WorldSession :: HandleRepopRequest ( WorldPackets :: Misc :: RepopRequest & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
2019-06-03 20:40:34 +02:00
if ( GetPlayer () -> IsAlive () || GetPlayer () -> HasPlayerFlag ( PLAYER_FLAGS_GHOST ))
2015-01-19 00:06:15 +00:00
return ;
if ( GetPlayer () -> HasAuraType ( SPELL_AURA_PREVENT_RESURRECTION ))
return ; // silently return, client should display the error by itself
// the world update order is sessions, players, creatures
// the netcode runs in parallel with all of these
// creatures can kill players
// so if the server is lagging enough the player can
// release spirit after he's killed but before he is updated
if ( GetPlayer () -> getDeathState () == JUST_DIED )
{
2020-04-05 14:28:24 +02:00
TC_LOG_DEBUG ( "network" , "HandleRepopRequestOpcode: got request after player %s %s was killed and before he was updated" ,
2015-01-19 00:06:15 +00:00
GetPlayer () -> GetName (). c_str (), GetPlayer () -> GetGUID (). ToString (). c_str ());
GetPlayer () -> KillPlayer ();
}
//this is spirit release confirm?
2020-08-14 17:06:03 +02:00
GetPlayer () -> RemovePet ( nullptr , PET_SAVE_NOT_IN_SLOT , true );
2015-01-19 00:06:15 +00:00
GetPlayer () -> BuildPlayerRepop ();
GetPlayer () -> RepopAtGraveyard ();
}
2015-02-05 20:18:32 +01:00
void WorldSession :: HandleWhoOpcode ( WorldPackets :: Who :: WhoRequestPkt & whoRequest )
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
WorldPackets :: Who :: WhoRequest & request = whoRequest . Request ;
2015-01-19 00:06:15 +00:00
2018-02-18 17:07:52 +01:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleWhoOpcode: MinLevel: %u, MaxLevel: %u, Name: %s (VirtualRealmName: %s), Guild: %s (GuildVirtualRealmName: %s), RaceFilter: " UI64FMTD ", ClassFilter: %d, Areas: " SZFMTD ", Words: " SZFMTD "." ,
2015-02-05 20:18:32 +01:00
request . MinLevel , request . MaxLevel , request . Name . c_str (), request . VirtualRealmName . c_str (), request . Guild . c_str (), request . GuildVirtualRealmName . c_str (),
2020-03-30 19:06:11 +02:00
request . RaceFilter . RawValue , request . ClassFilter , whoRequest . Areas . size (), request . Words . size ());
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
// zones count, client limit = 10 (2.0.10)
// can't be received from real client or broken packet
if ( whoRequest . Areas . size () > 10 )
return ;
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
// user entered strings count, client limit=4 (checked on 2.0.10)
// can't be received from real client or broken packet
if ( request . Words . size () > 4 )
return ;
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
/// @todo: handle following packet values
/// VirtualRealmNames
/// ShowEnemies
/// ShowArenaPlayers
/// ExactName
/// ServerInfo
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
std :: vector < std :: wstring > wWords ;
wWords . resize ( request . Words . size ());
for ( size_t i = 0 ; i < request . Words . size (); ++ i )
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:35:44 +01:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleWhoOpcode: Word: %s" , request . Words [ i ]. Word . c_str ());
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
// user entered string, it used as universal search pattern(guild+player name)?
if ( ! Utf8toWStr ( request . Words [ i ]. Word , wWords [ i ]))
2015-01-19 00:06:15 +00:00
continue ;
2015-02-05 20:18:32 +01:00
wstrToLower ( wWords [ i ]);
2015-01-19 00:06:15 +00:00
}
2015-02-05 20:18:32 +01:00
std :: wstring wPlayerName ;
std :: wstring wGuildName ;
if ( ! ( Utf8toWStr ( request . Name , wPlayerName ) && Utf8toWStr ( request . Guild , wGuildName )))
2015-01-19 00:06:15 +00:00
return ;
2015-02-05 20:18:32 +01:00
wstrToLower ( wPlayerName );
wstrToLower ( wGuildName );
2015-01-19 00:06:15 +00:00
// client send in case not set max level value 100 but Trinity supports 255 max level,
// update it to show GMs with characters after 100 level
2015-02-05 20:18:32 +01:00
if ( whoRequest . Request . MaxLevel >= MAX_LEVEL )
whoRequest . Request . MaxLevel = STRONG_MAX_LEVEL ;
2015-01-19 00:06:15 +00:00
uint32 team = _player -> GetTeam ();
uint32 gmLevelInWhoList = sWorld -> getIntConfig ( CONFIG_GM_LEVEL_IN_WHO_LIST );
2015-02-05 20:18:32 +01:00
WorldPackets :: Who :: WhoResponsePkt response ;
2020-07-23 20:00:27 +02:00
response . RequestID = whoRequest . RequestID ;
2015-01-19 00:06:15 +00:00
2017-01-29 04:59:17 +01:00
WhoListInfoVector const & whoList = sWhoListStorageMgr -> GetWhoList ();
for ( WhoListPlayerInfo const & target : whoList )
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
// player can see member of other team only if has RBAC_PERM_TWO_SIDE_WHO_LIST
2017-01-29 04:59:17 +01:00
if ( target . GetTeam () != team && ! HasPermission ( rbac :: RBAC_PERM_TWO_SIDE_WHO_LIST ))
2015-01-19 00:06:15 +00:00
continue ;
2015-02-05 20:18:32 +01:00
// player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if has RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS
2017-01-29 04:59:17 +01:00
if ( target . GetSecurity () > AccountTypes ( gmLevelInWhoList ) && ! HasPermission ( rbac :: RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS ))
2015-01-19 00:06:15 +00:00
continue ;
// check if target is globally visible for player
2017-01-29 04:59:17 +01:00
if ( _player -> GetGUID () != target . GetGuid () && ! target . IsVisible ())
if ( AccountMgr :: IsPlayerAccount ( _player -> GetSession () -> GetSecurity ()) || target . GetSecurity () > _player -> GetSession () -> GetSecurity ())
continue ;
2015-01-19 00:06:15 +00:00
// check if target's level is in level range
2017-01-29 04:59:17 +01:00
uint8 lvl = target . GetLevel ();
2015-02-05 20:18:32 +01:00
if ( lvl < request . MinLevel || lvl > request . MaxLevel )
2015-01-19 00:06:15 +00:00
continue ;
// check if class matches classmask
2017-01-29 04:59:17 +01:00
if ( request . ClassFilter >= 0 && ! ( request . ClassFilter & ( 1 << target . GetClass ())))
2015-01-19 00:06:15 +00:00
continue ;
// check if race matches racemask
2020-03-30 19:06:11 +02:00
if ( ! request . RaceFilter . HasRace ( target . GetRace ()))
2015-01-19 00:06:15 +00:00
continue ;
2015-02-05 20:18:32 +01:00
if ( ! whoRequest . Areas . empty ())
2015-01-19 00:06:15 +00:00
{
2017-01-29 04:59:17 +01:00
if ( std :: find ( whoRequest . Areas . begin (), whoRequest . Areas . end (), target . GetZoneId ()) == whoRequest . Areas . end ())
2015-02-05 20:18:32 +01:00
continue ;
2015-01-19 00:06:15 +00:00
}
2017-01-29 04:59:17 +01:00
std :: wstring const & wTargetName = target . GetWidePlayerName ();
if ( ! ( wPlayerName . empty () || wTargetName . find ( wPlayerName ) != std :: wstring :: npos ))
2015-01-19 00:06:15 +00:00
continue ;
2017-01-29 04:59:17 +01:00
std :: wstring const & wTargetGuildName = target . GetWideGuildName ();
2015-02-05 20:18:32 +01:00
if ( ! wGuildName . empty () && wTargetGuildName . find ( wGuildName ) == std :: wstring :: npos )
continue ;
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
if ( ! wWords . empty ())
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
std :: string aName ;
2017-01-29 04:59:17 +01:00
if ( AreaTableEntry const * areaEntry = sAreaTableStore . LookupEntry ( target . GetZoneId ()))
2020-06-27 13:33:17 +02:00
aName = areaEntry -> AreaName [ GetSessionDbcLocale ()];
2015-02-05 20:18:32 +01:00
bool show = false ;
for ( size_t i = 0 ; i < wWords . size (); ++ i )
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
if ( ! wWords [ i ]. empty ())
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
if ( wTargetName . find ( wWords [ i ]) != std :: wstring :: npos ||
wTargetGuildName . find ( wWords [ i ]) != std :: wstring :: npos ||
Utf8FitTo ( aName , wWords [ i ]))
{
show = true ;
break ;
}
2015-01-19 00:06:15 +00:00
}
}
2015-02-05 20:18:32 +01:00
if ( ! show )
continue ;
2015-01-19 00:06:15 +00:00
}
2015-02-05 20:18:32 +01:00
WorldPackets :: Who :: WhoEntry whoEntry ;
2017-01-29 04:59:17 +01:00
if ( ! whoEntry . PlayerData . Initialize ( target . GetGuid (), nullptr ))
2015-01-19 00:06:15 +00:00
continue ;
2017-01-29 04:59:17 +01:00
if ( ! target . GetGuildGuid (). IsEmpty ())
2015-02-05 20:18:32 +01:00
{
2017-01-29 04:59:17 +01:00
whoEntry . GuildGUID = target . GetGuildGuid ();
2015-02-05 20:18:32 +01:00
whoEntry . GuildVirtualRealmAddress = GetVirtualRealmAddress ();
2017-01-29 04:59:17 +01:00
whoEntry . GuildName = target . GetGuildName ();
2015-02-05 20:18:32 +01:00
}
2015-01-19 00:06:15 +00:00
2017-01-29 04:59:17 +01:00
whoEntry . AreaID = target . GetZoneId ();
whoEntry . IsGM = target . IsGameMaster ();
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
response . Response . Entries . push_back ( whoEntry );
2015-01-19 00:06:15 +00:00
2015-02-05 20:18:32 +01:00
// 50 is maximum player count sent to client - can be overridden
// through config, but is unstable
if ( response . Response . Entries . size () >= sWorld -> getIntConfig ( CONFIG_MAX_WHO ))
break ;
}
SendPacket ( response . Write ());
2015-01-19 00:06:15 +00:00
}
void WorldSession :: HandleLogoutRequestOpcode ( WorldPackets :: Character :: LogoutRequest & /*logoutRequest*/ )
{
2016-12-28 01:12:01 +01:00
if ( ! GetPlayer () -> GetLootGUID (). IsEmpty ())
GetPlayer () -> SendLootReleaseAll ();
2015-01-19 00:06:15 +00:00
2019-06-03 20:40:34 +02:00
bool instantLogout = ( GetPlayer () -> HasPlayerFlag ( PLAYER_FLAGS_RESTING ) && ! GetPlayer () -> IsInCombat ()) ||
2015-01-19 00:06:15 +00:00
GetPlayer () -> IsInFlight () || HasPermission ( rbac :: RBAC_PERM_INSTANT_LOGOUT );
/// TODO: Possibly add RBAC permission to log out in combat
2019-06-03 20:40:34 +02:00
bool canLogoutInCombat = GetPlayer () -> HasPlayerFlag ( PLAYER_FLAGS_RESTING );
2015-01-19 00:06:15 +00:00
uint32 reason = 0 ;
if ( GetPlayer () -> IsInCombat () && ! canLogoutInCombat )
reason = 1 ;
else if ( GetPlayer () -> IsFalling ())
reason = 3 ; // is jumping or falling
else if ( GetPlayer () -> duel || GetPlayer () -> HasAura ( 9454 )) // is dueling or frozen by GM via freeze command
reason = 2 ; // FIXME - Need the correct value
WorldPackets :: Character :: LogoutResponse logoutResponse ;
logoutResponse . LogoutResult = reason ;
logoutResponse . Instant = instantLogout ;
SendPacket ( logoutResponse . Write ());
if ( reason )
{
SetLogoutStartTime ( 0 );
return ;
}
// instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf
if ( instantLogout )
{
LogoutPlayer ( true );
return ;
}
// not set flags if player can't free move to prevent lost state at logout cancel
if ( GetPlayer () -> CanFreeMove ())
{
2015-01-28 19:29:31 +00:00
if ( GetPlayer () -> GetStandState () == UNIT_STAND_STATE_STAND )
2015-01-19 00:06:15 +00:00
GetPlayer () -> SetStandState ( UNIT_STAND_STATE_SIT );
GetPlayer () -> SetRooted ( true );
2019-06-03 20:40:34 +02:00
GetPlayer () -> AddUnitFlag ( UNIT_FLAG_STUNNED );
2015-01-19 00:06:15 +00:00
}
2017-12-10 12:39:37 +01:00
SetLogoutStartTime ( GameTime :: GetGameTime ());
2015-01-19 00:06:15 +00:00
}
void WorldSession :: HandleLogoutCancelOpcode ( WorldPackets :: Character :: LogoutCancel & /*logoutCancel*/ )
{
// Player have already logged out serverside, too late to cancel
if ( ! GetPlayer ())
return ;
SetLogoutStartTime ( 0 );
SendPacket ( WorldPackets :: Character :: LogoutCancelAck (). Write ());
// not remove flags if can't free move - its not set in Logout request code.
if ( GetPlayer () -> CanFreeMove ())
{
//!we can move again
GetPlayer () -> SetRooted ( false );
//! Stand Up
GetPlayer () -> SetStandState ( UNIT_STAND_STATE_STAND );
//! DISABLE_ROTATE
2019-06-03 20:40:34 +02:00
GetPlayer () -> RemoveUnitFlag ( UNIT_FLAG_STUNNED );
2015-01-19 00:06:15 +00:00
}
}
2015-08-02 01:29:23 +02:00
void WorldSession :: HandleTogglePvP ( WorldPackets :: Misc :: TogglePvP & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
2021-12-26 20:14:46 +02:00
if ( ! GetPlayer () -> HasPlayerFlag ( PLAYER_FLAGS_IN_PVP ))
2015-01-19 00:06:15 +00:00
{
2019-06-03 20:40:34 +02:00
GetPlayer () -> AddPlayerFlag ( PLAYER_FLAGS_IN_PVP );
GetPlayer () -> RemovePlayerFlag ( PLAYER_FLAGS_PVP_TIMER );
if ( ! GetPlayer () -> IsPvP () || GetPlayer () -> pvpInfo . EndTimer )
GetPlayer () -> UpdatePvP ( true , true );
2015-01-19 00:06:15 +00:00
}
2021-12-26 20:14:46 +02:00
else if ( ! GetPlayer () -> IsWarModeLocalActive ())
2015-08-02 16:20:01 +02:00
{
2019-06-03 20:40:34 +02:00
GetPlayer () -> RemovePlayerFlag ( PLAYER_FLAGS_IN_PVP );
GetPlayer () -> AddPlayerFlag ( PLAYER_FLAGS_PVP_TIMER );
if ( ! GetPlayer () -> pvpInfo . IsHostile && GetPlayer () -> IsPvP ())
2019-07-08 13:04:35 +02:00
GetPlayer () -> pvpInfo . EndTimer = GameTime :: GetGameTime () + 300 ; // start toggle-off
2015-08-02 16:20:01 +02:00
}
2021-12-26 20:14:46 +02:00
}
void WorldSession :: HandleSetPvP ( WorldPackets :: Misc :: SetPvP & packet )
{
if ( packet . EnablePVP )
2015-08-02 16:20:01 +02:00
{
2019-06-03 20:40:34 +02:00
GetPlayer () -> AddPlayerFlag ( PLAYER_FLAGS_IN_PVP );
GetPlayer () -> RemovePlayerFlag ( PLAYER_FLAGS_PVP_TIMER );
if ( ! GetPlayer () -> IsPvP () || GetPlayer () -> pvpInfo . EndTimer )
GetPlayer () -> UpdatePvP ( true , true );
2015-08-02 16:20:01 +02:00
}
2021-12-26 20:14:46 +02:00
else if ( ! GetPlayer () -> IsWarModeLocalActive ())
{
GetPlayer () -> RemovePlayerFlag ( PLAYER_FLAGS_IN_PVP );
GetPlayer () -> AddPlayerFlag ( PLAYER_FLAGS_PVP_TIMER );
if ( ! GetPlayer () -> pvpInfo . IsHostile && GetPlayer () -> IsPvP ())
GetPlayer () -> pvpInfo . EndTimer = GameTime :: GetGameTime () + 300 ; // start toggle-off
}
}
void WorldSession :: HandleSetWarMode ( WorldPackets :: Misc :: SetWarMode & packet )
{
_player -> SetWarModeDesired ( packet . Enable );
2015-08-02 16:20:01 +02:00
}
2015-01-19 00:06:15 +00:00
void WorldSession :: HandlePortGraveyard ( WorldPackets :: Misc :: PortGraveyard & /*packet*/ )
{
2019-06-03 20:40:34 +02:00
if ( GetPlayer () -> IsAlive () || ! GetPlayer () -> HasPlayerFlag ( PLAYER_FLAGS_GHOST ))
2015-01-19 00:06:15 +00:00
return ;
GetPlayer () -> RepopAtGraveyard ();
}
void WorldSession :: HandleRequestCemeteryList ( WorldPackets :: Misc :: RequestCemeteryList & /*packet*/ )
{
uint32 zoneId = _player -> GetZoneId ();
uint32 team = _player -> GetTeam ();
std :: vector < uint32 > graveyardIds ;
2020-09-04 13:38:24 +02:00
auto range = sObjectMgr -> GraveyardStore . equal_range ( zoneId );
2015-01-19 00:06:15 +00:00
for ( auto it = range . first ; it != range . second && graveyardIds . size () < 16 ; ++ it ) // client max
{
if ( it -> second . team == 0 || it -> second . team == team )
graveyardIds . push_back ( it -> first );
}
if ( graveyardIds . empty ())
{
TC_LOG_DEBUG ( "network" , "No graveyards found for zone %u for %s (team %u) in CMSG_REQUEST_CEMETERY_LIST" ,
zoneId , _player -> GetGUID (). ToString (). c_str (), team );
return ;
}
WorldPackets :: Misc :: RequestCemeteryListResponse packet ;
packet . IsGossipTriggered = false ;
packet . CemeteryID . reserve ( graveyardIds . size ());
for ( uint32 id : graveyardIds )
packet . CemeteryID . push_back ( id );
SendPacket ( packet . Write ());
}
void WorldSession :: HandleSetSelectionOpcode ( WorldPackets :: Misc :: SetSelection & packet )
{
_player -> SetSelection ( packet . Selection );
}
2015-01-28 19:29:31 +00:00
void WorldSession :: HandleStandStateChangeOpcode ( WorldPackets :: Misc :: StandStateChange & packet )
2015-01-19 00:06:15 +00:00
{
2019-10-27 11:15:15 +01:00
switch ( packet . StandState )
{
case UNIT_STAND_STATE_STAND :
case UNIT_STAND_STATE_SIT :
case UNIT_STAND_STATE_SLEEP :
case UNIT_STAND_STATE_KNEEL :
break ;
default :
return ;
}
2015-01-28 19:29:31 +00:00
_player -> SetStandState ( packet . StandState );
2015-01-19 00:06:15 +00:00
}
2015-03-22 13:47:55 +01:00
void WorldSession :: HandleReclaimCorpse ( WorldPackets :: Misc :: ReclaimCorpse & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
if ( _player -> IsAlive ())
return ;
// do not allow corpse reclaim in arena
if ( _player -> InArena ())
return ;
// body not released yet
2019-06-03 20:40:34 +02:00
if ( ! _player -> HasPlayerFlag ( PLAYER_FLAGS_GHOST ))
2015-01-19 00:06:15 +00:00
return ;
Corpse * corpse = _player -> GetCorpse ();
if ( ! corpse )
return ;
// prevent resurrect before 30-sec delay after body release not finished
2017-12-10 12:39:37 +01:00
if ( time_t ( corpse -> GetGhostTime () + _player -> GetCorpseReclaimDelay ( corpse -> GetType () == CORPSE_RESURRECTABLE_PVP )) > time_t ( GameTime :: GetGameTime ()))
2015-01-19 00:06:15 +00:00
return ;
if ( ! corpse -> IsWithinDistInMap ( _player , CORPSE_RECLAIM_RADIUS , true ))
return ;
// resurrect
_player -> ResurrectPlayer ( _player -> InBattleground () ? 1.0f : 0.5f );
// spawn bones
_player -> SpawnCorpseBones ();
}
void WorldSession :: HandleResurrectResponse ( WorldPackets :: Misc :: ResurrectResponse & packet )
{
if ( GetPlayer () -> IsAlive ())
return ;
2015-04-19 13:45:43 +02:00
if ( packet . Response != 0 ) // Accept = 0 Decline = 1 Timeout = 2
2015-01-19 00:06:15 +00:00
{
GetPlayer () -> ClearResurrectRequestData (); // reject
return ;
}
if ( ! GetPlayer () -> IsResurrectRequestedBy ( packet . Resurrecter ))
return ;
2016-04-14 22:43:21 +02:00
if ( Player * ressPlayer = ObjectAccessor :: GetPlayer ( * GetPlayer (), packet . Resurrecter ))
{
if ( InstanceScript * instance = ressPlayer -> GetInstanceScript ())
{
if ( instance -> IsEncounterInProgress ())
{
if ( ! instance -> GetCombatResurrectionCharges ())
return ;
else
instance -> UseCombatResurrection ();
}
}
}
2015-01-19 00:06:15 +00:00
GetPlayer () -> ResurrectUsingRequestData ();
}
2017-01-29 00:00:43 +01:00
void WorldSession :: HandleAreaTriggerOpcode ( WorldPackets :: AreaTrigger :: AreaTrigger & packet )
2015-01-19 00:06:15 +00:00
{
Player * player = GetPlayer ();
if ( player -> IsInFlight ())
{
2020-04-05 14:28:24 +02:00
TC_LOG_DEBUG ( "network" , "HandleAreaTriggerOpcode: Player '%s' %s in flight, ignore Area Trigger ID:%u" ,
2015-01-19 00:06:15 +00:00
player -> GetName (). c_str (), player -> GetGUID (). ToString (). c_str (), packet . AreaTriggerID );
return ;
}
AreaTriggerEntry const * atEntry = sAreaTriggerStore . LookupEntry ( packet . AreaTriggerID );
if ( ! atEntry )
{
2020-04-05 14:28:24 +02:00
TC_LOG_DEBUG ( "network" , "HandleAreaTriggerOpcode: Player '%s' %s send unknown (by DBC) Area Trigger ID:%u" ,
2015-01-19 00:06:15 +00:00
player -> GetName (). c_str (), player -> GetGUID (). ToString (). c_str (), packet . AreaTriggerID );
return ;
}
2016-05-27 15:17:51 +02:00
if ( packet . Entered && ! player -> IsInAreaTriggerRadius ( atEntry ))
2015-01-19 00:06:15 +00:00
{
2020-04-05 14:28:24 +02:00
TC_LOG_DEBUG ( "network" , "HandleAreaTriggerOpcode: Player '%s' %s too far, ignore Area Trigger ID: %u" ,
2015-08-10 18:12:22 +02:00
player -> GetName (). c_str (), player -> GetGUID (). ToString (). c_str (), packet . AreaTriggerID );
2015-01-19 00:06:15 +00:00
return ;
}
if ( player -> isDebugAreaTriggers )
2015-04-18 11:11:06 +02:00
ChatHandler ( player -> GetSession ()). PSendSysMessage ( packet . Entered ? LANG_DEBUG_AREATRIGGER_ENTERED : LANG_DEBUG_AREATRIGGER_LEFT , packet . AreaTriggerID );
2015-01-19 00:06:15 +00:00
2021-10-26 22:58:49 +02:00
if ( ! sConditionMgr -> IsObjectMeetingNotGroupedConditions ( CONDITION_SOURCE_TYPE_AREATRIGGER_CLIENT_TRIGGERED , atEntry -> ID , player ))
return ;
2015-04-18 11:11:06 +02:00
if ( sScriptMgr -> OnAreaTrigger ( player , atEntry , packet . Entered ))
2015-01-19 00:06:15 +00:00
return ;
if ( player -> IsAlive ())
{
2021-05-10 22:45:54 +02:00
// not using Player::UpdateQuestObjectiveProgress, ObjectID in quest_objectives can be set to -1, areatrigger_involvedrelation then holds correct id
2016-01-19 20:12:09 +01:00
if ( std :: unordered_set < uint32 > const * quests = sObjectMgr -> GetQuestsForAreaTrigger ( packet . AreaTriggerID ))
2015-01-19 00:06:15 +00:00
{
2021-05-10 22:45:54 +02:00
bool anyObjectiveChangedCompletionState = false ;
2016-01-19 20:12:09 +01:00
for ( uint32 questId : * quests )
2015-01-19 00:06:15 +00:00
{
2016-01-19 20:12:09 +01:00
Quest const * qInfo = sObjectMgr -> GetQuestTemplate ( questId );
2021-05-09 20:21:32 +02:00
uint16 slot = player -> FindQuestSlot ( questId );
if ( qInfo && slot < MAX_QUEST_LOG_SIZE && player -> GetQuestStatus ( questId ) == QUEST_STATUS_INCOMPLETE )
2015-01-19 00:06:15 +00:00
{
2017-06-10 00:06:07 +02:00
for ( QuestObjective const & obj : qInfo -> Objectives )
2015-01-19 00:06:15 +00:00
{
2021-05-10 22:45:54 +02:00
if ( obj . Type != QUEST_OBJECTIVE_AREATRIGGER )
continue ;
if ( ! player -> IsQuestObjectiveCompletable ( slot , qInfo , obj ))
continue ;
if ( player -> IsQuestObjectiveComplete ( slot , qInfo , obj ))
continue ;
if ( obj . ObjectID != - 1 && obj . ObjectID != packet . AreaTriggerID )
continue ;
player -> SetQuestObjectiveData ( obj , 1 );
player -> SendQuestUpdateAddCreditSimple ( obj );
anyObjectiveChangedCompletionState = true ;
break ;
2015-01-19 00:06:15 +00:00
}
2016-01-19 20:12:09 +01:00
if ( player -> CanCompleteQuest ( questId ))
player -> CompleteQuest ( questId );
}
2015-01-19 00:06:15 +00:00
}
2021-05-09 20:21:32 +02:00
2021-05-10 22:45:54 +02:00
if ( anyObjectiveChangedCompletionState )
2019-07-05 14:11:15 +02:00
player -> UpdateVisibleGameobjectsOrSpellClicks ();
2015-01-19 00:06:15 +00:00
}
}
if ( sObjectMgr -> IsTavernAreaTrigger ( packet . AreaTriggerID ))
{
// set resting flag we are in the inn
2017-06-04 16:51:47 +02:00
player -> GetRestMgr (). SetRestFlag ( REST_FLAG_IN_TAVERN , atEntry -> ID );
2015-01-19 00:06:15 +00:00
if ( sWorld -> IsFFAPvPRealm ())
2019-06-03 20:40:34 +02:00
player -> RemovePvpFlag ( UNIT_BYTE2_FLAG_FFA_PVP );
2015-01-19 00:06:15 +00:00
return ;
}
if ( Battleground * bg = player -> GetBattleground ())
2016-05-27 15:17:51 +02:00
bg -> HandleAreaTrigger ( player , packet . AreaTriggerID , packet . Entered );
2015-01-19 00:06:15 +00:00
if ( OutdoorPvP * pvp = player -> GetOutdoorPvP ())
2015-04-18 11:11:06 +02:00
if ( pvp -> HandleAreaTrigger ( _player , packet . AreaTriggerID , packet . Entered ))
2015-01-19 00:06:15 +00:00
return ;
AreaTriggerStruct const * at = sObjectMgr -> GetAreaTrigger ( packet . AreaTriggerID );
if ( ! at )
return ;
bool teleported = false ;
if ( player -> GetMapId () != at -> target_mapId )
{
2015-12-31 19:51:07 +01:00
if ( Map :: EnterState denyReason = sMapMgr -> PlayerCannotEnter ( at -> target_mapId , player , false ))
{
bool reviveAtTrigger = false ; // should we revive the player if he is trying to enter the correct instance?
switch ( denyReason )
{
case Map :: CANNOT_ENTER_NO_ENTRY :
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' attempted to enter map with id %d which has no entry" , player -> GetName (). c_str (), at -> target_mapId );
break ;
case Map :: CANNOT_ENTER_UNINSTANCED_DUNGEON :
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' attempted to enter dungeon map %d but no instance template was found" , player -> GetName (). c_str (), at -> target_mapId );
break ;
case Map :: CANNOT_ENTER_DIFFICULTY_UNAVAILABLE :
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' attempted to enter instance map %d but the requested difficulty was not found" , player -> GetName (). c_str (), at -> target_mapId );
if ( MapEntry const * entry = sMapStore . LookupEntry ( at -> target_mapId ))
player -> SendTransferAborted ( entry -> ID , TRANSFER_ABORT_DIFFICULTY , player -> GetDifficultyID ( entry ));
break ;
case Map :: CANNOT_ENTER_NOT_IN_RAID :
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' must be in a raid group to enter map %d" , player -> GetName (). c_str (), at -> target_mapId );
player -> SendRaidGroupOnlyMessage ( RAID_GROUP_ERR_ONLY , 0 );
reviveAtTrigger = true ;
break ;
case Map :: CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE :
2017-01-29 00:00:43 +01:00
player -> GetSession () -> SendPacket ( WorldPackets :: AreaTrigger :: AreaTriggerNoCorpse (). Write ());
2015-12-31 19:51:07 +01:00
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' does not have a corpse in instance map %d and cannot enter" , player -> GetName (). c_str (), at -> target_mapId );
break ;
case Map :: CANNOT_ENTER_INSTANCE_BIND_MISMATCH :
if ( MapEntry const * entry = sMapStore . LookupEntry ( at -> target_mapId ))
{
2020-06-27 13:33:17 +02:00
char const * mapName = entry -> MapName [ player -> GetSession () -> GetSessionDbcLocale ()];
2015-12-31 19:51:07 +01:00
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' cannot enter instance map '%s' because their permanent bind is incompatible with their group's" , player -> GetName (). c_str (), mapName );
// is there a special opcode for this?
// @todo figure out how to get player localized difficulty string (e.g. "10 player", "Heroic" etc)
ChatHandler ( player -> GetSession ()). PSendSysMessage ( player -> GetSession () -> GetTrinityString ( LANG_INSTANCE_BIND_MISMATCH ), mapName );
}
reviveAtTrigger = true ;
break ;
case Map :: CANNOT_ENTER_TOO_MANY_INSTANCES :
player -> SendTransferAborted ( at -> target_mapId , TRANSFER_ABORT_TOO_MANY_INSTANCES );
TC_LOG_DEBUG ( "maps" , "MAP: Player '%s' cannot enter instance map %d because he has exceeded the maximum number of instances per hour." , player -> GetName (). c_str (), at -> target_mapId );
reviveAtTrigger = true ;
break ;
case Map :: CANNOT_ENTER_MAX_PLAYERS :
player -> SendTransferAborted ( at -> target_mapId , TRANSFER_ABORT_MAX_PLAYERS );
reviveAtTrigger = true ;
break ;
case Map :: CANNOT_ENTER_ZONE_IN_COMBAT :
player -> SendTransferAborted ( at -> target_mapId , TRANSFER_ABORT_ZONE_IN_COMBAT );
reviveAtTrigger = true ;
break ;
default :
break ;
}
if ( reviveAtTrigger ) // check if the player is touching the areatrigger leading to the map his corpse is on
if ( ! player -> IsAlive () && player -> HasCorpse ())
if ( player -> GetCorpseLocation (). GetMapId () == at -> target_mapId )
{
player -> ResurrectPlayer ( 0.5f );
player -> SpawnCorpseBones ();
}
2015-01-19 00:06:15 +00:00
return ;
2015-12-31 19:51:07 +01:00
}
2015-01-19 00:06:15 +00:00
if ( Group * group = player -> GetGroup ())
if ( group -> isLFGGroup () && player -> GetMap () -> IsDungeon ())
teleported = player -> TeleportToBGEntryPoint ();
}
if ( ! teleported )
2016-07-16 14:58:33 +02:00
{
WorldSafeLocsEntry const * entranceLocation = nullptr ;
InstanceSave * instanceSave = player -> GetInstanceSave ( at -> target_mapId );
if ( instanceSave )
{
// Check if we can contact the instancescript of the instance for an updated entrance location
if ( Map * map = sMapMgr -> FindMap ( at -> target_mapId , player -> GetInstanceSave ( at -> target_mapId ) -> GetInstanceId ()))
if ( InstanceMap * instanceMap = map -> ToInstanceMap ())
if ( InstanceScript * instanceScript = instanceMap -> GetInstanceScript ())
2019-10-26 23:58:29 +02:00
entranceLocation = sObjectMgr -> GetWorldSafeLoc ( instanceScript -> GetEntranceLocation ());
2016-07-16 14:58:33 +02:00
// Finally check with the instancesave for an entrance location if we did not get a valid one from the instancescript
if ( ! entranceLocation )
2019-10-26 23:58:29 +02:00
entranceLocation = sObjectMgr -> GetWorldSafeLoc ( instanceSave -> GetEntranceLocation ());
2016-07-16 14:58:33 +02:00
}
if ( entranceLocation )
2019-10-26 23:58:29 +02:00
player -> TeleportTo ( entranceLocation -> Loc , TELE_TO_NOT_LEAVE_TRANSPORT );
2016-07-16 14:58:33 +02:00
else
player -> TeleportTo ( at -> target_mapId , at -> target_X , at -> target_Y , at -> target_Z , at -> target_Orientation , TELE_TO_NOT_LEAVE_TRANSPORT );
}
2015-01-19 00:06:15 +00:00
}
void WorldSession :: HandleUpdateAccountData ( WorldPackets :: ClientConfig :: UserClientUpdateAccountData & packet )
{
2021-04-09 20:57:47 +02:00
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_UPDATE_ACCOUNT_DATA: type %u, time " SI64FMTD ", decompressedSize %u" ,
2021-04-06 19:10:28 +02:00
packet . DataType , packet . Time . AsUnderlyingType (), packet . Size );
2015-01-19 00:06:15 +00:00
2019-09-25 11:44:08 +02:00
if ( packet . DataType >= NUM_ACCOUNT_DATA_TYPES )
2015-01-19 00:06:15 +00:00
return ;
if ( packet . Size == 0 ) // erase
{
SetAccountData ( AccountDataType ( packet . DataType ), 0 , "" );
return ;
}
if ( packet . Size > 0xFFFF )
{
TC_LOG_ERROR ( "network" , "UAD: Account data packet too big, size %u" , packet . Size );
return ;
}
2020-05-20 17:28:38 +02:00
ByteBuffer dest ( packet . Size , ByteBuffer :: Resize {});
2015-01-19 00:06:15 +00:00
uLongf realSize = packet . Size ;
if ( uncompress ( dest . contents (), & realSize , packet . CompressedData . contents (), packet . CompressedData . size ()) != Z_OK )
{
TC_LOG_ERROR ( "network" , "UAD: Failed to decompress account data" );
return ;
}
std :: string adata ;
dest >> adata ;
SetAccountData ( AccountDataType ( packet . DataType ), packet . Time , adata );
}
void WorldSession :: HandleRequestAccountData ( WorldPackets :: ClientConfig :: RequestAccountData & request )
{
TC_LOG_DEBUG ( "network" , "WORLD: Received CMSG_REQUEST_ACCOUNT_DATA: type %u" , request . DataType );
if ( request . DataType >= NUM_ACCOUNT_DATA_TYPES )
return ;
AccountData const * adata = GetAccountData ( AccountDataType ( request . DataType ));
WorldPackets :: ClientConfig :: UpdateAccountData data ;
data . Player = _player ? _player -> GetGUID () : ObjectGuid :: Empty ;
data . Time = adata -> Time ;
data . Size = adata -> Data . size ();
data . DataType = request . DataType ;
uLongf destSize = compressBound ( data . Size );
data . CompressedData . resize ( destSize );
if ( data . Size && compress ( data . CompressedData . contents (), & destSize , ( uint8 const * ) adata -> Data . c_str (), data . Size ) != Z_OK )
{
TC_LOG_ERROR ( "network" , "RAD: Failed to compress account data" );
return ;
}
data . CompressedData . resize ( destSize );
SendPacket ( data . Write ());
}
void WorldSession :: HandleSetActionButtonOpcode ( WorldPackets :: Spells :: SetActionButton & packet )
{
uint32 action = ACTION_BUTTON_ACTION ( packet . Action );
uint32 type = ACTION_BUTTON_TYPE ( packet . Action );
TC_LOG_DEBUG ( "network" , "CMSG_SET_ACTION_BUTTON Button: %u Action: %u Type: %u" , packet . Index , action , type );
if ( ! packet . Action )
GetPlayer () -> RemoveActionButton ( packet . Index );
else
GetPlayer () -> AddActionButton ( packet . Index , action , type );
}
2015-04-25 14:53:58 +02:00
void WorldSession :: HandleCompleteCinematic ( WorldPackets :: Misc :: CompleteCinematic & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
2016-04-27 16:53:18 +02:00
// If player has sight bound to visual waypoint NPC we should remove it
GetPlayer () -> GetCinematicMgr () -> EndCinematic ();
2015-01-19 00:06:15 +00:00
}
2015-04-25 14:53:58 +02:00
void WorldSession :: HandleNextCinematicCamera ( WorldPackets :: Misc :: NextCinematicCamera & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
2016-04-27 16:53:18 +02:00
// Sent by client when cinematic actually begun. So we begin the server side process
2020-03-27 21:44:19 +01:00
GetPlayer () -> GetCinematicMgr () -> NextCinematicCamera ();
2015-01-19 00:06:15 +00:00
}
2015-04-21 21:26:15 +02:00
2016-12-17 18:27:43 +01:00
void WorldSession :: HandleCompleteMovie ( WorldPackets :: Misc :: CompleteMovie & /*packet*/ )
{
uint32 movie = _player -> GetMovie ();
if ( ! movie )
return ;
_player -> SetMovie ( 0 );
sScriptMgr -> OnMovieComplete ( _player , movie );
}
2015-02-02 09:57:01 +01:00
void WorldSession :: HandleSetActionBarToggles ( WorldPackets :: Character :: SetActionBarToggles & packet )
2015-01-19 00:06:15 +00:00
{
if ( ! GetPlayer ()) // ignore until not logged (check needed because STATUS_AUTHED)
{
2015-02-03 10:11:56 +01:00
if ( packet . Mask != 0 )
TC_LOG_ERROR ( "network" , "WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored" , uint32 ( packet . Mask ));
2015-01-19 00:06:15 +00:00
return ;
}
2019-06-03 20:40:34 +02:00
GetPlayer () -> SetMultiActionBars ( packet . Mask );
2015-01-19 00:06:15 +00:00
}
2015-04-01 01:44:10 +02:00
void WorldSession :: HandlePlayedTime ( WorldPackets :: Character :: RequestPlayedTime & packet )
2015-01-19 00:06:15 +00:00
{
2015-03-08 16:20:31 +01:00
WorldPackets :: Character :: PlayedTime playedTime ;
playedTime . TotalTime = _player -> GetTotalPlayedTime ();
playedTime . LevelTime = _player -> GetLevelPlayedTime ();
playedTime . TriggerEvent = packet . TriggerScriptEvent ; // 0-1 - will not show in chat frame
SendPacket ( playedTime . Write ());
2015-01-19 00:06:15 +00:00
}
2015-03-29 03:23:12 +02:00
void WorldSession :: HandleWhoIsOpcode ( WorldPackets :: Who :: WhoIsRequest & packet )
2015-01-19 00:06:15 +00:00
{
2015-02-05 20:18:32 +01:00
TC_LOG_DEBUG ( "network" , "Received whois command from player %s for character %s" ,
GetPlayer () -> GetName (). c_str (), packet . CharName . c_str ());
2015-01-19 00:06:15 +00:00
if ( ! HasPermission ( rbac :: RBAC_PERM_OPCODE_WHOIS ))
{
SendNotification ( LANG_YOU_NOT_HAVE_PERMISSION );
return ;
}
2015-02-05 20:18:32 +01:00
if ( packet . CharName . empty () || ! normalizePlayerName ( packet . CharName ))
2015-01-19 00:06:15 +00:00
{
SendNotification ( LANG_NEED_CHARACTER_NAME );
return ;
}
2015-02-05 20:18:32 +01:00
Player * player = ObjectAccessor :: FindConnectedPlayerByName ( packet . CharName );
2015-01-19 00:06:15 +00:00
if ( ! player )
{
2015-02-05 20:18:32 +01:00
SendNotification ( LANG_PLAYER_NOT_EXIST_OR_OFFLINE , packet . CharName . c_str ());
2015-01-19 00:06:15 +00:00
return ;
}
2019-07-27 01:00:37 +02:00
LoginDatabasePreparedStatement * stmt = LoginDatabase . GetPreparedStatement ( LOGIN_SEL_ACCOUNT_WHOIS );
2015-02-05 20:18:32 +01:00
stmt -> setUInt32 ( 0 , player -> GetSession () -> GetAccountId ());
2015-01-19 00:06:15 +00:00
PreparedQueryResult result = LoginDatabase . Query ( stmt );
if ( ! result )
{
2015-02-05 20:18:32 +01:00
SendNotification ( LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND , packet . CharName . c_str ());
2015-01-19 00:06:15 +00:00
return ;
}
Field * fields = result -> Fetch ();
std :: string acc = fields [ 0 ]. GetString ();
if ( acc . empty ())
acc = "Unknown" ;
2015-02-05 20:18:32 +01:00
2015-01-19 00:06:15 +00:00
std :: string email = fields [ 1 ]. GetString ();
if ( email . empty ())
email = "Unknown" ;
2015-02-05 20:18:32 +01:00
2015-01-19 00:06:15 +00:00
std :: string lastip = fields [ 2 ]. GetString ();
if ( lastip . empty ())
lastip = "Unknown" ;
2015-02-05 20:18:32 +01:00
WorldPackets :: Who :: WhoIsResponse response ;
response . AccountName = packet . CharName + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip ;
SendPacket ( response . Write ());
2015-01-19 00:06:15 +00:00
}
2015-05-01 13:33:13 +02:00
void WorldSession :: HandleFarSightOpcode ( WorldPackets :: Misc :: FarSight & packet )
2015-01-19 00:06:15 +00:00
{
2015-05-01 13:33:13 +02:00
if ( packet . Enable )
2015-01-19 00:06:15 +00:00
{
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "Added FarSight %s to player %s" , _player -> m_activePlayerData -> FarsightObject -> ToString (). c_str (), _player -> GetGUID (). ToString (). c_str ());
2015-01-19 00:06:15 +00:00
if ( WorldObject * target = _player -> GetViewpoint ())
_player -> SetSeer ( target );
else
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "Player %s %s requests non-existing seer %s" , _player -> GetName (). c_str (), _player -> GetGUID (). ToString (). c_str (), _player -> m_activePlayerData -> FarsightObject -> ToString (). c_str ());
2015-01-19 00:06:15 +00:00
}
else
{
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "Player %s set vision to self" , _player -> GetGUID (). ToString (). c_str ());
2015-01-19 00:06:15 +00:00
_player -> SetSeer ( _player );
}
GetPlayer () -> UpdateVisibilityForPlayer ();
}
2015-03-12 23:23:16 +01:00
void WorldSession :: HandleSetTitleOpcode ( WorldPackets :: Character :: SetTitle & packet )
2015-01-19 00:06:15 +00:00
{
// -1 at none
2019-06-03 20:40:34 +02:00
if ( packet . TitleID > 0 )
2015-01-19 00:06:15 +00:00
{
2015-03-12 23:23:16 +01:00
if ( ! GetPlayer () -> HasTitle ( packet . TitleID ))
2015-01-19 00:06:15 +00:00
return ;
}
else
2015-03-12 23:23:16 +01:00
packet . TitleID = 0 ;
2015-01-19 00:06:15 +00:00
2019-06-03 20:40:34 +02:00
GetPlayer () -> SetChosenTitle ( packet . TitleID );
2015-01-19 00:06:15 +00:00
}
2015-06-07 17:08:45 +02:00
void WorldSession :: HandleResetInstancesOpcode ( WorldPackets :: Instance :: ResetInstances & /*packet*/ )
2015-01-19 00:06:15 +00:00
{
if ( Group * group = _player -> GetGroup ())
{
if ( group -> IsLeader ( _player -> GetGUID ()))
group -> ResetInstances ( INSTANCE_RESET_ALL , false , false , _player );
}
else
_player -> ResetInstances ( INSTANCE_RESET_ALL , false , false );
}
void WorldSession :: HandleSetDungeonDifficultyOpcode ( WorldPackets :: Misc :: SetDungeonDifficulty & setDungeonDifficulty )
{
DifficultyEntry const * difficultyEntry = sDifficultyStore . LookupEntry ( setDungeonDifficulty . DifficultyID );
if ( ! difficultyEntry )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent an invalid instance mode %d!" ,
_player -> GetGUID (). ToString (). c_str (), setDungeonDifficulty . DifficultyID );
return ;
}
if ( difficultyEntry -> InstanceType != MAP_INSTANCE )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent an non-dungeon instance mode %d!" ,
_player -> GetGUID (). ToString (). c_str (), difficultyEntry -> ID );
return ;
}
if ( ! ( difficultyEntry -> Flags & DIFFICULTY_FLAG_CAN_SELECT ))
{
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: player %s sent unselectable instance mode %d!" ,
2015-01-19 00:06:15 +00:00
_player -> GetGUID (). ToString (). c_str (), difficultyEntry -> ID );
return ;
}
Difficulty difficultyID = Difficulty ( difficultyEntry -> ID );
if ( difficultyID == _player -> GetDungeonDifficultyID ())
return ;
// cannot reset while in an instance
Map * map = _player -> FindMap ();
if ( map && map -> IsDungeon ())
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: player (Name: %s, %s) tried to reset the instance while player is inside!" ,
_player -> GetName (). c_str (), _player -> GetGUID (). ToString (). c_str ());
return ;
}
Group * group = _player -> GetGroup ();
if ( group )
{
if ( group -> IsLeader ( _player -> GetGUID ()))
{
2020-08-14 17:06:03 +02:00
for ( GroupReference * itr = group -> GetFirstMember (); itr != nullptr ; itr = itr -> next ())
2015-01-19 00:06:15 +00:00
{
Player * groupGuy = itr -> GetSource ();
if ( ! groupGuy )
continue ;
if ( ! groupGuy -> IsInMap ( groupGuy ))
return ;
if ( groupGuy -> GetMap () -> IsNonRaidDungeon ())
{
2020-04-05 14:28:24 +02:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: player %s tried to reset the instance while group member (Name: %s, %s) is inside!" ,
2015-01-19 00:06:15 +00:00
_player -> GetGUID (). ToString (). c_str (), groupGuy -> GetName (). c_str (), groupGuy -> GetGUID (). ToString (). c_str ());
return ;
}
}
// the difficulty is set even if the instances can't be reset
//_player->SendDungeonDifficulty(true);
group -> ResetInstances ( INSTANCE_RESET_CHANGE_DIFFICULTY , false , false , _player );
group -> SetDungeonDifficultyID ( difficultyID );
}
}
else
{
_player -> ResetInstances ( INSTANCE_RESET_CHANGE_DIFFICULTY , false , false );
_player -> SetDungeonDifficultyID ( difficultyID );
_player -> SendDungeonDifficulty ();
}
}
void WorldSession :: HandleSetRaidDifficultyOpcode ( WorldPackets :: Misc :: SetRaidDifficulty & setRaidDifficulty )
{
DifficultyEntry const * difficultyEntry = sDifficultyStore . LookupEntry ( setRaidDifficulty . DifficultyID );
if ( ! difficultyEntry )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent an invalid instance mode %u!" ,
_player -> GetGUID (). ToString (). c_str (), setRaidDifficulty . DifficultyID );
return ;
}
if ( difficultyEntry -> InstanceType != MAP_RAID )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent an non-dungeon instance mode %u!" ,
_player -> GetGUID (). ToString (). c_str (), difficultyEntry -> ID );
return ;
}
if ( ! ( difficultyEntry -> Flags & DIFFICULTY_FLAG_CAN_SELECT ))
{
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: player %s sent unselectable instance mode %u!" ,
2015-01-19 00:06:15 +00:00
_player -> GetGUID (). ToString (). c_str (), difficultyEntry -> ID );
return ;
}
if ((( difficultyEntry -> Flags & DIFFICULTY_FLAG_LEGACY ) >> 5 ) != setRaidDifficulty . Legacy )
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetDungeonDifficultyOpcode: %s sent not matching legacy difficulty %u!" ,
_player -> GetGUID (). ToString (). c_str (), difficultyEntry -> ID );
return ;
}
Difficulty difficultyID = Difficulty ( difficultyEntry -> ID );
if ( difficultyID == ( setRaidDifficulty . Legacy ? _player -> GetLegacyRaidDifficultyID () : _player -> GetRaidDifficultyID ()))
return ;
// cannot reset while in an instance
Map * map = _player -> FindMap ();
if ( map && map -> IsDungeon ())
{
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetRaidDifficultyOpcode: player (Name: %s, %s) tried to reset the instance while player is inside!" ,
_player -> GetName (). c_str (), _player -> GetGUID (). ToString (). c_str ());
return ;
}
Group * group = _player -> GetGroup ();
if ( group )
{
if ( group -> IsLeader ( _player -> GetGUID ()))
{
2020-08-14 17:06:03 +02:00
for ( GroupReference * itr = group -> GetFirstMember (); itr != nullptr ; itr = itr -> next ())
2015-01-19 00:06:15 +00:00
{
Player * groupGuy = itr -> GetSource ();
if ( ! groupGuy )
continue ;
if ( ! groupGuy -> IsInMap ( groupGuy ))
return ;
if ( groupGuy -> GetMap () -> IsRaid ())
{
2020-04-04 19:16:37 +02:00
TC_LOG_DEBUG ( "network" , "WorldSession::HandleSetRaidDifficultyOpcode: player %s tried to reset the instance while group member (Name: %s, %s) is inside!" ,
2015-01-19 00:06:15 +00:00
_player -> GetGUID (). ToString (). c_str (), groupGuy -> GetName (). c_str (), groupGuy -> GetGUID (). ToString (). c_str ());
return ;
}
}
// the difficulty is set even if the instances can't be reset
group -> ResetInstances ( INSTANCE_RESET_CHANGE_DIFFICULTY , true , setRaidDifficulty . Legacy != 0 , _player );
if ( setRaidDifficulty . Legacy )
group -> SetLegacyRaidDifficultyID ( difficultyID );
else
group -> SetRaidDifficultyID ( difficultyID );
}
}
else
{
_player -> ResetInstances ( INSTANCE_RESET_CHANGE_DIFFICULTY , true , setRaidDifficulty . Legacy != 0 );
if ( setRaidDifficulty . Legacy )
_player -> SetLegacyRaidDifficultyID ( difficultyID );
else
_player -> SetRaidDifficultyID ( difficultyID );
_player -> SendRaidDifficulty ( setRaidDifficulty . Legacy != 0 );
}
}
2016-02-03 00:20:07 +01:00
void WorldSession :: HandleSetTaxiBenchmark ( WorldPackets :: Misc :: SetTaxiBenchmarkMode & packet )
2015-01-19 00:06:15 +00:00
{
2019-06-03 20:40:34 +02:00
if ( packet . Enable )
_player -> AddPlayerFlag ( PLAYER_FLAGS_TAXI_BENCHMARK );
else
_player -> RemovePlayerFlag ( PLAYER_FLAGS_TAXI_BENCHMARK );
2015-01-19 00:06:15 +00:00
}
void WorldSession :: HandleGuildSetFocusedAchievement ( WorldPackets :: Achievement :: GuildSetFocusedAchievement & setFocusedAchievement )
{
if ( Guild * guild = sGuildMgr -> GetGuildById ( _player -> GetGuildId ()))
guild -> GetAchievementMgr (). SendAchievementInfo ( _player , setFocusedAchievement . AchievementID );
}
2020-09-19 12:44:42 +02:00
void WorldSession :: HandleServerTimeOffsetRequest ( WorldPackets :: Misc :: ServerTimeOffsetRequest & /*request*/ )
2015-01-19 00:06:15 +00:00
{
2020-09-19 12:44:42 +02:00
WorldPackets :: Misc :: ServerTimeOffset response ;
2021-04-06 19:10:28 +02:00
response . Time = GameTime :: GetGameTimeSystemPoint ();
2015-01-19 00:06:15 +00:00
SendPacket ( response . Write ());
}
2015-07-28 19:09:20 +02:00
void WorldSession :: HandleInstanceLockResponse ( WorldPackets :: Instance :: InstanceLockResponse & packet )
2015-01-19 00:06:15 +00:00
{
if ( ! _player -> HasPendingBind ())
{
2020-04-05 14:28:24 +02:00
TC_LOG_INFO ( "network" , "InstanceLockResponse: Player %s %s tried to bind himself/teleport to graveyard without a pending bind!" ,
2015-01-19 00:06:15 +00:00
_player -> GetName (). c_str (), _player -> GetGUID (). ToString (). c_str ());
return ;
}
2015-07-28 19:09:20 +02:00
if ( packet . AcceptLock )
2015-01-19 00:06:15 +00:00
_player -> BindToInstance ();
else
_player -> RepopAtGraveyard ();
_player -> SetPendingBind ( 0 , 0 );
}
void WorldSession :: HandleViolenceLevel ( WorldPackets :: Misc :: ViolenceLevel & /*violenceLevel*/ )
{
// do something?
}
2015-04-13 00:21:21 +02:00
void WorldSession :: HandleObjectUpdateFailedOpcode ( WorldPackets :: Misc :: ObjectUpdateFailed & objectUpdateFailed )
2015-01-19 00:06:15 +00:00
{
2015-04-13 00:21:21 +02:00
TC_LOG_ERROR ( "network" , "Object update failed for %s for player %s (%s)" , objectUpdateFailed . ObjectGUID . ToString (). c_str (), GetPlayerName (). c_str (), _player -> GetGUID (). ToString (). c_str ());
2015-01-19 00:06:15 +00:00
// If create object failed for current player then client will be stuck on loading screen
2015-04-13 00:21:21 +02:00
if ( _player -> GetGUID () == objectUpdateFailed . ObjectGUID )
2015-01-19 00:06:15 +00:00
{
LogoutPlayer ( true );
return ;
}
// Pretend we've never seen this object
2015-04-13 00:21:21 +02:00
_player -> m_clientGUIDs . erase ( objectUpdateFailed . ObjectGUID );
}
void WorldSession :: HandleObjectUpdateRescuedOpcode ( WorldPackets :: Misc :: ObjectUpdateRescued & objectUpdateRescued )
{
TC_LOG_ERROR ( "network" , "Object update rescued for %s for player %s (%s)" , objectUpdateRescued . ObjectGUID . ToString (). c_str (), GetPlayerName (). c_str (), _player -> GetGUID (). ToString (). c_str ());
// Client received values update after destroying object
// re-register object in m_clientGUIDs to send DestroyObject on next visibility update
_player -> m_clientGUIDs . insert ( objectUpdateRescued . ObjectGUID );
2015-01-19 00:06:15 +00:00
}
2015-05-19 02:55:53 +01:00
void WorldSession :: HandleSaveCUFProfiles ( WorldPackets :: Misc :: SaveCUFProfiles & packet )
2015-01-19 00:06:15 +00:00
{
2015-05-19 02:55:53 +01:00
if ( packet . CUFProfiles . size () > MAX_CUF_PROFILES )
2015-01-19 00:06:15 +00:00
{
TC_LOG_ERROR ( "entities.player" , "HandleSaveCUFProfiles - %s tried to save more than %i CUF profiles. Hacking attempt?" , GetPlayerName (). c_str (), MAX_CUF_PROFILES );
return ;
}
2015-05-19 02:55:53 +01:00
for ( uint8 i = 0 ; i < packet . CUFProfiles . size (); ++ i )
GetPlayer () -> SaveCUFProfile ( i , std :: move ( packet . CUFProfiles [ i ]));
2015-01-19 00:06:15 +00:00
2015-05-19 02:55:53 +01:00
for ( uint8 i = packet . CUFProfiles . size (); i < MAX_CUF_PROFILES ; ++ i )
GetPlayer () -> SaveCUFProfile ( i , nullptr );
2015-01-19 00:06:15 +00:00
}
void WorldSession :: SendLoadCUFProfiles ()
{
Player * player = GetPlayer ();
2015-05-19 02:55:53 +01:00
WorldPackets :: Misc :: LoadCUFProfiles loadCUFProfiles ;
2015-01-19 00:06:15 +00:00
2015-05-19 02:55:53 +01:00
for ( uint8 i = 0 ; i < MAX_CUF_PROFILES ; i ++ )
2015-05-19 23:30:09 +01:00
if ( CUFProfile * cufProfile = player -> GetCUFProfile ( i ))
loadCUFProfiles . CUFProfiles . push_back ( cufProfile );
2015-05-19 02:55:53 +01:00
SendPacket ( loadCUFProfiles . Write ());
2015-01-19 00:06:15 +00:00
}
2015-08-08 15:15:14 +02:00
void WorldSession :: HandleSetAdvancedCombatLogging ( WorldPackets :: ClientConfig :: SetAdvancedCombatLogging & setAdvancedCombatLogging )
{
_player -> SetAdvancedCombatLogging ( setAdvancedCombatLogging . Enable );
}
2015-12-19 23:43:39 +01:00
2021-04-09 20:57:47 +02:00
void WorldSession :: HandleMountSpecialAnimOpcode ( WorldPackets :: Misc :: MountSpecial & mountSpecial )
2015-12-19 23:43:39 +01:00
{
WorldPackets :: Misc :: SpecialMountAnim specialMountAnim ;
specialMountAnim . UnitGUID = _player -> GetGUID ();
2021-04-09 20:57:47 +02:00
std :: copy ( mountSpecial . SpellVisualKitIDs . begin (), mountSpecial . SpellVisualKitIDs . end (), std :: back_inserter ( specialMountAnim . SpellVisualKitIDs ));
2015-12-19 23:43:39 +01:00
GetPlayer () -> SendMessageToSet ( specialMountAnim . Write (), false );
}
2016-10-01 13:48:16 +02:00
void WorldSession :: HandleMountSetFavorite ( WorldPackets :: Misc :: MountSetFavorite & mountSetFavorite )
{
_collectionMgr -> MountSetFavorite ( mountSetFavorite . MountSpellID , mountSetFavorite . IsFavorite );
}
2017-06-04 16:51:47 +02:00
2017-09-06 18:36:29 +02:00
void WorldSession :: HandleCloseInteraction ( WorldPackets :: Misc :: CloseInteraction & closeInteraction )
2017-08-14 00:42:02 +03:00
{
2017-09-06 18:36:29 +02:00
if ( _player -> PlayerTalkClass -> GetInteractionData (). SourceGuid == closeInteraction . SourceGuid )
_player -> PlayerTalkClass -> GetInteractionData (). Reset ();
2017-08-14 00:42:02 +03:00
}
2021-10-12 00:16:20 +02:00
void WorldSession :: HandleConversationLineStarted ( WorldPackets :: Misc :: ConversationLineStarted & conversationLineStarted )
{
if ( Conversation * convo = ObjectAccessor :: GetConversation ( * _player , conversationLineStarted . ConversationGUID ))
sScriptMgr -> OnConversationLineStarted ( convo , conversationLineStarted . LineID , _player );
}
2021-11-12 21:53:40 +01:00
void WorldSession :: HandleRequestLatestSplashScreen ( WorldPackets :: Misc :: RequestLatestSplashScreen & /*requestLatestSplashScreen*/ )
{
UISplashScreenEntry const * splashScreen = nullptr ;
for ( auto itr = sUISplashScreenStore . begin (); itr != sUISplashScreenStore . end (); ++ itr )
{
if ( PlayerConditionEntry const * playerCondition = sPlayerConditionStore . LookupEntry ( itr -> CharLevelConditionID ))
if ( ! ConditionMgr :: IsPlayerMeetingCondition ( _player , playerCondition ))
continue ;
splashScreen = * itr ;
}
WorldPackets :: Misc :: SplashScreenShowLatest splashScreenShowLatest ;
splashScreenShowLatest . UISplashScreenID = splashScreen ? splashScreen -> ID : 0 ;
SendPacket ( splashScreenShowLatest . Write ());
}