Start on replacing MySQL

This commit is contained in:
Jett
2023-10-10 01:40:48 +01:00
parent c6087ce77a
commit 8edfdd48a1
23 changed files with 846 additions and 797 deletions

View File

@@ -26,39 +26,16 @@ Character::Character(uint32_t id, User* parentUser) {
//First load the name, etc:
m_ID = id;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the character
auto character = Database::Connection->GetCharacterByID(m_ID);
m_Name = character.Name;
m_UnapprovedName = character.PendingName;
m_NameRejected = character.NameRejected;
m_PropertyCloneID = character.PropertyCloneID;
m_PermissionMap = character.PermissionMap;
stmt->setInt64(1, id);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_Name = res->getString(1).c_str();
m_UnapprovedName = res->getString(2).c_str();
m_NameRejected = res->getBoolean(3);
m_PropertyCloneID = res->getUInt(4);
m_PermissionMap = static_cast<ePermissionMap>(res->getUInt64(5));
}
delete res;
delete stmt;
//Load the xmlData now:
sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt(
"SELECT xml_data FROM charxml WHERE id=? LIMIT 1;"
);
xmlStmt->setInt64(1, id);
sql::ResultSet* xmlRes = xmlStmt->executeQuery();
while (xmlRes->next()) {
m_XMLData = xmlRes->getString(1).c_str();
}
delete xmlRes;
delete xmlStmt;
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
m_ZoneID = 0; //TEMP! Set back to 0 when done. This is so we can see loading screen progress for testing.
m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused.
@@ -85,38 +62,16 @@ Character::~Character() {
}
void Character::UpdateFromDatabase() {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"SELECT name, pending_name, needs_rename, prop_clone_id, permission_map FROM charinfo WHERE id=? LIMIT 1;"
);
// Load the character
auto character = Database::Connection->GetCharacterByID(m_ID);
m_Name = character.Name;
m_UnapprovedName = character.PendingName;
m_NameRejected = character.NameRejected;
m_PropertyCloneID = character.PropertyCloneID;
m_PermissionMap = character.PermissionMap;
stmt->setInt64(1, m_ID);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_Name = res->getString(1).c_str();
m_UnapprovedName = res->getString(2).c_str();
m_NameRejected = res->getBoolean(3);
m_PropertyCloneID = res->getUInt(4);
m_PermissionMap = static_cast<ePermissionMap>(res->getUInt64(5));
}
delete res;
delete stmt;
//Load the xmlData now:
sql::PreparedStatement* xmlStmt = Database::CreatePreppedStmt(
"SELECT xml_data FROM charxml WHERE id=? LIMIT 1;"
);
xmlStmt->setInt64(1, m_ID);
sql::ResultSet* xmlRes = xmlStmt->executeQuery();
while (xmlRes->next()) {
m_XMLData = xmlRes->getString(1).c_str();
}
delete xmlRes;
delete xmlStmt;
// Load the xmlData now
m_XMLData = Database::Connection->GetCharacterXMLByID(m_ID);
m_ZoneID = 0; //TEMP! Set back to 0 when done. This is so we can see loading screen progress for testing.
m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused.
@@ -404,18 +359,13 @@ void Character::SetIsNewLogin() {
}
void Character::WriteToDatabase() {
//Dump our xml into m_XMLData:
// Dump our xml into m_XMLData:
auto* printer = new tinyxml2::XMLPrinter(0, true, 0);
m_Doc->Print(printer);
m_XMLData = printer->CStr();
//Finally, save to db:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("UPDATE charxml SET xml_data=? WHERE id=?");
stmt->setString(1, m_XMLData.c_str());
stmt->setUInt(2, m_ID);
stmt->execute();
delete stmt;
delete printer;
// Save to DB
Database::Connection->WriteCharacterXMl(m_ID, m_XMLData);
}
void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {

View File

@@ -27,37 +27,21 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std:
//This needs to be re-enabled / updated whenever the mute stuff is moved to another table.
//This was only done because otherwise the website's account page dies and the website is waiting on a migration to wordpress.
//sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gmlevel, mute_expire FROM accounts WHERE name=? LIMIT 1;");
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id, gm_level FROM accounts WHERE name=? LIMIT 1;");
stmt->setString(1, username.c_str());
auto account = Database::Connection->GetAccountByName(username);
sql::ResultSet* res = stmt->executeQuery();
while (res->next()) {
m_AccountID = res->getUInt(1);
m_MaxGMLevel = static_cast<eGameMasterLevel>(res->getInt(2));
m_MuteExpire = 0; //res->getUInt64(3);
}
delete res;
delete stmt;
m_AccountID = account.ID;
m_MaxGMLevel = static_cast<eGameMasterLevel>(account.MaxGMLevel);
m_MuteExpire = 0;
//If we're loading a zone, we'll load the last used (aka current) character:
if (Game::server->GetZoneID() != 0) {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 1;");
stmt->setUInt(1, m_AccountID);
uint32_t characterId = Database::Connection->GetLatestCharacterOfAccount(m_AccountID);
sql::ResultSet* res = stmt->executeQuery();
if (res->rowsCount() > 0) {
while (res->next()) {
LWOOBJID objID = res->getUInt64(1);
Character* character = new Character(uint32_t(objID), this);
m_Characters.push_back(character);
Game::logger->Log("User", "Loaded %llu as it is the last used char", objID);
}
if (characterId != 0) {
Character* character = new Character(characterId, this);
m_Characters.push_back(character);
Game::logger->Log("User", "Loaded %u as it is the last used char", characterId);
}
delete res;
delete stmt;
}
}

View File

@@ -159,17 +159,7 @@ void UserManager::DeletePendingRemovals() {
}
bool UserManager::IsNameAvailable(const std::string& requestedName) {
bool toReturn = false; //To allow for a clean exit
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? OR pending_name=? LIMIT 1;");
stmt->setString(1, requestedName.c_str());
stmt->setString(2, requestedName.c_str());
sql::ResultSet* res = stmt->executeQuery();
if (res->rowsCount() == 0) toReturn = true;
delete stmt;
delete res;
return toReturn;
return Database::Connection->IsCharacterNameAvailable(requestedName);
}
std::string UserManager::GetPredefinedName(uint32_t firstNameIndex, uint32_t middleNameIndex, uint32_t lastNameIndex) {
@@ -201,10 +191,8 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
User* u = GetUser(sysAddr);
if (!u) return;
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE account_id=? ORDER BY last_login DESC LIMIT 4;");
stmt->setUInt(1, u->GetAccountID());
auto charInfos = Database::Connection->GetAllCharactersByAccountID(u->GetAccountID());
sql::ResultSet* res = stmt->executeQuery();
std::vector<Character*>& chars = u->GetCharacters();
for (size_t i = 0; i < chars.size(); ++i) {
@@ -232,16 +220,12 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
chars.clear();
while (res->next()) {
LWOOBJID objID = res->getUInt64(1);
Character* character = new Character(uint32_t(objID), u);
for (const auto& info : charInfos) {
Character* character = new Character(info.ID, u);
character->SetIsNewLogin();
chars.push_back(character);
}
delete res;
delete stmt;
WorldPackets::SendCharacterList(sysAddr, u);
}
@@ -290,12 +274,8 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
//Now that the name is ok, we can get an objectID from Master:
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) {
sql::PreparedStatement* overlapStmt = Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE id = ?");
overlapStmt->setUInt(1, objectID);
auto* overlapResult = overlapStmt->executeQuery();
if (overlapResult->next()) {
auto character = Database::Connection->GetCharacterInfoByID(objectID);
if (character.AccountID != 0) {
Game::logger->Log("UserManager", "Character object id unavailable, check objectidtracker!");
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
return;
@@ -333,45 +313,32 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
xml3 << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
//Check to see if our name was pre-approved:
// Check to see if our name was pre-approved
bool nameOk = IsNamePreapproved(name);
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
if (name != "") {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)");
stmt->setUInt(1, objectID);
stmt->setUInt(2, u->GetAccountID());
stmt->setString(3, predefinedName.c_str());
stmt->setString(4, name.c_str());
stmt->setBoolean(5, false);
stmt->setUInt64(6, time(NULL));
if (nameOk) {
stmt->setString(3, name.c_str());
stmt->setString(4, "");
}
stmt->execute();
delete stmt;
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
nameOk ? name : predefinedName,
nameOk ? "" : name,
false,
time(NULL)
);
} else {
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)");
stmt->setUInt(1, objectID);
stmt->setUInt(2, u->GetAccountID());
stmt->setString(3, predefinedName.c_str());
stmt->setString(4, "");
stmt->setBoolean(5, false);
stmt->setUInt64(6, time(NULL));
stmt->execute();
delete stmt;
Database::Connection->CreateCharacter(
objectID,
u->GetAccountID(),
predefinedName,
"",
false,
time(NULL)
);
}
//Now finally insert our character xml:
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charxml`(`id`, `xml_data`) VALUES (?,?)");
stmt->setUInt(1, objectID);
stmt->setString(2, xml3.str().c_str());
stmt->execute();
delete stmt;
// Now finally insert our character xml
Database::Connection->CreateCharacterXML(objectID, xml3.str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
UserManager::RequestCharacterList(sysAddr);
@@ -403,73 +370,13 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
WorldPackets::SendCharacterDeleteResponse(sysAddr, false);
} else {
Game::logger->Log("UserManager", "Deleting character %i", charID);
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM charxml WHERE id=? LIMIT 1;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM command_log WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;");
stmt->setUInt(1, charID);
stmt->setUInt(2, charID);
stmt->execute();
delete stmt;
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
bitStream.Write(objectID);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt(
"DELETE FROM properties_contents WHERE property_id IN (SELECT id FROM properties WHERE owner_id=?);"
);
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM properties WHERE owner_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM ugc WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM activity_log WHERE character_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM mail WHERE receiver_id=?;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
{
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM charinfo WHERE id=? LIMIT 1;");
stmt->setUInt64(1, charID);
stmt->execute();
delete stmt;
}
Database::Connection->DeleteCharacter(charID);
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
bitStream.Write(objectID);
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
WorldPackets::SendCharacterDeleteResponse(sysAddr, true);
}

View File

@@ -1083,44 +1083,23 @@ PetComponent::~PetComponent() {
}
void PetComponent::SetPetNameForModeration(const std::string& petName) {
int approved = 1; //default, in mod
int approved = 1; // default, in mod
//Make sure that the name isn't already auto-approved:
// Make sure that the name isn't already auto-approved
if (Game::chatFilter->IsSentenceOkay(petName, eGameMasterLevel::CIVILIAN).empty()) {
approved = 2; //approved
approved = 2;
}
auto deleteStmt = Database::CreatePreppedStmt("DELETE FROM pet_names WHERE id = ? LIMIT 1;");
deleteStmt->setUInt64(1, m_DatabaseId);
Database::Connection->DeletePetName(m_DatabaseId);
deleteStmt->execute();
delete deleteStmt;
//Save to db:
auto stmt = Database::CreatePreppedStmt("INSERT INTO `pet_names` (`id`, `pet_name`, `approved`) VALUES (?, ?, ?);");
stmt->setUInt64(1, m_DatabaseId);
stmt->setString(2, petName);
stmt->setInt(3, approved);
stmt->execute();
delete stmt;
// Save to db
Database::Connection->CreatePetName(m_DatabaseId, petName, approved);
}
void PetComponent::LoadPetNameFromModeration() {
auto stmt = Database::CreatePreppedStmt("SELECT pet_name, approved FROM pet_names WHERE id = ? LIMIT 1;");
stmt->setUInt64(1, m_DatabaseId);
auto res = stmt->executeQuery();
while (res->next()) {
m_ModerationStatus = res->getInt(2);
if (m_ModerationStatus == 2) {
m_Name = res->getString(1);
}
}
delete res;
delete stmt;
auto petNameInfo = Database::Connection->GetPetName(m_DatabaseId);
m_ModerationStatus = petNameInfo.Approved;
m_Name = petNameInfo.Name;
}
void PetComponent::SetPreconditions(std::string& preconditions) {

View File

@@ -360,11 +360,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
}
// Log command to database
auto stmt = Database::CreatePreppedStmt("INSERT INTO command_log (character_id, command) VALUES (?, ?);");
stmt->setInt(1, entity->GetCharacter()->GetID());
stmt->setString(2, GeneralUtils::UTF16ToWTF8(command).c_str());
stmt->execute();
delete stmt;
Database::Connection->InsertIntoCommandLog(entity->GetCharacter()->GetID(), GeneralUtils::UTF16ToWTF8(command));
if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0
int32_t minifigItemId;
@@ -816,18 +812,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) {
const auto& playerName = args[0];
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;");
stmt->setString(1, playerName);
sql::ResultSet* res = stmt->executeQuery();
uint32_t receiverID = 0;
if (res->rowsCount() > 0) {
while (res->next()) receiverID = res->getUInt(1);
}
delete stmt;
delete res;
auto character = Database::Connection->GetCharacterByName(playerName);
uint32_t receiverID = character.AccountID;
if (receiverID == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player");
@@ -1016,26 +1003,15 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
LWOOBJID characterId = 0;
if (player == nullptr) {
auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id, id FROM charinfo WHERE name=? LIMIT 1;");
auto character = Database::Connection->GetCharacterByName(args[0]);
accountQuery->setString(1, args[0]);
auto result = accountQuery->executeQuery();
if (result->rowsCount() > 0) {
while (result->next()) {
accountId = result->getUInt(1);
characterId = result->getUInt64(2);
GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT);
}
}
delete accountQuery;
delete result;
if (accountId == 0) {
if (accountId != 0) {
accountId = character.AccountID;
characterId = character.ID;
GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER);
GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT);
} else {
ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0]));
return;
@@ -1128,20 +1104,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
uint32_t accountId = 0;
if (player == nullptr) {
auto* accountQuery = Database::CreatePreppedStmt("SELECT account_id FROM charinfo WHERE name=? LIMIT 1;");
auto character = Database::Connection->GetCharacterInfoByName(args[0]);
accountId = character.AccountID;
accountQuery->setString(1, args[0]);
auto result = accountQuery->executeQuery();
if (result->rowsCount() > 0) {
while (result->next()) accountId = result->getUInt(1);
}
delete accountQuery;
delete result;
if (accountId == 0) {
if (character.AccountID == 0) {
ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0]));
return;