mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-18 00:18:43 +01:00
375 lines
12 KiB
C++
375 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Common.h"
|
|
#include "DatabaseEnv.h"
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
#include "Log.h"
|
|
#include "World.h"
|
|
#include "ObjectMgr.h"
|
|
#include "Player.h"
|
|
#include "UpdateMask.h"
|
|
#include "NPCHandler.h"
|
|
#include "MapManager.h"
|
|
#include "CharacterCache.h"
|
|
|
|
#include "Packets/QueryPackets.h"
|
|
|
|
void WorldSession::SendNameQueryOpcode(ObjectGuid guid)
|
|
{
|
|
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
|
|
CharacterCacheEntry const* nameData = sCharacterCache->GetCharacterCacheByGuid(guid);
|
|
|
|
WorldPacket data(SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10));
|
|
data << guid.WriteAsPacked();
|
|
if (!nameData)
|
|
{
|
|
data << uint8(1); // name unknown
|
|
SendPacket(&data);
|
|
return;
|
|
}
|
|
|
|
data << uint8(0); // name known
|
|
data << nameData->Name; // played name
|
|
data << uint8(0); // realm name - only set for cross realm interaction (such as Battlegrounds)
|
|
data << uint8(nameData->Race);
|
|
data << uint8(nameData->Sex);
|
|
data << uint8(nameData->Class);
|
|
|
|
if (DeclinedName const* names = (player ? player->GetDeclinedNames() : NULL))
|
|
{
|
|
data << uint8(1); // Name is declined
|
|
for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
|
|
data << names->name[i];
|
|
}
|
|
else
|
|
data << uint8(0); // Name is not declined
|
|
|
|
SendPacket(&data);
|
|
}
|
|
|
|
void WorldSession::HandleNameQueryOpcode(WorldPacket& recvData)
|
|
{
|
|
ObjectGuid guid;
|
|
recvData >> guid;
|
|
|
|
// This is disable by default to prevent lots of console spam
|
|
// TC_LOG_INFO("network", "HandleNameQueryOpcode %u", guid);
|
|
|
|
SendNameQueryOpcode(guid);
|
|
}
|
|
|
|
void WorldSession::HandleQueryTimeOpcode(WorldPacket & /*recvData*/)
|
|
{
|
|
SendQueryTimeResponse();
|
|
}
|
|
|
|
void WorldSession::SendQueryTimeResponse()
|
|
{
|
|
WorldPacket data(SMSG_QUERY_TIME_RESPONSE, 4+4);
|
|
data << uint32(time(NULL));
|
|
data << uint32(sWorld->GetNextDailyQuestsResetTime() - time(NULL));
|
|
SendPacket(&data);
|
|
}
|
|
|
|
/// Only _static_ data is sent in this packet !!!
|
|
void WorldSession::HandleCreatureQueryOpcode(WorldPackets::Query::QueryCreature& query)
|
|
{
|
|
if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(query.CreatureID))
|
|
{
|
|
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), query.CreatureID);
|
|
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
|
SendPacket(&ci->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
|
|
else
|
|
{
|
|
WorldPacket response = ci->BuildQueryData(GetSessionDbLocaleIndex());
|
|
SendPacket(&response);
|
|
}
|
|
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
|
}
|
|
else
|
|
{
|
|
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (%s, ENTRY: %u)",
|
|
query.Guid.ToString().c_str(), query.CreatureID);
|
|
|
|
WorldPackets::Query::QueryCreatureResponse response;
|
|
response.CreatureID = query.CreatureID;
|
|
SendPacket(response.Write());
|
|
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
|
}
|
|
}
|
|
|
|
/// Only _static_ data is sent in this packet !!!
|
|
void WorldSession::HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& query)
|
|
{
|
|
if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(query.GameObjectID))
|
|
{
|
|
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
|
SendPacket(&info->QueryData[static_cast<uint32>(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 (%s, ENTRY: %u)",
|
|
query.Guid.ToString().c_str(), query.GameObjectID);
|
|
|
|
WorldPackets::Query::QueryGameObjectResponse response;
|
|
response.GameObjectID = query.GameObjectID;
|
|
SendPacket(response.Write());
|
|
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
|
|
{
|
|
if (!_player->HasCorpse())
|
|
{
|
|
WorldPacket data(MSG_CORPSE_QUERY, 1);
|
|
data << uint8(0); // corpse not found
|
|
SendPacket(&data);
|
|
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->entrance_map >= 0)
|
|
{
|
|
// if corpse map have entrance
|
|
if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->entrance_map))
|
|
{
|
|
mapID = corpseMapEntry->entrance_map;
|
|
x = corpseMapEntry->entrance_x;
|
|
y = corpseMapEntry->entrance_y;
|
|
z = entranceMap->GetHeight(GetPlayer()->GetPhaseMask(), x, y, MAX_HEIGHT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4));
|
|
data << uint8(1); // corpse found
|
|
data << int32(mapID);
|
|
data << float(x);
|
|
data << float(y);
|
|
data << float(z);
|
|
data << int32(corpseMapID);
|
|
data << uint32(0); // unknown
|
|
SendPacket(&data);
|
|
}
|
|
|
|
void WorldSession::HandleNpcTextQueryOpcode(WorldPacket& recvData)
|
|
{
|
|
uint32 textID;
|
|
uint64 guid;
|
|
|
|
recvData >> textID;
|
|
TC_LOG_DEBUG("network", "WORLD: CMSG_NPC_TEXT_QUERY TextId: %u", textID);
|
|
|
|
recvData >> guid;
|
|
|
|
GossipText const* gossip = sObjectMgr->GetGossipText(textID);
|
|
|
|
WorldPacket data(SMSG_NPC_TEXT_UPDATE, 100); // guess size
|
|
data << textID;
|
|
|
|
if (!gossip)
|
|
{
|
|
for (uint8 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i)
|
|
{
|
|
data << float(0);
|
|
data << "Greetings $N";
|
|
data << "Greetings $N";
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
data << uint32(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::string text0[MAX_GOSSIP_TEXT_OPTIONS], text1[MAX_GOSSIP_TEXT_OPTIONS];
|
|
LocaleConstant locale = GetSessionDbLocaleIndex();
|
|
|
|
for (uint8 i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; ++i)
|
|
{
|
|
BroadcastText const* bct = sObjectMgr->GetBroadcastText(gossip->Options[i].BroadcastTextID);
|
|
if (bct)
|
|
{
|
|
text0[i] = bct->GetText(locale, GENDER_MALE, true);
|
|
text1[i] = bct->GetText(locale, GENDER_FEMALE, true);
|
|
}
|
|
else
|
|
{
|
|
text0[i] = gossip->Options[i].Text_0;
|
|
text1[i] = gossip->Options[i].Text_1;
|
|
}
|
|
|
|
if (locale != DEFAULT_LOCALE && !bct)
|
|
{
|
|
if (NpcTextLocale const* npcTextLocale = sObjectMgr->GetNpcTextLocale(textID))
|
|
{
|
|
ObjectMgr::GetLocaleString(npcTextLocale->Text_0[i], locale, text0[i]);
|
|
ObjectMgr::GetLocaleString(npcTextLocale->Text_1[i], locale, text1[i]);
|
|
}
|
|
}
|
|
|
|
data << gossip->Options[i].Probability;
|
|
|
|
if (text0[i].empty())
|
|
data << text1[i];
|
|
else
|
|
data << text0[i];
|
|
|
|
if (text1[i].empty())
|
|
data << text0[i];
|
|
else
|
|
data << text1[i];
|
|
|
|
data << gossip->Options[i].Language;
|
|
|
|
for (uint8 j = 0; j < MAX_GOSSIP_TEXT_EMOTES; ++j)
|
|
{
|
|
data << gossip->Options[i].Emotes[j]._Delay;
|
|
data << gossip->Options[i].Emotes[j]._Emote;
|
|
}
|
|
}
|
|
}
|
|
|
|
SendPacket(&data);
|
|
}
|
|
|
|
/// Only _static_ data is sent in this packet !!!
|
|
void WorldSession::HandlePageTextQueryOpcode(WorldPacket& recvData)
|
|
{
|
|
TC_LOG_DEBUG("network", "WORLD: Received CMSG_PAGE_TEXT_QUERY");
|
|
|
|
uint32 pageID;
|
|
recvData >> pageID;
|
|
recvData.read_skip<uint64>(); // guid
|
|
|
|
while (pageID)
|
|
{
|
|
PageText const* pageText = sObjectMgr->GetPageText(pageID);
|
|
// guess size
|
|
WorldPacket data(SMSG_PAGE_TEXT_QUERY_RESPONSE, 50);
|
|
data << pageID;
|
|
|
|
if (!pageText)
|
|
{
|
|
data << "Item page missing.";
|
|
data << uint32(0);
|
|
pageID = 0;
|
|
}
|
|
else
|
|
{
|
|
std::string Text = pageText->Text;
|
|
|
|
int loc_idx = GetSessionDbLocaleIndex();
|
|
if (loc_idx >= 0)
|
|
if (PageTextLocale const* player = sObjectMgr->GetPageTextLocale(pageID))
|
|
ObjectMgr::GetLocaleString(player->Text, loc_idx, Text);
|
|
|
|
data << Text;
|
|
data << uint32(pageText->NextPage);
|
|
pageID = pageText->NextPage;
|
|
}
|
|
SendPacket(&data);
|
|
|
|
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_PAGE_TEXT_QUERY_RESPONSE");
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleCorpseMapPositionQuery(WorldPacket& recvData)
|
|
{
|
|
TC_LOG_DEBUG("network", "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY");
|
|
|
|
uint32 unk;
|
|
recvData >> unk;
|
|
|
|
WorldPacket data(SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4);
|
|
data << float(0);
|
|
data << float(0);
|
|
data << float(0);
|
|
data << float(0);
|
|
SendPacket(&data);
|
|
}
|
|
|
|
void WorldSession::HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& query)
|
|
{
|
|
if (query.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<uint32> questIds;
|
|
for (uint32 i = 0; i < query.MissingQuestCount; ++i)
|
|
questIds.insert(query.MissingQuestPOIs[i]); // quest id
|
|
|
|
WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4 + 40) * questIds.size());
|
|
data << uint32(questIds.size()); // count
|
|
|
|
for (uint32 questId : questIds)
|
|
{
|
|
uint16 const questSlot = _player->FindQuestSlot(questId);
|
|
if (questSlot != MAX_QUEST_LOG_SIZE && _player->GetQuestSlotQuestId(questSlot) == questId)
|
|
{
|
|
if (QuestPOIWrapper const* poiWrapper = sObjectMgr->GetQuestPOIWrapper(questId))
|
|
{
|
|
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
|
data.append(poiWrapper->QueryDataBuffer);
|
|
else
|
|
{
|
|
ByteBuffer POIByteBuffer = poiWrapper->BuildQueryData();
|
|
data.append(POIByteBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data << uint32(questId); // quest ID
|
|
data << uint32(0); // POI count
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data << uint32(questId); // quest ID
|
|
data << uint32(0); // POI count
|
|
}
|
|
}
|
|
|
|
SendPacket(&data);
|
|
}
|