check pending names too (#1748)

This commit is contained in:
David Markowitz 2025-03-28 15:03:04 -07:00 committed by GitHub
parent d104559cc4
commit 347fc46f01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 26 additions and 7 deletions

View File

@ -44,6 +44,8 @@ public:
// Updates the given character ids last login to be right now. // Updates the given character ids last login to be right now.
virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0; virtual void UpdateLastLoggedInCharacter(const uint32_t characterId) = 0;
virtual bool IsNameInUse(const std::string_view name) = 0;
}; };
#endif //!__ICHARINFO__H__ #endif //!__ICHARINFO__H__

View File

@ -124,8 +124,9 @@ public:
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override; void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override;
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override; void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override;
void DeleteUgcBuild(const LWOOBJID bigId) override; void DeleteUgcBuild(const LWOOBJID bigId) override;
sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
uint32_t GetAccountCount() override; uint32_t GetAccountCount() override;
bool IsNameInUse(const std::string_view name) override;
sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
private: private:
// Generic query functions that can be used for any query. // Generic query functions that can be used for any query.

View File

@ -76,3 +76,9 @@ void MySQLDatabase::SetPendingCharacterName(const uint32_t characterId, const st
void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { void MySQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1", static_cast<uint32_t>(time(NULL)), characterId); ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ? LIMIT 1", static_cast<uint32_t>(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();
}

View File

@ -123,6 +123,7 @@ public:
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override; void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override;
void DeleteUgcBuild(const LWOOBJID bigId) override; void DeleteUgcBuild(const LWOOBJID bigId) override;
uint32_t GetAccountCount() override; uint32_t GetAccountCount() override;
bool IsNameInUse(const std::string_view name) override;
private: private:
CppSQLite3Statement CreatePreppedStmt(const std::string& query); CppSQLite3Statement CreatePreppedStmt(const std::string& query);

View File

@ -77,3 +77,9 @@ void SQLiteDatabase::SetPendingCharacterName(const uint32_t characterId, const s
void SQLiteDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { void SQLiteDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ?;", static_cast<uint32_t>(time(NULL)), characterId); ExecuteUpdate("UPDATE charinfo SET last_login = ? WHERE id = ?;", static_cast<uint32_t>(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();
}

View File

@ -102,6 +102,8 @@ class TestSQLDatabase : public GameDatabase {
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override {}; void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override {};
void DeleteUgcBuild(const LWOOBJID bigId) override {}; void DeleteUgcBuild(const LWOOBJID bigId) override {};
uint32_t GetAccountCount() override { return 0; }; uint32_t GetAccountCount() override { return 0; };
bool IsNameInUse(const std::string_view name) override { return false; };
}; };
#endif //!TESTSQLDATABASE_H #endif //!TESTSQLDATABASE_H

View File

@ -305,13 +305,13 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle); LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle);
LOT pantsLOT = FindCharPantsID(pantsColor); 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()); LOG("AccountID: %i chose unavailable name: %s", u->GetAccountID(), name.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::CUSTOM_NAME_IN_USE);
return; return;
} }
if (Database::Get()->GetCharacterInfo(predefinedName)) { if (Database::Get()->IsNameInUse(predefinedName)) {
LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str()); LOG("AccountID: %i chose unavailable predefined name: %s", u->GetAccountID(), predefinedName.c_str());
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE); WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::PREDEFINED_NAME_IN_USE);
return; 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: //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)) { if (Database::Get()->GetCharacterInfo(objectID)) {
LOG("Character object id unavailable, check object_id_tracker!"); LOG("Character object id unavailable, check object_id_tracker!");
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE); 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 // 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 // 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; std::stringstream nameObjID;
nameObjID << "minifig" << objectID; 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 : ""; std::string pendingName = !name.empty() && !nameOk ? name : "";
ICharInfo::Info info; ICharInfo::Info info;