2010-03-05 23:18:47 +00:00
/ *
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
2010-06-09 19:51:24 +00:00
using System ;
2010-03-06 00:07:47 +00:00
using System.Collections.Generic ;
2010-03-05 23:18:47 +00:00
using System.Reflection ;
2012-07-23 19:08:02 +00:00
using System.IO ;
using System.Xml ;
2010-03-05 23:18:47 +00:00
using log4net ;
2010-07-30 18:26:54 +00:00
using Mono.Addins ;
2010-03-05 23:18:47 +00:00
using Nini.Config ;
using OpenMetaverse ;
2010-04-16 21:54:25 +00:00
using OpenMetaverse.Packets ;
2010-03-05 23:18:47 +00:00
using OpenSim.Framework ;
using OpenSim.Region.Framework ;
using OpenSim.Region.Framework.Interfaces ;
using OpenSim.Region.Framework.Scenes ;
2010-08-26 21:09:52 +00:00
using OpenSim.Region.Framework.Scenes.Serialization ;
2010-03-05 23:18:47 +00:00
namespace OpenSim.Region.CoreModules.Avatar.Attachments
2010-03-10 04:15:36 +00:00
{
2010-07-30 18:26:54 +00:00
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]
public class AttachmentsModule : IAttachmentsModule , INonSharedRegionModule
2010-03-05 23:18:47 +00:00
{
2011-10-04 21:40:39 +00:00
#region INonSharedRegionModule
2010-03-05 23:18:47 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2011-08-30 21:25:38 +00:00
private Scene m_scene ;
2012-05-23 00:58:10 +00:00
private IInventoryAccessModule m_invAccessModule ;
2011-09-30 00:19:22 +00:00
/// <summary>
/// Are attachments enabled?
/// </summary>
public bool Enabled { get ; private set ; }
2010-07-30 18:26:54 +00:00
2010-09-12 17:43:49 +00:00
public string Name { get { return "Attachments Module" ; } }
public Type ReplaceableInterface { get { return null ; } }
2010-03-05 23:18:47 +00:00
2011-09-30 00:19:22 +00:00
public void Initialise ( IConfigSource source )
{
IConfig config = source . Configs [ "Attachments" ] ;
if ( config ! = null )
Enabled = config . GetBoolean ( "Enabled" , true ) ;
else
Enabled = true ;
}
2010-07-30 18:26:54 +00:00
public void AddRegion ( Scene scene )
2010-03-05 23:18:47 +00:00
{
m_scene = scene ;
2010-07-30 18:26:54 +00:00
m_scene . RegisterModuleInterface < IAttachmentsModule > ( this ) ;
2011-09-30 00:19:22 +00:00
if ( Enabled )
m_scene . EventManager . OnNewClient + = SubscribeToClientEvents ;
2010-07-30 20:41:44 +00:00
// TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
2010-03-05 23:18:47 +00:00
}
2010-07-30 18:26:54 +00:00
public void RemoveRegion ( Scene scene )
2010-03-05 23:18:47 +00:00
{
2010-07-30 18:26:54 +00:00
m_scene . UnregisterModuleInterface < IAttachmentsModule > ( this ) ;
2011-09-30 00:19:22 +00:00
if ( Enabled )
m_scene . EventManager . OnNewClient - = SubscribeToClientEvents ;
2010-03-05 23:18:47 +00:00
}
2010-07-30 18:26:54 +00:00
2012-05-23 00:58:10 +00:00
public void RegionLoaded ( Scene scene )
{
m_invAccessModule = m_scene . RequestModuleInterface < IInventoryAccessModule > ( ) ;
}
2010-07-30 18:26:54 +00:00
public void Close ( )
2010-03-05 23:18:47 +00:00
{
2010-07-30 18:26:54 +00:00
RemoveRegion ( m_scene ) ;
2010-03-05 23:18:47 +00:00
}
2011-10-04 21:40:39 +00:00
# endregion
#region IAttachmentsModule
2011-08-30 22:05:43 +00:00
2012-06-26 23:41:46 +00:00
public void CopyAttachments ( IScenePresence sp , AgentData ad )
{
lock ( sp . AttachmentsSyncLock )
{
// Attachment objects
List < SceneObjectGroup > attachments = sp . GetAttachments ( ) ;
if ( attachments . Count > 0 )
{
ad . AttachmentObjects = new List < ISceneObject > ( ) ;
ad . AttachmentObjectStates = new List < string > ( ) ;
// IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
sp . InTransitScriptStates . Clear ( ) ;
foreach ( SceneObjectGroup sog in attachments )
{
// We need to make a copy and pass that copy
// because of transfers withn the same sim
ISceneObject clone = sog . CloneForNewScene ( ) ;
// Attachment module assumes that GroupPosition holds the offsets...!
( ( SceneObjectGroup ) clone ) . RootPart . GroupPosition = sog . RootPart . AttachedPos ;
( ( SceneObjectGroup ) clone ) . IsAttachment = false ;
ad . AttachmentObjects . Add ( clone ) ;
string state = sog . GetStateSnapshot ( ) ;
ad . AttachmentObjectStates . Add ( state ) ;
sp . InTransitScriptStates . Add ( state ) ;
// Let's remove the scripts of the original object here
sog . RemoveScriptInstances ( true ) ;
}
}
}
}
public void CopyAttachments ( AgentData ad , IScenePresence sp )
{
if ( ad . AttachmentObjects ! = null & & ad . AttachmentObjects . Count > 0 )
{
lock ( sp . AttachmentsSyncLock )
sp . ClearAttachments ( ) ;
int i = 0 ;
foreach ( ISceneObject so in ad . AttachmentObjects )
{
( ( SceneObjectGroup ) so ) . LocalId = 0 ;
( ( SceneObjectGroup ) so ) . RootPart . ClearUpdateSchedule ( ) ;
so . SetState ( ad . AttachmentObjectStates [ i + + ] , m_scene ) ;
m_scene . IncomingCreateObject ( Vector3 . Zero , so ) ;
}
}
}
2011-08-30 22:05:43 +00:00
/// <summary>
/// RezAttachments. This should only be called upon login on the first region.
/// Attachment rezzings on crossings and TPs are done in a different way.
/// </summary>
public void RezAttachments ( IScenePresence sp )
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2011-08-30 22:05:43 +00:00
if ( null = = sp . Appearance )
{
m_log . WarnFormat ( "[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}" , sp . UUID ) ;
return ;
}
2011-12-09 22:32:28 +00:00
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing any attachments for {0}", sp.Name);
2011-08-30 22:05:43 +00:00
List < AvatarAttachment > attachments = sp . Appearance . GetAttachments ( ) ;
foreach ( AvatarAttachment attach in attachments )
{
2011-09-03 00:11:16 +00:00
uint p = ( uint ) attach . AttachPoint ;
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
// attach.ItemID, attach.AssetID, p, sp.Name, m_scene.RegionInfo.RegionName);
2011-08-30 22:05:43 +00:00
// For some reason assetIDs are being written as Zero's in the DB -- need to track tat down
// But they're not used anyway, the item is being looked up for now, so let's proceed.
//if (UUID.Zero == assetID)
//{
// m_log.DebugFormat("[ATTACHMENT]: Cannot rez attachment in point {0} with itemID {1}", p, itemID);
// continue;
//}
try
{
2011-09-03 00:11:16 +00:00
// If we're an NPC then skip all the item checks and manipulations since we don't have an
// inventory right now.
if ( sp . PresenceType = = PresenceType . Npc )
RezSingleAttachmentFromInventoryInternal ( sp , UUID . Zero , attach . AssetID , p ) ;
else
2011-10-03 23:44:32 +00:00
RezSingleAttachmentFromInventory ( sp , attach . ItemID , p ) ;
2011-08-30 22:05:43 +00:00
}
catch ( Exception e )
{
2012-04-23 12:31:45 +00:00
UUID agentId = ( sp . ControllingClient = = null ) ? ( UUID ) null : sp . ControllingClient . AgentId ;
m_log . ErrorFormat ( "[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}" ,
attach . ItemID , attach . AssetID , p , agentId , e . Message , e . StackTrace ) ;
2011-08-30 22:05:43 +00:00
}
}
}
2011-08-30 22:32:30 +00:00
2012-07-23 19:08:02 +00:00
public void DeRezAttachments ( IScenePresence sp )
2011-08-30 22:32:30 +00:00
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2012-06-25 21:48:13 +00:00
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
lock ( sp . AttachmentsSyncLock )
2011-08-30 22:32:30 +00:00
{
2012-07-10 21:41:11 +00:00
foreach ( SceneObjectGroup so in sp . GetAttachments ( ) )
2012-06-25 21:48:13 +00:00
{
2012-07-23 19:08:02 +00:00
UpdateDetachedObject ( sp , so ) ;
2012-06-25 21:48:13 +00:00
}
sp . ClearAttachments ( ) ;
2011-08-30 22:32:30 +00:00
}
}
2011-08-31 16:53:58 +00:00
public void DeleteAttachmentsFromScene ( IScenePresence sp , bool silent )
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2012-06-25 21:48:13 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
// m_scene.RegionInfo.RegionName, sp.Name, silent);
2011-08-31 16:53:58 +00:00
foreach ( SceneObjectGroup sop in sp . GetAttachments ( ) )
{
sop . Scene . DeleteSceneObject ( sop , silent ) ;
}
sp . ClearAttachments ( ) ;
}
2012-09-29 00:14:23 +00:00
2012-08-13 23:12:15 +00:00
public bool AttachObject ( IScenePresence sp , SceneObjectGroup group , uint attachmentPt , bool silent , bool temp )
2012-09-29 00:14:23 +00:00
{
if ( ! Enabled )
return false ;
if ( AttachObjectInternal ( sp , group , attachmentPt , silent , temp ) )
{
m_scene . EventManager . TriggerOnAttach ( group . LocalId , group . FromItemID , sp . UUID ) ;
return true ;
}
return false ;
}
private bool AttachObjectInternal ( IScenePresence sp , SceneObjectGroup group , uint attachmentPt , bool silent , bool temp )
2010-03-05 23:18:47 +00:00
{
2011-09-12 20:57:22 +00:00
lock ( sp . AttachmentsSyncLock )
2010-11-23 04:26:07 +00:00
{
2011-09-13 19:25:32 +00:00
// 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);
2012-07-09 20:24:32 +00:00
if ( group . GetSittingAvatarsCount ( ) ! = 0 )
{
// m_log.WarnFormat(
// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
return false ;
}
2011-09-12 20:57:22 +00:00
if ( sp . GetAttachments ( attachmentPt ) . Contains ( group ) )
2011-09-06 01:40:19 +00:00
{
2011-09-12 20:57:22 +00:00
// 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);
2011-09-03 00:11:16 +00:00
2011-09-12 20:57:22 +00:00
return false ;
2011-09-06 01:40:19 +00:00
}
2011-09-03 00:11:16 +00:00
2011-09-12 20:57:22 +00:00
Vector3 attachPos = group . AbsolutePosition ;
// 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 ! = 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 ;
}
group . AttachmentPoint = attachmentPt ;
group . AbsolutePosition = attachPos ;
2012-07-06 21:07:19 +00:00
2011-09-12 20:57:22 +00:00
if ( sp . PresenceType ! = PresenceType . Npc )
2012-08-13 23:12:15 +00:00
UpdateUserInventoryWithAttachment ( sp , group , attachmentPt , temp ) ;
2011-09-12 20:57:22 +00:00
AttachToAgent ( sp , group , attachmentPt , attachPos , silent ) ;
2011-09-03 00:11:16 +00:00
}
2010-11-23 04:26:07 +00:00
2010-03-05 23:18:47 +00:00
return true ;
2011-09-12 20:57:22 +00:00
}
2012-08-13 23:12:15 +00:00
private void UpdateUserInventoryWithAttachment ( IScenePresence sp , SceneObjectGroup group , uint attachmentPt , bool temp )
2012-07-06 21:07:19 +00:00
{
// Remove any previous attachments
List < SceneObjectGroup > attachments = sp . GetAttachments ( attachmentPt ) ;
// At the moment we can only deal with a single attachment
if ( attachments . Count ! = 0 )
{
if ( attachments [ 0 ] . FromItemID ! = UUID . Zero )
DetachSingleAttachmentToInvInternal ( sp , attachments [ 0 ] ) ;
2012-08-13 23:12:15 +00:00
// Error logging commented because UUID.Zero now means temp attachment
// else
// m_log.WarnFormat(
// "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
2012-07-06 21:07:19 +00:00
}
// Add the new attachment to inventory if we don't already have it.
2012-08-13 23:12:15 +00:00
if ( ! temp )
{
UUID newAttachmentItemID = group . FromItemID ;
if ( newAttachmentItemID = = UUID . Zero )
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv ( sp , group ) . ID ;
2012-07-06 21:07:19 +00:00
2012-08-13 23:12:15 +00:00
ShowAttachInUserInventory ( sp , attachmentPt , newAttachmentItemID , group ) ;
}
2012-07-06 21:07:19 +00:00
}
2012-07-11 20:43:35 +00:00
public SceneObjectGroup RezSingleAttachmentFromInventory ( IScenePresence sp , UUID itemID , uint AttachmentPt )
2011-09-12 20:57:22 +00:00
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return null ;
2011-09-13 19:25:32 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
2010-10-14 16:08:59 +00:00
// 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 ;
2011-09-13 21:13:58 +00:00
// Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such).
// This often happens during login - not sure the exact reason.
// For now, we will ignore the request. Unfortunately, this means that we need to dig through all the
// ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login
// before anything has actually been attached.
bool alreadyOn = false ;
List < SceneObjectGroup > existingAttachments = sp . GetAttachments ( ) ;
foreach ( SceneObjectGroup so in existingAttachments )
{
2012-04-06 23:33:02 +00:00
if ( so . FromItemID = = itemID )
2011-09-13 21:13:58 +00:00
{
alreadyOn = true ;
break ;
}
}
// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
if ( alreadyOn )
{
// m_log.WarnFormat(
// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
// sp.Name, itemID, AttachmentPt);
return null ;
}
2012-06-28 21:48:49 +00:00
return RezSingleAttachmentFromInventoryInternal ( sp , itemID , UUID . Zero , AttachmentPt ) ;
2010-09-12 17:43:49 +00:00
}
2010-03-12 23:20:38 +00:00
2011-10-04 21:40:39 +00:00
public void RezMultipleAttachmentsFromInventory ( IScenePresence sp , List < KeyValuePair < UUID , uint > > rezlist )
2010-03-06 00:07:47 +00:00
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2011-10-04 21:40:39 +00:00
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name);
lock ( sp . AttachmentsSyncLock )
2010-03-06 00:07:47 +00:00
{
2011-10-04 21:40:39 +00:00
foreach ( KeyValuePair < UUID , uint > rez in rezlist )
2011-09-12 20:57:22 +00:00
{
2011-10-04 21:40:39 +00:00
RezSingleAttachmentFromInventory ( sp , rez . Key , rez . Value ) ;
2011-09-12 20:57:22 +00:00
}
2011-08-22 22:59:48 +00:00
}
2010-03-10 04:15:36 +00:00
}
2010-03-06 00:07:47 +00:00
2011-10-03 23:44:32 +00:00
public void DetachSingleAttachmentToGround ( IScenePresence sp , uint soLocalId )
2012-07-31 13:45:23 +00:00
{
DetachSingleAttachmentToGround ( sp , soLocalId , sp . AbsolutePosition , Quaternion . Identity ) ;
}
public void DetachSingleAttachmentToGround ( IScenePresence sp , uint soLocalId , Vector3 absolutePos , Quaternion absoluteRot )
2010-04-16 22:15:13 +00:00
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2011-08-30 21:06:24 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
2011-10-03 23:44:32 +00:00
// sp.UUID, soLocalId);
2011-08-30 21:06:24 +00:00
2011-08-30 21:25:38 +00:00
SceneObjectGroup so = m_scene . GetGroupByPrim ( soLocalId ) ;
2011-08-26 21:37:53 +00:00
if ( so = = null )
2010-04-16 22:15:13 +00:00
return ;
2011-10-03 23:44:32 +00:00
if ( so . AttachedAvatar ! = sp . UUID )
2010-09-30 14:57:52 +00:00
return ;
2012-04-06 23:33:02 +00:00
UUID inventoryID = so . FromItemID ;
2010-04-16 22:15:13 +00:00
2012-08-14 00:12:27 +00:00
// As per Linden spec, drop is disabled for temp attachs
if ( inventoryID = = UUID . Zero )
return ;
2011-08-30 21:06:24 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
// so.Name, so.LocalId, inventoryID);
2011-10-03 23:44:32 +00:00
lock ( sp . AttachmentsSyncLock )
2010-04-16 22:15:13 +00:00
{
2011-10-03 23:44:32 +00:00
if ( ! m_scene . Permissions . CanRezObject (
so . PrimCount , sp . UUID , sp . AbsolutePosition ) )
2011-10-04 21:40:39 +00:00
return ;
2012-08-13 23:12:15 +00:00
bool changed = false ;
if ( inventoryID ! = UUID . Zero )
changed = sp . Appearance . DetachAttachment ( inventoryID ) ;
2011-10-03 23:44:32 +00:00
if ( changed & & m_scene . AvatarFactory ! = null )
2011-10-04 21:40:39 +00:00
m_scene . AvatarFactory . QueueAppearanceSave ( sp . UUID ) ;
sp . RemoveAttachment ( so ) ;
2012-04-06 23:33:02 +00:00
so . FromItemID = UUID . Zero ;
2011-10-04 21:40:39 +00:00
SceneObjectPart rootPart = so . RootPart ;
2012-07-31 13:45:23 +00:00
so . AbsolutePosition = absolutePos ;
if ( absoluteRot ! = Quaternion . Identity )
{
so . UpdateGroupRotationR ( absoluteRot ) ;
}
2011-10-04 21:40:39 +00:00
so . AttachedAvatar = UUID . Zero ;
rootPart . SetParentLocalId ( 0 ) ;
so . ClearPartAttachmentData ( ) ;
2011-10-15 01:47:27 +00:00
rootPart . ApplyPhysics ( rootPart . GetEffectiveObjectFlags ( ) , rootPart . VolumeDetectActive ) ;
2011-10-04 21:40:39 +00:00
so . HasGroupChanged = true ;
rootPart . Rezzed = DateTime . Now ;
rootPart . RemFlag ( PrimFlags . TemporaryOnRez ) ;
so . AttachToBackup ( ) ;
m_scene . EventManager . TriggerParcelPrimCountTainted ( ) ;
rootPart . ScheduleFullUpdate ( ) ;
2011-10-03 23:44:32 +00:00
rootPart . ClearUndoState ( ) ;
List < UUID > uuids = new List < UUID > ( ) ;
uuids . Add ( inventoryID ) ;
m_scene . InventoryService . DeleteItems ( sp . UUID , uuids ) ;
sp . ControllingClient . SendRemoveInventoryItem ( inventoryID ) ;
2011-09-12 20:57:22 +00:00
}
2011-08-26 21:49:11 +00:00
2011-10-03 23:44:32 +00:00
m_scene . EventManager . TriggerOnAttach ( so . LocalId , so . UUID , UUID . Zero ) ;
2011-08-26 21:49:11 +00:00
}
2010-03-06 00:07:47 +00:00
2012-06-28 22:31:23 +00:00
public void DetachSingleAttachmentToInv ( IScenePresence sp , SceneObjectGroup so )
2011-10-04 21:40:39 +00:00
{
2011-09-12 20:57:22 +00:00
lock ( sp . AttachmentsSyncLock )
2010-03-06 00:07:47 +00:00
{
2011-10-04 21:40:39 +00:00
// Save avatar attachment information
2012-04-24 23:52:33 +00:00
// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
2011-09-12 20:57:22 +00:00
2012-06-28 22:31:23 +00:00
if ( so . AttachedAvatar ! = sp . UUID )
{
m_log . WarnFormat (
"[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}" ,
so . Name , sp . Name , sp . UUID , so . AttachedAvatar , m_scene . RegionInfo . RegionName ) ;
return ;
}
bool changed = sp . Appearance . DetachAttachment ( so . FromItemID ) ;
2011-10-04 21:40:39 +00:00
if ( changed & & m_scene . AvatarFactory ! = null )
m_scene . AvatarFactory . QueueAppearanceSave ( sp . UUID ) ;
2011-09-12 20:57:22 +00:00
2012-06-28 22:31:23 +00:00
DetachSingleAttachmentToInvInternal ( sp , so ) ;
2010-03-06 00:07:47 +00:00
}
2010-03-10 04:15:36 +00:00
}
2010-08-26 20:50:19 +00:00
2010-12-14 00:11:41 +00:00
public void UpdateAttachmentPosition ( SceneObjectGroup sog , Vector3 pos )
{
2011-09-30 00:19:22 +00:00
if ( ! Enabled )
return ;
2010-12-14 00:11:41 +00:00
sog . UpdateGroupPosition ( pos ) ;
sog . HasGroupChanged = true ;
}
2011-10-04 21:40:39 +00:00
# endregion
#region AttachmentModule private methods
// This is public but is not part of the IAttachmentsModule interface.
// RegionCombiner module needs to poke at it to deliver client events.
// This breaks the encapsulation of the module and should get fixed somehow.
public void SubscribeToClientEvents ( IClientAPI client )
{
client . OnRezSingleAttachmentFromInv + = Client_OnRezSingleAttachmentFromInv ;
client . OnRezMultipleAttachmentsFromInv + = Client_OnRezMultipleAttachmentsFromInv ;
client . OnObjectAttach + = Client_OnObjectAttach ;
client . OnObjectDetach + = Client_OnObjectDetach ;
client . OnDetachAttachmentIntoInv + = Client_OnDetachAttachmentIntoInv ;
client . OnObjectDrop + = Client_OnObjectDrop ;
}
// This is public but is not part of the IAttachmentsModule interface.
// RegionCombiner module needs to poke at it to deliver client events.
// This breaks the encapsulation of the module and should get fixed somehow.
public void UnsubscribeFromClientEvents ( IClientAPI client )
{
client . OnRezSingleAttachmentFromInv - = Client_OnRezSingleAttachmentFromInv ;
client . OnRezMultipleAttachmentsFromInv - = Client_OnRezMultipleAttachmentsFromInv ;
client . OnObjectAttach - = Client_OnObjectAttach ;
client . OnObjectDetach - = Client_OnObjectDetach ;
client . OnDetachAttachmentIntoInv - = Client_OnDetachAttachmentIntoInv ;
client . OnObjectDrop - = Client_OnObjectDrop ;
}
2010-08-26 21:09:52 +00:00
/// <summary>
/// Update the attachment asset for the new sog details if they have changed.
/// </summary>
2011-08-17 23:53:05 +00:00
/// <remarks>
2010-08-26 21:09:52 +00:00
/// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects,
/// these details are not stored on the region.
2011-08-17 23:53:05 +00:00
/// </remarks>
2011-10-04 21:40:39 +00:00
/// <param name="sp"></param>
2010-08-26 21:09:52 +00:00
/// <param name="grp"></param>
2012-07-11 20:43:35 +00:00
/// <param name="saveAllScripted"></param>
2012-07-23 19:08:02 +00:00
private void UpdateKnownItem ( IScenePresence sp , SceneObjectGroup grp , string scriptedState )
2010-08-26 21:09:52 +00:00
{
2012-08-13 23:12:15 +00:00
if ( grp . FromItemID = = UUID . Zero )
{
// We can't save temp attachments
grp . HasGroupChanged = false ;
return ;
}
2012-01-07 11:06:21 +00:00
// Saving attachments for NPCs messes them up for the real owner!
INPCModule module = m_scene . RequestModuleInterface < INPCModule > ( ) ;
if ( module ! = null )
{
if ( module . IsNPC ( sp . UUID , m_scene ) )
return ;
}
2012-07-23 19:08:02 +00:00
if ( grp . HasGroupChanged )
2010-08-26 21:09:52 +00:00
{
2012-10-31 00:31:18 +00:00
m_log . DebugFormat (
"[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}" ,
grp . UUID , grp . AttachmentPoint ) ;
2011-08-26 20:46:12 +00:00
2012-07-23 19:08:02 +00:00
string sceneObjectXml = SceneObjectSerializer . ToOriginalXmlFormat ( grp , scriptedState ) ;
2010-08-26 21:09:52 +00:00
2012-04-06 23:33:02 +00:00
InventoryItemBase item = new InventoryItemBase ( grp . FromItemID , sp . UUID ) ;
2011-09-13 21:24:33 +00:00
item = m_scene . InventoryService . GetItem ( item ) ;
2010-08-26 21:09:52 +00:00
2011-09-13 21:24:33 +00:00
if ( item ! = null )
2010-08-26 21:09:52 +00:00
{
2011-09-13 21:24:33 +00:00
AssetBase asset = m_scene . CreateAsset (
grp . GetPartName ( grp . LocalId ) ,
grp . GetPartDescription ( grp . LocalId ) ,
( sbyte ) AssetType . Object ,
Utils . StringToBytes ( sceneObjectXml ) ,
2011-10-04 21:40:39 +00:00
sp . UUID ) ;
2011-09-13 21:24:33 +00:00
m_scene . AssetService . Store ( asset ) ;
item . AssetID = asset . FullID ;
item . Description = asset . Description ;
item . Name = asset . Name ;
item . AssetType = asset . Type ;
item . InvType = ( int ) InventoryType . Object ;
m_scene . InventoryService . UpdateItem ( item ) ;
2012-07-16 23:17:51 +00:00
// If the name of the object has been changed whilst attached then we want to update the inventory
// item in the viewer.
if ( sp . ControllingClient ! = null )
sp . ControllingClient . SendInventoryItemCreateUpdate ( item , 0 ) ;
2010-08-26 21:09:52 +00:00
}
2012-07-16 23:17:51 +00:00
2012-02-01 09:38:20 +00:00
grp . HasGroupChanged = false ; // Prevent it being saved over and over
2010-08-26 21:09:52 +00:00
}
2012-04-24 23:52:33 +00:00
// else
// {
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint);
// }
2011-10-04 21:40:39 +00:00
}
2010-09-01 00:11:52 +00:00
/// <summary>
/// Attach this scene object to the given avatar.
/// </summary>
2011-09-03 00:11:16 +00:00
/// <remarks>
2010-09-01 00:11:52 +00:00
/// This isn't publicly available since attachments should always perform the corresponding inventory
/// operation (to show the attach in user inventory and update the asset with positional information).
2011-09-03 00:11:16 +00:00
/// </remarks>
2010-09-01 00:11:52 +00:00
/// <param name="sp"></param>
/// <param name="so"></param>
/// <param name="attachmentpoint"></param>
2011-04-29 03:19:54 +00:00
/// <param name="attachOffset"></param>
2010-09-01 00:11:52 +00:00
/// <param name="silent"></param>
2011-09-03 00:11:16 +00:00
private void AttachToAgent (
2011-10-04 21:40:39 +00:00
IScenePresence sp , SceneObjectGroup so , uint attachmentpoint , Vector3 attachOffset , bool silent )
2010-09-01 00:11:52 +00:00
{
2012-05-04 23:29:14 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
2011-10-04 21:40:39 +00:00
2010-09-01 00:11:52 +00:00
so . DetachFromBackup ( ) ;
// Remove from database and parcel prim count
m_scene . DeleteFromStorage ( so . UUID ) ;
m_scene . EventManager . TriggerParcelPrimCountTainted ( ) ;
2011-10-04 21:40:39 +00:00
so . AttachedAvatar = sp . UUID ;
2010-09-01 00:11:52 +00:00
if ( so . RootPart . PhysActor ! = null )
2011-10-15 01:02:39 +00:00
so . RootPart . RemoveFromPhysics ( ) ;
2010-09-01 00:11:52 +00:00
2011-04-29 03:19:54 +00:00
so . AbsolutePosition = attachOffset ;
so . RootPart . AttachedPos = attachOffset ;
2011-08-26 23:15:21 +00:00
so . IsAttachment = true ;
2011-10-04 21:40:39 +00:00
so . RootPart . SetParentLocalId ( sp . LocalId ) ;
2011-08-26 23:33:24 +00:00
so . AttachmentPoint = attachmentpoint ;
2010-09-01 00:11:52 +00:00
2011-10-04 21:40:39 +00:00
sp . AddAttachment ( so ) ;
2010-09-01 00:11:52 +00:00
if ( ! silent )
{
2013-01-03 20:57:14 +00:00
if ( so . HasPrivateAttachmentPoint )
2012-06-14 01:26:38 +00:00
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
// so.Name, sp.Name, so.AttachmentPoint);
2012-06-14 01:30:40 +00:00
// As this scene object can now only be seen by the attaching avatar, tell everybody else in the
// scene that it's no longer in their awareness.
2012-06-14 01:26:38 +00:00
m_scene . ForEachClient (
client = >
{ if ( client . AgentId ! = so . AttachedAvatar )
client . SendKillObject ( m_scene . RegionInfo . RegionHandle , new List < uint > ( ) { so . LocalId } ) ;
} ) ;
}
2010-09-01 00:11:52 +00:00
2013-01-03 21:06:50 +00:00
// Fudge below is an extremely unhelpful comment. It's probably here so that the scheduled full update
// will succeed, as that will not update if an attachment is selected.
so . IsSelected = false ; // fudge....
2010-09-01 00:11:52 +00:00
so . ScheduleGroupForFullUpdate ( ) ;
}
2011-10-04 21:40:39 +00:00
2010-09-01 00:11:52 +00:00
// In case it is later dropped again, don't let
// it get cleaned up
so . RootPart . RemFlag ( PrimFlags . TemporaryOnRez ) ;
}
2011-08-24 20:35:44 +00:00
/// <summary>
2011-09-06 01:29:22 +00:00
/// Add a scene object as a new attachment in the user inventory.
2011-08-24 20:35:44 +00:00
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="grp"></param>
2011-08-24 20:40:36 +00:00
/// <returns>The user inventory item created that holds the attachment.</returns>
2011-10-04 21:40:39 +00:00
private InventoryItemBase AddSceneObjectAsNewAttachmentInInv ( IScenePresence sp , SceneObjectGroup grp )
2011-08-24 20:35:44 +00:00
{
2012-05-23 00:58:10 +00:00
if ( m_invAccessModule = = null )
return null ;
2011-10-04 21:40:39 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
// grp.Name, grp.LocalId, remoteClient.Name);
2011-08-24 20:35:44 +00:00
2012-07-06 21:07:19 +00:00
InventoryItemBase newItem
= m_invAccessModule . CopyToInventory (
DeRezAction . TakeCopy ,
m_scene . InventoryService . GetFolderForType ( sp . UUID , AssetType . Object ) . ID ,
new List < SceneObjectGroup > { grp } ,
sp . ControllingClient , true ) [ 0 ] ;
2011-08-24 20:35:44 +00:00
// sets itemID so client can show item as 'attached' in inventory
2012-05-23 00:58:10 +00:00
grp . FromItemID = newItem . ID ;
2011-08-24 20:35:44 +00:00
2012-05-23 00:58:10 +00:00
return newItem ;
2011-08-24 20:35:44 +00:00
}
2011-10-04 21:40:39 +00:00
2012-07-23 19:08:02 +00:00
private string GetObjectScriptStates ( SceneObjectGroup grp )
2011-10-04 21:40:39 +00:00
{
2012-07-23 19:08:02 +00:00
using ( StringWriter sw = new StringWriter ( ) )
{
using ( XmlTextWriter writer = new XmlTextWriter ( sw ) )
{
grp . SaveScriptedState ( writer ) ;
}
2011-10-04 21:40:39 +00:00
2012-07-23 19:08:02 +00:00
return sw . ToString ( ) ;
}
}
private void UpdateDetachedObject ( IScenePresence sp , SceneObjectGroup so )
{
// Don't save attachments for HG visitors, it
// messes up their inventory. When a HG visitor logs
// out on a foreign grid, their attachments will be
// reloaded in the state they were in when they left
// the home grid. This is best anyway as the visited
// grid may use an incompatible script engine.
bool saveChanged
= sp . PresenceType ! = PresenceType . Npc
& & ( m_scene . UserManagementModule = = null
| | m_scene . UserManagementModule . IsLocalGridUser ( sp . UUID ) ) ;
// Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will
// clobber the run flag
string scriptedState = GetObjectScriptStates ( so ) ;
// Remove the object from the scene so no more updates
// are sent. Doing this before the below changes will ensure
// updates can't cause "HUD artefacts"
m_scene . DeleteSceneObject ( so , false , false ) ;
2012-07-10 21:41:11 +00:00
2012-06-28 22:31:23 +00:00
// Prepare sog for storage
so . AttachedAvatar = UUID . Zero ;
so . RootPart . SetParentLocalId ( 0 ) ;
so . IsAttachment = false ;
2012-07-20 09:54:59 +00:00
2012-07-23 19:08:02 +00:00
if ( saveChanged )
{
// We cannot use AbsolutePosition here because that would
// attempt to cross the prim as it is detached
so . ForEachPart ( x = > { x . GroupPosition = so . RootPart . AttachedPos ; } ) ;
UpdateKnownItem ( sp , so , scriptedState ) ;
}
// Now, remove the scripts
so . RemoveScriptInstances ( true ) ;
}
2012-06-28 22:01:12 +00:00
2012-07-23 19:08:02 +00:00
private void DetachSingleAttachmentToInvInternal ( IScenePresence sp , SceneObjectGroup so )
{
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
m_scene . EventManager . TriggerOnAttach ( so . LocalId , so . FromItemID , UUID . Zero ) ;
sp . RemoveAttachment ( so ) ;
2012-07-20 09:54:59 +00:00
2012-07-23 19:08:02 +00:00
UpdateDetachedObject ( sp , so ) ;
2011-10-04 21:40:39 +00:00
}
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal (
IScenePresence sp , UUID itemID , UUID assetID , uint attachmentPt )
{
2012-05-23 00:58:10 +00:00
if ( m_invAccessModule = = null )
return null ;
lock ( sp . AttachmentsSyncLock )
2011-10-04 21:40:39 +00:00
{
2012-05-23 00:58:10 +00:00
SceneObjectGroup objatt ;
if ( itemID ! = UUID . Zero )
objatt = m_invAccessModule . RezObject ( sp . ControllingClient ,
itemID , Vector3 . Zero , Vector3 . Zero , UUID . Zero , ( byte ) 1 , true ,
false , false , sp . UUID , true ) ;
else
objatt = m_invAccessModule . RezObject ( sp . ControllingClient ,
null , assetID , Vector3 . Zero , Vector3 . Zero , UUID . Zero , ( byte ) 1 , true ,
false , false , sp . UUID , true ) ;
if ( objatt ! = null )
2011-10-04 21:40:39 +00:00
{
2012-07-11 20:43:35 +00:00
// 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);
2012-05-23 00:58:10 +00:00
// 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 ;
2012-07-11 20:43:35 +00:00
// 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.
2012-05-23 00:58:10 +00:00
// This will throw if the attachment fails
try
2011-10-04 21:40:39 +00:00
{
2012-09-29 00:14:23 +00:00
AttachObjectInternal ( sp , objatt , attachmentPt , false , false ) ;
2012-05-23 00:58:10 +00:00
}
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 ;
}
2011-10-04 21:40:39 +00:00
2012-05-23 00:58:10 +00:00
if ( tainted )
objatt . HasGroupChanged = true ;
2011-10-04 21:40:39 +00:00
2012-05-23 00:58:10 +00:00
// Fire after attach, so we don't get messy perms dialogs
// 4 == AttachedRez
objatt . CreateScriptInstances ( 0 , true , m_scene . DefaultScriptEngine , 4 ) ;
objatt . ResumeScripts ( ) ;
2011-10-04 21:40:39 +00:00
2012-05-23 00:58:10 +00:00
// 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 ) ;
2011-10-04 21:40:39 +00:00
2012-05-23 00:58:10 +00:00
return objatt ;
}
else
{
m_log . WarnFormat (
"[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}" ,
itemID , sp . Name , attachmentPt ) ;
2011-10-04 21:40:39 +00:00
}
}
return null ;
}
/// <summary>
/// Update the user inventory to reflect an attachment
/// </summary>
/// <param name="sp"></param>
/// <param name="AttachmentPt"></param>
/// <param name="itemID"></param>
/// <param name="att"></param>
private void ShowAttachInUserInventory ( IScenePresence sp , uint AttachmentPt , UUID itemID , SceneObjectGroup att )
{
2012-05-04 23:29:14 +00:00
// m_log.DebugFormat(
// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
// att.Name, sp.Name, AttachmentPt, itemID);
2011-10-04 21:40:39 +00:00
if ( UUID . Zero = = itemID )
{
m_log . Error ( "[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID." ) ;
return ;
}
if ( 0 = = AttachmentPt )
{
m_log . Error ( "[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point." ) ;
return ;
}
InventoryItemBase item = new InventoryItemBase ( itemID , sp . UUID ) ;
item = m_scene . InventoryService . GetItem ( item ) ;
2012-09-22 21:01:51 +00:00
if ( item = = null )
return ;
2011-10-04 21:40:39 +00:00
bool changed = sp . Appearance . SetAttachment ( ( int ) AttachmentPt , itemID , item . AssetID ) ;
if ( changed & & m_scene . AvatarFactory ! = null )
2012-07-06 21:07:19 +00:00
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
// sp.Name, att.Name, AttachmentPt);
2011-10-04 21:40:39 +00:00
m_scene . AvatarFactory . QueueAppearanceSave ( sp . UUID ) ;
2012-07-06 21:07:19 +00:00
}
2011-10-04 21:40:39 +00:00
}
# endregion
#region Client Event Handlers
private ISceneEntity Client_OnRezSingleAttachmentFromInv ( IClientAPI remoteClient , UUID itemID , uint AttachmentPt )
{
if ( ! Enabled )
return null ;
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}",
// (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name);
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
if ( sp = = null )
{
m_log . ErrorFormat (
"[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()" ,
remoteClient . Name , remoteClient . AgentId ) ;
return null ;
}
return RezSingleAttachmentFromInventory ( sp , itemID , AttachmentPt ) ;
}
private void Client_OnRezMultipleAttachmentsFromInv ( IClientAPI remoteClient , List < KeyValuePair < UUID , uint > > rezlist )
{
if ( ! Enabled )
return ;
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
if ( sp ! = null )
RezMultipleAttachmentsFromInventory ( sp , rezlist ) ;
else
m_log . ErrorFormat (
"[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()" ,
remoteClient . Name , remoteClient . AgentId ) ;
}
private void Client_OnObjectAttach ( IClientAPI remoteClient , uint objectLocalID , uint AttachmentPt , bool silent )
{
2012-05-04 23:29:14 +00:00
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
// objectLocalID, remoteClient.Name, AttachmentPt, silent);
2011-10-04 21:40:39 +00:00
if ( ! Enabled )
return ;
try
{
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
if ( sp = = null )
{
m_log . ErrorFormat (
"[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}" , remoteClient . Name , remoteClient . AgentId ) ;
return ;
}
// If we can't take it, we can't attach it!
SceneObjectPart part = m_scene . GetSceneObjectPart ( objectLocalID ) ;
if ( part = = null )
return ;
if ( ! m_scene . Permissions . CanTakeObject ( part . UUID , remoteClient . AgentId ) )
{
remoteClient . SendAgentAlertMessage (
"You don't have sufficient permissions to attach this object" , false ) ;
return ;
}
// 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 ;
// Calls attach with a Zero position
2012-09-29 00:14:23 +00:00
AttachObject ( sp , part . ParentGroup , AttachmentPt , false , false ) ;
2011-10-04 21:40:39 +00:00
}
catch ( Exception e )
{
m_log . ErrorFormat ( "[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}" , e . Message , e . StackTrace ) ;
}
}
private void Client_OnObjectDetach ( uint objectLocalID , IClientAPI remoteClient )
{
if ( ! Enabled )
return ;
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
SceneObjectGroup group = m_scene . GetGroupByPrim ( objectLocalID ) ;
2012-06-28 22:31:23 +00:00
2012-08-20 13:35:06 +00:00
if ( sp ! = null & & group ! = null & & group . FromItemID ! = UUID . Zero )
2012-06-28 22:31:23 +00:00
DetachSingleAttachmentToInv ( sp , group ) ;
2011-10-04 21:40:39 +00:00
}
private void Client_OnDetachAttachmentIntoInv ( UUID itemID , IClientAPI remoteClient )
{
if ( ! Enabled )
return ;
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
if ( sp ! = null )
2012-06-28 22:31:23 +00:00
{
lock ( sp . AttachmentsSyncLock )
{
List < SceneObjectGroup > attachments = sp . GetAttachments ( ) ;
foreach ( SceneObjectGroup group in attachments )
{
2012-08-20 13:35:06 +00:00
if ( group . FromItemID = = itemID & & group . FromItemID ! = UUID . Zero )
2012-06-28 22:31:23 +00:00
{
DetachSingleAttachmentToInv ( sp , group ) ;
return ;
}
}
}
}
2011-10-04 21:40:39 +00:00
}
private void Client_OnObjectDrop ( uint soLocalId , IClientAPI remoteClient )
{
if ( ! Enabled )
return ;
ScenePresence sp = m_scene . GetScenePresence ( remoteClient . AgentId ) ;
if ( sp ! = null )
DetachSingleAttachmentToGround ( sp , soLocalId ) ;
}
# endregion
2010-03-05 23:18:47 +00:00
}
2011-10-03 18:55:54 +00:00
}