diff options
-rw-r--r-- | src/server/game/Chat/LanguageMgr.cpp | 111 | ||||
-rw-r--r-- | src/server/game/Chat/LanguageMgr.h | 20 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 20 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 9 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 11 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/ChatHandler.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Texts/ChatTextBuilder.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Texts/ChatTextBuilder.h | 2 | ||||
-rw-r--r-- | src/server/game/Texts/CreatureTextMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 15 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_learn.cpp | 4 |
13 files changed, 73 insertions, 149 deletions
diff --git a/src/server/game/Chat/LanguageMgr.cpp b/src/server/game/Chat/LanguageMgr.cpp index acbd76f0a56..5e81ed35193 100644 --- a/src/server/game/Chat/LanguageMgr.cpp +++ b/src/server/game/Chat/LanguageMgr.cpp @@ -16,12 +16,12 @@ */ #include "LanguageMgr.h" +#include "Containers.h" #include "DB2Stores.h" #include "Log.h" #include "SpellInfo.h" #include "SpellMgr.h" #include "Timer.h" - #include <sstream> LanguageMgr::LanguageMgr() : _langsMap(), _wordsMap() { } @@ -43,37 +43,8 @@ void LanguageMgr::LoadSpellEffectLanguage(SpellEffectEntry const* spellEffect) ASSERT(spellEffect && spellEffect->Effect == SPELL_EFFECT_LANGUAGE); uint32 languageId = uint32(spellEffect->EffectMiscValue[0]); - auto iter = _langsMap.find(languageId); - if (iter == _langsMap.end()) - { - TC_LOG_WARN("languages.spell", "LoadSpellEffectLanguage called on Spell %u with language %u which does not exist in Language.db2!", - spellEffect->SpellID, languageId); - return; - } - LanguageDesc& desc = iter->second; - desc.SpellId = spellEffect->SpellID; -} - -uint32 LanguageMgr::GetSpellLanguage(uint32 spellId) const -{ - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE)) - { - SpellEffectInfoVector const& effects = spellInfo->GetEffects(); - if (effects.size() != 1 || effects[0]->Effect != SPELL_EFFECT_LANGUAGE) - TC_LOG_WARN("languages.spell", "Invalid language spell %u. Expected 1 effect with SPELL_EFFECT_LANGUAGE", spellId); - else - return effects[0]->MiscValue; - } - return 0; -} - -bool LanguageMgr::IsRelevantLanguageSkill(SkillLineEntry const* skillLineEntry) const -{ - if (!skillLineEntry) - return false; - SkillRaceClassInfoEntry const* entry = sDB2Manager.GetAvailableSkillRaceClassInfo(skillLineEntry->ID); - return entry != nullptr; + _langsMap.emplace(languageId, LanguageDesc{ spellEffect->SpellID, 0 }); // register without a skill id for now } void LanguageMgr::LoadLanguages() @@ -82,57 +53,33 @@ void LanguageMgr::LoadLanguages() // Load languages from Languages.db2. Just the id, we don't need the name for (LanguagesEntry const* langEntry : sLanguagesStore) - _langsMap.emplace(langEntry->ID, LanguageDesc()); - - // Add the languages used in code in case they don't exist - _langsMap.emplace(LANG_UNIVERSAL, LanguageDesc()); - _langsMap.emplace(LANG_ADDON, LanguageDesc()); - _langsMap.emplace(LANG_ADDON_LOGGED, LanguageDesc()); - - // Log load time - TC_LOG_INFO("server.loading", ">> Loaded %u languages in %u ms", uint32(_langsMap.size()), GetMSTimeDiffToNow(oldMSTime)); -} - -void LanguageMgr::LoadLanguagesSkills() -{ - uint32 oldMSTime = getMSTime(); - - uint32 count = 0; - for (SkillLineEntry const* skillLineEntry : sSkillLineStore) { - if (skillLineEntry->CategoryID != SKILL_CATEGORY_LANGUAGES) - continue; - - if (!IsRelevantLanguageSkill(skillLineEntry)) - continue; - - std::vector<SkillLineAbilityEntry const*> const* skills = sDB2Manager.GetSkillLineAbilitiesBySkill(skillLineEntry->ID); - - // We're expecting only 1 skill - if (skills->size() != 1) - TC_LOG_WARN("server.loading", "Found language skill line with %u spells. Expected 1. Will use 1st if available", uint32(skills->size())); - - if (SkillLineAbilityEntry const* ability = skills->empty() ? nullptr : skills->at(0)) + auto spellsRange = Trinity::Containers::MapEqualRange(_langsMap, langEntry->ID); + if (spellsRange.begin() == spellsRange.end()) + _langsMap.emplace(langEntry->ID, LanguageDesc()); + else { - if (uint32 languageId = GetSpellLanguage(ability->Spell)) + std::vector<LanguageDesc> langsWithSkill; + for (LanguagesMap::value_type const& spellItr : spellsRange) + for (SkillLineAbilityMap::value_type const& skillPair : Trinity::Containers::MakeIteratorPair(sSpellMgr->GetSkillLineAbilityMapBounds(spellItr.second.SpellId))) + langsWithSkill.emplace_back(LanguageDesc{ spellItr.second.SpellId, uint32(skillPair.second->SkillLine) }); + + for (LanguageDesc const& langDesc : langsWithSkill) { - auto iter = _langsMap.find(languageId); - if (iter == _langsMap.cend()) - TC_LOG_WARN("server.loading", "Spell %u has language %u, which doesn't exist in Languages.db2", ability->Spell, languageId); - else - { - iter->second.SpellId = ability->Spell; - iter->second.SkillId = skillLineEntry->ID; - ++count; - } + // erase temporary assignment that lacked skill + Trinity::Containers::MultimapErasePair(_langsMap, langEntry->ID, { langDesc.SpellId, 0 }); + _langsMap.emplace(langEntry->ID, langDesc); } } } - // Languages that don't have skills will be added in SpellMgr::LoadSpellInfoStore() (e.g. LANG_ZOMBIE, LANG_SHATH_YAR) + // Add the languages used in code in case they don't exist + _langsMap.emplace(LANG_UNIVERSAL, LanguageDesc()); + _langsMap.emplace(LANG_ADDON, LanguageDesc()); + _langsMap.emplace(LANG_ADDON_LOGGED, LanguageDesc()); // Log load time - TC_LOG_INFO("server.loading", ">> Loaded %u languages skills in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u languages in %u ms", uint32(_langsMap.size()), GetMSTimeDiffToNow(oldMSTime)); } void LanguageMgr::LoadLanguagesWords() @@ -146,8 +93,7 @@ void LanguageMgr::LoadLanguagesWords() WordKey key = WordKey(wordEntry->LanguageID, length); - auto result = _wordsMap.insert(std::make_pair(key, WordList())); - result.first->second.push_back(wordEntry->Word); + _wordsMap[key].push_back(wordEntry->Word); ++wordsNum; } @@ -157,10 +103,7 @@ void LanguageMgr::LoadLanguagesWords() LanguageMgr::WordList const* LanguageMgr::FindWordGroup(uint32 language, uint32 wordLen) const { - WordsMap::const_iterator iter = _wordsMap.find(WordKey(language, wordLen)); - if (iter != _wordsMap.end()) - return &(iter->second); - return nullptr; + return Trinity::Containers::MapGetValuePtr(_wordsMap, WordKey(language, wordLen)); } std::string LanguageMgr::Translate(std::string const& msg, uint32 sourcePlayerLanguage) const @@ -221,14 +164,10 @@ uint32 LanguageMgr::SStrHash(char const* string, bool caseInsensitive, uint32 se bool LanguageMgr::IsLanguageExist(uint32 languageId) const { - auto iter = _langsMap.find(languageId); - return iter != _langsMap.cend(); + return sLanguagesStore.HasRecord(languageId); } -LanguageDesc const* LanguageMgr::GetLanguageDescById(uint32 languageId) const +Trinity::IteratorPair<LanguageMgr::LanguagesMap::const_iterator> LanguageMgr::GetLanguageDescById(Language languageId) const { - auto iter = _langsMap.find(languageId); - if (iter == _langsMap.cend()) - return nullptr; - return &(iter->second); + return Trinity::Containers::MapEqualRange(_langsMap, languageId); } diff --git a/src/server/game/Chat/LanguageMgr.h b/src/server/game/Chat/LanguageMgr.h index 57e5a6428eb..26010bfbcf8 100644 --- a/src/server/game/Chat/LanguageMgr.h +++ b/src/server/game/Chat/LanguageMgr.h @@ -20,6 +20,7 @@ #include "Define.h" #include "Hash.h" +#include "IteratorPair.h" #include "SharedDefines.h" #include <string> #include <vector> @@ -27,11 +28,15 @@ struct LanguageDesc { - uint32 SpellId; - uint32 SkillId; + uint32 SpellId = 0; + uint32 SkillId = 0; + + friend bool operator==(LanguageDesc const& left, LanguageDesc const& right) + { + return left.SpellId == right.SpellId && left.SkillId == right.SkillId; + } }; -struct SkillLineEntry; struct SpellEffectEntry; class TC_GAME_API LanguageMgr @@ -43,7 +48,7 @@ class TC_GAME_API LanguageMgr typedef std::vector<char const*> WordList; typedef std::unordered_map<WordKey, WordList> WordsMap; - typedef std::unordered_map<uint32, LanguageDesc> LanguagesMap; + typedef std::unordered_multimap<uint32, LanguageDesc> LanguagesMap; // Constructors private: @@ -60,7 +65,7 @@ class TC_GAME_API LanguageMgr uint32 SStrHash(char const* string, bool caseInsensitive, uint32 seed = 0x7FED7FED) const; bool IsLanguageExist(uint32 languageId) const; - LanguageDesc const* GetLanguageDescById(uint32 languageId) const; + Trinity::IteratorPair<LanguagesMap::const_iterator> GetLanguageDescById(Language languageId) const; /* Calls a callback for each available language. * Callback signature: bool callback(uint32 lang, LanguageDesc const& languageDesc) @@ -83,11 +88,6 @@ class TC_GAME_API LanguageMgr void LoadLanguagesWords(); void LoadLanguages(); - void LoadLanguagesSkills(); - - bool IsRelevantLanguageSkill(SkillLineEntry const* skillLineEntry) const; - - uint32 GetSpellLanguage(uint32 spellId) const; WordList const* FindWordGroup(uint32 language, uint32 wordLen) const; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index bdd97316759..3580a6903ec 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -2625,18 +2625,20 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio if (condition->LanguageID) { - if (LanguageDesc const* langDesc = sLanguageMgr->GetLanguageDescById(condition->LanguageID)) + int32 languageSkill = 0; + if (player->HasAuraTypeWithMiscvalue(SPELL_AURA_COMPREHEND_LANGUAGE, condition->LanguageID)) + languageSkill = 300; + else { - int32 languageSkill = player->GetSkillValue(langDesc->SkillId); - if (!languageSkill && player->HasAuraTypeWithMiscvalue(SPELL_AURA_COMPREHEND_LANGUAGE, condition->LanguageID)) - languageSkill = 300; + for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(Language(condition->LanguageID))) + languageSkill = std::max<int32>(languageSkill, player->GetSkillValue(languageDesc.second.SkillId)); + } - if (condition->MinLanguage && languageSkill < condition->MinLanguage) - return false; + if (condition->MinLanguage && languageSkill < condition->MinLanguage) + return false; - if (condition->MaxLanguage && languageSkill > condition->MaxLanguage) - return false; - } + if (condition->MaxLanguage && languageSkill > condition->MaxLanguage) + return false; } if (condition->MinFactionID[0] && condition->MinFactionID[1] && condition->MinFactionID[2] && condition->MaxFactionID) diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index de9f0c1e0df..81e848bb87d 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -2782,15 +2782,6 @@ std::vector<SkillLineAbilityEntry const*> const* DB2Manager::GetSkillLineAbiliti return Trinity::Containers::MapGetValuePtr(_skillLineAbilitiesBySkillupSkill, skillId); } -SkillRaceClassInfoEntry const* DB2Manager::GetAvailableSkillRaceClassInfo(uint32 skill) const -{ - auto bounds = _skillRaceClassInfoBySkill.equal_range(skill); - for (auto itr = bounds.first; itr != bounds.second; ++itr) - if (itr->second->Availability == 1) - return itr->second; - return nullptr; -} - SkillRaceClassInfoEntry const* DB2Manager::GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_) { auto bounds = _skillRaceClassInfoBySkill.equal_range(skill); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index e442d5c0297..47ff813c03d 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -404,7 +404,6 @@ public: std::vector<SkillLineEntry const*> const* GetSkillLinesForParentSkill(uint32 parentSkillId) const; std::vector<SkillLineAbilityEntry const*> const* GetSkillLineAbilitiesBySkill(uint32 skillId) const; SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); - SkillRaceClassInfoEntry const* GetAvailableSkillRaceClassInfo(uint32 skill) const; std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const; bool IsSpecSetMember(int32 specSetId, uint32 specId) const; static bool IsValidSpellFamiliyName(SpellFamilyNames family); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 208abfda260..f2ceb6bfd1a 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22082,9 +22082,16 @@ void Player::Whisper(uint32 textId, Player* target, bool /*isBossWhisper = false target->SendDirectMessage(packet.Write()); } -bool Player::CanUnderstandLanguageSkillId(uint32 langSkillId) const +bool Player::CanUnderstandLanguage(Language language) const { - return IsGameMaster() || (langSkillId && HasSkill(langSkillId)); + if (IsGameMaster()) + return true; + + for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(language)) + if (languageDesc.second.SkillId && HasSkill(languageDesc.second.SkillId)) + return true; + + return false; } Item* Player::GetMItem(ObjectGuid::LowType id) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index b664a7d6b62..335c60074a6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1166,7 +1166,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void Whisper(uint32 textId, Player* target, bool isBossWhisper = false) override; void WhisperAddon(std::string const& text, std::string const& prefix, bool isLogged, Player* receiver); - bool CanUnderstandLanguageSkillId(uint32 langSkillId) const; + bool CanUnderstandLanguage(Language language) const; /*********************************************************/ /*** STORAGE SYSTEM ***/ diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 97ce6ab32a5..8f45920a5af 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -107,27 +107,18 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms } // prevent talking at unknown language (cheating) - LanguageDesc const* langDesc = sLanguageMgr->GetLanguageDescById(lang); - if (!langDesc) + auto languageData = sLanguageMgr->GetLanguageDescById(lang); + if (languageData.begin() == languageData.end()) { SendNotification(LANG_UNKNOWN_LANGUAGE); return; } - if (langDesc->SkillId != 0 && !sender->HasSkill(langDesc->SkillId)) + if (std::none_of(languageData.begin(), languageData.end(), + [sender](std::pair<uint32 const, LanguageDesc> const& langDesc) { return langDesc.second.SkillId == 0 || sender->HasSkill(langDesc.second.SkillId); })) { // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language) - Unit::AuraEffectList const& langAuras = sender->GetAuraEffectsByType(SPELL_AURA_COMPREHEND_LANGUAGE); - bool foundAura = false; - for (Unit::AuraEffectList::const_iterator i = langAuras.begin(); i != langAuras.end(); ++i) - { - if ((*i)->GetMiscValue() == int32(lang)) - { - foundAura = true; - break; - } - } - if (!foundAura) + if (!sender->HasAuraTypeWithMiscvalue(SPELL_AURA_COMPREHEND_LANGUAGE, lang)) { SendNotification(LANG_NOT_LEARNED_LANGUAGE); return; diff --git a/src/server/game/Texts/ChatTextBuilder.cpp b/src/server/game/Texts/ChatTextBuilder.cpp index b31d126d676..ea564c2aa7f 100644 --- a/src/server/game/Texts/ChatTextBuilder.cpp +++ b/src/server/game/Texts/ChatTextBuilder.cpp @@ -27,17 +27,15 @@ namespace Trinity { ChatPacketSender::ChatPacketSender(ChatMsg chatType, ::Language language, WorldObject const* sender, WorldObject const* receiver, std::string message, uint32 achievementId /*= 0*/, LocaleConstant locale /*= LOCALE_enUS*/) - : Type(chatType), Language(language), Sender(sender), Receiver(receiver), Text(std::move(message)), AchievementId(achievementId), Locale(locale), LanguageSkillId(0) + : Type(chatType), Language(language), Sender(sender), Receiver(receiver), Text(std::move(message)), AchievementId(achievementId), Locale(locale) { UntranslatedPacket.Initialize(Type, Language, Sender, Receiver, Text, AchievementId, "", Locale); UntranslatedPacket.Write(); - if (LanguageDesc const* languageDesc = sLanguageMgr->GetLanguageDescById(language)) - LanguageSkillId = languageDesc->SkillId; } void ChatPacketSender::operator()(Player const* player) const { - if (Language == LANG_UNIVERSAL || Language == LANG_ADDON || Language == LANG_ADDON_LOGGED || player->CanUnderstandLanguageSkillId(LanguageSkillId)) + if (Language == LANG_UNIVERSAL || Language == LANG_ADDON || Language == LANG_ADDON_LOGGED || player->CanUnderstandLanguage(Language)) { player->SendDirectMessage(UntranslatedPacket.GetRawPacket()); return; diff --git a/src/server/game/Texts/ChatTextBuilder.h b/src/server/game/Texts/ChatTextBuilder.h index 74d677dfbfa..94ae1339652 100644 --- a/src/server/game/Texts/ChatTextBuilder.h +++ b/src/server/game/Texts/ChatTextBuilder.h @@ -40,8 +40,6 @@ namespace Trinity uint32 AchievementId; LocaleConstant Locale; - uint32 LanguageSkillId; - public: // caches WorldPackets::Chat::Chat UntranslatedPacket; diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 430af3e1a55..3f2cdb660eb 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -82,7 +82,7 @@ void CreatureTextMgr::LoadCreatureTexts() } } - if (!sLanguageMgr->IsLanguageExist(temp.lang)) + if (temp.lang != LANG_UNIVERSAL && !sLanguageMgr->IsLanguageExist(temp.lang)) { TC_LOG_ERROR("sql.sql", "CreatureTextMgr: Entry %u, Group %u in table `creature_text` using Language %u but Language does not exist.", temp.creatureId, temp.groupId, uint32(temp.lang)); temp.lang = LANG_UNIVERSAL; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index bbcfce3ed97..a2fdd5aea7d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1756,12 +1756,6 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Initializing PlayerDump tables..."); PlayerDump::InitializeTables(); - TC_LOG_INFO("server.loading", "Loading languages..."); - sLanguageMgr->LoadLanguages(); - - TC_LOG_INFO("server.loading", "Loading languages words..."); - sLanguageMgr->LoadLanguagesWords(); - TC_LOG_INFO("server.loading", "Loading SpellInfo store..."); sSpellMgr->LoadSpellInfoStore(); @@ -1783,15 +1777,18 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading SpellInfo immunity infos..."); sSpellMgr->LoadSpellInfoImmunities(); - TC_LOG_INFO("server.loading", "Loading languages skills..."); - sLanguageMgr->LoadLanguagesSkills(); - TC_LOG_INFO("server.loading", "Loading PetFamilySpellsStore Data..."); sSpellMgr->LoadPetFamilySpellsStore(); TC_LOG_INFO("server.loading", "Loading Spell Totem models..."); sSpellMgr->LoadSpellTotemModel(); + TC_LOG_INFO("server.loading", "Loading languages..."); // must be after LoadSpellInfoStore and LoadSkillLineAbilityMap + sLanguageMgr->LoadLanguages(); + + TC_LOG_INFO("server.loading", "Loading languages words..."); + sLanguageMgr->LoadLanguagesWords(); + TC_LOG_INFO("server.loading", "Loading GameObject models..."); LoadGameObjectModelList(m_dataPath); diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index b67c1427f63..4b86ff544cf 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -291,7 +291,9 @@ public: { sLanguageMgr->ForEachLanguage([handler](uint32 /*lang*/, LanguageDesc const& languageDesc) { - handler->GetSession()->GetPlayer()->LearnSpell(languageDesc.SpellId, false); + if (languageDesc.SpellId) + handler->GetSession()->GetPlayer()->LearnSpell(languageDesc.SpellId, false); + return true; }); |