aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp56
-rw-r--r--src/server/game/Entities/Creature/Creature.h5
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp152
-rw-r--r--src/server/game/Entities/Creature/GossipDef.h2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp50
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h5
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.cpp139
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h5
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp70
-rw-r--r--src/server/game/Globals/ObjectMgr.h29
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp145
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp122
-rw-r--r--src/server/game/Quests/QuestDef.cpp154
-rw-r--r--src/server/game/Quests/QuestDef.h6
-rw-r--r--src/server/game/World/World.cpp6
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp3
-rw-r--r--src/server/worldserver/worldserver.conf.dist11
18 files changed, 573 insertions, 388 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 0fec09ac8f2..93345dee29e 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -146,6 +146,62 @@ uint32 CreatureTemplate::GetFirstVisibleModel() const
return 17519;
}
+void CreatureTemplate::InitializeQueryData()
+{
+ WorldPacket queryTemp;
+ for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
+ {
+ queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
+ QueryData[loc] = queryTemp;
+ }
+}
+
+WorldPacket CreatureTemplate::BuildQueryData(LocaleConstant loc) const
+{
+ WorldPacket queryTemp(SMSG_CREATURE_QUERY_RESPONSE, 200);
+
+ std::string locName = Name, locTitle = Title;
+ if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(Entry))
+ {
+ ObjectMgr::GetLocaleString(cl->Name, loc, locName);
+ ObjectMgr::GetLocaleString(cl->Title, loc, locTitle);
+ }
+
+ queryTemp << uint32(Entry); // creature entry
+ queryTemp << locName;
+ queryTemp << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
+ queryTemp << locTitle;
+ queryTemp << IconName; // "Directions" for guard, string for Icons 2.3.0
+ queryTemp << uint32(type_flags); // flags
+ queryTemp << uint32(type); // CreatureType.dbc
+ queryTemp << uint32(family); // CreatureFamily.dbc
+ queryTemp << uint32(rank); // Creature Rank (elite, boss, etc)
+ queryTemp << uint32(KillCredit[0]); // new in 3.1, kill credit
+ queryTemp << uint32(KillCredit[1]); // new in 3.1, kill credit
+ queryTemp << uint32(Modelid1); // Modelid1
+ queryTemp << uint32(Modelid2); // Modelid2
+ queryTemp << uint32(Modelid3); // Modelid3
+ queryTemp << uint32(Modelid4); // Modelid4
+ queryTemp << float(ModHealth); // dmg/hp modifier
+ queryTemp << float(ModMana); // dmg/mana modifier
+ queryTemp << uint8(RacialLeader);
+
+ CreatureQuestItemList const* items = sObjectMgr->GetCreatureQuestItemList(Entry);
+ if (items)
+ {
+ for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
+ queryTemp << (i < items->size() ? uint32((*items)[i]) : uint32(0));
+ }
+ else
+ {
+ for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
+ queryTemp << uint32(0);
+ }
+
+ queryTemp << uint32(movementId); // CreatureMovementInfo.dbc
+ return queryTemp;
+}
+
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
if (Unit* victim = ObjectAccessor::GetUnit(m_owner, m_victim))
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 50e70cdcd0e..aa9b2466e62 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -26,6 +26,7 @@
#include "LootMgr.h"
#include "DatabaseEnv.h"
#include "Cell.h"
+#include "WorldPacket.h"
#include <list>
@@ -140,6 +141,7 @@ struct TC_GAME_API CreatureTemplate
uint32 MechanicImmuneMask;
uint32 flags_extra;
uint32 ScriptID;
+ WorldPacket QueryData[TOTAL_LOCALES];
uint32 GetRandomValidModelId() const;
uint32 GetFirstValidModelId() const;
uint32 GetFirstInvisibleModel() const;
@@ -171,6 +173,9 @@ struct TC_GAME_API CreatureTemplate
// if can tame exotic then can tame any tameable
return canTameExotic || !IsExotic();
}
+
+ void InitializeQueryData();
+ WorldPacket BuildQueryData(LocaleConstant loc) const;
};
typedef std::vector<uint32> CreatureQuestItemList;
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index df5abb14f71..4ace28fc131 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -234,7 +234,7 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID)
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
if (questLevelInTitle)
- AddQuestLevelToTitle(title, quest->GetQuestLevel());
+ Quest::AddQuestLevelToTitle(title, quest->GetQuestLevel());
data << title; // max 0x200
}
@@ -353,7 +353,7 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
if (questLevelInTitle)
- AddQuestLevelToTitle(title, quest->GetQuestLevel());
+ Quest::AddQuestLevelToTitle(title, quest->GetQuestLevel());
data << uint32(questID);
data << uint32(qmi.QuestIcon);
@@ -399,7 +399,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
}
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+ Quest::AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
data << uint64(npcGUID);
@@ -489,138 +489,14 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
{
- std::string questTitle = quest->GetTitle();
- std::string questDetails = quest->GetDetails();
- std::string questObjectives = quest->GetObjectives();
- std::string questAreaDescription = quest->GetAreaDescription();
- std::string questCompletedText = quest->GetCompletedText();
-
- std::string questObjectiveText[QUEST_OBJECTIVES_COUNT];
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- questObjectiveText[i] = quest->ObjectiveText[i];
-
- int32 locale = _session->GetSessionDbLocaleIndex();
- if (locale >= 0)
- {
- if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
- {
- ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle);
- ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails);
- ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives);
- ObjectMgr::GetLocaleString(localeData->AreaDescription, locale, questAreaDescription);
- ObjectMgr::GetLocaleString(localeData->CompletedText, locale, questCompletedText);
-
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], locale, questObjectiveText[i]);
- }
- }
-
- WorldPacket data(SMSG_QUEST_QUERY_RESPONSE, 100); // guess size
-
- data << uint32(quest->GetQuestId()); // quest id
- data << uint32(quest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details)
- data << uint32(quest->GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client)
- data << uint32(quest->GetMinLevel()); // min level
- data << uint32(quest->GetZoneOrSort()); // zone or sort to display in quest log
-
- data << uint32(quest->GetType()); // quest type
- data << uint32(quest->GetSuggestedPlayers()); // suggested players count
-
- data << uint32(quest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective
- data << uint32(quest->GetRepObjectiveValue()); // shown in quest log as part of quest objective
-
- data << uint32(quest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPPOSITE faction
- data << uint32(quest->GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction
-
- data << uint32(quest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0
- data << uint32(quest->GetXPId()); // used for calculating rewarded experience
-
- if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
- data << uint32(0); // Hide money rewarded
- else
- data << uint32(quest->GetRewOrReqMoney()); // reward money (below max lvl)
-
- data << uint32(quest->GetRewMoneyMaxLevel()); // used in XP calculation at client
- data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0)
- data << int32(quest->GetRewSpellCast()); // cast spell
-
- // rewarded honor points
- data << uint32(quest->GetRewHonorAddition());
- data << float(quest->GetRewHonorMultiplier());
- data << uint32(quest->GetSrcItemId()); // source item id
- data << uint32(quest->GetFlags() & 0xFFFF); // quest flags
- data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
- data << uint32(quest->GetPlayersSlain()); // players slain
- data << uint32(quest->GetBonusTalents()); // bonus talents
- data << uint32(quest->GetRewArenaPoints()); // bonus arena points
- data << uint32(0); // review rep show mask
-
- if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
- {
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
- data << uint32(0) << uint32(0);
- for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- data << uint32(0) << uint32(0);
- }
+ if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ _session->SendPacket(&quest->QueryData[static_cast<uint32>(_session->GetSessionDbLocaleIndex())]);
else
{
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
- {
- data << uint32(quest->RewardItemId[i]);
- data << uint32(quest->RewardItemIdCount[i]);
- }
- for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- {
- data << uint32(quest->RewardChoiceItemId[i]);
- data << uint32(quest->RewardChoiceItemCount[i]);
- }
+ WorldPacket queryPacket = quest->BuildQueryData(_session->GetSessionDbLocaleIndex());
+ _session->SendPacket(&queryPacket);
}
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
- data << uint32(quest->RewardFactionId[i]);
-
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc?
- data << int32(quest->RewardFactionValueId[i]);
-
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0)
- data << int32(quest->RewardFactionValueIdOverride[i]);
-
- data << uint32(quest->GetPOIContinent());
- data << float(quest->GetPOIx());
- data << float(quest->GetPOIy());
- data << uint32(quest->GetPointOpt());
-
- if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
-
- data << questTitle;
- data << questObjectives;
- data << questDetails;
- data << questAreaDescription;
- data << questCompletedText; // display in quest objectives window once all objectives are completed
-
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- {
- if (quest->RequiredNpcOrGo[i] < 0)
- data << uint32((quest->RequiredNpcOrGo[i] * (-1)) | 0x80000000); // client expects gameobject template id in form (id|0x80000000)
- else
- data << uint32(quest->RequiredNpcOrGo[i]);
-
- data << uint32(quest->RequiredNpcOrGoCount[i]);
- data << uint32(quest->ItemDrop[i]);
- data << uint32(0); // req source count?
- }
-
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- {
- data << uint32(quest->RequiredItemId[i]);
- data << uint32(quest->RequiredItemCount[i]);
- }
-
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- data << questObjectiveText[i];
-
- _session->SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", quest->GetQuestId());
}
@@ -640,7 +516,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI
}
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+ Quest::AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size
data << uint64(npcGUID);
@@ -743,7 +619,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
}
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+ Quest::AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size
data << uint64(npcGUID);
@@ -794,13 +670,3 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
_session->SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPC=%s, questid=%u", npcGUID.ToString().c_str(), quest->GetQuestId());
}
-
-void PlayerMenu::AddQuestLevelToTitle(std::string &title, int32 level)
-{
- // Adds the quest level to the front of the quest title
- // example: [13] Westfall Stew
-
- std::stringstream questTitlePretty;
- questTitlePretty << "[" << level << "] " << title;
- title = questTitlePretty.str();
-}
diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h
index b649b4ae873..9826057361d 100644
--- a/src/server/game/Entities/Creature/GossipDef.h
+++ b/src/server/game/Entities/Creature/GossipDef.h
@@ -286,8 +286,6 @@ class TC_GAME_API PlayerMenu
void SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUID, bool enableNext) const;
void SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGUID, bool canComplete, bool closeOnCancel) const;
- static void AddQuestLevelToTitle(std::string &title, int32 level);
-
private:
GossipMenu _gossipMenu;
QuestMenu _questMenu;
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 3ef54a6187c..2fc2d44666b 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -33,6 +33,56 @@
#include "World.h"
#include "Transport.h"
+void GameObjectTemplate::InitializeQueryData()
+{
+ WorldPacket queryTemp;
+ for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
+ {
+ queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
+ QueryData[loc] = queryTemp;
+ }
+}
+
+WorldPacket GameObjectTemplate::BuildQueryData(LocaleConstant loc) const
+{
+ WorldPacket queryTemp(SMSG_GAMEOBJECT_QUERY_RESPONSE, 200);
+
+ std::string locName = name;
+ std::string locIconName = IconName;
+ std::string locCastBarCaption = castBarCaption;
+
+ if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
+ {
+ ObjectMgr::GetLocaleString(gameObjectLocale->Name, loc, locName);
+ ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, loc, locCastBarCaption);
+ }
+
+ queryTemp << uint32(entry);
+ queryTemp << uint32(type);
+ queryTemp << uint32(displayId);
+ queryTemp << locName;
+ queryTemp << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
+ queryTemp << locIconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
+ queryTemp << locCastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
+ queryTemp << unk1; // 2.0.3, string
+ queryTemp.append(raw.data, MAX_GAMEOBJECT_DATA);
+ queryTemp << float(size); // go size
+
+ GameObjectQuestItemList const* items = sObjectMgr->GetGameObjectQuestItemList(entry);
+ if (items)
+ {
+ for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
+ queryTemp << (i < items->size() ? uint32((*items)[i]) : uint32(0));
+ }
+ else
+ {
+ for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
+ queryTemp << uint32(0);
+ }
+
+ return queryTemp;
+}
+
GameObject::GameObject() : WorldObject(false), MapObject(),
m_model(nullptr), m_goValue(), m_AI(nullptr)
{
diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h
index 549b51cbab6..b9160f3cc11 100644
--- a/src/server/game/Entities/GameObject/GameObject.h
+++ b/src/server/game/Entities/GameObject/GameObject.h
@@ -25,6 +25,7 @@
#include "Object.h"
#include "LootMgr.h"
#include "DatabaseEnv.h"
+#include "WorldPacket.h"
#include <G3D/Quat.h>
class GameObjectAI;
@@ -423,6 +424,7 @@ struct GameObjectTemplate
std::string AIName;
uint32 ScriptId;
+ WorldPacket QueryData[TOTAL_LOCALES];
// helpers
bool IsDespawnAtAction() const
@@ -559,6 +561,9 @@ struct GameObjectTemplate
default: return 0;
}
}
+
+ void InitializeQueryData();
+ WorldPacket BuildQueryData(LocaleConstant loc) const;
};
// From `gameobject_template_addon`
diff --git a/src/server/game/Entities/Item/ItemTemplate.cpp b/src/server/game/Entities/Item/ItemTemplate.cpp
index 90c488992f2..e55d0d73132 100644
--- a/src/server/game/Entities/Item/ItemTemplate.cpp
+++ b/src/server/game/Entities/Item/ItemTemplate.cpp
@@ -16,6 +16,10 @@
*/
#include "ItemTemplate.h"
+#include "ObjectMgr.h"
+#include "Opcodes.h"
+#include "SpellMgr.h"
+#include "SpellInfo.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
@@ -143,3 +147,138 @@ void ItemTemplate::_LoadTotalAP()
_totalAP = totalAP;
}
+
+void ItemTemplate::InitializeQueryData()
+{
+ WorldPacket queryTemp;
+ for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
+ {
+ queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
+ QueryData[loc] = queryTemp;
+ }
+}
+
+WorldPacket ItemTemplate::BuildQueryData(LocaleConstant loc) const
+{
+ WorldPacket queryTemp(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 500);
+
+ std::string locName = Name1;
+ std::string locDescription = Description;
+
+ if (ItemLocale const* il = sObjectMgr->GetItemLocale(ItemId))
+ {
+ ObjectMgr::GetLocaleString(il->Name, loc, locName);
+ ObjectMgr::GetLocaleString(il->Description, loc, locDescription);
+ }
+
+ queryTemp << ItemId;
+ queryTemp << Class;
+ queryTemp << SubClass;
+ queryTemp << SoundOverrideSubclass;
+ queryTemp << locName;
+ queryTemp << uint8(0x00); //Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
+ queryTemp << uint8(0x00); //Name3; // blizz not send name there, just uint8(0x00);
+ queryTemp << uint8(0x00); //Name4; // blizz not send name there, just uint8(0x00);
+ queryTemp << DisplayInfoID;
+ queryTemp << Quality;
+ queryTemp << Flags;
+ queryTemp << Flags2;
+ queryTemp << BuyPrice;
+ queryTemp << SellPrice;
+ queryTemp << InventoryType;
+ queryTemp << AllowableClass;
+ queryTemp << AllowableRace;
+ queryTemp << ItemLevel;
+ queryTemp << RequiredLevel;
+ queryTemp << RequiredSkill;
+ queryTemp << RequiredSkillRank;
+ queryTemp << RequiredSpell;
+ queryTemp << RequiredHonorRank;
+ queryTemp << RequiredCityRank;
+ queryTemp << RequiredReputationFaction;
+ queryTemp << RequiredReputationRank;
+ queryTemp << int32(MaxCount);
+ queryTemp << int32(Stackable);
+ queryTemp << ContainerSlots;
+ queryTemp << StatsCount; // item stats count
+ for (uint32 i = 0; i < StatsCount; ++i)
+ {
+ queryTemp << ItemStat[i].ItemStatType;
+ queryTemp << ItemStat[i].ItemStatValue;
+ }
+ queryTemp << ScalingStatDistribution; // scaling stats distribution
+ queryTemp << ScalingStatValue; // some kind of flags used to determine stat values column
+ for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
+ {
+ queryTemp << Damage[i].DamageMin;
+ queryTemp << Damage[i].DamageMax;
+ queryTemp << Damage[i].DamageType;
+ }
+
+ // resistances (7)
+ queryTemp << Armor;
+ queryTemp << HolyRes;
+ queryTemp << FireRes;
+ queryTemp << NatureRes;
+ queryTemp << FrostRes;
+ queryTemp << ShadowRes;
+ queryTemp << ArcaneRes;
+
+ queryTemp << Delay;
+ queryTemp << AmmoType;
+ queryTemp << RangedModRange;
+
+ for (uint8 s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
+ {
+ // spells are validated on template loading
+ if (Spells[s].SpellId > 0)
+ {
+ queryTemp << Spells[s].SpellId;
+ queryTemp << Spells[s].SpellTrigger;
+ queryTemp << uint32(-abs(Spells[s].SpellCharges));
+ queryTemp << uint32(Spells[s].SpellCooldown);
+ queryTemp << uint32(Spells[s].SpellCategory);
+ queryTemp << uint32(Spells[s].SpellCategoryCooldown);
+ }
+ else
+ {
+ queryTemp << uint32(0);
+ queryTemp << uint32(0);
+ queryTemp << uint32(0);
+ queryTemp << uint32(-1);
+ queryTemp << uint32(0);
+ queryTemp << uint32(-1);
+ }
+ }
+ queryTemp << Bonding;
+ queryTemp << locDescription;
+ queryTemp << PageText;
+ queryTemp << LanguageID;
+ queryTemp << PageMaterial;
+ queryTemp << StartQuest;
+ queryTemp << LockID;
+ queryTemp << int32(Material);
+ queryTemp << Sheath;
+ queryTemp << RandomProperty;
+ queryTemp << RandomSuffix;
+ queryTemp << Block;
+ queryTemp << ItemSet;
+ queryTemp << MaxDurability;
+ queryTemp << Area;
+ queryTemp << Map; // Added in 1.12.x & 2.0.1 client branch
+ queryTemp << BagFamily;
+ queryTemp << TotemCategory;
+ for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
+ {
+ queryTemp << Socket[s].Color;
+ queryTemp << Socket[s].Content;
+ }
+ queryTemp << socketBonus;
+ queryTemp << GemProperties;
+ queryTemp << RequiredDisenchantSkill;
+ queryTemp << ArmorDamageModifier;
+ queryTemp << Duration; // added in 2.4.2.8209, duration (seconds)
+ queryTemp << ItemLimitCategory; // WotLK, ItemLimitCategory
+ queryTemp << HolidayId; // Holiday.dbc?
+ return queryTemp;
+}
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index 79b2147b1be..5ea34aedb01 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -21,6 +21,7 @@
#include "Common.h"
#include "SharedDefines.h"
+#include "WorldPacket.h"
class ObjectMgr;
@@ -685,6 +686,7 @@ struct ItemTemplate
uint32 MinMoneyLoot;
uint32 MaxMoneyLoot;
uint32 FlagsCu;
+ WorldPacket QueryData[TOTAL_LOCALES];
// helpers
bool CanChangeEquipStateInCombat() const;
@@ -710,6 +712,9 @@ struct ItemTemplate
bool IsArmorVellum() const { return Class == ITEM_CLASS_TRADE_GOODS && SubClass == ITEM_SUBCLASS_ARMOR_ENCHANTMENT; }
bool IsConjuredConsumable() const { return Class == ITEM_CLASS_CONSUMABLE && (Flags & ITEM_FLAG_CONJURED); }
+ void InitializeQueryData();
+ WorldPacket BuildQueryData(LocaleConstant loc) const;
+
private:
// Cached info
int32 _totalAP;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 62df5d7e63d..1c2ae545ef3 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -7387,7 +7387,11 @@ void ObjectMgr::LoadQuestPOI()
if (questId < POIs.size() && id < POIs[questId].size())
{
POI.points = POIs[questId][id];
- _questPOIStore[questId].push_back(POI);
+ QuestPOIContainer::iterator itr = _questPOIStore.find(questId);
+ if (itr == _questPOIStore.end())
+ _questPOIStore[questId] = QuestPOIWrapper();
+
+ _questPOIStore[questId].DataVector.push_back(POI);
}
else
TC_LOG_ERROR("server.loading", "Table quest_poi references unknown quest points for quest %u POI id %u", questId, id);
@@ -9325,3 +9329,67 @@ void ObjectMgr::LoadCreatureQuestItems()
TC_LOG_INFO("server.loading", ">> Loaded %u creature quest items in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
+
+void ObjectMgr::InitializeQueriesData(QueryDataGroup mask)
+{
+ // cache disabled
+ if (!sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ return;
+
+ // Initialize Query data for creatures
+ if (mask & QUERY_DATA_CREATURES)
+ for (auto& creaturePair : _creatureTemplateStore)
+ creaturePair.second.InitializeQueryData();
+
+ // Initialize Query Data for gameobjects
+ if (mask & QUERY_DATA_GAMEOBJECTS)
+ for (auto& gameobjectPair : _gameObjectTemplateStore)
+ gameobjectPair.second.InitializeQueryData();
+
+ // Initialize Query Data for items
+ if (mask & QUERY_DATA_ITEMS)
+ for (auto& itemPair : _itemTemplateStore)
+ itemPair.second.InitializeQueryData();
+
+ // Initialize Query Data for quests
+ if (mask & QUERY_DATA_QUESTS)
+ for (auto& questPair : _questTemplates)
+ questPair.second->InitializeQueryData();
+
+ // Initialize Quest POI data
+ if (mask & QUERY_DATA_POIS)
+ for (auto& poiPair : _questPOIStore)
+ poiPair.second.InitializeQueryData(poiPair.first);
+}
+
+void QuestPOIWrapper::InitializeQueryData(uint32 questId)
+{
+ QueryDataBuffer = BuildQueryData(questId);
+}
+
+ByteBuffer QuestPOIWrapper::BuildQueryData(uint32 questId) const
+{
+ ByteBuffer tempBuffer;
+ tempBuffer << uint32(questId); // quest ID
+ tempBuffer << uint32(DataVector.size()); // POI count
+
+ for (QuestPOIVector::const_iterator itr = DataVector.begin(); itr != DataVector.end(); ++itr)
+ {
+ tempBuffer << uint32(itr->Id); // POI index
+ tempBuffer << int32(itr->ObjectiveIndex); // objective index
+ tempBuffer << uint32(itr->MapId); // mapid
+ tempBuffer << uint32(itr->AreaId); // areaid
+ tempBuffer << uint32(itr->FloorId); // floorid
+ tempBuffer << uint32(itr->Unk3); // unknown
+ tempBuffer << uint32(itr->Unk4); // unknown
+ tempBuffer << uint32(itr->points.size()); // POI points count
+
+ for (std::vector<QuestPOIPoint>::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2)
+ {
+ tempBuffer << int32(itr2->x); // POI point x
+ tempBuffer << int32(itr2->y); // POI point y
+ }
+ }
+
+ return tempBuffer;
+}
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 97b2c6cc3e4..8b61cd221ed 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -615,7 +615,19 @@ struct QuestPOI
};
typedef std::vector<QuestPOI> QuestPOIVector;
-typedef std::unordered_map<uint32, QuestPOIVector> QuestPOIContainer;
+
+struct QuestPOIWrapper
+{
+ QuestPOIVector DataVector;
+ ByteBuffer QueryDataBuffer;
+
+ void InitializeQueryData(uint32 questId);
+ ByteBuffer BuildQueryData(uint32 questId) const;
+
+ QuestPOIWrapper() : QueryDataBuffer(0) { }
+};
+
+typedef std::unordered_map<uint32, QuestPOIWrapper> QuestPOIContainer;
struct GraveYardData
{
@@ -678,6 +690,17 @@ struct DungeonEncounter
typedef std::list<DungeonEncounter const*> DungeonEncounterList;
typedef std::unordered_map<uint32, DungeonEncounterList> DungeonEncounterContainer;
+enum QueryDataGroup
+{
+ QUERY_DATA_CREATURES = 0x01,
+ QUERY_DATA_GAMEOBJECTS = 0x02,
+ QUERY_DATA_ITEMS = 0x04,
+ QUERY_DATA_QUESTS = 0x08,
+ QUERY_DATA_POIS = 0x10,
+
+ QUERY_DATA_ALL = 0xFF
+};
+
class PlayerDumpReader;
class TC_GAME_API ObjectMgr
@@ -877,7 +900,7 @@ class TC_GAME_API ObjectMgr
return nullptr;
}
- QuestPOIVector const* GetQuestPOIVector(uint32 questId)
+ QuestPOIWrapper const* GetQuestPOIWrapper(uint32 questId)
{
QuestPOIContainer::const_iterator itr = _questPOIStore.find(questId);
if (itr != _questPOIStore.end())
@@ -1033,6 +1056,8 @@ class TC_GAME_API ObjectMgr
void LoadTrainerSpell();
void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel);
+ void InitializeQueriesData(QueryDataGroup mask);
+
std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint8 level);
uint32 GetXPForLevel(uint8 level) const;
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 640775bff4c..7dca74d59d0 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -313,147 +313,16 @@ void WorldSession::HandleItemQuerySingleOpcode(WorldPacket& recvData)
TC_LOG_INFO("network", "STORAGE: Item Query = %u", item);
- ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
- if (pProto)
+ ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item);
+ if (itemTemplate)
{
- std::string Name = pProto->Name1;
- std::string Description = pProto->Description;
-
- int loc_idx = GetSessionDbLocaleIndex();
- if (loc_idx >= 0)
- {
- if (ItemLocale const* il = sObjectMgr->GetItemLocale(pProto->ItemId))
- {
- ObjectMgr::GetLocaleString(il->Name, loc_idx, Name);
- ObjectMgr::GetLocaleString(il->Description, loc_idx, Description);
- }
- }
- // guess size
- WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
- data << pProto->ItemId;
- data << pProto->Class;
- data << pProto->SubClass;
- data << pProto->SoundOverrideSubclass;
- data << Name;
- data << uint8(0x00); //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
- data << uint8(0x00); //pProto->Name3; // blizz not send name there, just uint8(0x00);
- data << uint8(0x00); //pProto->Name4; // blizz not send name there, just uint8(0x00);
- data << pProto->DisplayInfoID;
- data << pProto->Quality;
- data << pProto->Flags;
- data << pProto->Flags2;
- data << pProto->BuyPrice;
- data << pProto->SellPrice;
- data << pProto->InventoryType;
- data << pProto->AllowableClass;
- data << pProto->AllowableRace;
- data << pProto->ItemLevel;
- data << pProto->RequiredLevel;
- data << pProto->RequiredSkill;
- data << pProto->RequiredSkillRank;
- data << pProto->RequiredSpell;
- data << pProto->RequiredHonorRank;
- data << pProto->RequiredCityRank;
- data << pProto->RequiredReputationFaction;
- data << pProto->RequiredReputationRank;
- data << int32(pProto->MaxCount);
- data << int32(pProto->Stackable);
- data << pProto->ContainerSlots;
- data << pProto->StatsCount; // item stats count
- for (uint32 i = 0; i < pProto->StatsCount; ++i)
- {
- data << pProto->ItemStat[i].ItemStatType;
- data << pProto->ItemStat[i].ItemStatValue;
- }
- data << pProto->ScalingStatDistribution; // scaling stats distribution
- data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
- for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
- {
- data << pProto->Damage[i].DamageMin;
- data << pProto->Damage[i].DamageMax;
- data << pProto->Damage[i].DamageType;
- }
-
- // resistances (7)
- data << pProto->Armor;
- data << pProto->HolyRes;
- data << pProto->FireRes;
- data << pProto->NatureRes;
- data << pProto->FrostRes;
- data << pProto->ShadowRes;
- data << pProto->ArcaneRes;
-
- data << pProto->Delay;
- data << pProto->AmmoType;
- data << pProto->RangedModRange;
-
- for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
- {
- // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
- // use `item_template` or if not set then only use spell cooldowns
- SpellInfo const* spell = sSpellMgr->GetSpellInfo(pProto->Spells[s].SpellId);
- if (spell)
- {
- bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0;
-
- data << pProto->Spells[s].SpellId;
- data << pProto->Spells[s].SpellTrigger;
- data << uint32(-abs(pProto->Spells[s].SpellCharges));
-
- if (db_data)
- {
- data << uint32(pProto->Spells[s].SpellCooldown);
- data << uint32(pProto->Spells[s].SpellCategory);
- data << uint32(pProto->Spells[s].SpellCategoryCooldown);
- }
- else
- {
- data << uint32(spell->RecoveryTime);
- data << uint32(spell->GetCategory());
- data << uint32(spell->CategoryRecoveryTime);
- }
- }
- else
- {
- data << uint32(0);
- data << uint32(0);
- data << uint32(0);
- data << uint32(-1);
- data << uint32(0);
- data << uint32(-1);
- }
- }
- data << pProto->Bonding;
- data << Description;
- data << pProto->PageText;
- data << pProto->LanguageID;
- data << pProto->PageMaterial;
- data << pProto->StartQuest;
- data << pProto->LockID;
- data << int32(pProto->Material);
- data << pProto->Sheath;
- data << pProto->RandomProperty;
- data << pProto->RandomSuffix;
- data << pProto->Block;
- data << pProto->ItemSet;
- data << pProto->MaxDurability;
- data << pProto->Area;
- data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
- data << pProto->BagFamily;
- data << pProto->TotemCategory;
- for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
+ if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ SendPacket(&itemTemplate->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
+ else
{
- data << pProto->Socket[s].Color;
- data << pProto->Socket[s].Content;
+ WorldPacket queryPacket = itemTemplate->BuildQueryData(GetSessionDbLocaleIndex());
+ SendPacket(&queryPacket);
}
- data << pProto->socketBonus;
- data << pProto->GemProperties;
- data << pProto->RequiredDisenchantSkill;
- data << pProto->ArmorDamageModifier;
- data << pProto->Duration; // added in 2.4.2.8209, duration (seconds)
- data << pProto->ItemLimitCategory; // WotLK, ItemLimitCategory
- data << pProto->HolidayId; // Holiday.dbc?
- SendPacket(&data);
}
else
{
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 3feed3daca7..707c733cc00 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -97,51 +97,14 @@ void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recvData)
CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(entry);
if (ci)
{
- std::string Name, Title;
- Name = ci->Name;
- Title = ci->Title;
-
- int loc_idx = GetSessionDbLocaleIndex();
- if (loc_idx >= 0)
- {
- if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(entry))
- {
- ObjectMgr::GetLocaleString(cl->Name, loc_idx, Name);
- ObjectMgr::GetLocaleString(cl->Title, loc_idx, Title);
- }
- }
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), entry);
- // guess size
- WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100);
- data << uint32(entry); // creature entry
- data << Name;
- data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
- data << Title;
- data << ci->IconName; // "Directions" for guard, string for Icons 2.3.0
- data << uint32(ci->type_flags); // flags
- data << uint32(ci->type); // CreatureType.dbc
- data << uint32(ci->family); // CreatureFamily.dbc
- data << uint32(ci->rank); // Creature Rank (elite, boss, etc)
- data << uint32(ci->KillCredit[0]); // new in 3.1, kill credit
- data << uint32(ci->KillCredit[1]); // new in 3.1, kill credit
- data << uint32(ci->Modelid1); // Modelid1
- data << uint32(ci->Modelid2); // Modelid2
- data << uint32(ci->Modelid3); // Modelid3
- data << uint32(ci->Modelid4); // Modelid4
- data << float(ci->ModHealth); // dmg/hp modifier
- data << float(ci->ModMana); // dmg/mana modifier
- data << uint8(ci->RacialLeader);
-
- CreatureQuestItemList const* items = sObjectMgr->GetCreatureQuestItemList(entry);
- if (items)
- for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
- data << (i < items->size() ? uint32((*items)[i]) : uint32(0));
+ if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ SendPacket(&ci->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
else
- for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
- data << uint32(0);
-
- data << uint32(ci->movementId); // CreatureMovementInfo.dbc
- SendPacket(&data);
+ {
+ WorldPacket queryPacket = ci->BuildQueryData(GetSessionDbLocaleIndex());
+ SendPacket(&queryPacket);
+ }
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
}
else
@@ -166,44 +129,13 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData)
const GameObjectTemplate* info = sObjectMgr->GetGameObjectTemplate(entry);
if (info)
{
- std::string Name;
- std::string IconName;
- std::string CastBarCaption;
-
- Name = info->name;
- IconName = info->IconName;
- CastBarCaption = info->castBarCaption;
-
- LocaleConstant localeConstant = GetSessionDbLocaleIndex();
- if (localeConstant >= LOCALE_enUS)
- if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
- {
- ObjectMgr::GetLocaleString(gameObjectLocale->Name, localeConstant, Name);
- ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, localeConstant, CastBarCaption);
- }
-
- TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry);
- WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150);
- data << uint32(entry);
- data << uint32(info->type);
- data << uint32(info->displayId);
- data << Name;
- data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
- data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
- data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
- data << info->unk1; // 2.0.3, string
- data.append(info->raw.data, MAX_GAMEOBJECT_DATA);
- data << float(info->size); // go size
-
- GameObjectQuestItemList const* items = sObjectMgr->GetGameObjectQuestItemList(entry);
- if (items)
- for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
- data << (i < items->size() ? uint32((*items)[i]) : uint32(0));
+ if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ SendPacket(&info->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
else
- for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
- data << uint32(0);
-
- SendPacket(&data);
+ {
+ WorldPacket queryPacket = info->BuildQueryData(GetSessionDbLocaleIndex());
+ SendPacket(&queryPacket);
+ }
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
}
else
@@ -421,7 +353,7 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recvData)
for (uint32 i = 0; i < count; ++i)
questIds.insert(recvData.read<uint32>()); // quest id
- WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4)*questIds.size());
+ WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4 + 40)*questIds.size());
data << uint32(questIds.size()); // count
for (auto itr = questIds.begin(); itr != questIds.end(); ++itr)
@@ -437,29 +369,15 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recvData)
if (questOk)
{
- QuestPOIVector const* POI = sObjectMgr->GetQuestPOIVector(questId);
-
- if (POI)
+ if (QuestPOIWrapper const* poiWrapper = sObjectMgr->GetQuestPOIWrapper(questId))
{
- data << uint32(questId); // quest ID
- data << uint32(POI->size()); // POI count
-
- for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr)
+
+ if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
+ data.append(poiWrapper->QueryDataBuffer);
+ else
{
- data << uint32(itr->Id); // POI index
- data << int32(itr->ObjectiveIndex); // objective index
- data << uint32(itr->MapId); // mapid
- data << uint32(itr->AreaId); // areaid
- data << uint32(itr->FloorId); // floorid
- data << uint32(itr->Unk3); // unknown
- data << uint32(itr->Unk4); // unknown
- data << uint32(itr->points.size()); // POI points count
-
- for (std::vector<QuestPOIPoint>::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2)
- {
- data << int32(itr2->x); // POI point x
- data << int32(itr2->y); // POI point y
- }
+ ByteBuffer POIByteBuffer = poiWrapper->BuildQueryData(questId);
+ data.append(POIByteBuffer);
}
}
else
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index f38d3c37b12..5445e3be998 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -19,6 +19,8 @@
#include "QuestDef.h"
#include "Player.h"
#include "World.h"
+#include "ObjectMgr.h"
+#include "Opcodes.h"
Quest::Quest(Field* questRecord)
{
@@ -320,3 +322,155 @@ bool Quest::CanIncreaseRewardedQuestCounters() const
// This affects counters and client requests for completed quests.
return (!IsDFQuest() && !IsDaily() && (!IsRepeatable() || IsWeekly() || IsMonthly() || IsSeasonal()));
}
+
+void Quest::InitializeQueryData()
+{
+ WorldPacket queryTemp;
+ for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
+ {
+ queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
+ QueryData[loc] = queryTemp;
+ }
+}
+
+WorldPacket Quest::BuildQueryData(LocaleConstant loc) const
+{
+ WorldPacket queryTemp(SMSG_QUEST_QUERY_RESPONSE, 2000);
+
+ std::string locQuestTitle = GetTitle();
+ std::string locQuestDetails = GetDetails();
+ std::string locQuestObjectives = GetObjectives();
+ std::string locQuestAreaDescription = GetAreaDescription();
+ std::string locQuestCompletedText = GetCompletedText();
+
+ std::string locQuestObjectiveText[QUEST_OBJECTIVES_COUNT];
+ for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
+ locQuestObjectiveText[i] = ObjectiveText[i];
+
+ if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(GetQuestId()))
+ {
+ ObjectMgr::GetLocaleString(localeData->Title, loc, locQuestTitle);
+ ObjectMgr::GetLocaleString(localeData->Details, loc, locQuestDetails);
+ ObjectMgr::GetLocaleString(localeData->Objectives, loc, locQuestObjectives);
+ ObjectMgr::GetLocaleString(localeData->AreaDescription, loc, locQuestAreaDescription);
+ ObjectMgr::GetLocaleString(localeData->CompletedText, loc, locQuestCompletedText);
+
+ for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
+ ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], loc, locQuestObjectiveText[i]);
+ }
+
+ queryTemp << uint32(GetQuestId()); // quest id
+ queryTemp << uint32(GetQuestMethod()); // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details)
+ queryTemp << uint32(GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client)
+ queryTemp << uint32(GetMinLevel()); // min level
+ queryTemp << uint32(GetZoneOrSort()); // zone or sort to display in quest log
+
+ queryTemp << uint32(GetType()); // quest type
+ queryTemp << uint32(GetSuggestedPlayers()); // suggested players count
+
+ queryTemp << uint32(GetRepObjectiveFaction()); // shown in quest log as part of quest objective
+ queryTemp << uint32(GetRepObjectiveValue()); // shown in quest log as part of quest objective
+
+ queryTemp << uint32(GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPPOSITE faction
+ queryTemp << uint32(GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction
+
+ queryTemp << uint32(GetNextQuestInChain()); // client will request this quest from NPC, if not 0
+ queryTemp << uint32(GetXPId()); // used for calculating rewarded experience
+
+ if (HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
+ queryTemp << uint32(0); // Hide money rewarded
+ else
+ queryTemp << uint32(GetRewOrReqMoney()); // reward money (below max lvl)
+
+ queryTemp << uint32(GetRewMoneyMaxLevel()); // used in XP calculation at client
+ queryTemp << uint32(GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0)
+ queryTemp << int32(GetRewSpellCast()); // cast spell
+
+ // rewarded honor points
+ queryTemp << uint32(GetRewHonorAddition());
+ queryTemp << float(GetRewHonorMultiplier());
+ queryTemp << uint32(GetSrcItemId()); // source item id
+ queryTemp << uint32(GetFlags() & 0xFFFF); // quest flags
+ queryTemp << uint32(GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
+ queryTemp << uint32(GetPlayersSlain()); // players slain
+ queryTemp << uint32(GetBonusTalents()); // bonus talents
+ queryTemp << uint32(GetRewArenaPoints()); // bonus arena points
+ queryTemp << uint32(0); // review rep show mask
+
+ if (HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
+ {
+ for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ queryTemp << uint32(0) << uint32(0);
+ for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ queryTemp << uint32(0) << uint32(0);
+ }
+ else
+ {
+ for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ {
+ queryTemp << uint32(RewardItemId[i]);
+ queryTemp << uint32(RewardItemIdCount[i]);
+ }
+ for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ {
+ queryTemp << uint32(RewardChoiceItemId[i]);
+ queryTemp << uint32(RewardChoiceItemCount[i]);
+ }
+ }
+
+ for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
+ queryTemp << uint32(RewardFactionId[i]);
+
+ for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc?
+ queryTemp << int32(RewardFactionValueId[i]);
+
+ for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unk (0)
+ queryTemp << int32(RewardFactionValueIdOverride[i]);
+
+ queryTemp << uint32(GetPOIContinent());
+ queryTemp << float(GetPOIx());
+ queryTemp << float(GetPOIy());
+ queryTemp << uint32(GetPointOpt());
+
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ Quest::AddQuestLevelToTitle(locQuestTitle, GetQuestLevel());
+
+ queryTemp << locQuestTitle;
+ queryTemp << locQuestObjectives;
+ queryTemp << locQuestDetails;
+ queryTemp << locQuestAreaDescription;
+ queryTemp << locQuestCompletedText; // display in quest objectives window once all objectives are completed
+
+ for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
+ {
+ if (RequiredNpcOrGo[i] < 0)
+ queryTemp << uint32((RequiredNpcOrGo[i] * (-1)) | 0x80000000); // client expects gameobject template id in form (id|0x80000000)
+ else
+ queryTemp << uint32(RequiredNpcOrGo[i]);
+
+ queryTemp << uint32(RequiredNpcOrGoCount[i]);
+ queryTemp << uint32(ItemDrop[i]);
+ queryTemp << uint32(0); // req source count?
+ }
+
+ for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
+ {
+ queryTemp << uint32(RequiredItemId[i]);
+ queryTemp << uint32(RequiredItemCount[i]);
+ }
+
+ for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
+ queryTemp << locQuestObjectiveText[i];
+
+ return queryTemp;
+}
+
+void Quest::AddQuestLevelToTitle(std::string &title, int32 level)
+{
+ // Adds the quest level to the front of the quest title
+ // example: [13] Westfall Stew
+
+ std::stringstream questTitlePretty;
+ questTitlePretty << "[" << level << "] " << title;
+ title = questTitlePretty.str();
+}
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 13b959c2100..50f5ae76866 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -23,6 +23,7 @@
#include "DatabaseEnv.h"
#include "SharedDefines.h"
#include "DBCEnums.h"
+#include "WorldPacket.h"
#include <string>
#include <vector>
@@ -307,10 +308,15 @@ class TC_GAME_API Quest
void SetEventIdForQuest(uint16 eventId) { _eventIdForQuest = eventId; }
uint16 GetEventIdForQuest() const { return _eventIdForQuest; }
+ static void AddQuestLevelToTitle(std::string& title, int32 level);
+ void InitializeQueryData();
+ WorldPacket BuildQueryData(LocaleConstant loc) const;
+
typedef std::vector<int32> PrevQuests;
PrevQuests prevQuests;
typedef std::vector<uint32> PrevChainQuests;
PrevChainQuests prevChainQuests;
+ WorldPacket QueryData[TOTAL_LOCALES];
// cached data
private:
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 2f72455ce6e..f3557f07f49 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1355,6 +1355,9 @@ void World::LoadConfigSettings(bool reload)
// Allow 5-man parties to use raid warnings
m_bool_configs[CONFIG_CHAT_PARTY_RAID_WARNINGS] = sConfigMgr->GetBoolDefault("PartyRaidWarnings", false);
+ // Allow to cache data queries
+ m_bool_configs[CONFIG_CACHE_DATA_QUERIES] = sConfigMgr->GetBoolDefault("CacheDataQueries", true);
+
// call ScriptMgr if we're reloading the configuration
if (reload)
sScriptMgr->OnConfigLoad(reload);
@@ -1853,6 +1856,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Calendar data...");
sCalendarMgr->LoadFromDB();
+ TC_LOG_INFO("server.loading", "Initialize query data...");
+ sObjectMgr->InitializeQueriesData(QUERY_DATA_ALL);
+
///- Initialize game time and timers
TC_LOG_INFO("server.loading", "Initialize game time and timers");
m_gameTime = time(NULL);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index c7669f7c222..8a1c3773653 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -177,6 +177,7 @@ enum WorldBoolConfigs
CONFIG_HOTSWAP_INSTALL_ENABLED,
CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED,
CONFIG_PREVENT_RENAME_CUSTOMIZATION,
+ CONFIG_CACHE_DATA_QUERIES,
BOOL_CONFIG_VALUE_COUNT
};
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 14af467ecf5..ee40877e721 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -447,6 +447,7 @@ public:
sObjectMgr->CheckCreatureTemplate(cInfo);
}
+ sObjectMgr->InitializeQueriesData(QUERY_DATA_CREATURES);
handler->SendGlobalGMSysMessage("Creature template reloaded.");
return true;
}
@@ -521,6 +522,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading Quest Templates...");
sObjectMgr->LoadQuests();
+ sObjectMgr->InitializeQueriesData(QUERY_DATA_QUESTS);
handler->SendGlobalGMSysMessage("DB table `quest_template` (quest definitions) reloaded.");
/// dependent also from `gameobject` but this table not reloaded anyway
@@ -700,6 +702,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading Quest POI ..." );
sObjectMgr->LoadQuestPOI();
+ sObjectMgr->InitializeQueriesData(QUERY_DATA_POIS);
handler->SendGlobalGMSysMessage("DB Table `quest_poi` and `quest_poi_points` reloaded.");
return true;
}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index 0e287aa203d..3dca4170a60 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1228,6 +1228,17 @@ Account.PasswordChangeSecurity = 0
BirthdayTime = 1222964635
#
+# CacheDataQueries
+# Description: Server caches data queries at startup.
+# Can be disabled if not enough memory is available.
+# Default: 1 - (Enabled)
+# 0 - (Disabled)
+#
+#
+
+CacheDataQueries = 1
+
+#
###################################################################################################
###################################################################################################