mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-09-05 14:58:27 +00:00
feat: limit user sent mail so that it can't be spammed
This commit is contained in:
@@ -24,6 +24,9 @@ public:
|
|||||||
// Get the number of unread mail for the given character id.
|
// Get the number of unread mail for the given character id.
|
||||||
virtual uint32_t GetUnreadMailCount(const uint32_t characterId) = 0;
|
virtual uint32_t GetUnreadMailCount(const uint32_t characterId) = 0;
|
||||||
|
|
||||||
|
// Get the number of mail for a given character id.
|
||||||
|
virtual uint32_t GetMailCount(const uint32_t characterId) = 0;
|
||||||
|
|
||||||
// Mark the given mail as read.
|
// Mark the given mail as read.
|
||||||
virtual void MarkMailRead(const uint64_t mailId) = 0;
|
virtual void MarkMailRead(const uint64_t mailId) = 0;
|
||||||
|
|
||||||
|
@@ -89,6 +89,7 @@ public:
|
|||||||
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
||||||
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
||||||
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
||||||
|
uint32_t GetMailCount(const uint32_t characterId) override;
|
||||||
void MarkMailRead(const uint64_t mailId) override;
|
void MarkMailRead(const uint64_t mailId) override;
|
||||||
void DeleteMail(const uint64_t mailId) override;
|
void DeleteMail(const uint64_t mailId) override;
|
||||||
void ClaimMailItem(const uint64_t mailId) override;
|
void ClaimMailItem(const uint64_t mailId) override;
|
||||||
|
@@ -71,6 +71,16 @@ uint32_t MySQLDatabase::GetUnreadMailCount(const uint32_t characterId) {
|
|||||||
return res->getInt("number_unread");
|
return res->getInt("number_unread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t MySQLDatabase::GetMailCount(const uint32_t characterId) {
|
||||||
|
auto res = ExecuteSelect("SELECT COUNT(*) AS mail_count FROM mail WHERE receiver_id=?;", characterId);
|
||||||
|
|
||||||
|
if (!res->next()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res->getInt("mail_count");
|
||||||
|
}
|
||||||
|
|
||||||
void MySQLDatabase::MarkMailRead(const uint64_t mailId) {
|
void MySQLDatabase::MarkMailRead(const uint64_t mailId) {
|
||||||
ExecuteUpdate("UPDATE mail SET was_read=1 WHERE id=? LIMIT 1;", mailId);
|
ExecuteUpdate("UPDATE mail SET was_read=1 WHERE id=? LIMIT 1;", mailId);
|
||||||
}
|
}
|
||||||
|
@@ -87,6 +87,7 @@ public:
|
|||||||
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
||||||
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
||||||
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
||||||
|
uint32_t GetMailCount(const uint32_t characterId) override;
|
||||||
void MarkMailRead(const uint64_t mailId) override;
|
void MarkMailRead(const uint64_t mailId) override;
|
||||||
void DeleteMail(const uint64_t mailId) override;
|
void DeleteMail(const uint64_t mailId) override;
|
||||||
void ClaimMailItem(const uint64_t mailId) override;
|
void ClaimMailItem(const uint64_t mailId) override;
|
||||||
|
@@ -70,6 +70,16 @@ uint32_t SQLiteDatabase::GetUnreadMailCount(const uint32_t characterId) {
|
|||||||
return res.getIntField("number_unread");
|
return res.getIntField("number_unread");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t SQLiteDatabase::GetMailCount(const uint32_t characterId) {
|
||||||
|
auto [_, res] = ExecuteSelect("SELECT COUNT(*) AS mail_count FROM mail WHERE receiver_id=?;", characterId);
|
||||||
|
|
||||||
|
if (res.eof()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.getIntField("mail_count");
|
||||||
|
}
|
||||||
|
|
||||||
void SQLiteDatabase::MarkMailRead(const uint64_t mailId) {
|
void SQLiteDatabase::MarkMailRead(const uint64_t mailId) {
|
||||||
ExecuteUpdate("UPDATE mail SET was_read=1 WHERE id=?;", mailId);
|
ExecuteUpdate("UPDATE mail SET was_read=1 WHERE id=?;", mailId);
|
||||||
}
|
}
|
||||||
@@ -81,3 +91,4 @@ void SQLiteDatabase::ClaimMailItem(const uint64_t mailId) {
|
|||||||
void SQLiteDatabase::DeleteMail(const uint64_t mailId) {
|
void SQLiteDatabase::DeleteMail(const uint64_t mailId) {
|
||||||
ExecuteDelete("DELETE FROM mail WHERE id=?;", mailId);
|
ExecuteDelete("DELETE FROM mail WHERE id=?;", mailId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -66,6 +66,7 @@ class TestSQLDatabase : public GameDatabase {
|
|||||||
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
std::vector<MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
||||||
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
std::optional<MailInfo> GetMail(const uint64_t mailId) override;
|
||||||
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
||||||
|
uint32_t GetMailCount(const uint32_t characterId) override;
|
||||||
void MarkMailRead(const uint64_t mailId) override;
|
void MarkMailRead(const uint64_t mailId) override;
|
||||||
void DeleteMail(const uint64_t mailId) override;
|
void DeleteMail(const uint64_t mailId) override;
|
||||||
void ClaimMailItem(const uint64_t mailId) override;
|
void ClaimMailItem(const uint64_t mailId) override;
|
||||||
|
@@ -81,56 +81,64 @@ namespace Mail {
|
|||||||
} else if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) {
|
} else if (GeneralUtils::CaseInsensitiveStringCompare(mailInfo.recipient, character->GetName()) || receiverID->id == character->GetID()) {
|
||||||
response.status = eSendResponse::CannotMailSelf;
|
response.status = eSendResponse::CannotMailSelf;
|
||||||
} else {
|
} else {
|
||||||
uint32_t mailCost = Game::zoneManager->GetWorldConfig().mailBaseFee;
|
// check if recipient mailbox is full
|
||||||
uint32_t stackSize = 0;
|
if (Database::Get()->GetMailCount(receiverID->id) >= 20) {
|
||||||
|
// There is no Mailbox full response, so we will do this instead
|
||||||
auto inventoryComponent = player->GetComponent<InventoryComponent>();
|
response.status = eSendResponse::UnknownError;
|
||||||
Item* item = nullptr;
|
// send system chat message to player
|
||||||
|
ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Recipient's mailbox is full. Please try again later.");
|
||||||
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 {
|
} else {
|
||||||
bool removeSuccess = true;
|
uint32_t mailCost = Game::zoneManager->GetWorldConfig().mailBaseFee;
|
||||||
// Remove coins and items from the sender
|
uint32_t stackSize = 0;
|
||||||
player->GetCharacter()->SetCoins(player->GetCharacter()->GetCoins() - mailCost, eLootSourceType::MAIL);
|
|
||||||
if (inventoryComponent && hasAttachment && item) {
|
auto inventoryComponent = player->GetComponent<InventoryComponent>();
|
||||||
removeSuccess = inventoryComponent->RemoveItem(mailInfo.itemLOT, mailInfo.itemCount, INVALID, true);
|
Item* item = nullptr;
|
||||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
|
||||||
if (missionComponent && removeSuccess) missionComponent->Progress(eMissionTaskType::GATHER, mailInfo.itemLOT, LWOOBJID_EMPTY, "", -mailInfo.itemCount);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we passed all the checks, now we can actully send the mail
|
if (hasAttachment && !item) {
|
||||||
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;
|
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<MissionComponent>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
response.status = eSendResponse::SenderAccountIsMuted;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
response.status = eSendResponse::SenderAccountIsMuted;
|
|
||||||
}
|
}
|
||||||
LOG("Finished send with status %s", StringifiedEnum::ToString(response.status).data());
|
LOG("Finished send with status %s", StringifiedEnum::ToString(response.status).data());
|
||||||
response.Send(sysAddr);
|
response.Send(sysAddr);
|
||||||
|
Reference in New Issue
Block a user