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.cs309
1 files changed, 165 insertions, 144 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 6323160..165dd17 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -256,12 +256,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
256 256
257// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); 257// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
258 258
259 List<SceneObjectGroup> attachments = sp.GetAttachments();
260
261 if (attachments.Count <= 0)
262 return;
263
264 Dictionary<SceneObjectGroup, string> scriptStates = new Dictionary<SceneObjectGroup, string>();
265
266 foreach (SceneObjectGroup so in attachments)
267 {
268 // Scripts MUST be snapshotted before the object is
269 // removed from the scene because doing otherwise will
270 // clobber the run flag
271 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
272 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
273 scriptStates[so] = PrepareScriptInstanceForSave(so, false);
274 }
275
259 lock (sp.AttachmentsSyncLock) 276 lock (sp.AttachmentsSyncLock)
260 { 277 {
261 foreach (SceneObjectGroup so in sp.GetAttachments()) 278 foreach (SceneObjectGroup so in attachments)
262 { 279 UpdateDetachedObject(sp, so, scriptStates[so]);
263 UpdateDetachedObject(sp, so);
264 }
265 280
266 sp.ClearAttachments(); 281 sp.ClearAttachments();
267 } 282 }
@@ -300,32 +315,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
300 315
301 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp) 316 private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool useAttachData, bool temp)
302 { 317 {
303 lock (sp.AttachmentsSyncLock)
304 {
305// m_log.DebugFormat( 318// m_log.DebugFormat(
306// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", 319// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
307// group.Name, group.LocalId, sp.Name, attachmentPt, silent); 320// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
308 321
309 if (group.GetSittingAvatarsCount() != 0) 322 if (group.GetSittingAvatarsCount() != 0)
310 { 323 {
311// m_log.WarnFormat( 324// m_log.WarnFormat(
312// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", 325// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
313// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); 326// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
314 327
315 return false; 328 return false;
316 } 329 }
317 330
318 if (sp.GetAttachments(attachmentPt).Contains(group)) 331 if (sp.GetAttachments(attachmentPt).Contains(group))
319 { 332 {
320 // m_log.WarnFormat( 333// m_log.WarnFormat(
321 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", 334// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
322 // group.Name, group.LocalId, sp.Name, AttachmentPt); 335// group.Name, group.LocalId, sp.Name, AttachmentPt);
323 336
324 return false; 337 return false;
325 } 338 }
326 339
340 // Remove any previous attachments
341 List<SceneObjectGroup> existingAttachments = sp.GetAttachments(attachmentPt);
342 string existingAttachmentScriptState = null;
343
344 // At the moment we can only deal with a single attachment
345 if (existingAttachments.Count != 0 && existingAttachments[0].FromItemID != UUID.Zero)
346 DetachSingleAttachmentToInv(sp, group);
347
348 lock (sp.AttachmentsSyncLock)
349 {
327 Vector3 attachPos = group.AbsolutePosition; 350 Vector3 attachPos = group.AbsolutePosition;
328 351
329 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 352 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
330 // be removed when that functionality is implemented in opensim 353 // be removed when that functionality is implemented in opensim
331 attachmentPt &= 0x7f; 354 attachmentPt &= 0x7f;
@@ -337,14 +360,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
337 { 360 {
338 attachPos = Vector3.Zero; 361 attachPos = Vector3.Zero;
339 } 362 }
340 363
341 // AttachmentPt 0 means the client chose to 'wear' the attachment. 364 // AttachmentPt 0 means the client chose to 'wear' the attachment.
342 if (attachmentPt == 0) 365 if (attachmentPt == 0)
343 { 366 {
344 // Check object for stored attachment point 367 // Check object for stored attachment point
345 attachmentPt = group.AttachmentPoint; 368 attachmentPt = group.AttachmentPoint;
346 } 369 }
347 370
348 // if we still didn't find a suitable attachment point....... 371 // if we still didn't find a suitable attachment point.......
349 if (attachmentPt == 0) 372 if (attachmentPt == 0)
350 { 373 {
@@ -376,7 +399,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
376 399
377 if (sp.PresenceType != PresenceType.Npc) 400 if (sp.PresenceType != PresenceType.Npc)
378 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp); 401 UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp);
379 402
380 AttachToAgent(sp, group, attachmentPt, attachPos, silent); 403 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
381 } 404 }
382 405
@@ -385,21 +408,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
385 408
386 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp) 409 private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool temp)
387 { 410 {
388 // Remove any previous attachments
389 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
390
391 // At the moment we can only deal with a single attachment
392 if (attachments.Count != 0)
393 {
394 if (attachments[0].FromItemID != UUID.Zero)
395 DetachSingleAttachmentToInvInternal(sp, attachments[0]);
396 // Error logging commented because UUID.Zero now means temp attachment
397// else
398// m_log.WarnFormat(
399// "[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!",
400// attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
401 }
402
403 // Add the new attachment to inventory if we don't already have it. 411 // Add the new attachment to inventory if we don't already have it.
404 if (!temp) 412 if (!temp)
405 { 413 {
@@ -464,12 +472,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
464 return; 472 return;
465 473
466 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); 474 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name);
467 lock (sp.AttachmentsSyncLock) 475
476 foreach (KeyValuePair<UUID, uint> rez in rezlist)
468 { 477 {
469 foreach (KeyValuePair<UUID, uint> rez in rezlist) 478 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
470 {
471 RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value);
472 }
473 } 479 }
474 } 480 }
475 481
@@ -549,25 +555,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
549 555
550 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) 556 public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
551 { 557 {
558 if (so.AttachedAvatar != sp.UUID)
559 {
560 m_log.WarnFormat(
561 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
562 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
563
564 return;
565 }
566
567 // Scripts MUST be snapshotted before the object is
568 // removed from the scene because doing otherwise will
569 // clobber the run flag
570 // This must be done outside the sp.AttachmentSyncLock so that there is no risk of a deadlock from
571 // scripts performing attachment operations at the same time. Getting object states stops the scripts.
572 string scriptedState = PrepareScriptInstanceForSave(so, true);
573
552 lock (sp.AttachmentsSyncLock) 574 lock (sp.AttachmentsSyncLock)
553 { 575 {
554 // Save avatar attachment information 576 // Save avatar attachment information
555// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); 577// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
556 578
557 if (so.AttachedAvatar != sp.UUID)
558 {
559 m_log.WarnFormat(
560 "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
561 so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
562
563 return;
564 }
565
566 bool changed = sp.Appearance.DetachAttachment(so.FromItemID); 579 bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
567 if (changed && m_scene.AvatarFactory != null) 580 if (changed && m_scene.AvatarFactory != null)
568 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); 581 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
569 582
570 DetachSingleAttachmentToInvInternal(sp, so); 583 sp.RemoveAttachment(so);
584 UpdateDetachedObject(sp, so, scriptedState);
571 } 585 }
572 } 586 }
573 587
@@ -777,8 +791,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
777 return newItem; 791 return newItem;
778 } 792 }
779 793
780 private string GetObjectScriptStates(SceneObjectGroup grp) 794 /// <summary>
795 /// Prepares the script instance for save.
796 /// </summary>
797 /// <remarks>
798 /// This involves triggering the detach event and getting the script state (which also stops the script)
799 /// This MUST be done outside sp.AttachmentsSyncLock, since otherwise there is a chance of deadlock if a
800 /// running script is performing attachment operations.
801 /// </remarks>
802 /// <returns>
803 /// The script state ready for persistence.
804 /// </returns>
805 /// <param name='grp'>
806 /// </param>
807 /// <param name='fireDetachEvent'>
808 /// If true, then fire the script event before we save its state.
809 /// </param>
810 private string PrepareScriptInstanceForSave(SceneObjectGroup grp, bool fireDetachEvent)
781 { 811 {
812 if (fireDetachEvent)
813 m_scene.EventManager.TriggerOnAttach(grp.LocalId, grp.FromItemID, UUID.Zero);
814
782 using (StringWriter sw = new StringWriter()) 815 using (StringWriter sw = new StringWriter())
783 { 816 {
784 using (XmlTextWriter writer = new XmlTextWriter(sw)) 817 using (XmlTextWriter writer = new XmlTextWriter(sw))
@@ -790,7 +823,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
790 } 823 }
791 } 824 }
792 825
793 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so) 826 private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so, string scriptedState)
794 { 827 {
795 // Don't save attachments for HG visitors, it 828 // Don't save attachments for HG visitors, it
796 // messes up their inventory. When a HG visitor logs 829 // messes up their inventory. When a HG visitor logs
@@ -803,11 +836,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
803 && (m_scene.UserManagementModule == null 836 && (m_scene.UserManagementModule == null
804 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID)); 837 || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
805 838
806 // Scripts MUST be snapshotted before the object is
807 // removed from the scene because doing otherwise will
808 // clobber the run flag
809 string scriptedState = GetObjectScriptStates(so);
810
811 // Remove the object from the scene so no more updates 839 // Remove the object from the scene so no more updates
812 // are sent. Doing this before the below changes will ensure 840 // are sent. Doing this before the below changes will ensure
813 // updates can't cause "HUD artefacts" 841 // updates can't cause "HUD artefacts"
@@ -831,97 +859,93 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
831 so.RemoveScriptInstances(true); 859 so.RemoveScriptInstances(true);
832 } 860 }
833 861
834 private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
835 {
836 // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
837
838 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
839 sp.RemoveAttachment(so);
840
841 UpdateDetachedObject(sp, so);
842 }
843
844 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 862 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
845 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) 863 IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc)
846 { 864 {
847 if (m_invAccessModule == null) 865 if (m_invAccessModule == null)
848 return null; 866 return null;
849 867
868 SceneObjectGroup objatt;
869
870 if (itemID != UUID.Zero)
871 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
872 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
873 false, false, sp.UUID, true);
874 else
875 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
876 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
877 false, false, sp.UUID, true);
878
879 if (objatt == null)
880 {
881 m_log.WarnFormat(
882 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
883 itemID, sp.Name, attachmentPt);
884
885 return null;
886 }
887
888 // Remove any previous attachments
889 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
890 string previousAttachmentScriptedState = null;
891
892 // At the moment we can only deal with a single attachment
893 if (attachments.Count != 0)
894 DetachSingleAttachmentToInv(sp, attachments[0]);
895
850 lock (sp.AttachmentsSyncLock) 896 lock (sp.AttachmentsSyncLock)
851 { 897 {
852 SceneObjectGroup objatt;
853
854 if (itemID != UUID.Zero)
855 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
856 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
857 false, false, sp.UUID, true);
858 else
859 objatt = m_invAccessModule.RezObject(sp.ControllingClient,
860 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
861 false, false, sp.UUID, true);
862
863 if (objatt != null)
864 {
865// m_log.DebugFormat( 898// m_log.DebugFormat(
866// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", 899// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
867// objatt.Name, sp.Name, attachmentPt, m_scene.Name); 900// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
868 901
869 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. 902 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
870 objatt.HasGroupChanged = false; 903 objatt.HasGroupChanged = false;
871 bool tainted = false; 904 bool tainted = false;
872 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) 905 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
873 tainted = true; 906 tainted = true;
874 907
875 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal 908 // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
876 // course of events. If not, then it's probably not worth trying to recover the situation 909 // course of events. If not, then it's probably not worth trying to recover the situation
877 // since this is more likely to trigger further exceptions and confuse later debugging. If 910 // since this is more likely to trigger further exceptions and confuse later debugging. If
878 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent 911 // exceptions can be thrown in expected error conditions (not NREs) then make this consistent
879 // since other normal error conditions will simply return false instead. 912 // since other normal error conditions will simply return false instead.
880 // This will throw if the attachment fails 913 // This will throw if the attachment fails
881 try 914 try
882 { 915 {
883 AttachObjectInternal(sp, objatt, attachmentPt, false, false, false); 916 AttachObjectInternal(sp, objatt, attachmentPt, false, false, false);
884 } 917 }
885 catch (Exception e) 918 catch (Exception e)
886 { 919 {
887 m_log.ErrorFormat( 920 m_log.ErrorFormat(
888 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", 921 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
889 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); 922 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
890
891 // Make sure the object doesn't stick around and bail
892 sp.RemoveAttachment(objatt);
893 m_scene.DeleteSceneObject(objatt, false);
894 return null;
895 }
896
897 if (tainted)
898 objatt.HasGroupChanged = true;
899
900 if (doc != null)
901 {
902 objatt.LoadScriptState(doc);
903 objatt.ResetOwnerChangeFlag();
904 }
905 923
906 // Fire after attach, so we don't get messy perms dialogs 924 // Make sure the object doesn't stick around and bail
907 // 4 == AttachedRez 925 sp.RemoveAttachment(objatt);
908 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); 926 m_scene.DeleteSceneObject(objatt, false);
909 objatt.ResumeScripts(); 927 return null;
928 }
910 929
911 // Do this last so that event listeners have access to all the effects of the attachment 930 if (tainted)
912 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 931 objatt.HasGroupChanged = true;
913 932
914 return objatt; 933 if (doc != null)
915 }
916 else
917 { 934 {
918 m_log.WarnFormat( 935 objatt.LoadScriptState(doc);
919 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", 936 objatt.ResetOwnerChangeFlag();
920 itemID, sp.Name, attachmentPt);
921 } 937 }
938
939 // Fire after attach, so we don't get messy perms dialogs
940 // 4 == AttachedRez
941 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
942 objatt.ResumeScripts();
943
944 // Do this last so that event listeners have access to all the effects of the attachment
945 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
946
947 return objatt;
922 } 948 }
923
924 return null;
925 } 949 }
926 950
927 /// <summary> 951 /// <summary>
@@ -1079,17 +1103,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
1079 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 1103 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
1080 if (sp != null) 1104 if (sp != null)
1081 { 1105 {
1082 lock (sp.AttachmentsSyncLock) 1106 List<SceneObjectGroup> attachments = sp.GetAttachments();
1107
1108 foreach (SceneObjectGroup group in attachments)
1083 { 1109 {
1084 List<SceneObjectGroup> attachments = sp.GetAttachments(); 1110 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero)
1085
1086 foreach (SceneObjectGroup group in attachments)
1087 { 1111 {
1088 if (group.FromItemID == itemID && group.FromItemID != UUID.Zero) 1112 DetachSingleAttachmentToInv(sp, group);
1089 { 1113 return;
1090 DetachSingleAttachmentToInv(sp, group);
1091 return;
1092 }
1093 } 1114 }
1094 } 1115 }
1095 } 1116 }