2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "Database/DatabaseEnv.h"
22 #include "Database/DatabaseImpl.h"
23 #include "WorldPacket.h"
29 #include "ObjectMgr.h"
30 #include "WorldSession.h"
31 #include "Auth/BigNumber.h"
32 #include "Auth/Sha1.h"
33 #include "UpdateData.h"
36 #include "ScriptMgr.h"
37 #include <zlib/zlib.h>
38 #include "ObjectAccessor.h"
40 #include "BattleGround/BattleGround.h"
41 #include "OutdoorPvP/OutdoorPvP.h"
44 #include "SocialMgr.h"
47 void WorldSession::HandleRepopRequestOpcode(WorldPacket
& recv_data
)
49 DEBUG_LOG("WORLD: Recvd CMSG_REPOP_REQUEST Message");
51 recv_data
.read_skip
<uint8
>();
53 if (GetPlayer()->isAlive() || GetPlayer()->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_GHOST
))
56 // the world update order is sessions, players, creatures
57 // the netcode runs in parallel with all of these
58 // creatures can kill players
59 // so if the server is lagging enough the player can
60 // release spirit after he's killed but before he is updated
61 if (GetPlayer()->getDeathState() == JUST_DIED
)
63 DEBUG_LOG("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
64 GetPlayer()->KillPlayer();
67 // this is spirit release confirm?
68 GetPlayer()->RemovePet(PET_SAVE_REAGENTS
);
69 GetPlayer()->BuildPlayerRepop();
70 GetPlayer()->RepopAtGraveyard();
73 void WorldSession::HandleWhoOpcode(WorldPacket
& recv_data
)
75 DEBUG_LOG("WORLD: Recvd CMSG_WHO Message");
76 // recv_data.hexlike();
78 uint32 clientcount
= 0;
80 uint32 level_min
, level_max
, racemask
, classmask
, zones_count
, str_count
;
81 uint32 zoneids
[10]; // 10 is client limit
82 std::string player_name
, guild_name
;
84 recv_data
>> level_min
; // maximal player level, default 0
85 recv_data
>> level_max
; // minimal player level, default 100 (MAX_LEVEL)
86 recv_data
>> player_name
; // player name, case sensitive...
88 recv_data
>> guild_name
; // guild name, case sensitive...
90 recv_data
>> racemask
; // race mask
91 recv_data
>> classmask
; // class mask
92 recv_data
>> zones_count
; // zones count, client limit=10 (2.0.10)
95 return; // can't be received from real client or broken packet
97 for (uint32 i
= 0; i
< zones_count
; ++i
)
100 recv_data
>> temp
; // zone id, 0 if zone is unknown...
102 DEBUG_LOG("Zone %u: %u", i
, zoneids
[i
]);
105 recv_data
>> str_count
; // user entered strings count, client limit=4 (checked on 2.0.10)
108 return; // can't be received from real client or broken packet
110 DEBUG_LOG("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min
, level_max
, player_name
.c_str(), guild_name
.c_str(), racemask
, classmask
, zones_count
, str_count
);
112 std::wstring str
[4]; // 4 is client limit
113 for (uint32 i
= 0; i
< str_count
; ++i
)
116 recv_data
>> temp
; // user entered string, it used as universal search pattern(guild+player name)?
118 if (!Utf8toWStr(temp
, str
[i
]))
123 DEBUG_LOG("String %u: %s", i
, temp
.c_str());
126 std::wstring wplayer_name
;
127 std::wstring wguild_name
;
128 if (!(Utf8toWStr(player_name
, wplayer_name
) && Utf8toWStr(guild_name
, wguild_name
)))
130 wstrToLower(wplayer_name
);
131 wstrToLower(wguild_name
);
133 // client send in case not set max level value 100 but mangos support 255 max level,
134 // update it to show GMs with characters after 100 level
135 if (level_max
>= MAX_LEVEL
)
136 level_max
= STRONG_MAX_LEVEL
;
138 Team team
= _player
->GetTeam();
139 uint32 security
= GetSecurity();
140 bool allowTwoSideWhoList
= sWorld
.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
);
141 AccountTypes gmLevelInWhoList
= (AccountTypes
)sWorld
.getConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST
);
143 WorldPacket
data(SMSG_WHO
, 50); // guess size
144 data
<< uint32(clientcount
); // clientcount place holder, listed count
145 data
<< uint32(clientcount
); // clientcount place holder, online count
147 // TODO: Guard Player map
148 HashMapHolder
<Player
>::MapType
& m
= sObjectAccessor
.GetPlayers();
149 for (HashMapHolder
<Player
>::MapType::const_iterator itr
= m
.begin(); itr
!= m
.end(); ++itr
)
151 Player
* pl
= itr
->second
;
153 if (security
== SEC_PLAYER
)
155 // player can see member of other team only if CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
156 if (pl
->GetTeam() != team
&& !allowTwoSideWhoList
)
159 // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
160 if (pl
->GetSession()->GetSecurity() > gmLevelInWhoList
)
164 // do not process players which are not in world
165 if (!pl
->IsInWorld())
168 // check if target is globally visible for player
169 if (!pl
->IsVisibleGloballyFor(_player
))
172 // check if target's level is in level range
173 uint32 lvl
= pl
->getLevel();
174 if (lvl
< level_min
|| lvl
> level_max
)
177 // check if class matches classmask
178 uint32 class_
= pl
->getClass();
179 if (!(classmask
& (1 << class_
)))
182 // check if race matches racemask
183 uint32 race
= pl
->getRace();
184 if (!(racemask
& (1 << race
)))
187 uint32 pzoneid
= pl
->GetZoneId();
188 uint8 gender
= pl
->getGender();
191 for (uint32 i
= 0; i
< zones_count
; ++i
)
193 if (zoneids
[i
] == pzoneid
)
204 std::string pname
= pl
->GetName();
206 if (!Utf8toWStr(pname
, wpname
))
210 if (!(wplayer_name
.empty() || wpname
.find(wplayer_name
) != std::wstring::npos
))
213 std::string gname
= sGuildMgr
.GetGuildNameById(pl
->GetGuildId());
215 if (!Utf8toWStr(gname
, wgname
))
219 if (!(wguild_name
.empty() || wgname
.find(wguild_name
) != std::wstring::npos
))
223 if (AreaTableEntry
const* areaEntry
= GetAreaEntryByAreaID(pzoneid
))
224 aname
= areaEntry
->area_name
[GetSessionDbcLocale()];
227 for (uint32 i
= 0; i
< str_count
; ++i
)
231 if (wgname
.find(str
[i
]) != std::wstring::npos
||
232 wpname
.find(str
[i
]) != std::wstring::npos
||
233 Utf8FitTo(aname
, str
[i
]))
244 data
<< pname
; // player name
245 data
<< gname
; // guild name
246 data
<< uint32(lvl
); // player level
247 data
<< uint32(class_
); // player class
248 data
<< uint32(race
); // player race
249 data
<< uint8(gender
); // player gender
250 data
<< uint32(pzoneid
); // player zone id
252 // 50 is maximum player count sent to client
253 if ((++clientcount
) == 50)
257 uint32 count
= m
.size();
258 data
.put(0, clientcount
); // insert right count, listed count
259 data
.put(4, count
> 50 ? count
: clientcount
); // insert right count, online count
262 DEBUG_LOG("WORLD: Send SMSG_WHO Message");
265 void WorldSession::HandleLogoutRequestOpcode(WorldPacket
& /*recv_data*/)
267 DEBUG_LOG("WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity());
269 if (ObjectGuid lootGuid
= GetPlayer()->GetLootGuid())
270 DoLootRelease(lootGuid
);
272 // Can not logout if...
273 if (GetPlayer()->isInCombat() || //...is in combat
274 GetPlayer()->duel
|| //...is in Duel
275 //...is jumping ...is falling
276 GetPlayer()->m_movementInfo
.HasMovementFlag(MovementFlags(MOVEFLAG_FALLING
| MOVEFLAG_FALLINGFAR
)))
278 WorldPacket
data(SMSG_LOGOUT_RESPONSE
, 5);
286 // instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in mangosd.conf
287 if (GetPlayer()->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_RESTING
) || GetPlayer()->IsTaxiFlying() ||
288 GetSecurity() >= (AccountTypes
)sWorld
.getConfig(CONFIG_UINT32_INSTANT_LOGOUT
))
294 // not set flags if player can't free move to prevent lost state at logout cancel
295 if (GetPlayer()->CanFreeMove())
297 float height
= GetPlayer()->GetTerrain()->GetHeight(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY(), GetPlayer()->GetPositionZ());
298 if ((GetPlayer()->GetPositionZ() < height
+ 0.1f
) && !(GetPlayer()->IsInWater()))
299 GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT
);
302 GetPlayer()->BuildForceMoveRootPacket(&data
, true, 2);
304 GetPlayer()->SetFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_STUNNED
);
307 WorldPacket
data(SMSG_LOGOUT_RESPONSE
, 5);
311 LogoutRequest(time(NULL
));
314 void WorldSession::HandlePlayerLogoutOpcode(WorldPacket
& /*recv_data*/)
316 DEBUG_LOG("WORLD: Recvd CMSG_PLAYER_LOGOUT Message");
319 void WorldSession::HandleLogoutCancelOpcode(WorldPacket
& /*recv_data*/)
321 DEBUG_LOG("WORLD: Recvd CMSG_LOGOUT_CANCEL Message");
325 WorldPacket
data(SMSG_LOGOUT_CANCEL_ACK
, 0);
328 // not remove flags if can't free move - its not set in Logout request code.
329 if (GetPlayer()->CanFreeMove())
331 //! we can move again
332 GetPlayer()->BuildForceMoveRootPacket(&data
, false, 0);
336 GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND
);
339 GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS
, UNIT_FLAG_STUNNED
);
342 DEBUG_LOG("WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message");
345 void WorldSession::HandleTogglePvP(WorldPacket
& recv_data
)
347 // this opcode can be used in two ways: Either set explicit new status or toggle old status
348 if (recv_data
.size() == 1)
351 recv_data
>> newPvPStatus
;
352 GetPlayer()->ApplyModFlag(PLAYER_FLAGS
, PLAYER_FLAGS_IN_PVP
, newPvPStatus
);
353 GetPlayer()->ApplyModFlag(PLAYER_FLAGS
, PLAYER_FLAGS_PVP_TIMER
, !newPvPStatus
);
357 GetPlayer()->ToggleFlag(PLAYER_FLAGS
, PLAYER_FLAGS_IN_PVP
);
358 GetPlayer()->ToggleFlag(PLAYER_FLAGS
, PLAYER_FLAGS_PVP_TIMER
);
361 if (GetPlayer()->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_IN_PVP
))
363 if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo
.endTimer
!= 0)
364 GetPlayer()->UpdatePvP(true, true);
368 if (!GetPlayer()->pvpInfo
.inHostileArea
&& GetPlayer()->IsPvP())
369 GetPlayer()->pvpInfo
.endTimer
= time(NULL
); // start toggle-off
373 void WorldSession::HandleZoneUpdateOpcode(WorldPacket
& recv_data
)
376 recv_data
>> newZone
;
378 DETAIL_LOG("WORLD: Recvd ZONE_UPDATE: %u", newZone
);
380 // use server size data
381 uint32 newzone
, newarea
;
382 GetPlayer()->GetZoneAndAreaId(newzone
, newarea
);
383 GetPlayer()->UpdateZone(newzone
, newarea
);
386 void WorldSession::HandleSetTargetOpcode(WorldPacket
& recv_data
)
388 // When this packet send?
392 _player
->SetTargetGuid(guid
);
394 // update reputation list if need
395 Unit
* unit
= ObjectAccessor::GetUnit(*_player
, guid
); // can select group members at diff maps
399 if (FactionTemplateEntry
const* factionTemplateEntry
= sFactionTemplateStore
.LookupEntry(unit
->getFaction()))
400 _player
->GetReputationMgr().SetVisible(factionTemplateEntry
);
403 void WorldSession::HandleSetSelectionOpcode(WorldPacket
& recv_data
)
408 _player
->SetSelectionGuid(guid
);
410 // update reputation list if need
411 Unit
* unit
= ObjectAccessor::GetUnit(*_player
, guid
); // can select group members at diff maps
415 if (FactionTemplateEntry
const* factionTemplateEntry
= sFactionTemplateStore
.LookupEntry(unit
->getFaction()))
416 _player
->GetReputationMgr().SetVisible(factionTemplateEntry
);
419 void WorldSession::HandleStandStateChangeOpcode(WorldPacket
& recv_data
)
421 // DEBUG_LOG( "WORLD: Received CMSG_STANDSTATECHANGE" ); -- too many spam in log at lags/debug stop
423 recv_data
>> animstate
;
425 _player
->SetStandState(animstate
);
428 void WorldSession::HandleContactListOpcode(WorldPacket
& recv_data
)
430 DEBUG_LOG("WORLD: Received CMSG_CONTACT_LIST");
433 DEBUG_LOG("unk value is %u", unk
);
434 _player
->GetSocial()->SendSocialList();
437 void WorldSession::HandleAddFriendOpcode(WorldPacket
& recv_data
)
439 DEBUG_LOG("WORLD: Received CMSG_ADD_FRIEND");
441 std::string friendName
= GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN
);
442 std::string friendNote
;
444 recv_data
>> friendName
;
446 recv_data
>> friendNote
;
448 if (!normalizePlayerName(friendName
))
451 CharacterDatabase
.escape_string(friendName
); // prevent SQL injection - normal name don't must changed by this call
453 DEBUG_LOG("WORLD: %s asked to add friend : '%s'",
454 GetPlayer()->GetName(), friendName
.c_str());
456 CharacterDatabase
.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack
, GetAccountId(), friendNote
, "SELECT guid, race FROM characters WHERE name = '%s'", friendName
.c_str());
459 void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult
* result
, uint32 accountId
, std::string friendNote
)
464 uint32 friendLowGuid
= (*result
)[0].GetUInt32();
465 ObjectGuid friendGuid
= ObjectGuid(HIGHGUID_PLAYER
, friendLowGuid
);
466 Team team
= Player::TeamForRace((*result
)[1].GetUInt8());
470 WorldSession
* session
= sWorld
.FindSession(accountId
);
471 if (!session
|| !session
->GetPlayer())
474 FriendsResult friendResult
= FRIEND_NOT_FOUND
;
477 if (friendGuid
== session
->GetPlayer()->GetObjectGuid())
478 friendResult
= FRIEND_SELF
;
479 else if (session
->GetPlayer()->GetTeam() != team
&& !sWorld
.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND
) && session
->GetSecurity() < SEC_MODERATOR
)
480 friendResult
= FRIEND_ENEMY
;
481 else if (session
->GetPlayer()->GetSocial()->HasFriend(friendGuid
))
482 friendResult
= FRIEND_ALREADY
;
485 Player
* pFriend
= ObjectAccessor::FindPlayer(friendGuid
);
486 if (pFriend
&& pFriend
->IsInWorld() && pFriend
->IsVisibleGloballyFor(session
->GetPlayer()))
487 friendResult
= FRIEND_ADDED_ONLINE
;
489 friendResult
= FRIEND_ADDED_OFFLINE
;
491 if (!session
->GetPlayer()->GetSocial()->AddToSocialList(friendGuid
, false))
493 friendResult
= FRIEND_LIST_FULL
;
494 DEBUG_LOG("WORLD: %s's friend list is full.", session
->GetPlayer()->GetName());
497 session
->GetPlayer()->GetSocial()->SetFriendNote(friendGuid
, friendNote
);
501 sSocialMgr
.SendFriendStatus(session
->GetPlayer(), friendResult
, friendGuid
, false);
503 DEBUG_LOG("WORLD: Sent (SMSG_FRIEND_STATUS)");
506 void WorldSession::HandleDelFriendOpcode(WorldPacket
& recv_data
)
508 ObjectGuid friendGuid
;
510 DEBUG_LOG("WORLD: Received CMSG_DEL_FRIEND");
512 recv_data
>> friendGuid
;
514 _player
->GetSocial()->RemoveFromSocialList(friendGuid
, false);
516 sSocialMgr
.SendFriendStatus(GetPlayer(), FRIEND_REMOVED
, friendGuid
, false);
518 DEBUG_LOG("WORLD: Sent motd (SMSG_FRIEND_STATUS)");
521 void WorldSession::HandleAddIgnoreOpcode(WorldPacket
& recv_data
)
523 DEBUG_LOG("WORLD: Received CMSG_ADD_IGNORE");
525 std::string IgnoreName
= GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN
);
527 recv_data
>> IgnoreName
;
529 if (!normalizePlayerName(IgnoreName
))
532 CharacterDatabase
.escape_string(IgnoreName
); // prevent SQL injection - normal name don't must changed by this call
534 DEBUG_LOG("WORLD: %s asked to Ignore: '%s'",
535 GetPlayer()->GetName(), IgnoreName
.c_str());
537 CharacterDatabase
.AsyncPQuery(&WorldSession::HandleAddIgnoreOpcodeCallBack
, GetAccountId(), "SELECT guid FROM characters WHERE name = '%s'", IgnoreName
.c_str());
540 void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult
* result
, uint32 accountId
)
545 uint32 ignoreLowGuid
= (*result
)[0].GetUInt32();
546 ObjectGuid ignoreGuid
= ObjectGuid(HIGHGUID_PLAYER
, ignoreLowGuid
);
550 WorldSession
* session
= sWorld
.FindSession(accountId
);
551 if (!session
|| !session
->GetPlayer())
554 FriendsResult ignoreResult
= FRIEND_IGNORE_NOT_FOUND
;
557 if (ignoreGuid
== session
->GetPlayer()->GetObjectGuid())
558 ignoreResult
= FRIEND_IGNORE_SELF
;
559 else if (session
->GetPlayer()->GetSocial()->HasIgnore(ignoreGuid
))
560 ignoreResult
= FRIEND_IGNORE_ALREADY
;
563 ignoreResult
= FRIEND_IGNORE_ADDED
;
566 if (!session
->GetPlayer()->GetSocial()->AddToSocialList(ignoreGuid
, true))
567 ignoreResult
= FRIEND_IGNORE_FULL
;
571 sSocialMgr
.SendFriendStatus(session
->GetPlayer(), ignoreResult
, ignoreGuid
, false);
573 DEBUG_LOG("WORLD: Sent (SMSG_FRIEND_STATUS)");
576 void WorldSession::HandleDelIgnoreOpcode(WorldPacket
& recv_data
)
578 ObjectGuid ignoreGuid
;
580 DEBUG_LOG("WORLD: Received CMSG_DEL_IGNORE");
582 recv_data
>> ignoreGuid
;
584 _player
->GetSocial()->RemoveFromSocialList(ignoreGuid
, true);
586 sSocialMgr
.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED
, ignoreGuid
, false);
588 DEBUG_LOG("WORLD: Sent motd (SMSG_FRIEND_STATUS)");
591 void WorldSession::HandleSetContactNotesOpcode(WorldPacket
& recv_data
)
593 DEBUG_LOG("CMSG_SET_CONTACT_NOTES");
596 recv_data
>> guid
>> note
;
597 _player
->GetSocial()->SetFriendNote(guid
, note
);
600 void WorldSession::HandleBugOpcode(WorldPacket
& recv_data
)
602 uint32 suggestion
, contentlen
, typelen
;
603 std::string content
, type
;
605 recv_data
>> suggestion
>> contentlen
>> content
;
607 recv_data
>> typelen
>> type
;
610 DEBUG_LOG("WORLD: Received CMSG_BUG [Bug Report]");
612 DEBUG_LOG("WORLD: Received CMSG_BUG [Suggestion]");
614 DEBUG_LOG("%s", type
.c_str());
615 DEBUG_LOG("%s", content
.c_str());
617 CharacterDatabase
.escape_string(type
);
618 CharacterDatabase
.escape_string(content
);
619 CharacterDatabase
.PExecute("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type
.c_str(), content
.c_str());
622 void WorldSession::HandleReclaimCorpseOpcode(WorldPacket
& recv_data
)
624 DETAIL_LOG("WORLD: Received CMSG_RECLAIM_CORPSE");
629 if (GetPlayer()->isAlive())
632 // do not allow corpse reclaim in arena
633 if (GetPlayer()->InArena())
636 // body not released yet
637 if (!GetPlayer()->HasFlag(PLAYER_FLAGS
, PLAYER_FLAGS_GHOST
))
640 Corpse
* corpse
= GetPlayer()->GetCorpse();
645 // prevent resurrect before 30-sec delay after body release not finished
646 if (corpse
->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse
->GetType() == CORPSE_RESURRECTABLE_PVP
) > time(NULL
))
649 if (!corpse
->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS
, true))
653 GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f
: 0.5f
);
656 GetPlayer()->SpawnCorpseBones();
659 void WorldSession::HandleResurrectResponseOpcode(WorldPacket
& recv_data
)
661 DETAIL_LOG("WORLD: Received CMSG_RESURRECT_RESPONSE");
668 if (GetPlayer()->isAlive())
673 GetPlayer()->clearResurrectRequestData(); // reject
677 if (!GetPlayer()->isRessurectRequestedBy(guid
))
680 GetPlayer()->ResurectUsingRequestData(); // will call spawncorpsebones
683 void WorldSession::HandleAreaTriggerOpcode(WorldPacket
& recv_data
)
685 DEBUG_LOG("WORLD: Received CMSG_AREATRIGGER");
689 recv_data
>> Trigger_ID
;
690 DEBUG_LOG("Trigger ID: %u", Trigger_ID
);
691 Player
* player
= GetPlayer();
693 if (player
->IsTaxiFlying())
695 DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", player
->GetName(), player
->GetGUIDLow(), Trigger_ID
);
699 AreaTriggerEntry
const* atEntry
= sAreaTriggerStore
.LookupEntry(Trigger_ID
);
702 DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", player
->GetName(), player
->GetGUIDLow(), Trigger_ID
);
706 // delta is safe radius
707 const float delta
= 5.0f
;
709 // check if player in the range of areatrigger
710 if (!IsPointInAreaTriggerZone(atEntry
, player
->GetMapId(), player
->GetPositionX(), player
->GetPositionY(), player
->GetPositionZ(), delta
))
712 DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", player
->GetName(), player
->GetGUIDLow(), Trigger_ID
);
716 if (sScriptMgr
.OnAreaTrigger(player
, atEntry
))
719 uint32 quest_id
= sObjectMgr
.GetQuestForAreaTrigger(Trigger_ID
);
720 if (quest_id
&& player
->isAlive() && player
->IsActiveQuest(quest_id
))
722 Quest
const* pQuest
= sObjectMgr
.GetQuestTemplate(quest_id
);
725 if (player
->GetQuestStatus(quest_id
) == QUEST_STATUS_INCOMPLETE
)
726 player
->AreaExploredOrEventHappens(quest_id
);
730 // enter to tavern, not overwrite city rest
731 if (sObjectMgr
.IsTavernAreaTrigger(Trigger_ID
))
733 // set resting flag we are in the inn
734 if (player
->GetRestType() != REST_TYPE_IN_CITY
)
735 player
->SetRestType(REST_TYPE_IN_TAVERN
, Trigger_ID
);
739 if (BattleGround
* bg
= player
->GetBattleGround())
741 bg
->HandleAreaTrigger(player
, Trigger_ID
);
744 else if (OutdoorPvP
* outdoorPvP
= sOutdoorPvPMgr
.GetScript(player
->GetCachedZoneId()))
746 if (outdoorPvP
->HandleAreaTrigger(player
, Trigger_ID
))
750 // NULL if all values default (non teleport trigger)
751 AreaTrigger
const* at
= sObjectMgr
.GetAreaTrigger(Trigger_ID
);
755 MapEntry
const* targetMapEntry
= sMapStore
.LookupEntry(at
->target_mapId
);
759 // ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases)
760 if (!player
->isAlive() && targetMapEntry
->IsDungeon())
762 int32 corpseMapId
= 0;
763 if (Corpse
* corpse
= player
->GetCorpse())
764 corpseMapId
= corpse
->GetMapId();
766 // check back way from corpse to entrance
767 uint32 instance_map
= corpseMapId
;
770 // most often fast case
771 if (instance_map
== targetMapEntry
->MapID
)
774 InstanceTemplate
const* instance
= ObjectMgr::GetInstanceTemplate(instance_map
);
775 instance_map
= instance
? instance
->parent
: 0;
777 while (instance_map
);
779 // corpse not in dungeon or some linked deep dungeons
782 WorldPacket
data(SMSG_AREA_TRIGGER_NO_CORPSE
);
783 player
->GetSession()->SendPacket(&data
);
787 // need find areatrigger to inner dungeon for landing point
788 if (at
->target_mapId
!= corpseMapId
)
790 if (AreaTrigger
const* corpseAt
= sObjectMgr
.GetMapEntranceTrigger(corpseMapId
))
793 targetMapEntry
= sMapStore
.LookupEntry(at
->target_mapId
);
797 // now we can resurrect player, and then check teleport requirements
798 player
->ResurrectPlayer(0.5f
);
799 player
->SpawnCorpseBones();
802 // teleport player (trigger requirement will be checked on TeleportTo)
803 player
->TeleportTo(at
->target_mapId
, at
->target_X
, at
->target_Y
, at
->target_Z
, at
->target_Orientation
, TELE_TO_NOT_LEAVE_TRANSPORT
, at
);
806 void WorldSession::HandleUpdateAccountData(WorldPacket
& recv_data
)
808 DETAIL_LOG("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
810 uint32 type
, timestamp
, decompressedSize
;
811 recv_data
>> type
>> timestamp
>> decompressedSize
;
813 DEBUG_LOG("UAD: type %u, time %u, decompressedSize %u", type
, timestamp
, decompressedSize
);
815 if (type
> NUM_ACCOUNT_DATA_TYPES
)
818 if (decompressedSize
== 0) // erase
820 SetAccountData(AccountDataType(type
), 0, "");
822 WorldPacket
data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE
, 4 + 4);
823 data
<< uint32(type
);
830 if (decompressedSize
> 0xFFFF)
832 recv_data
.rpos(recv_data
.wpos()); // unnneded warning spam in this case
833 sLog
.outError("UAD: Account data packet too big, size %u", decompressedSize
);
838 dest
.resize(decompressedSize
);
840 uLongf realSize
= decompressedSize
;
841 if (uncompress(const_cast<uint8
*>(dest
.contents()), &realSize
, const_cast<uint8
*>(recv_data
.contents() + recv_data
.rpos()), recv_data
.size() - recv_data
.rpos()) != Z_OK
)
843 recv_data
.rpos(recv_data
.wpos()); // unneded warning spam in this case
844 sLog
.outError("UAD: Failed to decompress account data");
848 recv_data
.rpos(recv_data
.wpos()); // uncompress read (recv_data.size() - recv_data.rpos())
853 SetAccountData(AccountDataType(type
), timestamp
, adata
);
855 WorldPacket
data(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE
, 4 + 4);
856 data
<< uint32(type
);
861 void WorldSession::HandleRequestAccountData(WorldPacket
& recv_data
)
863 DETAIL_LOG("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
868 DEBUG_LOG("RAD: type %u", type
);
870 if (type
> NUM_ACCOUNT_DATA_TYPES
)
873 AccountData
* adata
= GetAccountData(AccountDataType(type
));
875 uint32 size
= adata
->Data
.size();
877 uLongf destSize
= compressBound(size
);
880 dest
.resize(destSize
);
882 if (size
&& compress(const_cast<uint8
*>(dest
.contents()), &destSize
, (uint8
*)adata
->Data
.c_str(), size
) != Z_OK
)
884 DEBUG_LOG("RAD: Failed to compress account data");
888 dest
.resize(destSize
);
890 WorldPacket
data(SMSG_UPDATE_ACCOUNT_DATA
, 8 + 4 + 4 + 4 + destSize
);
891 data
<< (_player
? _player
->GetObjectGuid() : ObjectGuid());// player guid
892 data
<< uint32(type
); // type (0-7)
893 data
<< uint32(adata
->Time
); // unix time
894 data
<< uint32(size
); // decompressed length
895 data
.append(dest
); // compressed data
899 void WorldSession::HandleSetActionButtonOpcode(WorldPacket
& recv_data
)
901 DEBUG_LOG("WORLD: Received CMSG_SET_ACTION_BUTTON");
904 recv_data
>> button
>> packetData
;
906 uint32 action
= ACTION_BUTTON_ACTION(packetData
);
907 uint8 type
= ACTION_BUTTON_TYPE(packetData
);
909 DETAIL_LOG("BUTTON: %u ACTION: %u TYPE: %u", button
, action
, type
);
912 DETAIL_LOG("MISC: Remove action from button %u", button
);
913 GetPlayer()->removeActionButton(GetPlayer()->GetActiveSpec(), button
);
919 case ACTION_BUTTON_MACRO
:
920 case ACTION_BUTTON_CMACRO
:
921 DETAIL_LOG("MISC: Added Macro %u into button %u", action
, button
);
923 case ACTION_BUTTON_EQSET
:
924 DETAIL_LOG("MISC: Added EquipmentSet %u into button %u", action
, button
);
926 case ACTION_BUTTON_SPELL
:
927 DETAIL_LOG("MISC: Added Spell %u into button %u", action
, button
);
929 case ACTION_BUTTON_ITEM
:
930 DETAIL_LOG("MISC: Added Item %u into button %u", action
, button
);
933 sLog
.outError("MISC: Unknown action button type %u for action %u into button %u", type
, action
, button
);
936 GetPlayer()->addActionButton(GetPlayer()->m_activeSpec
, button
, action
, type
);
940 void WorldSession::HandleCompleteCinematic(WorldPacket
& /*recv_data*/)
942 DEBUG_LOG("WORLD: Player is watching cinema");
945 void WorldSession::HandleNextCinematicCamera(WorldPacket
& /*recv_data*/)
947 DEBUG_LOG("WORLD: Which movie to play");
950 void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket
& recv_data
)
952 /* WorldSession::Update( WorldTimer::getMSTime() );*/
953 DEBUG_LOG("WORLD: Time Lag/Synchronization Resent/Update");
957 recv_data
>> Unused
<uint32
>();
958 recv_data
.ReadGuidMask
<5, 1, 3, 7, 6, 0, 4, 2>(guid
);
959 recv_data
.ReadGuidBytes
<7, 1, 2, 4, 3, 6, 0, 5>(guid
);
965 recv_data >> time_skipped;
966 DEBUG_LOG( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
969 must be need use in mangos
970 We substract server Lags to move time ( AntiLags )
972 GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
976 void WorldSession::HandleFeatherFallAck(WorldPacket
& recv_data
)
978 DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
981 recv_data
.rfinish(); // prevent warnings spam
987 void WorldSession::HandleMoveUnRootAck(WorldPacket
& recv_data
)
990 recv_data
.rfinish(); // prevent warnings spam
996 void WorldSession::HandleMoveRootAck(WorldPacket
& recv_data
)
999 recv_data
.rfinish(); // prevent warnings spam
1005 void WorldSession::HandleSetActionBarTogglesOpcode(WorldPacket
& recv_data
)
1009 recv_data
>> ActionBar
;
1011 if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
1014 sLog
.outError("WorldSession::HandleSetActionBarToggles in not logged state with value: %u, ignored", uint32(ActionBar
));
1018 GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES
, 2, ActionBar
);
1021 void WorldSession::HandleWardenDataOpcode(WorldPacket
& recv_data
)
1023 recv_data
.read_skip
<uint8
>();
1027 DEBUG_LOG("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u", tmp);
1031 void WorldSession::HandlePlayedTime(WorldPacket
& recv_data
)
1034 recv_data
>> unk1
; // 0 or 1 expected
1036 WorldPacket
data(SMSG_PLAYED_TIME
, 4 + 4 + 1);
1037 data
<< uint32(_player
->GetTotalPlayedTime());
1038 data
<< uint32(_player
->GetLevelPlayedTime());
1039 data
<< uint8(unk1
); // 0 - will not show in chat frame
1043 void WorldSession::HandleInspectOpcode(WorldPacket
& recv_data
)
1047 DEBUG_LOG("Inspected guid is %s", guid
.GetString().c_str());
1049 _player
->SetSelectionGuid(guid
);
1051 Player
* plr
= sObjectMgr
.GetPlayer(guid
);
1052 if (!plr
) // wrong player
1055 WorldPacket
data(SMSG_INSPECT_RESULTS
, 50);
1056 data
<< plr
->GetObjectGuid();
1058 if (sWorld
.getConfig(CONFIG_BOOL_TALENTS_INSPECTING
) || _player
->isGameMaster())
1059 plr
->BuildPlayerTalentsInfoData(&data
);
1062 data
<< uint32(0); // unspentTalentPoints
1063 data
<< uint8(0); // talentGroupCount
1064 data
<< uint8(0); // talentGroupIndex
1067 plr
->BuildEnchantmentsInfoData(&data
);
1068 if (Guild
* guild
= sGuildMgr
.GetGuildById(plr
->GetGuildId()))
1070 data
<< guild
->GetObjectGuid();
1071 data
<< uint32(guild
->GetLevel());
1072 data
<< uint64(0/*guild->GetXP()*/);
1073 data
<< uint32(guild
->GetMemberSize()); // number of members
1079 void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket
& recv_data
)
1082 recv_data
.ReadGuidMask
<1, 5, 7, 3, 2, 4, 0, 6>(guid
);
1083 recv_data
.ReadGuidBytes
<4, 7, 0, 5, 1, 6, 2, 3>(guid
);
1085 Player
* player
= sObjectMgr
.GetPlayer(guid
);
1088 sLog
.outError("InspectHonorStats: WTF, player not found...");
1092 WorldPacket
data(SMSG_INSPECT_HONOR_STATS
, 18);
1093 data
.WriteGuidMask
<4, 3, 6, 2, 5, 0, 7, 1>(player
->GetObjectGuid());
1094 data
<< uint8(0); // rank
1095 data
<< uint16(player
->GetUInt16Value(PLAYER_FIELD_KILLS
, 1)); // yesterday kills
1096 data
<< uint16(player
->GetUInt16Value(PLAYER_FIELD_KILLS
, 0)); // today kills
1097 data
.WriteGuidBytes
<2, 0, 6, 3, 4, 1, 5>(player
->GetObjectGuid());
1098 data
<< uint32(player
->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS
));
1099 data
.WriteGuidBytes
<7>(player
->GetObjectGuid());
1104 void WorldSession::HandleWorldTeleportOpcode(WorldPacket
& recv_data
)
1106 // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
1107 // Received opcode CMSG_WORLD_TELEPORT
1108 // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
1117 recv_data
>> time
; // time in m.sec.
1119 recv_data
>> PositionX
;
1120 recv_data
>> PositionY
;
1121 recv_data
>> PositionZ
;
1122 recv_data
>> Orientation
; // o (3.141593 = 180 degrees)
1124 // DEBUG_LOG("Received opcode CMSG_WORLD_TELEPORT");
1126 if (GetPlayer()->IsTaxiFlying())
1128 DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore worldport command.", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
1132 DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time
/ 1000, mapid
, PositionX
, PositionY
, PositionZ
, Orientation
);
1134 if (GetSecurity() >= SEC_ADMINISTRATOR
)
1135 GetPlayer()->TeleportTo(mapid
, PositionX
, PositionY
, PositionZ
, Orientation
);
1137 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION
);
1138 DEBUG_LOG("Received worldport command from player %s", GetPlayer()->GetName());
1141 void WorldSession::HandleWhoisOpcode(WorldPacket
& recv_data
)
1143 DEBUG_LOG("Received opcode CMSG_WHOIS");
1144 std::string charname
;
1145 recv_data
>> charname
;
1147 if (GetSecurity() < SEC_ADMINISTRATOR
)
1149 SendNotification(LANG_YOU_NOT_HAVE_PERMISSION
);
1153 if (charname
.empty() || !normalizePlayerName(charname
))
1155 SendNotification(LANG_NEED_CHARACTER_NAME
);
1159 Player
* plr
= sObjectMgr
.GetPlayer(charname
.c_str());
1163 SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE
, charname
.c_str());
1167 uint32 accid
= plr
->GetSession()->GetAccountId();
1169 QueryResult
* result
= LoginDatabase
.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid
);
1172 SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND
, charname
.c_str());
1176 Field
* fields
= result
->Fetch();
1177 std::string acc
= fields
[0].GetCppString();
1180 std::string email
= fields
[1].GetCppString();
1183 std::string lastip
= fields
[2].GetCppString();
1187 std::string msg
= charname
+ "'s " + "account is " + acc
+ ", e-mail: " + email
+ ", last ip: " + lastip
;
1189 WorldPacket
data(SMSG_WHOIS
, msg
.size() + 1);
1191 _player
->GetSession()->SendPacket(&data
);
1195 DEBUG_LOG("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname
.c_str());
1198 void WorldSession::HandleComplainOpcode(WorldPacket
& recv_data
)
1200 DEBUG_LOG("WORLD: CMSG_COMPLAIN");
1201 recv_data
.hexlike();
1203 uint8 spam_type
; // 0 - mail, 1 - chat
1204 ObjectGuid spammerGuid
;
1209 std::string description
= "";
1210 recv_data
>> spam_type
; // unk 0x01 const, may be spam type (mail/chat)
1211 recv_data
>> spammerGuid
; // player guid
1215 recv_data
>> unk1
; // const 0
1216 recv_data
>> unk2
; // probably mail id
1217 recv_data
>> unk3
; // const 0
1220 recv_data
>> unk1
; // probably language
1221 recv_data
>> unk2
; // message type?
1222 recv_data
>> unk3
; // probably channel id
1223 recv_data
>> unk4
; // unk random value
1224 recv_data
>> description
; // spam description string (messagetype, channel name, player name, message)
1228 // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
1229 // if it's mail spam - ALL mails from this spammer automatically removed by client
1231 // Complaint Received message
1232 WorldPacket
data(SMSG_COMPLAIN_RESULT
, 1);
1236 DEBUG_LOG("REPORT SPAM: type %u, spammer %s, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type
, spammerGuid
.GetString().c_str(), unk1
, unk2
, unk3
, unk4
, description
.c_str());
1239 void WorldSession::HandleRealmSplitOpcode(WorldPacket
& recv_data
)
1241 DEBUG_LOG("CMSG_REALM_SPLIT");
1244 std::string split_date
= "01/01/01";
1247 WorldPacket
data(SMSG_REALM_SPLIT
, 4 + 4 + split_date
.size() + 1);
1249 data
<< uint32(0x00000000); // realm split state
1253 // 0x2 realm split pending
1256 // DEBUG_LOG("response sent %u", unk);
1259 void WorldSession::HandleFarSightOpcode(WorldPacket
& recv_data
)
1261 DEBUG_LOG("WORLD: CMSG_FAR_SIGHT");
1262 // recv_data.hexlike();
1267 WorldObject
* obj
= _player
->GetMap()->GetWorldObject(_player
->GetFarSightGuid());
1274 DEBUG_LOG("Removed FarSight from %s", _player
->GetGuidStr().c_str());
1275 _player
->GetCamera().ResetView(false);
1278 DEBUG_LOG("Added FarSight %s to %s", _player
->GetFarSightGuid().GetString().c_str(), _player
->GetGuidStr().c_str());
1279 _player
->GetCamera().SetView(obj
, false);
1284 void WorldSession::HandleSetTitleOpcode(WorldPacket
& recv_data
)
1286 DEBUG_LOG("CMSG_SET_TITLE");
1292 if (title
> 0 && title
< MAX_TITLE_INDEX
)
1294 if (!GetPlayer()->HasTitle(title
))
1300 GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE
, title
);
1303 void WorldSession::HandleTimeSyncResp(WorldPacket
& recv_data
)
1305 DEBUG_LOG("CMSG_TIME_SYNC_RESP");
1307 uint32 counter
, clientTicks
;
1308 recv_data
>> counter
>> clientTicks
;
1310 if (counter
!= _player
->m_timeSyncCounter
- 1)
1311 DEBUG_LOG("Wrong time sync counter from player %s (cheater?)", _player
->GetName());
1313 DEBUG_LOG("Time sync received: counter %u, client ticks %u, time since last sync %u", counter
, clientTicks
, clientTicks
- _player
->m_timeSyncClient
);
1315 uint32 ourTicks
= clientTicks
+ (WorldTimer::getMSTime() - _player
->m_timeSyncServer
);
1317 // diff should be small
1318 DEBUG_LOG("Our ticks: %u, diff %u, latency %u", ourTicks
, ourTicks
- clientTicks
, GetLatency());
1320 _player
->m_timeSyncClient
= clientTicks
;
1323 void WorldSession::HandleResetInstancesOpcode(WorldPacket
& /*recv_data*/)
1325 DEBUG_LOG("WORLD: CMSG_RESET_INSTANCES");
1327 if (Group
* pGroup
= _player
->GetGroup())
1329 if (pGroup
->IsLeader(_player
->GetObjectGuid()))
1330 pGroup
->ResetInstances(INSTANCE_RESET_ALL
, false, _player
);
1333 _player
->ResetInstances(INSTANCE_RESET_ALL
, false);
1336 void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket
& recv_data
)
1338 DEBUG_LOG("MSG_SET_DUNGEON_DIFFICULTY");
1343 if (mode
>= MAX_DUNGEON_DIFFICULTY
)
1345 sLog
.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player
->GetGUIDLow(), mode
);
1349 if (Difficulty(mode
) == _player
->GetDungeonDifficulty())
1352 // cannot reset while in an instance
1353 Map
* map
= _player
->GetMap();
1354 if (map
&& map
->IsDungeon())
1356 sLog
.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player
->GetGUIDLow());
1360 // Exception to set mode to normal for low-level players
1361 if (_player
->getLevel() < LEVELREQUIREMENT_HEROIC
&& mode
> REGULAR_DIFFICULTY
)
1364 if (Group
* pGroup
= _player
->GetGroup())
1366 if (pGroup
->IsLeader(_player
->GetObjectGuid()))
1368 // the difficulty is set even if the instances can't be reset
1369 //_player->SendDungeonDifficulty(true);
1370 pGroup
->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY
, false, _player
);
1371 pGroup
->SetDungeonDifficulty(Difficulty(mode
));
1376 _player
->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY
, false);
1377 _player
->SetDungeonDifficulty(Difficulty(mode
));
1381 void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket
& recv_data
)
1383 DEBUG_LOG("MSG_SET_RAID_DIFFICULTY");
1388 if (mode
>= MAX_RAID_DIFFICULTY
)
1390 sLog
.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player
->GetGUIDLow(), mode
);
1394 if (Difficulty(mode
) == _player
->GetRaidDifficulty())
1397 // cannot reset while in an instance
1398 Map
* map
= _player
->GetMap();
1399 if (map
&& map
->IsDungeon())
1401 sLog
.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player
->GetGUIDLow());
1405 // Exception to set mode to normal for low-level players
1406 if (_player
->getLevel() < LEVELREQUIREMENT_HEROIC
&& mode
> REGULAR_DIFFICULTY
)
1409 if (Group
* pGroup
= _player
->GetGroup())
1411 if (pGroup
->IsLeader(_player
->GetObjectGuid()))
1413 // the difficulty is set even if the instances can't be reset
1414 _player
->SendDungeonDifficulty(true);
1415 pGroup
->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY
, true, _player
);
1416 pGroup
->SetRaidDifficulty(Difficulty(mode
));
1421 _player
->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY
, true);
1422 _player
->SetRaidDifficulty(Difficulty(mode
));
1426 void WorldSession::HandleCancelMountAuraOpcode(WorldPacket
& /*recv_data*/)
1428 DEBUG_LOG("WORLD: CMSG_CANCEL_MOUNT_AURA");
1430 // If player is not mounted, so go out :)
1431 if (!_player
->IsMounted()) // not blizz like; no any messages on blizz
1433 ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED
);
1437 if (_player
->IsTaxiFlying()) // not blizz like; no any messages on blizz
1439 ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT
);
1443 _player
->Unmount(_player
->HasAuraType(SPELL_AURA_MOUNTED
));
1444 _player
->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED
);
1447 void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket
& recv_data
)
1450 DEBUG_LOG("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
1452 MovementInfo movementInfo
;
1453 recv_data
>> movementInfo
;
1455 if (_player
->GetMover()->GetObjectGuid() != movementInfo
.GetGuid())
1457 DEBUG_LOG("WorldSession::HandleMoveSetCanFlyAckOpcode: player %s, mover %s, received %s, ignored",
1458 _player
->GetGuidStr().c_str(), _player
->GetMover()->GetGuidStr().c_str(), movementInfo
.GetGuid().GetString().c_str());
1462 _player
->GetMover()->m_movementInfo
.SetMovementFlags(movementInfo
.GetMovementFlags());
1465 void WorldSession::HandleRequestPetInfoOpcode(WorldPacket
& /*recv_data */)
1468 DEBUG_LOG("WORLD: CMSG_REQUEST_PET_INFO");
1469 recv_data.hexlike();
1473 void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket
& recv_data
)
1478 DEBUG_LOG("Client used \"/timetest %d\" command", mode
);
1481 void WorldSession::HandleQueryInspectAchievementsOpcode(WorldPacket
& recv_data
)
1485 recv_data
>> guid
.ReadAsPacked();
1487 if (Player
* player
= sObjectMgr
.GetPlayer(guid
))
1488 player
->GetAchievementMgr().SendRespondInspectAchievements(_player
);
1491 void WorldSession::HandleUITimeRequestOpcode(WorldPacket
& /*recv_data*/)
1494 DEBUG_LOG("WORLD: SMSG_UI_TIME");
1496 WorldPacket
data(SMSG_UI_TIME
, 4);
1497 data
<< uint32(time(NULL
));
1501 void WorldSession::HandleReadyForAccountDataTimesOpcode(WorldPacket
& /*recv_data*/)
1504 DEBUG_LOG("WORLD: CMSG_READY_FOR_ACCOUNT_DATA_TIMES");
1506 SendAccountDataTimes(GLOBAL_CACHE_MASK
);
1509 void WorldSession::HandleHearthandResurrect(WorldPacket
& /*recv_data*/)
1511 DEBUG_LOG("WORLD: CMSG_HEARTH_AND_RESURRECT");
1513 AreaTableEntry
const* atEntry
= sAreaStore
.LookupEntry(_player
->GetAreaId());
1514 if (!atEntry
|| !(atEntry
->flags
& AREA_FLAG_CAN_HEARTH_AND_RES
))
1517 // Can't use in flight
1518 if (_player
->IsTaxiFlying())
1522 _player
->BuildPlayerRepop();
1523 _player
->ResurrectPlayer(100);
1524 _player
->TeleportToHomebind();