root/trunk/src/game/MiscHandler.cpp @ 42

Revision 39, 56.3 kB (checked in by yumileroy, 17 years ago)

[svn] * Various small changes here and there.
* Implementing MangChat? IRC system.
* Added new config option, MAX_WHO, can be used to set the limit of characters being sent in a /who request from client.

Original author: XTZGZoReX
Date: 2008-10-12 14:03:38-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "Common.h"
20#include "Language.h"
21#include "Database/DatabaseEnv.h"
22#include "WorldPacket.h"
23#include "Opcodes.h"
24#include "Log.h"
25#include "Player.h"
26#include "World.h"
27#include "ObjectMgr.h"
28#include "WorldSession.h"
29#include "Auth/BigNumber.h"
30#include "Auth/Sha1.h"
31#include "UpdateData.h"
32#include "LootMgr.h"
33#include "Chat.h"
34#include "ScriptCalls.h"
35#include <zlib/zlib.h>
36#include "MapManager.h"
37#include "ObjectAccessor.h"
38#include "Object.h"
39#include "BattleGround.h"
40#include "SpellAuras.h"
41#include "Pet.h"
42#include "SocialMgr.h"
43
44void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
45{
46    sLog.outDebug( "WORLD: Recvd CMSG_REPOP_REQUEST Message" );
47
48    if(GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
49        return;
50
51    // the world update order is sessions, players, creatures
52    // the netcode runs in parallel with all of these
53    // creatures can kill players
54    // so if the server is lagging enough the player can
55    // release spirit after he's killed but before he is updated
56    if(GetPlayer()->getDeathState() == JUST_DIED)
57    {
58        sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
59        GetPlayer()->KillPlayer();
60    }
61
62    //this is spirit release confirm?
63    GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
64    GetPlayer()->BuildPlayerRepop();
65    GetPlayer()->RepopAtGraveyard();
66}
67
68void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
69{
70    CHECK_PACKET_SIZE(recv_data,4+4+1+1+4+4+4+4);
71
72    sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
73    //recv_data.hexlike();
74
75    uint32 clientcount = 0;
76
77    uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
78    uint32 zoneids[10];                                     // 10 is client limit
79    std::string player_name, guild_name;
80
81    recv_data >> level_min;                                 // maximal player level, default 0
82    recv_data >> level_max;                                 // minimal player level, default 100
83    recv_data >> player_name;                               // player name, case sensitive...
84
85    // recheck
86    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+1+4+4+4+4);
87
88    recv_data >> guild_name;                                // guild name, case sensitive...
89
90    // recheck
91    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+4);
92
93    recv_data >> racemask;                                  // race mask
94    recv_data >> classmask;                                 // class mask
95    recv_data >> zones_count;                               // zones count, client limit=10 (2.0.10)
96
97    if(zones_count > 10)
98        return;                                             // can't be received from real client or broken packet
99
100    // recheck
101    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
102
103    for(uint32 i = 0; i < zones_count; i++)
104    {
105        uint32 temp;
106        recv_data >> temp;                                  // zone id, 0 if zone is unknown...
107        zoneids[i] = temp;
108        sLog.outDebug("Zone %u: %u", i, zoneids[i]);
109    }
110
111    recv_data >> str_count;                                 // user entered strings count, client limit=4 (checked on 2.0.10)
112
113    if(str_count > 4)
114        return;                                             // can't be received from real client or broken packet
115
116    // recheck
117    CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4+(1*str_count));
118
119    sLog.outDebug("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);
120
121    std::wstring str[4];                                    // 4 is client limit
122    for(uint32 i = 0; i < str_count; i++)
123    {
124        // recheck (have one more byte)
125        CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
126
127        std::string temp;
128        recv_data >> temp;                                  // user entered string, it used as universal search pattern(guild+player name)?
129
130        if(!Utf8toWStr(temp,str[i]))
131            continue;
132
133        wstrToLower(str[i]);
134
135        sLog.outDebug("String %u: %s", i, str[i].c_str());
136    }
137
138    std::wstring wplayer_name;
139    std::wstring wguild_name;
140    if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
141        return;
142    wstrToLower(wplayer_name);
143    wstrToLower(wguild_name);
144
145    // client send in case not set max level value 100 but mangos support 255 max level,
146    // update it to show GMs with characters after 100 level
147    if(level_max >= 100)
148        level_max = 255;
149
150    uint32 team = _player->GetTeam();
151    uint32 security = GetSecurity();
152    bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
153    bool gmInWhoList         = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
154
155    WorldPacket data( SMSG_WHO, 50 );                       // guess size
156    data << clientcount;                                    // clientcount place holder
157    data << clientcount;                                    // clientcount place holder
158
159    //TODO: Guard Player map
160    HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
161    for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
162    {
163        if (security == SEC_PLAYER)
164        {
165            // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
166            if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
167                continue;
168
169            // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
170            if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
171                continue;
172        }
173
174        // check if target is globally visible for player
175        if (!(itr->second->IsVisibleGloballyFor(_player)))
176            continue;
177
178        // check if target's level is in level range
179        uint32 lvl = itr->second->getLevel();
180        if (lvl < level_min || lvl > level_max)
181            continue;
182
183        // check if class matches classmask
184        uint32 class_ = itr->second->getClass();
185        if (!(classmask & (1 << class_)))
186            continue;
187
188        // check if race matches racemask
189        uint32 race = itr->second->getRace();
190        if (!(racemask & (1 << race)))
191            continue;
192
193        uint32 pzoneid = itr->second->GetZoneId();
194
195        bool z_show = true;
196        for(uint32 i = 0; i < zones_count; i++)
197        {
198            if(zoneids[i] == pzoneid)
199            {
200                z_show = true;
201                break;
202            }
203
204            z_show = false;
205        }
206        if (!z_show)
207            continue;
208
209        std::string pname = itr->second->GetName();
210        std::wstring wpname;
211        if(!Utf8toWStr(pname,wpname))
212            continue;
213        wstrToLower(wpname);
214
215        if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
216            continue;
217
218        std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId());
219        std::wstring wgname;
220        if(!Utf8toWStr(gname,wgname))
221            continue;
222        wstrToLower(wgname);
223
224        if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
225            continue;
226
227        std::string aname;
228        if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
229            aname = areaEntry->area_name[GetSessionDbcLocale()];
230
231        bool s_show = true;
232        for(uint32 i = 0; i < str_count; i++)
233        {
234            if (!str[i].empty())
235            {
236                if (wgname.find(str[i]) != std::wstring::npos ||
237                    wpname.find(str[i]) != std::wstring::npos ||
238                    Utf8FitTo(aname, str[i]) )
239                {
240                    s_show = true;
241                    break;
242                }
243                s_show = false;
244            }
245        }
246        if (!s_show)
247            continue;
248
249        data << pname;                                      // player name
250        data << gname;                                      // guild name
251        data << uint32( lvl );                              // player level
252        data << uint32( class_ );                           // player class
253        data << uint32( race );                             // player race
254        data << uint8(0);                                   // new 2.4.0
255        data << uint32( pzoneid );                          // player zone id
256
257        // 49 is maximum player count sent to client - can be overriden
258        // through config, but is unstable
259        if ((++clientcount) == sWorld.getConfig(CONFIG_MAX_WHO))
260            break;
261    }
262
263    data.put( 0,              clientcount );                //insert right count
264    data.put( sizeof(uint32), clientcount );                //insert right count
265
266    SendPacket(&data);
267    sLog.outDebug( "WORLD: Send SMSG_WHO Message" );
268}
269
270void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
271{
272    sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity() );
273
274    if (uint64 lguid = GetPlayer()->GetLootGUID())
275        DoLootRelease(lguid);
276
277    //instant logout for admins, gm's, mod's
278    if( GetSecurity() > SEC_PLAYER )
279    {
280        LogoutPlayer(true);
281        return;
282    }
283
284    //Can not logout if...
285    if( GetPlayer()->isInCombat() ||                        //...is in combat
286        GetPlayer()->duel         ||                        //...is in Duel
287                                                            //...is jumping ...is falling
288        GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
289    {
290        WorldPacket data( SMSG_LOGOUT_RESPONSE, (2+4) ) ;
291        data << (uint8)0xC;
292        data << uint32(0);
293        data << uint8(0);
294        SendPacket( &data );
295        LogoutRequest(0);
296        return;
297    }
298
299    //instant logout in taverns/cities or on taxi or if its enabled in mangosd.conf
300    if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || sWorld.getConfig(CONFIG_INSTANT_LOGOUT))
301    {
302        LogoutPlayer(true);
303        return;
304    }
305
306    // not set flags if player can't free move to prevent lost state at logout cancel
307    if(GetPlayer()->CanFreeMove())
308    {
309        GetPlayer()->SetStandState(PLAYER_STATE_SIT);
310
311        WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) );    // guess size
312        data.append(GetPlayer()->GetPackGUID());
313        data << (uint32)2;
314        SendPacket( &data );
315        GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
316    }
317
318    WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
319    data << uint32(0);
320    data << uint8(0);
321    SendPacket( &data );
322    LogoutRequest(time(NULL));
323}
324
325void WorldSession::HandlePlayerLogoutOpcode( WorldPacket & /*recv_data*/ )
326{
327    sLog.outDebug( "WORLD: Recvd CMSG_PLAYER_LOGOUT Message" );
328}
329
330void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
331{
332    sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_CANCEL Message" );
333
334    LogoutRequest(0);
335
336    WorldPacket data( SMSG_LOGOUT_CANCEL_ACK, 0 );
337    SendPacket( &data );
338
339    // not remove flags if can't free move - its not set in Logout request code.
340    if(GetPlayer()->CanFreeMove())
341    {
342        //!we can move again
343        data.Initialize( SMSG_FORCE_MOVE_UNROOT, 8 );       // guess size
344        data.append(GetPlayer()->GetPackGUID());
345        data << uint32(0);
346        SendPacket( &data );
347
348        //! Stand Up
349        GetPlayer()->SetStandState(PLAYER_STATE_NONE);
350
351        //! DISABLE_ROTATE
352        GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
353    }
354
355    sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
356}
357
358void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
359{
360    int len = text ? strlen(text) : 0;
361    WorldPacket data( SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4) );
362    data << uint32(status);                                 // standard 0x0A, 0x06 if text present
363    if(status == 6)
364    {
365        data << text;                                       // ticket text
366        data << uint8(0x7);                                 // ticket category
367        data << float(0);                                   // time from ticket creation?
368        data << float(0);                                   // const
369        data << float(0);                                   // const
370        data << uint8(0);                                   // const
371        data << uint8(0);                                   // const
372    }
373    SendPacket( &data );
374}
375
376void WorldSession::HandleGMTicketGetTicketOpcode( WorldPacket & /*recv_data*/ )
377{
378    WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
379    data << (uint32)time(NULL);
380    data << (uint32)0;
381    SendPacket( &data );
382
383    uint64 guid;
384    Field *fields;
385    guid = GetPlayer()->GetGUID();
386
387    QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(ticket_id) FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
388
389    if (result)
390    {
391        int cnt;
392        fields = result->Fetch();
393        cnt = fields[0].GetUInt32();
394        delete result;
395
396        if ( cnt > 0 )
397        {
398            QueryResult *result2 = CharacterDatabase.PQuery("SELECT ticket_text FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
399            if(result2)
400            {
401                Field *fields2 = result2->Fetch();
402                SendGMTicketGetTicket(0x06,fields2[0].GetString());
403                delete result2;
404            }
405        }
406        else
407            SendGMTicketGetTicket(0x0A,0);
408    }
409}
410
411void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
412{
413    CHECK_PACKET_SIZE(recv_data,1);
414
415    std::string ticketText;
416    recv_data >> ticketText;
417
418    CharacterDatabase.escape_string(ticketText);
419    CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", ticketText.c_str(), _player->GetGUIDLow());
420}
421
422void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
423{
424    uint32 guid = GetPlayer()->GetGUIDLow();
425
426    CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1",guid);
427
428    WorldPacket data( SMSG_GMTICKET_DELETETICKET, 4 );
429    data << uint32(9);
430    SendPacket( &data );
431
432    SendGMTicketGetTicket(0x0A, 0);
433}
434
435void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
436{
437    CHECK_PACKET_SIZE(recv_data, 4*4+1+2*4);
438
439    uint32 map;
440    float x, y, z;
441    std::string ticketText = "";
442    uint32 unk1, unk2;
443
444    recv_data >> map >> x >> y >> z;                        // last check 2.4.3
445    recv_data >> ticketText;
446
447    // recheck
448    CHECK_PACKET_SIZE(recv_data,4*4+(ticketText.size()+1)+2*4);
449
450    recv_data >> unk1 >> unk2;
451    // note: the packet might contain more data, but the exact structure of that is unknown
452
453    sLog.outDebug("TicketCreate: map %u, x %f, y %f, z %f, text %s, unk1 %u, unk2 %u", map, x, y, z, ticketText.c_str(), unk1, unk2);
454
455    CharacterDatabase.escape_string(ticketText);
456
457    QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM character_ticket WHERE guid = '%u'", _player->GetGUIDLow());
458
459    if (result)
460    {
461        int cnt;
462        Field *fields = result->Fetch();
463        cnt = fields[0].GetUInt32();
464        delete result;
465
466        if ( cnt > 0 )
467        {
468            WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
469            data << uint32(1);
470            SendPacket( &data );
471        }
472        else
473        {
474            CharacterDatabase.PExecute("INSERT INTO character_ticket (guid,ticket_text) VALUES ('%u', '%s')", _player->GetGUIDLow(), ticketText.c_str());
475
476            WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
477            data << (uint32)time(NULL);
478            data << (uint32)0;
479            SendPacket( &data );
480
481            data.Initialize( SMSG_GMTICKET_CREATE, 4 );
482            data << uint32(2);
483            SendPacket( &data );
484            DEBUG_LOG("update the ticket\n");
485
486            //TODO: Guard player map
487            HashMapHolder<Player>::MapType &m = ObjectAccessor::Instance().GetPlayers();
488            for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
489            {
490                if(itr->second->GetSession()->GetSecurity() >= SEC_GAMEMASTER && itr->second->isAcceptTickets())
491                    ChatHandler(itr->second).PSendSysMessage(LANG_COMMAND_TICKETNEW,GetPlayer()->GetName());
492            }
493        }
494    }
495}
496
497void WorldSession::HandleGMTicketSystemStatusOpcode( WorldPacket & /*recv_data*/ )
498{
499    WorldPacket data( SMSG_GMTICKET_SYSTEMSTATUS,4 );
500    data << uint32(1);                                      // we can also disable ticket system by sending 0 value
501
502    SendPacket( &data );
503}
504
505void WorldSession::HandleGMSurveySubmit( WorldPacket & recv_data)
506{
507    // GM survey is shown after SMSG_GM_TICKET_STATUS_UPDATE with status = 3
508    CHECK_PACKET_SIZE(recv_data,4+4);
509    uint32 x;
510    recv_data >> x;                                         // answer range? (6 = 0-5?)
511    sLog.outDebug("SURVEY: X = %u", x);
512
513    uint8 result[10];
514    memset(result, 0, sizeof(result));
515    for( int i = 0; i < 10; ++i)
516    {
517        CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+4);
518        uint32 questionID;
519        recv_data >> questionID;                            // GMSurveyQuestions.dbc
520        if (!questionID)
521            break;
522
523        CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1+1);
524        uint8 value;
525        std::string unk_text;
526        recv_data >> value;                                 // answer
527        recv_data >> unk_text;                              // always empty?
528
529        result[i] = value;
530        sLog.outDebug("SURVEY: ID %u, value %u, text %s", questionID, value, unk_text.c_str());
531    }
532
533    CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1);
534    std::string comment;
535    recv_data >> comment;                                   // addional comment
536    sLog.outDebug("SURVEY: comment %s", comment.c_str());
537
538    // TODO: chart this data in some way
539}
540
541void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
542{
543    // this opcode can be used in two ways: Either set explicit new status or toggle old status
544    if(recv_data.size() == 1)
545    {
546        bool newPvPStatus;
547        recv_data >> newPvPStatus;
548        GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
549    }
550    else
551    {
552        GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
553    }
554
555    if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
556    {
557        if(!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
558            GetPlayer()->UpdatePvP(true, true);
559    }
560    else
561    {
562        if(!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
563            GetPlayer()->pvpInfo.endTimer = time(NULL);     // start toggle-off
564    }
565}
566
567void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
568{
569    CHECK_PACKET_SIZE(recv_data,4);
570
571    uint32 newZone;
572    recv_data >> newZone;
573
574    sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
575
576    if(newZone != _player->GetZoneId())
577        GetPlayer()->SendInitWorldStates();                 // only if really enters to new zone, not just area change, works strange...
578
579        // AntiCheat.GMIsland
580        if(sWorld.getConfig(CONFIG_KICK_FROM_GMISLAND))
581        {
582                if(newZone == 876 && GetPlayer()->GetSession()->GetSecurity() == SEC_PLAYER)
583                        _player->TeleportTo(13,0,0,0,0);
584        }
585
586    GetPlayer()->UpdateZone(newZone);
587}
588
589void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
590{
591    // When this packet send?
592    CHECK_PACKET_SIZE(recv_data,8);
593
594    uint64 guid ;
595    recv_data >> guid;
596
597    _player->SetUInt32Value(UNIT_FIELD_TARGET,guid);
598
599    // update reputation list if need
600    Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
601    if(!unit)
602        return;
603
604    _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
605}
606
607void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
608{
609    CHECK_PACKET_SIZE(recv_data,8);
610
611    uint64 guid;
612    recv_data >> guid;
613
614    _player->SetSelection(guid);
615
616    // update reputation list if need
617    Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
618    if(!unit)
619        return;
620
621    _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
622}
623
624void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
625{
626    CHECK_PACKET_SIZE(recv_data,1);
627
628    sLog.outDebug( "WORLD: Received CMSG_STAND_STATE_CHANGE"  );
629    uint8 animstate;
630    recv_data >> animstate;
631
632    _player->SetStandState(animstate);
633}
634
635void WorldSession::HandleFriendListOpcode( WorldPacket & recv_data )
636{
637    CHECK_PACKET_SIZE(recv_data, 4);
638    sLog.outDebug( "WORLD: Received CMSG_CONTACT_LIST" );
639    uint32 unk;
640    recv_data >> unk;
641    sLog.outDebug("unk value is %u", unk);
642    _player->GetSocial()->SendSocialList();
643}
644
645void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
646{
647    CHECK_PACKET_SIZE(recv_data, 1+1);
648
649    sLog.outDebug( "WORLD: Received CMSG_ADD_FRIEND" );
650
651    std::string friendName  = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
652    std::string friendNote;
653    FriendsResult friendResult = FRIEND_NOT_FOUND;
654    Player *pFriend     = NULL;
655    uint64 friendGuid   = 0;
656
657    recv_data >> friendName;
658
659    // recheck
660    CHECK_PACKET_SIZE(recv_data, (friendName.size()+1)+1);
661
662    recv_data >> friendNote;
663
664    if(!normalizePlayerName(friendName))
665        return;
666
667    CharacterDatabase.escape_string(friendName);            // prevent SQL injection - normal name don't must changed by this call
668
669    sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
670        GetPlayer()->GetName(), friendName.c_str() );
671
672    friendGuid = objmgr.GetPlayerGUIDByName(friendName);
673
674    if(friendGuid)
675    {
676        pFriend = ObjectAccessor::FindPlayer(friendGuid);
677        if(pFriend==GetPlayer())
678            friendResult = FRIEND_SELF;
679        else if(GetPlayer()->GetTeam()!=objmgr.GetPlayerTeamByGUID(friendGuid) && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && GetSecurity() < SEC_MODERATOR)
680            friendResult = FRIEND_ENEMY;
681        else if(GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
682            friendResult = FRIEND_ALREADY;
683    }
684
685    if (friendGuid && friendResult==FRIEND_NOT_FOUND)
686    {
687        if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer()))
688            friendResult = FRIEND_ADDED_ONLINE;
689        else
690            friendResult = FRIEND_ADDED_OFFLINE;
691
692        if(!_player->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
693        {
694            friendResult = FRIEND_LIST_FULL;
695            sLog.outDebug( "WORLD: %s's friend list is full.", GetPlayer()->GetName());
696        }
697
698        _player->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
699
700        sLog.outDebug( "WORLD: %s Guid found '%u'.", friendName.c_str(), GUID_LOPART(friendGuid));
701    }
702    else if(friendResult==FRIEND_ALREADY)
703    {
704        sLog.outDebug( "WORLD: %s Guid Already a Friend.", friendName.c_str() );
705    }
706    else if(friendResult==FRIEND_SELF)
707    {
708        sLog.outDebug( "WORLD: %s Guid can't add himself.", friendName.c_str() );
709    }
710    else
711    {
712        sLog.outDebug( "WORLD: %s Guid not found.", friendName.c_str() );
713    }
714
715    sSocialMgr.SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), friendName, false);
716
717    sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
718}
719
720void WorldSession::HandleDelFriendOpcode( WorldPacket & recv_data )
721{
722    CHECK_PACKET_SIZE(recv_data, 8);
723
724    uint64 FriendGUID;
725
726    sLog.outDebug( "WORLD: Received CMSG_DEL_FRIEND" );
727
728    recv_data >> FriendGUID;
729
730    _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false);
731
732    sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), "", false);
733
734    sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
735}
736
737void WorldSession::HandleAddIgnoreOpcode( WorldPacket & recv_data )
738{
739    CHECK_PACKET_SIZE(recv_data,1);
740
741    sLog.outDebug( "WORLD: Received CMSG_ADD_IGNORE" );
742
743    std::string IgnoreName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
744    FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
745    uint64 IgnoreGuid = 0;
746
747    recv_data >> IgnoreName;
748
749    if(!normalizePlayerName(IgnoreName))
750        return;
751
752    CharacterDatabase.escape_string(IgnoreName);            // prevent SQL injection - normal name don't must changed by this call
753
754    sLog.outDebug( "WORLD: %s asked to Ignore: '%s'",
755        GetPlayer()->GetName(), IgnoreName.c_str() );
756
757    IgnoreGuid = objmgr.GetPlayerGUIDByName(IgnoreName);
758
759    if(IgnoreGuid)
760    {
761        if(IgnoreGuid==GetPlayer()->GetGUID())
762            ignoreResult = FRIEND_IGNORE_SELF;
763        else
764        {
765            if( GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid)) )
766                ignoreResult = FRIEND_IGNORE_ALREADY;
767        }
768    }
769
770    if (IgnoreGuid && ignoreResult == FRIEND_IGNORE_NOT_FOUND)
771    {
772        ignoreResult = FRIEND_IGNORE_ADDED;
773
774        _player->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true);
775    }
776    else if(ignoreResult==FRIEND_IGNORE_ALREADY)
777    {
778        sLog.outDebug( "WORLD: %s Guid Already Ignored.", IgnoreName.c_str() );
779    }
780    else if(ignoreResult==FRIEND_IGNORE_SELF)
781    {
782        sLog.outDebug( "WORLD: %s Guid can't add himself.", IgnoreName.c_str() );
783    }
784    else
785    {
786        sLog.outDebug( "WORLD: %s Guid not found.", IgnoreName.c_str() );
787    }
788
789    sSocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), "", false);
790
791    sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
792}
793
794void WorldSession::HandleDelIgnoreOpcode( WorldPacket & recv_data )
795{
796    CHECK_PACKET_SIZE(recv_data, 8);
797
798    uint64 IgnoreGUID;
799
800    sLog.outDebug( "WORLD: Received CMSG_DEL_IGNORE" );
801
802    recv_data >> IgnoreGUID;
803
804    _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true);
805
806    sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), "", false);
807
808    sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
809}
810
811void WorldSession::HandleSetFriendNoteOpcode( WorldPacket & recv_data )
812{
813    CHECK_PACKET_SIZE(recv_data, 8+1);
814    uint64 guid;
815    std::string note;
816    recv_data >> guid >> note;
817    _player->GetSocial()->SetFriendNote(guid, note);
818}
819
820void WorldSession::HandleBugOpcode( WorldPacket & recv_data )
821{
822    CHECK_PACKET_SIZE(recv_data,4+4+1+4+1);
823
824    uint32 suggestion, contentlen;
825    std::string content;
826    uint32 typelen;
827    std::string type;
828
829    recv_data >> suggestion >> contentlen >> content;
830
831    //recheck
832    CHECK_PACKET_SIZE(recv_data,4+4+(content.size()+1)+4+1);
833
834    recv_data >> typelen >> type;
835
836    if( suggestion == 0 )
837        sLog.outDebug( "WORLD: Received CMSG_BUG [Bug Report]" );
838    else
839        sLog.outDebug( "WORLD: Received CMSG_BUG [Suggestion]" );
840
841    sLog.outDebug( type.c_str( ) );
842    sLog.outDebug( content.c_str( ) );
843
844    CharacterDatabase.escape_string(type);
845    CharacterDatabase.escape_string(content);
846    CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str( ), content.c_str( ));
847}
848
849void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
850{
851    CHECK_PACKET_SIZE(recv_data,8);
852
853    sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE");
854    if (GetPlayer()->isAlive())
855        return;
856
857    if (BattleGround * bg = _player->GetBattleGround())
858        if(bg->isArena())
859            return;
860
861    // body not released yet
862    if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
863        return;
864
865    Corpse *corpse = GetPlayer()->GetCorpse();
866
867    if (!corpse )
868        return;
869
870    // prevent resurrect before 30-sec delay after body release not finished
871    if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
872        return;
873
874    float dist = corpse->GetDistance2d(GetPlayer());
875    sLog.outDebug("Corpse 2D Distance: \t%f",dist);
876    if (dist > CORPSE_RECLAIM_RADIUS)
877        return;
878
879    uint64 guid;
880    recv_data >> guid;
881
882    // resurrect
883    GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
884
885    // spawn bones
886    GetPlayer()->SpawnCorpseBones();
887
888    GetPlayer()->SaveToDB();
889}
890
891void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data)
892{
893    CHECK_PACKET_SIZE(recv_data,8+1);
894
895    sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE");
896
897    if(GetPlayer()->isAlive())
898        return;
899
900    uint64 guid;
901    uint8 status;
902    recv_data >> guid;
903    recv_data >> status;
904
905    if(status == 0)
906    {
907        GetPlayer()->clearResurrectRequestData();           // reject
908        return;
909    }
910
911    if(!GetPlayer()->isRessurectRequestedBy(guid))
912        return;
913
914    GetPlayer()->ResurectUsingRequestData();
915    GetPlayer()->SaveToDB();
916}
917
918void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
919{
920    CHECK_PACKET_SIZE(recv_data,4);
921
922    sLog.outDebug("WORLD: Received CMSG_AREATRIGGER");
923
924    uint32 Trigger_ID;
925
926    recv_data >> Trigger_ID;
927    sLog.outDebug("Trigger ID:%u",Trigger_ID);
928
929    if(GetPlayer()->isInFlight())
930    {
931        sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
932        return;
933    }
934
935    AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
936    if(!atEntry)
937    {
938        sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
939        return;
940    }
941
942    if (GetPlayer()->GetMapId()!=atEntry->mapid)
943    {
944        sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID);
945        return;
946    }
947
948    // delta is safe radius
949    const float delta = 5.0f;
950    // check if player in the range of areatrigger
951    Player* pl = GetPlayer();
952
953    if (atEntry->radius > 0)
954    {
955        // if we have radius check it
956        float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z);
957        if(dist > atEntry->radius + delta)
958        {
959            sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u",
960                pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID);
961            return;
962        }
963    }
964    else
965    {
966        // we have only extent
967        float dx = pl->GetPositionX() - atEntry->x;
968        float dy = pl->GetPositionY() - atEntry->y;
969        float dz = pl->GetPositionZ() - atEntry->z;
970        double es = sin(atEntry->box_orientation);
971        double ec = cos(atEntry->box_orientation);
972        // calc rotated vector based on extent axis
973        double rotateDx = dx*ec - dy*es;
974        double rotateDy = dx*es + dy*ec;
975
976        if( (fabs(rotateDx) > atEntry->box_x/2 + delta) ||
977            (fabs(rotateDy) > atEntry->box_y/2 + delta) ||
978            (fabs(dz) > atEntry->box_z/2 + delta) )
979        {
980            sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %u 1/2 box Z: %u rotate dX: %f rotate dY: %f dZ:%f), ignore Area Trigger ID: %u",
981                pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotateDx, rotateDy, dz, Trigger_ID);
982            return;
983        }
984    }
985
986    if(Script->scriptAreaTrigger(GetPlayer(), atEntry))
987        return;
988
989    uint32 quest_id = objmgr.GetQuestForAreaTrigger( Trigger_ID );
990    if( quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id) )
991    {
992        Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
993        if( pQuest )
994        {
995            if(GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
996                GetPlayer()->AreaExploredOrEventHappens( quest_id );
997        }
998    }
999
1000    if(objmgr.IsTavernAreaTrigger(Trigger_ID))
1001    {
1002        // set resting flag we are in the inn
1003        GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
1004        GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z);
1005        GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
1006
1007        if(sWorld.IsFFAPvPRealm())
1008            GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
1009
1010        return;
1011    }
1012
1013    if(GetPlayer()->InBattleGround())
1014    {
1015        BattleGround* bg = GetPlayer()->GetBattleGround();
1016        if(bg)
1017            if(bg->GetStatus() == STATUS_IN_PROGRESS)
1018                bg->HandleAreaTrigger(GetPlayer(), Trigger_ID);
1019
1020        return;
1021    }
1022
1023    // NULL if all values default (non teleport trigger)
1024    AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
1025    if(!at)
1026        return;
1027
1028    if(!GetPlayer()->isGameMaster())
1029    {
1030        uint32 missingLevel = 0;
1031        if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
1032            missingLevel = at->requiredLevel;
1033
1034        // must have one or the other, report the first one that's missing
1035        uint32 missingItem = 0;
1036        if(at->requiredItem)
1037        {
1038            if(!GetPlayer()->HasItemCount(at->requiredItem, 1) &&
1039                (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
1040                missingItem = at->requiredItem;
1041        }
1042        else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
1043            missingItem = at->requiredItem2;
1044
1045        uint32 missingKey = 0;
1046        if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
1047        {
1048            if(at->heroicKey)
1049            {
1050                if(!GetPlayer()->HasItemCount(at->heroicKey, 1) &&
1051                    (!at->heroicKey2 || !GetPlayer()->HasItemCount(at->heroicKey2, 1)))
1052                    missingKey = at->heroicKey;
1053            }
1054            else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
1055                missingKey = at->heroicKey2;
1056        }
1057
1058        uint32 missingQuest = 0;
1059        if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
1060            missingQuest = at->requiredQuest;
1061
1062        if(missingLevel || missingItem || missingKey || missingQuest)
1063        {
1064            // TODO: all this is probably wrong
1065            if(missingItem)
1066                SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
1067            else if(missingKey)
1068                GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
1069            else if(missingQuest)
1070                SendAreaTriggerMessage(at->requiredFailedText.c_str());
1071            else if(missingLevel)
1072                SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), missingLevel);
1073            return;
1074        }
1075    }
1076
1077    GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
1078}
1079
1080void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
1081{
1082    sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
1083    //recv_data.hexlike();
1084}
1085
1086void WorldSession::HandleRequestAccountData(WorldPacket& /*recv_data*/)
1087{
1088    sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
1089    //recv_data.hexlike();
1090}
1091
1092void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
1093{
1094    CHECK_PACKET_SIZE(recv_data,1+2+1+1);
1095
1096    sLog.outDebug(  "WORLD: Received CMSG_SET_ACTION_BUTTON" );
1097    uint8 button, misc, type;
1098    uint16 action;
1099    recv_data >> button >> action >> misc >> type;
1100    sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
1101    if(action==0)
1102    {
1103        sLog.outDetail( "MISC: Remove action from button %u", button );
1104
1105        GetPlayer()->removeActionButton(button);
1106    }
1107    else
1108    {
1109        if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
1110        {
1111            sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
1112            GetPlayer()->addActionButton(button,action,type,misc);
1113        }
1114        else if(type==ACTION_BUTTON_SPELL)
1115        {
1116            sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
1117            GetPlayer()->addActionButton(button,action,type,misc);
1118        }
1119        else if(type==ACTION_BUTTON_ITEM)
1120        {
1121            sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
1122            GetPlayer()->addActionButton(button,action,type,misc);
1123        }
1124        else
1125            sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
1126    }
1127}
1128
1129void WorldSession::HandleCompleteCinema( WorldPacket & /*recv_data*/ )
1130{
1131    DEBUG_LOG( "WORLD: Player is watching cinema" );
1132}
1133
1134void WorldSession::HandleNextCinematicCamera( WorldPacket & /*recv_data*/ )
1135{
1136    DEBUG_LOG( "WORLD: Which movie to play" );
1137}
1138
1139void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & /*recv_data*/ )
1140{
1141    /*  WorldSession::Update( getMSTime() );*/
1142    DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
1143
1144    /*
1145        CHECK_PACKET_SIZE(recv_data,8+4);
1146        uint64 guid;
1147        uint32 time_skipped;
1148        recv_data >> guid;
1149        recv_data >> time_skipped;
1150        sLog.outDebug( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
1151
1152        /// TODO
1153        must be need use in mangos
1154        We substract server Lags to move time ( AntiLags )
1155        for exmaple
1156        GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
1157    */
1158}
1159
1160void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
1161{
1162    DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
1163}
1164
1165void WorldSession::HandleMoveUnRootAck(WorldPacket&/* recv_data*/)
1166{
1167    /*
1168        CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
1169
1170        sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK" );
1171        recv_data.hexlike();
1172        uint64 guid;
1173        uint64 unknown1;
1174        uint32 unknown2;
1175        float PositionX;
1176        float PositionY;
1177        float PositionZ;
1178        float Orientation;
1179
1180        recv_data >> guid;
1181        recv_data >> unknown1;
1182        recv_data >> unknown2;
1183        recv_data >> PositionX;
1184        recv_data >> PositionY;
1185        recv_data >> PositionZ;
1186        recv_data >> Orientation;
1187
1188        // TODO for later may be we can use for anticheat
1189        DEBUG_LOG("Guid " I64FMTD,guid);
1190        DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1191        DEBUG_LOG("unknown2 %u",unknown2);
1192        DEBUG_LOG("X %f",PositionX);
1193        DEBUG_LOG("Y %f",PositionY);
1194        DEBUG_LOG("Z %f",PositionZ);
1195        DEBUG_LOG("O %f",Orientation);
1196    */
1197}
1198
1199void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
1200{
1201    /*
1202        CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
1203
1204        sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_ROOT_ACK" );
1205        recv_data.hexlike();
1206        uint64 guid;
1207        uint64 unknown1;
1208        uint32 unknown2;
1209        float PositionX;
1210        float PositionY;
1211        float PositionZ;
1212        float Orientation;
1213
1214        recv_data >> guid;
1215        recv_data >> unknown1;
1216        recv_data >> unknown2;
1217        recv_data >> PositionX;
1218        recv_data >> PositionY;
1219        recv_data >> PositionZ;
1220        recv_data >> Orientation;
1221
1222        // for later may be we can use for anticheat
1223        DEBUG_LOG("Guid " I64FMTD,guid);
1224        DEBUG_LOG("unknown1 " I64FMTD,unknown1);
1225        DEBUG_LOG("unknown1 %u",unknown2);
1226        DEBUG_LOG("X %f",PositionX);
1227        DEBUG_LOG("Y %f",PositionY);
1228        DEBUG_LOG("Z %f",PositionZ);
1229        DEBUG_LOG("O %f",Orientation);
1230    */
1231}
1232
1233void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
1234{
1235    /*
1236        CHECK_PACKET_SIZE(recv_data,8+4);
1237
1238        sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
1239        uint64 guid;
1240        uint32 flags, time;
1241
1242        recv_data >> guid;
1243        recv_data >> flags >> time;
1244        DEBUG_LOG("Guid " I64FMTD,guid);
1245        DEBUG_LOG("Flags %u, time %u",flags, time/1000);
1246    */
1247}
1248
1249void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
1250{
1251    CHECK_PACKET_SIZE(recv_data,1);
1252
1253    uint8 ActionBar;
1254
1255    recv_data >> ActionBar;
1256
1257    if(!GetPlayer())                                        // ignore until not logged (check needed because STATUS_AUTHED)
1258    {
1259        if(ActionBar!=0)
1260            sLog.outError("WorldSession::HandleSetActionBar in not logged state with value: %u, ignored",uint32(ActionBar));
1261        return;
1262    }
1263
1264    GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
1265}
1266
1267void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
1268{
1269    /*
1270        CHECK_PACKET_SIZE(recv_data,1);
1271
1272        uint8 tmp;
1273        recv_data >> tmp;
1274        sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp);
1275    */
1276}
1277
1278void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
1279{
1280    uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
1281    uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
1282
1283    WorldPacket data(SMSG_PLAYED_TIME, 8);
1284    data << TotalTimePlayed;
1285    data << LevelPlayedTime;
1286    SendPacket(&data);
1287}
1288
1289void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
1290{
1291    CHECK_PACKET_SIZE(recv_data, 8);
1292
1293    uint64 guid;
1294    recv_data >> guid;
1295    DEBUG_LOG("Inspected guid is " I64FMTD, guid);
1296
1297    _player->SetSelection(guid);
1298
1299    Player *plr = objmgr.GetPlayer(guid);
1300    if(!plr)                                                // wrong player
1301        return;
1302
1303    uint32 talent_points = 0x3D;
1304    uint32 guid_size = plr->GetPackGUID().size();
1305    WorldPacket data(SMSG_INSPECT_TALENT, 4+talent_points);
1306    data.append(plr->GetPackGUID());
1307    data << uint32(talent_points);
1308
1309    // fill by 0 talents array
1310    for(uint32 i = 0; i < talent_points; ++i)
1311        data << uint8(0);
1312
1313    if(sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster())
1314    {
1315        // find class talent tabs (all players have 3 talent tabs)
1316        uint32 const* talentTabIds = GetTalentTabPages(plr->getClass());
1317
1318        uint32 talentTabPos = 0;                            // pos of first talent rank in tab including all prev tabs
1319        for(uint32 i = 0; i < 3; ++i)
1320        {
1321            uint32 talentTabId = talentTabIds[i];
1322
1323            // fill by real data
1324            for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
1325            {
1326                TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
1327                if(!talentInfo)
1328                    continue;
1329
1330                // skip another tab talents
1331                if(talentInfo->TalentTab != talentTabId)
1332                    continue;
1333
1334                // find talent rank
1335                uint32 curtalent_maxrank = 0;
1336                for(uint32 k = 5; k > 0; --k)
1337                {
1338                    if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
1339                    {
1340                        curtalent_maxrank = k;
1341                        break;
1342                    }
1343                }
1344
1345                // not learned talent
1346                if(!curtalent_maxrank)
1347                    continue;
1348
1349                // 1 rank talent bit index
1350                uint32 curtalent_index = talentTabPos + GetTalentInspectBitPosInTab(talentId);
1351
1352                uint32 curtalent_rank_index = curtalent_index+curtalent_maxrank-1;
1353
1354                // slot/offset in 7-bit bytes
1355                uint32 curtalent_rank_slot7   = curtalent_rank_index / 7;
1356                uint32 curtalent_rank_offset7 = curtalent_rank_index % 7;
1357
1358                // rank pos with skipped 8 bit
1359                uint32 curtalent_rank_index2 = curtalent_rank_slot7 * 8 + curtalent_rank_offset7;
1360
1361                // slot/offset in 8-bit bytes with skipped high bit
1362                uint32 curtalent_rank_slot = curtalent_rank_index2 / 8;
1363                uint32 curtalent_rank_offset =  curtalent_rank_index2 % 8;
1364
1365                // apply mask
1366                uint32 val = data.read<uint8>(guid_size + 4 + curtalent_rank_slot);
1367                val |= (1 << curtalent_rank_offset);
1368                data.put<uint8>(guid_size + 4 + curtalent_rank_slot, val & 0xFF);
1369            }
1370
1371            talentTabPos += GetTalentTabInspectBitSize(talentTabId);
1372        }
1373    }
1374
1375    SendPacket(&data);
1376}
1377
1378void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
1379{
1380    CHECK_PACKET_SIZE(recv_data, 8);
1381
1382    uint64 guid;
1383    recv_data >> guid;
1384
1385    Player *player = objmgr.GetPlayer(guid);
1386
1387    if(!player)
1388    {
1389        sLog.outError("InspectHonorStats: WTF, player not found...");
1390        return;
1391    }
1392
1393    WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
1394    data << uint64(player->GetGUID());
1395    data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY));
1396    data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
1397    data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
1398    data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION));
1399    data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
1400    SendPacket(&data);
1401}
1402
1403void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
1404{
1405    CHECK_PACKET_SIZE(recv_data,4+4+4+4+4+4);
1406
1407    // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
1408    // Received opcode CMSG_WORLD_TELEPORT
1409    // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
1410
1411    //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT");
1412
1413    if(GetPlayer()->isInFlight())
1414    {
1415        sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow());
1416        return;
1417    }
1418
1419    uint32 time;
1420    uint32 mapid;
1421    float PositionX;
1422    float PositionY;
1423    float PositionZ;
1424    float Orientation;
1425
1426    recv_data >> time;                                      // time in m.sec.
1427    recv_data >> mapid;
1428    recv_data >> PositionX;
1429    recv_data >> PositionY;
1430    recv_data >> PositionZ;
1431    recv_data >> Orientation;                               // o (3.141593 = 180 degrees)
1432    DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation);
1433
1434    if (GetSecurity() >= SEC_ADMINISTRATOR)
1435        GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation);
1436    else
1437        SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1438    sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName());
1439}
1440
1441void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
1442{
1443    CHECK_PACKET_SIZE(recv_data, 1);
1444
1445    sLog.outDebug("Received opcode CMSG_WHOIS");
1446    std::string charname;
1447    recv_data >> charname;
1448
1449    if (GetSecurity() < SEC_ADMINISTRATOR)
1450    {
1451        SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
1452        return;
1453    }
1454
1455    if(charname.empty())
1456    {
1457        SendNotification(LANG_NEED_CHARACTER_NAME);
1458        return;
1459    }
1460
1461    Player *plr = objmgr.GetPlayer(charname.c_str());
1462
1463    if(!plr)
1464    {
1465        SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str());
1466        return;
1467    }
1468
1469    uint32 accid = plr->GetSession()->GetAccountId();
1470
1471    QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
1472    if(!result)
1473    {
1474        SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
1475        return;
1476    }
1477
1478    Field *fields = result->Fetch();
1479    std::string acc = fields[0].GetCppString();
1480    if(acc.empty())
1481        acc = "Unknown";
1482    std::string email = fields[1].GetCppString();
1483    if(email.empty())
1484        email = "Unknown";
1485    std::string lastip = fields[2].GetCppString();
1486    if(lastip.empty())
1487        lastip = "Unknown";
1488
1489    std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
1490
1491    WorldPacket data(SMSG_WHOIS, msg.size()+1);
1492    data << msg;
1493    _player->GetSession()->SendPacket(&data);
1494
1495    delete result;
1496
1497    sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
1498}
1499
1500void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
1501{
1502    CHECK_PACKET_SIZE(recv_data, 1+8);
1503    sLog.outDebug("WORLD: CMSG_REPORT_SPAM");
1504    recv_data.hexlike();
1505
1506    uint8 spam_type;                                        // 0 - mail, 1 - chat
1507    uint64 spammer_guid;
1508    uint32 unk1, unk2, unk3, unk4 = 0;
1509    std::string description = "";
1510    recv_data >> spam_type;                                 // unk 0x01 const, may be spam type (mail/chat)
1511    recv_data >> spammer_guid;                              // player guid
1512    switch(spam_type)
1513    {
1514        case 0:
1515            CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4);
1516            recv_data >> unk1;                              // const 0
1517            recv_data >> unk2;                              // probably mail id
1518            recv_data >> unk3;                              // const 0
1519            break;
1520        case 1:
1521            CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4+1);
1522            recv_data >> unk1;                              // probably language
1523            recv_data >> unk2;                              // message type?
1524            recv_data >> unk3;                              // probably channel id
1525            recv_data >> unk4;                              // unk random value
1526            recv_data >> description;                       // spam description string (messagetype, channel name, player name, message)
1527            break;
1528    }
1529
1530    // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
1531    // if it's mail spam - ALL mails from this spammer automatically removed by client
1532
1533    // Complaint Received message
1534    WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
1535    data << uint8(0);
1536    SendPacket(&data);
1537
1538    sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str());
1539}
1540
1541void WorldSession::HandleRealmStateRequestOpcode( WorldPacket & recv_data )
1542{
1543    CHECK_PACKET_SIZE(recv_data, 4);
1544
1545    sLog.outDebug("CMSG_REALM_SPLIT");
1546
1547    uint32 unk;
1548    std::string split_date = "01/01/01";
1549    recv_data >> unk;
1550
1551    WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1);
1552    data << unk;
1553    data << uint32(0x00000000);                             // realm split state
1554    // split states:
1555    // 0x0 realm normal
1556    // 0x1 realm split
1557    // 0x2 realm split pending
1558    data << split_date;
1559    SendPacket(&data);
1560    //sLog.outDebug("response sent %u", unk);
1561}
1562
1563void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
1564{
1565    CHECK_PACKET_SIZE(recv_data, 1);
1566
1567    sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
1568    //recv_data.hexlike();
1569
1570    uint8 unk;
1571    recv_data >> unk;
1572
1573    switch(unk)
1574    {
1575        case 0:
1576            //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0)
1577            //SendPacket(&data);
1578            //_player->SetUInt64Value(PLAYER_FARSIGHT, 0);
1579            sLog.outDebug("Removed FarSight from player %u", _player->GetGUIDLow());
1580            break;
1581        case 1:
1582            sLog.outDebug("Added FarSight " I64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
1583            break;
1584    }
1585}
1586
1587void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
1588{
1589    CHECK_PACKET_SIZE(recv_data, 4);
1590
1591    sLog.outDebug("CMSG_SET_TITLE");
1592
1593    int32 title;
1594    recv_data >> title;
1595
1596    // -1 at none
1597    if(title > 0 && title < 64)
1598    {
1599       if(!GetPlayer()->HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << title))
1600            return;
1601    }
1602    else
1603        title = 0;
1604
1605    GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
1606}
1607
1608void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
1609{
1610    CHECK_PACKET_SIZE(recv_data, 4+4);
1611
1612    sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
1613
1614    uint32 counter, time_;
1615    recv_data >> counter >> time_;
1616
1617    // time_ seems always more than getMSTime()
1618    uint32 diff = getMSTimeDiff(getMSTime(),time_);
1619
1620    sLog.outDebug("response sent: counter %u, time %u (HEX: %X), ms. time %u, diff %u", counter, time_, time_, getMSTime(), diff);
1621}
1622
1623void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
1624{
1625    sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
1626    Group *pGroup = _player->GetGroup();
1627    if(pGroup)
1628    {
1629        if(pGroup->IsLeader(_player->GetGUID()))
1630            pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
1631    }
1632    else
1633        _player->ResetInstances(INSTANCE_RESET_ALL);
1634}
1635
1636void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
1637{
1638    CHECK_PACKET_SIZE(recv_data, 4);
1639
1640    sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
1641
1642    uint32 mode;
1643    recv_data >> mode;
1644
1645    if(mode == _player->GetDifficulty())
1646        return;
1647
1648    if(mode > DIFFICULTY_HEROIC)
1649    {
1650        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
1651        return;
1652    }
1653
1654    // cannot reset while in an instance
1655    Map *map = _player->GetMap();
1656    if(map && map->IsDungeon())
1657    {
1658        sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
1659        return;
1660    }
1661
1662    if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
1663        return;
1664    Group *pGroup = _player->GetGroup();
1665    if(pGroup)
1666    {
1667        if(pGroup->IsLeader(_player->GetGUID()))
1668        {
1669            // the difficulty is set even if the instances can't be reset
1670            //_player->SendDungeonDifficulty(true);
1671            pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
1672            pGroup->SetDifficulty(mode);
1673        }
1674    }
1675    else
1676    {
1677        _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
1678        _player->SetDifficulty(mode);
1679    }
1680}
1681
1682void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
1683{
1684    sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
1685    recv_data.hexlike();
1686    /*
1687    New Unknown Opcode 837
1688    STORAGE_SIZE: 60
1689    02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
1690    89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
1691    BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
1692    23 91 26 3F 00 00 60 41 | 00 00 00 00
1693
1694    New Unknown Opcode 837
1695    STORAGE_SIZE: 44
1696    02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1697    7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
1698    BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
1699    */
1700}
1701
1702void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
1703{
1704    sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
1705    //recv_data.hexlike();
1706
1707    //If player is not mounted, so go out :)
1708    if (!_player->IsMounted())                              // not blizz like; no any messages on blizz
1709    {
1710        ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
1711        return;
1712    }
1713
1714    if(_player->isInFlight())                               // not blizz like; no any messages on blizz
1715    {
1716        ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
1717        return;
1718    }
1719
1720    _player->Unmount();
1721    _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
1722}
1723
1724void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
1725{
1726    CHECK_PACKET_SIZE(recv_data, 8+4+4);
1727
1728    // fly mode on/off
1729    sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
1730    //recv_data.hexlike();
1731
1732    uint64 guid;
1733    uint32 unk;
1734    uint32 flags;
1735
1736    recv_data >> guid >> unk >> flags;
1737
1738    _player->SetUnitMovementFlags(flags);
1739    /*
1740    on:
1741    25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
1742    85 4E A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1743    78 15 94 40 39 03 00 00 | 00 00 80 3F
1744    off:
1745    25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00
1746    10 FD A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
1747    78 15 94 40 39 03 00 00 | 00 00 00 00
1748    */
1749}
1750
1751void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)
1752{
1753    /*
1754        sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO");
1755        recv_data.hexlike();
1756    */
1757}
1758
1759void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
1760{
1761    CHECK_PACKET_SIZE(recv_data, 1);
1762
1763    uint8 mode;
1764    recv_data >> mode;
1765
1766    sLog.outDebug("Client used \"/timetest %d\" command", mode);
1767}
Note: See TracBrowser for help on using the browser.