diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index efcec8b1f..a59dc70d9 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -1713,7 +1713,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted // item - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + mi.AddItem(item); } int loc_idx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex(); diff --git a/src/game/AuctionHouseHandler.cpp b/src/game/AuctionHouseHandler.cpp index 605b10e8e..91db220a2 100644 --- a/src/game/AuctionHouseHandler.cpp +++ b/src/game/AuctionHouseHandler.cpp @@ -444,7 +444,7 @@ void WorldSession::HandleAuctionRemoveItem( WorldPacket & recv_data ) msgAuctionCanceledOwner << auction->item_template << ":0:" << AUCTION_CANCELED; MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + mi.AddItem(pItem); // item will deleted or added to received mail list WorldSession::SendMailTo(pl, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->GetHouseId(), pl->GetGUIDLow(), msgAuctionCanceledOwner.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); diff --git a/src/game/AuctionHouseMgr.cpp b/src/game/AuctionHouseMgr.cpp index 15dbc47fd..fd26f2a7e 100644 --- a/src/game/AuctionHouseMgr.cpp +++ b/src/game/AuctionHouseMgr.cpp @@ -142,7 +142,7 @@ void AuctionHouseMgr::SendAuctionWonMail( AuctionEntry *auction ) CharacterDatabase.CommitTransaction(); MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + mi.AddItem(pItem); if (bidder) bidder->GetSession()->SendAuctionBidderNotification( auction->GetHouseId(), auction->Id, bidder_guid, 0, 0, auction->item_template); @@ -262,7 +262,7 @@ void AuctionHouseMgr::SendAuctionExpiredMail( AuctionEntry * auction ) RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! MailItemsInfo mi; - mi.AddItem(auction->item_guidlow, auction->item_template, pItem); + mi.AddItem(pItem); // will delete item or place to receiver mail list WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->GetHouseId(), GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE); diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 13d922800..385bca466 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -935,7 +935,7 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count) // item MailItemsInfo mi; - mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem); + mi.AddItem(markItem); // subject: item name std::string subject = markProto->Name1; diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index edef1c641..46ed12157 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -6230,7 +6230,7 @@ bool ChatHandler::HandleSendItemsCommand(const char* args) if(Item* item = Item::CreateItem(itr->first,itr->second,m_session ? m_session->GetPlayer() : 0)) { item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + mi.AddItem(item); } } diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp index 649d2377e..42abda90f 100644 --- a/src/game/Mail.cpp +++ b/src/game/Mail.cpp @@ -39,18 +39,6 @@ enum MailShowFlags MAIL_SHOW_RETURN = 0x0010, }; -void MailItem::deleteItem( bool inDB ) -{ - if(item) - { - if(inDB) - CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", item->GetGUIDLow()); - - delete item; - item = NULL; - } -} - void WorldSession::HandleSendMail(WorldPacket & recv_data ) { uint64 mailbox, unk3; @@ -70,39 +58,35 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) recv_data >> unk1; // stationery? recv_data >> unk2; // 0x00000000 - MailItemsInfo mi; - uint8 items_count; recv_data >> items_count; // attached items count - if(items_count > 12) // client limit + if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam return; } + uint64 itemGUIDs[MAX_MAIL_ITEMS]; + for(uint8 i = 0; i < items_count; ++i) { - uint64 item_guid; - recv_data.read_skip(); // item slot in mail, not used - recv_data >> item_guid; - mi.AddItem(GUID_LOPART(item_guid)); + recv_data.read_skip(); // item slot in mail, not used + recv_data >> itemGUIDs[i]; } recv_data >> money >> COD; // money and cod recv_data >> unk3; // const 0 recv_data >> unk4; // const 0 - items_count = mi.size(); // this is the real size after the duplicates have been removed - if (receiver.empty()) return; Player* pl = _player; uint64 rc = 0; - if(normalizePlayerName(receiver)) + if (normalizePlayerName(receiver)) rc = objmgr.GetPlayerGUIDByName(receiver); if (!rc) @@ -115,7 +99,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) sLog.outDetail("Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", pl->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); - if(pl->GetGUID() == rc) + if (pl->GetGUID() == rc) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; @@ -136,7 +120,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) uint32 rc_team = 0; uint8 mails_count = 0; // do not allow to send to one player more than 100 mails - if(receive) + if (receive) { rc_team = receive->GetTeam(); mails_count = receive->GetMailSize(); @@ -144,8 +128,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) else { rc_team = objmgr.GetPlayerTeamByGUID(rc); - QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc)); - if(result) + if (QueryResult* result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM mail WHERE receiver = '%u'", GUID_LOPART(rc))) { Field *fields = result->Fetch(); mails_count = fields[0].GetUInt32(); @@ -167,100 +150,95 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data ) return; } - uint32 rc_account = 0; - if(receive) - rc_account = receive->GetSession()->GetAccountId(); - else - rc_account = objmgr.GetPlayerAccountIdByGUID(rc); + uint32 rc_account = receive + ? receive->GetSession()->GetAccountId() + : objmgr.GetPlayerAccountIdByGUID(rc); - for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) + Item* items[MAX_MAIL_ITEMS]; + + for(uint8 i = 0; i < items_count; ++i) { - MailItem& mailItem = mailItemIter->second; - - if(!mailItem.item_guidlow) + if (!itemGUIDs[i]) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } - mailItem.item = pl->GetItemByGuid(MAKE_NEW_GUID(mailItem.item_guidlow, 0, HIGHGUID_ITEM)); + Item* item = pl->GetItemByGuid(itemGUIDs[i]); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) - if(!mailItem.item) + if (!item) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } - if(!mailItem.item->CanBeTraded(true)) + if (!item->CanBeTraded(true)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } - if(mailItem.item->IsBoundAccountWide() && mailItem.item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) + if (item->IsBoundAccountWide() && item->IsSoulBound() && pl->GetSession()->GetAccountId() != rc_account) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; } - if (mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || mailItem.item->GetUInt32Value(ITEM_FIELD_DURATION)) + if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_CONJURED) || item->GetUInt32Value(ITEM_FIELD_DURATION)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_MAIL_BOUND_ITEM); return; } - if(COD && mailItem.item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) + if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_WRAPPED)) { pl->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; } + + items[i] = item; } pl->SendMailResult(0, MAIL_SEND, MAIL_OK); - uint32 itemTextId = 0; - if (!body.empty()) - { - itemTextId = objmgr.CreateItemText( body ); - } + uint32 itemTextId = !body.empty() ? itemTextId = objmgr.CreateItemText( body ) : 0; pl->ModifyMoney( -int32(reqmoney) ); pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; - if(items_count > 0 || money > 0) + MailItemsInfo mi; + + if (items_count > 0 || money > 0) { if (items_count > 0) { - for(MailItemMap::iterator mailItemIter = mi.begin(); mailItemIter != mi.end(); ++mailItemIter) + for(uint8 i = 0; i < items_count; ++i) { - MailItem& mailItem = mailItemIter->second; - if(!mailItem.item) - continue; - - mailItem.item_template = mailItem.item ? mailItem.item->GetEntry() : 0; - - if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) ) + Item* item = items[i]; + if (GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", - GetPlayerName(), GetAccountId(), mailItem.item->GetProto()->Name1, mailItem.item->GetEntry(), mailItem.item->GetCount(), receiver.c_str(), rc_account); + GetPlayerName(), GetAccountId(), item->GetProto()->Name1, item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); } - pl->MoveItemFromInventory(mailItem.item->GetBagSlot(), mailItem.item->GetSlot(), true); + pl->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); CharacterDatabase.BeginTransaction(); - mailItem.item->DeleteFromInventoryDB(); // deletes item from character's inventory - mailItem.item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone + item->DeleteFromInventoryDB(); // deletes item from character's inventory + item->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting - CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", GUID_LOPART(rc), mailItem.item->GetGUIDLow()); + CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", GUID_LOPART(rc), item->GetGUIDLow()); CharacterDatabase.CommitTransaction(); + + mi.AddItem(item); } // if item send to character at another account, then apply item delivery delay needItemDelay = pl->GetSession()->GetAccountId() != rc_account; } - if(money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) + if (money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE)) { sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account); @@ -365,7 +343,7 @@ void WorldSession::HandleMailReturnToSender(WorldPacket & recv_data ) { Item *item = pl->GetMItem(itr2->item_guid); if(item) - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + mi.AddItem(item); else { //WTF? @@ -413,10 +391,10 @@ void WorldSession::SendReturnToSender(uint8 messageType, uint32 sender_acc, uint CharacterDatabase.BeginTransaction(); for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) { - MailItem& mailItem = mailItemIter->second; - mailItem.item->SaveToDB(); // item not in inventory and can be save standalone + Item* item = mailItemIter->second; + item->SaveToDB(); // item not in inventory and can be save standalone // owner in data will set at mail receive and item extracting - CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", receiver_guid, mailItem.item->GetGUIDLow()); + CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'", receiver_guid, item->GetGUIDLow()); } CharacterDatabase.CommitTransaction(); } @@ -852,6 +830,24 @@ void WorldSession::SendMailTo(Player* receiver, uint8 messageType, uint8 station mailTemplateId = 0; } + // Add to DB + CharacterDatabase.BeginTransaction(); + CharacterDatabase.escape_string(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', '%d')", + mailId, messageType, stationery, mailTemplateId, sender_guidlow_or_entry, receiver_guidlow, subject.c_str(), itemTextId, (mi && !mi->empty() ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, money, COD, checked); + + if (mi) + { + for(MailItemMap::const_iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) + { + Item* item = mailItemIter->second; + CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')", mailId, item->GetGUIDLow(), item->GetEntry(), item->GetGUIDLow()); + } + } + CharacterDatabase.CommitTransaction(); + + // For online receiver update in game mail status and data if (receiver) { receiver->AddNewMailDeliverTime(deliver_time); @@ -883,11 +879,7 @@ void WorldSession::SendMailTo(Player* receiver, uint8 messageType, uint8 station if (mi) { for(MailItemMap::iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) - { - MailItem& mailItem = mailItemIter->second; - if (mailItem.item) - receiver->AddMItem(mailItem.item); - } + receiver->AddMItem(mailItemIter->second); } } else if (mi) @@ -895,22 +887,6 @@ void WorldSession::SendMailTo(Player* receiver, uint8 messageType, uint8 station } else if (mi) mi->deleteIncludedItems(); - - CharacterDatabase.BeginTransaction(); - CharacterDatabase.escape_string(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', '%d')", - mailId, messageType, stationery, mailTemplateId, sender_guidlow_or_entry, receiver_guidlow, subject.c_str(), itemTextId, (mi && !mi->empty() ? 1 : 0), (uint64)expire_time, (uint64)deliver_time, money, COD, checked); - - if (mi) - { - for(MailItemMap::const_iterator mailItemIter = mi->begin(); mailItemIter != mi->end(); ++mailItemIter) - { - MailItem const& mailItem = mailItemIter->second; - CharacterDatabase.PExecute("INSERT INTO mail_items (mail_id,item_guid,item_template,receiver) VALUES ('%u', '%u', '%u','%u')", mailId, mailItem.item_guidlow, mailItem.item_template, receiver_guidlow); - } - } - CharacterDatabase.CommitTransaction(); } void WorldSession::SendMailTo(Player* receiver, Object* sender, uint8 stationery, uint32 receiver_guidlow, std::string subject, uint32 itemTextId, MailItemsInfo* mi, uint32 money, uint32 COD, uint32 checked, uint32 deliver_delay, uint16 mailTemplateId) @@ -962,7 +938,7 @@ void WorldSession::SendMailTemplateTo(Player* receiver, Object* sender, uint8 st if (Item* item = Item::CreateItem(lootitem->itemid,lootitem->count,receiver)) { item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + mi.AddItem(item); } } } diff --git a/src/game/Mail.h b/src/game/Mail.h index 7efda13eb..1efba2a67 100644 --- a/src/game/Mail.h +++ b/src/game/Mail.h @@ -80,18 +80,7 @@ struct MailItemInfo uint32 item_template; }; -struct MailItem -{ - MailItem() : item_guidlow(0), item_template(0), item(NULL) {} - - uint32 item_guidlow; // item guid (low part) - uint32 item_template; // item entry - Item *item; // item pointer - - void deleteItem(bool inDB = false); -}; - -typedef std::map MailItemMap; +typedef std::map MailItemMap; class MailItemsInfo { @@ -101,20 +90,9 @@ class MailItemsInfo MailItemMap::iterator begin() { return i_MailItemMap.begin(); } MailItemMap::iterator end() { return i_MailItemMap.end(); } - void AddItem(uint32 guidlow, uint32 _template, Item *item) + void AddItem(Item *item) { - MailItem mailItem; - mailItem.item_guidlow = guidlow; - mailItem.item_template = _template; - mailItem.item = item; - i_MailItemMap[guidlow] = mailItem; - } - - void AddItem(uint32 guidlow) - { - MailItem mailItem; - mailItem.item_guidlow = guidlow; - i_MailItemMap[guidlow] = mailItem; + i_MailItemMap[item->GetGUIDLow()] = item; } uint8 size() const { return i_MailItemMap.size(); } @@ -124,9 +102,15 @@ class MailItemsInfo { for(MailItemMap::iterator mailItemIter = begin(); mailItemIter != end(); ++mailItemIter) { - MailItem& mailItem = mailItemIter->second; - mailItem.deleteItem(inDB); + Item* item = mailItemIter->second; + + if(inDB) + CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", item->GetGUIDLow()); + + delete item; } + + i_MailItemMap.clear(); } private: MailItemMap i_MailItemMap; // Keep the items in a map to avoid duplicate guids (which can happen), store only low part of guid @@ -163,8 +147,8 @@ struct Mail { for(MailItemMap::iterator mailItemIter = pMailItemsInfo.begin(); mailItemIter != pMailItemsInfo.end(); ++mailItemIter) { - MailItem& mailItem = mailItemIter->second; - AddItem(mailItem.item_guidlow, mailItem.item_template); + Item* item = mailItemIter->second; + AddItem(item->GetGUIDLow(), item->GetEntry()); } } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 8bacc46cc..9b8b612fd 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -3963,7 +3963,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC continue; } - mi.AddItem(item_guidlow, item_template, pItem); + mi.AddItem(pItem); } while (resultItems->NextRow()); @@ -14949,7 +14949,7 @@ void Player::_LoadInventory(QueryResult *result, uint32 timediff) Item* item = problematicItems.front(); problematicItems.pop_front(); - mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item); + mi.AddItem(item); } std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM); @@ -18823,7 +18823,7 @@ void Player::AutoUnequipOffhandIfNeed() else { MailItemsInfo mi; - mi.AddItem(offItem->GetGUIDLow(), offItem->GetEntry(), offItem); + mi.AddItem(offItem); MoveItemFromInventory(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true); CharacterDatabase.BeginTransaction(); offItem->DeleteFromInventoryDB(); // deletes item from character's inventory diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 5838165f3..cf542c056 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8763" + #define REVISION_NR "8764" #endif // __REVISION_NR_H__