From 7b1d6948c39ae5f4c4b798ed0cc62cca01807b07 Mon Sep 17 00:00:00 2001 From: Aaron Kimbre Date: Sun, 19 Jan 2025 00:25:20 -0600 Subject: [PATCH] Overaul, need to test --- dCommon/dEnums/eConnectionType.h | 3 +- dDatabase/GameDatabase/ITables/IMail.h | 23 +- dDatabase/GameDatabase/MySQL/MySQLDatabase.h | 6 +- dDatabase/GameDatabase/MySQL/Tables/Mail.cpp | 13 +- .../GameDatabase/SQLite/SQLiteDatabase.h | 6 +- dDatabase/GameDatabase/SQLite/Tables/Mail.cpp | 12 +- .../GameDatabase/TestSQL/TestSQLDatabase.cpp | 6 +- .../GameDatabase/TestSQL/TestSQLDatabase.h | 6 +- dGame/dComponents/CharacterComponent.cpp | 2 +- dGame/dComponents/InventoryComponent.cpp | 2 +- dGame/dUtilities/Mail.cpp | 525 +++++++++--------- dGame/dUtilities/Mail.h | 304 ++++------ .../GMGreaterThanZeroCommands.cpp | 2 +- dNet/BitStreamUtils.cpp | 29 + dNet/BitStreamUtils.h | 79 +-- dNet/CMakeLists.txt | 1 + dNet/MailInfo.cpp | 87 +++ dNet/MailInfo.h | 33 ++ dWorldServer/WorldServer.cpp | 19 +- 19 files changed, 592 insertions(+), 566 deletions(-) create mode 100644 dNet/BitStreamUtils.cpp create mode 100644 dNet/MailInfo.cpp create mode 100644 dNet/MailInfo.h diff --git a/dCommon/dEnums/eConnectionType.h b/dCommon/dEnums/eConnectionType.h index 406110a9e..ed75e1003 100644 --- a/dCommon/dEnums/eConnectionType.h +++ b/dCommon/dEnums/eConnectionType.h @@ -7,7 +7,8 @@ enum class eConnectionType : uint16_t { CHAT, WORLD = 4, CLIENT, - MASTER + MASTER, + UNKNOWN }; #endif //!__ECONNECTIONTYPE__H__ diff --git a/dDatabase/GameDatabase/ITables/IMail.h b/dDatabase/GameDatabase/ITables/IMail.h index 7fbc8230d..e77f9fa22 100644 --- a/dDatabase/GameDatabase/ITables/IMail.h +++ b/dDatabase/GameDatabase/ITables/IMail.h @@ -8,27 +8,14 @@ #include "dCommonVars.h" #include "NiQuaternion.h" #include "NiPoint3.h" +#include "MailInfo.h" + +namespace RakNet { + class BitStream; +} class IMail { public: - struct MailInfo { - std::string senderUsername; - std::string recipient; - std::string subject; - std::string body; - uint64_t id{}; - uint32_t senderId{}; - uint32_t receiverId{}; - uint64_t timeSent{}; - bool wasRead{}; - struct { - LWOOBJID itemID{}; - int32_t itemCount{}; - LOT itemLOT{}; - LWOOBJID itemSubkey{}; - }; - }; - // Insert a new mail into the database. virtual void InsertNewMail(const MailInfo& mail) = 0; diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index 081681411..dbaf23f83 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -79,14 +79,14 @@ class MySQLDatabase : public GameDatabase { void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; void InsertNewBugReport(const IBugReports::Info& info) override; void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override; - void InsertNewMail(const IMail::MailInfo& mail) override; + void InsertNewMail(const MailInfo& mail) override; void InsertNewUgcModel( std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) override; - std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; - std::optional GetMail(const uint64_t mailId) override; + std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; + std::optional GetMail(const uint64_t mailId) override; uint32_t GetUnreadMailCount(const uint32_t characterId) override; void MarkMailRead(const uint64_t mailId) override; void DeleteMail(const uint64_t mailId) override; diff --git a/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp index 63f5ceca3..74acb54f6 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/Mail.cpp @@ -1,6 +1,7 @@ #include "MySQLDatabase.h" -void MySQLDatabase::InsertNewMail(const IMail::MailInfo& mail) { + +void MySQLDatabase::InsertNewMail(const MailInfo& mail) { ExecuteInsert( "INSERT INTO `mail` " "(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`)" @@ -18,17 +19,17 @@ void MySQLDatabase::InsertNewMail(const IMail::MailInfo& mail) { mail.itemCount); } -std::vector MySQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { +std::vector MySQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { auto res = ExecuteSelect( "SELECT id, subject, body, sender_name, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read, time_sent" " FROM mail WHERE receiver_id=? limit ?;", characterId, numberOfMail); - std::vector toReturn; + std::vector toReturn; toReturn.reserve(res->rowsCount()); while (res->next()) { - IMail::MailInfo mail; + MailInfo mail; mail.id = res->getUInt64("id"); mail.subject = res->getString("subject").c_str(); mail.body = res->getString("body").c_str(); @@ -46,14 +47,14 @@ std::vector MySQLDatabase::GetMailForPlayer(const uint32_t char return toReturn; } -std::optional MySQLDatabase::GetMail(const uint64_t mailId) { +std::optional MySQLDatabase::GetMail(const uint64_t mailId) { auto res = ExecuteSelect("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;", mailId); if (!res->next()) { return std::nullopt; } - IMail::MailInfo toReturn; + MailInfo toReturn; toReturn.itemLOT = res->getInt("attachment_lot"); toReturn.itemCount = res->getInt("attachment_count"); diff --git a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h index a09c72c9f..8ef06eb51 100644 --- a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h +++ b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h @@ -77,14 +77,14 @@ class SQLiteDatabase : public GameDatabase { void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; void InsertNewBugReport(const IBugReports::Info& info) override; void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override; - void InsertNewMail(const IMail::MailInfo& mail) override; + void InsertNewMail(const MailInfo& mail) override; void InsertNewUgcModel( std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) override; - std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; - std::optional GetMail(const uint64_t mailId) override; + std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; + std::optional GetMail(const uint64_t mailId) override; uint32_t GetUnreadMailCount(const uint32_t characterId) override; void MarkMailRead(const uint64_t mailId) override; void DeleteMail(const uint64_t mailId) override; diff --git a/dDatabase/GameDatabase/SQLite/Tables/Mail.cpp b/dDatabase/GameDatabase/SQLite/Tables/Mail.cpp index 48c1e320d..edd4b672f 100644 --- a/dDatabase/GameDatabase/SQLite/Tables/Mail.cpp +++ b/dDatabase/GameDatabase/SQLite/Tables/Mail.cpp @@ -1,6 +1,6 @@ #include "SQLiteDatabase.h" -void SQLiteDatabase::InsertNewMail(const IMail::MailInfo& mail) { +void SQLiteDatabase::InsertNewMail(const MailInfo& mail) { ExecuteInsert( "INSERT INTO `mail` " "(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`)" @@ -18,16 +18,16 @@ void SQLiteDatabase::InsertNewMail(const IMail::MailInfo& mail) { mail.itemCount); } -std::vector SQLiteDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { +std::vector SQLiteDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { auto [_, res] = ExecuteSelect( "SELECT id, subject, body, sender_name, attachment_id, attachment_lot, attachment_subkey, attachment_count, was_read, time_sent" " FROM mail WHERE receiver_id=? limit ?;", characterId, numberOfMail); - std::vector toReturn; + std::vector toReturn; while (!res.eof()) { - IMail::MailInfo mail; + MailInfo mail; mail.id = res.getInt64Field("id"); mail.subject = res.getStringField("subject"); mail.body = res.getStringField("body"); @@ -46,14 +46,14 @@ std::vector SQLiteDatabase::GetMailForPlayer(const uint32_t cha return toReturn; } -std::optional SQLiteDatabase::GetMail(const uint64_t mailId) { +std::optional SQLiteDatabase::GetMail(const uint64_t mailId) { auto [_, res] = ExecuteSelect("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;", mailId); if (res.eof()) { return std::nullopt; } - IMail::MailInfo toReturn; + MailInfo toReturn; toReturn.itemLOT = res.getIntField("attachment_lot"); toReturn.itemCount = res.getIntField("attachment_count"); diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp index 0263a6e39..20fd942eb 100644 --- a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp @@ -184,7 +184,7 @@ void TestSQLDatabase::InsertCheatDetection(const IPlayerCheatDetections::Info& i } -void TestSQLDatabase::InsertNewMail(const IMail::MailInfo& mail) { +void TestSQLDatabase::InsertNewMail(const MailInfo& mail) { } @@ -192,11 +192,11 @@ void TestSQLDatabase::InsertNewUgcModel(std::istringstream& sd0Data, const uint3 } -std::vector TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { +std::vector TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { return {}; } -std::optional TestSQLDatabase::GetMail(const uint64_t mailId) { +std::optional TestSQLDatabase::GetMail(const uint64_t mailId) { return {}; } diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h index 9d4b184f0..70e870561 100644 --- a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h @@ -56,14 +56,14 @@ class TestSQLDatabase : public GameDatabase { void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; void InsertNewBugReport(const IBugReports::Info& info) override; void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override; - void InsertNewMail(const IMail::MailInfo& mail) override; + void InsertNewMail(const MailInfo& mail) override; void InsertNewUgcModel( std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) override; - std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; - std::optional GetMail(const uint64_t mailId) override; + std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; + std::optional GetMail(const uint64_t mailId) override; uint32_t GetUnreadMailCount(const uint32_t characterId) override; void MarkMailRead(const uint64_t mailId) override; void DeleteMail(const uint64_t mailId) override; diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index d706af9c2..9f711068f 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -786,7 +786,7 @@ void CharacterComponent::AwardClaimCodes() { subject << "%[RewardCodes_" << rewardCode << "_subjectText]"; std::ostringstream body; body << "%[RewardCodes_" << rewardCode << "_bodyText]"; - Mail::SendMail(LWOOBJID_EMPTY, "%[MAIL_SYSTEM_NOTIFICATION]", m_Parent, subject.str(), body.str(), attachmentLOT, 1); + Mail::SendMail(m_Parent, subject.str(), body.str(), attachmentLOT, 1); } } diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index aa7614aaf..4e49abff4 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -274,7 +274,7 @@ void InventoryComponent::AddItem( switch (sourceType) { case 0: - Mail::SendMail(LWOOBJID_EMPTY, "Darkflame Universe", m_Parent, "Lost Reward", "You received an item and didn't have room for it.", lot, size); + Mail::SendMail(m_Parent, "%[MAIL_ACTIVITY_OVERFLOW_HEADER]", "%[MAIL_ACTIVITY_OVERFLOW_BODY]", lot, size); break; case 1: diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index f333851d0..c4c39e49a 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -26,12 +26,280 @@ #include "eMissionTaskType.h" #include "eReplicaComponentType.h" #include "eConnectionType.h" +#include "User.h" +#include "StringifiedEnum.h" + +namespace { + const std::string DefaultSender = "%[MAIL_SYSTEM_NOTIFICATION]"; +} + +namespace Mail { + std::map(const SystemAddress&, Entity* const)>> handlers = { + {eMessageID::SendRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + {eMessageID::DataRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + {eMessageID::AttachmentCollectRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + {eMessageID::DeleteRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + {eMessageID::ReadRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + {eMessageID::NotificationRequest, [](const SystemAddress& sysAddr, Entity* const player) { + return std::make_unique(); + }}, + }; + + void MailLUBitStream::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(messageID); + } + + bool MailLUBitStream::Deserialize(RakNet::BitStream& bitstream) { + VALIDATE_READ(bitstream.Read(messageID)); + return true; + } + + bool SendRequest::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(mailInfo.Deserialize(bitStream)); + return true; + } + + 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 + auto* character = player->GetCharacter(); + + 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(); + } else { + SendResponse(eSendResponse::AttachmentNotFound).Send(sysAddr); + return; + } + } + + //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); + } + + 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(); + } + + void SendResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + bitStream.Write(response); + } + + void NotificationResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + bitStream.Write(notification); + bitStream.Write(0); // unused + bitStream.Write(0); // unused + bitStream.Write(auctionID); + bitStream.Write(0); // unused + bitStream.Write(mailCount); + } + + void DataRequest::Handle() { + auto playerMail = Database::Get()->GetMailForPlayer(player->GetObjectID()); + + if (playerMail.size() > 0) { + DataResponse response; + response.playerMail = playerMail; + response.Send(sysAddr); + } + } + + void DataResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + + bitStream.Write(this->throttled); + bitStream.Write(this->playerMail.size()); + bitStream.Write(0); // packing + for (const auto& mail : this->playerMail) { + mail.Serialize(bitStream); + } + } + + bool AttachmentCollectRequest::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(mailID)); + VALIDATE_READ(bitStream.Read(playerID)); + return true; + } + + void AttachmentCollectRequest::Handle() { + if (mailID > 0 && playerID == player->GetObjectID()) { + auto playerMail = Database::Get()->GetMail(mailID); + + LOT attachmentLOT = 0; + uint32_t attachmentCount = 0; + + if (playerMail) { + attachmentLOT = playerMail->itemLOT; + attachmentCount = playerMail->itemCount; + } + + auto inv = player->GetComponent(); + if (!inv) return; + + inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL); + + Database::Get()->ClaimMailItem(mailID); + + AttachmentCollectResponse(eRemoveAttachmentResponse::Success, mailID).Send(sysAddr); + } + } + + void AttachmentCollectResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + bitStream.Write(status); + bitStream.Write(mailID); + } + + bool DeleteRequest::Deserialize(RakNet::BitStream& bitStream) { + VALIDATE_READ(bitStream.Read(mailID)); + VALIDATE_READ(bitStream.Read(playerID)); + return true; + } + + void DeleteRequest::Handle() { + DeleteResponse response(mailID); + if (mailID > 0) { + Database::Get()->DeleteMail(mailID); + response.status = eDeleteResponse::Success; + } + response.Send(sysAddr); + } + + void DeleteResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + bitStream.Write(status); + bitStream.Write(mailID); + } + + bool ReadRequest::Deserialize(RakNet::BitStream& bitStream) { + int32_t unknown; + VALIDATE_READ(bitStream.Read(unknown)); + VALIDATE_READ(bitStream.Read(mailID)); + return true; + } + + void ReadRequest::Handle() { + ReadResponse response; + response.mailID = mailID; + response.status = eReadResponse::Success; + + if (mailID > 0) Database::Get()->MarkMailRead(mailID); + else response.status = eReadResponse::UnknownError; + response.Send(sysAddr); + } + + void ReadResponse::Serialize(RakNet::BitStream& bitStream) const { + MailLUBitStream::Serialize(bitStream); + bitStream.Write(status); + bitStream.Write(mailID); + } + + void NotificationRequest::Handle() { + auto unreadMailCount = Database::Get()->GetUnreadMailCount(player->GetObjectID()); + if (unreadMailCount > 0) NotificationResponse(eNotificationResponse::NewMail, unreadMailCount).Send(sysAddr); + } +} + +// Non Stuct Functions +void Mail::HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player) { + MailLUBitStream data; + if (!data.Deserialize(inStream)) { + LOG_DEBUG("Error Reading Mail header"); + return; + } + + auto it = handlers.find(data.messageID); + if (it != handlers.end()) { + auto mail_data = it->second(sysAddr, player); + if (!mail_data->Deserialize(inStream)) { + LOG_DEBUG("Error Reading Mail Data"); + return; + } + mail_data->Handle(); + } else { + LOG_DEBUG("Unhandled Mail Packet with ID: %i", data.messageID); + } +} void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment, const uint16_t attachmentCount) { SendMail( LWOOBJID_EMPTY, - ServerName, + DefaultSender, recipient->GetObjectID(), recipient->GetCharacter()->GetName(), subject, @@ -46,7 +314,7 @@ void Mail::SendMail(const LWOOBJID recipient, const std::string& recipientName, const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) { SendMail( LWOOBJID_EMPTY, - ServerName, + DefaultSender, recipient, recipientName, subject, @@ -75,7 +343,7 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, const void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJID recipient, const std::string& recipientName, const std::string& subject, const std::string& body, const LOT attachment, const uint16_t attachmentCount, const SystemAddress& sysAddr) { - IMail::MailInfo mailInsert; + MailInfo mailInsert; mailInsert.senderUsername = senderName; mailInsert.recipient = recipientName; mailInsert.subject = subject; @@ -91,254 +359,5 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server - SendNotification(sysAddr, 1); //Show the "one new mail" message -} - -void Mail::HandleMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) { - int mailStuffID = 0; - packet.Read(mailStuffID); - - auto returnVal = std::async(std::launch::async, [&packet, &sysAddr, entity, mailStuffID]() { - Mail::MailMessageID stuffID = MailMessageID(mailStuffID); - switch (stuffID) { - case MailMessageID::AttachmentCollect: - Mail::HandleAttachmentCollect(packet, sysAddr, entity); - break; - case MailMessageID::DataRequest: - Mail::HandleDataRequest(packet, sysAddr, entity); - break; - case MailMessageID::MailDelete: - Mail::HandleMailDelete(packet, sysAddr); - break; - case MailMessageID::MailRead: - Mail::HandleMailRead(packet, sysAddr); - break; - case MailMessageID::NotificationRequest: - Mail::HandleNotificationRequest(sysAddr, entity->GetObjectID()); - break; - case MailMessageID::Send: - Mail::HandleSendMail(packet, sysAddr, entity); - break; - default: - LOG("Unhandled and possibly undefined MailStuffID: %i", int(stuffID)); - } - }); -} - -void Mail::HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) { - //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 - auto* character = entity->GetCharacter(); - - if (!character) return; - - if (character->HasPermission(ePermissionMap::RestrictedMailAccess)) { - // Send a message to the player - ChatPackets::SendSystemMessage( - sysAddr, - u"This character has restricted mail access." - ); - - Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::SenderAccountIsMuted); - - return; - } - - LUWString subjectRead(50); - packet.Read(subjectRead); - - LUWString bodyRead(400); - packet.Read(bodyRead); - - LUWString recipientRead(32); - packet.Read(recipientRead); - - const std::string subject = subjectRead.GetAsString(); - const std::string body = bodyRead.GetAsString(); - - //Cleanse recipient: - const std::string recipient = std::regex_replace(recipientRead.GetAsString(), std::regex("[^0-9a-zA-Z]+"), ""); - - uint64_t unknown64 = 0; - LWOOBJID attachmentID; - uint16_t attachmentCount; - - packet.Read(unknown64); - packet.Read(attachmentID); - packet.Read(attachmentCount); //We don't care about the rest of the packet. - uint32_t itemID = static_cast(attachmentID); - LOT itemLOT = 0; - //Inventory::InventoryType itemType; - int mailCost = Game::zoneManager->GetWorldConfig()->mailBaseFee; - int stackSize = 0; - auto inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); - Item* item = nullptr; - - if (itemID > 0 && attachmentCount > 0 && inv) { - item = inv->FindItemById(attachmentID); - if (item) { - mailCost += (item->GetInfo().baseValue * Game::zoneManager->GetWorldConfig()->mailPercentAttachmentFee); - stackSize = item->GetCount(); - itemLOT = item->GetLot(); - } else { - Mail::SendSendResponse(sysAddr, MailSendResponse::AttachmentNotFound); - return; - } - } - - //Check if we can even send this mail (negative coins bug): - if (entity->GetCharacter()->GetCoins() - mailCost < 0) { - Mail::SendSendResponse(sysAddr, MailSendResponse::NotEnoughCoins); - return; - } - - //Get the receiver's id: - auto receiverID = Database::Get()->GetCharacterInfo(recipient); - - if (!receiverID) { - Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound); - return; - } - - //Check if we have a valid receiver: - if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID->id == character->GetID()) { - Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf); - return; - } else { - IMail::MailInfo mailInsert; - mailInsert.senderUsername = character->GetName(); - mailInsert.recipient = recipient; - mailInsert.subject = subject; - mailInsert.body = body; - mailInsert.senderId = character->GetID(); - mailInsert.receiverId = receiverID->id; - mailInsert.itemCount = attachmentCount; - mailInsert.itemID = itemID; - mailInsert.itemLOT = itemLOT; - mailInsert.itemSubkey = LWOOBJID_EMPTY; - Database::Get()->InsertNewMail(mailInsert); - } - - Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::Success); - entity->GetCharacter()->SetCoins(entity->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL); - - LOG("Seeing if we need to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT); - - if (inv && itemLOT != 0 && attachmentCount > 0 && item) { - LOG("Trying to remove item with ID/count/LOT: %i %i %i", itemID, attachmentCount, itemLOT); - inv->RemoveItem(itemLOT, attachmentCount, INVALID, true); - - auto* missionCompoent = entity->GetComponent(); - - if (missionCompoent != nullptr) { - missionCompoent->Progress(eMissionTaskType::GATHER, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount); - } - } - - character->SaveXMLToDatabase(); -} - -void Mail::HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) { - auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20); - RakNet::BitStream bitStream; - Mail::Data data = Mail::Data(playerMail); - bitStream.Write(data); - Game::server->Send(bitStream, sysAddr, false); -} - -void Mail::HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) { - int unknown; - uint64_t mailID; - LWOOBJID playerID; - packet.Read(unknown); - packet.Read(mailID); - packet.Read(playerID); - - if (mailID > 0 && playerID == player->GetObjectID()) { - auto playerMail = Database::Get()->GetMail(mailID); - - LOT attachmentLOT = 0; - uint32_t attachmentCount = 0; - - if (playerMail) { - attachmentLOT = playerMail->itemLOT; - attachmentCount = playerMail->itemCount; - } - - auto inv = player->GetComponent(); - if (!inv) return; - - inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL); - - Mail::SendAttachmentRemoveConfirm(sysAddr, mailID); - - Database::Get()->ClaimMailItem(mailID); - } -} - -void Mail::HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr) { - int unknown; - uint64_t mailID; - LWOOBJID playerID; - packet.Read(unknown); - packet.Read(mailID); - packet.Read(playerID); - - if (mailID > 0) Mail::SendDeleteConfirm(sysAddr, mailID, playerID); -} - -void Mail::HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr) { - int unknown; - uint64_t mailID; - packet.Read(unknown); - packet.Read(mailID); - - if (mailID > 0) Mail::SendReadConfirm(sysAddr, mailID); -} - -void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) { - auto unreadMailCount = Database::Get()->GetUnreadMailCount(objectID); - - if (unreadMailCount > 0) Mail::SendNotification(sysAddr, unreadMailCount); -} - -void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) { - RakNet::BitStream bitStream; - Mail::Response data = Mail::Response(response); - bitStream.Write(data); - Game::server->Send(bitStream, sysAddr, false); -} - -void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { - RakNet::BitStream bitStream; - Mail::Notification data = Mail::Notification(MailNotification::NewMail, mailCount); - Game::server->Send(bitStream, sysAddr, false); -} - -void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) { - RakNet::BitStream bitStream; - AttachmentCollect data = AttachmentCollect(MailRemoveAttachment::Success, mailID); - bitStream.Write(data); - Game::server->Send(bitStream, sysAddr, false); -} - -void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) { - RakNet::BitStream bitStream; - DeleteMail data = DeleteMail(MailDeleteResponse::Success, mailID); - bitStream.Write(data); - Game::server->Send(bitStream, sysAddr, false); - - Database::Get()->DeleteMail(mailID); -} - -void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { - RakNet::BitStream bitStream; - Read data = Read(MailReadResponse::Success, mailID); - bitStream.Write(data); - Game::server->Send(bitStream, sysAddr, false); - - Database::Get()->MarkMailRead(mailID); + NotificationResponse(eNotificationResponse::NewMail).Send(sysAddr); } diff --git a/dGame/dUtilities/Mail.h b/dGame/dUtilities/Mail.h index 6a78f47a0..42980ce4d 100644 --- a/dGame/dUtilities/Mail.h +++ b/dGame/dUtilities/Mail.h @@ -5,25 +5,24 @@ #include "BitStream.h" #include "RakNetTypes.h" #include "dCommonVars.h" - -template -struct LUHeader; +#include "BitStreamUtils.h" +#include "MailInfo.h" class Entity; namespace Mail { - enum class MailMessageID : uint32_t { - Send = 0, + enum class eMessageID : uint32_t { + SendRequest = 0, SendResponse, - Notification, + NotificationResponse, DataRequest, - MailData, - AttachmentCollect, - AttachmentCollectConfirm, - MailDelete, - MailDeleteConfirm, - MailRead, - MailReadConfirm, + DataResponse, + AttachmentCollectRequest, + AttachmentCollectResponse, + DeleteRequest, + DeleteResponse, + ReadRequest, + ReadResponse, NotificationRequest, AuctionCreate, AuctionCreationResponse, @@ -36,7 +35,7 @@ namespace Mail { UnknownError }; - enum class MailSendResponse : uint32_t { + enum class eSendResponse : uint32_t { Success = 0, NotEnoughCoins, AttachmentNotFound, @@ -54,15 +53,15 @@ namespace Mail { UnknownError }; - enum class MailDeleteResponse : uint32_t { + enum class eDeleteResponse : uint32_t { Success = 0, HasAttachements, - NotFoud, + NotFound, Throttled, UnknownError }; - enum class MailRemoveAttachment : uint32_t { + enum class eRemoveAttachmentResponse : uint32_t { Success = 0, AttachmentNotFound, NoSpaceInInventory, @@ -71,7 +70,7 @@ namespace Mail { UnknownError }; - enum class MailNotification : uint32_t { + enum class eNotificationResponse : uint32_t { NewMail = 0, UnHandled, AuctionWon, @@ -83,106 +82,118 @@ namespace Mail { UnknownError }; - enum class MailReadResponse : uint32_t { + enum class eReadResponse : uint32_t { Success = 0, UnknownError }; - struct MailInfo { - uint64_t id; - std::string senderUsername; - std::string recipient; - std::string subject; - std::string body; - uint32_t senderId; - uint32_t receiverId; - uint32_t itemCount; - uint32_t itemID; - LOT itemLOT; - LWOOBJID itemSubkey; + struct MailLUBitStream : public LUBitStream { + eMessageID messageID = eMessageID::UnknownError; + const SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS; + Entity* const player = nullptr; + + MailLUBitStream() = default; + MailLUBitStream(eMessageID _messageID) : LUBitStream(eConnectionType::CLIENT, MessageType::Client::MAIL), messageID{_messageID} {}; + MailLUBitStream(const SystemAddress& _sysAddr, Entity* const _player) : sysAddr(_sysAddr), player(_player) {}; + + virtual void Serialize(RakNet::BitStream& bitStream) const override; + virtual bool Deserialize(RakNet::BitStream& bitStream) override; + virtual void Handle() override {}; + }; + + struct SendRequest : public MailLUBitStream { + MailInfo mailInfo; + + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle() override; + }; + + struct SendResponse :public MailLUBitStream { + eSendResponse response = eSendResponse::UnknownError; + + SendResponse(eSendResponse _response) : MailLUBitStream(eMessageID::SendResponse), response{_response} {}; + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + struct NotificationResponse : public MailLUBitStream { + eNotificationResponse notification = 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} {}; + void Serialize(RakNet::BitStream& bitStream) const override; }; - struct MailLUHeader { - LUHeader header = LUHeader(eConnectionType::CLIENT, MessageType::Client::MAIL); - MailMessageID messageID; + struct DataRequest : public MailLUBitStream { + void Handle() override; }; - struct Data { - MailLUHeader header; + struct DataResponse : public MailLUBitStream { uint32_t throttled = 0; - std::vector playerMail; + std::vector playerMail; + + DataResponse() : MailLUBitStream(eMessageID::DataRequest) {}; + void Serialize(RakNet::BitStream& bitStream) const override; - Data() = delete; - Data(std::vector mailData) { - this->header.messageID = MailMessageID::MailData; - this->playerMail = mailData; - } }; - struct Response { - MailLUHeader header; - MailSendResponse response; + struct AttachmentCollectRequest : public MailLUBitStream { + uint64_t mailID = 0; + LWOOBJID playerID = LWOOBJID_EMPTY; - Response() = delete; - Response(MailSendResponse response) { - this->header.messageID = MailMessageID::SendResponse; - this->response = response; - } + AttachmentCollectRequest() : MailLUBitStream(eMessageID::AttachmentCollectRequest) {}; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle() override; }; - struct Notification { - MailLUHeader header; - MailNotification notification; - LWOOBJID auctionID = 0; - uint32_t mailCount = 0; - - Notification() = delete; - Notification(MailNotification notification, uint32_t mailCount, LWOOBJID auctionID = LWOOBJID_EMPTY) { - this->header.messageID = MailMessageID::Notification; - this->notification = notification; - this->auctionID = auctionID; - this->mailCount = mailCount; - } + struct AttachmentCollectResponse : public MailLUBitStream { + eRemoveAttachmentResponse status = eRemoveAttachmentResponse::UnknownError; + uint64_t mailID = 0; + + AttachmentCollectResponse(eRemoveAttachmentResponse _status, uint64_t _mailID) : MailLUBitStream(eMessageID::AttachmentCollectResponse), status{_status}, mailID{_mailID} {}; + void Serialize(RakNet::BitStream& bitStream) const override; + }; + + struct DeleteRequest : public MailLUBitStream { + uint64_t mailID = 0; + LWOOBJID playerID = LWOOBJID_EMPTY; + + + DeleteRequest() : MailLUBitStream(eMessageID::DeleteRequest) {}; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle() override; }; - struct AttachmentCollect { - MailLUHeader header; - MailRemoveAttachment status; - uint64_t mailID; - - AttachmentCollect() = delete; - AttachmentCollect(MailRemoveAttachment status, uint64_t mailID) { - this->header.messageID = MailMessageID::AttachmentCollect; - this->status = status; - this->mailID = mailID; - } + struct DeleteResponse : public MailLUBitStream { + eDeleteResponse status = eDeleteResponse::UnknownError; + uint64_t mailID = 0; + DeleteResponse(uint64_t _mailID) : MailLUBitStream(eMessageID::DeleteResponse), mailID{_mailID} {}; + void Serialize(RakNet::BitStream& bitStream) const override; }; - struct DeleteMail { - MailLUHeader header; - MailDeleteResponse status; - uint64_t mailID; + struct ReadRequest : public MailLUBitStream { + uint64_t mailID = 0; - DeleteMail() = delete; - DeleteMail(MailDeleteResponse status, uint64_t mailID) { - this->status = status; - this->mailID = mailID; - } + ReadRequest() : MailLUBitStream(eMessageID::ReadRequest) {}; + bool Deserialize(RakNet::BitStream& bitStream) override; + void Handle() override; }; - struct Read { - MailLUHeader header; - MailReadResponse status; - uint64_t mailID; + struct ReadResponse : public MailLUBitStream { + uint64_t mailID = 0; + eReadResponse status = eReadResponse::UnknownError; + + ReadResponse() : MailLUBitStream(eMessageID::ReadResponse) {}; + void Serialize(RakNet::BitStream& bitStream) const override; + }; - Read() = delete; - Read(MailReadResponse status, uint64_t mailID) { - this->status = status; - this->mailID = mailID; - } + struct NotificationRequest : public MailLUBitStream { + NotificationRequest() : MailLUBitStream(eMessageID::NotificationRequest) {}; + void Handle() override; }; - const std::string ServerName = "Darkflame Universe"; + void HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player); void SendMail( const Entity* recipient, @@ -223,113 +234,6 @@ namespace Mail { uint16_t attachmentCount, const SystemAddress& sysAddr ); - - void HandleMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity); - void HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity); - void HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player); - void HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player); - void HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr); - void HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr); - void HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID); - - void SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response); - void SendNotification(const SystemAddress& sysAddr, int mailCount); - void SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID); - void SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID); - void SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID); }; - -namespace RakNet { - template <> - inline void RakNet::BitStream::Write(Mail::MailLUHeader data) { - this->Write>(data.header); - this->Write(static_cast(data.messageID)); - } - - template <> - inline void RakNet::BitStream::Write(Mail::Data data) { - - this->Write(data.header); - this->Write(data.throttled); - - this->Write(data.playerMail.size()); - this->Write(0); // packing - for (auto& mail : data.playerMail) { - this->Write(mail.id); - - const LUWString subject(mail.subject, 50); - this->Write(subject); - - const LUWString body(mail.body, 400); - this->Write(body); - - const LUWString sender(mail.senderUsername, 32); - this->Write(sender); - this->Write(uint32_t(0)); // packing - - this->Write(uint64_t(0)); // attachedCurrency - this->Write(mail.itemID); - - LOT lot = mail.itemLOT; - if (lot <= 0) this->Write(LOT(-1)); - else this->Write(lot); - this->Write(uint32_t(0)); // packing - - this->Write(mail.itemSubkey); - - this->Write(mail.itemCount); - this->Write(uint8_t(0)); // subject type (used for auction) - this->Write(uint8_t(0)); // packing - this->Write(uint32_t(0)); // packing - - this->Write(mail.timeSent); // expiration date - this->Write(mail.timeSent);// send date - this->Write(mail.wasRead); // was read - - this->Write(uint8_t(0)); // isLocalized - this->Write(uint16_t(0)); // packing - this->Write(uint32_t(0)); // packing - } - } - - template <> - inline void RakNet::BitStream::Write(Mail::Response data) { - this->Write(data.header); - this->Write(static_cast(data.response)); - } - - template <> - inline void RakNet::BitStream::Write(Mail::Notification data) { - this->Write(data.header); - this->Write(data.notification); - this->Write(0); // unused - this->Write(0); // unused - this->Write(data.auctionID); - this->Write(0); // unused - this->Write(data.mailCount); - } - - template <> - inline void RakNet::BitStream::Write(Mail::AttachmentCollect data) { - this->Write(data.header); - this->Write(data.status); - this->Write(data.mailID); - } - - template <> - inline void RakNet::BitStream::Write(Mail::DeleteMail data) { - this->Write(data.header); - this->Write(data.status); - this->Write(data.mailID); - } - - template <> - inline void RakNet::BitStream::Write(Mail::Read data) { - this->Write(data.header); - this->Write(data.status); - this->Write(data.mailID); - } -} - #endif // !__MAIL_H__ diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp index 3032a33bc..5c710c09e 100644 --- a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp @@ -102,7 +102,7 @@ namespace GMGreaterThanZeroCommands { return; } - IMail::MailInfo mailInsert; + MailInfo mailInsert; mailInsert.senderId = entity->GetObjectID(); mailInsert.senderUsername = "Darkflame Universe"; mailInsert.receiverId = receiverID; diff --git a/dNet/BitStreamUtils.cpp b/dNet/BitStreamUtils.cpp new file mode 100644 index 000000000..64142e990 --- /dev/null +++ b/dNet/BitStreamUtils.cpp @@ -0,0 +1,29 @@ +#include "BitStreamUtils.h" +#include "dServer.h" +#include "BitStream.h" + + +void LUBitStream::WriteHeader(RakNet::BitStream& bitStream) const { + bitStream.Write(ID_USER_PACKET_ENUM); + bitStream.Write(this->connectionType); + bitStream.Write(this->internalPacketID); + bitStream.Write(0); // padding +} + +bool LUBitStream::ReadHeader(RakNet::BitStream& bitStream) { + MessageID messageID; + bitStream.Read(messageID); + if (messageID != ID_USER_PACKET_ENUM) return false; + VALIDATE_READ(bitStream.Read(this->connectionType)); + VALIDATE_READ(bitStream.Read(this->internalPacketID)); + uint8_t padding; + VALIDATE_READ(bitStream.Read(padding)); + return true; +} + +void LUBitStream::Send(const SystemAddress& sysAddr) const { + RakNet::BitStream bitStream; + this->WriteHeader(bitStream); + this->Serialize(bitStream); + Game::server->Send(bitStream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); +} diff --git a/dNet/BitStreamUtils.h b/dNet/BitStreamUtils.h index d55df14ad..d9e9bc9b1 100644 --- a/dNet/BitStreamUtils.h +++ b/dNet/BitStreamUtils.h @@ -3,18 +3,12 @@ #include "GeneralUtils.h" #include "BitStream.h" +#include "MessageIdentifiers.h" +#include "eConnectionType.h" #include #include -namespace MessageType { - enum class Auth : uint32_t; - enum class Client : uint32_t; - enum class Server : uint32_t; - enum class World : uint32_t; - enum class Master : uint32_t; -} - -enum class eConnectionType : uint16_t; +#define VALIDATE_READ(x) do { if (!x) return false; } while (0) struct LUString { std::string string; @@ -52,19 +46,28 @@ struct LUWString { }; }; -template -struct LUHeader { - MessageID messageID; - eConnectionType connectionType; - T internalPacketID; +struct LUBitStream { + eConnectionType connectionType = eConnectionType::UNKNOWN; + uint32_t internalPacketID = 0xFFFFFFFF; + + LUBitStream() = default; - LUHeader(eConnectionType connectionType, T internalPacketID, MessageID messageID = ID_USER_PACKET_ENUM) { - this->messageID = messageID; + template + LUBitStream(eConnectionType connectionType, T internalPacketID) { this->connectionType = connectionType; - this->internalPacketID = internalPacketID; - }; + this->internalPacketID = static_cast(internalPacketID); + } + + void WriteHeader(RakNet::BitStream& bitStream) const; + bool ReadHeader(RakNet::BitStream& bitStream); + void Send(const SystemAddress& sysAddr) const; + + virtual void Serialize(RakNet::BitStream& bitStream) const {} + virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; } + virtual void Handle() {}; }; + namespace BitStreamUtils { template void WriteHeader(RakNet::BitStream& bitStream, eConnectionType connectionType, T internalPacketID) { @@ -119,46 +122,6 @@ namespace RakNet { value.string.resize(value.size); this->Write(value.string); } - - template <> - inline void RakNet::BitStream::Write>(LUHeader value) { - this->Write(value.messageID); - this->Write(value.connectionType); - this->Write(static_cast(value.internalPacketID)); - this->Write(0); - } - - template <> - inline void RakNet::BitStream::Write>(LUHeader value) { - this->Write(value.messageID); - this->Write(value.connectionType); - this->Write(static_cast(value.internalPacketID)); - this->Write(0); - } - - template <> - inline void RakNet::BitStream::Write>(LUHeader value) { - this->Write(value.messageID); - this->Write(value.connectionType); - this->Write(static_cast(value.internalPacketID)); - this->Write(0); - } - - template <> - inline void RakNet::BitStream::Write>(LUHeader value) { - this->Write(value.messageID); - this->Write(value.connectionType); - this->Write(static_cast(value.internalPacketID)); - this->Write(0); - } - - template <> - inline void RakNet::BitStream::Write>(LUHeader value) { - this->Write(value.messageID); - this->Write(value.connectionType); - this->Write(static_cast(value.internalPacketID)); - this->Write(0); - } }; #endif //!__BITSTREAMUTILS__H__ diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt index 172aee205..84ba7e3ff 100644 --- a/dNet/CMakeLists.txt +++ b/dNet/CMakeLists.txt @@ -1,4 +1,5 @@ set(DNET_SOURCES "AuthPackets.cpp" + "BitStreamUtils.cpp" "ChatPackets.cpp" "ClientPackets.cpp" "dServer.cpp" diff --git a/dNet/MailInfo.cpp b/dNet/MailInfo.cpp new file mode 100644 index 000000000..687fee2e6 --- /dev/null +++ b/dNet/MailInfo.cpp @@ -0,0 +1,87 @@ +#include "MailInfo.h" +#include "BitStream.h" +#include "DluAssert.h" + +void MailInfo::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(id); + + const LUWString subject(this->subject, 50); + bitStream.Write(subject); + + const LUWString body(this->body, 400); + bitStream.Write(body); + + const LUWString sender(this->senderUsername, 32); + bitStream.Write(sender); + bitStream.Write(0); // packing + + bitStream.Write(0); // attachedCurrency + bitStream.Write(itemID); + + LOT lot = itemLOT; + if (lot <= 0) bitStream.Write(LOT_NULL); + else bitStream.Write(lot); + bitStream.Write(0); // packing + + bitStream.Write(itemSubkey); + + bitStream.Write(itemCount); + bitStream.Write(0); // subject type (used for auction) + bitStream.Write(0); // packing + bitStream.Write(0); // packing + + bitStream.Write(timeSent); // expiration date + bitStream.Write(timeSent);// send date + bitStream.Write(wasRead); // was read + + bitStream.Write(0); // isLocalized + bitStream.Write(0); // packing + 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(); + + LUWString body(400); + VALIDATE_READ(bitStream.Read(body)); + this->body = body.GetAsString(); + + LUWString sender(32); + VALIDATE_READ(bitStream.Read(sender)); + this->senderUsername = sender.GetAsString(); + + bitStream.IgnoreBytes(4); // packing + + 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 + + DluAssert(bitStream.GetNumberOfUnreadBits() == 0); + + return true; +} \ No newline at end of file diff --git a/dNet/MailInfo.h b/dNet/MailInfo.h new file mode 100644 index 000000000..75100d36f --- /dev/null +++ b/dNet/MailInfo.h @@ -0,0 +1,33 @@ +#ifndef __MAILINFO_H__ +#define __MAILINFO_H__ + +#include +#include +#include "dCommonVars.h" + +namespace RakNet { + class BitStream; +} + +struct MailInfo { + std::string senderUsername; + std::string recipient; + std::string subject; + std::string body; + uint64_t id{}; + uint32_t senderId{}; + uint32_t receiverId{}; + uint64_t timeSent{}; + bool wasRead{}; + struct { + LWOOBJID itemID{}; + int32_t itemCount{}; + LOT itemLOT{}; + LWOOBJID itemSubkey{}; + }; + + void Serialize(RakNet::BitStream& bitStream) const {} + bool Deserialize(RakNet::BitStream& bitStream) { return true; } +}; + +#endif // __MAILINFO_H__ diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index a467ac0f1..44c1a5fcf 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -831,15 +831,20 @@ void HandlePacket(Packet* packet) { } if (packet->data[0] != ID_USER_PACKET_ENUM || packet->length < 4) return; - if (static_cast(packet->data[1]) == eConnectionType::SERVER) { - if (static_cast(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) { + + CINSTREAM; + LUBitStream luBitStream; + luBitStream.ReadHeader(inStream); + + if (luBitStream.connectionType == eConnectionType::SERVER) { + if (static_cast(luBitStream.internalPacketID) == MessageType::Server::VERSION_CONFIRM) { AuthPackets::HandleHandshake(Game::server, packet); } } - if (static_cast(packet->data[1]) != eConnectionType::WORLD) return; + if (luBitStream.connectionType != eConnectionType::WORLD) return; - switch (static_cast(packet->data[3])) { + switch (static_cast(luBitStream.internalPacketID)) { case MessageType::World::VALIDATION: { CINSTREAM_SKIP_HEADER; LUWString username; @@ -1185,11 +1190,7 @@ void HandlePacket(Packet* packet) { } case MessageType::World::MAIL: { - RakNet::BitStream bitStream(packet->data, packet->length, false); - // FIXME: Change this to the macro to skip the header... - LWOOBJID space; - bitStream.Read(space); - Mail::HandleMail(bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); + Mail::HandleMail(inStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); break; }