Advertisement
Guest User

Untitled

a guest
Nov 15th, 2013
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 47.11 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
  3.  * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License as published by the
  7.  * Free Software Foundation; either version 2 of the License, or (at your
  8.  * option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful, but WITHOUT
  11.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12.  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13.  * more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with this program. If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.     \ingroup u2w
  21. */
  22.  
  23. #include "WorldSocket.h"                                    // must be first to make ACE happy with ACE includes in it
  24. #include "Config.h"
  25. #include "Common.h"
  26. #include "DatabaseEnv.h"
  27. #include "AccountMgr.h"
  28. #include "Log.h"
  29. #include "Opcodes.h"
  30. #include "WorldPacket.h"
  31. #include "WorldSession.h"
  32. #include "Player.h"
  33. #include "Vehicle.h"
  34. #include "ObjectMgr.h"
  35. #include "GuildMgr.h"
  36. #include "Group.h"
  37. #include "Guild.h"
  38. #include "World.h"
  39. #include "ObjectAccessor.h"
  40. #include "BattlegroundMgr.h"
  41. #include "OutdoorPvPMgr.h"
  42. #include "MapManager.h"
  43. #include "SocialMgr.h"
  44. #include "zlib.h"
  45. #include "ScriptMgr.h"
  46. #include "Transport.h"
  47. #include "WardenWin.h"
  48. #include "WardenMac.h"
  49.  
  50. namespace {
  51.  
  52. std::string const DefaultPlayerName = "<none>";
  53.  
  54. } // namespace
  55.  
  56. bool MapSessionFilter::Process(WorldPacket* packet)
  57. {
  58.     OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
  59.  
  60.     //let's check if our opcode can be really processed in Map::Update()
  61.     if (opHandle.packetProcessing == PROCESS_INPLACE)
  62.         return true;
  63.  
  64.     //we do not process thread-unsafe packets
  65.     if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
  66.         return false;
  67.  
  68.     Player* player = m_pSession->GetPlayer();
  69.     if (!player)
  70.         return false;
  71.  
  72.     //in Map::Update() we do not process packets where player is not in world!
  73.     return player->IsInWorld();
  74. }
  75.  
  76. //we should process ALL packets when player is not in world/logged in
  77. //OR packet handler is not thread-safe!
  78. bool WorldSessionFilter::Process(WorldPacket* packet)
  79. {
  80.     OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()];
  81.     //check if packet handler is supposed to be safe
  82.     if (opHandle.packetProcessing == PROCESS_INPLACE)
  83.         return true;
  84.  
  85.     //thread-unsafe packets should be processed in World::UpdateSessions()
  86.     if (opHandle.packetProcessing == PROCESS_THREADUNSAFE)
  87.         return true;
  88.  
  89.     //no player attached? -> our client! ^^
  90.     Player* player = m_pSession->GetPlayer();
  91.     if (!player)
  92.         return true;
  93.  
  94.     //lets process all packets for non-in-the-world player
  95.     return (player->IsInWorld() == false);
  96. }
  97.  
  98. /// WorldSession constructor
  99. WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter):
  100.     m_muteTime(mute_time),
  101.     m_timeOutTime(0),
  102.     AntiDOS(this),
  103.     _player(NULL),
  104.     m_Socket(sock),
  105.     _security(sec),
  106.     _accountId(id),
  107.     m_expansion(expansion),
  108.     _warden(NULL),
  109.     _logoutTime(0),
  110.     m_inQueue(false),
  111.     m_playerLoading(false),
  112.     m_playerLogout(false),
  113.     m_playerRecentlyLogout(false),
  114.     m_playerSave(false),
  115.     m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)),
  116.     m_sessionDbLocaleIndex(locale),
  117.     m_latency(0),
  118.     m_clientTimeDelay(0),
  119.     m_TutorialsChanged(false),
  120.     recruiterId(recruiter),
  121.     isRecruiter(isARecruiter),
  122.     timeLastWhoCommand(0),
  123.     _RBACData(NULL),
  124.     protectedPacketsCounter()
  125. {
  126.     if (sock)
  127.     {
  128.         m_Address = sock->GetRemoteAddress();
  129.         sock->AddReference();
  130.         ResetTimeOutTime();
  131.         LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId());     // One-time query
  132.     }
  133.  
  134.     InitializeQueryCallbackParameters();
  135. }
  136.  
  137. /// WorldSession destructor
  138. WorldSession::~WorldSession()
  139. {
  140.     ///- unload player if not unloaded
  141.     if (_player)
  142.         LogoutPlayer (true);
  143.  
  144.     /// - If have unclosed socket, close it
  145.     if (m_Socket)
  146.     {
  147.         m_Socket->CloseSocket();
  148.         m_Socket->RemoveReference();
  149.         m_Socket = NULL;
  150.     }
  151.  
  152.     delete _warden;
  153.     delete _RBACData;
  154.  
  155.     ///- empty incoming packet queue
  156.     WorldPacket* packet = NULL;
  157.     while (_recvQueue.next(packet))
  158.         delete packet;
  159.  
  160.     LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId());     // One-time query
  161. }
  162.  
  163. std::string const & WorldSession::GetPlayerName() const
  164. {
  165.     return _player != NULL ? _player->GetName() : DefaultPlayerName;
  166. }
  167.  
  168. std::string WorldSession::GetPlayerInfo() const
  169. {
  170.     std::ostringstream ss;
  171.  
  172.     ss << "[Player: " << GetPlayerName()
  173.        << " (Guid: " << (_player != NULL ? _player->GetGUID() : 0)
  174.        << ", Account: " << GetAccountId() << ")]";
  175.  
  176.     return ss.str();
  177. }
  178.  
  179. /// Get player guid if available. Use for logging purposes only
  180. uint32 WorldSession::GetGuidLow() const
  181. {
  182.     return GetPlayer() ? GetPlayer()->GetGUIDLow() : 0;
  183. }
  184.  
  185. /// Send a packet to the client
  186. void WorldSession::SendPacket(WorldPacket const* packet)
  187. {
  188.     if (!m_Socket)
  189.         return;
  190.  
  191. #ifdef TRINITY_DEBUG
  192.     // Code for network use statistic
  193.     static uint64 sendPacketCount = 0;
  194.     static uint64 sendPacketBytes = 0;
  195.  
  196.     static time_t firstTime = time(NULL);
  197.     static time_t lastTime = firstTime;                     // next 60 secs start time
  198.  
  199.     static uint64 sendLastPacketCount = 0;
  200.     static uint64 sendLastPacketBytes = 0;
  201.  
  202.     time_t cur_time = time(NULL);
  203.  
  204.     if ((cur_time - lastTime) < 60)
  205.     {
  206.         sendPacketCount+=1;
  207.         sendPacketBytes+=packet->size();
  208.  
  209.         sendLastPacketCount+=1;
  210.         sendLastPacketBytes+=packet->size();
  211.     }
  212.     else
  213.     {
  214.         uint64 minTime = uint64(cur_time - lastTime);
  215.         uint64 fullTime = uint64(lastTime - firstTime);
  216.         TC_LOG_INFO(LOG_FILTER_GENERAL, "Send all time packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u", sendPacketCount, sendPacketBytes, float(sendPacketCount)/fullTime, float(sendPacketBytes)/fullTime, uint32(fullTime));
  217.         TC_LOG_INFO(LOG_FILTER_GENERAL, "Send last min packets count: " UI64FMTD " bytes: " UI64FMTD " avr.count/sec: %f avr.bytes/sec: %f", sendLastPacketCount, sendLastPacketBytes, float(sendLastPacketCount)/minTime, float(sendLastPacketBytes)/minTime);
  218.  
  219.         lastTime = cur_time;
  220.         sendLastPacketCount = 1;
  221.         sendLastPacketBytes = packet->wpos();               // wpos is real written size
  222.     }
  223. #endif                                                      // !TRINITY_DEBUG
  224.  
  225.     if (m_Socket->SendPacket(*packet) == -1)
  226.         m_Socket->CloseSocket();
  227. }
  228.  
  229. /// Add an incoming packet to the queue
  230. void WorldSession::QueuePacket(WorldPacket* new_packet)
  231. {
  232.     _recvQueue.add(new_packet);
  233. }
  234.  
  235. /// Logging helper for unexpected opcodes
  236. void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, const char* status, const char *reason)
  237. {
  238.     TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received unexpected opcode %s Status: %s Reason: %s from %s",
  239.         GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), status, reason, GetPlayerInfo().c_str());
  240. }
  241.  
  242. /// Logging helper for unexpected opcodes
  243. void WorldSession::LogUnprocessedTail(WorldPacket* packet)
  244. {
  245.     if (!sLog->ShouldLog(LOG_FILTER_OPCODES, LOG_LEVEL_TRACE) || packet->rpos() >= packet->wpos())
  246.         return;
  247.  
  248.     TC_LOG_TRACE(LOG_FILTER_OPCODES, "Unprocessed tail data (read stop at %u from %u) Opcode %s from %s",
  249.         uint32(packet->rpos()), uint32(packet->wpos()), GetOpcodeNameForLogging(packet->GetOpcode()).c_str(), GetPlayerInfo().c_str());
  250.     packet->print_storage();
  251. }
  252.  
  253. /// Update the WorldSession (triggered by World update)
  254. bool WorldSession::Update(uint32 diff, PacketFilter& updater)
  255. {
  256.     /// Update Timeout timer.
  257.     UpdateTimeOutTime(diff);
  258.  
  259.     ///- Before we process anything:
  260.     /// If necessary, kick the player from the character select screen
  261.     if (IsConnectionIdle())
  262.         m_Socket->CloseSocket();
  263.  
  264.     ///- Retrieve packets from the receive queue and call the appropriate handlers
  265.     /// not process packets if socket already closed
  266.     WorldPacket* packet = NULL;
  267.     //! Delete packet after processing by default
  268.     bool deletePacket = true;
  269.     //! To prevent infinite loop
  270.     WorldPacket* firstDelayedPacket = NULL;
  271.     //! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all
  272.     //! *properly timed* packets, and we're now at the part of the queue where we find
  273.     //! delayed packets that were re-enqueued due to improper timing. To prevent an infinite
  274.     //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session
  275.     //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session.
  276.     uint32 processedPackets = 0;
  277.  
  278.     while (m_Socket && !m_Socket->IsClosed() &&
  279.             !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket &&
  280.             _recvQueue.next(packet, updater))
  281.     {
  282.         if (!AntiDOS.EvaluateOpcode(*packet))
  283.         {
  284.             KickPlayer();
  285.         }
  286.         else if (packet->GetOpcode() >= NUM_MSG_TYPES)
  287.         {
  288.             TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received non-existed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
  289.                             , GetPlayerInfo().c_str());
  290.             sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet));
  291.         }
  292.         else
  293.         {
  294.             OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()];
  295.             try
  296.             {
  297.                 switch (opHandle.status)
  298.                 {
  299.                     case STATUS_LOGGEDIN:
  300.                         if (!_player)
  301.                         {
  302.                             // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
  303.                             //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize
  304.                             //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later.
  305.                             if (!m_playerRecentlyLogout)
  306.                             {
  307.                                 //! Prevent infinite loop
  308.                                 if (!firstDelayedPacket)
  309.                                     firstDelayedPacket = packet;
  310.                                 //! Because checking a bool is faster than reallocating memory
  311.                                 deletePacket = false;
  312.                                 QueuePacket(packet);
  313.                                 //! Log
  314.                                 TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "Re-enqueueing packet with opcode %s with with status STATUS_LOGGEDIN. "
  315.                                     "Player is currently not in world yet.", GetOpcodeNameForLogging(packet->GetOpcode()).c_str());
  316.                             }
  317.                         }
  318.                         else if (_player->IsInWorld())
  319.                         {
  320.                             sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
  321.                             (this->*opHandle.handler)(*packet);
  322.                             LogUnprocessedTail(packet);
  323.                         }
  324.                         // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
  325.                         break;
  326.                     case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT:
  327.                         if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout
  328.                             LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT",
  329.                                 "the player has not logged in yet and not recently logout");
  330.                         else
  331.                         {
  332.                             // not expected _player or must checked in packet handler
  333.                             sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
  334.                             (this->*opHandle.handler)(*packet);
  335.                             LogUnprocessedTail(packet);
  336.                         }
  337.                         break;
  338.                     case STATUS_TRANSFER:
  339.                         if (!_player)
  340.                             LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet");
  341.                         else if (_player->IsInWorld())
  342.                             LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world");
  343.                         else
  344.                         {
  345.                             sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
  346.                             (this->*opHandle.handler)(*packet);
  347.                             LogUnprocessedTail(packet);
  348.                         }
  349.                         break;
  350.                     case STATUS_AUTHED:
  351.                         // prevent cheating with skip queue wait
  352.                         if (m_inQueue)
  353.                         {
  354.                             LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet");
  355.                             break;
  356.                         }
  357.  
  358.                         // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes
  359.                         // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process.
  360.                         if (packet->GetOpcode() == CMSG_CHAR_ENUM)
  361.                             m_playerRecentlyLogout = false;
  362.  
  363.                         sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet));
  364.                         (this->*opHandle.handler)(*packet);
  365.                         LogUnprocessedTail(packet);
  366.                         break;
  367.                     case STATUS_NEVER:
  368.                         TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received not allowed opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
  369.                             , GetPlayerInfo().c_str());
  370.                         break;
  371.                     case STATUS_UNHANDLED:
  372.                         TC_LOG_DEBUG(LOG_FILTER_OPCODES, "Received not handled opcode %s from %s", GetOpcodeNameForLogging(packet->GetOpcode()).c_str()
  373.                             , GetPlayerInfo().c_str());
  374.                         break;
  375.                 }
  376.             }
  377.             catch (ByteBufferException const&)
  378.             {
  379.                 TC_LOG_ERROR(LOG_FILTER_GENERAL, "WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
  380.                         packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
  381.                 packet->hexlike();
  382.             }
  383.         }
  384.  
  385.         if (deletePacket)
  386.             delete packet;
  387.  
  388.         deletePacket = true;
  389.  
  390. #define MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE 100
  391.         processedPackets++;
  392.  
  393.         //process only a max amout of packets in 1 Update() call.
  394.         //Any leftover will be processed in next update
  395.         if (processedPackets > MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE)
  396.             break;
  397.     }
  398.  
  399.     if (m_Socket && !m_Socket->IsClosed() && _warden)
  400.         _warden->Update();
  401.  
  402.     ProcessQueryCallbacks();
  403.  
  404.     //check if we are safe to proceed with logout
  405.     //logout procedure should happen only in World::UpdateSessions() method!!!
  406.     if (updater.ProcessLogout())
  407.     {
  408.         time_t currTime = time(NULL);
  409.         ///- If necessary, log the player out
  410.         if (ShouldLogOut(currTime) && !m_playerLoading)
  411.             LogoutPlayer(true);
  412.  
  413.         if (m_Socket && GetPlayer() && _warden)
  414.             _warden->Update();
  415.  
  416.         ///- Cleanup socket pointer if need
  417.         if (m_Socket && m_Socket->IsClosed())
  418.         {
  419.             m_Socket->RemoveReference();
  420.             m_Socket = NULL;
  421.         }
  422.  
  423.         if (!m_Socket)
  424.             return false;                                       //Will remove this session from the world session map
  425.     }
  426.  
  427.     return true;
  428. }
  429.  
  430. /// %Log the player out
  431. void WorldSession::LogoutPlayer(bool save)
  432. {
  433.     // finish pending transfers before starting the logout
  434.     while (_player && _player->IsBeingTeleportedFar())
  435.         HandleMoveWorldportAckOpcode();
  436.  
  437.     m_playerLogout = true;
  438.     m_playerSave = save;
  439.  
  440.     if (_player)
  441.     {
  442.         if (uint64 lguid = _player->GetLootGUID())
  443.             DoLootRelease(lguid);
  444.  
  445.         ///- If the player just died before logging out, make him appear as a ghost
  446.         //FIXME: logout must be delayed in case lost connection with client in time of combat
  447.         if (_player->GetDeathTimer())
  448.         {
  449.             _player->getHostileRefManager().deleteReferences();
  450.             _player->BuildPlayerRepop();
  451.             _player->RepopAtGraveyard();
  452.         }
  453.         else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
  454.         {
  455.             // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION
  456.             _player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
  457.             _player->KillPlayer();
  458.             _player->BuildPlayerRepop();
  459.             _player->RepopAtGraveyard();
  460.         }
  461.         else if (_player->HasPendingBind())
  462.         {
  463.             _player->RepopAtGraveyard();
  464.             _player->SetPendingBind(0, 0);
  465.         }
  466.  
  467.         //drop a flag if player is carrying it
  468.         if (Battleground* bg = _player->GetBattleground())
  469.             bg->EventPlayerLoggedOut(_player);
  470.  
  471.         ///- Teleport to home if the player is in an invalid instance
  472.         if (!_player->m_InstanceValid && !_player->IsGameMaster())
  473.             _player->TeleportTo(_player->m_homebindMapId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ, _player->GetOrientation());
  474.  
  475.         sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId());
  476.  
  477.         for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
  478.         {
  479.             if (BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i))
  480.             {
  481.                 _player->RemoveBattlegroundQueueId(bgQueueTypeId);
  482.                 BattlegroundQueue& queue = sBattlegroundMgr->GetBattlegroundQueue(bgQueueTypeId);
  483.                 queue.RemovePlayer(_player->GetGUID(), true);
  484.             }
  485.         }
  486.  
  487.         // Repop at GraveYard or other player far teleport will prevent saving player because of not present map
  488.         // Teleport player immediately for correct player save
  489.         while (_player->IsBeingTeleportedFar())
  490.             HandleMoveWorldportAckOpcode();
  491.  
  492.         ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members
  493.         if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId()))
  494.             guild->HandleMemberLogout(this);
  495.  
  496.         ///- Remove pet
  497.         _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true);
  498.  
  499.         ///- Clear whisper whitelist
  500.         _player->ClearWhisperWhiteList();
  501.  
  502.         ///- empty buyback items and save the player in the database
  503.         // some save parts only correctly work in case player present in map/player_lists (pets, etc)
  504.         if (save)
  505.         {
  506.             uint32 eslot;
  507.             for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j)
  508.             {
  509.                 eslot = j - BUYBACK_SLOT_START;
  510.                 _player->SetUInt64Value(PLAYER_FIELD_VENDORBUYBACK_SLOT_1 + (eslot * 2), 0);
  511.                 _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_PRICE_1 + eslot, 0);
  512.                 _player->SetUInt32Value(PLAYER_FIELD_BUYBACK_TIMESTAMP_1 + eslot, 0);
  513.             }
  514.             _player->SaveToDB();
  515.         }
  516.  
  517.         ///- Leave all channels before player delete...
  518.         _player->CleanupChannels();
  519.  
  520.         ///- If the player is in a group (or invited), remove him. If the group if then only 1 person, disband the group.
  521.         _player->UninviteFromGroup();
  522.  
  523.         // remove player from the group if he is:
  524.         // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected)
  525.         if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket)
  526.             _player->RemoveFromGroup();
  527.  
  528.         //! Send update to group and reset stored max enchanting level
  529.         if (_player->GetGroup())
  530.         {
  531.             _player->GetGroup()->SendUpdate();
  532.             _player->GetGroup()->ResetMaxEnchantingLevel();
  533.         }
  534.  
  535.         //! Broadcast a logout message to the player's friends
  536.         sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUIDLow(), true);
  537.         sSocialMgr->RemovePlayerSocial(_player->GetGUIDLow());
  538.  
  539.         //! Call script hook before deletion
  540.         sScriptMgr->OnPlayerLogout(_player);
  541.  
  542.         //! Remove the player from the world
  543.         // the player may not be in the world when logging out
  544.         // e.g if he got disconnected during a transfer to another map
  545.         // calls to GetMap in this case may cause crashes
  546.         _player->CleanupsBeforeDelete();
  547.         TC_LOG_INFO(LOG_FILTER_CHARACTER, "Account: %d (IP: %s) Logout Character:[%s] (GUID: %u) Level: %d",
  548.             GetAccountId(), GetRemoteAddress().c_str(), _player->GetName().c_str(), _player->GetGUIDLow(), _player->getLevel());
  549.         if (Map* _map = _player->FindMap())
  550.             _map->RemovePlayerFromMap(_player, true);
  551.  
  552.         SetPlayer(NULL); //! Pointer already deleted during RemovePlayerFromMap
  553.  
  554.         //! Send the 'logout complete' packet to the client
  555.         //! Client will respond by sending 3x CMSG_CANCEL_TRADE, which we currently dont handle
  556.         WorldPacket data(SMSG_LOGOUT_COMPLETE, 0);
  557.         SendPacket(&data);
  558.         TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "SESSION: Sent SMSG_LOGOUT_COMPLETE Message");
  559.  
  560.         //! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
  561.         PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE);
  562.         stmt->setUInt32(0, GetAccountId());
  563.         CharacterDatabase.Execute(stmt);
  564.     }
  565.  
  566.     m_playerLogout = false;
  567.     m_playerSave = false;
  568.     m_playerRecentlyLogout = true;
  569.     AntiDOS.AllowOpcode(CMSG_CHAR_ENUM, true);
  570.     LogoutRequest(0);
  571. }
  572.  
  573. /// Kick a player out of the World
  574. void WorldSession::KickPlayer()
  575. {
  576.     if (m_Socket)
  577.         m_Socket->CloseSocket();
  578. }
  579.  
  580. void WorldSession::SendNotification(const char *format, ...)
  581. {
  582.     if (format)
  583.     {
  584.         va_list ap;
  585.         char szStr[1024];
  586.         szStr[0] = '\0';
  587.         va_start(ap, format);
  588.         vsnprintf(szStr, 1024, format, ap);
  589.         va_end(ap);
  590.  
  591.         WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr) + 1));
  592.         data << szStr;
  593.         SendPacket(&data);
  594.     }
  595. }
  596.  
  597. void WorldSession::SendNotification(uint32 string_id, ...)
  598. {
  599.     char const* format = GetTrinityString(string_id);
  600.     if (format)
  601.     {
  602.         va_list ap;
  603.         char szStr[1024];
  604.         szStr[0] = '\0';
  605.         va_start(ap, string_id);
  606.         vsnprintf(szStr, 1024, format, ap);
  607.         va_end(ap);
  608.  
  609.         WorldPacket data(SMSG_NOTIFICATION, (strlen(szStr) + 1));
  610.         data << szStr;
  611.         SendPacket(&data);
  612.     }
  613. }
  614.  
  615. const char *WorldSession::GetTrinityString(int32 entry) const
  616. {
  617.     return sObjectMgr->GetTrinityString(entry, GetSessionDbLocaleIndex());
  618. }
  619.  
  620. void WorldSession::Handle_NULL(WorldPacket& recvPacket)
  621. {
  622.     TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received unhandled opcode %s from %s"
  623.         , GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
  624. }
  625.  
  626. void WorldSession::Handle_EarlyProccess(WorldPacket& recvPacket)
  627. {
  628.     TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received opcode %s that must be processed in WorldSocket::OnRead from %s"
  629.         , GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
  630. }
  631.  
  632. void WorldSession::Handle_ServerSide(WorldPacket& recvPacket)
  633. {
  634.     TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received server-side opcode %s from %s"
  635.         , GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
  636. }
  637.  
  638. void WorldSession::Handle_Deprecated(WorldPacket& recvPacket)
  639. {
  640.     TC_LOG_ERROR(LOG_FILTER_OPCODES, "Received deprecated opcode %s from %s"
  641.         , GetOpcodeNameForLogging(recvPacket.GetOpcode()).c_str(), GetPlayerInfo().c_str());
  642. }
  643.  
  644. void WorldSession::SendAuthWaitQue(uint32 position)
  645. {
  646.     if (position == 0)
  647.     {
  648.         WorldPacket packet(SMSG_AUTH_RESPONSE, 1);
  649.         packet << uint8(AUTH_OK);
  650.         SendPacket(&packet);
  651.     }
  652.     else
  653.     {
  654.         WorldPacket packet(SMSG_AUTH_RESPONSE, 6);
  655.         packet << uint8(AUTH_WAIT_QUEUE);
  656.         packet << uint32(position);
  657.         packet << uint8(0);                                 // unk
  658.         SendPacket(&packet);
  659.     }
  660. }
  661.  
  662. void WorldSession::LoadGlobalAccountData()
  663. {
  664.     PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_DATA);
  665.     stmt->setUInt32(0, GetAccountId());
  666.     LoadAccountData(CharacterDatabase.Query(stmt), GLOBAL_CACHE_MASK);
  667. }
  668.  
  669. void WorldSession::LoadAccountData(PreparedQueryResult result, uint32 mask)
  670. {
  671.     for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
  672.         if (mask & (1 << i))
  673.             m_accountData[i] = AccountData();
  674.  
  675.     if (!result)
  676.         return;
  677.  
  678.     do
  679.     {
  680.         Field* fields = result->Fetch();
  681.         uint32 type = fields[0].GetUInt8();
  682.         if (type >= NUM_ACCOUNT_DATA_TYPES)
  683.         {
  684.             TC_LOG_ERROR(LOG_FILTER_GENERAL, "Table `%s` have invalid account data type (%u), ignore.",
  685.                 mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type);
  686.             continue;
  687.         }
  688.  
  689.         if ((mask & (1 << type)) == 0)
  690.         {
  691.             TC_LOG_ERROR(LOG_FILTER_GENERAL, "Table `%s` have non appropriate for table  account data type (%u), ignore.",
  692.                 mask == GLOBAL_CACHE_MASK ? "account_data" : "character_account_data", type);
  693.             continue;
  694.         }
  695.  
  696.         m_accountData[type].Time = time_t(fields[1].GetUInt32());
  697.         m_accountData[type].Data = fields[2].GetString();
  698.     }
  699.     while (result->NextRow());
  700. }
  701.  
  702. void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string const& data)
  703. {
  704.     uint32 id = 0;
  705.     uint32 index = 0;
  706.     if ((1 << type) & GLOBAL_CACHE_MASK)
  707.     {
  708.         id = GetAccountId();
  709.         index = CHAR_REP_ACCOUNT_DATA;
  710.     }
  711.     else
  712.     {
  713.         // _player can be NULL and packet received after logout but m_GUID still store correct guid
  714.         if (!m_GUIDLow)
  715.             return;
  716.  
  717.         id = m_GUIDLow;
  718.         index = CHAR_REP_PLAYER_ACCOUNT_DATA;
  719.     }
  720.  
  721.     PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(index);
  722.     stmt->setUInt32(0, id);
  723.     stmt->setUInt8 (1, type);
  724.     stmt->setUInt32(2, uint32(tm));
  725.     stmt->setString(3, data);
  726.     CharacterDatabase.Execute(stmt);
  727.  
  728.     m_accountData[type].Time = tm;
  729.     m_accountData[type].Data = data;
  730. }
  731.  
  732. void WorldSession::SendAccountDataTimes(uint32 mask)
  733. {
  734.     WorldPacket data(SMSG_ACCOUNT_DATA_TIMES, 4 + 1 + 4 + NUM_ACCOUNT_DATA_TYPES * 4);
  735.     data << uint32(time(NULL));                             // Server time
  736.     data << uint8(1);
  737.     data << uint32(mask);                                   // type mask
  738.     for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i)
  739.         if (mask & (1 << i))
  740.             data << uint32(GetAccountData(AccountDataType(i))->Time);// also unix time
  741.     SendPacket(&data);
  742. }
  743.  
  744. void WorldSession::LoadTutorialsData()
  745. {
  746.     memset(m_Tutorials, 0, sizeof(uint32) * MAX_ACCOUNT_TUTORIAL_VALUES);
  747.  
  748.     PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_TUTORIALS);
  749.     stmt->setUInt32(0, GetAccountId());
  750.     if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
  751.         for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
  752.             m_Tutorials[i] = (*result)[i].GetUInt32();
  753.  
  754.     m_TutorialsChanged = false;
  755. }
  756.  
  757. void WorldSession::SendTutorialsData()
  758. {
  759.     WorldPacket data(SMSG_TUTORIAL_FLAGS, 4 * MAX_ACCOUNT_TUTORIAL_VALUES);
  760.     for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
  761.         data << m_Tutorials[i];
  762.     SendPacket(&data);
  763. }
  764.  
  765. void WorldSession::SaveTutorialsData(SQLTransaction &trans)
  766. {
  767.     if (!m_TutorialsChanged)
  768.         return;
  769.  
  770.     PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_HAS_TUTORIALS);
  771.     stmt->setUInt32(0, GetAccountId());
  772.     bool hasTutorials = !CharacterDatabase.Query(stmt).null();
  773.     // Modify data in DB
  774.     stmt = CharacterDatabase.GetPreparedStatement(hasTutorials ? CHAR_UPD_TUTORIALS : CHAR_INS_TUTORIALS);
  775.     for (uint8 i = 0; i < MAX_ACCOUNT_TUTORIAL_VALUES; ++i)
  776.         stmt->setUInt32(i, m_Tutorials[i]);
  777.     stmt->setUInt32(MAX_ACCOUNT_TUTORIAL_VALUES, GetAccountId());
  778.     trans->Append(stmt);
  779.  
  780.     m_TutorialsChanged = false;
  781. }
  782.  
  783. void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi)
  784. {
  785.     data >> mi->flags;
  786.     data >> mi->flags2;
  787.     data >> mi->time;
  788.     data >> mi->pos.PositionXYZOStream();
  789.  
  790.     if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
  791.     {
  792.         data.readPackGUID(mi->transport.guid);
  793.  
  794.         data >> mi->transport.pos.PositionXYZOStream();
  795.         data >> mi->transport.time;
  796.         data >> mi->transport.seat;
  797.  
  798.         if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT))
  799.             data >> mi->transport.time2;
  800.     }
  801.  
  802.     if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING)))
  803.         data >> mi->pitch;
  804.  
  805.     data >> mi->fallTime;
  806.  
  807.     if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING))
  808.     {
  809.         data >> mi->jump.zspeed;
  810.         data >> mi->jump.sinAngle;
  811.         data >> mi->jump.cosAngle;
  812.         data >> mi->jump.xyspeed;
  813.     }
  814.  
  815.     if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION))
  816.         data >> mi->splineElevation;
  817.  
  818.     //! Anti-cheat checks. Please keep them in seperate if () blocks to maintain a clear overview.
  819.     //! Might be subject to latency, so just remove improper flags.
  820.     #ifdef TRINITY_DEBUG
  821.     #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
  822.     { \
  823.         if (check) \
  824.         { \
  825.             TC_LOG_DEBUG(LOG_FILTER_UNITS, "WorldSession::ReadMovementInfo: Violation of MovementFlags found (%s). " \
  826.                 "MovementFlags: %u, MovementFlags2: %u for player GUID: %u. Mask %u will be removed.", \
  827.                 STRINGIZE(check), mi->GetMovementFlags(), mi->GetExtraMovementFlags(), GetPlayer()->GetGUIDLow(), maskToRemove); \
  828.             mi->RemoveMovementFlag((maskToRemove)); \
  829.         } \
  830.     }
  831.     #else
  832.     #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
  833.         if (check) \
  834.             mi->RemoveMovementFlag((maskToRemove));
  835.     #endif
  836.  
  837.  
  838.     /*! This must be a packet spoofing attempt. MOVEMENTFLAG_ROOT sent from the client is not valid
  839.         in conjunction with any of the moving movement flags such as MOVEMENTFLAG_FORWARD.
  840.         It will freeze clients that receive this player's movement info.
  841.     */
  842.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ROOT),
  843.         MOVEMENTFLAG_ROOT);
  844.  
  845.     //! Cannot hover without SPELL_AURA_HOVER
  846.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_HOVER) && !GetPlayer()->HasAuraType(SPELL_AURA_HOVER),
  847.         MOVEMENTFLAG_HOVER);
  848.  
  849.     //! Cannot ascend and descend at the same time
  850.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_ASCENDING) && mi->HasMovementFlag(MOVEMENTFLAG_DESCENDING),
  851.         MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING);
  852.  
  853.     //! Cannot move left and right at the same time
  854.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_RIGHT),
  855.         MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT);
  856.  
  857.     //! Cannot strafe left and right at the same time
  858.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_LEFT) && mi->HasMovementFlag(MOVEMENTFLAG_STRAFE_RIGHT),
  859.         MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT);
  860.  
  861.     //! Cannot pitch up and down at the same time
  862.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_PITCH_UP) && mi->HasMovementFlag(MOVEMENTFLAG_PITCH_DOWN),
  863.         MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN);
  864.  
  865.     //! Cannot move forwards and backwards at the same time
  866.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FORWARD) && mi->HasMovementFlag(MOVEMENTFLAG_BACKWARD),
  867.         MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD);
  868.  
  869.     //! Cannot walk on water without SPELL_AURA_WATER_WALK
  870.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK),
  871.         MOVEMENTFLAG_WATERWALKING);
  872.  
  873.     //! Cannot feather fall without SPELL_AURA_FEATHER_FALL
  874.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FALLING_SLOW) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL),
  875.         MOVEMENTFLAG_FALLING_SLOW);
  876.  
  877.     /*! Cannot fly if no fly auras present. Exception is being a GM.
  878.         Note that we check for account level instead of Player::IsGameMaster() because in some
  879.         situations it may be feasable to use .gm fly on as a GM without having .gm on,
  880.         e.g. aerial combat.
  881.     */
  882.  
  883.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY) && GetSecurity() == SEC_PLAYER &&
  884.         !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_FLY) &&
  885.         !GetPlayer()->m_mover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED),
  886.         MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY);
  887.  
  888.     //! Cannot fly and fall at the same time
  889.     REMOVE_VIOLATING_FLAGS(mi->HasMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY) && mi->HasMovementFlag(MOVEMENTFLAG_FALLING),
  890.         MOVEMENTFLAG_FALLING);
  891.  
  892.     #undef REMOVE_VIOLATING_FLAGS
  893. }
  894.  
  895. void WorldSession::WriteMovementInfo(WorldPacket* data, MovementInfo* mi)
  896. {
  897.     data->appendPackGUID(mi->guid);
  898.  
  899.     *data << mi->flags;
  900.     *data << mi->flags2;
  901.     *data << mi->time;
  902.     *data << mi->pos.PositionXYZOStream();
  903.  
  904.     if (mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
  905.     {
  906.        data->appendPackGUID(mi->transport.guid);
  907.  
  908.        *data << mi->transport.pos.PositionXYZOStream();
  909.        *data << mi->transport.time;
  910.        *data << mi->transport.seat;
  911.  
  912.        if (mi->HasExtraMovementFlag(MOVEMENTFLAG2_INTERPOLATED_MOVEMENT))
  913.            *data << mi->transport.time2;
  914.     }
  915.  
  916.     if (mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || mi->HasExtraMovementFlag(MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING))
  917.         *data << mi->pitch;
  918.  
  919.     *data << mi->fallTime;
  920.  
  921.     if (mi->HasMovementFlag(MOVEMENTFLAG_FALLING))
  922.     {
  923.         *data << mi->jump.zspeed;
  924.         *data << mi->jump.sinAngle;
  925.         *data << mi->jump.cosAngle;
  926.         *data << mi->jump.xyspeed;
  927.     }
  928.  
  929.     if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION))
  930.         *data << mi->splineElevation;
  931. }
  932.  
  933. void WorldSession::ReadAddonsInfo(WorldPacket &data)
  934. {
  935.     if (data.rpos() + 4 > data.size())
  936.         return;
  937.  
  938.     uint32 size;
  939.     data >> size;
  940.  
  941.     if (!size)
  942.         return;
  943.  
  944.     if (size > 0xFFFFF)
  945.     {
  946.         TC_LOG_ERROR(LOG_FILTER_GENERAL, "WorldSession::ReadAddonsInfo addon info too big, size %u", size);
  947.         return;
  948.     }
  949.  
  950.     uLongf uSize = size;
  951.  
  952.     uint32 pos = data.rpos();
  953.  
  954.     ByteBuffer addonInfo;
  955.     addonInfo.resize(size);
  956.  
  957.     if (uncompress(addonInfo.contents(), &uSize, data.contents() + pos, data.size() - pos) == Z_OK)
  958.     {
  959.         uint32 addonsCount;
  960.         addonInfo >> addonsCount;                         // addons count
  961.  
  962.         for (uint32 i = 0; i < addonsCount; ++i)
  963.         {
  964.             std::string addonName;
  965.             uint8 enabled;
  966.             uint32 crc, unk1;
  967.  
  968.             // check next addon data format correctness
  969.             if (addonInfo.rpos() + 1 > addonInfo.size())
  970.                 return;
  971.  
  972.             addonInfo >> addonName;
  973.  
  974.             addonInfo >> enabled >> crc >> unk1;
  975.  
  976.             TC_LOG_INFO(LOG_FILTER_GENERAL, "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk1);
  977.  
  978.             AddonInfo addon(addonName, enabled, crc, 2, true);
  979.  
  980.             SavedAddon const* savedAddon = AddonMgr::GetAddonInfo(addonName);
  981.             if (savedAddon)
  982.             {
  983.                 if (addon.CRC != savedAddon->CRC)
  984.                     TC_LOG_INFO(LOG_FILTER_GENERAL, "ADDON: %s was known, but didn't match known CRC (0x%x)!", addon.Name.c_str(), savedAddon->CRC);
  985.                 else
  986.                     TC_LOG_INFO(LOG_FILTER_GENERAL, "ADDON: %s was known, CRC is correct (0x%x)", addon.Name.c_str(), savedAddon->CRC);
  987.             }
  988.             else
  989.             {
  990.                 AddonMgr::SaveAddon(addon);
  991.  
  992.                 TC_LOG_INFO(LOG_FILTER_GENERAL, "ADDON: %s (0x%x) was not known, saving...", addon.Name.c_str(), addon.CRC);
  993.             }
  994.  
  995.             /// @todo Find out when to not use CRC/pubkey, and other possible states.
  996.             m_addonsList.push_back(addon);
  997.         }
  998.  
  999.         uint32 currentTime;
  1000.         addonInfo >> currentTime;
  1001.         TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "ADDON: CurrentTime: %u", currentTime);
  1002.     }
  1003.     else
  1004.         TC_LOG_ERROR(LOG_FILTER_GENERAL, "Addon packet uncompress error!");
  1005. }
  1006.  
  1007. void WorldSession::SendAddonsInfo()
  1008. {
  1009.     uint8 addonPublicKey[256] =
  1010.     {
  1011.         0xC3, 0x5B, 0x50, 0x84, 0xB9, 0x3E, 0x32, 0x42, 0x8C, 0xD0, 0xC7, 0x48, 0xFA, 0x0E, 0x5D, 0x54,
  1012.         0x5A, 0xA3, 0x0E, 0x14, 0xBA, 0x9E, 0x0D, 0xB9, 0x5D, 0x8B, 0xEE, 0xB6, 0x84, 0x93, 0x45, 0x75,
  1013.         0xFF, 0x31, 0xFE, 0x2F, 0x64, 0x3F, 0x3D, 0x6D, 0x07, 0xD9, 0x44, 0x9B, 0x40, 0x85, 0x59, 0x34,
  1014.         0x4E, 0x10, 0xE1, 0xE7, 0x43, 0x69, 0xEF, 0x7C, 0x16, 0xFC, 0xB4, 0xED, 0x1B, 0x95, 0x28, 0xA8,
  1015.         0x23, 0x76, 0x51, 0x31, 0x57, 0x30, 0x2B, 0x79, 0x08, 0x50, 0x10, 0x1C, 0x4A, 0x1A, 0x2C, 0xC8,
  1016.         0x8B, 0x8F, 0x05, 0x2D, 0x22, 0x3D, 0xDB, 0x5A, 0x24, 0x7A, 0x0F, 0x13, 0x50, 0x37, 0x8F, 0x5A,
  1017.         0xCC, 0x9E, 0x04, 0x44, 0x0E, 0x87, 0x01, 0xD4, 0xA3, 0x15, 0x94, 0x16, 0x34, 0xC6, 0xC2, 0xC3,
  1018.         0xFB, 0x49, 0xFE, 0xE1, 0xF9, 0xDA, 0x8C, 0x50, 0x3C, 0xBE, 0x2C, 0xBB, 0x57, 0xED, 0x46, 0xB9,
  1019.         0xAD, 0x8B, 0xC6, 0xDF, 0x0E, 0xD6, 0x0F, 0xBE, 0x80, 0xB3, 0x8B, 0x1E, 0x77, 0xCF, 0xAD, 0x22,
  1020.         0xCF, 0xB7, 0x4B, 0xCF, 0xFB, 0xF0, 0x6B, 0x11, 0x45, 0x2D, 0x7A, 0x81, 0x18, 0xF2, 0x92, 0x7E,
  1021.         0x98, 0x56, 0x5D, 0x5E, 0x69, 0x72, 0x0A, 0x0D, 0x03, 0x0A, 0x85, 0xA2, 0x85, 0x9C, 0xCB, 0xFB,
  1022.         0x56, 0x6E, 0x8F, 0x44, 0xBB, 0x8F, 0x02, 0x22, 0x68, 0x63, 0x97, 0xBC, 0x85, 0xBA, 0xA8, 0xF7,
  1023.         0xB5, 0x40, 0x68, 0x3C, 0x77, 0x86, 0x6F, 0x4B, 0xD7, 0x88, 0xCA, 0x8A, 0xD7, 0xCE, 0x36, 0xF0,
  1024.         0x45, 0x6E, 0xD5, 0x64, 0x79, 0x0F, 0x17, 0xFC, 0x64, 0xDD, 0x10, 0x6F, 0xF3, 0xF5, 0xE0, 0xA6,
  1025.         0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A,
  1026.         0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2
  1027.     };
  1028.  
  1029.     WorldPacket data(SMSG_ADDON_INFO, 4);
  1030.  
  1031.     for (AddonsList::iterator itr = m_addonsList.begin(); itr != m_addonsList.end(); ++itr)
  1032.     {
  1033.         data << uint8(itr->State);
  1034.  
  1035.         uint8 crcpub = itr->UsePublicKeyOrCRC;
  1036.         data << uint8(crcpub);
  1037.         if (crcpub)
  1038.         {
  1039.             uint8 usepk = (itr->CRC != STANDARD_ADDON_CRC); // If addon is Standard addon CRC
  1040.             data << uint8(usepk);
  1041.             if (usepk)                                      // if CRC is wrong, add public key (client need it)
  1042.             {
  1043.                 TC_LOG_INFO(LOG_FILTER_GENERAL, "ADDON: CRC (0x%x) for addon %s is wrong (does not match expected 0x%x), sending pubkey",
  1044.                     itr->CRC, itr->Name.c_str(), STANDARD_ADDON_CRC);
  1045.  
  1046.                 data.append(addonPublicKey, sizeof(addonPublicKey));
  1047.             }
  1048.  
  1049.             data << uint32(0);                              /// @todo Find out the meaning of this.
  1050.         }
  1051.  
  1052.         data << uint8(0);       // uses URL
  1053.         //if (usesURL)
  1054.         //    data << uint8(0); // URL
  1055.     }
  1056.  
  1057.     m_addonsList.clear();
  1058.  
  1059.     AddonMgr::BannedAddonList const* bannedAddons = AddonMgr::GetBannedAddons();
  1060.     data << uint32(bannedAddons->size());
  1061.     for (AddonMgr::BannedAddonList::const_iterator itr = bannedAddons->begin(); itr != bannedAddons->end(); ++itr)
  1062.     {
  1063.         data << uint32(itr->Id);
  1064.         data.append(itr->NameMD5, sizeof(itr->NameMD5));
  1065.         data.append(itr->VersionMD5, sizeof(itr->VersionMD5));
  1066.         data << uint32(itr->Timestamp);
  1067.         data << uint32(1);  // IsBanned
  1068.     }
  1069.  
  1070.     SendPacket(&data);
  1071. }
  1072.  
  1073. void WorldSession::SetPlayer(Player* player)
  1074. {
  1075.     _player = player;
  1076.  
  1077.     // set m_GUID that can be used while player loggined and later until m_playerRecentlyLogout not reset
  1078.     if (_player)
  1079.         m_GUIDLow = _player->GetGUIDLow();
  1080. }
  1081.  
  1082. void WorldSession::InitializeQueryCallbackParameters()
  1083. {
  1084.     // Callback parameters that have pointers in them should be properly
  1085.     // initialized to NULL here.
  1086.     _charCreateCallback.SetParam(NULL);
  1087. }
  1088.  
  1089. void WorldSession::ProcessQueryCallbacks()
  1090. {
  1091.     PreparedQueryResult result;
  1092.  
  1093.     //! HandleCharEnumOpcode
  1094.     if (_charEnumCallback.ready())
  1095.     {
  1096.         _charEnumCallback.get(result);
  1097.         HandleCharEnum(result);
  1098.         _charEnumCallback.cancel();
  1099.     }
  1100.  
  1101.     if (_charCreateCallback.IsReady())
  1102.     {
  1103.         _charCreateCallback.GetResult(result);
  1104.         HandleCharCreateCallback(result, _charCreateCallback.GetParam());
  1105.         // Don't call FreeResult() here, the callback handler will do that depending on the events in the callback chain
  1106.     }
  1107.  
  1108.     //! HandlePlayerLoginOpcode
  1109.     if (_charLoginCallback.ready())
  1110.     {
  1111.         SQLQueryHolder* param;
  1112.         _charLoginCallback.get(param);
  1113.         HandlePlayerLogin((LoginQueryHolder*)param);
  1114.         _charLoginCallback.cancel();
  1115.     }
  1116.  
  1117.     //! HandleAddFriendOpcode
  1118.     if (_addFriendCallback.IsReady())
  1119.     {
  1120.         std::string param = _addFriendCallback.GetParam();
  1121.         _addFriendCallback.GetResult(result);
  1122.         HandleAddFriendOpcodeCallBack(result, param);
  1123.         _addFriendCallback.FreeResult();
  1124.     }
  1125.  
  1126.     //- HandleCharRenameOpcode
  1127.     if (_charRenameCallback.IsReady())
  1128.     {
  1129.         std::string param = _charRenameCallback.GetParam();
  1130.         _charRenameCallback.GetResult(result);
  1131.         HandleChangePlayerNameOpcodeCallBack(result, param);
  1132.         _charRenameCallback.FreeResult();
  1133.     }
  1134.  
  1135.     //- HandleCharAddIgnoreOpcode
  1136.     if (_addIgnoreCallback.ready())
  1137.     {
  1138.         _addIgnoreCallback.get(result);
  1139.         HandleAddIgnoreOpcodeCallBack(result);
  1140.         _addIgnoreCallback.cancel();
  1141.     }
  1142.  
  1143.     //- SendStabledPet
  1144.     if (_sendStabledPetCallback.IsReady())
  1145.     {
  1146.         uint64 param = _sendStabledPetCallback.GetParam();
  1147.         _sendStabledPetCallback.GetResult(result);
  1148.         SendStablePetCallback(result, param);
  1149.         _sendStabledPetCallback.FreeResult();
  1150.     }
  1151.  
  1152.     //- HandleStablePet
  1153.     if (_stablePetCallback.ready())
  1154.     {
  1155.         _stablePetCallback.get(result);
  1156.         HandleStablePetCallback(result);
  1157.         _stablePetCallback.cancel();
  1158.     }
  1159.  
  1160.     //- HandleUnstablePet
  1161.     if (_unstablePetCallback.IsReady())
  1162.     {
  1163.         uint32 param = _unstablePetCallback.GetParam();
  1164.         _unstablePetCallback.GetResult(result);
  1165.         HandleUnstablePetCallback(result, param);
  1166.         _unstablePetCallback.FreeResult();
  1167.     }
  1168.  
  1169.     //- HandleStableSwapPet
  1170.     if (_stableSwapCallback.IsReady())
  1171.     {
  1172.         uint32 param = _stableSwapCallback.GetParam();
  1173.         _stableSwapCallback.GetResult(result);
  1174.         HandleStableSwapPetCallback(result, param);
  1175.         _stableSwapCallback.FreeResult();
  1176.     }
  1177. }
  1178.  
  1179. void WorldSession::InitWarden(BigNumber* k, std::string const& os)
  1180. {
  1181.     if (os == "Win")
  1182.     {
  1183.         _warden = new WardenWin();
  1184.         _warden->Init(this, k);
  1185.     }
  1186.     else if (os == "OSX")
  1187.     {
  1188.         // Disabled as it is causing the client to crash
  1189.         // _warden = new WardenMac();
  1190.         // _warden->Init(this, k);
  1191.     }
  1192. }
  1193.  
  1194. void WorldSession::LoadPermissions()
  1195. {
  1196.     uint32 id = GetAccountId();
  1197.     std::string name;
  1198.     AccountMgr::GetName(id, name);
  1199.     uint8 secLevel = GetSecurity();
  1200.  
  1201.     _RBACData = new rbac::RBACData(id, name, realmID, secLevel);
  1202.     _RBACData->LoadFromDB();
  1203.  
  1204.     TC_LOG_DEBUG(LOG_FILTER_RBAC, "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]",
  1205.                    id, name.c_str(), realmID, secLevel);
  1206. }
  1207.  
  1208. rbac::RBACData* WorldSession::GetRBACData()
  1209. {
  1210.     return _RBACData;
  1211. }
  1212.  
  1213. bool WorldSession::HasPermission(uint32 permission)
  1214. {
  1215.     if (!_RBACData)
  1216.         LoadPermissions();
  1217.  
  1218.     bool hasPermission = _RBACData->HasPermission(permission);
  1219.     TC_LOG_DEBUG(LOG_FILTER_RBAC, "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]",
  1220.                    _RBACData->GetId(), _RBACData->GetName().c_str(), realmID);
  1221.  
  1222.     return hasPermission;
  1223. }
  1224.  
  1225. void WorldSession::InvalidateRBACData()
  1226. {
  1227.     TC_LOG_DEBUG(LOG_FILTER_RBAC, "WorldSession::Invalidaterbac::RBACData [AccountId: %u, Name: %s, realmId: %d]",
  1228.                    _RBACData->GetId(), _RBACData->GetName().c_str(), realmID);
  1229.     delete _RBACData;
  1230.     _RBACData = NULL;
  1231. }
  1232.  
  1233. bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p) const
  1234. {
  1235.     if (IsOpcodeAllowed(p.GetOpcode()))
  1236.         return true;
  1237.  
  1238.     // Opcode not allowed, let the punishment begin
  1239.     TC_LOG_INFO(LOG_FILTER_NETWORKIO, "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)",
  1240.         Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size());
  1241.  
  1242.     switch (_policy)
  1243.     {
  1244.         case POLICY_LOG:
  1245.             return true;
  1246.         case POLICY_KICK:
  1247.             TC_LOG_INFO(LOG_FILTER_NETWORKIO, "AntiDOS: Player kicked!");
  1248.             return false;
  1249.         case POLICY_BAN:
  1250.         {
  1251.             BanMode bm = (BanMode)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANMODE);
  1252.             uint32 duration = sWorld->getIntConfig(CONFIG_PACKET_SPOOF_BANDURATION); // in seconds
  1253.             std::string nameOrIp = "";
  1254.             switch (bm)
  1255.             {
  1256.                 case BAN_CHARACTER: // not supported, ban account
  1257.                 case BAN_ACCOUNT: (void)sAccountMgr->GetName(Session->GetAccountId(), nameOrIp); break;
  1258.                 case BAN_IP: nameOrIp = Session->GetRemoteAddress(); break;
  1259.             }
  1260.             sWorld->BanAccount(bm, nameOrIp, duration, "DOS (Packet Flooding/Spoofing", "Server: AutoDOS");
  1261.             TC_LOG_INFO(LOG_FILTER_NETWORKIO, "AntiDOS: Player automatically banned for %u seconds.", duration);
  1262.  
  1263.             return false;
  1264.         }
  1265.         default: // invalid policy
  1266.             return true;
  1267.     }
  1268. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement