Implement more abstracted database functions.

This commit is contained in:
Jett 2023-10-10 11:59:30 +00:00
parent 6fb0677bd9
commit d61d3b0ce2
6 changed files with 209 additions and 144 deletions

View File

@ -56,6 +56,10 @@ public:
virtual AccountInfo GetAccountByID(uint32_t id) = 0;
virtual uint32_t GetLatestCharacterOfAccount(uint32_t id) = 0;
// Account Set
virtual void BanAccount(uint32_t id) = 0;
virtual void MuteAccount(uint32_t id, uint64_t muteExpireDate) = 0;
// Pet Write
virtual void CreatePetName(uint64_t id, const std::string& name, bool approved) = 0;
@ -73,6 +77,19 @@ public:
// Object ID tracker Set
virtual void SetObjectIDTracker(uint32_t id) = 0;
// Mail Get
virtual MailInfo GetMailByID(uint64_t id) = 0;
virtual std::vector<MailInfo> GetAllRecentMailOfUser(uint32_t id) = 0;
virtual uint32_t GetUnreadMailCountForUser(uint32_t id) = 0;
// Mail Write
virtual void WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId = 0, uint32_t attachmentLot = 0, uint64_t attachmentSubkey = 0, uint32_t attachmentCount = 0, bool wasRead = false) = 0;
virtual void SetMailAsRead(uint64_t id) = 0;
virtual void RemoveAttachmentFromMail(uint64_t id) = 0;
// Mail Delete
virtual void DeleteMail(uint64_t id) = 0;
private:
};

View File

@ -404,6 +404,19 @@ AccountInfo MySQLDatabase::GetAccountByID(uint32_t id) {
return AccountInfo{};
}
void MySQLDatabase::BanAccount(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE accounts SET banned = 1 WHERE id = ?;");
stmt->setUInt(1, id);
stmt->execute();
}
void MySQLDatabase::MuteAccount(uint32_t id, uint64_t muteExpireDate) {
auto stmt = CreatePreppedStmtUnique("UPDATE accounts SET mute_expire = ? WHERE id = ?;");
stmt->setUInt64(1, muteExpireDate);
stmt->setUInt(2, id);
stmt->execute();
}
std::vector<CharacterInfo> MySQLDatabase::GetAllCharactersByAccountID(uint32_t accountId) {
auto stmt = CreatePreppedStmtUnique("SELECT id FROM charinfo WHERE account_id = ? LIMIT 4;");
stmt->setUInt(1, accountId);
@ -485,3 +498,110 @@ void MySQLDatabase::SetObjectIDTracker(uint32_t id) {
stmt->setUInt(1, id);
stmt->execute();
}
MailInfo MySQLDatabase::GetMailByID(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM mail WHERE id = ?;");
stmt->setUInt64(1, id);
auto res = GetResultsOfStatement(stmt.get());
if (res->next()) {
MailInfo mail{};
mail.ID = id;
mail.SenderID = res->getUInt("sender_id");
mail.SenderName = res->getString("sender_name");
mail.ReceiverID = res->getUInt("receiver_id");
mail.ReceiverName = res->getString("receiver_name");
mail.TimeSent = res->getUInt64("time_sent");
mail.Subject = res->getString("subject");
mail.Body = res->getString("body");
mail.AttachmentID = res->getUInt("attachment_id");
mail.AttachmentLOT = res->getUInt("attachment_lot");
mail.AttachmentSubkey = res->getUInt64("attachment_subkey");
mail.AttachmentCount = res->getUInt("attachment_count");
mail.WasRead = res->getBoolean("was_read");
return mail;
}
return MailInfo{};
}
std::vector<MailInfo> MySQLDatabase::GetAllRecentMailOfUser(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT * FROM mail WHERE receiver_id = ? LIMIT 20;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
std::vector<MailInfo> mail;
while (res->next()) {
MailInfo mailInfo{};
mailInfo.ID = res->getUInt64("id");
mailInfo.SenderID = res->getUInt("sender_id");
mailInfo.SenderName = res->getString("sender_name");
mailInfo.ReceiverID = res->getUInt("receiver_id");
mailInfo.ReceiverName = res->getString("receiver_name");
mailInfo.TimeSent = res->getUInt64("time_sent");
mailInfo.Subject = res->getString("subject");
mailInfo.Body = res->getString("body");
mailInfo.AttachmentID = res->getUInt("attachment_id");
mailInfo.AttachmentLOT = res->getUInt("attachment_lot");
mailInfo.AttachmentSubkey = res->getUInt64("attachment_subkey");
mailInfo.AttachmentCount = res->getUInt("attachment_count");
mailInfo.WasRead = res->getBoolean("was_read");
mail.push_back(mailInfo);
}
return mail;
}
uint32_t MySQLDatabase::GetUnreadMailCountForUser(uint32_t id) {
auto stmt = CreatePreppedStmtUnique("SELECT COUNT(*) FROM mail WHERE receiver_id = ? AND was_read = 0;");
stmt->setUInt(1, id);
auto res = GetResultsOfStatement(stmt.get());
while (res->next()) {
return res->getUInt(1);
}
return 0;
}
void MySQLDatabase::WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId, uint32_t attachmentLot, uint64_t attachmentSubkey, uint32_t attachmentCount, bool wasRead) {
auto stmt = CreatePreppedStmtUnique("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) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
stmt->setUInt(1, senderId);
stmt->setString(2, senderName);
stmt->setUInt(3, receiverId);
stmt->setString(4, receiverName);
stmt->setUInt64(5, sendTime);
stmt->setString(6, subject);
stmt->setString(7, body);
stmt->setUInt(8, attachmentId);
stmt->setUInt(9, attachmentLot);
stmt->setUInt64(10, attachmentSubkey);
stmt->setUInt(11, attachmentCount);
stmt->setBoolean(12, wasRead);
stmt->execute();
}
void MySQLDatabase::DeleteMail(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("DELETE FROM mail WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
void MySQLDatabase::SetMailAsRead(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE mail SET was_read = 1 WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}
void MySQLDatabase::RemoveAttachmentFromMail(uint64_t id) {
auto stmt = CreatePreppedStmtUnique("UPDATE mail SET attachment_lot = 0 WHERE id = ?;");
stmt->setUInt64(1, id);
stmt->execute();
}

View File

@ -59,6 +59,9 @@ public:
AccountInfo GetAccountByID(uint32_t id) override;
uint32_t GetLatestCharacterOfAccount(uint32_t id) override;
void BanAccount(uint32_t id) override;
void MuteAccount(uint32_t id, uint64_t muteExpireDate) override;
void CreatePetName(uint64_t id, const std::string& name, bool approved) override;
void DeletePetName(uint64_t id) override;
@ -70,6 +73,16 @@ public:
uint32_t GetObjectIDTracker() override;
void SetObjectIDTracker(uint32_t id) override;
MailInfo GetMailByID(uint64_t id) override;
std::vector<MailInfo> GetAllRecentMailOfUser(uint32_t id) override;
uint32_t GetUnreadMailCountForUser(uint32_t id) override;
void WriteMail(uint32_t senderId, const std::string& senderName, uint32_t receiverId, const std::string& receiverName, uint64_t sendTime, const std::string& subject, const std::string& body, uint32_t attachmentId = 0, uint32_t attachmentLot = 0, uint64_t attachmentSubkey = 0, uint32_t attachmentCount = 0, bool wasRead = false) override;
void SetMailAsRead(uint64_t id) override;
void RemoveAttachmentFromMail(uint64_t id) override;
void DeleteMail(uint64_t id) override;
private:
std::string m_Host;
std::string m_Database;

View File

@ -31,3 +31,19 @@ struct PetName {
std::string Name;
bool Approved;
};
struct MailInfo {
uint64_t ID;
uint32_t SenderID;
std::string SenderName;
uint32_t ReceiverID;
std::string ReceiverName;
uint64_t TimeSent;
std::string Subject;
std::string Body;
uint32_t AttachmentID;
uint32_t AttachmentLOT;
uint64_t AttachmentSubkey;
uint32_t AttachmentCount;
bool WasRead;
};

View File

@ -76,22 +76,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) {
auto* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, sender);
ins->setString(2, senderName.c_str());
ins->setUInt(3, recipient);
ins->setString(4, recipientName.c_str());
ins->setUInt64(5, time(nullptr));
ins->setString(6, subject.c_str());
ins->setString(7, body.c_str());
ins->setUInt(8, 0);
ins->setInt(9, attachment);
ins->setInt(10, 0);
ins->setInt(11, attachmentCount);
ins->execute();
delete ins;
Database::Connection->WriteMail(sender, senderName, recipient, recipientName, time(nullptr), subject, body, 0, attachment, 0, attachmentCount, false);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server
@ -220,43 +205,20 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
//Get the receiver's id:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;");
stmt->setString(1, recipient);
sql::ResultSet* res = stmt->executeQuery();
uint32_t receiverID = 0;
auto recipientInfo = Database::Connection->GetCharacterInfoByName(recipient);
uint32_t receiverID = recipientInfo.ID;
if (res->rowsCount() > 0) {
while (res->next()) receiverID = res->getUInt(1);
} else {
if (receiverID == 0) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::RecipientNotFound);
delete stmt;
delete res;
return;
}
delete stmt;
delete res;
//Check if we have a valid receiver:
if (GeneralUtils::CaseInsensitiveStringCompare(recipient, character->GetName()) || receiverID == character->GetObjectID()) {
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::CannotMailSelf);
return;
} else {
uint64_t currentTime = time(NULL);
sql::PreparedStatement* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, character->GetObjectID());
ins->setString(2, character->GetName());
ins->setUInt(3, receiverID);
ins->setString(4, recipient);
ins->setUInt64(5, currentTime);
ins->setString(6, subject);
ins->setString(7, body);
ins->setUInt(8, itemID);
ins->setInt(9, itemLOT);
ins->setInt(10, 0);
ins->setInt(11, attachmentCount);
ins->execute();
delete ins;
Database::Connection->WriteMail(character->GetObjectID(), character->GetName(), receiverID, recipient, time(nullptr), subject, body, itemID, itemLOT, 0, attachmentCount, false);
}
Mail::SendSendResponse(sysAddr, Mail::MailSendResponse::Success);
@ -279,57 +241,45 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd
}
void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT * FROM mail WHERE receiver_id=? limit 20;");
stmt->setUInt(1, player->GetCharacter()->GetObjectID());
sql::ResultSet* res = stmt->executeQuery();
auto mail = Database::Connection->GetAllRecentMailOfUser(player->GetCharacter()->GetObjectID());
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL);
bitStream.Write(int(MailMessageID::MailData));
bitStream.Write(int(0));
bitStream.Write(uint16_t(res->rowsCount()));
bitStream.Write(uint16_t(mail.size()));
bitStream.Write(uint16_t(0));
if (res->rowsCount() > 0) {
while (res->next()) {
bitStream.Write(res->getUInt64(1)); //MailID
for (const auto& mailInfo : mail) {
bitStream.Write(mailInfo.ID); //MailID
/*std::u16string subject = GeneralUtils::UTF8ToUTF16(res->getString(7));
std::u16string body = GeneralUtils::UTF8ToUTF16(res->getString(8));
std::u16string sender = GeneralUtils::UTF8ToUTF16(res->getString(3));
WriteStringAsWString(&bitStream, mailInfo.Subject, 50); //subject
WriteStringAsWString(&bitStream, mailInfo.Body, 400); //body
WriteStringAsWString(&bitStream, mailInfo.SenderName, 32); //sender
WriteToPacket(&bitStream, subject, 50);
WriteToPacket(&bitStream, body, 400);
WriteToPacket(&bitStream, sender, 32);*/
bitStream.Write(uint32_t(0));
bitStream.Write(uint64_t(0));
WriteStringAsWString(&bitStream, res->getString(7).c_str(), 50); //subject
WriteStringAsWString(&bitStream, res->getString(8).c_str(), 400); //body
WriteStringAsWString(&bitStream, res->getString(3).c_str(), 32); //sender
bitStream.Write(mailInfo.AttachmentID); //Attachment ID
LOT lot = mailInfo.AttachmentLOT;
if (lot <= 0) bitStream.Write(LOT(-1));
else bitStream.Write(lot);
bitStream.Write(uint32_t(0));
bitStream.Write(uint32_t(0));
bitStream.Write(uint64_t(0));
bitStream.Write(mailInfo.AttachmentSubkey); //Attachment subKey
bitStream.Write(uint16_t(mailInfo.AttachmentCount)); //Attachment count
bitStream.Write(res->getUInt64(9)); //Attachment ID
LOT lot = res->getInt(10);
if (lot <= 0) bitStream.Write(LOT(-1));
else bitStream.Write(lot);
bitStream.Write(uint32_t(0));
bitStream.Write(uint32_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(res->getInt64(11)); //Attachment subKey
bitStream.Write(uint16_t(res->getInt(12))); //Attachment count
bitStream.Write(uint64_t(mailInfo.TimeSent)); //time sent (twice?)
bitStream.Write(uint64_t(mailInfo.TimeSent));
bitStream.Write(uint8_t(mailInfo.WasRead)); //was read
bitStream.Write(uint32_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint64_t(res->getUInt64(6))); //time sent (twice?)
bitStream.Write(uint64_t(res->getUInt64(6)));
bitStream.Write(uint8_t(res->getBoolean(13))); //was read
bitStream.Write(uint8_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint32_t(0));
}
bitStream.Write(uint8_t(0));
bitStream.Write(uint16_t(0));
bitStream.Write(uint32_t(0));
}
Game::server->Send(&bitStream, sysAddr, false);
@ -345,31 +295,17 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres
packet->Read(playerID);
if (mailID > 0 && playerID == player->GetObjectID()) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT attachment_lot, attachment_count FROM mail WHERE id=? LIMIT 1;");
stmt->setUInt64(1, mailID);
sql::ResultSet* res = stmt->executeQuery();
LOT attachmentLOT = 0;
uint32_t attachmentCount = 0;
while (res->next()) {
attachmentLOT = res->getInt(1);
attachmentCount = res->getInt(2);
}
auto mailInfo = Database::Connection->GetMailByID(mailID);
if (mailInfo.ID == 0) return;
auto inv = static_cast<InventoryComponent*>(player->GetComponent(eReplicaComponentType::INVENTORY));
if (!inv) return;
inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::MAIL);
inv->AddItem(mailInfo.AttachmentLOT, mailInfo.AttachmentCount, eLootSourceType::MAIL);
Mail::SendAttachmentRemoveConfirm(sysAddr, mailID);
sql::PreparedStatement* up = Database::CreatePreppedStmt("UPDATE mail SET attachment_lot=0 WHERE id=?;");
up->setUInt64(1, mailID);
up->execute();
delete up;
delete res;
delete stmt;
Database::Connection->RemoveAttachmentFromMail(mailID);
}
}
@ -395,14 +331,10 @@ void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAdd
void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID) {
auto returnVal = std::async(std::launch::async, [&]() {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM mail WHERE receiver_id=? AND was_read=0");
stmt->setUInt(1, objectID);
sql::ResultSet* res = stmt->executeQuery();
auto unreadCount = Database::Connection->GetUnreadMailCountForUser(objectID);
if (res->rowsCount() > 0) Mail::SendNotification(sysAddr, res->rowsCount());
delete res;
delete stmt;
});
if (unreadCount > 0) Mail::SendNotification(sysAddr, unreadCount);
});
}
void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) {
@ -449,10 +381,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO
bitStream.Write(mailID);
Game::server->Send(&bitStream, sysAddr, false);
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM mail WHERE id=? LIMIT 1;");
stmt->setUInt64(1, mailID);
stmt->execute();
delete stmt;
Database::Connection->DeleteMail(mailID);
}
void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
@ -463,8 +392,5 @@ void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) {
bitStream.Write(mailID);
Game::server->Send(&bitStream, sysAddr, false);
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE mail SET was_read=1 WHERE id=?");
stmt->setUInt64(1, mailID);
stmt->execute();
delete stmt;
Database::Connection->SetMailAsRead(mailID);
}

View File

@ -813,7 +813,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) {
const auto& playerName = args[0];
auto character = Database::Connection->GetCharacterByName(playerName);
auto character = Database::Connection->GetCharacterInfoByName(playerName);
uint32_t receiverID = character.AccountID;
if (receiverID == 0) {
@ -829,21 +829,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
uint64_t currentTime = time(NULL);
sql::PreparedStatement* ins = Database::CreatePreppedStmt("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`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)");
ins->setUInt(1, entity->GetObjectID());
ins->setString(2, "Darkflame Universe");
ins->setUInt(3, receiverID);
ins->setString(4, playerName);
ins->setUInt64(5, currentTime);
ins->setString(6, "Lost item");
ins->setString(7, "This is a replacement item for one you lost.");
ins->setUInt(8, 0);
ins->setInt(9, lot);
ins->setInt(10, 0);
ins->setInt(11, 1);
ins->execute();
delete ins;
Database::Connection->WriteMail(entity->GetObjectID(), "Darkflame Universe", receiverID, playerName, time(nullptr), "Lost item", "This is a replacement item for one you lost.", 0, lot, 0, 1);
ChatPackets::SendSystemMessage(sysAddr, u"Mail sent");
@ -1003,7 +989,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
LWOOBJID characterId = 0;
if (player == nullptr) {
auto character = Database::Connection->GetCharacterByName(args[0]);
auto character = Database::Connection->GetCharacterInfoByName(args[0]);
if (accountId != 0) {
accountId = character.AccountID;
@ -1021,8 +1007,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
characterId = player->GetCharacter()->GetID();
}
auto* userUpdate = Database::CreatePreppedStmt("UPDATE accounts SET mute_expire = ? WHERE id = ?;");
time_t expire = 1; // Default to indefinate mute
if (args.size() >= 2) {
@ -1047,12 +1031,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
expire += 60 * 60 * hours;
}
userUpdate->setUInt64(1, expire);
userUpdate->setInt(2, accountId);
userUpdate->executeUpdate();
delete userUpdate;
Database::Connection->MuteAccount(accountId, expire);
char buffer[32] = "brought up for review.\0";
@ -1116,13 +1095,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
accountId = player->GetParentUser()->GetAccountID();
}
auto* userUpdate = Database::CreatePreppedStmt("UPDATE accounts SET banned = true WHERE id = ?;");
userUpdate->setInt(1, accountId);
userUpdate->executeUpdate();
delete userUpdate;
Database::Connection->BanAccount(accountId);
if (player != nullptr) {
Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED);