Merge commit '3611d33b00650ccc71994b331e4c6595f95d3131' into careminster

Conflicts:
	OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
avinationmerge
Melanie 2013-03-19 01:00:09 +00:00
commit 8553a37881
2 changed files with 355 additions and 147 deletions

View File

@ -304,21 +304,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled) if (!Enabled)
return false; return false;
if (AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, append)) AttachObjectInternal(sp, group, attachmentPt, silent, useAttachData, temp, append);
{
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
return true;
}
return false;
} }
/// <summary>
/// Internal method which actually does all the work for attaching an object.
/// </summary>
/// <returns>The object attached.</returns>
/// <param name='sp'></param>
/// <param name='group'>The object to attach.</param>
/// <param name='attachmentPt'></param>
/// <param name='silent'></param>
/// <param name='temp'></param>
/// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append) private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp, bool append)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
// group.Name, group.LocalId, sp.Name, attachmentPt, silent); // 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) if (group.GetSittingAvatarsCount() != 0)
{ {
// m_log.WarnFormat( // m_log.WarnFormat(
@ -328,67 +341,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return false; return false;
} }
if (sp.GetAttachments(attachmentPt).Contains(group)) Vector3 attachPos = group.AbsolutePosition;
{
// 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; // 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 // AttachmentPt 0 (default) means the client chose to 'wear' the attachment.
List<SceneObjectGroup> existingAttachments = sp.GetAttachments(attachmentPt); 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 we still didn't find a suitable attachment point.......
if (existingAttachments.Count != 0 && existingAttachments[0].FromItemID != UUID.Zero) if (attachmentPt == 0)
DetachSingleAttachmentToInv(sp, group); {
// Stick it on left hand with Zero Offset from the attachment point.
attachmentPt = (uint)AttachmentPoint.LeftHand;
attachPos = Vector3.Zero;
}
List<SceneObjectGroup> 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) 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.AttachmentPoint = attachmentPt;
group.AbsolutePosition = attachPos; group.AbsolutePosition = attachPos;
@ -396,6 +399,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append); UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
AttachToAgent(sp, group, attachmentPt, attachPos, silent); 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; return true;
@ -425,8 +439,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null; return null;
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", // "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
// (AttachmentPoint)AttachmentPt, itemID, sp.Name); // (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
bool append = (AttachmentPt & 0x80) != 0; bool append = (AttachmentPt & 0x80) != 0;
AttachmentPt &= 0x7f; AttachmentPt &= 0x7f;
@ -558,6 +572,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return; 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 // Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will // removed from the scene because doing otherwise will
// clobber the run flag // clobber the run flag
@ -879,79 +897,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null; return null;
} }
List<SceneObjectGroup> 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 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
while (attachments.Count >= 5) // 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) if (doc != null)
{ {
objatt.LoadScriptState(doc); objatt.LoadScriptState(doc);
objatt.ResetOwnerChangeFlag(); objatt.ResetOwnerChangeFlag();
} }
// Fire after attach, so we don't get messy perms dialogs AttachObjectInternal(sp, objatt, attachmentPt, false, true, false, append);
// 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;
} }
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;
} }
/// <summary> /// <summary>

View File

@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); 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<SceneObjectGroup> 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<SceneObjectGroup> 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<SceneObjectGroup> 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));
}
}
/// <summary> /// <summary>
/// Test that we do not attempt to attach an in-world object that someone else is sitting on. /// Test that we do not attempt to attach an in-world object that someone else is sitting on.
/// </summary> /// </summary>
@ -275,29 +389,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
m_numberOfAttachEventsFired = 0; {
scene.AttachmentsModule.RezSingleAttachmentFromInventory( scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest); sp, attItem.ID, (uint)AttachmentPoint.Chest);
// Check scene presence status // Check scene presence status
Assert.That(sp.HasAttachments(), Is.True); Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments(); List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1)); Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0]; SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
Assert.That(attSo.IsAttachment); Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False); Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False); Assert.That(attSo.IsTemporary, Is.False);
// Check appearance status // Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); 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 // Test attaching an already attached attachment
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1)); {
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
// Check scene presence status
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> 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));
}
}
/// <summary>
/// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
/// </summary>
[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<SceneObjectGroup> 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<SceneObjectGroup> 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<SceneObjectGroup> 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));
}
} }
/// <summary> /// <summary>