aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-01-04 20:34:39 +0000
committerJustin Clark-Casey (justincc)2013-01-04 20:34:39 +0000
commit9503383887d6af871e843cbcbb141a50df56f551 (patch)
tree85caf28a22c20e703aa60572db978dd7c929c4fc /OpenSim/Region
parentminor: Add some doc to the extremely unhelpful 'fudge....' comment as to why ... (diff)
downloadopensim-SC-9503383887d6af871e843cbcbb141a50df56f551.zip
opensim-SC-9503383887d6af871e843cbcbb141a50df56f551.tar.gz
opensim-SC-9503383887d6af871e843cbcbb141a50df56f551.tar.bz2
opensim-SC-9503383887d6af871e843cbcbb141a50df56f551.tar.xz
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
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs35
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs79
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs48
3 files changed, 99 insertions, 63 deletions
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
647 /// </remarks> 647 /// </remarks>
648 public UUID FromFolderID { get; set; } 648 public UUID FromFolderID { get; set; }
649 649
650 /// <summary>
651 /// IDs of all avatars sat on this scene object.
652 /// </summary>
653 /// <remarks>
654 /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
655 /// This must be locked before it is read or written.
656 /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
657 /// No avatar should appear more than once in this list.
658 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
659 /// </remarks>
660 protected internal List<UUID> m_sittingAvatars = new List<UUID>();
661
650 #endregion 662 #endregion
651 663
652// ~SceneObjectGroup() 664// ~SceneObjectGroup()
@@ -3564,17 +3576,28 @@ namespace OpenSim.Region.Framework.Scenes
3564 } 3576 }
3565 3577
3566 /// <summary> 3578 /// <summary>
3579 /// Get a copy of the list of sitting avatars on all prims of this object.
3580 /// </summary>
3581 /// <remarks>
3582 /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
3583 /// down after it move one place down the list.
3584 /// </remarks>
3585 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
3586 public List<UUID> GetSittingAvatars()
3587 {
3588 lock (m_sittingAvatars)
3589 return new List<UUID>(m_sittingAvatars);
3590 }
3591
3592 /// <summary>
3567 /// Gets the number of sitting avatars. 3593 /// Gets the number of sitting avatars.
3568 /// </summary> 3594 /// </summary>
3569 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> 3595 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
3570 /// <returns></returns> 3596 /// <returns></returns>
3571 public int GetSittingAvatarsCount() 3597 public int GetSittingAvatarsCount()
3572 { 3598 {
3573 int count = 0; 3599 lock (m_sittingAvatars)
3574 3600 return m_sittingAvatars.Count;
3575 Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount());
3576
3577 return count;
3578 } 3601 }
3579 3602
3580 public override string ToString() 3603 public override string ToString()
@@ -3583,7 +3606,7 @@ namespace OpenSim.Region.Framework.Scenes
3583 } 3606 }
3584 3607
3585 #region ISceneObject 3608 #region ISceneObject
3586 3609
3587 public virtual ISceneObject CloneForNewScene() 3610 public virtual ISceneObject CloneForNewScene()
3588 { 3611 {
3589 SceneObjectGroup sog = Copy(false); 3612 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
1256 public UUID SitTargetAvatar { get; set; } 1256 public UUID SitTargetAvatar { get; set; }
1257 1257
1258 /// <summary> 1258 /// <summary>
1259 /// IDs of all avatars start on this object part. 1259 /// IDs of all avatars sat on this part.
1260 /// </summary> 1260 /// </summary>
1261 /// <remarks> 1261 /// <remarks>
1262 /// We need to track this so that we can stop sat upon prims from being attached. 1262 /// 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
4504 /// <param name='avatarId'></param> 4504 /// <param name='avatarId'></param>
4505 protected internal bool AddSittingAvatar(UUID avatarId) 4505 protected internal bool AddSittingAvatar(UUID avatarId)
4506 { 4506 {
4507 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) 4507 lock (ParentGroup.m_sittingAvatars)
4508 SitTargetAvatar = avatarId; 4508 {
4509 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
4510 SitTargetAvatar = avatarId;
4509 4511
4510 HashSet<UUID> sittingAvatars = m_sittingAvatars; 4512 if (m_sittingAvatars == null)
4513 m_sittingAvatars = new HashSet<UUID>();
4511 4514
4512 if (sittingAvatars == null) 4515 if (m_sittingAvatars.Add(avatarId))
4513 sittingAvatars = new HashSet<UUID>(); 4516 {
4517 ParentGroup.m_sittingAvatars.Add(avatarId);
4514 4518
4515 lock (sittingAvatars) 4519 return true;
4516 { 4520 }
4517 m_sittingAvatars = sittingAvatars; 4521
4518 return m_sittingAvatars.Add(avatarId); 4522 return false;
4519 } 4523 }
4520 } 4524 }
4521 4525
@@ -4529,27 +4533,26 @@ namespace OpenSim.Region.Framework.Scenes
4529 /// <param name='avatarId'></param> 4533 /// <param name='avatarId'></param>
4530 protected internal bool RemoveSittingAvatar(UUID avatarId) 4534 protected internal bool RemoveSittingAvatar(UUID avatarId)
4531 { 4535 {
4532 if (SitTargetAvatar == avatarId) 4536 lock (ParentGroup.m_sittingAvatars)
4533 SitTargetAvatar = UUID.Zero; 4537 {
4534 4538 if (SitTargetAvatar == avatarId)
4535 HashSet<UUID> sittingAvatars = m_sittingAvatars; 4539 SitTargetAvatar = UUID.Zero;
4536 4540
4537 // This can occur under a race condition where another thread 4541 if (m_sittingAvatars == null)
4538 if (sittingAvatars == null) 4542 return false;
4539 return false;
4540 4543
4541 lock (sittingAvatars) 4544 if (m_sittingAvatars.Remove(avatarId))
4542 {
4543 if (sittingAvatars.Remove(avatarId))
4544 { 4545 {
4545 if (sittingAvatars.Count == 0) 4546 if (m_sittingAvatars.Count == 0)
4546 m_sittingAvatars = null; 4547 m_sittingAvatars = null;
4547 4548
4549 ParentGroup.m_sittingAvatars.Remove(avatarId);
4550
4548 return true; 4551 return true;
4549 } 4552 }
4550 }
4551 4553
4552 return false; 4554 return false;
4555 }
4553 } 4556 }
4554 4557
4555 /// <summary> 4558 /// <summary>
@@ -4559,16 +4562,12 @@ namespace OpenSim.Region.Framework.Scenes
4559 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns> 4562 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
4560 public HashSet<UUID> GetSittingAvatars() 4563 public HashSet<UUID> GetSittingAvatars()
4561 { 4564 {
4562 HashSet<UUID> sittingAvatars = m_sittingAvatars; 4565 lock (ParentGroup.m_sittingAvatars)
4563
4564 if (sittingAvatars == null)
4565 {
4566 return null;
4567 }
4568 else
4569 { 4566 {
4570 lock (sittingAvatars) 4567 if (m_sittingAvatars == null)
4571 return new HashSet<UUID>(sittingAvatars); 4568 return null;
4569 else
4570 return new HashSet<UUID>(m_sittingAvatars);
4572 } 4571 }
4573 } 4572 }
4574 4573
@@ -4579,13 +4578,13 @@ namespace OpenSim.Region.Framework.Scenes
4579 /// <returns></returns> 4578 /// <returns></returns>
4580 public int GetSittingAvatarsCount() 4579 public int GetSittingAvatarsCount()
4581 { 4580 {
4582 HashSet<UUID> sittingAvatars = m_sittingAvatars; 4581 lock (ParentGroup.m_sittingAvatars)
4583 4582 {
4584 if (sittingAvatars == null) 4583 if (m_sittingAvatars == null)
4585 return 0; 4584 return 0;
4586 4585 else
4587 lock (sittingAvatars) 4586 return m_sittingAvatars.Count;
4588 return sittingAvatars.Count; 4587 }
4589 } 4588 }
4590 } 4589 }
4591} 4590} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 75749a9..f31bbff 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -3738,33 +3738,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3738 public LSL_String llGetLinkKey(int linknum) 3738 public LSL_String llGetLinkKey(int linknum)
3739 { 3739 {
3740 m_host.AddScriptLPS(1); 3740 m_host.AddScriptLPS(1);
3741 List<UUID> keytable = new List<UUID>();
3742 // parse for sitting avatare-uuids
3743 World.ForEachRootScenePresence(delegate(ScenePresence presence)
3744 {
3745 if (presence.ParentID != 0 && m_host.ParentGroup.ContainsPart(presence.ParentID))
3746 keytable.Add(presence.UUID);
3747 });
3748 3741
3749 int totalprims = m_host.ParentGroup.PrimCount + keytable.Count; 3742 if (linknum < 0)
3750 if (linknum > m_host.ParentGroup.PrimCount && linknum <= totalprims)
3751 { 3743 {
3752 return keytable[totalprims - linknum].ToString(); 3744 if (linknum == ScriptBaseClass.LINK_THIS)
3745 return m_host.UUID.ToString();
3746 else
3747 return ScriptBaseClass.NULL_KEY;
3753 } 3748 }
3754 3749
3755 if (linknum == 1 && m_host.ParentGroup.PrimCount == 1 && keytable.Count == 1) 3750 int actualPrimCount = m_host.ParentGroup.PrimCount;
3751 List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
3752 int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
3753
3754 // Special case for a single prim. In this case the linknum is zero. However, this will not match a single
3755 // prim that has any avatars sat upon it (in which case the root prim is link 1).
3756 if (linknum == 0)
3756 { 3757 {
3757 return m_host.UUID.ToString(); 3758 if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
3758 } 3759 return m_host.UUID.ToString();
3759 3760
3760 SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum); 3761 return ScriptBaseClass.NULL_KEY;
3761 if (part != null) 3762 }
3763 // Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
3764 // here we must match 1 (ScriptBaseClass.LINK_ROOT).
3765 else if (linknum == 1 && actualPrimCount == 1)
3762 { 3766 {
3763 return part.UUID.ToString(); 3767 if (sittingAvatarIds.Count > 0)
3768 return m_host.ParentGroup.RootPart.UUID.ToString();
3769 else
3770 return ScriptBaseClass.NULL_KEY;
3771 }
3772 else if (linknum <= adjustedPrimCount)
3773 {
3774 if (linknum <= actualPrimCount)
3775 return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString();
3776 else
3777 return sittingAvatarIds[linknum - actualPrimCount - 1].ToString();
3764 } 3778 }
3765 else 3779 else
3766 { 3780 {
3767 return UUID.Zero.ToString(); 3781 return ScriptBaseClass.NULL_KEY;
3768 } 3782 }
3769 } 3783 }
3770 3784