diff options
author | Justin Clark-Casey (justincc) | 2012-07-09 21:24:32 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-07-09 21:24:32 +0100 |
commit | 2eaa6d5ace738cf1848f82ce7a0b435928b6846f (patch) | |
tree | 091add9a2885fbb702cf908e1b2f70f5d1730131 /OpenSim/Region | |
parent | More keys for automated ini processing (diff) | |
download | opensim-SC-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.zip opensim-SC-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.tar.gz opensim-SC-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.tar.bz2 opensim-SC-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.tar.xz |
Do not allow a script to attach a prim if its being sat upon.
This prevents a stack overflow where a get position on the avatar will refer to the attachment which will in turn refer back to the avatar.
This required recording of all sitting avatars on a prim which is done separately from recording the sit target avatar.
Recording HashSet is null if there are no sitting avatars in order to save memory.
Diffstat (limited to '')
5 files changed, 162 insertions, 9 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 9eb0e38..eccf7a6 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -251,6 +251,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
251 | // m_log.DebugFormat( | 251 | // m_log.DebugFormat( |
252 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", | 252 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", |
253 | // group.Name, group.LocalId, sp.Name, attachmentPt, silent); | 253 | // group.Name, group.LocalId, sp.Name, attachmentPt, silent); |
254 | |||
255 | if (group.GetSittingAvatarsCount() != 0) | ||
256 | { | ||
257 | // m_log.WarnFormat( | ||
258 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", | ||
259 | // group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); | ||
260 | |||
261 | return false; | ||
262 | } | ||
254 | 263 | ||
255 | if (sp.GetAttachments(attachmentPt).Contains(group)) | 264 | if (sp.GetAttachments(attachmentPt).Contains(group)) |
256 | { | 265 | { |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 5dcbd28..3e06900 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -118,7 +118,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
118 | 118 | ||
119 | Scene scene = CreateDefaultTestScene(); | 119 | Scene scene = CreateDefaultTestScene(); |
120 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); | 120 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); |
121 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); | 121 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); |
122 | 122 | ||
123 | string attName = "att"; | 123 | string attName = "att"; |
124 | 124 | ||
@@ -154,6 +154,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
154 | // TestHelpers.DisableLogging(); | 154 | // TestHelpers.DisableLogging(); |
155 | } | 155 | } |
156 | 156 | ||
157 | /// <summary> | ||
158 | /// Test that we do not attempt to attach an in-world object that someone else is sitting on. | ||
159 | /// </summary> | ||
160 | [Test] | ||
161 | public void TestAddSatOnAttachmentFromGround() | ||
162 | { | ||
163 | TestHelpers.InMethod(); | ||
164 | // TestHelpers.EnableLogging(); | ||
165 | |||
166 | Scene scene = CreateDefaultTestScene(); | ||
167 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); | ||
168 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); | ||
169 | |||
170 | string attName = "att"; | ||
171 | |||
172 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); | ||
173 | |||
174 | UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(scene, 0x2); | ||
175 | ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, ua2); | ||
176 | |||
177 | // Put avatar within 10m of the prim so that sit doesn't fail. | ||
178 | sp2.AbsolutePosition = new Vector3(0, 0, 0); | ||
179 | sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); | ||
180 | |||
181 | scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false); | ||
182 | |||
183 | Assert.That(sp.HasAttachments(), Is.False); | ||
184 | Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
185 | } | ||
186 | |||
157 | [Test] | 187 | [Test] |
158 | public void TestAddAttachmentFromInventory() | 188 | public void TestAddAttachmentFromInventory() |
159 | { | 189 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 4e0e183..fc04761 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -3401,6 +3401,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
3401 | return count; | 3401 | return count; |
3402 | } | 3402 | } |
3403 | 3403 | ||
3404 | /// <summary> | ||
3405 | /// Gets the number of sitting avatars. | ||
3406 | /// </summary> | ||
3407 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | ||
3408 | /// <returns></returns> | ||
3409 | public int GetSittingAvatarsCount() | ||
3410 | { | ||
3411 | int count = 0; | ||
3412 | |||
3413 | Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount()); | ||
3414 | |||
3415 | return count; | ||
3416 | } | ||
3417 | |||
3404 | public override string ToString() | 3418 | public override string ToString() |
3405 | { | 3419 | { |
3406 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); | 3420 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 3d81358..6518b84 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -374,7 +374,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
374 | private uint _category; | 374 | private uint _category; |
375 | private Int32 _creationDate; | 375 | private Int32 _creationDate; |
376 | private uint _parentID = 0; | 376 | private uint _parentID = 0; |
377 | private UUID m_sitTargetAvatar = UUID.Zero; | ||
378 | private uint _baseMask = (uint)PermissionMask.All; | 377 | private uint _baseMask = (uint)PermissionMask.All; |
379 | private uint _ownerMask = (uint)PermissionMask.All; | 378 | private uint _ownerMask = (uint)PermissionMask.All; |
380 | private uint _groupMask = (uint)PermissionMask.None; | 379 | private uint _groupMask = (uint)PermissionMask.None; |
@@ -1233,13 +1232,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1233 | } | 1232 | } |
1234 | 1233 | ||
1235 | /// <summary> | 1234 | /// <summary> |
1236 | /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero | 1235 | /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero |
1237 | /// </summary> | 1236 | /// </summary> |
1238 | public UUID SitTargetAvatar | 1237 | public UUID SitTargetAvatar { get; set; } |
1239 | { | 1238 | |
1240 | get { return m_sitTargetAvatar; } | 1239 | /// <summary> |
1241 | set { m_sitTargetAvatar = value; } | 1240 | /// IDs of all avatars start on this object part. |
1242 | } | 1241 | /// </summary> |
1242 | /// <remarks> | ||
1243 | /// We need to track this so that we can stop sat upon prims from being attached. | ||
1244 | /// </remarks> | ||
1245 | /// <value> | ||
1246 | /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene. | ||
1247 | /// </value> | ||
1248 | private HashSet<UUID> m_sittingAvatars; | ||
1243 | 1249 | ||
1244 | public virtual UUID RegionID | 1250 | public virtual UUID RegionID |
1245 | { | 1251 | { |
@@ -4493,5 +4499,83 @@ namespace OpenSim.Region.Framework.Scenes | |||
4493 | Color color = Color; | 4499 | Color color = Color; |
4494 | return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); | 4500 | return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A)); |
4495 | } | 4501 | } |
4502 | |||
4503 | /// <summary> | ||
4504 | /// Record an avatar sitting on this part. | ||
4505 | /// </summary> | ||
4506 | /// <remarks>This is called for all the sitting avatars whether there is a sit target set or not.</remarks> | ||
4507 | /// <returns> | ||
4508 | /// true if the avatar was not already recorded, false otherwise. | ||
4509 | /// </returns> | ||
4510 | /// <param name='avatarId'></param> | ||
4511 | protected internal bool AddSittingAvatar(UUID avatarId) | ||
4512 | { | ||
4513 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | ||
4514 | |||
4515 | if (sittingAvatars == null) | ||
4516 | sittingAvatars = new HashSet<UUID>(); | ||
4517 | |||
4518 | lock (sittingAvatars) | ||
4519 | { | ||
4520 | m_sittingAvatars = sittingAvatars; | ||
4521 | return m_sittingAvatars.Add(avatarId); | ||
4522 | } | ||
4523 | } | ||
4524 | |||
4525 | /// <summary> | ||
4526 | /// Remove an avatar recorded as sitting on this part. | ||
4527 | /// </summary> | ||
4528 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | ||
4529 | /// <returns> | ||
4530 | /// true if the avatar was present and removed, false if it was not present. | ||
4531 | /// </returns> | ||
4532 | /// <param name='avatarId'></param> | ||
4533 | protected internal bool RemoveSittingAvatar(UUID avatarId) | ||
4534 | { | ||
4535 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | ||
4536 | |||
4537 | // This can occur under a race condition where another thread | ||
4538 | if (sittingAvatars == null) | ||
4539 | return false; | ||
4540 | |||
4541 | lock (sittingAvatars) | ||
4542 | { | ||
4543 | if (sittingAvatars.Remove(avatarId)) | ||
4544 | { | ||
4545 | if (sittingAvatars.Count == 0) | ||
4546 | m_sittingAvatars = null; | ||
4547 | |||
4548 | return true; | ||
4549 | } | ||
4550 | } | ||
4551 | |||
4552 | return false; | ||
4553 | } | ||
4554 | |||
4555 | /// <summary> | ||
4556 | /// Get a copy of the list of sitting avatars. | ||
4557 | /// </summary> | ||
4558 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | ||
4559 | /// <returns></returns> | ||
4560 | public HashSet<UUID> GetSittingAvatars() | ||
4561 | { | ||
4562 | return new HashSet<UUID>(m_sittingAvatars); | ||
4563 | } | ||
4564 | |||
4565 | /// <summary> | ||
4566 | /// Gets the number of sitting avatars. | ||
4567 | /// </summary> | ||
4568 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | ||
4569 | /// <returns></returns> | ||
4570 | public int GetSittingAvatarsCount() | ||
4571 | { | ||
4572 | HashSet<UUID> sittingAvatars = m_sittingAvatars; | ||
4573 | |||
4574 | if (sittingAvatars == null) | ||
4575 | return 0; | ||
4576 | |||
4577 | lock (sittingAvatars) | ||
4578 | return sittingAvatars.Count; | ||
4579 | } | ||
4496 | } | 4580 | } |
4497 | } | 4581 | } |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index c7a670f..c6a2a03 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -578,6 +578,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
578 | public uint ParentID { get; set; } | 578 | public uint ParentID { get; set; } |
579 | 579 | ||
580 | /// <summary> | 580 | /// <summary> |
581 | /// Are we sitting on an object? | ||
582 | /// </summary> | ||
583 | /// <remarks>A more readable way of testing presence sit status than ParentID == 0</remarks> | ||
584 | public bool IsSatOnObject { get { return ParentID != 0; } } | ||
585 | |||
586 | /// <summary> | ||
581 | /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null. | 587 | /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null. |
582 | /// </summary> | 588 | /// </summary> |
583 | /// <remarks> | 589 | /// <remarks> |
@@ -1808,6 +1814,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1808 | SendAvatarDataToAllAgents(); | 1814 | SendAvatarDataToAllAgents(); |
1809 | m_requestedSitTargetID = 0; | 1815 | m_requestedSitTargetID = 0; |
1810 | 1816 | ||
1817 | part.RemoveSittingAvatar(UUID); | ||
1818 | |||
1811 | if (part != null) | 1819 | if (part != null) |
1812 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); | 1820 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); |
1813 | } | 1821 | } |
@@ -1887,7 +1895,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1887 | ) | 1895 | ) |
1888 | )); | 1896 | )); |
1889 | 1897 | ||
1890 | // m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied); | 1898 | m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied); |
1891 | 1899 | ||
1892 | if (PhysicsActor != null) | 1900 | if (PhysicsActor != null) |
1893 | m_sitAvatarHeight = PhysicsActor.Size.Z; | 1901 | m_sitAvatarHeight = PhysicsActor.Size.Z; |
@@ -1920,6 +1928,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1920 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); | 1928 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); |
1921 | canSit = true; | 1929 | canSit = true; |
1922 | } | 1930 | } |
1931 | // else | ||
1932 | // { | ||
1933 | // m_log.DebugFormat( | ||
1934 | // "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m", | ||
1935 | // Name, part.Name, part.LocalId); | ||
1936 | // } | ||
1923 | } | 1937 | } |
1924 | 1938 | ||
1925 | if (canSit) | 1939 | if (canSit) |
@@ -1930,6 +1944,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1930 | RemoveFromPhysicalScene(); | 1944 | RemoveFromPhysicalScene(); |
1931 | } | 1945 | } |
1932 | 1946 | ||
1947 | part.AddSittingAvatar(UUID); | ||
1948 | |||
1933 | cameraAtOffset = part.GetCameraAtOffset(); | 1949 | cameraAtOffset = part.GetCameraAtOffset(); |
1934 | cameraEyeOffset = part.GetCameraEyeOffset(); | 1950 | cameraEyeOffset = part.GetCameraEyeOffset(); |
1935 | forceMouselook = part.GetForceMouselook(); | 1951 | forceMouselook = part.GetForceMouselook(); |