Files
DarkflameServer/dGame/dUtilities/Mail.h
Aaron Kimbrell b629766182 fix(mail): new mail notices in live's form
Live filled a NewMail notice with the mail it was about: the mail ID, the
player, the attachment (LOT -1 without one) and a count of 1, and at load sent
one notice per unread mail. DLU sent one notice with every field 0 and the
unread total as the count. The answer to NotificationRequest names the player
and no mail, with LOT -1 and the unread count, as live's did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:51:21 -05:00

279 lines
7.7 KiB
C++

#ifndef __MAIL_H__
#define __MAIL_H__
#include <cstdint>
#include <vector>
#include "BitStream.h"
#include "RakNetTypes.h"
#include "dCommonVars.h"
#include "BitStreamUtils.h"
#include "MailInfo.h"
class Entity;
namespace Mail {
enum class eMessageID : uint32_t {
SendRequest = 0,
SendResponse,
NotificationResponse,
DataRequest,
DataResponse,
AttachmentCollectRequest,
AttachmentCollectResponse,
DeleteRequest,
DeleteResponse,
ReadRequest,
ReadResponse,
NotificationRequest,
AuctionCreate,
AuctionCreationResponse,
AuctionCancel,
AuctionCancelResponse,
AuctionList,
AuctionListResponse,
AuctionBid,
AuctionBidResponse,
UnknownError
};
enum class eSendResponse : uint32_t {
Success = 0,
NotEnoughCoins,
AttachmentNotFound,
ItemCannotBeMailed,
CannotMailSelf,
RecipientNotFound,
RecipientDifferentFaction,
UnHandled7,
ModerationFailure,
SenderAccountIsMuted,
UnHandled10,
RecipientIsIgnored,
UnHandled12,
RecipientIsFTP,
UnknownError
};
enum class eDeleteResponse : uint32_t {
Success = 0,
HasAttachments,
NotFound,
Throttled,
UnknownError
};
enum class eAttachmentCollectResponse : uint32_t {
Success = 0,
AttachmentNotFound,
NoSpaceInInventory,
MailNotFound,
Throttled,
UnknownError
};
enum class eNotificationResponse : uint32_t {
NewMail = 0,
UnHandled,
AuctionWon,
AuctionSold,
AuctionOutbided,
AuctionExpired,
AuctionCancelled,
AuctionUpdated,
UnknownError
};
enum class eReadResponse : uint32_t {
Success = 0,
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;
Entity* player = nullptr;
MailLUBitStream() = default;
MailLUBitStream(eMessageID _messageID) : LUBitStream(ServiceType::CLIENT, MessageType::Client::MAIL), messageID{_messageID} {};
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;
SendRequest() : MailLUBitStream(eMessageID::SendRequest) {}
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct SendResponse :public MailLUBitStream {
eSendResponse status = eSendResponse::UnknownError;
SendResponse() : MailLUBitStream(eMessageID::SendResponse) {}
void Serialize(RakNet::BitStream& bitStream) const override;
};
// Live filled a NewMail notice with the mail it was about (the answer to NotificationRequest named no mail and
// carried the unread count). The client reads the status and mailCount, and the object for auction notices.
struct NotificationResponse : public MailLUBitStream {
eNotificationResponse status = eNotificationResponse::UnknownError;
uint64_t mailID = 0;
LWOOBJID receiverID = LWOOBJID_EMPTY; // the player's object ID
LWOOBJID attachmentID = LWOOBJID_EMPTY;
LOT attachmentLOT = LOT_NULL;
uint16_t attachmentCount = 0;
uint32_t mailCount = 1;
NotificationResponse() : MailLUBitStream(eMessageID::NotificationResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct DataRequest : public MailLUBitStream {
DataRequest() : MailLUBitStream(eMessageID::DataRequest) {}
bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override;
};
struct DataResponse : public MailLUBitStream {
uint32_t throttled = 0;
std::vector<MailInfo> playerMail;
DataResponse() : MailLUBitStream(eMessageID::DataResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct AttachmentCollectRequest : public MailLUBitStream {
uint64_t mailID = 0;
LWOOBJID playerID = LWOOBJID_EMPTY;
AttachmentCollectRequest() : MailLUBitStream(eMessageID::AttachmentCollectRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct AttachmentCollectResponse : public MailLUBitStream {
eAttachmentCollectResponse status = eAttachmentCollectResponse::UnknownError;
uint64_t mailID = 0;
AttachmentCollectResponse() : MailLUBitStream(eMessageID::AttachmentCollectResponse) {};
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 DeleteResponse : public MailLUBitStream {
eDeleteResponse status = eDeleteResponse::UnknownError;
uint64_t mailID = 0;
DeleteResponse() : MailLUBitStream(eMessageID::DeleteResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct ReadRequest : public MailLUBitStream {
uint64_t mailID = 0;
ReadRequest() : MailLUBitStream(eMessageID::ReadRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct ReadResponse : public MailLUBitStream {
uint64_t mailID = 0;
eReadResponse status = eReadResponse::UnknownError;
ReadResponse() : MailLUBitStream(eMessageID::ReadResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct NotificationRequest : public MailLUBitStream {
NotificationRequest() : MailLUBitStream(eMessageID::NotificationRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override;
};
void HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player);
// A NewMail notice about one mail, the way live sent it: the mail, its attachment and a count of 1.
NotificationResponse NewMailNotice(const MailInfo& mail, LWOOBJID playerID);
// Part of a player's load: live told the client about unread mail right after the respawn checkpoint, without
// being asked, one NewMail notice per mail, and sent nothing when there was none.
void NotifyUnreadMailOnLoad(LWOOBJID characterID, LWOOBJID playerID, const SystemAddress& sysAddr);
// The notices NotifyUnreadMailOnLoad sends for this mail: one per unread mail, oldest first.
std::vector<NotificationResponse> UnreadMailNotices(std::vector<MailInfo> mail, LWOOBJID playerID);
// Tells the receiver about their unread mail if they are a player in this world. Returns false if they are not.
bool NotifyNewMailHere(LWOOBJID receiver);
// Tells the receiver about their new mail wherever they are online: in this world directly, otherwise through the
// chat server to the world they are in.
void NotifyNewMail(LWOOBJID receiver);
void SendMail(
const Entity* recipient,
const std::string& subject,
const std::string& body,
LOT attachment,
uint16_t attachmentCount
);
void SendMail(
LWOOBJID recipient,
const std::string& recipientName,
const std::string& subject,
const std::string& body,
LOT attachment,
uint16_t attachmentCount,
const SystemAddress& sysAddr
);
void SendMail(
LWOOBJID sender,
const std::string& senderName,
const Entity* recipient,
const std::string& subject,
const std::string& body,
LOT attachment,
uint16_t attachmentCount
);
void SendMail(
LWOOBJID sender,
const std::string& senderName,
LWOOBJID recipient,
const std::string& recipientName,
const std::string& subject,
const std::string& body,
LOT attachment,
uint16_t attachmentCount,
const SystemAddress& sysAddr
);
};
#endif // !__MAIL_H__