aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs306
1 files changed, 167 insertions, 139 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index ed4506c..ab7e932 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -241,12 +241,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
241 241
242// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); 242// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
243 243
244 List<SceneObjectGroup> attachments = sp.GetAttachments();
245
246 if (attachments.Count <= 0)
247 return;
248
249 Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>();
250
251 foreach (SceneObjectGroup so in attachments)
252 {
253 // Scripts MUST be snapshotted before the object is
254 // removed from the scene because doing otherwise will
255 // clobber the run flag
256 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
257 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
258 scriptStates[so] = PrepareScriptInstanceForSave(so, false);
259 }
260
244 lock (sp.AttachmentsSyncLock) 261 lock (sp.AttachmentsSyncLock)
245 { 262 {
246 foreach (SceneObjectGroup so in sp.GetAttachments()) 263 foreach (SceneObjectGroup so in attachments)
247 { 264 UpdateDetachedObject(sp, so, scriptStates[so]);
248 UpdateDetachedObject(sp, so);
249 }
250 265
251 sp.ClearAttachments(); 266 sp.ClearAttachments();
252 } 267 }
@@ -285,32 +300,50 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
285 300
286 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool append) 301 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool append)
287 { 302 {
288 lock (sp.AttachmentsSyncLock)
289 {
290// m_log.DebugFormat( 303// m_log.DebugFormat(
291// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 304// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
292// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 305// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
293 306
294 if (group.GetSittingAvatarsCount() != 0) 307 if (group.GetSittingAvatarsCount() != 0)
295 { 308 {
296// m_log.WarnFormat( 309// m_log.WarnFormat(
297// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", 310// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
298// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); 311// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
299 312
300 return false; 313 return false;
301 } 314 }
302 315
303 if (sp.GetAttachments(attachmentPt).Contains(group)) 316 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
317 if (attachments.Contains(group))
318 {
319// m_log.WarnFormat(
320// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
321// group.Name, group.LocalId, sp.Name, AttachmentPt);
322
323 return false;
324 }
325
326 // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
327 while (attachments.Count >= 5)
328 {
329 if (attachments[0].FromItemID != UUID.Zero)
330 DetachSingleAttachmentToInv(sp, attachments[0]);
331 attachments.RemoveAt(0);
332 }
333
334 // If we're not appending, remove the rest as well
335 if (attachments.Count != 0 && !append)
336 {
337 foreach (SceneObjectGroup g in attachments)
304 { 338 {
305 // m_log.WarnFormat( 339 if (g.FromItemID != UUID.Zero)
306 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", 340 DetachSingleAttachmentToInv(sp, g);
307 // group.Name, group.LocalId, sp.Name, AttachmentPt);
308
309 return false;
310 } 341 }
311 342 }
343
344 lock (sp.AttachmentsSyncLock)
345 {
312 Vector3 attachPos = group.AbsolutePosition; 346 Vector3 attachPos = group.AbsolutePosition;
313
314 // If the attachment point isn't the same as the one previously used 347 // If the attachment point isn't the same as the one previously used
315 // set it's offset position = 0 so that it appears on the attachment point 348 // set it's offset position = 0 so that it appears on the attachment point
316 // and not in a weird location somewhere unknown. 349 // and not in a weird location somewhere unknown.
@@ -318,14 +351,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
318 { 351 {
319 attachPos = Vector3.Zero; 352 attachPos = Vector3.Zero;
320 } 353 }
321 354
322 // AttachmentPt 0 means the client chose to 'wear' the attachment. 355 // AttachmentPt 0 means the client chose to 'wear' the attachment.
323 if (attachmentPt == 0) 356 if (attachmentPt == 0)
324 { 357 {
325 // Check object for stored attachment point 358 // Check object for stored attachment point
326 attachmentPt = group.AttachmentPoint; 359 attachmentPt = group.AttachmentPoint;
327 } 360 }
328 361
329 // if we still didn't find a suitable attachment point....... 362 // if we still didn't find a suitable attachment point.......
330 if (attachmentPt == 0) 363 if (attachmentPt == 0)
331 { 364 {
@@ -333,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
333 attachmentPt = (uint)AttachmentPoint.LeftHand; 366 attachmentPt = (uint)AttachmentPoint.LeftHand;
334 attachPos = Vector3.Zero; 367 attachPos = Vector3.Zero;
335 } 368 }
336 369
337 group.AttachmentPoint = attachmentPt; 370 group.AttachmentPoint = attachmentPt;
338 group.AbsolutePosition = attachPos; 371 group.AbsolutePosition = attachPos;
339 372
@@ -350,24 +383,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
350 { 383 {
351 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); 384 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
352 385
353 // If we already have 5, remove the oldest until only 4 are left. Skip over temp ones
354 while (attachments.Count >= 5)
355 {
356 if (attachments[0].FromItemID != UUID.Zero)
357 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
358 attachments.RemoveAt(0);
359 }
360
361 // If we're not appending, remove the rest as well
362 if (attachments.Count != 0 && !append)
363 {
364 foreach (SceneObjectGroup g in attachments)
365 {
366 if (g.FromItemID != UUID.Zero)
367 DetachSingleAttachmentToInvInternal(sp, g);
368 }
369 }
370
371 // Add the new attachment to inventory if we don't already have it. 386 // Add the new attachment to inventory if we don't already have it.
372 if (!temp) 387 if (!temp)
373 { 388 {
@@ -426,12 +441,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
426 return; 441 return;
427 442
428 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); 443 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name);
429 lock (sp.AttachmentsSyncLock) 444
445 foreach (KeyValuePair<UUID, uint> rez in rezlist)
430 { 446 {
431 foreach (KeyValuePair<UUID, uint> rez in rezlist) 447 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
432 {
433 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
434 }
435 } 448 }
436 } 449 }
437 450
@@ -511,25 +524,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
511 524
512 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) 525 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
513 { 526 {
527 if (so.AttachedAvatar != sp.UUID)
528 {
529 m_log.WarnFormat(
530 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
531 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
532
533 return;
534 }
535
536 // Scripts MUST be snapshotted before the object is
537 // removed from the scene because doing otherwise will
538 // clobber the run flag
539 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
540 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
541 string scriptedState = PrepareScriptInstanceForSave(so, true);
542
514 lock (sp.AttachmentsSyncLock) 543 lock (sp.AttachmentsSyncLock)
515 { 544 {
516 // Save avatar attachment information 545 // Save avatar attachment information
517// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 546// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
518 547
519 if (so.AttachedAvatar != sp.UUID)
520 {
521 m_log.WarnFormat(
522 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
523 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
524
525 return;
526 }
527
528 bool changed = sp.Appearance.DetachAttachment(so.FromItemID); 548 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
529 if (changed && m_scene.AvatarFactory != null) 549 if (changed && m_scene.AvatarFactory != null)
530 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 550 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
531 551
532 DetachSingleAttachmentToInvInternal(sp, so); 552 sp.RemoveAttachment(so);
553 UpdateDetachedObject(sp, so, scriptedState);
533 } 554 }
534 } 555 }
535 556
@@ -739,8 +760,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
739 return newItem; 760 return newItem;
740 } 761 }
741 762
742 private string GetObjectScriptStates(SceneObjectGroup grp) 763 /// <summary>
764 /// Prepares the script instance for save.
765 /// </summary>
766 /// <remarks>
767 /// This involves triggering the detach event and getting the script state (which also stops the script)
768 /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a
769 /// running script is performing attachment operations.
770 /// </remarks>
771 /// <returns>
772 /// The script state ready for persistence.
773 /// </returns>
774 /// <param name='grp'>
775 /// </param>
776 /// <param name='fireDetachEvent'>
777 /// If true, then fire the script event before we save its state.
778 /// </param>
779 private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent)
743 { 780 {
781 if (fireDetachEvent)
782 m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero);
783
744 using (StringWriter sw = new StringWriter()) 784 using (StringWriter sw = new StringWriter())
745 { 785 {
746 using (XmlTextWriter writer = new XmlTextWriter(sw)) 786 using (XmlTextWriter writer = new XmlTextWriter(sw))
@@ -752,7 +792,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
752 } 792 }
753 } 793 }
754 794
755 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) 795 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState)
756 { 796 {
757 // Don't save attachments for HG visitors, it 797 // Don't save attachments for HG visitors, it
758 // messes up their inventory. When a HG visitor logs 798 // messes up their inventory. When a HG visitor logs
@@ -765,11 +805,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
765 && (m_scene.UserManagementModule == null 805 && (m_scene.UserManagementModule == null
766 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); 806 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
767 807
768 // Scripts MUST be snapshotted before the object is
769 // removed from the scene because doing otherwise will
770 // clobber the run flag
771 string scriptedState = GetObjectScriptStates(so);
772
773 // Remove the object from the scene so no more updates 808 // Remove the object from the scene so no more updates
774 // are sent. Doing this before the below changes will ensure 809 // are sent. Doing this before the below changes will ensure
775 // updates can't cause "HUD artefacts" 810 // updates can't cause "HUD artefacts"
@@ -793,91 +828,87 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
793 so.RemoveScriptInstances(true); 828 so.RemoveScriptInstances(true);
794 } 829 }
795 830
796 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
797 {
798 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
799
800 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
801 sp.RemoveAttachment(so);
802
803 UpdateDetachedObject(sp, so);
804 }
805
806 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 831 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
807 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append) 832 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, bool append)
808 { 833 {
809 if (m_invAccessModule == null) 834 if (m_invAccessModule == null)
810 return null; 835 return null;
811 836
812 lock (sp.AttachmentsSyncLock) 837 SceneObjectGroup objatt;
838
839 if (itemID != UUID.Zero)
840 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
841 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
842 false, false, sp.UUID, true);
843 else
844 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
845 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
846 false, false, sp.UUID, true);
847
848 if (objatt == null)
813 { 849 {
814 SceneObjectGroup objatt; 850 m_log.WarnFormat(
851 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
852 itemID, sp.Name, attachmentPt);
815 853
816 if (itemID != UUID.Zero) 854 return null;
817 objatt = m_invAccessModule.RezObject(sp.ControllingClient, 855 }
818 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
819 false, false, sp.UUID, true);
820 else
821 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
822 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
823 false, false, sp.UUID, true);
824 856
825 if (objatt != null) 857 // Remove any previous attachments
826 { 858 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
859 string previousAttachmentScriptedState = null;
860
861 // At the moment we can only deal with a single attachment
862 if (attachments.Count != 0)
863 DetachSingleAttachmentToInv(sp, attachments[0]);
864
865 lock (sp.AttachmentsSyncLock)
866 {
827// m_log.DebugFormat( 867// m_log.DebugFormat(
828// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", 868// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
829// objatt.Name, sp.Name, attachmentPt, m_scene.Name); 869// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
830 870
831 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. 871 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
832 objatt.HasGroupChanged = false; 872 objatt.HasGroupChanged = false;
833 bool tainted = false; 873 bool tainted = false;
834 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) 874 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
835 tainted = true; 875 tainted = true;
836 876
837 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal 877 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
838 // course of events. If not, then it's probably not worth trying to recover the situation 878 // course of events. If not, then it's probably not worth trying to recover the situation
839 // since this is more likely to trigger further exceptions and confuse later debugging. If 879 // since this is more likely to trigger further exceptions and confuse later debugging. If
840 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent 880 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
841 // since other normal error conditions will simply return false instead. 881 // since other normal error conditions will simply return false instead.
842 // This will throw if the attachment fails 882 // This will throw if the attachment fails
843 try 883 try
844 { 884 {
845 AttachObjectInternal(sp, objatt, attachmentPt, false, false, append); 885 AttachObjectInternal(sp, objatt, attachmentPt, false, false, append);
846 } 886 }
847 catch (Exception e) 887 catch (Exception e)
848 { 888 {
849 m_log.ErrorFormat( 889 m_log.ErrorFormat(
850 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", 890 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
851 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); 891 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
852
853 // Make sure the object doesn't stick around and bail
854 sp.RemoveAttachment(objatt);
855 m_scene.DeleteSceneObject(objatt, false);
856 return null;
857 }
858 892
859 if (tainted) 893 // Make sure the object doesn't stick around and bail
860 objatt.HasGroupChanged = true; 894 sp.RemoveAttachment(objatt);
895 m_scene.DeleteSceneObject(objatt, false);
896 return null;
897 }
861 898
862 // Fire after attach, so we don't get messy perms dialogs 899 if (tainted)
863 // 4 == AttachedRez 900 objatt.HasGroupChanged = true;
864 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
865 objatt.ResumeScripts();
866 901
867 // Do this last so that event listeners have access to all the effects of the attachment 902 // Fire after attach, so we don't get messy perms dialogs
868 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 903 // 4 == AttachedRez
904 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
905 objatt.ResumeScripts();
869 906
870 return objatt; 907 // Do this last so that event listeners have access to all the effects of the attachment
871 } 908 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
872 else
873 {
874 m_log.WarnFormat(
875 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
876 itemID, sp.Name, attachmentPt);
877 }
878 }
879 909
880 return null; 910 return objatt;
911 }
881 } 912 }
882 913
883 /// <summary> 914 /// <summary>
@@ -1035,17 +1066,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1035 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1066 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
1036 if (sp != null) 1067 if (sp != null)
1037 { 1068 {
1038 lock (sp.AttachmentsSyncLock) 1069 List<SceneObjectGroup> attachments = sp.GetAttachments();
1070
1071 foreach (SceneObjectGroup group in attachments)
1039 { 1072 {
1040 List<SceneObjectGroup> attachments = sp.GetAttachments(); 1073 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
1041
1042 foreach (SceneObjectGroup group in attachments)
1043 { 1074 {
1044 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) 1075 DetachSingleAttachmentToInv(sp, group);
1045 { 1076 return;
1046 DetachSingleAttachmentToInv(sp, group);
1047 return;
1048 }
1049 } 1077 }
1050 } 1078 }
1051 } 1079 }