diff options
author | Carbenium <keresztesschmidt@gmail.com> | 2015-02-03 23:11:07 +0100 |
---|---|---|
committer | Carbenium <keresztesschmidt@gmail.com> | 2015-02-07 12:43:25 +0100 |
commit | 829e11b6623f967672143d79cd8d31772f54866d (patch) | |
tree | e2fcced6ddde99843b23abda068f8c2d2aeade70 | |
parent | 919ab9157e7458257e300546e05312049b0872cd (diff) |
Core/Packets: Implement all mail system relevant packets
Thanks @joschiwald, @DDuarte and @Warpten
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Handlers/MailHandler.cpp | 461 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MailPackets.cpp | 272 | ||||
-rw-r--r-- | src/server/game/Server/Packets/MailPackets.h | 257 | ||||
-rw-r--r-- | src/server/game/Server/Packets/QueryPackets.cpp | 15 | ||||
-rw-r--r-- | src/server/game/Server/Packets/QueryPackets.h | 1 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 27 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 31 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 2 |
10 files changed, 741 insertions, 365 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b869bdd26c3..84197b90626 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -56,6 +56,7 @@ #include "LFGMgr.h" #include "Language.h" #include "Log.h" +#include "MailPackets.h" #include "MapInstanced.h" #include "MapManager.h" #include "MovementStructures.h" @@ -3236,26 +3237,36 @@ void Player::RemoveMail(uint32 id) void Player::SendMailResult(uint32 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, ObjectGuid::LowType item_guid, uint32 item_count) { - WorldPacket data(SMSG_SEND_MAIL_RESULT, (4+4+4+(mailError == MAIL_ERR_EQUIP_ERROR?4:(mailAction == MAIL_ITEM_TAKEN?4+4:0)))); - data << uint32(mailId); - data << uint32(mailAction); - data << uint32(mailError); - if (mailError == MAIL_ERR_EQUIP_ERROR) - data << uint32(equipError); - else if (mailAction == MAIL_ITEM_TAKEN) + + WorldPackets::Mail::MailCommandResult result; + + result.MailID = mailId; + result.Command = mailAction; + result.ErrorCode = mailError; + + switch (mailError) { - data << uint64(item_guid); // item guid low? - data << uint32(item_count); // item count? + case MAIL_ERR_EQUIP_ERROR: + result.BagResult = equipError; + break; + case MAIL_ITEM_TAKEN: + result.AttachID = item_guid; + result.QtyInInventory = item_count; + break; + default: + break; } - GetSession()->SendPacket(&data); + + GetSession()->SendPacket(result.Write()); } void Player::SendNewMail() { // deliver undelivered mail - WorldPacket data(SMSG_RECEIVED_MAIL, 4); - data << (uint32) 0; - GetSession()->SendPacket(&data); + WorldPackets::Mail::NotifyRecievedMail notify; + notify.Delay = 0.0f; + + GetSession()->SendPacket(notify.Write()); } void Player::UpdateNextMailTimeAndUnreads() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a9b713c6b1a..ec8c5933e25 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1835,8 +1835,7 @@ class Player : public Unit, public GridObject<Player> uint32 GetMailSize() { return m_mail.size();} Mail* GetMail(uint32 id); - PlayerMails::iterator GetMailBegin() { return m_mail.begin();} - PlayerMails::iterator GetMailEnd() { return m_mail.end();} + PlayerMails const& GetMails() const { return m_mail; } void SendItemRetrievalMail(uint32 itemEntry, uint32 count); // Item retrieval mails sent by The Postmaster (34337), used in multiple places. diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index d173b409008..136f998b308 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -24,6 +24,7 @@ #include "World.h" #include "ObjectMgr.h" #include "Player.h" +#include "MailPackets.h" #include "Language.h" #include "DBCStores.h" #include "Item.h" @@ -57,91 +58,18 @@ bool WorldSession::CanOpenMailBox(ObjectGuid guid) return true; } -void WorldSession::HandleSendMail(WorldPacket& recvData) +void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& packet) { - ObjectGuid mailbox; - uint64 money, COD; - std::string receiverName, subject, body; - uint32 bodyLength, subjectLength, receiverLength; - uint32 package, stationery; - - recvData >> package; - recvData >> stationery; - - recvData >> COD >> money; // money and cod - bodyLength = recvData.ReadBits(12); - subjectLength = recvData.ReadBits(9); - - uint8 items_count = recvData.ReadBits(5); // attached items count - - if (items_count > MAX_MAIL_ITEMS) // client limit + if (packet.Info.Attachments.size() > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); - recvData.rfinish(); // set to end to avoid warnings spam return; } - mailbox[0] = recvData.ReadBit(); - - ObjectGuid itemGUIDs[MAX_MAIL_ITEMS]; - - for (uint8 i = 0; i < items_count; ++i) - { - itemGUIDs[i][2] = recvData.ReadBit(); - itemGUIDs[i][6] = recvData.ReadBit(); - itemGUIDs[i][3] = recvData.ReadBit(); - itemGUIDs[i][7] = recvData.ReadBit(); - itemGUIDs[i][1] = recvData.ReadBit(); - itemGUIDs[i][0] = recvData.ReadBit(); - itemGUIDs[i][4] = recvData.ReadBit(); - itemGUIDs[i][5] = recvData.ReadBit(); - } - - mailbox[3] = recvData.ReadBit(); - mailbox[4] = recvData.ReadBit(); - receiverLength = recvData.ReadBits(7); - mailbox[2] = recvData.ReadBit(); - mailbox[6] = recvData.ReadBit(); - mailbox[1] = recvData.ReadBit(); - mailbox[7] = recvData.ReadBit(); - mailbox[5] = recvData.ReadBit(); - - recvData.ReadByteSeq(mailbox[4]); - - for (uint8 i = 0; i < items_count; ++i) - { - recvData.ReadByteSeq(itemGUIDs[i][6]); - recvData.ReadByteSeq(itemGUIDs[i][1]); - recvData.ReadByteSeq(itemGUIDs[i][7]); - recvData.ReadByteSeq(itemGUIDs[i][2]); - recvData.read_skip<uint8>(); // item slot in mail, not used - recvData.ReadByteSeq(itemGUIDs[i][3]); - recvData.ReadByteSeq(itemGUIDs[i][0]); - recvData.ReadByteSeq(itemGUIDs[i][4]); - recvData.ReadByteSeq(itemGUIDs[i][5]); - } - - recvData.ReadByteSeq(mailbox[7]); - recvData.ReadByteSeq(mailbox[3]); - recvData.ReadByteSeq(mailbox[6]); - recvData.ReadByteSeq(mailbox[5]); - - subject = recvData.ReadString(subjectLength); - receiverName = recvData.ReadString(receiverLength); - - recvData.ReadByteSeq(mailbox[2]); - recvData.ReadByteSeq(mailbox[0]); - - body = recvData.ReadString(bodyLength); - - recvData.ReadByteSeq(mailbox[1]); - - // packet read complete, now do check - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(packet.Info.Mailbox)) return; - if (receiverName.empty()) + if (packet.Info.Target.empty()) return; Player* player = _player; @@ -153,23 +81,39 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } ObjectGuid receiverGuid; - if (normalizePlayerName(receiverName)) - receiverGuid = ObjectMgr::GetPlayerGUIDByName(receiverName); + if (normalizePlayerName(packet.Info.Target)) + receiverGuid = ObjectMgr::GetPlayerGUIDByName(packet.Info.Target); if (!receiverGuid) { TC_LOG_INFO("network", "Player %s is sending mail to %s (GUID: not existed!) with subject %s " - "and body %s includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", - player->GetGUID().ToString().c_str(), receiverName.c_str(), subject.c_str(), body.c_str(), - items_count, money, COD, stationery, package); + "and body %s includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d", + GetPlayerInfo().c_str(), packet.Info.Target.c_str(), packet.Info.Subject.c_str(), packet.Info.Body.c_str(), + packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } + if (packet.Info.SendMoney < 0) + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); + TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative money value (SendMoney: " SI64FMTD ")", + GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.SendMoney); + return; + } + + if (packet.Info.Cod < 0) + { + GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_INTERNAL_ERROR); + TC_LOG_WARN("cheat", "Player %s attempted to send mail to %s (%s) with negative COD value (Cod: " SI64FMTD ")", + GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Cod); + return; + } + TC_LOG_INFO("network", "Player %s is sending mail to %s (%s) with subject %s and body %s " - "includes %u items, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u", - player->GetGUID().ToString().c_str(), receiverName.c_str(), receiverGuid.ToString().c_str(), subject.c_str(), - body.c_str(), items_count, money, COD, stationery, package); + "includes " SZFMTD " items, " SI64FMTD " copper and " SI64FMTD " COD copper with StationeryID = %d, PackageID = %d", + GetPlayerInfo().c_str(), packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), packet.Info.Subject.c_str(), + packet.Info.Body.c_str(), packet.Info.Attachments.size(), packet.Info.SendMoney, packet.Info.Cod, packet.Info.StationeryID, packet.Info.PackageID); if (player->GetGUID() == receiverGuid) { @@ -177,12 +121,12 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client + uint32 cost = !packet.Info.Attachments.empty() ? 30 * packet.Info.Attachments.size() : 30; // price hardcoded in client - uint64 reqmoney = cost + money; + int64 reqmoney = cost + packet.Info.SendMoney; // Check for overflow - if (reqmoney < money) + if (reqmoney < packet.Info.SendMoney) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_ENOUGH_MONEY); return; @@ -246,10 +190,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } // test the receiver's Faction... or all items are account bound - bool accountBound = items_count ? true : false; - for (uint8 i = 0; i < items_count; ++i) + bool accountBound = !packet.Info.Attachments.empty(); + for (auto const& att : packet.Info.Attachments) { - if (Item* item = player->GetItemByGuid(itemGUIDs[i])) + if (Item* item = player->GetItemByGuid(att.ItemGUID)) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->GetFlags() & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) @@ -272,17 +216,17 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - Item* items[MAX_MAIL_ITEMS]; + std::vector<Item*> items; - for (uint8 i = 0; i < items_count; ++i) + for (auto const& att : packet.Info.Attachments) { - if (!itemGUIDs[i]) + if (att.ItemGUID.IsEmpty()) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_MAIL_ATTACHMENT_INVALID); return; } - Item* item = player->GetItemByGuid(itemGUIDs[i]); + Item* item = player->GetItemByGuid(att.ItemGUID); // prevent sending bag with items (cheat: can be placed in bag after adding equipped empty bag to mail) if (!item) @@ -312,7 +256,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - if (COD && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (packet.Info.Cod && item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANT_SEND_WRAPPED_COD); return; @@ -324,38 +268,37 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - items[i] = item; + items.push_back(item); } player->SendMailResult(0, MAIL_SEND, MAIL_OK); - player->ModifyMoney(-int64(reqmoney)); + player->ModifyMoney(-reqmoney); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost); bool needItemDelay = false; - MailDraft draft(subject, body); + MailDraft draft(packet.Info.Subject, packet.Info.Body); SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (items_count > 0 || money > 0) + if (!packet.Info.Attachments.empty() || packet.Info.SendMoney > 0) { bool log = HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE); - if (items_count > 0) + if (!packet.Info.Attachments.empty()) { - for (uint8 i = 0; i < items_count; ++i) + for (auto const& item : items) { - Item* item = items[i]; if (log) { sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail item: %s (Entry: %u Count: %u) " "to: %s (%s) (Account: %u)", GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), item->GetTemplate()->GetDefaultLocaleName(), item->GetEntry(), item->GetCount(), - receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); + packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable - player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); + player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory item->SetOwnerGUID(receiverGuid); @@ -368,10 +311,10 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } - if (log && money > 0) + if (log && packet.Info.SendMoney > 0) { - sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: " UI64FMTD " to: %s (%s) (Account: %u)", - GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), money, receiverName.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); + sLog->outCommand(GetAccountId(), "GM %s (%s) (Account: %u) mail money: " SI64FMTD " to: %s (%s) (Account: %u)", + GetPlayerName().c_str(), _player->GetGUID().ToString().c_str(), GetAccountId(), packet.Info.SendMoney, packet.Info.Target.c_str(), receiverGuid.ToString().c_str(), receiverAccountId); } } @@ -384,32 +327,27 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) deliver_delay = 0; // don't ask for COD if there are no items - if (items_count == 0) - COD = 0; + if (packet.Info.Attachments.empty()) + packet.Info.Cod = 0; // will delete item or place to receiver mail list draft - .AddMoney(money) - .AddCOD(COD) - .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); + .AddMoney(packet.Info.SendMoney) + .AddCOD(packet.Info.Cod) + .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), MailSender(player), packet.Info.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); } //called when mail is read -void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) +void WorldSession::HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& packet) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(packet.MailID); if (m && m->state != MAIL_STATE_DELETED) { if (player->unReadMails) @@ -421,18 +359,9 @@ void WorldSession::HandleMailMarkAsRead(WorldPacket& recvData) } //called when client deletes mail -void WorldSession::HandleMailDelete(WorldPacket& recvData) +void WorldSession::HandleMailDelete(WorldPackets::Mail::MailDelete& packet) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - recvData.read_skip<uint32>(); // mailTemplateId - - if (!CanOpenMailBox(mailbox)) - return; - - Mail* m = _player->GetMail(mailId); + Mail* m = _player->GetMail(packet.MailID); Player* player = _player; player->m_mailsUpdated = true; if (m) @@ -440,45 +369,40 @@ void WorldSession::HandleMailDelete(WorldPacket& recvData) // delete shouldn't show up for COD mails if (m->COD) { - player->SendMailResult(mailId, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_DELETED, MAIL_ERR_INTERNAL_ERROR); return; } m->state = MAIL_STATE_DELETED; } - player->SendMailResult(mailId, MAIL_DELETED, MAIL_OK); + player->SendMailResult(packet.MailID, MAIL_DELETED, MAIL_OK); } -void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) +void WorldSession::HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& packet) { - ObjectGuid mailbox; - uint32 mailId; - recvData >> mailbox; - recvData >> mailId; - recvData.read_skip<uint64>(); // original sender GUID for return to, not used - - if (!CanOpenMailBox(mailbox)) - return; + //TODO: find a proper way to replace this check. Idea: Save Guid form MailGetList until CMSG_CLOSE_INTERACTION is sent + /*if (!CanOpenMailBox(mailbox)) + return;*/ Player* player = _player; - Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + Mail* m = player->GetMail(packet.MailID); + if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr) || m->sender != packet.SenderGUID.GetCounter()) { - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_RETURNED_TO_SENDER, MAIL_ERR_INTERNAL_ERROR); return; } //we can return mail now, so firstly delete the old one SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID); - stmt->setUInt32(0, mailId); + stmt->setUInt32(0, packet.MailID); trans->Append(stmt); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID); - stmt->setUInt32(0, mailId); + stmt->setUInt32(0, packet.MailID); trans->Append(stmt); - player->RemoveMail(mailId); + player->RemoveMail(packet.MailID); // only return mail if the player exists (and delete if not existing) if (m->messageType == MAIL_NORMAL && m->sender) @@ -502,54 +426,49 @@ void WorldSession::HandleMailReturnToSender(WorldPacket& recvData) CharacterDatabase.CommitTransaction(trans); delete m; //we can deallocate old mail - player->SendMailResult(mailId, MAIL_RETURNED_TO_SENDER, MAIL_OK); + player->SendMailResult(packet.MailID, MAIL_RETURNED_TO_SENDER, MAIL_OK); } //called when player takes item attached in mail -void WorldSession::HandleMailTakeItem(WorldPacket& recvData) +void WorldSession::HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& packet) { - ObjectGuid mailbox; - uint32 mailId; - ObjectGuid::LowType itemId; - recvData >> mailbox; - recvData >> mailId; - recvData >> itemId; // item guid low - - if (!CanOpenMailBox(mailbox)) + uint32 AttachID = packet.AttachID; + + if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); - if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) + Mail* m = player->GetMail(packet.MailID); + if (!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr)) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // verify that the mail has the item to avoid cheaters taking COD items without paying - if (std::find_if(m->items.begin(), m->items.end(), [itemId](MailItemInfo info){ return info.item_guid == itemId; }) == m->items.end()) + if (std::find_if(m->items.begin(), m->items.end(), [AttachID](MailItemInfo info){ return info.item_guid == AttachID; }) == m->items.end()) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } // prevent cheating with skip client money check if (!player->HasEnoughMoney(uint64(m->COD))) { - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); + player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_NOT_ENOUGH_MONEY); return; } - Item* it = player->GetMItem(itemId); + Item* it = player->GetMItem(packet.AttachID); ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, it, false); if (msg == EQUIP_ERR_OK) { SQLTransaction trans = CharacterDatabase.BeginTransaction(); - m->RemoveItem(itemId); - m->removedItems.push_back(itemId); + m->RemoveItem(packet.AttachID); + m->removedItems.push_back(packet.AttachID); if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail { @@ -603,38 +522,30 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) player->_SaveMail(trans); CharacterDatabase.CommitTransaction(trans); - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_OK, 0, itemId, count); + player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_OK, 0, packet.AttachID, count); } else - player->SendMailResult(mailId, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); + player->SendMailResult(packet.MailID, MAIL_ITEM_TAKEN, MAIL_ERR_EQUIP_ERROR, msg); } -void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) +void WorldSession::HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& packet) { - ObjectGuid mailbox; - uint64 money; - uint32 mailId; - - recvData >> mailbox; - recvData >> mailId; - recvData >> money; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); + Mail* m = player->GetMail(packet.MailID); if ((!m || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL)) || - (money > 0 && m->money != money)) + (packet.Money > 0 && m->money != uint64(packet.Money))) { - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_INTERNAL_ERROR); return; } if (!player->ModifyMoney(m->money, false)) { - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); + player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); return; } @@ -642,7 +553,7 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + player->SendMailResult(packet.MailID, MAIL_MONEY_TAKEN, MAIL_OK); // save money and mail to prevent cheating SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -652,12 +563,9 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) } //called when player lists his received mails -void WorldSession::HandleGetMailList(WorldPacket& recvData) +void WorldSession::HandleGetMailList(WorldPackets::Mail::MailGetList& packet) { - ObjectGuid mailbox; - recvData >> mailbox; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; @@ -666,130 +574,42 @@ void WorldSession::HandleGetMailList(WorldPacket& recvData) if (!player->m_mailsLoaded) player->_LoadMail(); - // client can't work with packets > max int16 value - const uint32 maxPacketSize = 32767; - - uint32 mailsCount = 0; // real send to client mails amount - uint32 realCount = 0; // real mails amount - - WorldPacket data(SMSG_MAIL_LIST_RESULT, 200); // guess size - data << uint32(0); // real mail's count - data << uint8(0); // mail's count - time_t cur_time = time(NULL); + WorldPackets::Mail::MailListResult response; + response.TotalNumRecords = player->GetMailSize(); - for (PlayerMails::iterator itr = player->GetMailBegin(); itr != player->GetMailEnd(); ++itr) + time_t cur_time = time(nullptr); + + for (Mail* m : player->GetMails()) { - // Only first 50 mails are displayed - if (mailsCount >= 50) - { - realCount += 1; - continue; - } - // skip deleted or not delivered (deliver delay not expired) mails - if ((*itr)->state == MAIL_STATE_DELETED || cur_time < (*itr)->deliver_time) + if (m->state == MAIL_STATE_DELETED || cur_time < m->deliver_time) continue; - uint8 item_count = (*itr)->items.size(); // max count is MAX_MAIL_ITEMS (12) - - size_t next_mail_size = 2+4+1+((*itr)->messageType == MAIL_NORMAL ? 8 : 4)+4*8+((*itr)->subject.size()+1)+((*itr)->body.size()+1)+1+item_count*(1+8+4+MAX_INSPECTED_ENCHANTMENT_SLOT*3*4+4+4+4+4+4+4+1); - - if (data.wpos()+next_mail_size > maxPacketSize) - { - realCount += 1; - continue; - } - - data << uint16(next_mail_size); // Message size - data << uint32((*itr)->messageID); // Message ID - data << uint8((*itr)->messageType); // Message Type - - switch ((*itr)->messageType) - { - case MAIL_NORMAL: // sender guid - data << ObjectGuid::Create<HighGuid::Player>((*itr)->sender); - break; - case MAIL_CREATURE: - case MAIL_GAMEOBJECT: - case MAIL_AUCTION: - case MAIL_CALENDAR: - data << uint32((*itr)->sender); // creature/gameobject entry, auction id, calendar event id? - break; - } - - data << uint64((*itr)->COD); // COD - data << uint32(0); // Package.dbc ID ? - data << uint32((*itr)->stationery); // stationery (Stationery.dbc) - data << uint64((*itr)->money); // Gold - data << uint32((*itr)->checked); // flags - data << float(float((*itr)->expire_time-time(NULL))/DAY); // Time - data << uint32((*itr)->mailTemplateId); // mail template (MailTemplate.dbc) - data << (*itr)->subject; // Subject string - once 00, when mail type = 3, max 256 - data << (*itr)->body; // message? max 8000 - data << uint8(item_count); // client limit is 0x10 - - for (uint8 i = 0; i < item_count; ++i) - { - Item* item = player->GetMItem((*itr)->items[i].item_guid); - // item index (0-6?) - data << uint8(i); - // item guid low? - data << uint64((item ? item->GetGUID().GetCounter() : UI64LIT(0))); - // entry - data << uint32((item ? item->GetEntry() : 0)); - for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; ++j) - { - data << uint32((item ? item->GetEnchantmentId((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentDuration((EnchantmentSlot)j) : 0)); - data << uint32((item ? item->GetEnchantmentCharges((EnchantmentSlot)j) : 0)); - } - - // can be negative - data << int32((item ? item->GetItemRandomPropertyId() : 0)); - // unk - data << uint32((item ? item->GetItemSuffixFactor() : 0)); - // stack count - data << uint32((item ? item->GetCount() : 0)); - // charges - data << uint32((item ? item->GetSpellCharges() : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY) : 0)); - // durability - data << uint32((item ? item->GetUInt32Value(ITEM_FIELD_DURABILITY) : 0)); - // unknown wotlk - data << uint8(0); - } + response.Mails.emplace_back(m, player); - ++realCount; - ++mailsCount; + // max. 50 mails can be sent + if (response.Mails.size() >= 50) + break; } - data.put<uint32>(0, realCount); // this will display warning about undelivered mail to player if realCount > mailsCount - data.put<uint8>(4, mailsCount); // set real send mails to client - SendPacket(&data); + SendPacket(response.Write()); // recalculate m_nextMailDelivereTime and unReadMails _player->UpdateNextMailTimeAndUnreads(); } //used when player copies mail body to his inventory -void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) +void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& packet) { - ObjectGuid mailbox; - uint32 mailId; - - recvData >> mailbox; - recvData >> mailId; - - if (!CanOpenMailBox(mailbox)) + if (!CanOpenMailBox(packet.Mailbox)) return; Player* player = _player; - Mail* m = player->GetMail(mailId); - if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(NULL) || (m->checked & MAIL_CHECK_MASK_COPIED)) + Mail* m = player->GetMail(packet.MailID); + if (!m || (m->body.empty() && !m->mailTemplateId) || m->state == MAIL_STATE_DELETED || m->deliver_time > time(nullptr) || (m->checked & MAIL_CHECK_MASK_COPIED)) { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } @@ -806,7 +626,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) MailTemplateEntry const* mailTemplateEntry = sMailTemplateStore.LookupEntry(m->mailTemplateId); if (!mailTemplateEntry) { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); + player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_INTERNAL_ERROR); return; } @@ -820,8 +640,6 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_MAIL_TEXT_MASK); - TC_LOG_INFO("network", "HandleMailCreateTextItem mailid=%u", mailId); - ItemPosCountVec dest; uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false); if (msg == EQUIP_ERR_OK) @@ -831,65 +649,54 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) player->m_mailsUpdated = true; player->StoreItem(dest, bodyItem, true); - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_OK); + player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_OK); } else { - player->SendMailResult(mailId, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); + player->SendMailResult(packet.MailID, MAIL_MADE_PERMANENT, MAIL_ERR_EQUIP_ERROR, msg); delete bodyItem; } } /// @todo Fix me! ... this void has probably bad condition, but good data are sent -void WorldSession::HandleQueryNextMailTime(WorldPacket& /*recvData*/) +void WorldSession::HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& /*packet*/) { - WorldPacket data(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, 8); + WorldPackets::Mail::MailQueryNextTimeResult result; if (!_player->m_mailsLoaded) _player->_LoadMail(); if (_player->unReadMails > 0) { - data << float(0); // float - data << uint32(0); // count + result.NextMailTime = 0.0f; - uint32 count = 0; - time_t now = time(NULL); + time_t now = time(nullptr); std::set<ObjectGuid::LowType> sentSenders; - for (PlayerMails::iterator itr = _player->GetMailBegin(); itr != _player->GetMailEnd(); ++itr) + + for (Mail* mail : _player->GetMails()) { - Mail* m = (*itr); - // must be not checked yet - if (m->checked & MAIL_CHECK_MASK_READ) + if (mail->checked & MAIL_CHECK_MASK_READ) continue; - // and already delivered - if (now < m->deliver_time) + // already delivered + if (now < mail->deliver_time) continue; // only send each mail sender once - if (sentSenders.count(m->sender)) + if (sentSenders.count(mail->sender)) continue; - data << (m->messageType == MAIL_NORMAL ? ObjectGuid::Create<HighGuid::Player>(m->sender) : ObjectGuid::Empty); // player guid - data << uint32(m->messageType != MAIL_NORMAL ? m->sender : 0); // non-player entries - data << uint32(m->messageType); - data << uint32(m->stationery); - data << float(m->deliver_time - now); + result.Next.emplace_back(mail); - sentSenders.insert(m->sender); - ++count; - if (count == 2) // do not display more than 2 mails + sentSenders.insert(mail->sender); + + // do not send more than 2 mails + if (sentSenders.size() > 2) break; } - - data.put<uint32>(4, count); } else - { - data << float(-DAY); - data << uint32(0); - } + result.NextMailTime = -DAY; - SendPacket(&data); + SendPacket(result.Write()); } diff --git a/src/server/game/Server/Packets/MailPackets.cpp b/src/server/game/Server/Packets/MailPackets.cpp new file mode 100644 index 00000000000..c712fe0d5b0 --- /dev/null +++ b/src/server/game/Server/Packets/MailPackets.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Mail.h" +#include "MailPackets.h" +#include "Player.h" +#include "World.h" + +WorldPackets::Mail::MailAttachedItem::MailAttachedItem(::Item const* item, uint8 pos) +{ + Position = pos; + AttachID = item->GetGUID().GetCounter(); + Count = item->GetCount(); + Charges = item->GetSpellCharges(); + MaxDurability = item->GetUInt32Value(ITEM_FIELD_MAXDURABILITY); + Durability = item->GetUInt32Value(ITEM_FIELD_DURABILITY); + Unlocked = !item->IsLocked(); //TODO: Check + + for (uint8 j = 0; j < MAX_INSPECTED_ENCHANTMENT_SLOT; j++) + { + Enchants[j].Enchant = item->GetEnchantmentId((EnchantmentSlot)j); + Enchants[j].Duration = item->GetEnchantmentDuration((EnchantmentSlot)j); + Enchants[j].Charges = item->GetEnchantmentCharges((EnchantmentSlot)j); + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailAttachedItem const& att) +{ + data << uint8(att.Position); + data << uint32(att.AttachID); + data << WorldPackets::Item::ItemInstance(att.Item); + + for (auto const& en : att.Enchants) + { + data << int32(en.Enchant); + data << int32(en.Duration); + data << int32(en.Charges); + } + + data << int32(att.Count); + data << int32(att.Charges); + data << int32(att.MaxDurability); + data << int32(att.Durability); + data.WriteBit(att.Unlocked); + data.FlushBits(); + + return data; +} + +WorldPackets::Mail::MailListEntry::MailListEntry(::Mail const* mail, ::Player* player) +{ + MailID = mail->messageID; + SenderType = mail->messageType; + + switch (mail->messageType) + { + case MAIL_NORMAL: + SenderCharacter.Set(ObjectGuid::Create<HighGuid::Player>(mail->sender)); + SenderHint.NativeRealmAddress.Set(GetVirtualRealmAddress()); + SenderHint.VirtualRealmAddress.Set(GetVirtualRealmAddress()); + break; + case MAIL_CREATURE: + case MAIL_GAMEOBJECT: + case MAIL_AUCTION: + case MAIL_CALENDAR: + AltSenderID.Set(mail->sender); + break; + } + + Cod = mail->COD; + PackageID = 0; + StationeryID = mail->stationery; + SentMoney = mail->money; + Flags = mail->checked; + DaysLeft = float(mail->expire_time - time(nullptr)) / DAY; + MailTemplateID = mail->mailTemplateId; + Subject = mail->subject; + Body = mail->body; + + for (uint8 i = 0; i < mail->items.size(); i++) + { + if (::Item* item = player->GetMItem(mail->items[i].item_guid)) + Attachments.emplace_back(item, i); + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailListEntry const& entry) +{ + data << int32(entry.MailID); + data << int8(entry.SenderType); + + data << entry.SenderHint; + + data << int64(entry.Cod); + data << int32(entry.PackageID); + data << int32(entry.StationeryID); + data << int64(entry.SentMoney); + data << int32(entry.Flags); + data << float(entry.DaysLeft); + data << int32(entry.MailTemplateID); + + data << int32(entry.Attachments.size()); + + for (auto const& att : entry.Attachments) + data << att; + + data.WriteBit(entry.SenderCharacter.HasValue); + data.WriteBit(entry.AltSenderID.HasValue); + data.WriteBits(entry.Subject.size(), 8); + data.WriteBits(entry.Body.size(), 13); + data.FlushBits(); + + return data; +} + +void WorldPackets::Mail::MailGetList::Read() +{ + _worldPacket >> Mailbox; + LowGuids.resize(_worldPacket.read<int32>()); + + for (auto& l : LowGuids) + _worldPacket >> l; +} + +WorldPacket const* WorldPackets::Mail::MailListResult::Write() +{ + _worldPacket << int32(Mails.size()); + _worldPacket << int32(TotalNumRecords); + + for (auto const& mail : Mails) + _worldPacket << mail; + + return &_worldPacket; +} + +void WorldPackets::Mail::MailCreateTextItem::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; +} + +void WorldPackets::Mail::SendMail::Read() +{ + _worldPacket >> Info.Mailbox; + _worldPacket >> Info.StationeryID; + _worldPacket >> Info.PackageID; + _worldPacket >> Info.SendMoney; + _worldPacket >> Info.Cod; + + uint32 targetLength = _worldPacket.ReadBits(9); + uint32 subjectLength = _worldPacket.ReadBits(9); + uint32 bodyLength = _worldPacket.ReadBits(11); + + Info.Attachments.resize(_worldPacket.ReadBits(5)); + + Info.Target = _worldPacket.ReadString(targetLength); + Info.Subject = _worldPacket.ReadString(subjectLength); + Info.Body = _worldPacket.ReadString(bodyLength); + + for (auto& att : Info.Attachments) + { + _worldPacket >> att.AttachPosition; + _worldPacket >> att.ItemGUID; + } +} + +void WorldPackets::Mail::MailReturnToSender::Read() +{ + _worldPacket >> MailID; + _worldPacket >> SenderGUID; +} + +WorldPacket const* WorldPackets::Mail::MailCommandResult::Write() +{ + _worldPacket << uint32(MailID); + _worldPacket << uint32(Command); + _worldPacket << uint32(ErrorCode); + _worldPacket << uint32(BagResult); + _worldPacket << uint32(AttachID); + _worldPacket << uint32(QtyInInventory); + + return &_worldPacket; +} + +void WorldPackets::Mail::MailMarkAsRead::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + BiReceipt = _worldPacket.ReadBit(); +} + +void WorldPackets::Mail::MailDelete::Read() +{ + _worldPacket >> MailID; + _worldPacket >> DeleteReason; +} + +void WorldPackets::Mail::MailTakeItem::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + _worldPacket >> AttachID; +} + +void WorldPackets::Mail::MailTakeMoney::Read() +{ + _worldPacket >> Mailbox; + _worldPacket >> MailID; + _worldPacket >> Money; +} + +WorldPackets::Mail::MailQueryNextTimeResult::MailNextTimeEntry::MailNextTimeEntry(::Mail const* mail) +{ + switch (mail->messageType) + { + case MAIL_NORMAL: + SenderGuid = ObjectGuid::Create<HighGuid::Player>(mail->sender); + SenderHint.NativeRealmAddress.Set(GetVirtualRealmAddress()); + SenderHint.VirtualRealmAddress.Set(GetVirtualRealmAddress()); + break; + case MAIL_AUCTION: + case MAIL_CREATURE: + case MAIL_GAMEOBJECT: + case MAIL_CALENDAR: + AltSenderID = mail->sender; + break; + } + + TimeLeft = mail->deliver_time - time(nullptr); + AltSenderType = mail->messageType; + StationeryID = mail->stationery; +} + +WorldPacket const* WorldPackets::Mail::MailQueryNextTimeResult::Write() +{ + _worldPacket << float(NextMailTime); + _worldPacket << int32(Next.size()); + + for (auto const& entry : Next) + { + _worldPacket << entry.SenderGuid; + _worldPacket << entry.SenderHint; + + _worldPacket << float(entry.TimeLeft); + _worldPacket << int32(entry.AltSenderID); + _worldPacket << int8(entry.AltSenderType); + _worldPacket << int32(entry.StationeryID); + } + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Mail::NotifyRecievedMail::Write() +{ + _worldPacket << float(Delay); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MailPackets.h b/src/server/game/Server/Packets/MailPackets.h new file mode 100644 index 00000000000..8019c274191 --- /dev/null +++ b/src/server/game/Server/Packets/MailPackets.h @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MailPackets_h__ +#define MailPackets_h__ + +#include "ItemPackets.h" +#include "Packet.h" +#include "QueryPackets.h" +#include "ObjectGuid.h" + +struct Mail; + +namespace WorldPackets +{ + namespace Mail + { + struct MailAttachedItemEnchant + { + int32 Enchant = 0; + int32 Duration = 0; + int32 Charges = 0; + }; + + struct MailAttachedItem + { + MailAttachedItem(::Item const* item, uint8 pos); + + uint8 Position = 0; + int32 AttachID = 0; + Item::ItemInstance Item; + int32 Count = 0; + int32 Charges = 0; + int32 MaxDurability = 0; + int32 Durability = 0; + bool Unlocked = false; + MailAttachedItemEnchant Enchants[8]; + }; + + struct MailListEntry + { + MailListEntry(::Mail const* mail, ::Player* player); + + int32 MailID = 0; + uint8 SenderType = 0; + Optional<ObjectGuid> SenderCharacter; + Query::PlayerGuidLookupHint SenderHint; + Optional<uint32> AltSenderID; + int64 Cod = 0; + int32 PackageID = 0; + int32 StationeryID = 0; + int64 SentMoney = 0; + int32 Flags = 0; + float DaysLeft = 0.0f; + int32 MailTemplateID = 0; + std::string Subject; + std::string Body; + std::vector<MailAttachedItem> Attachments; + }; + + class MailGetList final : public ClientPacket + { + public: + MailGetList(WorldPacket&& packet) : ClientPacket(CMSG_GET_MAIL_LIST, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + std::vector<ObjectGuid::LowType> LowGuids; + }; + + class MailListResult final : public ServerPacket + { + public: + MailListResult() : ServerPacket(SMSG_MAIL_LIST_RESULT, 8) { } + + WorldPacket const* Write() override; + + int32 TotalNumRecords = 0; + std::vector<MailListEntry> Mails; + }; + + class MailCreateTextItem final : public ClientPacket + { + public: + MailCreateTextItem(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_CREATE_TEXT_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + uint32 MailID = 0; + }; + + class SendMail final : public ClientPacket + { + public: + struct StructSendMail + { + struct MailAttachment + { + uint8 AttachPosition = 0; + ObjectGuid ItemGUID; + }; + + ObjectGuid Mailbox; + int32 StationeryID = 0; + int32 PackageID = 0; + int64 SendMoney = 0; + int64 Cod = 0; + std::string Target; + std::string Subject; + std::string Body; + std::vector<MailAttachment> Attachments; + }; + + SendMail(WorldPacket&& packet) : ClientPacket(CMSG_SEND_MAIL, std::move(packet)) { } + + void Read() override; + + StructSendMail Info; + }; + + class MailCommandResult final : public ServerPacket + { + public: + MailCommandResult() : ServerPacket(SMSG_SEND_MAIL_RESULT) { } + + WorldPacket const* Write() override; + + uint32 MailID = 0; + uint32 Command = 0; + uint32 ErrorCode = 0; + uint32 BagResult = 0; + uint32 AttachID = 0; + uint32 QtyInInventory = 0; + }; + + class MailReturnToSender final : public ClientPacket + { + public: + MailReturnToSender(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_RETURN_TO_SENDER, std::move(packet)) { } + + void Read() override; + + int32 MailID = 0; + ObjectGuid SenderGUID; + }; + + class MailMarkAsRead final : public ClientPacket + { + public: + MailMarkAsRead(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_MARK_AS_READ, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + bool BiReceipt = false; + }; + + class MailDelete final : public ClientPacket + { + public: + MailDelete(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_DELETE, std::move(packet)) { } + + void Read() override; + + int32 MailID = 0; + int32 DeleteReason = 0; + }; + + class MailTakeItem final : public ClientPacket + { + public: + MailTakeItem(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_TAKE_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + int32 AttachID = 0; + }; + + class MailTakeMoney final : public ClientPacket + { + public: + MailTakeMoney(WorldPacket&& packet) : ClientPacket(CMSG_MAIL_TAKE_MONEY, std::move(packet)) { } + + void Read() override; + + ObjectGuid Mailbox; + int32 MailID = 0; + int64 Money = 0; + }; + + class MailQueryNextMailTime final : public ClientPacket + { + public: + MailQueryNextMailTime(WorldPacket&& packet) : ClientPacket(CMSG_QUERY_NEXT_MAIL_TIME, std::move(packet)) { } + + void Read() override { } + }; + + class MailQueryNextTimeResult final : public ServerPacket + { + public: + struct MailNextTimeEntry + { + MailNextTimeEntry(::Mail const* mail); + + ObjectGuid SenderGuid; + Query::PlayerGuidLookupHint SenderHint; + float TimeLeft = 0.0f; + int32 AltSenderID = 0; + int8 AltSenderType = 0; + int32 StationeryID = 0; + }; + + MailQueryNextTimeResult() : ServerPacket(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, 8) { } + + WorldPacket const* Write() override; + + float NextMailTime = 0.0f; + std::vector<MailNextTimeEntry> Next; + }; + + class NotifyRecievedMail : ServerPacket + { + public: + NotifyRecievedMail() : ServerPacket(SMSG_NOTIFY_RECEIVED_MAIL, 4) { } + + WorldPacket const* Write() override; + + float Delay = 0.0f; + }; + + } +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailAttachedItem const& att); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Mail::MailListEntry const& entry); + +#endif // MailPackets_h__ diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index 4dfd01dfcaa..d9e48ca1205 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -106,6 +106,21 @@ void WorldPackets::Query::QueryPlayerName::Read() _worldPacket >> Hint.NativeRealmAddress.Value; } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::PlayerGuidLookupHint const& lookupHint) +{ + data.WriteBit(lookupHint.VirtualRealmAddress.HasValue); + data.WriteBit(lookupHint.NativeRealmAddress.HasValue); + data.FlushBits(); + + if (lookupHint.VirtualRealmAddress.HasValue) + data << uint32(lookupHint.VirtualRealmAddress.Value); + + if (lookupHint.NativeRealmAddress.HasValue) + data << uint32(lookupHint.NativeRealmAddress.Value); + + return data; +} + bool WorldPackets::Query::PlayerGuidLookupData::Initialize(ObjectGuid const& guid, Player const* player /*= nullptr*/) { CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(guid); diff --git a/src/server/game/Server/Packets/QueryPackets.h b/src/server/game/Server/Packets/QueryPackets.h index 3907476129c..97648385a50 100644 --- a/src/server/game/Server/Packets/QueryPackets.h +++ b/src/server/game/Server/Packets/QueryPackets.h @@ -323,6 +323,7 @@ namespace WorldPackets } } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::PlayerGuidLookupHint const& lookupHint); ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Query::PlayerGuidLookupData const& lookupData); #endif // QueryPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 9b9bb079729..e2c097c8fc4 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -33,6 +33,7 @@ #include "Packets/InspectPackets.h" #include "Packets/ItemPackets.h" #include "Packets/LootPackets.h" +#include "Packets/MailPackets.h" #include "Packets/MiscPackets.h" #include "Packets/MovementPackets.h" #include "Packets/NPCPackets.h" @@ -377,7 +378,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_CHALLENGE_MODE_REWARDS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_GARRISON_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_GET_ITEM_PURCHASE_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::GetItemPurchaseData, &WorldSession::HandleGetItemPurchaseData); - DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MAIL_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetMailList ); + DEFINE_HANDLER(CMSG_GET_MAIL_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailGetList, &WorldSession::HandleGetMailList); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_MIRROR_IMAGE_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_SHIPMENT_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_GET_TROPHY_LIST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -529,12 +530,12 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_LOOT_ROLL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleLootRoll ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LOW_LEVEL_RAID1, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_LOW_LEVEL_RAID2, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_CREATE_TEXT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailCreateTextItem ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_DELETE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailDelete ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_MARK_AS_READ, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailMarkAsRead ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_RETURN_TO_SENDER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailReturnToSender ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_TAKE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeItem ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_MAIL_TAKE_MONEY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleMailTakeMoney ); + DEFINE_HANDLER(CMSG_MAIL_CREATE_TEXT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailCreateTextItem, &WorldSession::HandleMailCreateTextItem); + DEFINE_HANDLER(CMSG_MAIL_DELETE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailDelete, &WorldSession::HandleMailDelete); + DEFINE_HANDLER(CMSG_MAIL_MARK_AS_READ, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailMarkAsRead, &WorldSession::HandleMailMarkAsRead); + DEFINE_HANDLER(CMSG_MAIL_RETURN_TO_SENDER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailReturnToSender, &WorldSession::HandleMailReturnToSender); + DEFINE_HANDLER(CMSG_MAIL_TAKE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeItem, &WorldSession::HandleMailTakeItem); + DEFINE_HANDLER(CMSG_MAIL_TAKE_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailTakeMoney, &WorldSession::HandleMailTakeMoney); DEFINE_OPCODE_HANDLER_OLD(CMSG_MASTER_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MEETINGSTONE_INFO, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_MESSAGECHAT_ADDON_CHANNEL, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -690,7 +691,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_COUNTDOWN_TIMER, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_GUILD_XP, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleGuildQueryXPOpcode ); DEFINE_HANDLER(CMSG_QUERY_INSPECT_ACHIEVEMENTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Inspect::QueryInspectAchievements, &WorldSession::HandleQueryInspectAchievements); - DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_NEXT_MAIL_TIME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryNextMailTime ); + DEFINE_HANDLER(CMSG_QUERY_NEXT_MAIL_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::MailQueryNextMailTime, &WorldSession::HandleQueryNextMailTime); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_PETITION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_SCENARIO_POI, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_QUERY_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Query::QueryTime, &WorldSession::HandleQueryTimeOpcode); @@ -768,7 +769,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SELF_RES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSelfResOpcode ); DEFINE_HANDLER(CMSG_SELL_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::SellItem, &WorldSession::HandleSellItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_SEND_CONTACT_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleContactListOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SEND_MAIL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSendMail ); + DEFINE_HANDLER(CMSG_SEND_MAIL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Mail::SendMail, &WorldSession::HandleSendMail); DEFINE_OPCODE_HANDLER_OLD(CMSG_SEND_SOR_REQUEST_VIA_ADDRESS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SEND_SOR_REQUEST_VIA_BNET_ACCOUNT_ID, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SERVERTIME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -1477,8 +1478,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_SLOT_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOSS_OF_CONTROL_AURA_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_LIST_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAIL_QUERY_NEXT_TIME_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJECTIVES_INIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MAP_OBJ_EVENTS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_MASTER_LOOT_CANDIDATE_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1594,7 +1595,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_DEST_LOC_SPELL_CAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MISSILE_TRAJECTORY_COLLISION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_MONEY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_RECEIVED_MAIL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_NOTIFY_RECEIVED_MAIL, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NPC_TEXT_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_NPC_WONT_TALK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_OFFER_PETITION_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1782,7 +1783,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_ITEM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SELL_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_ITEM_PASSIVES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_MAIL_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_MAIL_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_RAID_TARGET_UPDATE_SINGLE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_SPELL_CHARGES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 029d97ce9bd..d90cb1f1770 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -198,6 +198,19 @@ namespace WorldPackets class LootMoney; } + namespace Mail + { + class MailCreateTextItem; + class MailDelete; + class MailGetList; + class MailMarkAsRead; + class MailQueryNextMailTime; + class MailReturnToSender; + class MailTakeItem; + class MailTakeMoney; + class SendMail; + } + namespace Misc { class AreaTrigger; @@ -937,16 +950,16 @@ class WorldSession // Black Market void HandleBlackMarketOpen(WorldPackets::BlackMarket::BlackMarketOpen& packet); - void HandleGetMailList(WorldPacket& recvData); - void HandleSendMail(WorldPacket& recvData); - void HandleMailTakeMoney(WorldPacket& recvData); - void HandleMailTakeItem(WorldPacket& recvData); - void HandleMailMarkAsRead(WorldPacket& recvData); - void HandleMailReturnToSender(WorldPacket& recvData); - void HandleMailDelete(WorldPacket& recvData); + void HandleGetMailList(WorldPackets::Mail::MailGetList& packet); + void HandleSendMail(WorldPackets::Mail::SendMail& packet); + void HandleMailTakeMoney(WorldPackets::Mail::MailTakeMoney& packet); + void HandleMailTakeItem(WorldPackets::Mail::MailTakeItem& packet); + void HandleMailMarkAsRead(WorldPackets::Mail::MailMarkAsRead& packet); + void HandleMailReturnToSender(WorldPackets::Mail::MailReturnToSender& packet); + void HandleMailDelete(WorldPackets::Mail::MailDelete& packet); void HandleItemTextQuery(WorldPacket& recvData); - void HandleMailCreateTextItem(WorldPacket& recvData); - void HandleQueryNextMailTime(WorldPacket& recvData); + void HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextItem& packet); + void HandleQueryNextMailTime(WorldPackets::Mail::MailQueryNextMailTime& packet); void HandleCancelChanneling(WorldPacket& recvData); void SendItemPageInfo(ItemTemplate* itemProto); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 9d7a09702eb..727a03b85f1 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -131,7 +131,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs, item_guid, itemEntry, owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid WHERE mail_id = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, itemguid, itemEntry FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); |