aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs553
1 files changed, 286 insertions, 267 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index fd7cad2..394b90a 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 51
52 private Scene m_scene; 52 private Scene m_scene;
53 private IDialogModule m_dialogModule; 53 private IInventoryAccessModule m_invAccessModule;
54 54
55 /// <summary> 55 /// <summary>
56 /// Are attachments enabled? 56 /// Are attachments enabled?
@@ -72,7 +72,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
72 public void AddRegion(Scene scene) 72 public void AddRegion(Scene scene)
73 { 73 {
74 m_scene = scene; 74 m_scene = scene;
75 m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
76 m_scene.RegisterModuleInterface<IAttachmentsModule>(this); 75 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
77 76
78 if (Enabled) 77 if (Enabled)
@@ -89,7 +88,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
89 m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; 88 m_scene.EventManager.OnNewClient -= SubscribeToClientEvents;
90 } 89 }
91 90
92 public void RegionLoaded(Scene scene) {} 91 public void RegionLoaded(Scene scene)
92 {
93 m_invAccessModule = m_scene.RequestModuleInterface<IInventoryAccessModule>();
94 }
93 95
94 public void Close() 96 public void Close()
95 { 97 {
@@ -100,6 +102,56 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
100 102
101 #region IAttachmentsModule 103 #region IAttachmentsModule
102 104
105 public void CopyAttachments(IScenePresence sp, AgentData ad)
106 {
107 lock (sp.AttachmentsSyncLock)
108 {
109 // Attachment objects
110 List<SceneObjectGroup> attachments = sp.GetAttachments();
111 if (attachments.Count > 0)
112 {
113 ad.AttachmentObjects = new List<ISceneObject>();
114 ad.AttachmentObjectStates = new List<string>();
115 // IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
116 sp.InTransitScriptStates.Clear();
117
118 foreach (SceneObjectGroup sog in attachments)
119 {
120 // We need to make a copy and pass that copy
121 // because of transfers withn the same sim
122 ISceneObject clone = sog.CloneForNewScene();
123 // Attachment module assumes that GroupPosition holds the offsets...!
124 ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos;
125 ((SceneObjectGroup)clone).IsAttachment = false;
126 ad.AttachmentObjects.Add(clone);
127 string state = sog.GetStateSnapshot();
128 ad.AttachmentObjectStates.Add(state);
129 sp.InTransitScriptStates.Add(state);
130 // Let's remove the scripts of the original object here
131 sog.RemoveScriptInstances(true);
132 }
133 }
134 }
135 }
136
137 public void CopyAttachments(AgentData ad, IScenePresence sp)
138 {
139 if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0)
140 {
141 lock (sp.AttachmentsSyncLock)
142 sp.ClearAttachments();
143
144 int i = 0;
145 foreach (ISceneObject so in ad.AttachmentObjects)
146 {
147 ((SceneObjectGroup)so).LocalId = 0;
148 ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
149 so.SetState(ad.AttachmentObjectStates[i++], m_scene);
150 m_scene.IncomingCreateObject(Vector3.Zero, so);
151 }
152 }
153 }
154
103 /// <summary> 155 /// <summary>
104 /// RezAttachments. This should only be called upon login on the first region. 156 /// RezAttachments. This should only be called upon login on the first region.
105 /// Attachment rezzings on crossings and TPs are done in a different way. 157 /// Attachment rezzings on crossings and TPs are done in a different way.
@@ -185,40 +237,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
185 if (sp.PresenceType == PresenceType.Npc) 237 if (sp.PresenceType == PresenceType.Npc)
186 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null); 238 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null);
187 else 239 else
188 RezSingleAttachmentFromInventory(sp, attach.ItemID, p, true, d); 240 RezSingleAttachmentFromInventory(sp, attach.ItemID, p, d);
189 } 241 }
190 catch (Exception e) 242 catch (Exception e)
191 { 243 {
192 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment: {0}{1}", e.Message, e.StackTrace); 244 UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId;
245 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}",
246 attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace);
193 } 247 }
194 } 248 }
195 } 249 }
196 250
197 public void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted) 251 public void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted)
198 { 252 {
199// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
200
201 if (!Enabled) 253 if (!Enabled)
202 return; 254 return;
203 255
204 foreach (SceneObjectGroup grp in sp.GetAttachments()) 256// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
257
258 lock (sp.AttachmentsSyncLock)
205 { 259 {
206 grp.IsAttachment = false; 260 foreach (SceneObjectGroup so in sp.GetAttachments())
207 grp.AbsolutePosition = grp.RootPart.AttachedPos; 261 {
208 UpdateKnownItem(sp, grp, saveAllScripted); 262 // We can only remove the script instances from the script engine after we've retrieved their xml state
209 grp.IsAttachment = true; 263 // when we update the attachment item.
264 m_scene.DeleteSceneObject(so, false, false);
265
266 if (saveChanged || saveAllScripted)
267 {
268 so.IsAttachment = false;
269 so.AbsolutePosition = so.RootPart.AttachedPos;
270 UpdateKnownItem(sp, so, saveAllScripted);
271 }
272
273 so.RemoveScriptInstances(true);
274 }
275
276 sp.ClearAttachments();
210 } 277 }
211 } 278 }
212 279
213 public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent) 280 public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent)
214 { 281 {
215// m_log.DebugFormat(
216// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
217// m_scene.RegionInfo.RegionName, sp.Name, silent);
218
219 if (!Enabled) 282 if (!Enabled)
220 return; 283 return;
221 284
285// m_log.DebugFormat(
286// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
287// m_scene.RegionInfo.RegionName, sp.Name, silent);
288
222 foreach (SceneObjectGroup sop in sp.GetAttachments()) 289 foreach (SceneObjectGroup sop in sp.GetAttachments())
223 { 290 {
224 sop.Scene.DeleteSceneObject(sop, silent); 291 sop.Scene.DeleteSceneObject(sop, silent);
@@ -234,6 +301,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
234// m_log.DebugFormat( 301// m_log.DebugFormat(
235// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 302// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
236// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 303// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
304
305 if (group.GetSittingAvatarsCount() != 0)
306 {
307// m_log.WarnFormat(
308// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
309// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
310
311 return false;
312 }
237 313
238 if (sp.GetAttachments(attachmentPt).Contains(group)) 314 if (sp.GetAttachments(attachmentPt).Contains(group))
239 { 315 {
@@ -294,32 +370,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
294 group.AttachmentPoint = attachmentPt; 370 group.AttachmentPoint = attachmentPt;
295 group.AbsolutePosition = attachPos; 371 group.AbsolutePosition = attachPos;
296 372
297 // We also don't want to do any of the inventory operations for an NPC.
298 if (sp.PresenceType != PresenceType.Npc) 373 if (sp.PresenceType != PresenceType.Npc)
299 { 374 UpdateUserInventoryWithAttachment(sp, group, attachmentPt);
300 // Remove any previous attachments
301 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
302
303 // At the moment we can only deal with a single attachment
304 if (attachments.Count != 0)
305 {
306 UUID oldAttachmentItemID = attachments[0].FromItemID;
307
308 if (oldAttachmentItemID != UUID.Zero)
309 DetachSingleAttachmentToInvInternal(sp, oldAttachmentItemID);
310 else
311 m_log.WarnFormat(
312 "[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!",
313 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
314 }
315
316 // Add the new attachment to inventory if we don't already have it.
317 UUID newAttachmentItemID = group.FromItemID;
318 if (newAttachmentItemID == UUID.Zero)
319 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
320
321 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
322 }
323 375
324 AttachToAgent(sp, group, attachmentPt, attachPos, silent); 376 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
325 } 377 }
@@ -327,12 +379,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
327 return true; 379 return true;
328 } 380 }
329 381
382 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt)
383 {
384 // Remove any previous attachments
385 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
386
387 // At the moment we can only deal with a single attachment
388 if (attachments.Count != 0)
389 {
390 if (attachments[0].FromItemID != UUID.Zero)
391 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
392 else
393 m_log.WarnFormat(
394 "[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!",
395 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
396 }
397
398 // Add the new attachment to inventory if we don't already have it.
399 UUID newAttachmentItemID = group.FromItemID;
400 if (newAttachmentItemID == UUID.Zero)
401 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
402
403 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
404 }
405
330 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) 406 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
331 { 407 {
332 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, true, null); 408 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, null);
333 } 409 }
334 410
335 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) 411 public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, XmlDocument doc)
336 { 412 {
337 if (!Enabled) 413 if (!Enabled)
338 return null; 414 return null;
@@ -371,12 +447,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
371 return null; 447 return null;
372 } 448 }
373 449
374 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); 450 return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc);
375
376 if (att == null)
377 DetachSingleAttachmentToInv(sp, itemID);
378
379 return att;
380 } 451 }
381 452
382 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) 453 public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
@@ -453,18 +524,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
453 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); 524 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero);
454 } 525 }
455 526
456 public void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID) 527 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
457 { 528 {
458 lock (sp.AttachmentsSyncLock) 529 lock (sp.AttachmentsSyncLock)
459 { 530 {
460 // Save avatar attachment information 531 // Save avatar attachment information
461 m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 532// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
533
534 if (so.AttachedAvatar != sp.UUID)
535 {
536 m_log.WarnFormat(
537 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
538 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
462 539
463 bool changed = sp.Appearance.DetachAttachment(itemID); 540 return;
541 }
542
543 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
464 if (changed && m_scene.AvatarFactory != null) 544 if (changed && m_scene.AvatarFactory != null)
465 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 545 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
466 546
467 DetachSingleAttachmentToInvInternal(sp, itemID); 547 DetachSingleAttachmentToInvInternal(sp, so);
468 } 548 }
469 } 549 }
470 550
@@ -473,17 +553,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
473 if (!Enabled) 553 if (!Enabled)
474 return; 554 return;
475 555
476 // First we save the
477 // attachment point information, then we update the relative
478 // positioning. Then we have to mark the object as NOT an
479 // attachment. This is necessary in order to correctly save
480 // and retrieve GroupPosition information for the attachment.
481 // Finally, we restore the object's attachment status.
482 uint attachmentPoint = sog.AttachmentPoint;
483 sog.UpdateGroupPosition(pos); 556 sog.UpdateGroupPosition(pos);
484 sog.IsAttachment = false;
485 sog.AbsolutePosition = sog.RootPart.AttachedPos;
486 sog.AttachmentPoint = attachmentPoint;
487 sog.HasGroupChanged = true; 557 sog.HasGroupChanged = true;
488 } 558 }
489 559
@@ -526,6 +596,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
526 /// </remarks> 596 /// </remarks>
527 /// <param name="sp"></param> 597 /// <param name="sp"></param>
528 /// <param name="grp"></param> 598 /// <param name="grp"></param>
599 /// <param name="saveAllScripted"></param>
529 private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, bool saveAllScripted) 600 private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, bool saveAllScripted)
530 { 601 {
531 // Saving attachments for NPCs messes them up for the real owner! 602 // Saving attachments for NPCs messes them up for the real owner!
@@ -538,9 +609,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
538 609
539 if (grp.HasGroupChanged || (saveAllScripted && grp.ContainsScripts())) 610 if (grp.HasGroupChanged || (saveAllScripted && grp.ContainsScripts()))
540 { 611 {
541 m_log.DebugFormat( 612// m_log.DebugFormat(
542 "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", 613// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
543 grp.UUID, grp.AttachmentPoint); 614// grp.UUID, grp.AttachmentPoint);
544 615
545 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); 616 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
546 617
@@ -571,12 +642,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
571 } 642 }
572 grp.HasGroupChanged = false; // Prevent it being saved over and over 643 grp.HasGroupChanged = false; // Prevent it being saved over and over
573 } 644 }
574 else 645// else
575 { 646// {
576 m_log.DebugFormat( 647// m_log.DebugFormat(
577 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", 648// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
578 grp.UUID, grp.AttachmentPoint); 649// grp.UUID, grp.AttachmentPoint);
579 } 650// }
580 } 651 }
581 652
582 /// <summary> 653 /// <summary>
@@ -594,9 +665,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
594 private void AttachToAgent( 665 private void AttachToAgent(
595 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 666 IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
596 { 667 {
597 // m_log.DebugFormat( 668// m_log.DebugFormat(
598 // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", 669// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
599 // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); 670// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
600 671
601 so.DetachFromBackup(); 672 so.DetachFromBackup();
602 673
@@ -627,6 +698,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
627 { 698 {
628 m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId }); 699 m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId });
629 } 700 }
701 else if (so.HasPrivateAttachmentPoint)
702 {
703// m_log.DebugFormat(
704// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
705// so.Name, sp.Name, so.AttachmentPoint);
706
707 // As this scene object can now only be seen by the attaching avatar, tell everybody else in the
708 // scene that it's no longer in their awareness.
709 m_scene.ForEachClient(
710 client =>
711 { if (client.AgentId != so.AttachedAvatar)
712 client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId });
713 });
714 }
630 715
631 so.IsSelected = false; // fudge.... 716 so.IsSelected = false; // fudge....
632 so.ScheduleGroupForFullUpdate(); 717 so.ScheduleGroupForFullUpdate();
@@ -645,210 +730,124 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
645 /// <returns>The user inventory item created that holds the attachment.</returns> 730 /// <returns>The user inventory item created that holds the attachment.</returns>
646 private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) 731 private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp)
647 { 732 {
733 if (m_invAccessModule == null)
734 return null;
735
648 // m_log.DebugFormat( 736 // m_log.DebugFormat(
649 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", 737 // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
650 // grp.Name, grp.LocalId, remoteClient.Name); 738 // grp.Name, grp.LocalId, remoteClient.Name);
651 739
652// Vector3 inventoryStoredPosition = new Vector3 740 InventoryItemBase newItem
653// (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 741 = m_invAccessModule.CopyToInventory(
654// ? (float)Constants.RegionSize - 6 742 DeRezAction.TakeCopy,
655// : grp.AbsolutePosition.X) 743 m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID,
656// , 744 new List<SceneObjectGroup> { grp },
657// (grp.AbsolutePosition.Y > (int)Constants.RegionSize) 745 sp.ControllingClient, true)[0];
658// ? (float)Constants.RegionSize - 6
659// : grp.AbsolutePosition.Y,
660// grp.AbsolutePosition.Z);
661//
662// Vector3 originalPosition = grp.AbsolutePosition;
663//
664// grp.AbsolutePosition = inventoryStoredPosition;
665
666 // If we're being called from a script, then trying to serialize that same script's state will not complete
667 // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
668 // the client/server crashes rather than logging out normally, the attachment's scripts will resume
669 // without state on relog. Arguably, this is what we want anyway.
670 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false);
671
672// grp.AbsolutePosition = originalPosition;
673
674 AssetBase asset = m_scene.CreateAsset(
675 grp.GetPartName(grp.LocalId),
676 grp.GetPartDescription(grp.LocalId),
677 (sbyte)AssetType.Object,
678 Utils.StringToBytes(sceneObjectXml),
679 sp.UUID);
680
681 m_scene.AssetService.Store(asset);
682
683 InventoryItemBase item = new InventoryItemBase();
684 item.CreatorId = grp.RootPart.CreatorID.ToString();
685 item.CreatorData = grp.RootPart.CreatorData;
686 item.Owner = sp.UUID;
687 item.ID = UUID.Random();
688 item.AssetID = asset.FullID;
689 item.Description = asset.Description;
690 item.Name = asset.Name;
691 item.AssetType = asset.Type;
692 item.InvType = (int)InventoryType.Object;
693
694 InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
695 if (folder != null)
696 item.Folder = folder.ID;
697 else // oopsies
698 item.Folder = UUID.Zero;
699
700 // Nix the special bits we used to use for slam and the folded perms
701 uint allowablePermissionsMask = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move);
702
703 if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions())
704 {
705 item.BasePermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
706 item.CurrentPermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
707 item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask;
708 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
709 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask;
710 }
711 else
712 {
713 item.BasePermissions = grp.RootPart.BaseMask & allowablePermissionsMask;
714 item.CurrentPermissions = grp.RootPart.OwnerMask & allowablePermissionsMask;
715 item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask;
716 item.EveryOnePermissions = grp.RootPart.EveryoneMask & allowablePermissionsMask;
717 item.GroupPermissions = grp.RootPart.GroupMask & allowablePermissionsMask;
718 }
719 item.CreationDate = Util.UnixTimeSinceEpoch();
720 746
721 // sets itemID so client can show item as 'attached' in inventory 747 // sets itemID so client can show item as 'attached' in inventory
722 grp.FromItemID = item.ID; 748 grp.FromItemID = newItem.ID;
723
724 if (m_scene.AddInventoryItem(item))
725 {
726 sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
727 }
728 else
729 {
730 if (m_dialogModule != null)
731 m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed");
732 }
733 749
734 return item; 750 return newItem;
735 } 751 }
736 752
737 // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. 753 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
738 // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
739 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID)
740 { 754 {
741 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); 755 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
742 756
743 if (itemID == UUID.Zero) // If this happened, someone made a mistake.... 757 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
744 return; 758 sp.RemoveAttachment(so);
745
746 // We can NOT use the dictionries here, as we are looking
747 // for an entity by the fromAssetID, which is NOT the prim UUID
748 EntityBase[] detachEntities = m_scene.GetEntities();
749 SceneObjectGroup group;
750
751 lock (sp.AttachmentsSyncLock)
752 {
753 foreach (EntityBase entity in detachEntities)
754 {
755 if (entity is SceneObjectGroup)
756 {
757 group = (SceneObjectGroup)entity;
758 if (group.FromItemID == itemID)
759 {
760 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
761 sp.RemoveAttachment(group);
762 759
763 // Prepare sog for storage 760 // We can only remove the script instances from the script engine after we've retrieved their xml state
764 group.AttachedAvatar = UUID.Zero; 761 // when we update the attachment item.
765 group.RootPart.SetParentLocalId(0); 762 m_scene.DeleteSceneObject(so, false, false);
766 group.IsAttachment = false;
767 group.AbsolutePosition = group.RootPart.AttachedPos;
768 763
769 UpdateKnownItem(sp, group, true); 764 // Prepare sog for storage
770 m_scene.DeleteSceneObject(group, false); 765 so.AttachedAvatar = UUID.Zero;
766 so.RootPart.SetParentLocalId(0);
767 so.IsAttachment = false;
768 so.AbsolutePosition = so.RootPart.AttachedPos;
771 769
772 return; 770 UpdateKnownItem(sp, so, true);
773 } 771 so.RemoveScriptInstances(true);
774 }
775 }
776 }
777 } 772 }
778 773
779 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 774 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
780 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) 775 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc)
781 { 776 {
782 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 777 if (m_invAccessModule == null)
783 if (invAccess != null) 778 return null;
779
780 lock (sp.AttachmentsSyncLock)
784 { 781 {
785 lock (sp.AttachmentsSyncLock) 782 SceneObjectGroup objatt;
783
784 if (itemID != UUID.Zero)
785 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
786 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
787 false, false, sp.UUID, true);
788 else
789 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
790 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
791 false, false, sp.UUID, true);
792
793 if (objatt != null)
786 { 794 {
787 SceneObjectGroup objatt; 795// m_log.DebugFormat(
788 796// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
789 if (itemID != UUID.Zero) 797// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
790 objatt = invAccess.RezObject(sp.ControllingClient, 798
791 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 799 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
792 false, false, sp.UUID, true); 800 objatt.HasGroupChanged = false;
793 else 801 bool tainted = false;
794 objatt = invAccess.RezObject(sp.ControllingClient, 802 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
795 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 803 tainted = true;
796 false, false, sp.UUID, true); 804
797 805 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
798 // m_log.DebugFormat( 806 // course of events. If not, then it's probably not worth trying to recover the situation
799 // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", 807 // since this is more likely to trigger further exceptions and confuse later debugging. If
800 // objatt.Name, remoteClient.Name, AttachmentPt); 808 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
801 809 // since other normal error conditions will simply return false instead.
802 if (objatt != null) 810 // This will throw if the attachment fails
811 try
803 { 812 {
804 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. 813 AttachObject(sp, objatt, attachmentPt, false, false);
805 objatt.HasGroupChanged = false;
806 bool tainted = false;
807 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
808 tainted = true;
809
810 // This will throw if the attachment fails
811 try
812 {
813 AttachObject(sp, objatt, attachmentPt, false, false);
814 }
815 catch (Exception e)
816 {
817 m_log.ErrorFormat(
818 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
819 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
820
821 // Make sure the object doesn't stick around and bail
822 sp.RemoveAttachment(objatt);
823 m_scene.DeleteSceneObject(objatt, false);
824 return null;
825 }
826
827 if (tainted)
828 objatt.HasGroupChanged = true;
829
830 if (doc != null)
831 {
832 objatt.LoadScriptState(doc);
833 objatt.ResetOwnerChangeFlag();
834 }
835
836 // Fire after attach, so we don't get messy perms dialogs
837 // 4 == AttachedRez
838 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
839 objatt.ResumeScripts();
840
841 // Do this last so that event listeners have access to all the effects of the attachment
842 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
843
844 return objatt;
845 } 814 }
846 else 815 catch (Exception e)
816 {
817 m_log.ErrorFormat(
818 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
819 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
820
821 // Make sure the object doesn't stick around and bail
822 sp.RemoveAttachment(objatt);
823 m_scene.DeleteSceneObject(objatt, false);
824 return null;
825 }
826
827 if (tainted)
828 objatt.HasGroupChanged = true;
829
830 if (doc != null)
847 { 831 {
848 m_log.WarnFormat( 832 objatt.LoadScriptState(doc);
849 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", 833 objatt.ResetOwnerChangeFlag();
850 itemID, sp.Name, attachmentPt);
851 } 834 }
835
836 // Fire after attach, so we don't get messy perms dialogs
837 // 4 == AttachedRez
838 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
839 objatt.ResumeScripts();
840
841 // Do this last so that event listeners have access to all the effects of the attachment
842 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
843
844 return objatt;
845 }
846 else
847 {
848 m_log.WarnFormat(
849 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
850 itemID, sp.Name, attachmentPt);
852 } 851 }
853 } 852 }
854 853
@@ -864,9 +863,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
864 /// <param name="att"></param> 863 /// <param name="att"></param>
865 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 864 private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att)
866 { 865 {
867 // m_log.DebugFormat( 866// m_log.DebugFormat(
868 // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 867// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
869 // att.Name, sp.Name, AttachmentPt, itemID); 868// att.Name, sp.Name, AttachmentPt, itemID);
870 869
871 if (UUID.Zero == itemID) 870 if (UUID.Zero == itemID)
872 { 871 {
@@ -884,7 +883,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
884 item = m_scene.InventoryService.GetItem(item); 883 item = m_scene.InventoryService.GetItem(item);
885 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 884 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
886 if (changed && m_scene.AvatarFactory != null) 885 if (changed && m_scene.AvatarFactory != null)
886 {
887// m_log.DebugFormat(
888// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
889// sp.Name, att.Name, AttachmentPt);
890
887 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 891 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
892 }
888 } 893 }
889 894
890 #endregion 895 #endregion
@@ -929,9 +934,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
929 934
930 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) 935 private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
931 { 936 {
932 // m_log.DebugFormat( 937// m_log.DebugFormat(
933 // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", 938// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
934 // objectLocalID, remoteClient.Name, AttachmentPt, silent); 939// objectLocalID, remoteClient.Name, AttachmentPt, silent);
935 940
936 if (!Enabled) 941 if (!Enabled)
937 return; 942 return;
@@ -967,13 +972,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
967 // Calls attach with a Zero position 972 // Calls attach with a Zero position
968 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true)) 973 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true))
969 { 974 {
970 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); 975// m_log.Debug(
976// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
977// + ", AttachmentPoint: " + AttachmentPt);
971 978
972 // Save avatar attachment information 979 // Save avatar attachment information
973 m_log.Debug( 980 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
974 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
975 + ", AttachmentPoint: " + AttachmentPt);
976
977 } 981 }
978 } 982 }
979 catch (Exception e) 983 catch (Exception e)
@@ -989,8 +993,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
989 993
990 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 994 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
991 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); 995 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
996
992 if (sp != null && group != null) 997 if (sp != null && group != null)
993 DetachSingleAttachmentToInv(sp, group.FromItemID); 998 DetachSingleAttachmentToInv(sp, group);
994 } 999 }
995 1000
996 private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient) 1001 private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient)
@@ -1000,7 +1005,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1000 1005
1001 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1006 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
1002 if (sp != null) 1007 if (sp != null)
1003 DetachSingleAttachmentToInv(sp, itemID); 1008 {
1009 lock (sp.AttachmentsSyncLock)
1010 {
1011 List<SceneObjectGroup> attachments = sp.GetAttachments();
1012
1013 foreach (SceneObjectGroup group in attachments)
1014 {
1015 if (group.FromItemID == itemID)
1016 {
1017 DetachSingleAttachmentToInv(sp, group);
1018 return;
1019 }
1020 }
1021 }
1022 }
1004 } 1023 }
1005 1024
1006 private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient) 1025 private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient)