mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-31 12:41:55 +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. | ||||
| 	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. | ||||
| 	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::optional<MailInfo> GetMail(const uint64_t mailId) 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 DeleteMail(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"); | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	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::optional<MailInfo> GetMail(const uint64_t mailId) 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 DeleteMail(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"); | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 	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) { | ||||
| 	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::optional<MailInfo> GetMail(const uint64_t mailId) 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 DeleteMail(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()) { | ||||
| 				response.status = eSendResponse::CannotMailSelf; | ||||
| 			} else { | ||||
| 				uint32_t mailCost = Game::zoneManager->GetWorldConfig().mailBaseFee; | ||||
| 				uint32_t stackSize = 0; | ||||
| 				 | ||||
| 				auto inventoryComponent = player->GetComponent<InventoryComponent>(); | ||||
| 				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; | ||||
| 				// check if recipient mailbox is full | ||||
| 				if (Database::Get()->GetMailCount(receiverID->id) >= 20) { | ||||
| 					// There is no Mailbox full response, so we will do this instead | ||||
| 					response.status = eSendResponse::UnknownError; | ||||
| 					// send system chat message to player | ||||
| 					ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Recipient's mailbox is full. Please try again later."); | ||||
| 				} 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); | ||||
| 					uint32_t mailCost = Game::zoneManager->GetWorldConfig().mailBaseFee; | ||||
| 					uint32_t stackSize = 0; | ||||
| 					 | ||||
| 					auto inventoryComponent = player->GetComponent<InventoryComponent>(); | ||||
| 					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(); | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					// 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 { | ||||
| 					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<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()); | ||||
| 		response.Send(sysAddr); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Aronwk
					Aronwk