From b327224b74b7e5dfb98cce34b67cdd4d31be8f9b Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Wed, 1 Feb 2023 18:56:08 +0000 Subject: [PATCH] try improve profiles online indication a bit more --- .../Avatar/Friends/FriendsModule.cs | 80 ++++++++++++++++--- .../Avatar/Friends/HGStatusNotifier.cs | 14 +++- .../Avatar/UserProfiles/UserProfileModule.cs | 34 ++++---- .../Framework/Interfaces/IFriendsModule.cs | 3 + 4 files changed, 97 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 6c99761d72..b224f878c2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -88,6 +88,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends /// protected Dictionary m_Friends = new(); + protected Dictionary> m_OnlineFriendsCache = new(); + /// /// Maintain a record of clients that need to notify about their online status. This only /// needs to be done on login. Subsequent online/offline friend changes are sent by a different mechanism. @@ -241,15 +243,54 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends public virtual int GetRightsGrantedByFriend(UUID principalID, UUID friendID) { FriendInfo[] friends = GetFriendsFromCache(principalID); - FriendInfo finfo = GetFriend(friends, friendID); - if (finfo is not null && finfo.TheirFlags != -1) + if (friends.Length > 0) { - return finfo.TheirFlags; + FriendInfo finfo = GetFriend(friends, friendID); + if (finfo is not null && finfo.TheirFlags != -1) + { + return finfo.TheirFlags; + } } return 0; } - private void OnMakeRootAgent(ScenePresence sp) + public bool IsFriendOnline(UUID userID, UUID friendID) + { + if(m_OnlineFriendsCache.TryGetValue(userID, out HashSet friends)) + return friends.Contains(friendID); + return false; + } + + public void CacheFriendsOnline(UUID userID, List friendsOnline, bool online) + { + if (!m_OnlineFriendsCache.TryGetValue(userID, out HashSet friends)) + { + friends = new HashSet(); + m_OnlineFriendsCache[userID] = friends; + } + foreach (UUID friendID in friendsOnline) + { + if (online) + friends.Add(friendID); + else + friends.Remove(friendID); + } + } + + public void CacheFriendOnline(UUID userID, UUID friendID, bool online) + { + if (!m_OnlineFriendsCache.TryGetValue(userID, out HashSet friends)) + { + friends = new HashSet(); + m_OnlineFriendsCache[userID] = friends; + } + if (online) + friends.Add(friendID); + else + friends.Remove(friendID); + } + + private void OnMakeRootAgent(ScenePresence sp) { if(sp.m_gotCrossUpdate) return; @@ -333,6 +374,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends lock (m_Friends) { + m_OnlineFriendsCache.Remove(agentID); if (m_Friends.TryGetValue(agentID, out UserFriendData friendsData)) { friendsData.Refcount--; @@ -438,17 +480,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends List GetOnlineFriends(UUID userID) { - List friendList = new(); - + List online = new(); FriendInfo[] friends = GetFriendsFromCache(userID); + if(friends.Length == 0) + return online; + + List friendList = new(friends.Length); foreach (FriendInfo fi in friends) { if (((fi.TheirFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1)) friendList.Add(fi.Friend); } - List online = new(); - if (friendList.Count > 0) GetOnlineFriends(userID, friendList, online); @@ -458,16 +501,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return online; } - protected virtual void GetOnlineFriends(UUID userID, List friendList, /*collector*/ List online) + protected virtual void GetOnlineFriends(UUID userID, List friendList, List online) { //m_log.DebugFormat( // "[FRIENDS MODULE]: Looking for online presence of {0} users for {1}", friendList.Count, userID); PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray()); + if(presence.Length == 0) + return; + + if (!m_OnlineFriendsCache.TryGetValue(userID, out HashSet friends)) + { + friends = new HashSet(); + m_OnlineFriendsCache[userID] = friends; + } + foreach (PresenceInfo pi in presence) { if (UUID.TryParse(pi.UserID, out UUID presenceID)) + { online.Add(presenceID); + friends.Add(presenceID); + } } } @@ -962,6 +1017,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends IClientAPI friendClient = LocateClientObject(friendID); if (friendClient is not null) { + CacheFriendOnline(friendID, userID, online); // the friend in this sim as root agent if (online) friendClient.SendAgentOnline(new UUID[] { userID }); @@ -1001,7 +1057,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends lock (m_Friends) { FriendInfo[] friends = GetFriendsFromCache(friendID); - if(friends != EMPTY_FRIENDS) + if(friends.Length > 0) { FriendInfo finfo = GetFriend(friends, userID); if(finfo is not null) @@ -1019,11 +1075,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event // is on the critical path for transferring an avatar from one region to another. - UUID agentID = client.AgentId; lock (m_Friends) { - UserFriendData friendsData; - if (m_Friends.TryGetValue(agentID, out friendsData)) + if (m_Friends.TryGetValue(client.AgentId, out UserFriendData friendsData)) friendsData.Friends = GetFriendsFromService(client); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs index 542a7c1e4d..5ed72139d1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGStatusNotifier.cs @@ -28,6 +28,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends public void Notify(UUID userID, Dictionary> friendsPerDomain, bool online) { + if(m_FriendsModule is null) + return; + foreach (KeyValuePair> kvp in friendsPerDomain) { // For the others, call the user agent service @@ -51,10 +54,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends List friendsOnline = fConn.StatusNotification(ids, userID, online); - if (online && friendsOnline.Count > 0) + if (friendsOnline.Count > 0) { IClientAPI client = m_FriendsModule.LocateClientObject(userID); - client?.SendAgentOnline(friendsOnline.ToArray()); + if(client is not null) + { + m_FriendsModule.CacheFriendsOnline(userID, friendsOnline, online); + if(online) + client?.SendAgentOnline(friendsOnline.ToArray()); + else + client?.SendAgentOffline(friendsOnline.ToArray()); + } } } } diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs index fe322bf3fb..f63744a36c 100644 --- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs @@ -155,7 +155,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles m_profilesCache.AddOrUpdate(props.UserId, uce, PROFILECACHEEXPIRE); } - if (IsFriendOnline(req.client.AgentId, req.agent)) + if (IsFriendOnline(req.client, req.agent)) flags |= (uint)ProfileFlags.Online; else flags &= (uint)~ProfileFlags.Online; @@ -1086,9 +1086,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { //m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); - UserProfilePick pick = new UserProfilePick(); - string serverURI = string.Empty; - GetUserProfileServerURI(remoteClient.AgentId, out serverURI); + UserProfilePick pick = new(); + GetUserProfileServerURI(remoteClient.AgentId, out string serverURI); if(string.IsNullOrWhiteSpace(serverURI)) return; @@ -1192,10 +1191,8 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles { if(m_profilesCache.TryGetValue(remoteClient.AgentId, out uce) && uce is not null) { - if(uce.picks != null && uce.picks.ContainsKey(queryPickID)) - uce.picks.Remove(queryPickID); - if(uce.picksList is not null) - uce.picksList.Remove(queryPickID); + uce.picks?.Remove(queryPickID); + uce.picksList?.Remove(queryPickID); m_profilesCache.AddOrUpdate(remoteClient.AgentId, uce, PROFILECACHEEXPIRE); } } @@ -1451,7 +1448,7 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles props = uce.props; uint cflags = uce.flags; - if (IsFriendOnline(remoteClient.AgentId, avatarID)) + if (IsFriendOnline(remoteClient, avatarID)) cflags = (uint)ProfileFlags.Online; else cflags &= (uint)~ProfileFlags.Online; @@ -1831,22 +1828,21 @@ namespace OpenSim.Region.CoreModules.Avatar.UserProfiles return null; } - public virtual bool IsFriendOnline(UUID client, UUID agent) + public virtual bool IsFriendOnline(IClientAPI client, UUID agent) { - // if on same region force online + // if on same region force online ScenePresence p = Scene.GetScenePresence(agent); - if (p is not null && !p.IsDeleted) + if (p is not null && !p.IsChildAgent && !p.IsDeleted) return true; IFriendsModule friendsModule = Scene.RequestModuleInterface(); - if (friendsModule is not null) + if (friendsModule is not null && friendsModule.IsFriendOnline(client.AgentId, agent)) + return true; + + if(client.SceneAgent is ScenePresence sp && sp.IsViewerUIGod) { - int friendPerms = friendsModule.GetRightsGrantedByFriend(client, agent); - if((friendPerms & (int)FriendRights.CanSeeOnline) != 0) - { - Services.Interfaces.PresenceInfo[] pi = Scene.PresenceService?.GetAgents(new string[] { agent.ToString() }); - return pi is not null && pi.Length > 0; - } + Services.Interfaces.PresenceInfo[] pi = Scene.PresenceService?.GetAgents(new string[] { agent.ToString() }); + return pi != null && pi.Length > 0; } return false; } diff --git a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs index ec014f4619..3bd7fbfbf2 100644 --- a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs @@ -96,5 +96,8 @@ namespace OpenSim.Region.Framework.Interfaces void IsNowRoot(ScenePresence sp); bool SendFriendsOnlineIfNeeded(IClientAPI client); + bool IsFriendOnline(UUID userID, UUID friendID); + void CacheFriendsOnline(UUID userID, List friendsOnline, bool online); + void CacheFriendOnline(UUID userID, UUID friendOnline, bool online); } } \ No newline at end of file