From 0639ac159fbe1166544d8b04e77a3743133ac163 Mon Sep 17 00:00:00 2001 From: Antz Date: Thu, 2 Feb 2023 23:01:28 +0000 Subject: [PATCH] refactor emails and remove item_text in line with other cores --- src/game/Object/AuctionHouseMgr.cpp | 2 +- src/game/Object/Item.cpp | 19 ++--- src/game/Object/Item.h | 4 + src/game/Object/ObjectMgr.cpp | 85 ++----------------- src/game/Object/ObjectMgr.h | 26 ++---- src/game/Object/Player.cpp | 46 +++++----- src/game/Tools/PlayerDump.cpp | 30 ------- src/game/Tools/PlayerDump.h | 2 - src/game/WorldHandlers/AccountMgr.cpp | 4 +- .../WorldHandlers/AuctionHouseHandler.cpp | 6 +- src/game/WorldHandlers/CharacterHandler.cpp | 2 +- src/game/WorldHandlers/Mail.cpp | 43 ++-------- src/game/WorldHandlers/Mail.h | 32 +++---- src/game/WorldHandlers/MailHandler.cpp | 57 +++++++------ src/game/WorldHandlers/World.cpp | 3 - .../playerbot/strategy/actions/MailAction.cpp | 4 +- src/shared/revision_data.h.in | 4 +- 17 files changed, 105 insertions(+), 264 deletions(-) diff --git a/src/game/Object/AuctionHouseMgr.cpp b/src/game/Object/AuctionHouseMgr.cpp index 793ecec1c..045cb85d1 100644 --- a/src/game/Object/AuctionHouseMgr.cpp +++ b/src/game/Object/AuctionHouseMgr.cpp @@ -299,7 +299,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail(AuctionEntry* auction) auction->itemGuidLow = 0; // will delete item or place to receiver mail list - MailDraft(subject.str()) + MailDraft(subject.str(),"") .AddItem(pItem) .SendMailTo(MailReceiver(owner, owner_guid), auction, MAIL_CHECK_MASK_COPIED); } diff --git a/src/game/Object/Item.cpp b/src/game/Object/Item.cpp index 780699942..578c56769 100644 --- a/src/game/Object/Item.cpp +++ b/src/game/Object/Item.cpp @@ -379,15 +379,17 @@ void Item::SaveToDB() ss << GetUInt32Value(i) << " "; } - stmt = CharacterDatabase.CreateStatement(insItem, "INSERT INTO `item_instance` (`guid`,`owner_guid`,`data`) VALUES (?, ?, ?)"); - stmt.PExecute(guid, GetOwnerGuid().GetCounter(), ss.str().c_str()); + stmt = CharacterDatabase.CreateStatement(insItem, "INSERT INTO `item_instance` (`guid`,`owner_guid`,`data`,`text`) VALUES (?, ?, ?, ?)"); + stmt.PExecute(guid, GetOwnerGuid().GetCounter(), ss.str().c_str(), m_text.c_str()); } break; case ITEM_CHANGED: { + std::string text = m_text; + CharacterDatabase.escape_string(text); static SqlStatementID updInstance ; static SqlStatementID updGifts ; - SqlStatement stmt = CharacterDatabase.CreateStatement(updInstance, "UPDATE `item_instance` SET `data` = ?, `owner_guid` = ? WHERE `guid` = ?"); + SqlStatement stmt = CharacterDatabase.CreateStatement(updInstance, "UPDATE `item_instance` SET `data` = ?, `owner_guid` = ?, `text` = ? WHERE `guid` = ?"); std::ostringstream ss; for (uint16 i = 0; i < m_valuesCount; ++i) @@ -395,7 +397,7 @@ void Item::SaveToDB() ss << GetUInt32Value(i) << " "; } - stmt.PExecute(ss.str().c_str(), GetOwnerGuid().GetCounter(), guid); + stmt.PExecute(ss.str().c_str(), GetOwnerGuid().GetCounter(), m_text.c_str(), guid); if (HasFlag(ITEM_FIELD_FLAGS, ITEM_DYNFLAG_WRAPPED)) { @@ -405,17 +407,10 @@ void Item::SaveToDB() } break; case ITEM_REMOVED: { - static SqlStatementID delItemText; static SqlStatementID delInst ; static SqlStatementID delGifts ; static SqlStatementID delLoot ; - if (uint32 item_text_id = GetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID)) - { - SqlStatement stmt = CharacterDatabase.CreateStatement(delItemText, "DELETE FROM `item_text` WHERE `id` = ?"); - stmt.PExecute(item_text_id); - } - SqlStatement stmt = CharacterDatabase.CreateStatement(delInst, "DELETE FROM `item_instance` WHERE `guid` = ?"); stmt.PExecute(guid); @@ -511,6 +506,8 @@ bool Item::LoadFromDB(uint32 guidLow, Field* fields, ObjectGuid ownerGuid) return false; } + SetText(fields[1].GetCppString()); + bool need_save = false; // need explicit save data at load fixes // overwrite possible wrong/corrupted guid diff --git a/src/game/Object/Item.h b/src/game/Object/Item.h index 1c50b6c24..0fa613432 100644 --- a/src/game/Object/Item.h +++ b/src/game/Object/Item.h @@ -340,6 +340,9 @@ class Item : public Object uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);} uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);} + std::string const& GetText() const { return m_text; } + void SetText(std::string const& text) { m_text = text; } + void SendTimeUpdate(Player* owner); void UpdateDuration(Player* owner, uint32 diff); @@ -379,6 +382,7 @@ class Item : public Object void RemoveFromClientUpdateList() override; void BuildUpdateData(UpdateDataMapType& update_players) override; private: + std::string m_text; uint8 m_slot; Bag* m_container; ItemUpdateState uState; diff --git a/src/game/Object/ObjectMgr.cpp b/src/game/Object/ObjectMgr.cpp index e242bd131..489cd73cb 100644 --- a/src/game/Object/ObjectMgr.cpp +++ b/src/game/Object/ObjectMgr.cpp @@ -141,7 +141,6 @@ ObjectMgr::ObjectMgr() : m_ArenaTeamIds("Arena team ids"), m_AuctionIds("Auction ids"), m_GuildIds("Guild ids"), - m_ItemTextIds("Item text ids"), m_MailIds("Mail ids"), m_PetNumbers("Pet numbers"), m_FirstTemporaryCreatureGuid(1), @@ -4685,43 +4684,6 @@ void ObjectMgr::LoadPetCreateSpells() sLog.outString(">> Loaded %u pet create spells from table and %u from DBC", count, dcount); } -void ObjectMgr::LoadItemTexts() -{ - QueryResult* result = CharacterDatabase.Query("SELECT `id`, `text` FROM `item_text`"); - - uint32 count = 0; - - if (!result) - { - BarGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u item pages", count); - return; - } - - BarGoLink bar(result->GetRowCount()); - - Field* fields; - do - { - bar.step(); - - fields = result->Fetch(); - - mItemTexts[ fields[0].GetUInt32()] = fields[1].GetCppString(); - - ++count; - } - while (result->NextRow()); - - delete result; - - sLog.outString(">> Loaded %u item texts", count); - sLog.outString(); -} - void ObjectMgr::LoadPageTexts() { sPageTextStore.Load(); @@ -5108,10 +5070,10 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) // delete all old mails without item and without body immediately, if starting server if (!serverUp) { - CharacterDatabase.PExecute("DELETE FROM `mail` WHERE `expire_time` < '" UI64FMTD "' AND `has_items` = '0' AND `itemTextId` = 0", (uint64)basetime); + CharacterDatabase.PExecute("DELETE FROM `mail` WHERE `expire_time` < '" UI64FMTD "' AND `has_items` = '0' AND `body` = ''", (uint64)basetime); } // 0 1 2 3 4 5 6 7 8 9 - QueryResult* result = CharacterDatabase.PQuery("SELECT `id`,`messageType`,`sender`,`receiver`,`itemTextId`,`has_items`,`expire_time`,`cod`,`checked`,`mailTemplateId` FROM `mail` WHERE `expire_time` < '" UI64FMTD "'", (uint64)basetime); + QueryResult* result = CharacterDatabase.PQuery("SELECT `id`,`messageType`,`sender`,`receiver`,`has_items`,`expire_time`,`cod`,`checked`,`mailTemplateId` FROM `mail` WHERE `expire_time` < '" UI64FMTD "'", (uint64)basetime); if (!result) { BarGoLink bar(1); @@ -5140,12 +5102,12 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) m->messageType = fields[1].GetUInt8(); m->sender = fields[2].GetUInt32(); m->receiverGuid = ObjectGuid(HIGHGUID_PLAYER, fields[3].GetUInt32()); - bool has_items = fields[5].GetBool(); - m->expire_time = (time_t)fields[6].GetUInt64(); + bool has_items = fields[4].GetBool(); + m->expire_time = (time_t)fields[5].GetUInt64(); m->deliver_time = 0; - m->COD = fields[7].GetUInt32(); - m->checked = fields[8].GetUInt32(); - m->mailTemplateId = fields[9].GetInt16(); + m->COD = fields[6].GetUInt32(); + m->checked = fields[7].GetUInt32(); + m->mailTemplateId = fields[8].GetInt16(); Player* pl = 0; if (serverUp) @@ -5203,11 +5165,6 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp) } } - if (m->itemTextId) - { - CharacterDatabase.PExecute("DELETE FROM `item_text` WHERE `id` = '%u'", m->itemTextId); - } - // deletemail = true; // delmails << m->messageID << ", "; CharacterDatabase.PExecute("DELETE FROM `mail` WHERE `id` = '%u'", m->messageID); @@ -5999,13 +5956,6 @@ void ObjectMgr::SetHighestGuids() delete result; } - result = CharacterDatabase.Query("SELECT MAX(`id`) FROM `item_text`"); - if (result) - { - m_ItemTextGuids.Set((*result)[0].GetUInt32() + 1); - delete result; - } - // Cleanup other tables from nonexistent guids (>=m_hiItemGuid) CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM `character_inventory` WHERE `item` >= '%u'", m_ItemGuids.GetNextAfterMaxUsed()); @@ -6035,13 +5985,6 @@ void ObjectMgr::SetHighestGuids() delete result; } - result = CharacterDatabase.Query("SELECT MAX(`id`) FROM `item_text`"); - if (result) - { - m_ItemTextIds.Set((*result)[0].GetUInt32() + 1); - delete result; - } - result = CharacterDatabase.Query("SELECT MAX(`guid`) FROM `corpse`"); if (result) { @@ -6078,20 +6021,6 @@ void ObjectMgr::SetHighestGuids() m_FirstTemporaryGameObjectGuid += sWorld.getConfig(CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT); } -uint32 ObjectMgr::CreateItemText(std::string text) -{ - uint32 newItemTextId = GenerateItemTextID(); - // insert new itempage to container - mItemTexts[ newItemTextId ] = text; - // save new itempage - CharacterDatabase.escape_string(text); - // any Delete query needed, itemTextId is maximum of all ids - std::ostringstream query; - query << "INSERT INTO `item_text` (`id`,`text`) VALUES ( '" << newItemTextId << "', '" << text << "')"; - CharacterDatabase.Execute(query.str().c_str()); // needs to be run this way, because mail body may be more than 1024 characters - return newItemTextId; -} - void ObjectMgr::LoadGameObjectLocales() { mGameObjectLocaleMap.clear(); // need for reload case diff --git a/src/game/Object/ObjectMgr.h b/src/game/Object/ObjectMgr.h index 215ade7fc..6ef5da840 100644 --- a/src/game/Object/ObjectMgr.h +++ b/src/game/Object/ObjectMgr.h @@ -460,8 +460,6 @@ class ObjectMgr ObjectMgr(); ~ObjectMgr(); - typedef UNORDERED_MAP ItemMap; - typedef UNORDERED_MAP GroupMap; typedef UNORDERED_MAP ArenaTeamMap; @@ -704,7 +702,6 @@ class ObjectMgr void LoadTavernAreaTriggers(); void LoadGameObjectForQuests(); - void LoadItemTexts(); void LoadPageTexts(); void LoadPlayerInfo(); @@ -811,10 +808,6 @@ class ObjectMgr { return m_GuildIds.Generate(); } - uint32 GenerateItemTextID() - { - return m_ItemTextGuids.Generate(); - } uint32 GenerateMailID() { return m_MailIds.Generate(); @@ -823,18 +816,14 @@ class ObjectMgr { return m_PetNumbers.Generate(); } - - uint32 CreateItemText(std::string text); - void AddItemText(uint32 itemTextId, std::string text) - { - mItemTexts[itemTextId] = text; - } std::string GetItemText(uint32 id) { - ItemTextMap::const_iterator itr = mItemTexts.find(id); - if (itr != mItemTexts.end()) + if (QueryResult* result = CharacterDatabase.PQuery("SELECT `body` FROM `mail` WHERE `id` = '%u'", id)) { - return itr->second; + Field* fields = result->Fetch(); + std::string body = fields[0].GetCppString(); + delete result; + return body; } else { @@ -1221,7 +1210,6 @@ class ObjectMgr IdGenerator m_ArenaTeamIds; IdGenerator m_AuctionIds; IdGenerator m_GuildIds; - IdGenerator m_ItemTextIds; IdGenerator m_MailIds; IdGenerator m_PetNumbers; @@ -1236,7 +1224,6 @@ class ObjectMgr // first free low guid for selected guid type ObjectGuidGenerator m_CharGuids; ObjectGuidGenerator m_ItemGuids; - ObjectGuidGenerator m_ItemTextGuids; ObjectGuidGenerator m_CorpseGuids; ObjectGuidGenerator m_GroupGuids; @@ -1244,7 +1231,6 @@ class ObjectMgr typedef UNORDERED_MAP GossipTextMap; typedef UNORDERED_MAP QuestAreaTriggerMap; - typedef UNORDERED_MAP ItemTextMap; typedef std::set TavernAreaTriggerSet; typedef std::set GameObjectForQuestSet; @@ -1254,8 +1240,6 @@ class ObjectMgr GroupMap mGroupMap; ArenaTeamMap mArenaTeamMap; - ItemTextMap mItemTexts; - QuestAreaTriggerMap mQuestAreaTriggerMap; TavernAreaTriggerSet mTavernAreaTriggerSet; GameObjectForQuestSet mGameObjectForQuestSet; diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index 14be2f41e..c955852da 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -4568,8 +4568,8 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe // completely remove from the database case 0: { - // return back all mails with COD and Item 0 1 2 3 4 5 6 7 - QueryResult* resultMail = CharacterDatabase.PQuery("SELECT `id`,`messageType`,`mailTemplateId`,`sender`,`subject`,`itemTextId`,`money`,`has_items` FROM `mail` WHERE `receiver`='%u' AND `has_items`<>0 AND `cod`<>0", lowguid); + // return back all mails with COD and Item 0 1 2 3 4 5 6 7 + QueryResult* resultMail = CharacterDatabase.PQuery("SELECT `id`,`messageType`,`mailTemplateId`,`sender`,`subject`,`body`,`money`,`has_items` FROM `mail` WHERE `receiver`='%u' AND `has_items`<>0 AND `cod`<>0", lowguid); if (resultMail) { do @@ -4581,7 +4581,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe uint16 mailTemplateId = fields[2].GetUInt16(); uint32 sender = fields[3].GetUInt32(); std::string subject = fields[4].GetCppString(); - uint32 itemTextId = fields[5].GetUInt32(); + std::string body = fields[5].GetCppString(); uint32 money = fields[6].GetUInt32(); bool has_items = fields[7].GetBool(); @@ -4599,29 +4599,29 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe continue; } - MailDraft draft; + MailDraft draft(subject, body); if (mailTemplateId) { draft.SetMailTemplate(mailTemplateId, false); // items already included } else { - draft.SetSubjectAndBodyId(subject, itemTextId); + draft.SetSubjectAndBody(subject, body); } if (has_items) { // data needs to be at first place for Item::LoadFromDB - // 0 1 2 - QueryResult* resultItems = CharacterDatabase.PQuery("SELECT `data`,`item_guid`,`item_template` FROM `mail_items` JOIN `item_instance` ON `item_guid` = `guid` WHERE `mail_id`='%u'", mail_id); + // 0 1 2 3 + QueryResult* resultItems = CharacterDatabase.PQuery("SELECT `data`,`text`,`item_guid`,`item_template` FROM `mail_items` JOIN `item_instance` ON `item_guid` = `guid` WHERE `mail_id`='%u'", mail_id); if (resultItems) { do { Field* fields2 = resultItems->Fetch(); - uint32 item_guidlow = fields2[1].GetUInt32(); - uint32 item_template = fields2[2].GetUInt32(); + uint32 item_guidlow = fields2[2].GetUInt32(); + uint32 item_template = fields2[3].GetUInt32(); ItemPrototype const* itemProto = ObjectMgr::GetItemPrototype(item_template); if (!itemProto) @@ -12774,7 +12774,6 @@ uint32 Player::DestroyItemCount(uint32 item, uint32 count, bool update, bool une { remcount += pItem->GetCount(); DestroyItem(INVENTORY_SLOT_BAG_0, i, update); - if (remcount >= count) { return remcount; @@ -14715,7 +14714,6 @@ void Player::PrepareQuestMenu(ObjectGuid guid) void Player::SendPreparedQuest(ObjectGuid guid) { QuestMenu& questMenu = PlayerTalkClass->GetQuestMenu(); - if (questMenu.Empty()) { return; @@ -18129,7 +18127,7 @@ void Player::_LoadInventory(QueryResult* result, uint32 timediff) std::string subject = "Item could not be loaded to inventory."; std::string content = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); // fill mail - MailDraft draft(subject); + MailDraft draft(subject,""); draft.SetSubjectAndBody(subject,content); for (int i = 0; !problematicItems.empty() && i < MAX_MAIL_ITEMS; ++i) { @@ -18179,8 +18177,8 @@ void Player::_LoadItemLoot(QueryResult* result) void Player::_LoadMailedItems(QueryResult* result) { // data needs to be at first place for Item::LoadFromDB - // 0 1 2 3 - // "SELECT data, mail_id, item_guid, item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE receiver = '%u'", GUID_LOPART(m_guid) + // 0 1 2 3 4 + // "SELECT data, text, mail_id, item_guid, item_template FROM mail_items JOIN item_instance ON item_guid = guid WHERE receiver = '%u'", GUID_LOPART(m_guid) if (!result) { return; @@ -18231,8 +18229,8 @@ void Player::_LoadMailedItems(QueryResult* result) void Player::_LoadMails(QueryResult* result) { m_mail.clear(); - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 - //"SELECT id,messageType,sender,receiver,subject,itemTextId,expire_time,deliver_time,money,cod,checked,stationery,mailTemplateId,has_items FROM mail WHERE receiver = '%u' ORDER BY id DESC",GetGUIDLow() + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + //"SELECT id,messageType,sender,receiver,subject,body,expire_time,deliver_time,money,cod,checked,stationery,mailTemplateId,has_items FROM mail WHERE receiver = '%u' ORDER BY id DESC", GetGUIDLow() if (!result) { return; @@ -18247,7 +18245,7 @@ void Player::_LoadMails(QueryResult* result) m->sender = fields[2].GetUInt32(); m->receiverGuid = ObjectGuid(HIGHGUID_PLAYER, fields[3].GetUInt32()); m->subject = fields[4].GetCppString(); - m->itemTextId = fields[5].GetUInt32(); + m->body = fields[5].GetCppString(); m->expire_time = (time_t)fields[6].GetUInt64(); m->deliver_time = (time_t)fields[7].GetUInt64(); m->money = fields[8].GetUInt32(); @@ -19375,7 +19373,6 @@ void Player::_SaveMail() static SqlStatementID deleteMailItems ; static SqlStatementID deleteItem ; - static SqlStatementID deleteItemText; static SqlStatementID deleteMail ; static SqlStatementID deleteItems ; @@ -19384,8 +19381,8 @@ void Player::_SaveMail() Mail* m = (*itr); if (m->state == MAIL_STATE_CHANGED) { - SqlStatement stmt = CharacterDatabase.CreateStatement(updateMail, "UPDATE `mail` SET `itemTextId` = ?,`has_items` = ?, `expire_time` = ?, `deliver_time` = ?, `money` = ?, `cod` = ?, `checked` = ? WHERE `id` = ?"); - stmt.addUInt32(m->itemTextId); + SqlStatement stmt = CharacterDatabase.CreateStatement(updateMail, "UPDATE `mail` SET `body` = ?,`has_items` = ?, `expire_time` = ?, `deliver_time` = ?, `money` = ?, `cod` = ?, `checked` = ? WHERE `id` = ?"); + stmt.addString(m->body); stmt.addUInt32(m->HasItems() ? 1 : 0); stmt.addUInt64(uint64(m->expire_time)); stmt.addUInt64(uint64(m->deliver_time)); @@ -19419,12 +19416,6 @@ void Player::_SaveMail() } } - if (m->itemTextId) - { - SqlStatement stmt = CharacterDatabase.CreateStatement(deleteItemText, "DELETE FROM `item_text` WHERE `id` = ?"); - stmt.PExecute(m->itemTextId); - } - SqlStatement stmt = CharacterDatabase.CreateStatement(deleteMail, "DELETE FROM `mail` WHERE `id` = ?"); stmt.PExecute(m->messageID); @@ -20952,6 +20943,7 @@ void Player::InitDataForForm(bool reapplyMods) { SetPowerType(Powers(cEntry->powerType)); } + break; } } @@ -22834,7 +22826,7 @@ void Player::AutoUnequipOffhandIfNeed() CharacterDatabase.CommitTransaction(); std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); - MailDraft(subject).AddItem(offItem).SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED); + MailDraft(subject, "There's were problems with equipping this item.").AddItem(offItem).SendMailTo(this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED); } } diff --git a/src/game/Tools/PlayerDump.cpp b/src/game/Tools/PlayerDump.cpp index eece80d32..645cbb8a0 100644 --- a/src/game/Tools/PlayerDump.cpp +++ b/src/game/Tools/PlayerDump.cpp @@ -64,7 +64,6 @@ static DumpTable dumpTables[] = { "character_gifts", DTT_ITEM_GIFT }, // <- item guids { "item_instance", DTT_ITEM }, // <- item guids { "item_loot", DTT_ITEM_LOOT }, // <- item guids - { "item_text", DTT_ITEM_TEXT }, { NULL, DTT_CHAR_TABLE }, // end marker }; @@ -346,7 +345,6 @@ void PlayerDumpWriter::DumpTableContent(std::string& dump, uint32 guid, char con case DTT_PET_DECL: fieldname = "id"; break; case DTT_MAIL: fieldname = "receiver"; break; case DTT_MAIL_ITEM: fieldname = "mail_id"; guids = &mails; break; - case DTT_ITEM_TEXT: fieldname = "id"; guids = &texts; break; default: fieldname = "guid"; break; } @@ -408,14 +406,10 @@ void PlayerDumpWriter::DumpTableContent(std::string& dump, uint32 guid, char con { case DTT_INVENTORY: StoreGUID(result, 3, items); break; // item guid collection - case DTT_ITEM: - StoreGUID(result, 0, ITEM_FIELD_ITEM_TEXT_ID, texts); break; - // item text id collection case DTT_PET: StoreGUID(result, 0, pets); break; // pet petnumber collection (character_pet.id) case DTT_MAIL: StoreGUID(result, 0, mails); // mail id collection (mail.id) - StoreGUID(result, 7, texts); break; // item text id collection case DTT_MAIL_ITEM: StoreGUID(result, 1, items); break; // item guid collection (mail_items.item_guid) default: break; @@ -754,10 +748,6 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s { ROLLBACK(DUMP_FILE_BROKEN); // item_instance.data.ITEM_FIELD_OWNER update } - if (!changetokGuid(vals, ITEM_FIELD_ITEM_TEXT_ID + 1, itemTexts, sObjectMgr.m_ItemTextIds.GetNextAfterMaxUsed(), true)) - { - ROLLBACK(DUMP_FILE_BROKEN); - } if (!changenth(line, 3, vals.c_str())) // item_instance.data update { ROLLBACK(DUMP_FILE_BROKEN); @@ -877,10 +867,6 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s { ROLLBACK(DUMP_FILE_BROKEN); } - if (!changeGuid(line, 8, itemTexts, sObjectMgr.m_ItemTextIds.GetNextAfterMaxUsed())) - { - ROLLBACK(DUMP_FILE_BROKEN); - } break; } case DTT_MAIL_ITEM: // mail_items @@ -899,20 +885,6 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s } break; } - case DTT_ITEM_TEXT: // item_text - { - // id - if (!changeGuid(line, 1, itemTexts, sObjectMgr.m_ItemTextIds.GetNextAfterMaxUsed())) - { - ROLLBACK(DUMP_FILE_BROKEN); - } - - // add it to cache - uint32 id = atoi(getnth(line, 1).c_str()); - std::string text = getnth(line, 2); - sObjectMgr.AddItemText(id, text); - break; - } default: sLog.outError("Unknown dump table type: %u", type); break; @@ -928,9 +900,7 @@ DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, s // FIXME: current code with post-updating guids not safe for future per-map threads sObjectMgr.m_ItemGuids.Set(sObjectMgr.m_ItemGuids.GetNextAfterMaxUsed() + items.size()); - sObjectMgr.m_ItemTextGuids.Set(sObjectMgr.m_ItemTextGuids.GetNextAfterMaxUsed() + itemTexts.size()); sObjectMgr.m_MailIds.Set(sObjectMgr.m_MailIds.GetNextAfterMaxUsed() + mails.size()); - sObjectMgr.m_ItemTextIds.Set(sObjectMgr.m_ItemTextIds.GetNextAfterMaxUsed() + itemTexts.size()); if (incHighest) { diff --git a/src/game/Tools/PlayerDump.h b/src/game/Tools/PlayerDump.h index 0e61a3cfe..612b2542b 100644 --- a/src/game/Tools/PlayerDump.h +++ b/src/game/Tools/PlayerDump.h @@ -55,7 +55,6 @@ enum DumpTableType DTT_PET, // -> pet guids collection // character_pet DTT_PET_TABLE, // <- pet guids // pet_aura, pet_spell, pet_spell_cooldown - DTT_ITEM_TEXT, // <- item_text // item_text DTT_PET_DECL, // <- pet guids // character_pet_declinedname }; @@ -92,7 +91,6 @@ class PlayerDumpWriter : public PlayerDump GUIDs pets; GUIDs mails; GUIDs items; - GUIDs texts; }; class PlayerDumpReader : public PlayerDump diff --git a/src/game/WorldHandlers/AccountMgr.cpp b/src/game/WorldHandlers/AccountMgr.cpp index 77c08d687..169a7844c 100644 --- a/src/game/WorldHandlers/AccountMgr.cpp +++ b/src/game/WorldHandlers/AccountMgr.cpp @@ -73,7 +73,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass if (GetId(username)) { { - return AOR_NAME_ALREADY_EXIST; // username does already exist + return AOR_NAME_ALREADY_EXIST; // username does already exist } } @@ -83,7 +83,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass } LoginDatabase.Execute("INSERT INTO `realmcharacters` (`realmid`, `acctid`, `numchars`) SELECT `realmlist`.`id`, `account`.`id`, 0 FROM `realmlist`,`account` LEFT JOIN `realmcharacters` ON `acctid`=`account`.`id` WHERE `acctid` IS NULL"); - return AOR_OK; // everything's fine + return AOR_OK; // everything's fine } /** diff --git a/src/game/WorldHandlers/AuctionHouseHandler.cpp b/src/game/WorldHandlers/AuctionHouseHandler.cpp index bcd7e876f..fba0c9f3f 100644 --- a/src/game/WorldHandlers/AuctionHouseHandler.cpp +++ b/src/game/WorldHandlers/AuctionHouseHandler.cpp @@ -185,7 +185,7 @@ void WorldSession::SendAuctionOutbiddedMail(AuctionEntry* auction) oldBidder->GetSession()->SendAuctionBidderNotification(auction, false); } - MailDraft(msgAuctionOutbiddedSubject.str()) + MailDraft(msgAuctionOutbiddedSubject.str(),"") .SetMoney(auction->bid) .SendMailTo(MailReceiver(oldBidder, oldBidder_guid), auction, MAIL_CHECK_MASK_COPIED); } @@ -214,7 +214,7 @@ void WorldSession::SendAuctionCancelledToBidderMail(AuctionEntry* auction) bidder->GetSession()->SendAuctionRemovedNotification(auction); } - MailDraft(msgAuctionCancelledSubject.str()) + MailDraft(msgAuctionCancelledSubject.str(),"") .SetMoney(auction->bid) .SendMailTo(MailReceiver(bidder, bidder_guid), auction, MAIL_CHECK_MASK_COPIED); } @@ -517,7 +517,7 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket& recv_data) msgAuctionCanceledOwner << auction->itemTemplate << ":" << auction->itemRandomPropertyId << ":" << AUCTION_CANCELED; // item will deleted or added to received mail list - MailDraft(msgAuctionCanceledOwner.str()) + MailDraft(msgAuctionCanceledOwner.str(),"") .AddItem(pItem) .SendMailTo(pl, auction, MAIL_CHECK_MASK_COPIED); diff --git a/src/game/WorldHandlers/CharacterHandler.cpp b/src/game/WorldHandlers/CharacterHandler.cpp index 453172c2c..33a4fdf31 100644 --- a/src/game/WorldHandlers/CharacterHandler.cpp +++ b/src/game/WorldHandlers/CharacterHandler.cpp @@ -129,7 +129,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT `arenateamid`, `played_week`, `played_season`, `personal_rating` FROM `arena_team_member` WHERE `guid`='%u'", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, "SELECT `instance_id`, `team`, `join_x`, `join_y`, `join_z`, `join_o`, `join_map` FROM `character_battleground_data` WHERE `guid` = '%u'", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT `skill`, `value`, `max` FROM `character_skills` WHERE `guid` = '%u'", m_guid.GetCounter()); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILS, "SELECT `id`,`messageType`,`sender`,`receiver`,`subject`,`itemTextId`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`,`stationery`,`mailTemplateId`,`has_items` FROM `mail` WHERE `receiver` = '%u' ORDER BY `id` DESC", m_guid.GetCounter()); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILS, "SELECT `id`,`messageType`,`sender`,`receiver`,`subject`,`body`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`,`stationery`,`mailTemplateId`,`has_items` FROM `mail` WHERE `receiver` = '%u' ORDER BY `id` DESC", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILEDITEMS, "SELECT `data`, `mail_id`, `item_guid`, `item_template` FROM `mail_items` JOIN `item_instance` ON `item_guid` = `guid` WHERE `receiver` = '%u'", m_guid.GetCounter()); return res; diff --git a/src/game/WorldHandlers/Mail.cpp b/src/game/WorldHandlers/Mail.cpp index 9c9978d85..ef35ca033 100644 --- a/src/game/WorldHandlers/Mail.cpp +++ b/src/game/WorldHandlers/Mail.cpp @@ -107,27 +107,6 @@ MailReceiver::MailReceiver(Player* receiver, ObjectGuid receiver_guid) : m_recei MANGOS_ASSERT(!receiver || receiver->GetObjectGuid() == receiver_guid); } -/** - * Creates a new MailDraft object using subject and contect texts. - * - * @param subject The subject of the mail. - * @param itemText The text of the body of the mail. - */ -MailDraft::MailDraft(std::string subject, std::string text) : m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_subject(subject), - m_bodyId(!text.empty() ? sObjectMgr.CreateItemText(text) : 0), m_money(0), m_COD(0) -{ -} - -MailDraft& MailDraft::SetSubjectAndBody(std::string subject, std::string text) -{ - m_subject = subject; - - MANGOS_ASSERT(!m_bodyId); - m_bodyId = !text.empty() ? sObjectMgr.CreateItemText(text) : 0; - - return *this; -} - /** * Adds an item to the MailDraft. * @@ -203,14 +182,7 @@ void MailDraft::CloneFrom(MailDraft const& draft) m_mailTemplateItemsNeed = draft.m_mailTemplateItemsNeed; m_subject = draft.GetSubject(); - - MANGOS_ASSERT(!m_bodyId); - if (uint32 bodyId = draft.GetBodyId()) - { - std::string text = sObjectMgr.GetItemText(bodyId); - m_bodyId = sObjectMgr.CreateItemText(text); - } - + m_body = draft.GetBody(); m_money = draft.GetMoney(); m_COD = draft.GetCOD(); @@ -344,12 +316,15 @@ void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sende // Add to DB std::string safe_subject = GetSubject(); + CharacterDatabase.escape_string(safe_subject); + + std::string safe_body = GetBody(); + CharacterDatabase.escape_string(safe_body); CharacterDatabase.BeginTransaction(); - CharacterDatabase.escape_string(safe_subject); - CharacterDatabase.PExecute("INSERT INTO `mail` (`id`,`messageType`,`stationery`,`mailTemplateId`,`sender`,`receiver`,`subject`,`itemTextId`,`has_items`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`) " - "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%u', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%u')", - mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGuid().GetCounter(), safe_subject.c_str(), GetBodyId(), (has_items ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked); + CharacterDatabase.PExecute("INSERT INTO `mail` (`id`,`messageType`,`stationery`,`mailTemplateId`,`sender`,`receiver`,`subject`,`body`,`has_items`,`expire_time`,`deliver_time`,`money`,`cod`,`checked`) " + "VALUES ('%u', '%u', '%u', '%u', '%u', '%u', '%s', '%s', '%u', '" UI64FMTD "','" UI64FMTD "', '%u', '%u', '%u')", + mailId, sender.GetMailMessageType(), sender.GetStationery(), GetMailTemplateId(), sender.GetSenderId(), receiver.GetPlayerGuid().GetCounter(), safe_subject.c_str(), safe_body.c_str(), (has_items ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, m_money, m_COD, checked); for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter) { @@ -368,7 +343,7 @@ void MailDraft::SendMailTo(MailReceiver const& receiver, MailSender const& sende m->messageID = mailId; m->mailTemplateId = GetMailTemplateId(); m->subject = GetSubject(); - m->itemTextId = GetBodyId(); + m->body = GetBody(); m->money = GetMoney(); m->COD = GetCOD(); diff --git a/src/game/WorldHandlers/Mail.h b/src/game/WorldHandlers/Mail.h index 9529ac054..61e6f78ed 100644 --- a/src/game/WorldHandlers/Mail.h +++ b/src/game/WorldHandlers/Mail.h @@ -195,7 +195,7 @@ class MailDraft * */ MailDraft() - : m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_bodyId(0), m_money(0), m_COD(0) {} + : m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_money(0), m_COD(0) {} /** * Creates a new MailDraft object using mail template id. * @@ -204,39 +204,31 @@ class MailDraft * */ explicit MailDraft(uint16 mailTemplateId, bool need_items = true) - : m_mailTemplateId(mailTemplateId), m_mailTemplateItemsNeed(need_items), m_bodyId(0), m_money(0), m_COD(0) + : m_mailTemplateId(mailTemplateId), m_mailTemplateItemsNeed(need_items), m_money(0), m_COD(0) {} - /** - * Creates a new MailDraft object using subject text and content text id. - * - * @param subject The subject of the mail. - * @param itemTextId The id of the body of the mail. - */ - MailDraft(std::string subject, uint32 itemTextId = 0) - : m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_subject(subject), m_bodyId(itemTextId), m_money(0), m_COD(0) {} /** * Creates a new MailDraft object using subject and content texts. * * @param subject The subject of the mail. * @param itemText The text of the body of the mail. */ - MailDraft(std::string subject, std::string text); + MailDraft(std::string subject, std::string body) + : m_mailTemplateId(0), m_mailTemplateItemsNeed(false), m_subject(subject), m_body(body), m_money(0), m_COD(0) {} public: // Accessors /// Returns the template ID used for this MailDraft. uint16 GetMailTemplateId() const { return m_mailTemplateId; } /// Returns the subject of this MailDraft. std::string const& GetSubject() const { return m_subject; } - /// Returns the ID of the text of this MailDraft. - uint32 GetBodyId() const { return m_bodyId; } + /// Returns the subject of this MailDraft. + std::string const& GetBody() const { return m_body; } /// Returns the amount of money in this MailDraft. uint32 GetMoney() const { return m_money; } /// Returns the Cost of delivery of this MailDraft. uint32 GetCOD() const { return m_COD; } public: // modifiers - // this two modifiers expected to be applied in normal case to blank draft and exclusively, It DON'T must overwrite already set itemTextId, in other cases it will work and with mixed cases but this will be not normal way use. - MailDraft& SetSubjectAndBodyId(std::string subject, uint32 itemTextId) { m_subject = subject; MANGOS_ASSERT(!m_bodyId); m_bodyId = itemTextId; return *this; } - MailDraft& SetSubjectAndBody(std::string subject, std::string text); + // this two modifiers expected to be applied in normal case to blank draft and exclusively, it will work and with mixed cases but this will be not normal way use. + MailDraft& SetSubjectAndBody(std::string subject, std::string body) { m_subject = subject; m_body = body; return *this; } MailDraft& SetMailTemplate(uint16 mailTemplateId, bool need_items = true) { m_mailTemplateId = mailTemplateId, m_mailTemplateItemsNeed = need_items; return *this; } MailDraft& AddItem(Item* item); @@ -270,8 +262,8 @@ class MailDraft bool m_mailTemplateItemsNeed; /// The subject of the MailDraft. std::string m_subject; - /// The ID of the body of the MailDraft. - uint32 m_bodyId; + /// The body of the MailDraft. + std::string m_body; /// A map of items in this MailDraft. MailItemMap m_items; ///< Keep the items in a map to avoid duplicate guids (which can happen), store only low part of guid @@ -309,8 +301,8 @@ struct Mail ObjectGuid receiverGuid; /// the subject of the mail std::string subject; - /// The ID of the itemtext. - uint32 itemTextId; + /// the body of the mail + std::string body; /// flag mark mail that already has items, or already generate none items for template bool has_items; /// A vector containing Information about the items in this mail. diff --git a/src/game/WorldHandlers/MailHandler.cpp b/src/game/WorldHandlers/MailHandler.cpp index 2f3984774..8b2e60018 100644 --- a/src/game/WorldHandlers/MailHandler.cpp +++ b/src/game/WorldHandlers/MailHandler.cpp @@ -46,9 +46,27 @@ bool WorldSession::CheckMailBox(ObjectGuid guid) { - if (!GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_MAILBOX)) + // GM case + if (guid == GetPlayer()->GetObjectGuid()) + { + // command case will return only if player have real access to command + if (!ChatHandler(GetPlayer()).FindCommand("mailbox")) + { + DEBUG_LOG("%s attempt open mailbox in cheating way.", guid.GetString().c_str()); + return false; + } + } + // mailbox case + else if (guid.IsGameObject()) + { + if (!GetPlayer()->GetGameObjectIfCanInteractWith(guid, GAMEOBJECT_TYPE_MAILBOX)) + { + DEBUG_LOG("Mailbox %s not found or %s can't interact with him.", guid.GetString().c_str(), GetPlayer()->GetGuidStr().c_str()); + return false; + } + } + else { - DEBUG_LOG("Mailbox %s not found or you can't interact with him.", guid.GetString().c_str()); return false; } @@ -434,7 +452,7 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recv_data) } else { - draft.SetSubjectAndBodyId(m->subject, m->itemTextId); + draft.SetSubjectAndBody(m->subject, m->body); } if (m->HasItems()) @@ -535,7 +553,7 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recv_data) // check player existence if (sender || sender_accId) { - MailDraft(m->subject) + MailDraft(m->subject, "") .SetMoney(m->COD) .SendMailTo(MailReceiver(sender, sender_guid), _player, MAIL_CHECK_MASK_COD_PAYMENT); } @@ -666,7 +684,7 @@ void WorldSession::HandleGetMailList(WorldPacket& recv_data) } data << uint32((*itr)->COD); // COD - data << uint32((*itr)->itemTextId); // item text + data << uint32((*itr)->messageID); // Use the MessageID to look up the Body later data << uint32(0); // unknown data << uint32((*itr)->stationery); // stationery (Stationery.dbc) data << uint32((*itr)->money); // copper @@ -727,19 +745,19 @@ void WorldSession::HandleGetMailList(WorldPacket& recv_data) */ void WorldSession::HandleItemTextQuery(WorldPacket& recv_data) { - uint32 itemTextId; + uint32 itemId; uint32 mailId; // this value can be item id in bag, but it is also mail id uint32 unk; // maybe something like state - 0x70000000 - recv_data >> itemTextId >> mailId >> unk; + recv_data >> itemId >> mailId >> unk; /// TODO: some check needed, if player has item with guid mailId, or has mail with id mailId - DEBUG_LOG("CMSG_ITEM_TEXT_QUERY itemguid: %u, mailId: %u, unk: %u", itemTextId, mailId, unk); + DEBUG_LOG("CMSG_ITEM_TEXT_QUERY itemguid: %u, mailId: %u, unk: %u", itemId, mailId, unk); WorldPacket data(SMSG_ITEM_TEXT_QUERY_RESPONSE, (4 + 10)); // guess size - data << itemTextId; - data << sObjectMgr.GetItemText(itemTextId); + data << itemId; + data << sObjectMgr.GetItemText(itemId); // CString TODO: max length 8000 SendPacket(&data); } @@ -767,27 +785,12 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recv_data) Player* pl = _player; Mail* m = pl->GetMail(mailId); - if (!m || (!m->itemTextId && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) { pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } - uint32 itemTextId = m->itemTextId; - - // in mail template case we need create new item text - if (!itemTextId) - { - MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); - if (!mailTemplateEntry) - { - pl->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); - return; - } - - itemTextId = sObjectMgr.CreateItemText(mailTemplateEntry->content[GetSessionDbcLocale()]); - } - Item* bodyItem = new Item; // This is not bag and then can be used new Item. if (!bodyItem->Create(sObjectMgr.GenerateItemLowGuid(), MAIL_BODY_ITEM_TEMPLATE, pl)) { @@ -795,7 +798,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recv_data) return; } - bodyItem->SetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID, itemTextId); + bodyItem->SetUInt32Value(ITEM_FIELD_ITEM_TEXT_ID, mailId); bodyItem->SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid(HIGHGUID_PLAYER, m->sender)); DETAIL_LOG("HandleMailCreateTextItem mailid=%u", mailId); diff --git a/src/game/WorldHandlers/World.cpp b/src/game/WorldHandlers/World.cpp index ce183b1c2..da38eae57 100644 --- a/src/game/WorldHandlers/World.cpp +++ b/src/game/WorldHandlers/World.cpp @@ -1129,9 +1129,6 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Item Templates..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts sObjectMgr.LoadItemPrototypes(); - sLog.outString("Loading Item Texts..."); - sObjectMgr.LoadItemTexts(); - sLog.outString("Loading Creature Model Based Info Data..."); sObjectMgr.LoadCreatureModelInfo(); diff --git a/src/modules/Bots/playerbot/strategy/actions/MailAction.cpp b/src/modules/Bots/playerbot/strategy/actions/MailAction.cpp index 81ae6cf0f..ec224e2d9 100644 --- a/src/modules/Bots/playerbot/strategy/actions/MailAction.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/MailAction.cpp @@ -158,9 +158,9 @@ class ReadMailProcessor : public MailProcessor ostringstream out, body; out << "|cffffffff" << mail->subject; ai->TellMaster(out.str()); - if (mail->itemTextId) + if (mail->messageID) { - body << "\n" << sObjectMgr.GetItemText(mail->itemTextId); + body << "\n" << sObjectMgr.GetItemText(mail->messageID); ai->TellMaster(body.str()); } return true; diff --git a/src/shared/revision_data.h.in b/src/shared/revision_data.h.in index b69e60604..e1d9f138b 100644 --- a/src/shared/revision_data.h.in +++ b/src/shared/revision_data.h.in @@ -39,9 +39,9 @@ #define REALMD_DB_UPDATE_DESCRIPT "Release 22" #define CHAR_DB_VERSION_NR "22" - #define CHAR_DB_STRUCTURE_NR "5" + #define CHAR_DB_STRUCTURE_NR "6" #define CHAR_DB_CONTENT_NR "1" - #define CHAR_DB_UPDATE_DESCRIPT "fix_ai_playerbot_names_table" + #define CHAR_DB_UPDATE_DESCRIPT "remove_item_text" #define WORLD_DB_VERSION_NR "22" #define WORLD_DB_STRUCTURE_NR "3"