rendered paste bodyIndex: src/game/Creature.h===================================================================--- src/game/Creature.h (revision 4577)+++ src/game/Creature.h (working copy)@@ -203,6 +203,13 @@ char const* ScriptName; }; +struct CreatureLocale+{+ uint32 Entry;+ std::string Name[8];+ std::string SubName[8];+};+ struct EquipmentInfo { uint32 entry;Index: src/game/GameObject.h===================================================================--- src/game/GameObject.h (revision 4577)+++ src/game/GameObject.h (working copy)@@ -68,6 +68,12 @@ char *ScriptName; }; +struct GameObjectLocale+{+ uint32 Entry;+ std::string Name[8];+};+ // from `ganeobject` struct GameObjectData {Index: src/game/GossipDef.cpp===================================================================--- src/game/GossipDef.cpp (revision 4577)+++ src/game/GossipDef.cpp (working copy)@@ -135,7 +135,17 @@ data << questID; data << uint32( pQuestMenu->GetItem(iI).m_qIcon ); data << uint32( pQuest ? pQuest->GetQuestLevel() : 0 );- data << (pQuest ? pQuest->GetTitle() : "");+ std::string Title = pQuest->GetTitle();+ if (pSession->GetSessionLanguage()>0)+ {+ QuestLocale const *ql = objmgr.GetQuestLocale(questID);+ if (ql)+ {+ if (ql->Title[pSession->GetSessionLanguage()]!="")+ Title=ql->Title[pSession->GetSessionLanguage()];+ }+ }+ data << Title; } pSession->SendPacket( &data );@@ -178,34 +188,54 @@ data << uint32( 0 ); data << "Greetings $N"; data << "Greetings $N";- } else+ } else {+ std::string Text_0[8],Text_1[8];+ for (int i=0;i<8;i++)+ {+ Text_0[i]=pGossip->Options[i].Text_0;+ Text_1[i]=pGossip->Options[i].Text_1;+ } - for (int i=0; i<8; i++)- {- data << pGossip->Options[i].Probability;+ if (pSession->GetSessionLanguage()>0)+ {+ NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);+ if (nl)+ {+ for (int i=0;i<8;i++)+ {+ if (nl->Text_0[i][pSession->GetSessionLanguage()]!="")+ Text_0[i]=nl->Text_0[i][pSession->GetSessionLanguage()];+ if (nl->Text_1[i][pSession->GetSessionLanguage()]!="")+ Text_1[i]=nl->Text_1[i][pSession->GetSessionLanguage()];+ }+ }+ }+ for (int i=0; i<8; i++)+ {+ data << pGossip->Options[i].Probability; - if ( pGossip->Options[i].Text_0 == "" )- data << pGossip->Options[i].Text_1;- else- data << pGossip->Options[i].Text_0;+ if ( Text_0[i] == "" )+ data << Text_1[i];+ else+ data << Text_0[i]; - if ( pGossip->Options[i].Text_1 == "" )- data << pGossip->Options[i].Text_0; - else- data << pGossip->Options[i].Text_1;+ if ( Text_1[i] == "" )+ data << Text_0[i]; + else+ data << Text_1[i]; - data << pGossip->Options[i].Language;+ data << pGossip->Options[i].Language; - data << pGossip->Options[i].Emotes[0]._Delay;- data << pGossip->Options[i].Emotes[0]._Emote;+ data << pGossip->Options[i].Emotes[0]._Delay;+ data << pGossip->Options[i].Emotes[0]._Emote; - data << pGossip->Options[i].Emotes[1]._Delay;- data << pGossip->Options[i].Emotes[1]._Emote;+ data << pGossip->Options[i].Emotes[1]._Delay;+ data << pGossip->Options[i].Emotes[1]._Emote; - data << pGossip->Options[i].Emotes[2]._Delay;- data << pGossip->Options[i].Emotes[2]._Emote;+ data << pGossip->Options[i].Emotes[2]._Delay;+ data << pGossip->Options[i].Emotes[2]._Emote;+ } }- pSession->SendPacket( &data ); sLog.outDetail( "WORLD: Sent SMSG_NPC_TEXT_UPDATE " );@@ -308,9 +338,28 @@ { WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size + std::string Title,Details,Objectives,EndText;+ Title = pQuest->GetTitle();+ Details = pQuest->GetDetails();+ Objectives = pQuest->GetObjectives();+ EndText = pQuest->GetEndText();+ if (pSession->GetSessionLanguage()>0)+ {+ QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());+ if (ql)+ {+ if (ql->Title[pSession->GetSessionLanguage()]!="")+ Title=ql->Title[pSession->GetSessionLanguage()];+ if (ql->Details[pSession->GetSessionLanguage()]!="")+ Details=ql->Details[pSession->GetSessionLanguage()];+ if (ql->Objectives[pSession->GetSessionLanguage()]!="")+ Objectives=ql->Objectives[pSession->GetSessionLanguage()];+ }+ }+ data << npcGUID;- data << pQuest->GetQuestId() << pQuest->GetTitle() << pQuest->GetDetails();- data << pQuest->GetObjectives();+ data << pQuest->GetQuestId() << Title << Details;+ data << Objectives; data << (uint32)ActivateAccept; data << pQuest->GetSuggestedPlayers(); @@ -379,6 +428,31 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) {+ std::string Title,Details,Objectives,EndText;+ std::string ObjectiveText[QUEST_OBJECTIVES_COUNT];+ Title = pQuest->GetTitle();+ Details = pQuest->GetDetails();+ Objectives = pQuest->GetObjectives();+ EndText = pQuest->GetEndText();+ for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)+ ObjectiveText[i]=pQuest->ObjectiveText[i];+ if (pSession->GetSessionLanguage()>0)+ {+ QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());+ if (ql)+ {+ if (ql->Title[pSession->GetSessionLanguage()]!="")+ Title=ql->Title[pSession->GetSessionLanguage()];+ if (ql->Details[pSession->GetSessionLanguage()]!="")+ Details=ql->Details[pSession->GetSessionLanguage()];+ if (ql->Objectives[pSession->GetSessionLanguage()]!="")+ Objectives=ql->Objectives[pSession->GetSessionLanguage()];+ for (int i=0;i<QUEST_OBJECTIVES_COUNT;i++)+ if (ql->ObjectiveText[i][pSession->GetSessionLanguage()]!="")+ ObjectiveText[i]=ql->ObjectiveText[i][pSession->GetSessionLanguage()];+ }+ }+ WorldPacket data( SMSG_QUEST_QUERY_RESPONSE, 100 ); // guess size data << uint32(pQuest->GetQuestId());@@ -439,10 +513,10 @@ data << pQuest->GetPointY(); data << pQuest->GetPointOpt(); - data << pQuest->GetTitle();- data << pQuest->GetObjectives();- data << pQuest->GetDetails();- data << pQuest->GetEndText();+ data << Title;+ data << Objectives;+ data << Details;+ data << EndText; for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++) {@@ -461,7 +535,7 @@ } for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; iI++)- data << pQuest->ObjectiveText[iI];+ data << ObjectiveText[iI]; pSession->SendPacket( &data ); //sLog.outDebug( "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u",pQuest->GetQuestId() );@@ -473,12 +547,27 @@ if(!qInfo) return; + std::string Title,OfferRewardText;+ Title = qInfo->GetTitle();+ OfferRewardText = qInfo->GetOfferRewardText();+ if (pSession->GetSessionLanguage()>0)+ {+ QuestLocale const *ql = objmgr.GetQuestLocale(quest_id);+ if (ql)+ {+ if (ql->Title[pSession->GetSessionLanguage()]!="")+ Title=ql->Title[pSession->GetSessionLanguage()];+ if (ql->OfferRewardText[pSession->GetSessionLanguage()]!="")+ OfferRewardText=ql->OfferRewardText[pSession->GetSessionLanguage()];+ }+ }+ WorldPacket data( SMSG_QUESTGIVER_OFFER_REWARD, 50 ); // guess size data << npcGUID; data << quest_id;- data << qInfo->GetTitle();- data << qInfo->GetOfferRewardText();+ data << Title;+ data << OfferRewardText; data << uint32( EnbleNext ); @@ -563,18 +652,33 @@ // items. Otherwise, we'll skip straight to the OfferReward // We may wish a better check, perhaps checking the real quest requirements- if (strlen(pQuest->GetRequestItemsText()) == 0)+ if (pQuest->GetRequestItemsText().size() == 0) { SendQuestGiverOfferReward(pQuest->GetQuestId(), npcGUID, true); return; } + std::string Title,RequestItemsText;+ Title = pQuest->GetTitle();+ RequestItemsText = pQuest->GetRequestItemsText();+ if (pSession->GetSessionLanguage()>0)+ {+ QuestLocale const *ql = objmgr.GetQuestLocale(pQuest->GetQuestId());+ if (ql)+ {+ if (ql->Title[pSession->GetSessionLanguage()]!="")+ Title=ql->Title[pSession->GetSessionLanguage()];+ if (ql->RequestItemsText[pSession->GetSessionLanguage()]!="")+ RequestItemsText=ql->RequestItemsText[pSession->GetSessionLanguage()];+ }+ }+ WorldPacket data( SMSG_QUESTGIVER_REQUEST_ITEMS, 50 ); // guess size data << npcGUID; data << pQuest->GetQuestId();- data << pQuest->GetTitle();+ data << Title; - data << pQuest->GetRequestItemsText();+ data << RequestItemsText; data << uint32(0x00); // unk Index: src/game/ItemHandler.cpp===================================================================--- src/game/ItemHandler.cpp (revision 4577)+++ src/game/ItemHandler.cpp (working copy)@@ -203,6 +203,20 @@ if( pProto ) {+ std::string Name, Description;+ Name = pProto->Name1;+ Description = pProto->Description;+ if (GetSessionLanguage()>0)+ {+ ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);+ if (il)+ {+ if (il->Name[GetSessionLanguage()]!="") // default to english+ Name = il->Name[GetSessionLanguage()];+ if (il->Description[GetSessionLanguage()]!="") // default to english+ Description = il->Description[GetSessionLanguage()];+ }+ } data << pProto->ItemId; data << pProto->Class; @@ -210,7 +224,7 @@ data << uint32(pProto->Class==ITEM_CLASS_CONSUMABLE ? 0 : pProto->SubClass); data << uint32(-1); // new 2.0.3, not exist in wdb cache?- data << pProto->Name1;+ 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);@@ -308,7 +322,7 @@ } } data << pProto->Bonding;- data << pProto->Description;+ data << Description; data << pProto->PageText; data << pProto->LanguageID; data << pProto->PageMaterial;@@ -812,10 +826,21 @@ ItemPrototype const *pProto = objmgr.GetItemPrototype( itemid ); if( pProto ) {+ std::string Name;+ Name = pProto->Name1;+ if (GetSessionLanguage()>0)+ {+ ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);+ if (il)+ {+ if (il->Name[GetSessionLanguage()]!="") // default to english+ Name = il->Name[GetSessionLanguage()];+ }+ } // guess size WorldPacket data(SMSG_ITEM_NAME_QUERY_RESPONSE, (4+10)); data << pProto->ItemId;- data << pProto->Name1;+ data << Name; SendPacket(&data); return; }Index: src/game/ItemPrototype.h===================================================================--- src/game/ItemPrototype.h (revision 4577)+++ src/game/ItemPrototype.h (working copy)@@ -523,6 +523,13 @@ uint32 FoodType; }; +struct ItemLocale+{+ uint32 Entry;+ std::string Name[8];+ std::string Description[8];+};+ // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform #if defined( __GNUC__ ) #pragma pack()Index: src/game/NPCHandler.h===================================================================--- src/game/NPCHandler.h (revision 4577)+++ src/game/NPCHandler.h (working copy)@@ -34,6 +34,12 @@ uint32 Next_Page; }; +struct PageTextLocale+{+ uint32 Entry;+ std::string Text[8];+};+ // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some paltform #if defined( __GNUC__ ) #pragma pack()@@ -61,4 +67,12 @@ uint32 Text_ID; GossipTextOption Options[8]; };++struct NpcTextLocale+{+ uint32 Entry;+ std::string Text_0[8][8];+ std::string Text_1[8][8];+};+ #endifIndex: src/game/ObjectMgr.cpp===================================================================--- src/game/ObjectMgr.cpp (revision 4577)+++ src/game/ObjectMgr.cpp (working copy)@@ -386,6 +386,59 @@ return sCreatureStorage.LookupEntry<CreatureInfo>(id); } +void ObjectMgr::LoadCreatureLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`name_loc" << (int)*itr << "`,`subname_loc" << (int)*itr << "`";+ itr++;+ while (itr != Locales->end())+ { + ostr << ",`name_loc" << (int)*itr << "`,`subname_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_creature`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ CreatureLocale& data = mCreatureLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ data.Name[*itr] = fields[currentIndex*2+1].GetCppString();+ data.SubName[*itr]= fields[currentIndex*2+2].GetCppString();+ currentIndex++;+ }++ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );+}+ void ObjectMgr::LoadCreatureTemplates() { sCreatureStorage.Load();@@ -913,6 +966,58 @@ sLog.outString(); } +void ObjectMgr::LoadItemLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`name_loc" << (int)*itr << "`,`description_loc" << (int)*itr << "`";+ itr++;+ while (itr != Locales->end())+ { + ostr << ",`name_loc" << (int)*itr << "`,`description_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_item`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ ItemLocale& data = mItemLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ data.Name[*itr] = fields[currentIndex*2+1].GetCppString();+ data.Description[*itr]= fields[currentIndex*2+2].GetCppString();+ currentIndex++;+ }+ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );+}+ void ObjectMgr::LoadItemPrototypes() { sItemStorage.Load ();@@ -2133,6 +2238,69 @@ sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() ); } +void ObjectMgr::LoadQuestLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`Title_loc" << (int)*itr << "`,`Details_loc" << (int)*itr << "`,`Objectives_loc" << (int)*itr;+ ostr << "`,`OfferRewardText_loc" << (int)*itr << "`,`RequestItemsText_loc" << (int)*itr << "`,`EndText_loc" << (int)*itr;+ ostr << "`,`ObjectiveText1_loc" << (int)*itr << "`,`ObjectiveText2_loc" << (int)*itr << "`,`ObjectiveText3_loc" << (int)*itr << "`,`ObjectiveText4_loc" << (int)*itr << "`";+ + itr++;+ while (itr != Locales->end())+ { + ostr << ",`Title_loc" << (int)*itr << "`,`Details_loc" << (int)*itr << "`,`Objectives_loc" << (int)*itr;+ ostr << "`,`OfferRewardText_loc" << (int)*itr << "`,`RequestItemsText_loc" << (int)*itr << "`,`EndText_loc" << (int)*itr;+ ostr << "`,`ObjectiveText1_loc" << (int)*itr << "`,`ObjectiveText2_loc" << (int)*itr << "`,`ObjectiveText3_loc" << (int)*itr << "`,`ObjectiveText4_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_quest`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ QuestLocale& data = mQuestLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ data.Title[*itr] = fields[currentIndex*10+1].GetCppString();+ data.Details[*itr] = fields[currentIndex*10+2].GetCppString();+ data.Objectives[*itr] = fields[currentIndex*10+3].GetCppString();+ data.OfferRewardText[*itr] = fields[currentIndex*10+4].GetCppString();+ data.RequestItemsText[*itr] = fields[currentIndex*10+5].GetCppString();+ data.EndText[*itr] = fields[currentIndex*10+2].GetCppString();+ for (int i=0;i<4;i++)+ data.ObjectiveText[i][*itr] = fields[currentIndex*10+6+i].GetCppString();+ currentIndex++;+ }+ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );+}+ void ObjectMgr::LoadSpellChains() { mSpellChains.clear(); // need for reload case@@ -2716,6 +2884,58 @@ sLog.outString(); } +void ObjectMgr::LoadPageTextLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`text_loc" << (int)*itr << "`";+ itr++;+ while (itr != Locales->end())+ { + ostr << ",`text_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_page_text`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ PageTextLocale& data = mPageTextLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ data.Text[*itr] = fields[currentIndex+1].GetCppString();+ currentIndex++;+ }++ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );+}+ void ObjectMgr::AddGossipText(GossipText *pGText) { ASSERT( pGText->Text_ID );@@ -2794,6 +3014,64 @@ delete result; } +void ObjectMgr::LoadNpcTextLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`Text0_0_loc" << (int)*itr << "`,`Text0_1_loc" << (int)*itr << "`";+ for (int i=1;i<8;i++)+ ostr << ",`Text" << i << "_0_loc" << (int)*itr << "`,`Text" << i << "_1_loc" << (int)*itr << "`";+ itr++;+ while (itr != Locales->end())+ {+ for (int i=0;i<8;i++)+ ostr << ",`Text" << i << "_0_loc" << (int)*itr << "`,`Text" << i << "_1_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_npc_text`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ NpcTextLocale& data = mNpcTextLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ for (int i=0;i<8;i++)+ {+ data.Text_0[i][*itr] = fields[currentIndex*16+1+i*2].GetCppString();+ data.Text_1[i][*itr] = fields[currentIndex*16+2+i*2].GetCppString();+ }+ currentIndex++;+ }+ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );+}+ //not very fast function but it is called only once a day, or on starting-up void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) {@@ -3513,6 +3791,58 @@ return 0; } +void ObjectMgr::LoadGameObjectLocales()+{+ const World::LocalizationMap *Locales = sWorld.GetSupportedLocals();++ World::LocalizationMap::const_iterator itr = Locales->begin();+ std::ostringstream ostr;+ ostr << "`name_loc" << (int)*itr << "`";+ itr++;+ while (itr != Locales->end())+ { + ostr << ",`name_loc" << (int)*itr << "`";+ itr++;+ }++ QueryResult *result = sDatabase.PQuery("SELECT `entry`,%s FROM `locales_gameobject`",ostr.str().c_str());++ if(!result)+ {+ barGoLink bar(1);++ bar.step();++ sLog.outString("");+ sLog.outErrorDb(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");+ return;+ }++ barGoLink bar(result->GetRowCount());++ do+ {+ Field *fields = result->Fetch();+ bar.step();++ uint32 entry = fields[0].GetUInt32();++ GameObjectLocale& data = mGameObjectLocaleMap[entry];+ uint16 currentIndex=0;+ for (itr = Locales->begin(); itr != Locales->end(); ++itr)+ {+ data.Name[*itr] = fields[currentIndex+1].GetCppString();+ currentIndex++;+ }++ } while (result->NextRow());++ delete result;++ sLog.outString();+ sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );+}+ void ObjectMgr::LoadGameobjectInfo() { sGOStorage.Load();Index: src/game/ObjectMgr.h===================================================================--- src/game/ObjectMgr.h (revision 4577)+++ src/game/ObjectMgr.h (working copy)@@ -112,6 +112,12 @@ typedef HM_NAMESPACE::hash_map<uint32,CreatureData> CreatureDataMap; typedef HM_NAMESPACE::hash_map<uint32,GameObjectData> GameObjectDataMap;+typedef HM_NAMESPACE::hash_map<uint32,CreatureLocale> CreatureLocaleMap;+typedef HM_NAMESPACE::hash_map<uint32,GameObjectLocale> GameObjectLocaleMap;+typedef HM_NAMESPACE::hash_map<uint32,ItemLocale> ItemLocaleMap;+typedef HM_NAMESPACE::hash_map<uint32,QuestLocale> QuestLocaleMap;+typedef HM_NAMESPACE::hash_map<uint32,NpcTextLocale> NpcTextLocaleMap;+typedef HM_NAMESPACE::hash_map<uint32,PageTextLocale> PageTextLocaleMap; typedef std::multimap<uint32,uint32> QuestRelations; @@ -415,17 +421,23 @@ void LoadSpellScriptTarget(); void LoadPetCreateSpells();+ void LoadCreatureLocales(); void LoadCreatureTemplates(); void LoadCreatures(); void LoadCreatureRespawnTimes(); void LoadCreatureAddons(); void LoadCreatureModelInfo(); void LoadEquipmentTemplates();+ void LoadGameObjectLocales(); void LoadGameobjects(); void LoadGameobjectRespawnTimes(); void LoadSpellProcEvents(); void LoadSpellThreats(); void LoadItemPrototypes();+ void LoadItemLocales();+ void LoadQuestLocales();+ void LoadNpcTextLocales();+ void LoadPageTextLocales(); void LoadGossipText(); @@ -617,6 +629,43 @@ CreatureData& NewCreatureData(uint32 guid) { return mCreatureDataMap[guid]; } void DeleteCreatureData(uint32 guid); + CreatureLocale const* GetCreatureLocale(uint32 entry) const+ {+ CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry);+ if(itr==mCreatureLocaleMap.end()) return NULL;+ return &itr->second;+ }+ GameObjectLocale const* GetGameObjectLocale(uint32 entry) const+ {+ GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry);+ if(itr==mGameObjectLocaleMap.end()) return NULL;+ return &itr->second;+ }+ ItemLocale const* GetItemLocale(uint32 entry) const+ {+ ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry);+ if(itr==mItemLocaleMap.end()) return NULL;+ return &itr->second;+ }+ QuestLocale const* GetQuestLocale(uint32 entry) const+ {+ QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry);+ if(itr==mQuestLocaleMap.end()) return NULL;+ return &itr->second;+ }+ NpcTextLocale const* GetNpcTextLocale(uint32 entry) const+ {+ NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry);+ if(itr==mNpcTextLocaleMap.end()) return NULL;+ return &itr->second;+ }+ PageTextLocale const* GetPageTextLocale(uint32 entry) const+ {+ PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry);+ if(itr==mPageTextLocaleMap.end()) return NULL;+ return &itr->second;+ }+ GameObjectData const* GetGOData(uint32 guid) const { GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid);@@ -721,7 +770,13 @@ MapObjectGuids mMapObjectGuids; CreatureDataMap mCreatureDataMap;+ CreatureLocaleMap mCreatureLocaleMap; GameObjectDataMap mGameObjectDataMap;+ GameObjectLocaleMap mGameObjectLocaleMap;+ ItemLocaleMap mItemLocaleMap;+ QuestLocaleMap mQuestLocaleMap;+ NpcTextLocaleMap mNpcTextLocaleMap;+ PageTextLocaleMap mPageTextLocaleMap; RespawnTimes mCreatureRespawnTimes; RespawnTimes mGORespawnTimes; Index: src/game/Player.cpp===================================================================--- src/game/Player.cpp (revision 4577)+++ src/game/Player.cpp (working copy)@@ -10447,6 +10447,15 @@ title = gossiptext->Options[0].Text_0 == "" ? gossiptext->Options[0].Text_1 : gossiptext->Options[0].Text_0; if( &title == NULL ) title = "";+ if (GetSession()->GetSessionLanguage()>0)+ {+ NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textid);+ if (nl)+ {+ if (nl->Text_0[0][GetSession()->GetSessionLanguage()]!="" || nl->Text_1[0][GetSession()->GetSessionLanguage()]!="")+ title = nl->Text_0[0][GetSession()->GetSessionLanguage()]=="" ? nl->Text_1[0][GetSession()->GetSessionLanguage()] : nl->Text_0[0][GetSession()->GetSessionLanguage()];+ }+ } } } PlayerTalkClass->SendQuestGiverQuestList( qe, title, guid );Index: src/game/QueryHandler.cpp===================================================================--- src/game/QueryHandler.cpp (revision 4577)+++ src/game/QueryHandler.cpp (working copy)@@ -114,8 +114,6 @@ // return; } - //CreatureInfo const *ci = unit->GetCreatureInfo();- CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); if (!ci)@@ -124,18 +122,38 @@ return; } + std::string Name, SubName;+ //CreatureInfo const *ci = unit->GetCreatureInfo();+ Name = ci->Name;+ SubName = ci->SubName;++ if (GetSessionLanguage()>0)+ {+ CreatureLocale const *cl = objmgr.GetCreatureLocale(entry);+ if (cl)+ {+ if (cl->Name[GetSessionLanguage()]!="") // default to english+ Name = cl->Name[GetSessionLanguage()];+ if (cl->SubName[GetSessionLanguage()]!="") // same+ SubName = cl->SubName[GetSessionLanguage()];+ }+ }+ sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u - GUID: %u.", ci->Name, entry, guid); WorldPacket data( SMSG_CREATURE_QUERY_RESPONSE, 100 ); // guess size data << (uint32)entry; // creature entry- data << (unit ? unit->GetName() : ci->Name); // creature name+ if (unit)+ data << ((unit->isPet()) ? unit->GetName() : Name); // creature name+ else+ data << Name; data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty if (unit)- data << ((unit->isPet()) ? "Pet" : ci->SubName); // subname+ data << ((unit->isPet()) ? "Pet" : SubName); // subname else- data << ci->SubName;+ data << SubName; data << ci->flag1; // flags wdbFeild7=wad flags1 @@ -157,7 +175,7 @@ data << (float)1; // unk data << (float)1; // unk data << uint8(ci->civilian);- data << uint8(0); // boss flag?+ data << uint8(ci->RacialLeader); SendPacket( &data ); } @@ -171,6 +189,7 @@ recv_data >> entryID; recv_data >> guid; + std::string Name; const GameObjectInfo *info = objmgr.GetGameObjectInfo(entryID); // guess size WorldPacket data ( SMSG_GAMEOBJECT_QUERY_RESPONSE, 150 );@@ -181,11 +200,21 @@ } else {+ Name = info->name;+ if (GetSessionLanguage()>0)+ {+ GameObjectLocale const *gl = objmgr.GetGameObjectLocale(entryID);+ if (gl)+ {+ if (gl->Name[GetSessionLanguage()]!="") // default to english+ Name = gl->Name[GetSessionLanguage()];+ }+ } sLog.outDetail("WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u - GUID: %u.", info->name, entryID, guid); data << entryID; data << (uint32)info->type; data << (uint32)info->displayId;- data << info->name;+ data << Name; data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4 data << uint8(0); // 2.0.3, string data << uint8(0); // 2.0.3, string@@ -266,32 +295,54 @@ data << uint32( 0 ); data << "Greetings $N"; data << "Greetings $N";- } else+ } else {+ std::string Text_0[8], Text_1[8];+ for (int i=0;i<8;i++)+ {+ Text_0[i]=pGossip->Options[i].Text_0;+ Text_1[i]=pGossip->Options[i].Text_1;+ } - for (int i=0; i<8; i++)- {- data << pGossip->Options[i].Probability;+ if (GetSessionLanguage()>0)+ {+ NpcTextLocale const *nl = objmgr.GetNpcTextLocale(textID);+ if (nl)+ {+ for (int i=0;i<8;i++)+ {+ if (nl->Text_0[i][GetSessionLanguage()]!="")+ Text_0[i]=nl->Text_0[i][GetSessionLanguage()];+ if (nl->Text_1[i][GetSessionLanguage()]!="")+ Text_1[i]=nl->Text_1[i][GetSessionLanguage()];+ }+ }+ } - if ( pGossip->Options[i].Text_0 == "" )- data << pGossip->Options[i].Text_1;- else- data << pGossip->Options[i].Text_0;+ for (int i=0; i<8; i++)+ {+ data << pGossip->Options[i].Probability; - if ( pGossip->Options[i].Text_1 == "" )- data << pGossip->Options[i].Text_0; - else- data << pGossip->Options[i].Text_1;+ if ( Text_0[i] == "" )+ data << Text_1[i];+ else+ data << Text_0[i]; - data << pGossip->Options[i].Language;+ if ( Text_1[i] == "" )+ data << Text_0[i];+ else+ data << Text_1[i]; - data << pGossip->Options[i].Emotes[0]._Delay;- data << pGossip->Options[i].Emotes[0]._Emote;+ data << pGossip->Options[i].Language; - data << pGossip->Options[i].Emotes[1]._Delay;- data << pGossip->Options[i].Emotes[1]._Emote;+ data << pGossip->Options[i].Emotes[0]._Delay;+ data << pGossip->Options[i].Emotes[0]._Emote; - data << pGossip->Options[i].Emotes[2]._Delay;- data << pGossip->Options[i].Emotes[2]._Emote;+ data << pGossip->Options[i].Emotes[1]._Delay;+ data << pGossip->Options[i].Emotes[1]._Emote;++ data << pGossip->Options[i].Emotes[2]._Delay;+ data << pGossip->Options[i].Emotes[2]._Emote;+ } } SendPacket( &data );@@ -323,7 +374,17 @@ } else {- data << pPage->Text;+ std::string Text = pPage->Text;+ if (GetSessionLanguage()>0)+ {+ PageTextLocale const *pl = objmgr.GetPageTextLocale(pageID);+ if (pl)+ {+ if (pl->Text[GetSessionLanguage()]!="")+ Text = pl->Text[GetSessionLanguage()];+ }+ }+ data << Text; data << uint32(pPage->Next_Page); pageID = pPage->Next_Page; }Index: src/game/QuestDef.h===================================================================--- src/game/QuestDef.h (revision 4577)+++ src/game/QuestDef.h (working copy)@@ -126,6 +126,18 @@ //QUEST_SPECIAL_FLAGS_UNK5 = 2048, // unknown tbc }; +struct QuestLocale+{+ uint32 Entry;+ std::string Title[8];+ std::string Details[8];+ std::string Objectives[8];+ std::string OfferRewardText[8];+ std::string RequestItemsText[8];+ std::string EndText[8];+ std::string ObjectiveText[QUEST_OBJECTIVES_COUNT][8];+};+ // This Quest class provides a convenient way to access a few pretotaled (cached) quest details, // all base quest information, and any utility functions such as generating the amount of // xp to give@@ -147,9 +159,9 @@ uint32 GetRequiredRaces() const { return RequiredRaces; } uint32 GetRequiredSkillValue() const { return RequiredSkillValue; } uint32 GetRequiredMinRepFaction() const { return RequiredMinRepFaction; }- int32 GetRequiredMinRepValue() const { return RequiredMinRepValue; }+ int32 GetRequiredMinRepValue() const { return RequiredMinRepValue; } uint32 GetRequiredMaxRepFaction() const { return RequiredMaxRepFaction; }- int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; }+ int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; } uint32 GetSuggestedPlayers() const { return SuggestedPlayers; } uint32 GetLimitTime() const { return LimitTime; } int32 GetNextQuestId() const { return NextQuestId; }@@ -158,12 +170,12 @@ uint32 GetSrcItemId() const { return SrcItemId; } uint32 GetSrcItemCount() const { return SrcItemCount; } uint32 GetSrcSpell() const { return SrcSpell; }- const char* GetTitle() const { return Title.c_str(); }- const char* GetDetails() const { return Details.c_str(); }- const char* GetObjectives() const { return Objectives.c_str(); }- const char* GetOfferRewardText() const { return OfferRewardText.c_str(); }- const char* GetRequestItemsText() const { return RequestItemsText.c_str(); }- const char* GetEndText() const { return EndText.c_str(); }+ std::string GetTitle() const { return Title; }+ std::string GetDetails() const { return Details; }+ std::string GetObjectives() const { return Objectives; }+ std::string GetOfferRewardText() const { return OfferRewardText; }+ std::string GetRequestItemsText() const { return RequestItemsText; }+ std::string GetEndText() const { return EndText; } int32 GetRewOrReqMoney() const { return RewOrReqMoney; } uint32 GetRewXpOrMoney() const { return RewXpOrMoney; } uint32 GetRewSpell() const { return RewSpell; }Index: src/game/World.cpp===================================================================--- src/game/World.cpp (revision 4577)+++ src/game/World.cpp (working copy)@@ -475,6 +475,9 @@ exit(1); } + std::string localization = sConfig.GetStringDefault("StringLocalize", "");+ FillSupportedLocals(localization);+ ///- Update the realm entry in the database with the realm type from the config file //No SQL injection as values are treated as integers loginDatabase.PExecute("UPDATE `realmlist` SET `icon` = %u WHERE `id` = '%d'", m_configs[CONFIG_GAME_TYPE],realmID);@@ -495,6 +498,17 @@ objmgr.PackInstances(); ///- Load static data tables from the database+ if (m_SupportedLocals.size()>0)+ {+ sLog.outString( "Loading Localization strings..." );+ objmgr.LoadCreatureLocales();+ objmgr.LoadGameObjectLocales();+ objmgr.LoadItemLocales();+ objmgr.LoadQuestLocales();+ objmgr.LoadNpcTextLocales();+ objmgr.LoadPageTextLocales();+ }+ sLog.outString( "Loading Game Object Templates..." ); objmgr.LoadGameobjectInfo(); @@ -1647,3 +1661,29 @@ loginDatabase.PExecute("INSERT INTO `realmcharacters` (`numchars`, `acctid`, `realmid`) VALUES (%u, %u, %u) ON DUPLICATE KEY UPDATE `numchars` = '%u'", charCount, accountId, realmID, charCount); } }++void World::FillSupportedLocals(std::string str)+{+ if(str=="")+ {+ return; // English by default if none selected+ }+ int local;+ std::istringstream ss(str);+ for(int i = 0; i < 8; ++i)+ {+ ss >> local;+ if (local > 0 && local <8)+ SetSupportedLocals((uint8) local);+ if(!ss)+ break;+ }+ if (m_SupportedLocals.empty())+ {+ sLog.outError("Unable to determine your Locales!!");+ exit(1);+ }+ LocalizationMap::const_iterator itr;+ for (itr = m_SupportedLocals.begin(); itr != m_SupportedLocals.end(); ++itr)+ sLog.outString("Support for local %u will be used",*itr);+}Index: src/game/World.h===================================================================--- src/game/World.h (revision 4577)+++ src/game/World.h (working copy)@@ -349,11 +349,16 @@ void UpdateRealmCharCount(uint32 accid); + typedef std::set<uint8> LocalizationMap;+ LocalizationMap const* GetSupportedLocals() const { return &m_SupportedLocals; }+ protected: void _UpdateGameTime(); void ScriptsProcess(); // callback for UpdateRealmCharacters void _UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId);+ void SetSupportedLocals(uint8 local) { m_SupportedLocals.insert(local); }+ void FillSupportedLocals(std::string str); private: time_t m_startTime;@@ -394,6 +399,9 @@ // CLI command holder to be thread safe ZThread::LockedQueue<CliCommandHolder*, ZThread::FastMutex> cliCmdQueue; SqlResultQueue *m_resultQueue;++ // Localization+ LocalizationMap m_SupportedLocals; }; extern uint32 realmID;Index: src/game/WorldSession.cpp===================================================================--- src/game/WorldSession.cpp (revision 4577)+++ src/game/WorldSession.cpp (working copy)@@ -40,9 +40,9 @@ #include "Chat.h" /// WorldSession constructor-WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time) :+WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time, uint8 locale) : LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time),-_player(NULL), _socket(sock),_security(sec), _accountId(id), m_isTBC(tbc),+_player(NULL), _socket(sock),_security(sec), _accountId(id), m_isTBC(tbc), m_sessionLanguage(locale), _logoutTime(0), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false) { FillOpcodeHandlerHashTable();Index: src/game/WorldSession.h===================================================================--- src/game/WorldSession.h (revision 4577)+++ src/game/WorldSession.h (working copy)@@ -64,7 +64,7 @@ { friend class CharacterHandler; public:- WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time);+ WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time, uint8 locale); ~WorldSession(); bool PlayerLoading() { return m_playerLoading; }@@ -170,6 +170,9 @@ // Account mute time time_t m_muteTime;++ // Locales+ uint8 GetSessionLanguage() { return m_sessionLanguage; } protected: void HandleCharEnumOpcode(WorldPacket& recvPacket);@@ -556,6 +559,7 @@ bool m_playerLoading; // code processed in LoginPlayer bool m_playerLogout; // code processed in LogoutPlayer bool m_playerRecentlyLogout;+ uint8 m_sessionLanguage; void FillOpcodeHandlerHashTable(); Index: src/game/WorldSocket.cpp===================================================================--- src/game/WorldSocket.cpp (revision 4577)+++ src/game/WorldSocket.cpp (working copy)@@ -221,6 +221,7 @@ uint32 unk2; uint32 BuiltNumberClient; uint32 id, security;+ uint8 locale; bool tbc = false; std::string account; Sha1Hash sha1;@@ -248,8 +249,8 @@ std::string safe_account=account; // Duplicate, else will screw the SHA hash verification below loginDatabase.escape_string(safe_account); //No SQL injection, username escaped.- // 0 1 2 3 4 5 6 7 8 9- QueryResult *result = loginDatabase.PQuery("SELECT `id`,`gmlevel`,`sessionkey`,`last_ip`,`locked`, `I`, `v`, `s`, `tbc`,`mutetime` FROM `account` WHERE `username` = '%s'", safe_account.c_str());+ // 0 1 2 3 4 5 6 7 8 9 10+ QueryResult *result = loginDatabase.PQuery("SELECT `id`,`gmlevel`,`sessionkey`,`last_ip`,`locked`, `I`, `v`, `s`, `tbc`,`mutetime`,`locale` FROM `account` WHERE `username` = '%s'", safe_account.c_str()); ///- Stop if the account is not found if ( !result )@@ -321,7 +322,7 @@ security = fields[1].GetUInt16(); K.SetHexStr(fields[2].GetString()); time_t mutetime = time_t(fields[9].GetUInt64());-+ locale = fields[10].GetUInt8(); delete result; ///- Re-check account ban (same check as in realmd) /// TO DO: why on earth do 2 checks for same thing?@@ -395,7 +396,7 @@ SendPacket(&packet); ///- Create a new WorldSession for the player and add it to the World- _session = new WorldSession(id, this,security,tbc,mutetime);+ _session = new WorldSession(id, this,security,tbc,mutetime,locale); sWorld.AddSession(_session); if(sLog.IsOutDebug()) // optimize disabled debug outputIndex: src/mangosd/mangosd.conf.in===================================================================--- src/mangosd/mangosd.conf.in (revision 4577)+++ src/mangosd/mangosd.conf.in (working copy)@@ -54,6 +54,14 @@ # 255 = Auto Detect (Default) DBC.Locale = 255 +# Full localization support activation+# use the same codes as for DBC language to enable localization support in this language+# Be informed that activating it consumes some memory (around 57MB per language activated)+# ex: StringLocalize = "2" will activate French on top of default English+# You can activate several languages like StringLocalize = "2 3" for French and German+# StringLocalize = "" (Default = Disabled)+StringLocalize = ""+ # Enable logging of GM commands - all SQL code will be written to a log file # All commands are written to a file: YYYY-MM-DD_logSQL.sql # If a new day starts (00:00:00) then a new file is created - the oldIndex: src/realmd/AuthSocket.cpp===================================================================--- src/realmd/AuthSocket.cpp (revision 4577)+++ src/realmd/AuthSocket.cpp (working copy)@@ -448,6 +448,14 @@ pkt.append(s.AsByteArray(), s.GetNumBytes()); pkt.append(unk3.AsByteArray(), 16); pkt << (uint8)0; // Added in 1.12.x client branch++ QueryResult *localeresult = dbRealmServer.PQuery("SELECT `locale` FROM `localization` WHERE `string` = '%c%c'",ch->country[3],ch->country[2]);+ if( localeresult )+ _localization=(*localeresult)[0].GetUInt8();+ else+ _localization=0; ++ sLog.outBasic("[AuthChallenge] acount %s is using '%c%c' locale (%u)", _login.c_str (), ch->country[3],ch->country[2], _localization); } } delete result;@@ -595,7 +603,7 @@ ///- Update the sessionkey, last_ip and last login time in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket- dbRealmServer.PExecute("UPDATE `account` SET `sessionkey` = '%s', `last_ip` = '%s', `last_login` = NOW() WHERE `username` = '%s'",K.AsHexStr(), GetRemoteAddress().c_str(), _safelogin.c_str() );+ dbRealmServer.PExecute("UPDATE `account` SET `sessionkey` = '%s', `last_ip` = '%s', `last_login` = NOW(), `locale` = '%u' WHERE `username` = '%s'",K.AsHexStr(), GetRemoteAddress().c_str(), _localization, _safelogin.c_str() ); ///- Finish SRP6 and send the final result to the client sha.Initialize();Index: src/realmd/AuthSocket.h===================================================================--- src/realmd/AuthSocket.h (revision 4577)+++ src/realmd/AuthSocket.h (working copy)@@ -68,6 +68,7 @@ std::string _login; std::string _safelogin;+ uint8 _localization; }; #endif /// @}