From ae355720abb70f0f27b3dcc7b711c76483ac0d07 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 4 Jan 2013 20:34:39 +0000 Subject: Fix llGetLinkKey() to return the last sat avatar as the last link number. As per http://wiki.secondlife.com/wiki/LlGetLinkKey This is done by keeping a scene-object wide list of sitters. This also fixes bugs in this function where linknums 0 and 1 weren't treated properly if there were sitting avatars on a single prim. This also fixes a minor race condition for multiple concurrent sitters on a prim with no current sitters by locking on the object-wide list rather than individual sop lists Addresses http://opensimulator.org/mantis/view.php?id=6477 --- .../Region/Framework/Scenes/SceneObjectGroup.cs | 35 ++++++++-- OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 79 +++++++++++----------- 2 files changed, 68 insertions(+), 46 deletions(-) (limited to 'OpenSim/Region/Framework') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 35e7c45..15795e5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -647,6 +647,18 @@ namespace OpenSim.Region.Framework.Scenes /// public UUID FromFolderID { get; set; } + /// + /// IDs of all avatars sat on this scene object. + /// + /// + /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts. + /// This must be locked before it is read or written. + /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions. + /// No avatar should appear more than once in this list. + /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart. + /// + protected internal List m_sittingAvatars = new List(); + #endregion // ~SceneObjectGroup() @@ -3564,17 +3576,28 @@ namespace OpenSim.Region.Framework.Scenes } /// + /// Get a copy of the list of sitting avatars on all prims of this object. + /// + /// + /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat + /// down after it move one place down the list. + /// + /// A list of the sitting avatars. Returns an empty list if there are no sitting avatars. + public List GetSittingAvatars() + { + lock (m_sittingAvatars) + return new List(m_sittingAvatars); + } + + /// /// Gets the number of sitting avatars. /// /// This applies to all sitting avatars whether there is a sit target set or not. /// public int GetSittingAvatarsCount() { - int count = 0; - - Array.ForEach(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount()); - - return count; + lock (m_sittingAvatars) + return m_sittingAvatars.Count; } public override string ToString() @@ -3583,7 +3606,7 @@ namespace OpenSim.Region.Framework.Scenes } #region ISceneObject - + public virtual ISceneObject CloneForNewScene() { SceneObjectGroup sog = Copy(false); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 7a97e5f..232861e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -1256,7 +1256,7 @@ namespace OpenSim.Region.Framework.Scenes public UUID SitTargetAvatar { get; set; } /// - /// IDs of all avatars start on this object part. + /// IDs of all avatars sat on this part. /// /// /// We need to track this so that we can stop sat upon prims from being attached. @@ -4504,18 +4504,22 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal bool AddSittingAvatar(UUID avatarId) { - if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) - SitTargetAvatar = avatarId; + lock (ParentGroup.m_sittingAvatars) + { + if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) + SitTargetAvatar = avatarId; - HashSet sittingAvatars = m_sittingAvatars; + if (m_sittingAvatars == null) + m_sittingAvatars = new HashSet(); - if (sittingAvatars == null) - sittingAvatars = new HashSet(); + if (m_sittingAvatars.Add(avatarId)) + { + ParentGroup.m_sittingAvatars.Add(avatarId); - lock (sittingAvatars) - { - m_sittingAvatars = sittingAvatars; - return m_sittingAvatars.Add(avatarId); + return true; + } + + return false; } } @@ -4529,27 +4533,26 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal bool RemoveSittingAvatar(UUID avatarId) { - if (SitTargetAvatar == avatarId) - SitTargetAvatar = UUID.Zero; - - HashSet sittingAvatars = m_sittingAvatars; + lock (ParentGroup.m_sittingAvatars) + { + if (SitTargetAvatar == avatarId) + SitTargetAvatar = UUID.Zero; - // This can occur under a race condition where another thread - if (sittingAvatars == null) - return false; + if (m_sittingAvatars == null) + return false; - lock (sittingAvatars) - { - if (sittingAvatars.Remove(avatarId)) + if (m_sittingAvatars.Remove(avatarId)) { - if (sittingAvatars.Count == 0) + if (m_sittingAvatars.Count == 0) m_sittingAvatars = null; + ParentGroup.m_sittingAvatars.Remove(avatarId); + return true; } - } - return false; + return false; + } } /// @@ -4559,16 +4562,12 @@ namespace OpenSim.Region.Framework.Scenes /// A hashset of the sitting avatars. Returns null if there are no sitting avatars. public HashSet GetSittingAvatars() { - HashSet sittingAvatars = m_sittingAvatars; - - if (sittingAvatars == null) - { - return null; - } - else + lock (ParentGroup.m_sittingAvatars) { - lock (sittingAvatars) - return new HashSet(sittingAvatars); + if (m_sittingAvatars == null) + return null; + else + return new HashSet(m_sittingAvatars); } } @@ -4579,13 +4578,13 @@ namespace OpenSim.Region.Framework.Scenes /// public int GetSittingAvatarsCount() { - HashSet sittingAvatars = m_sittingAvatars; - - if (sittingAvatars == null) - return 0; - - lock (sittingAvatars) - return sittingAvatars.Count; + lock (ParentGroup.m_sittingAvatars) + { + if (m_sittingAvatars == null) + return 0; + else + return m_sittingAvatars.Count; + } } } -} +} \ No newline at end of file -- cgit v1.1