diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index a0a7a68605..296f198104 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -304,21 +304,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled)
return false;
- if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, append))
- {
- m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
- return true;
- }
-
- return false;
+ AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, append);
}
-
+
+ ///
+ /// Internal method which actually does all the work for attaching an object.
+ ///
+ /// The object attached.
+ ///
+ /// The object to attach.
+ ///
+ ///
+ ///
+ /// If true then scripts are resumed on the attached object.
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
+ if (sp.GetAttachments().Contains(group))
+ {
+// m_log.WarnFormat(
+// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
+// group.Name, group.LocalId, sp.Name, AttachmentPt);
+
+ return false;
+ }
+
if (group.GetSittingAvatarsCount() != 0)
{
// m_log.WarnFormat(
@@ -328,67 +341,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return false;
}
- if (sp.GetAttachments(attachmentPt).Contains(group))
- {
-// m_log.WarnFormat(
-// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
-// group.Name, group.LocalId, sp.Name, AttachmentPt);
+ Vector3 attachPos = group.AbsolutePosition;
- return false;
+ // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
+ // be removed when that functionality is implemented in opensim
+ attachmentPt &= 0x7f;
+
+ // If the attachment point isn't the same as the one previously used
+ // set it's offset position = 0 so that it appears on the attachment point
+ // and not in a weird location somewhere unknown.
+ if (attachmentPt != (uint)AttachmentPoint.Default && attachmentPt != group.AttachmentPoint)
+ {
+ attachPos = Vector3.Zero;
}
- // Remove any previous attachments
- List existingAttachments = sp.GetAttachments(attachmentPt);
+ // AttachmentPt 0 (default) means the client chose to 'wear' the attachment.
+ if (attachmentPt == (uint)AttachmentPoint.Default)
+ {
+ // Check object for stored attachment point
+ attachmentPt = group.AttachmentPoint;
+ }
- // At the moment we can only deal with a single attachment
- if (existingAttachments.Count != 0 && existingAttachments[0].FromItemID != UUID.Zero)
- DetachSingleAttachmentToInv(sp, group);
+ // if we still didn't find a suitable attachment point.......
+ if (attachmentPt == 0)
+ {
+ // Stick it on left hand with Zero Offset from the attachment point.
+ attachmentPt = (uint)AttachmentPoint.LeftHand;
+ attachPos = Vector3.Zero;
+ }
+
+ List attachments = sp.GetAttachments(attachmentPt);
+
+ // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
+ while (attachments.Count >= 5)
+ {
+ if (attachments[0].FromItemID != UUID.Zero)
+ DetachSingleAttachmentToInv(sp, attachments[0]);
+ attachments.RemoveAt(0);
+ }
+
+ // If we're not appending, remove the rest as well
+ if (attachments.Count != 0 && !append)
+ {
+ foreach (SceneObjectGroup g in attachments)
+ {
+ if (g.FromItemID != UUID.Zero)
+ DetachSingleAttachmentToInv(sp, g);
+ }
+ }
lock (sp.AttachmentsSyncLock)
{
- Vector3 attachPos = group.AbsolutePosition;
-
- // If the attachment point isn't the same as the one previously used
- // set it's offset position = 0 so that it appears on the attachment point
- // and not in a weird location somewhere unknown.
- if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
- {
- attachPos = Vector3.Zero;
- }
-
- // AttachmentPt 0 means the client chose to 'wear' the attachment.
- if (attachmentPt == 0)
- {
- // Check object for stored attachment point
- attachmentPt = group.AttachmentPoint;
- }
-
- // if we still didn't find a suitable attachment point.......
- if (attachmentPt == 0)
- {
- // Stick it on left hand with Zero Offset from the attachment point.
- attachmentPt = (uint)AttachmentPoint.LeftHand;
- attachPos = Vector3.Zero;
- }
-
- if (useAttachData)
- {
- group.RootPart.RotationOffset = group.RootPart.AttachRotation;
- attachPos = group.RootPart.AttachOffset;
- if (attachmentPt == 0)
- {
- attachmentPt = group.RootPart.AttachPoint;
- if (attachmentPt == 0)
- {
- attachmentPt = (uint)AttachmentPoint.LeftHand;
- attachPos = Vector3.Zero;
- }
- }
- else if (group.RootPart.AttachPoint != attachmentPt)
- {
- attachPos = Vector3.Zero;
- }
- }
group.AttachmentPoint = attachmentPt;
group.AbsolutePosition = attachPos;
@@ -396,6 +399,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
+
+ if (resumeScripts)
+ {
+ // Fire after attach, so we don't get messy perms dialogs
+ // 4 == AttachedRez
+ group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
+ group.ResumeScripts();
+ }
+
+ // Do this last so that event listeners have access to all the effects of the attachment
+ m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
}
return true;
@@ -425,8 +439,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null;
// m_log.DebugFormat(
-// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
-// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
+// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
+// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
bool append = (AttachmentPt & 0x80) != 0;
AttachmentPt &= 0x7f;
@@ -558,6 +572,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return;
}
+// m_log.DebugFormat(
+// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}",
+// so.Name, so.LocalId, sp.Name, m_scene.Name);
+
// Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will
// clobber the run flag
@@ -879,79 +897,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null;
}
- List attachments = sp.GetAttachments(attachmentPt);
+ // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
+ objatt.HasGroupChanged = false;
+ bool tainted = false;
+ if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
+ tainted = true;
- // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
- while (attachments.Count >= 5)
+ // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
+ // course of events. If not, then it's probably not worth trying to recover the situation
+ // since this is more likely to trigger further exceptions and confuse later debugging. If
+ // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
+ // since other normal error conditions will simply return false instead.
+ // This will throw if the attachment fails
+ try
{
- if (attachments[0].FromItemID != UUID.Zero)
- DetachSingleAttachmentToInv(sp, attachments[0]);
- attachments.RemoveAt(0);
- }
-
- // If we're not appending, remove the rest as well
- if (attachments.Count != 0 && !append)
- {
- foreach (SceneObjectGroup g in attachments)
- {
- if (g.FromItemID != UUID.Zero)
- DetachSingleAttachmentToInv(sp, g);
- }
- }
-
- lock (sp.AttachmentsSyncLock)
- {
-// m_log.DebugFormat(
-// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
-// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
-
- // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
- objatt.HasGroupChanged = false;
- bool tainted = false;
- if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
- tainted = true;
-
- // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
- // course of events. If not, then it's probably not worth trying to recover the situation
- // since this is more likely to trigger further exceptions and confuse later debugging. If
- // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
- // since other normal error conditions will simply return false instead.
- // This will throw if the attachment fails
- try
- {
- AttachObjectInternal(sp, objatt, attachmentPt, false, false, false, append);
- }
- catch (Exception e)
- {
- m_log.ErrorFormat(
- "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
- objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
-
- // Make sure the object doesn't stick around and bail
- sp.RemoveAttachment(objatt);
- m_scene.DeleteSceneObject(objatt, false);
- return null;
- }
-
- if (tainted)
- objatt.HasGroupChanged = true;
-
if (doc != null)
{
objatt.LoadScriptState(doc);
objatt.ResetOwnerChangeFlag();
}
- // Fire after attach, so we don't get messy perms dialogs
- // 4 == AttachedRez
- objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
- objatt.ResumeScripts();
-
- // Do this last so that event listeners have access to all the effects of the attachment
- m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
-
- return objatt;
+ AttachObjectInternal(sp, objatt, attachmentPt, false, true, false, append);
}
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
+ objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
+
+ // Make sure the object doesn't stick around and bail
+ sp.RemoveAttachment(objatt);
+ m_scene.DeleteSceneObject(objatt, false);
+ return null;
+ }
+
+ if (tainted)
+ objatt.HasGroupChanged = true;
+
+ return objatt;
}
///
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 545aedaa20..da4bc83255 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
+ [Test]
+ public void TestWearAttachmentFromGround()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ Scene scene = CreateTestScene();
+ UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
+ ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
+
+ SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
+
+ {
+ SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
+
+ m_numberOfAttachEventsFired = 0;
+ scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, false);
+
+ // Check status on scene presence
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(so.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
+
+ // Check item status
+ Assert.That(
+ sp.Appearance.GetAttachpoint(attSo.FromItemID),
+ Is.EqualTo((int)AttachmentPoint.LeftHand));
+
+ InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
+ Assert.That(attachmentItem, Is.Not.Null);
+ Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
+
+ InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
+ Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
+
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
+ }
+
+ // Test wearing a different attachment from the ground.
+ {
+ scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
+
+ // Check status on scene presence
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(so2.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
+
+ // Check item status
+ Assert.That(
+ sp.Appearance.GetAttachpoint(attSo.FromItemID),
+ Is.EqualTo((int)AttachmentPoint.LeftHand));
+
+ InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
+ Assert.That(attachmentItem, Is.Not.Null);
+ Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
+
+ InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
+ Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
+
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
+ }
+
+ // Test rewearing an already worn attachment from ground. Nothing should happen.
+ {
+ scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
+
+ // Check status on scene presence
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(so2.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
+
+ // Check item status
+ Assert.That(
+ sp.Appearance.GetAttachpoint(attSo.FromItemID),
+ Is.EqualTo((int)AttachmentPoint.LeftHand));
+
+ InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
+ Assert.That(attachmentItem, Is.Not.Null);
+ Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
+
+ InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
+ Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
+
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
+ }
+ }
+
///
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
///
@@ -275,29 +389,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
- m_numberOfAttachEventsFired = 0;
- scene.AttachmentsModule.RezSingleAttachmentFromInventory(
- sp, attItem.ID, (uint)AttachmentPoint.Chest);
+ {
+ scene.AttachmentsModule.RezSingleAttachmentFromInventory(
+ sp, attItem.ID, (uint)AttachmentPoint.Chest);
- // Check scene presence status
- Assert.That(sp.HasAttachments(), Is.True);
- List attachments = sp.GetAttachments();
- Assert.That(attachments.Count, Is.EqualTo(1));
- SceneObjectGroup attSo = attachments[0];
- Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
- Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
- Assert.That(attSo.IsAttachment);
- Assert.That(attSo.UsesPhysics, Is.False);
- Assert.That(attSo.IsTemporary, Is.False);
+ // Check scene presence status
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
- // Check appearance status
- Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
- Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
+ // Check appearance status
+ Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
+ Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
- Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
+ }
- // Check events
- Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
+ // Test attaching an already attached attachment
+ {
+ scene.AttachmentsModule.RezSingleAttachmentFromInventory(
+ sp, attItem.ID, (uint)AttachmentPoint.Chest);
+
+ // Check scene presence status
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
+
+ // Check appearance status
+ Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
+ Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
+ }
+ }
+
+ ///
+ /// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
+ ///
+ [Test]
+ public void TestWearAttachmentFromInventory()
+ {
+ TestHelpers.InMethod();
+// TestHelpers.EnableLogging();
+
+ Scene scene = CreateTestScene();
+ UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
+ ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
+
+ InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
+ InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
+
+ {
+ m_numberOfAttachEventsFired = 0;
+ scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
+
+ // default attachment point is currently the left hand.
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+
+ // Check appearance status
+ Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
+ Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
+ }
+
+ // Test wearing a second attachment at the same position
+ // Until multiple attachments at one point is implemented, this will remove the first attachment
+ // This test relies on both attachments having the same default attachment point (in this case LeftHand
+ // since none other has been set).
+ {
+ scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
+
+ // default attachment point is currently the left hand.
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+
+ // Check appearance status
+ Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
+ Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
+ }
+
+ // Test wearing an already attached attachment
+ {
+ scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
+
+ // default attachment point is currently the left hand.
+ Assert.That(sp.HasAttachments(), Is.True);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments[0];
+ Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
+ Assert.That(attSo.IsAttachment);
+
+ // Check appearance status
+ Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
+ Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
+ Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
+
+ // Check events
+ Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
+ }
}
///