From a07d54e513bad6e5a2ad90ceea6f3f8edb5904d8 Mon Sep 17 00:00:00 2001 From: Aaron Kimbre Date: Mon, 20 Jan 2025 00:42:28 -0600 Subject: [PATCH] all tested and working --- dDatabase/GameDatabase/MySQL/Tables/Mail.cpp | 1 - dGame/dUtilities/Mail.cpp | 211 +++++++++---------- dGame/dUtilities/Mail.h | 40 +++- dGame/dUtilities/SlashCommandHandler.cpp | 2 +- dMasterServer/MasterServer.cpp | 2 +- dNet/BitStreamUtils.cpp | 2 - dNet/MailInfo.cpp | 46 +--- dNet/MailInfo.h | 3 +- 8 files changed, 138 insertions(+), 169 deletions(-) diff --git a/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp index 51355080..74acb54f 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp @@ -62,7 +62,6 @@ std::optional MySQLDatabase::GetMail(const uint64_t mailId) { } uint32_t MySQLDatabase::GetUnreadMailCount(const uint32_t characterId) { - LOG("Getting unread mail count for character %i", characterId); auto res = ExecuteSelect("SELECT COUNT(*) AS number_unread FROM mail WHERE receiver_id=? AND was_read=0;", characterId); if (!res->next()) { diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index e1c7dbd0..836628c6 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -56,7 +56,6 @@ namespace Mail { }; void MailLUBitStream::Serialize(RakNet::BitStream& bitStream) const { - LOG("Writing %s", StringifiedEnum::ToString(messageID).data()); bitStream.Write(messageID); } @@ -71,111 +70,89 @@ namespace Mail { } void SendRequest::Handle() { - //std::string subject = GeneralUtils::WStringToString(ReadFromPacket(packet, 50)); - //std::string body = GeneralUtils::WStringToString(ReadFromPacket(packet, 400)); - //std::string recipient = GeneralUtils::WStringToString(ReadFromPacket(packet, 32)); - - // Check if the player has restricted mail access + SendResponse response(eSendResponse::UnknownError); auto* character = player->GetCharacter(); + if (character && !(character->HasPermission(ePermissionMap::RestrictedMailAccess) || character->GetParentUser()->GetIsMuted())) { + mailInfo.recipient = std::regex_replace(mailInfo.recipient, std::regex("[^0-9a-zA-Z]+"), ""); + auto receiverID = Database::Get()->GetCharacterInfo(mailInfo.recipient); - if (!character) return; - - if (character->HasPermission(ePermissionMap::RestrictedMailAccess) || character->GetParentUser()->GetIsMuted()) { - // Send a message to the player - ChatPackets::SendSystemMessage( - sysAddr, - u"This character has restricted mail access." - ); - - SendResponse(Mail::eSendResponse::SenderAccountIsMuted).Send(sysAddr); - - return; - } - - //Cleanse recipient: - mailInfo.recipient = std::regex_replace(mailInfo.recipient, std::regex("[^0-9a-zA-Z]+"), ""); - - //Inventory::InventoryType itemType; - int mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee; - int stackSize = 0; - auto inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); - Item* item = nullptr; - - if (mailInfo.itemID > 0 && mailInfo.itemCount > 0 && inv) { - item = inv->FindItemById(mailInfo.itemID); - if (item) { - mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee); - stackSize = item->GetCount(); - mailInfo.itemLOT = item->GetLot(); + if (!receiverID) { + response.status = eSendResponse::RecipientNotFound; + } else if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) { + response.status = eSendResponse::CannotMailSelf; } else { - SendResponse(eSendResponse::AttachmentNotFound).Send(sysAddr); - return; + uint32_t mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee; + uint32_t stackSize = 0; + + auto inventoryComponent = player->GetComponent(); + Item* item = nullptr; + + bool hasAttachment = mailInfo.itemID != 0 && mailInfo.itemCount > 0; + + if (hasAttachment) { + item = inventoryComponent->FindItemById(mailInfo.itemID); + if (item) { + mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee); + mailInfo.itemLOT = item->GetLot(); + } + } + + if (hasAttachment && !item) { + response.status = eSendResponse::AttachmentNotFound; + } else if (player->GetCharacter()->GetCoins() - mailCost < 0) { + response.status = eSendResponse::NotEnoughCoins; + } else { + bool removeSuccess = true; + // Remove coins and items from the sender + player->GetCharacter()->SetCoins(player->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL); + if (inventoryComponent && hasAttachment && item) { + removeSuccess = inventoryComponent->RemoveItem(mailInfo.itemLOT, mailInfo.itemCount, INVALID, true); + auto* missionComponent = player->GetComponent(); + if (missionComponent && removeSuccess) missionComponent->Progress(eMissionTaskType::GATHER, mailInfo.itemLOT, LWOOBJID_EMPTY, "", -mailInfo.itemCount); + } + + // we passed all the checks, now we can actully send the mail + if (removeSuccess) { + mailInfo.senderId = character->GetID(); + mailInfo.senderUsername = character->GetName(); + mailInfo.receiverId = receiverID->id; + mailInfo.itemSubkey = LWOOBJID_EMPTY; + + //clear out the attachementID + mailInfo.itemID = 0; + + Database::Get()->InsertNewMail(mailInfo); + response.status = eSendResponse::Success; + character->SaveXMLToDatabase(); + } else { + response.status = eSendResponse::AttachmentNotFound; + } + } } - } - - //Check if we can even send this mail (negative coins bug): - if (player->GetCharacter()->GetCoins() - mailCost < 0) { - SendResponse(eSendResponse::NotEnoughCoins).Send(sysAddr); - return; - } - - //Get the receiver's id: - auto receiverID = Database::Get()->GetCharacterInfo(mailInfo.recipient); - - if (!receiverID) { - SendResponse(Mail::eSendResponse::RecipientNotFound).Send(sysAddr); - return; - } - - //Check if we have a valid receiver: - if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) { - SendResponse(Mail::eSendResponse::CannotMailSelf).Send(sysAddr); - return; } else { - Database::Get()->InsertNewMail(mailInfo); + response.status = eSendResponse::SenderAccountIsMuted; } - - SendResponse(Mail::eSendResponse::Success).Send(sysAddr); - player->GetCharacter()->SetCoins(player->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL); - - LOG("Seeing if we need to remove item with ID/count/LOT: %i %i %i", mailInfo.itemID, mailInfo.itemCount, mailInfo.itemLOT); - - if (inv && mailInfo.itemLOT != 0 && mailInfo.itemCount > 0 && item) { - LOG("Trying to remove item with ID/count/LOT: %i %i %i", mailInfo.itemID, mailInfo.itemCount, mailInfo.itemLOT); - inv->RemoveItem(mailInfo.itemLOT, mailInfo.itemCount, INVALID, true); - - auto* missionCompoent = player->GetComponent(); - - if (missionCompoent != nullptr) { - missionCompoent->Progress(eMissionTaskType::GATHER, mailInfo.itemLOT, LWOOBJID_EMPTY, "", -mailInfo.itemCount); - } - } - - character->SaveXMLToDatabase(); + response.Send(sysAddr); } void SendResponse::Serialize(RakNet::BitStream& bitStream) const { MailLUBitStream::Serialize(bitStream); - bitStream.Write(response); + bitStream.Write(status); } void NotificationResponse::Serialize(RakNet::BitStream& bitStream) const { MailLUBitStream::Serialize(bitStream); - LOG("notification: %s", StringifiedEnum::ToString(notification).data()); - bitStream.Write(notification); + bitStream.Write(status); bitStream.Write(0); // unused bitStream.Write(0); // unused - LOG("auctionID: %llu", auctionID); bitStream.Write(auctionID); bitStream.Write(0); // unused - LOG("mailCount: %i", mailCount); bitStream.Write(mailCount); + bitStream.Write(0); // packing } void DataRequest::Handle() { - LOG("DataRequest::Handle()"); auto playerMail = Database::Get()->GetMailForPlayer(static_cast(player->GetObjectID()), 20); - LOG("DataRequest::Handle() - Got %i mail", playerMail.size()); DataResponse response; response.playerMail = playerMail; response.Send(sysAddr); @@ -183,10 +160,8 @@ namespace Mail { void DataResponse::Serialize(RakNet::BitStream& bitStream) const { MailLUBitStream::Serialize(bitStream); - LOG("throtttled: %i", throttled); bitStream.Write(this->throttled); - LOG("playerMail.size(): %i", this->playerMail.size()); bitStream.Write(this->playerMail.size()); bitStream.Write(0); // packing for (const auto& mail : this->playerMail) { @@ -195,32 +170,30 @@ namespace Mail { } bool AttachmentCollectRequest::Deserialize(RakNet::BitStream& bitStream) { + uint32_t unknown; + VALIDATE_READ(bitStream.Read(unknown)); VALIDATE_READ(bitStream.Read(mailID)); VALIDATE_READ(bitStream.Read(playerID)); return true; } void AttachmentCollectRequest::Handle() { - if (mailID > 0 && playerID == player->GetObjectID()) { + auto response = AttachmentCollectResponse(eAttachmentCollectResponse::UnknownError); + auto inv = player->GetComponent(); + + if (mailID > 0 && playerID == player->GetObjectID() && inv) { auto playerMail = Database::Get()->GetMail(mailID); - - LOT attachmentLOT = 0; - uint32_t attachmentCount = 0; - - if (playerMail) { - attachmentLOT = playerMail->itemLOT; - attachmentCount = playerMail->itemCount; + if (!playerMail) { + response.status = eAttachmentCollectResponse::MailNotFound; + } else if (!inv->HasSpaceForLoot({ {playerMail->itemLOT, playerMail->itemCount} })) { + response.status = eAttachmentCollectResponse::NoSpaceInInventory; + } else { + inv->AddItem(playerMail->itemLOT, playerMail->itemCount, eLootSourceType::MAIL); + Database::Get()->ClaimMailItem(mailID); + response.status = eAttachmentCollectResponse::Success; } - - auto inv = player->GetComponent(); - if (!inv) return; - - inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL); - - Database::Get()->ClaimMailItem(mailID); - - AttachmentCollectResponse(eRemoveAttachmentResponse::Success, mailID).Send(sysAddr); } + response.Send(sysAddr); } void AttachmentCollectResponse::Serialize(RakNet::BitStream& bitStream) const { @@ -230,16 +203,24 @@ namespace Mail { } bool DeleteRequest::Deserialize(RakNet::BitStream& bitStream) { + int32_t unknown; + VALIDATE_READ(bitStream.Read(unknown)); VALIDATE_READ(bitStream.Read(mailID)); VALIDATE_READ(bitStream.Read(playerID)); return true; } void DeleteRequest::Handle() { - DeleteResponse response(mailID); - if (mailID > 0) { + auto response = DeleteResponse(mailID); + + auto mailData = Database::Get()->GetMail(mailID); + if (mailData && !(mailData->itemLOT != 0 && mailData->itemCount > 0)) { Database::Get()->DeleteMail(mailID); response.status = eDeleteResponse::Success; + } else if (mailData && mailData->itemLOT != 0 && mailData->itemCount > 0) { + response.status = eDeleteResponse::HasAttachments; + } else { + response.status = eDeleteResponse::NotFound; } response.Send(sysAddr); } @@ -258,12 +239,12 @@ namespace Mail { } void ReadRequest::Handle() { - ReadResponse response; - response.mailID = mailID; - response.status = eReadResponse::Success; + auto response = ReadResponse(mailID); - if (mailID > 0) Database::Get()->MarkMailRead(mailID); - else response.status = eReadResponse::UnknownError; + if (Database::Get()->GetMail(mailID)) { + response.status = eReadResponse::Success; + Database::Get()->MarkMailRead(mailID); + } response.Send(sysAddr); } @@ -274,14 +255,14 @@ namespace Mail { } void NotificationRequest::Handle() { + auto response = NotificationResponse(eNotificationResponse::UnknownError); auto character = player->GetCharacter(); - if (!character) { - NotificationResponse(eNotificationResponse::UnknownError, 0).Send(sysAddr); - return; + if (character) { + auto unreadMailCount = Database::Get()->GetUnreadMailCount(character->GetID()); + response.status = eNotificationResponse::NewMail; + response.mailCount = unreadMailCount; } - - auto unreadMailCount = Database::Get()->GetUnreadMailCount(character->GetID()); - if (unreadMailCount > 0) NotificationResponse(eNotificationResponse::NewMail, unreadMailCount).Send(sysAddr); + response.Send(sysAddr); } } diff --git a/dGame/dUtilities/Mail.h b/dGame/dUtilities/Mail.h index ab60c201..2ca5d3b9 100644 --- a/dGame/dUtilities/Mail.h +++ b/dGame/dUtilities/Mail.h @@ -55,13 +55,13 @@ namespace Mail { enum class eDeleteResponse : uint32_t { Success = 0, - HasAttachements, + HasAttachments, NotFound, Throttled, UnknownError }; - enum class eRemoveAttachmentResponse : uint32_t { + enum class eAttachmentCollectResponse : uint32_t { Success = 0, AttachmentNotFound, NoSpaceInInventory, @@ -87,6 +87,22 @@ namespace Mail { UnknownError }; + enum class eAuctionCreateResponse : uint32_t { + Success = 0, + NotEnoughMoney, + ItemNotFound, + ItemNotSellable, + UnknownError + }; + + enum class eAuctionCancelResponse : uint32_t { + NotFound = 0, + NotYours, + HasBid, + NoLongerExists, + UnknownError + }; + struct MailLUBitStream : public LUBitStream { eMessageID messageID = eMessageID::UnknownError; SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; @@ -108,18 +124,18 @@ namespace Mail { }; struct SendResponse :public MailLUBitStream { - eSendResponse response = eSendResponse::UnknownError; + eSendResponse status = eSendResponse::UnknownError; - SendResponse(eSendResponse _response) : MailLUBitStream(eMessageID::SendResponse), response{_response} {}; + SendResponse(eSendResponse _status) : MailLUBitStream(eMessageID::SendResponse), status{_status} {}; void Serialize(RakNet::BitStream& bitStream) const override; }; struct NotificationResponse : public MailLUBitStream { - eNotificationResponse notification = eNotificationResponse::UnknownError; + eNotificationResponse status = eNotificationResponse::UnknownError; LWOOBJID auctionID = LWOOBJID_EMPTY; uint32_t mailCount = 1; - NotificationResponse(eNotificationResponse _notification) : MailLUBitStream(eMessageID::NotificationResponse), notification{_notification} {}; - NotificationResponse(eNotificationResponse _notification, uint32_t _mailCount) : MailLUBitStream(eMessageID::NotificationResponse), notification{_notification}, mailCount{_mailCount} {}; + NotificationResponse(eNotificationResponse _status) : MailLUBitStream(eMessageID::NotificationResponse), status{_status} {}; + NotificationResponse(eNotificationResponse _status, uint32_t _mailCount) : MailLUBitStream(eMessageID::NotificationResponse), status{_status}, mailCount{_mailCount} {}; void Serialize(RakNet::BitStream& bitStream) const override; }; @@ -132,7 +148,7 @@ namespace Mail { uint32_t throttled = 0; std::vector playerMail; - DataResponse() : MailLUBitStream(eMessageID::DataRequest) {}; + DataResponse() : MailLUBitStream(eMessageID::DataResponse) {}; void Serialize(RakNet::BitStream& bitStream) const override; }; @@ -147,10 +163,10 @@ namespace Mail { }; struct AttachmentCollectResponse : public MailLUBitStream { - eRemoveAttachmentResponse status = eRemoveAttachmentResponse::UnknownError; + eAttachmentCollectResponse status = eAttachmentCollectResponse::UnknownError; uint64_t mailID = 0; - - AttachmentCollectResponse(eRemoveAttachmentResponse _status, uint64_t _mailID) : MailLUBitStream(eMessageID::AttachmentCollectResponse), status{_status}, mailID{_mailID} {}; + AttachmentCollectResponse(eAttachmentCollectResponse _status) : MailLUBitStream(eMessageID::AttachmentCollectResponse), status{_status} {}; + AttachmentCollectResponse(eAttachmentCollectResponse _status, uint64_t _mailID) : MailLUBitStream(eMessageID::AttachmentCollectResponse), status{_status}, mailID{_mailID} {}; void Serialize(RakNet::BitStream& bitStream) const override; }; @@ -168,6 +184,7 @@ namespace Mail { eDeleteResponse status = eDeleteResponse::UnknownError; uint64_t mailID = 0; DeleteResponse(uint64_t _mailID) : MailLUBitStream(eMessageID::DeleteResponse), mailID{_mailID} {}; + DeleteResponse(eDeleteResponse _status, uint64_t _mailID) : MailLUBitStream(eMessageID::DeleteResponse), status{_status}, mailID{_mailID} {}; void Serialize(RakNet::BitStream& bitStream) const override; }; @@ -184,6 +201,7 @@ namespace Mail { eReadResponse status = eReadResponse::UnknownError; ReadResponse() : MailLUBitStream(eMessageID::ReadResponse) {}; + ReadResponse(uint64_t _mailID) : MailLUBitStream(eMessageID::ReadResponse), mailID{_mailID} {}; void Serialize(RakNet::BitStream& bitStream) const override; }; diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index becdcdd4..da7da945 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -996,7 +996,7 @@ void SlashCommandHandler::Startup() { Command RequestMailCountCommand{ .help = "Gets the players mail count", .info = "Sends notification with number of unread messages in the player's mailbox", - .aliases = { "requestmailcount" }, + .aliases = { "requestmailcount", "checkmail" }, .handle = GMZeroCommands::RequestMailCount, .requiredLevel = eGameMasterLevel::CIVILIAN }; diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index fcac8143..89ecef05 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -348,7 +348,7 @@ int main(int argc, char** argv) { StartChatServer(); Game::im->GetInstance(0, false, 0); - Game::im->GetInstance(1100, false, 0); + Game::im->GetInstance(1000, false, 0); StartAuthServer(); } diff --git a/dNet/BitStreamUtils.cpp b/dNet/BitStreamUtils.cpp index 8fc5d20d..047a1227 100644 --- a/dNet/BitStreamUtils.cpp +++ b/dNet/BitStreamUtils.cpp @@ -26,7 +26,5 @@ void LUBitStream::Send(const SystemAddress& sysAddr) const { RakNet::BitStream bitStream; this->WriteHeader(bitStream); this->Serialize(bitStream); - LOG("%s", sysAddr.ToString(true)); - PacketUtils::SavePacket("mailv2", reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); Game::server->Send(bitStream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dNet/MailInfo.cpp b/dNet/MailInfo.cpp index 6ca1de47..335b4643 100644 --- a/dNet/MailInfo.cpp +++ b/dNet/MailInfo.cpp @@ -3,33 +3,26 @@ #include "DluAssert.h" void MailInfo::Serialize(RakNet::BitStream& bitStream) const { - LOG("Writing MailInfo"); - LOG("ID: %llu", id); bitStream.Write(id); - LOG("Subject: %s", subject.c_str()); const LUWString subject(this->subject, 50); bitStream.Write(subject); - LOG("Body: %s", body.c_str()); const LUWString body(this->body, 400); bitStream.Write(body); - LOG("Sender: %s", senderUsername.c_str()); const LUWString sender(this->senderUsername, 32); bitStream.Write(sender); bitStream.Write(0); // packing bitStream.Write(0); // attachedCurrency - LOG("ItemID: %llu", itemID); bitStream.Write(itemID); LOT lot = itemLOT; - LOG("ItemLOT: %u", lot); if (lot <= 0) bitStream.Write(LOT_NULL); else bitStream.Write(lot); bitStream.Write(0); // packing bitStream.Write(itemSubkey); - bitStream.Write(itemCount); + bitStream.Write(itemCount); bitStream.Write(0); // subject type (used for auction) bitStream.Write(0); // packing bitStream.Write(0); // packing @@ -39,13 +32,11 @@ void MailInfo::Serialize(RakNet::BitStream& bitStream) const { bitStream.Write(wasRead); // was read bitStream.Write(0); // isLocalized - bitStream.Write(0); // packing + bitStream.Write(1033); // language code bitStream.Write(0); // packing } bool MailInfo::Deserialize(RakNet::BitStream& bitStream) { - VALIDATE_READ(bitStream.Read(id)); - LUWString subject(50); VALIDATE_READ(bitStream.Read(subject)); this->subject = subject.GetAsString(); @@ -54,36 +45,17 @@ bool MailInfo::Deserialize(RakNet::BitStream& bitStream) { VALIDATE_READ(bitStream.Read(body)); this->body = body.GetAsString(); - LUWString sender(32); - VALIDATE_READ(bitStream.Read(sender)); - this->senderUsername = sender.GetAsString(); + LUWString recipientName(32); + VALIDATE_READ(bitStream.Read(recipientName)); + this->recipient = recipientName.GetAsString(); - bitStream.IgnoreBytes(4); // packing + uint64_t unknown; + VALIDATE_READ(bitStream.Read(unknown)); - bitStream.IgnoreBytes(8); // attachedCurrency VALIDATE_READ(bitStream.Read(itemID)); - - LOT lot; - VALIDATE_READ(bitStream.Read(lot)); - if (lot == LOT_NULL) itemLOT = 0; - else itemLOT = lot; - bitStream.IgnoreBytes(4); // packing - - VALIDATE_READ(bitStream.Read(itemSubkey)); - VALIDATE_READ(bitStream.Read(itemCount)); - - bitStream.IgnoreBytes(1); // subject type (used for auction) - bitStream.IgnoreBytes(1); // packing - bitStream.IgnoreBytes(4); // packing - - VALIDATE_READ(bitStream.Read(timeSent)); // expiration date - VALIDATE_READ(bitStream.Read(timeSent)); // send date - VALIDATE_READ(bitStream.Read(wasRead)); // was read - - bitStream.IgnoreBytes(1); // isLocalized - bitStream.IgnoreBytes(2); // packing - bitStream.IgnoreBytes(4); // packing + VALIDATE_READ(bitStream.Read(languageCode)); + bitStream.IgnoreBytes(4); // padding DluAssert(bitStream.GetNumberOfUnreadBits() == 0); diff --git a/dNet/MailInfo.h b/dNet/MailInfo.h index 2159c071..c74eee87 100644 --- a/dNet/MailInfo.h +++ b/dNet/MailInfo.h @@ -19,9 +19,10 @@ struct MailInfo { uint32_t receiverId{}; uint64_t timeSent{}; bool wasRead{}; + uint16_t languageCode{}; struct { LWOOBJID itemID{}; - int32_t itemCount{}; + int16_t itemCount{}; LOT itemLOT{}; LWOOBJID itemSubkey{}; };