diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 64ae5ff358..89c6b49b41 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -2941,13 +2941,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory");
+ m_host.AddScriptLPS(1);
+
+ ForceAttachToAvatarFromInventory(m_host.OwnerID, itemName, attachmentPoint);
+ }
+
+ public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint)
+ {
+ CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory");
+
+ m_host.AddScriptLPS(1);
+
+ UUID avatarId;
+
+ if (!UUID.TryParse(rawAvatarId, out avatarId))
+ return;
+
+ ForceAttachToAvatarFromInventory(avatarId, itemName, attachmentPoint);
+ }
+
+ public void ForceAttachToAvatarFromInventory(UUID avatarId, string itemName, int attachmentPoint)
+ {
IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule;
if (attachmentsModule == null)
return;
- m_host.AddScriptLPS(1);
-
InitLSL();
TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName);
@@ -2970,7 +2989,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return;
}
- ScenePresence sp = World.GetScenePresence(m_host.OwnerID);
+ ScenePresence sp = World.GetScenePresence(avatarId);
if (sp == null)
return;
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 7744567e57..37b6e3b9d7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -101,18 +101,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
// Attachment commands
///
- /// Attach the object containing this script to the avatar that owns it without checking for PERMISSION_ATTACH
+ /// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
///
/// The attachment point. For example, ATTACH_CHEST
void osForceAttachToAvatar(int attachment);
///
- /// Attach the inventory item in the object containing this script to the avatar that owns it without checking for PERMISSION_ATTACH
+ /// Attach an inventory item in the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
///
+ ///
+ /// Nothing happens if the owner is not in the region.
+ ///
/// Tha name of the item. If this is not found then a warning is said to the owner
/// The attachment point. For example, ATTACH_CHEST
void osForceAttachToAvatarFromInventory(string itemName, int attachment);
+ ///
+ /// Attach an inventory item in the object containing this script to any avatar in the region without asking for PERMISSION_ATTACH
+ ///
+ ///
+ /// Nothing happens if the avatar is not in the region.
+ ///
+ /// The UUID of the avatar to which to attach. Nothing happens if this is not a UUID
+ /// The name of the item. If this is not found then a warning is said to the owner
+ /// The attachment point. For example, ATTACH_CHEST
+ void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint);
+
///
/// Detach the object containing this script from the avatar it is attached to without checking for PERMISSION_ATTACH
///
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index e93936ffa9..837b5b8f5a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -301,6 +301,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
m_OSSL_Functions.osForceAttachToAvatarFromInventory(itemName, attachmentPoint);
}
+ public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint)
+ {
+ m_OSSL_Functions.osForceAttachToOtherAvatarFromInventory(rawAvatarId, itemName, attachmentPoint);
+ }
+
public void osForceDetachFromAvatar()
{
m_OSSL_Functions.osForceDetachFromAvatar();
diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
index 78db2c6a48..f5aa51843f 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs
@@ -174,5 +174,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
List attachmentsInAppearance = sp.Appearance.GetAttachments();
Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0));
}
+
+ [Test]
+ public void TestOsForceAttachToOtherAvatarFromInventory()
+ {
+ TestHelpers.InMethod();
+ TestHelpers.EnableLogging();
+
+ string taskInvObjItemName = "sphere";
+ UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000");
+ AttachmentPoint attachPoint = AttachmentPoint.Chin;
+
+ UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "one", 0x1, "pass");
+ UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "two", 0x2, "pass");
+
+ ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1);
+ SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID);
+ TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart);
+
+ new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem);
+ OSSL_Api osslApi = new OSSL_Api();
+ osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem);
+
+ // Create an object embedded inside the first
+ TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID);
+
+ ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2);
+
+ osslApi.osForceAttachToOtherAvatarFromInventory(sp2.UUID.ToString(), taskInvObjItemName, (int)attachPoint);
+
+ // Check scene presence status
+ Assert.That(sp.HasAttachments(), Is.False);
+ List attachments = sp.GetAttachments();
+ Assert.That(attachments.Count, Is.EqualTo(0));
+
+ Assert.That(sp2.HasAttachments(), Is.True);
+ List attachments2 = sp2.GetAttachments();
+ Assert.That(attachments2.Count, Is.EqualTo(1));
+ SceneObjectGroup attSo = attachments2[0];
+ Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName));
+ Assert.That(attSo.OwnerID, Is.EqualTo(ua2.PrincipalID));
+ Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint));
+ Assert.That(attSo.IsAttachment);
+ Assert.That(attSo.UsesPhysics, Is.False);
+ Assert.That(attSo.IsTemporary, Is.False);
+
+ // Check appearance status
+ List attachmentsInAppearance = sp.Appearance.GetAttachments();
+ Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0));
+
+ List attachmentsInAppearance2 = sp2.Appearance.GetAttachments();
+ Assert.That(attachmentsInAppearance2.Count, Is.EqualTo(1));
+ Assert.That(sp2.Appearance.GetAttachpoint(attachmentsInAppearance2[0].ItemID), Is.EqualTo((uint)attachPoint));
+ }
}
}
\ No newline at end of file