diff options
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 56 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/GossipDef.cpp | 152 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/GossipDef.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 50 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemTemplate.cpp | 139 | ||||
-rw-r--r-- | src/server/game/Entities/Item/ItemTemplate.h | 5 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 70 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 29 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 145 | ||||
-rw-r--r-- | src/server/game/Handlers/QueryHandler.cpp | 122 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 154 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 6 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 6 | ||||
-rw-r--r-- | src/server/game/World/World.h | 1 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_reload.cpp | 3 | ||||
-rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 11 |
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 + +# ################################################################################################### ################################################################################################### |