diff --git a/Source/Framework/Database/Databases/LoginDatabase.cs b/Source/Framework/Database/Databases/LoginDatabase.cs index 762c07bd5..037ce4a15 100644 --- a/Source/Framework/Database/Databases/LoginDatabase.cs +++ b/Source/Framework/Database/Databases/LoginDatabase.cs @@ -79,8 +79,7 @@ namespace Framework.Database PrepareStatement(LoginStatements.DEL_ACCOUNT_ACCESS_BY_REALM, "DELETE FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1)"); PrepareStatement(LoginStatements.INS_ACCOUNT_ACCESS, "INSERT INTO account_access (AccountID, SecurityLevel, RealmID) VALUES (?, ?, ?)"); PrepareStatement(LoginStatements.GET_ACCOUNT_ID_BY_USERNAME, "SELECT id FROM account WHERE username = ?"); - PrepareStatement(LoginStatements.GET_ACCOUNT_ACCESS_GMLEVEL, "SELECT SecurityLevel FROM account_access WHERE AccountID = ?"); - PrepareStatement(LoginStatements.GET_GMLEVEL_BY_REALMID, "SELECT SecurityLevel FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1)"); + PrepareStatement(LoginStatements.GET_GMLEVEL_BY_REALMID, "SELECT SecurityLevel FROM account_access WHERE AccountID = ? AND (RealmID = ? OR RealmID = -1) ORDER BY RealmID DESC"); PrepareStatement(LoginStatements.GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?"); PrepareStatement(LoginStatements.SEL_CHECK_PASSWORD, "SELECT salt, verifier FROM account WHERE id = ? AND salt IS NOT NULL AND verifier IS NOT NULL"); PrepareStatement(LoginStatements.SEL_CHECK_PASSWORD_BY_NAME, "SELECT salt, verifier FROM account WHERE username = ? AND salt IS NOT NULL AND verifier IS NOT NULL"); @@ -231,7 +230,6 @@ namespace Framework.Database DEL_ACCOUNT_ACCESS_BY_REALM, INS_ACCOUNT_ACCESS, GET_ACCOUNT_ID_BY_USERNAME, - GET_ACCOUNT_ACCESS_GMLEVEL, GET_GMLEVEL_BY_REALMID, GET_USERNAME_BY_ID, SEL_CHECK_PASSWORD, diff --git a/Source/Game/Accounts/AccountManager.cs b/Source/Game/Accounts/AccountManager.cs index 76a3c21aa..d27e2dd9a 100644 --- a/Source/Game/Accounts/AccountManager.cs +++ b/Source/Game/Accounts/AccountManager.cs @@ -247,14 +247,6 @@ namespace Game return !result.IsEmpty() ? result.Read(0) : 0; } - public AccountTypes GetSecurity(uint accountId) - { - PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_ACCOUNT_ACCESS_GMLEVEL); - stmt.AddValue(0, accountId); - SQLResult result = DB.Login.Query(stmt); - return !result.IsEmpty() ? (AccountTypes)result.Read(0) : AccountTypes.Player; - } - public AccountTypes GetSecurity(uint accountId, int realmId) { PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_GMLEVEL_BY_REALMID); @@ -264,6 +256,17 @@ namespace Game return !result.IsEmpty() ? (AccountTypes)result.Read(0) : AccountTypes.Player; } + public QueryCallback GetSecurityAsync(uint accountId, int realmId, Action callback) + { + PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_GMLEVEL_BY_REALMID); + stmt.AddValue(0, accountId); + stmt.AddValue(1, realmId); + return DB.Login.AsyncQuery(stmt).WithCallback(result => + { + callback(!result.IsEmpty() ? result.Read(0) : (uint)AccountTypes.Player); + }); + } + public bool GetName(uint accountId, out string name) { name = ""; @@ -497,7 +500,7 @@ namespace Game return false; } - RBACData rbac = new(accountId, "", (int)realmId); + RBACData rbac = new(accountId, "", (int)realmId, (byte)GetSecurity(accountId, (int)realmId)); rbac.LoadFromDB(); bool hasPermission = rbac.HasPermission(permissionId); diff --git a/Source/Game/Entities/Player/SocialMgr.cs b/Source/Game/Entities/Player/SocialMgr.cs index 4e419c122..3dd9e8710 100644 --- a/Source/Game/Entities/Player/SocialMgr.cs +++ b/Source/Game/Entities/Player/SocialMgr.cs @@ -34,7 +34,7 @@ namespace Game.Entities public const int FriendLimit = 50; public const int IgnoreLimit = 50; - public void GetFriendInfo(Player player, ObjectGuid friendGUID, FriendInfo friendInfo) + public static void GetFriendInfo(Player player, ObjectGuid friendGUID, FriendInfo friendInfo) { if (!player) return; @@ -283,7 +283,7 @@ namespace Game.Entities if (++ignoredCount > SocialManager.IgnoreLimit) continue; - Global.SocialMgr.GetFriendInfo(player, v.Key, v.Value); + SocialManager.GetFriendInfo(player, v.Key, v.Value); contactList.Contacts.Add(new ContactInfo(v.Key, v.Value)); } diff --git a/Source/Game/Handlers/SocialHandler.cs b/Source/Game/Handlers/SocialHandler.cs index e721fa23f..fd6be009e 100644 --- a/Source/Game/Handlers/SocialHandler.cs +++ b/Source/Game/Handlers/SocialHandler.cs @@ -222,42 +222,88 @@ namespace Game if (!ObjectManager.NormalizePlayerName(ref packet.Name)) return; - FriendsResult friendResult = FriendsResult.NotFound; - ObjectGuid friendGuid = ObjectGuid.Empty; - - CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByName(packet.Name); - if (characterInfo != null) + CharacterCacheEntry friendCharacterInfo = Global.CharacterCacheStorage.GetCharacterCacheByName(packet.Name); + if (friendCharacterInfo == null) { - friendGuid = characterInfo.Guid; - ObjectGuid friendAccountGuid = ObjectGuid.Create(HighGuid.WowAccount, characterInfo.AccountId); - Team team = Player.TeamForRace(characterInfo.RaceId); - uint friendAccountId = characterInfo.AccountId; - - if (HasPermission(RBACPermissions.AllowGmFriend) || Global.AccountMgr.IsPlayerAccount(Global.AccountMgr.GetSecurity(friendAccountId, (int)Global.WorldMgr.GetRealm().Id.Index))) - { - if (friendGuid == GetPlayer().GetGUID()) - friendResult = FriendsResult.Self; - else if (GetPlayer().GetTeam() != team && !HasPermission(RBACPermissions.TwoSideAddFriend)) - friendResult = FriendsResult.Enemy; - else if (GetPlayer().GetSocial().HasFriend(friendGuid)) - friendResult = FriendsResult.Already; - else - { - Player playerFriend = Global.ObjAccessor.FindPlayer(friendGuid); - if (playerFriend && playerFriend.IsVisibleGloballyFor(GetPlayer())) - friendResult = FriendsResult.AddedOnline; - else - friendResult = FriendsResult.AddedOffline; - - if (GetPlayer().GetSocial().AddToSocialList(friendGuid, friendAccountGuid, SocialFlag.Friend)) - GetPlayer().GetSocial().SetFriendNote(friendGuid, packet.Notes); - else - friendResult = FriendsResult.ListFull; - } - } + Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.NotFound, ObjectGuid.Empty); + return; } - Global.SocialMgr.SendFriendStatus(GetPlayer(), friendResult, friendGuid); + void processFriendRequest() + { + var playerGuid = _player.GetGUID(); + var friendGuid = friendCharacterInfo.Guid; + var friendAccountGuid = ObjectGuid.Create(HighGuid.WowAccount, friendCharacterInfo.AccountId); + var team = Player.TeamForRace(friendCharacterInfo.RaceId); + var friendNote = packet.Notes; + + if (playerGuid.GetCounter() != m_GUIDLow) + return; // not the player initiating request, do nothing + + FriendsResult friendResult = FriendsResult.NotFound; + if (friendGuid == GetPlayer().GetGUID()) + friendResult = FriendsResult.Self; + else if (GetPlayer().GetTeam() != team && !HasPermission(RBACPermissions.TwoSideAddFriend)) + friendResult = FriendsResult.Enemy; + else if (GetPlayer().GetSocial().HasFriend(friendGuid)) + friendResult = FriendsResult.Already; + else + { + Player pFriend = Global.ObjAccessor.FindPlayer(friendGuid); + if (pFriend != null && pFriend.IsVisibleGloballyFor(GetPlayer())) + friendResult = FriendsResult.Online; + else + friendResult = FriendsResult.AddedOnline; + if (GetPlayer().GetSocial().AddToSocialList(friendGuid, friendAccountGuid, SocialFlag.Friend)) + GetPlayer().GetSocial().SetFriendNote(friendGuid, friendNote); + else + friendResult = FriendsResult.ListFull; + } + + Global.SocialMgr.SendFriendStatus(GetPlayer(), friendResult, friendGuid); + } + + if (HasPermission(RBACPermissions.AllowGmFriend)) + { + processFriendRequest(); + return; + } + + // First try looking up friend candidate security from online object + Player friendPlayer = Global.ObjAccessor.FindPlayer(friendCharacterInfo.Guid); + if (friendPlayer != null) + { + if (!Global.AccountMgr.IsPlayerAccount(friendPlayer.GetSession().GetSecurity())) + { + Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.NotFound, ObjectGuid.Empty); + return; + } + + processFriendRequest(); + return; + } + + // When not found, consult database + GetQueryProcessor().AddCallback(Global.AccountMgr.GetSecurityAsync(friendCharacterInfo.AccountId, (int)Global.WorldMgr.GetRealmId().Index, friendSecurity => + { + if (!Global.AccountMgr.IsPlayerAccount((AccountTypes)friendSecurity)) + { + Global.SocialMgr.SendFriendStatus(GetPlayer(), FriendsResult.NotFound, ObjectGuid.Empty); + return; + } + + processFriendRequest(); + })); + + + + + + + + + + } [WorldPacketHandler(ClientOpcodes.DelFriend)]