aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-07-09 21:24:32 +0100
committerJustin Clark-Casey (justincc)2012-07-09 21:24:32 +0100
commit2eaa6d5ace738cf1848f82ce7a0b435928b6846f (patch)
tree091add9a2885fbb702cf908e1b2f70f5d1730131
parentMore keys for automated ini processing (diff)
downloadopensim-SC_OLD-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.zip
opensim-SC_OLD-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.tar.gz
opensim-SC_OLD-2eaa6d5ace738cf1848f82ce7a0b435928b6846f.tar.bz2
opensim-SC_OLD-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.
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs9
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs32
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs98
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs18
-rw-r--r--OpenSim/Tests/Common/Helpers/SceneHelpers.cs75
-rw-r--r--OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs9
7 files changed, 229 insertions, 26 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();
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index d5354cb..769de83 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -412,26 +412,49 @@ namespace OpenSim.Tests.Common
412 /// <returns></returns> 412 /// <returns></returns>
413 public static AgentCircuitData GenerateAgentData(UUID agentId) 413 public static AgentCircuitData GenerateAgentData(UUID agentId)
414 { 414 {
415 string firstName = "testfirstname"; 415 AgentCircuitData acd = GenerateCommonAgentData();
416 416
417 AgentCircuitData agentData = new AgentCircuitData(); 417 acd.AgentID = agentId;
418 agentData.AgentID = agentId; 418 acd.firstname = "testfirstname";
419 agentData.firstname = firstName; 419 acd.lastname = "testlastname";
420 agentData.lastname = "testlastname"; 420 acd.ServiceURLs = new Dictionary<string, object>();
421
422 return acd;
423 }
424
425 /// <summary>
426 /// Generate some standard agent connection data.
427 /// </summary>
428 /// <param name="agentId"></param>
429 /// <returns></returns>
430 public static AgentCircuitData GenerateAgentData(UserAccount ua)
431 {
432 AgentCircuitData acd = GenerateCommonAgentData();
433
434 acd.AgentID = ua.PrincipalID;
435 acd.firstname = ua.FirstName;
436 acd.lastname = ua.LastName;
437 acd.ServiceURLs = ua.ServiceURLs;
438
439 return acd;
440 }
441
442 private static AgentCircuitData GenerateCommonAgentData()
443 {
444 AgentCircuitData acd = new AgentCircuitData();
421 445
422 // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData. 446 // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData.
423 agentData.SessionID = UUID.Random(); 447 acd.SessionID = UUID.Random();
424 agentData.SecureSessionID = UUID.Random(); 448 acd.SecureSessionID = UUID.Random();
425 449
426 agentData.circuitcode = 123; 450 acd.circuitcode = 123;
427 agentData.BaseFolder = UUID.Zero; 451 acd.BaseFolder = UUID.Zero;
428 agentData.InventoryFolder = UUID.Zero; 452 acd.InventoryFolder = UUID.Zero;
429 agentData.startpos = Vector3.Zero; 453 acd.startpos = Vector3.Zero;
430 agentData.CapsPath = "http://wibble.com"; 454 acd.CapsPath = "http://wibble.com";
431 agentData.ServiceURLs = new Dictionary<string, object>(); 455 acd.Appearance = new AvatarAppearance();
432 agentData.Appearance = new AvatarAppearance(); 456
433 457 return acd;
434 return agentData;
435 } 458 }
436 459
437 /// <summary> 460 /// <summary>
@@ -440,6 +463,9 @@ namespace OpenSim.Tests.Common
440 /// <remarks> 463 /// <remarks>
441 /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions 464 /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions
442 /// and teleport doesn't take place. 465 /// and teleport doesn't take place.
466 ///
467 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
468 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
443 /// </remarks> 469 /// </remarks>
444 /// <param name="scene"></param> 470 /// <param name="scene"></param>
445 /// <param name="agentId"></param> 471 /// <param name="agentId"></param>
@@ -452,6 +478,10 @@ namespace OpenSim.Tests.Common
452 /// <summary> 478 /// <summary>
453 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test 479 /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test
454 /// </summary> 480 /// </summary>
481 /// <remarks>
482 /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will
483 /// make the agent circuit data (e.g. first, lastname) consistent with the user account data.
484 /// </remarks>
455 /// <param name="scene"></param> 485 /// <param name="scene"></param>
456 /// <param name="agentId"></param> 486 /// <param name="agentId"></param>
457 /// <param name="sceneManager"></param> 487 /// <param name="sceneManager"></param>
@@ -464,6 +494,17 @@ namespace OpenSim.Tests.Common
464 /// <summary> 494 /// <summary>
465 /// Add a root agent. 495 /// Add a root agent.
466 /// </summary> 496 /// </summary>
497 /// <param name="scene"></param>
498 /// <param name="ua"></param>
499 /// <returns></returns>
500 public static ScenePresence AddScenePresence(Scene scene, UserAccount ua)
501 {
502 return AddScenePresence(scene, GenerateAgentData(ua));
503 }
504
505 /// <summary>
506 /// Add a root agent.
507 /// </summary>
467 /// <remarks> 508 /// <remarks>
468 /// This function 509 /// This function
469 /// 510 ///
diff --git a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
index 3d3e65c..2fbebc4 100644
--- a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs
@@ -138,6 +138,15 @@ namespace OpenSim.Tests.Common
138 CreateUserWithInventory(scene, ua, pw); 138 CreateUserWithInventory(scene, ua, pw);
139 return ua; 139 return ua;
140 } 140 }
141
142 public static UserAccount CreateUserWithInventory(
143 Scene scene, string firstName, string lastName, int userId, string pw)
144 {
145 UserAccount ua
146 = new UserAccount(TestHelpers.ParseTail(userId)) { FirstName = firstName, LastName = lastName };
147 CreateUserWithInventory(scene, ua, pw);
148 return ua;
149 }
141 150
142 public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw) 151 public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw)
143 { 152 {