diff options
-rw-r--r-- | src/server/database/Database/Implementation/LoginDatabase.cpp | 3 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/LoginDatabase.h | 1 | ||||
-rw-r--r-- | src/server/game/Accounts/AccountMgr.cpp | 16 | ||||
-rw-r--r-- | src/server/game/Accounts/AccountMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/SocialMgr.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/SocialMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/Handlers/SocialHandler.cpp | 97 | ||||
-rw-r--r-- | src/server/worldserver/TCSoap/TCSoap.cpp | 3 |
8 files changed, 80 insertions, 46 deletions
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 64986ee955d..39337f03963 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -82,8 +82,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM, "DELETE FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_ACCESS, "INSERT INTO account_access (AccountID, SecurityLevel, RealmID) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL, "SELECT SecurityLevel FROM account_access WHERE AccountID = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_GET_GMLEVEL_BY_REALMID, "SELECT SecurityLevel FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1)", CONNECTION_SYNCH); + PrepareStatement(LOGIN_GET_GMLEVEL_BY_REALMID, "SELECT SecurityLevel FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1) ORDER BY RealmID DESC", CONNECTION_BOTH); PrepareStatement(LOGIN_GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD, "SELECT 1 FROM account WHERE id = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT 1 FROM account WHERE username = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index f7ae3a349d0..eee8302457c 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -81,7 +81,6 @@ enum LoginDatabaseStatements : uint32 LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM, LOGIN_INS_ACCOUNT_ACCESS, LOGIN_GET_ACCOUNT_ID_BY_USERNAME, - LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL, LOGIN_GET_GMLEVEL_BY_REALMID, LOGIN_GET_USERNAME_BY_ID, LOGIN_SEL_CHECK_PASSWORD, diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 310c0c19289..36c2e7955cb 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -283,23 +283,25 @@ uint32 AccountMgr::GetId(std::string const& username) return (result) ? (*result)[0].GetUInt32() : 0; } -uint32 AccountMgr::GetSecurity(uint32 accountId) +uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) { - LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, accountId); + stmt->setInt32(1, realmId); PreparedQueryResult result = LoginDatabase.Query(stmt); return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER); } -uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) +QueryCallback AccountMgr::GetSecurityAsync(uint32 accountId, int32 realmId, std::function<void(uint32)> callback) { LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, accountId); stmt->setInt32(1, realmId); - PreparedQueryResult result = LoginDatabase.Query(stmt); - - return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER); + return LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([callback = std::move(callback)](PreparedQueryResult result) + { + callback(result ? uint32((*result)[0].GetUInt8()) : uint32(SEC_PLAYER)); + }); } bool AccountMgr::GetName(uint32 accountId, std::string& name) @@ -548,7 +550,7 @@ bool AccountMgr::HasPermission(uint32 accountId, uint32 permissionId, uint32 rea return false; } - rbac::RBACData rbac(accountId, "", realmId, GetSecurity(accountId)); + rbac::RBACData rbac(accountId, "", realmId, GetSecurity(accountId, realmId)); rbac.LoadFromDB(); bool hasPermission = rbac.HasPermission(permissionId); diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 040562d6050..07a3d694492 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -67,8 +67,8 @@ class TC_GAME_API AccountMgr static bool CheckEmail(uint32 accountId, std::string newEmail); static uint32 GetId(std::string const& username); - static uint32 GetSecurity(uint32 accountId); static uint32 GetSecurity(uint32 accountId, int32 realmId); + [[nodiscard]] static QueryCallback GetSecurityAsync(uint32 accountId, int32 realmId, std::function<void(uint32)> callback); static bool GetName(uint32 accountId, std::string& name); static bool GetEmail(uint32 accountId, std::string& email); static uint32 GetCharactersCount(uint32 accountId); diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index 4922fb52f5f..a7a5ef2840b 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -151,7 +151,7 @@ void PlayerSocial::SendSocialList(Player* player, uint32 flags) continue; ++totalCount; - sSocialMgr->GetFriendInfo(player, v.first, v.second); + SocialMgr::GetFriendInfo(player, v.first, v.second); data << uint64(v.first); // player guid data << uint32(contactFlags); // player flag (0x1 = Friend, 0x2 = Ignored, 0x4 = Muted) diff --git a/src/server/game/Entities/Player/SocialMgr.h b/src/server/game/Entities/Player/SocialMgr.h index 81709cd15d0..413b835d058 100644 --- a/src/server/game/Entities/Player/SocialMgr.h +++ b/src/server/game/Entities/Player/SocialMgr.h @@ -142,7 +142,7 @@ class SocialMgr // Misc void RemovePlayerSocial(ObjectGuid const& guid) { _socialMap.erase(guid); } - void GetFriendInfo(Player* player, ObjectGuid const& friendGUID, FriendInfo& friendInfo); + static void GetFriendInfo(Player* player, ObjectGuid const& friendGUID, FriendInfo& friendInfo); // Packet send's void SendFriendStatus(Player* player, FriendsResult result, ObjectGuid const& friendGuid, bool broadcast = false); diff --git a/src/server/game/Handlers/SocialHandler.cpp b/src/server/game/Handlers/SocialHandler.cpp index c3fd69433bd..4271570e945 100644 --- a/src/server/game/Handlers/SocialHandler.cpp +++ b/src/server/game/Handlers/SocialHandler.cpp @@ -45,43 +45,76 @@ void WorldSession::HandleAddFriendOpcode(WorldPacket& recvData) TC_LOG_DEBUG("network", "WorldSession::HandleAddFriendOpcode: %s asked to add friend: %s", GetPlayer()->GetName().c_str(), friendName.c_str()); - FriendsResult friendResult = FRIEND_NOT_FOUND; - ObjectGuid friendGuid = sCharacterCache->GetCharacterGuidByName(friendName); - if (!friendGuid.IsEmpty()) + CharacterCacheEntry const* friendCharacterInfo = sCharacterCache->GetCharacterCacheByName(friendName); + if (!friendCharacterInfo) { - if (CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(friendGuid)) + sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_NOT_FOUND, ObjectGuid::Empty); + return; + } + + auto processFriendRequest = [this, + playerGuid = _player->GetGUID(), + friendGuid = friendCharacterInfo->Guid, + team = Player::TeamForRace(friendCharacterInfo->Race), + friendNote = std::move(friendNote)]() + { + if (playerGuid.GetCounter() != GetGUIDLow()) + return; // not the player initiating request, do nothing + + FriendsResult friendResult = FRIEND_NOT_FOUND; + if (friendGuid == GetPlayer()->GetGUID()) + friendResult = FRIEND_SELF; + else if (GetPlayer()->GetTeam() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND)) + friendResult = FRIEND_ENEMY; + else if (GetPlayer()->GetSocial()->HasFriend(friendGuid)) + friendResult = FRIEND_ALREADY; + else + { + Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); + if (pFriend && pFriend->IsVisibleGloballyFor(GetPlayer())) + friendResult = FRIEND_ADDED_ONLINE; + else + friendResult = FRIEND_ADDED_OFFLINE; + if (GetPlayer()->GetSocial()->AddToSocialList(friendGuid, SOCIAL_FLAG_FRIEND)) + GetPlayer()->GetSocial()->SetFriendNote(friendGuid, friendNote); + else + friendResult = FRIEND_LIST_FULL; + } + + sSocialMgr->SendFriendStatus(GetPlayer(), friendResult, friendGuid); + }; + + if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND)) + { + processFriendRequest(); + return; + } + + // First try looking up friend candidate security from online object + if (Player* friendPlayer = ObjectAccessor::FindPlayer(friendCharacterInfo->Guid)) + { + if (!AccountMgr::IsPlayerAccount(friendPlayer->GetSession()->GetSecurity())) { - uint32 team = Player::TeamForRace(characterInfo->Race); - uint32 friendAccountId = characterInfo->AccountId; - - if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realm.Id.Realm))) - { - if (friendGuid) - { - if (friendGuid == GetPlayer()->GetGUID()) - friendResult = FRIEND_SELF; - else if (GetPlayer()->GetTeam() != team && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_ADD_FRIEND)) - friendResult = FRIEND_ENEMY; - else if (GetPlayer()->GetSocial()->HasFriend(friendGuid)) - friendResult = FRIEND_ALREADY; - else - { - Player* pFriend = ObjectAccessor::FindPlayer(friendGuid); - if (pFriend && pFriend->IsVisibleGloballyFor(GetPlayer())) - friendResult = FRIEND_ADDED_ONLINE; - else - friendResult = FRIEND_ADDED_OFFLINE; - if (GetPlayer()->GetSocial()->AddToSocialList(friendGuid, SOCIAL_FLAG_FRIEND)) - GetPlayer()->GetSocial()->SetFriendNote(friendGuid, friendNote); - else - friendResult = FRIEND_LIST_FULL; - } - } - } + sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_NOT_FOUND, ObjectGuid::Empty); + return; } + + processFriendRequest(); + return; } - sSocialMgr->SendFriendStatus(GetPlayer(), friendResult, friendGuid); + // When not found, consult database + GetQueryProcessor().AddCallback(AccountMgr::GetSecurityAsync(friendCharacterInfo->AccountId, realm.Id.Realm, + [this, continuation = std::move(processFriendRequest)](uint32 friendSecurity) + { + if (!AccountMgr::IsPlayerAccount(friendSecurity)) + { + sSocialMgr->SendFriendStatus(GetPlayer(), FRIEND_NOT_FOUND, ObjectGuid::Empty); + return; + } + + continuation(); + })); } void WorldSession::HandleDelFriendOpcode(WorldPacket& recvData) diff --git a/src/server/worldserver/TCSoap/TCSoap.cpp b/src/server/worldserver/TCSoap/TCSoap.cpp index 6c8d5c95616..624fb35c600 100644 --- a/src/server/worldserver/TCSoap/TCSoap.cpp +++ b/src/server/worldserver/TCSoap/TCSoap.cpp @@ -18,6 +18,7 @@ #include "TCSoap.h" #include "soapH.h" #include "soapStub.h" +#include "Realm.h" #include "World.h" #include "AccountMgr.h" #include "Log.h" @@ -95,7 +96,7 @@ int ns1__executeCommand(soap* soap, char* command, char** result) return 401; } - if (AccountMgr::GetSecurity(accountId) < SEC_ADMINISTRATOR) + if (AccountMgr::GetSecurity(accountId, realm.Id.Realm) < SEC_ADMINISTRATOR) { TC_LOG_INFO("network.soap", "%s's gmlevel is too low", soap->userid); return 403; |