/* * Copyright (C) 2008-2019 TrinityCore * Copyright (C) 2005-2009 MaNGOS * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "WorldSession.h" #include "Common.h" #include "Corpse.h" #include "DatabaseEnv.h" #include "DB2Stores.h" #include "Item.h" #include "Log.h" #include "MapManager.h" #include "NPCHandler.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" #include "QueryPackets.h" #include "Realm.h" #include "World.h" #include "WorldPacket.h" void WorldSession::SendNameQueryOpcode(ObjectGuid guid) { Player* player = ObjectAccessor::FindConnectedPlayer(guid); WorldPackets::Query::QueryPlayerNameResponse response; response.Player = guid; if (response.Data.Initialize(guid, player)) response.Result = RESPONSE_SUCCESS; // name known else response.Result = RESPONSE_FAILURE; // name unknown SendPacket(response.Write()); } void WorldSession::HandleNameQueryOpcode(WorldPackets::Query::QueryPlayerName& packet) { SendNameQueryOpcode(packet.Player); } void WorldSession::HandleQueryTimeOpcode(WorldPackets::Query::QueryTime& /*queryTime*/) { SendQueryTimeResponse(); } void WorldSession::SendQueryTimeResponse() { WorldPackets::Query::QueryTimeResponse queryTimeResponse; queryTimeResponse.CurrentTime = time(nullptr); SendPacket(queryTimeResponse.Write()); } /// Only _static_ data is sent in this packet !!! void WorldSession::HandleCreatureQuery(WorldPackets::Query::QueryCreature& packet) { if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(packet.CreatureID)) { TC_LOG_DEBUG("network", "WORLD: CMSG_QUERY_CREATURE '%s' - Entry: %u.", ci->Name.c_str(), packet.CreatureID); if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES)) SendPacket(&ci->QueryData[static_cast(GetSessionDbLocaleIndex())]); else { WorldPacket response = ci->BuildQueryData(GetSessionDbLocaleIndex()); SendPacket(&response); } TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUERY_CREATURE_RESPONSE"); } else { TC_LOG_DEBUG("network", "WORLD: CMSG_QUERY_CREATURE - NO CREATURE INFO! (ENTRY: %u)", packet.CreatureID); WorldPackets::Query::QueryCreatureResponse response; response.CreatureID = packet.CreatureID; SendPacket(response.Write()); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUERY_CREATURE_RESPONSE"); } } /// Only _static_ data is sent in this packet !!! void WorldSession::HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& packet) { if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(packet.GameObjectID)) { if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES)) SendPacket(&info->QueryData[static_cast(GetSessionDbLocaleIndex())]); else { WorldPacket response = info->BuildQueryData(GetSessionDbLocaleIndex()); SendPacket(&response); } TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); } else { TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (ENTRY: %u)", packet.GameObjectID); WorldPackets::Query::QueryGameObjectResponse response; response.GameObjectID = packet.GameObjectID; SendPacket(response.Write()); TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE"); } } void WorldSession::HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLocationFromClient& queryCorpseLocation) { Player* player = ObjectAccessor::FindConnectedPlayer(queryCorpseLocation.Player); if (!player || !player->HasCorpse() || !_player->IsInSameRaidWith(player)) { WorldPackets::Query::CorpseLocation packet; packet.Valid = false; // corpse not found packet.Player = queryCorpseLocation.Player; SendPacket(packet.Write()); return; } WorldLocation corpseLocation = player->GetCorpseLocation(); uint32 corpseMapID = corpseLocation.GetMapId(); uint32 mapID = corpseLocation.GetMapId(); float x = corpseLocation.GetPositionX(); float y = corpseLocation.GetPositionY(); float z = corpseLocation.GetPositionZ(); // if corpse at different map if (mapID != player->GetMapId()) { // search entrance map for proper show entrance if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapID)) { if (corpseMapEntry->IsDungeon() && corpseMapEntry->CorpseMapID >= 0) { // if corpse map have entrance if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->CorpseMapID)) { mapID = corpseMapEntry->CorpseMapID; x = corpseMapEntry->Corpse.X; y = corpseMapEntry->Corpse.Y; z = entranceMap->GetHeight(player->GetPhaseShift(), x, y, MAX_HEIGHT); } } } } WorldPackets::Query::CorpseLocation packet; packet.Valid = true; packet.Player = queryCorpseLocation.Player; packet.MapID = corpseMapID; packet.ActualMapID = mapID; packet.Position = Position(x, y, z); packet.Transport = ObjectGuid::Empty; SendPacket(packet.Write()); } void WorldSession::HandleNpcTextQueryOpcode(WorldPackets::Query::QueryNPCText& packet) { TC_LOG_DEBUG("network", "WORLD: CMSG_NPC_TEXT_QUERY TextId: %u", packet.TextID); NpcText const* npcText = sObjectMgr->GetNpcText(packet.TextID); WorldPackets::Query::QueryNPCTextResponse response; response.TextID = packet.TextID; if (npcText) { for (uint8 i = 0; i < MAX_NPC_TEXT_OPTIONS; ++i) { response.Probabilities[i] = npcText->Data[i].Probability; response.BroadcastTextID[i] = npcText->Data[i].BroadcastTextID; if (!response.Allow && npcText->Data[i].BroadcastTextID) response.Allow = true; } } if (!response.Allow) TC_LOG_ERROR("sql.sql", "HandleNpcTextQueryOpcode: no BroadcastTextID found for text %u in `npc_text table`", packet.TextID); SendPacket(response.Write()); } /// Only _static_ data is sent in this packet !!! void WorldSession::HandleQueryPageText(WorldPackets::Query::QueryPageText& packet) { WorldPackets::Query::QueryPageTextResponse response; response.PageTextID = packet.PageTextID; uint32 pageID = packet.PageTextID; while (pageID) { PageText const* pageText = sObjectMgr->GetPageText(pageID); if (!pageText) break; WorldPackets::Query::QueryPageTextResponse::PageTextInfo page; page.ID = pageID; page.NextPageID = pageText->NextPageID; page.Text = pageText->Text; page.PlayerConditionID = pageText->PlayerConditionID; page.Flags = pageText->Flags; LocaleConstant locale = GetSessionDbLocaleIndex(); if (locale != LOCALE_enUS) if (PageTextLocale const* pageTextLocale = sObjectMgr->GetPageTextLocale(pageID)) ObjectMgr::GetLocaleString(pageTextLocale->Text, locale, page.Text); response.Pages.push_back(page); pageID = pageText->NextPageID; } response.Allow = !response.Pages.empty(); SendPacket(response.Write()); } void WorldSession::HandleQueryCorpseTransport(WorldPackets::Query::QueryCorpseTransport& queryCorpseTransport) { WorldPackets::Query::CorpseTransportQuery response; response.Player = queryCorpseTransport.Player; if (Player* player = ObjectAccessor::FindConnectedPlayer(queryCorpseTransport.Player)) { Corpse* corpse = player->GetCorpse(); if (_player->IsInSameRaidWith(player) && corpse && !corpse->GetTransGUID().IsEmpty() && corpse->GetTransGUID() == queryCorpseTransport.Transport) { response.Position = corpse->GetTransOffset(); response.Facing = corpse->GetTransOffsetO(); } } SendPacket(response.Write()); } void WorldSession::HandleQueryQuestCompletionNPCs(WorldPackets::Query::QueryQuestCompletionNPCs& queryQuestCompletionNPCs) { WorldPackets::Query::QuestCompletionNPCResponse response; for (int32& questID : queryQuestCompletionNPCs.QuestCompletionNPCs) { WorldPackets::Query::QuestCompletionNPC questCompletionNPC; if (!sObjectMgr->GetQuestTemplate(questID)) { TC_LOG_DEBUG("network", "WORLD: Unknown quest %u in CMSG_QUERY_QUEST_COMPLETION_NPCS by %s", questID, _player->GetGUID().ToString().c_str()); continue; } questCompletionNPC.QuestID = questID; auto creatures = sObjectMgr->GetCreatureQuestInvolvedRelationReverseBounds(questID); for (auto it = creatures.first; it != creatures.second; ++it) questCompletionNPC.NPCs.push_back(it->second); auto gos = sObjectMgr->GetGOQuestInvolvedRelationReverseBounds(questID); for (auto it = gos.first; it != gos.second; ++it) questCompletionNPC.NPCs.push_back(it->second | 0x80000000); // GO mask response.QuestCompletionNPCs.push_back(questCompletionNPC); } SendPacket(response.Write()); } void WorldSession::HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& questPoiQuery) { if (questPoiQuery.MissingQuestCount > MAX_QUEST_LOG_SIZE) return; // Read quest ids and add the in a unordered_set so we don't send POIs for the same quest multiple times std::unordered_set questIds; for (int32 i = 0; i < questPoiQuery.MissingQuestCount; ++i) questIds.insert(questPoiQuery.MissingQuestPOIs[i]); // QuestID WorldPackets::Query::QuestPOIQueryResponse response; for (uint32 questId : questIds) if (_player->FindQuestSlot(questId) != MAX_QUEST_LOG_SIZE) if (QuestPOIData const* poiData = sObjectMgr->GetQuestPOIData(questId)) response.QuestPOIDataStats.push_back(poiData); SendPacket(response.Write()); } /** * Handles the packet sent by the client when requesting information about item text. * * This function is called when player clicks on item which has some flag set */ void WorldSession::HandleItemTextQuery(WorldPackets::Query::ItemTextQuery& itemTextQuery) { WorldPackets::Query::QueryItemTextResponse queryItemTextResponse; queryItemTextResponse.Id = itemTextQuery.Id; if (Item* item = _player->GetItemByGuid(itemTextQuery.Id)) { queryItemTextResponse.Valid = true; queryItemTextResponse.Item.Text = item->GetText(); } SendPacket(queryItemTextResponse.Write()); } void WorldSession::HandleQueryRealmName(WorldPackets::Query::QueryRealmName& queryRealmName) { WorldPackets::Query::RealmQueryResponse realmQueryResponse; realmQueryResponse.VirtualRealmAddress = queryRealmName.VirtualRealmAddress; Battlenet::RealmHandle realmHandle(queryRealmName.VirtualRealmAddress); if (sObjectMgr->GetRealmName(realmHandle.Realm, realmQueryResponse.NameInfo.RealmNameActual, realmQueryResponse.NameInfo.RealmNameNormalized)) { realmQueryResponse.LookupState = RESPONSE_SUCCESS; realmQueryResponse.NameInfo.IsInternalRealm = false; realmQueryResponse.NameInfo.IsLocal = queryRealmName.VirtualRealmAddress == realm.Id.GetAddress(); } else realmQueryResponse.LookupState = RESPONSE_FAILURE; }