diff options
author | Justin Clark-Casey (justincc) | 2013-01-04 20:34:39 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-01-04 20:34:39 +0000 |
commit | 9503383887d6af871e843cbcbb141a50df56f551 (patch) | |
tree | 85caf28a22c20e703aa60572db978dd7c929c4fc /OpenSim/Region | |
parent | minor: Add some doc to the extremely unhelpful 'fudge....' comment as to why ... (diff) | |
download | opensim-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')
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 | ||