From 347fc46f0188ca0af2aa5525421842bc02a42bb3 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Fri, 28 Mar 2025 15:03:04 -0700 Subject: [PATCH] check pending names too (#1748) --- dDatabase/GameDatabase/ITables/ICharInfo.h | 2 ++ dDatabase/GameDatabase/MySQL/MySQLDatabase.h | 3 ++- dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp | 6 ++++++ dDatabase/GameDatabase/SQLite/SQLiteDatabase.h | 1 + dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp | 6 ++++++ dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h | 2 ++ dGame/UserManager.cpp | 13 +++++++------ 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/dDatabase/GameDatabase/ITables/ICharInfo.h b/dDatabase/GameDatabase/ITables/ICharInfo.h index 416dad2c..d908d993 100644 --- a/dDatabase/GameDatabase/ITables/ICharInfo.h +++ b/dDatabase/GameDatabase/ITables/ICharInfo.h @@ -44,6 +44,8 @@ public: // Updates the given character ids last login to be right now. virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0; + + virtual bool IsNameInUse(const std::string_view name) = 0; }; #endif //!__ICHARINFO__H__ diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index f56f229a..0f50f174 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -124,8 +124,9 @@ public: void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override; void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override; void DeleteUgcBuild(const LWOOBJID bigId) override; - sql::PreparedStatement* CreatePreppedStmt(const std::string& query); uint32_t GetAccountCount() override; + bool IsNameInUse(const std::string_view name) override; + sql::PreparedStatement* CreatePreppedStmt(const std::string& query); private: // Generic query functions that can be used for any query. diff --git a/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp index 7406e69b..ca8103d6 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/CharInfo.cpp @@ -76,3 +76,9 @@ void MySQLDatabase::SetPendingCharacterName(const uint32_t characterId, const st void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1", static_cast(time(NULL)), characterId); } + +bool MySQLDatabase::IsNameInUse(const std::string_view name) { + auto result = ExecuteSelect("SELECT name FROM charinfo WHERE name = ? or pending_name = ? LIMIT 1;", name, name); + + return result->next(); +} diff --git a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h index 14aad75d..f456c459 100644 --- a/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h +++ b/dDatabase/GameDatabase/SQLite/SQLiteDatabase.h @@ -123,6 +123,7 @@ public: void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override; void DeleteUgcBuild(const LWOOBJID bigId) override; uint32_t GetAccountCount() override; + bool IsNameInUse(const std::string_view name) override; private: CppSQLite3Statement CreatePreppedStmt(const std::string& query); diff --git a/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp b/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp index 27ae3611..7853442c 100644 --- a/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp +++ b/dDatabase/GameDatabase/SQLite/Tables/CharInfo.cpp @@ -77,3 +77,9 @@ void SQLiteDatabase::SetPendingCharacterName(const uint32_t characterId, const s void SQLiteDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ?;", static_cast(time(NULL)), characterId); } + +bool SQLiteDatabase::IsNameInUse(const std::string_view name) { + auto [_, result] = ExecuteSelect("SELECT name FROM charinfo WHERE name = ? or pending_name = ? LIMIT 1;", name, name); + + return result.eof(); +} diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h index 5a56610c..1cbb3c7b 100644 --- a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h @@ -102,6 +102,8 @@ class TestSQLDatabase : public GameDatabase { void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional characterId) override {}; void DeleteUgcBuild(const LWOOBJID bigId) override {}; uint32_t GetAccountCount() override { return 0; }; + + bool IsNameInUse(const std::string_view name) override { return false; }; }; #endif //!TESTSQLDATABASE_H diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index e0e37e7c..1cd9bbe5 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -305,13 +305,13 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle); LOT pantsLOT = FindCharPantsID(pantsColor); - if (!name.empty() && Database::Get()->GetCharacterInfo(name)) { + if (!name.empty() && Database::Get()->IsNameInUse(name)) { LOG("AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str()); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE); return; } - if (Database::Get()->GetCharacterInfo(predefinedName)) { + if (Database::Get()->IsNameInUse(predefinedName)) { LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str()); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE); return; @@ -324,7 +324,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) } //Now that the name is ok, we can get an objectID from Master: - ObjectIDManager::RequestPersistentID([=, this](uint32_t objectID) mutable { + ObjectIDManager::RequestPersistentID([=, this](uint32_t objectID) { if (Database::Get()->GetCharacterInfo(objectID)) { LOG("Character object id unavailable, check object_id_tracker!"); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE); @@ -369,13 +369,14 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) // If predefined name is invalid, change it to be their object id // that way more than one player can create characters if the predefined name files are not provided - if (predefinedName == "INVALID") { + auto assignedPredefinedName = predefinedName; + if (assignedPredefinedName == "INVALID") { std::stringstream nameObjID; nameObjID << "minifig" << objectID; - predefinedName = nameObjID.str(); + assignedPredefinedName = nameObjID.str(); } - std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName; + std::string_view nameToAssign = !name.empty() && nameOk ? name : assignedPredefinedName; std::string pendingName = !name.empty() && !nameOk ? name : ""; ICharInfo::Info info;