diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 734 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 2 |
2 files changed, 375 insertions, 361 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 78b9afc..f893eb3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -44,6 +44,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] | 44 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] |
45 | public class AttachmentsModule : IAttachmentsModule, INonSharedRegionModule | 45 | public class AttachmentsModule : IAttachmentsModule, INonSharedRegionModule |
46 | { | 46 | { |
47 | #region INonSharedRegionModule | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | 49 | ||
49 | private Scene m_scene; | 50 | private Scene m_scene; |
@@ -92,26 +93,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
92 | { | 93 | { |
93 | RemoveRegion(m_scene); | 94 | RemoveRegion(m_scene); |
94 | } | 95 | } |
95 | 96 | ||
96 | public void SubscribeToClientEvents(IClientAPI client) | 97 | #endregion |
97 | { | 98 | |
98 | client.OnRezSingleAttachmentFromInv += RezSingleAttachmentFromInventory; | 99 | #region IAttachmentsModule |
99 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; | ||
100 | client.OnObjectAttach += AttachObject; | ||
101 | client.OnObjectDetach += DetachObject; | ||
102 | client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv; | ||
103 | client.OnObjectDrop += DetachSingleAttachmentToGround; | ||
104 | } | ||
105 | |||
106 | public void UnsubscribeFromClientEvents(IClientAPI client) | ||
107 | { | ||
108 | client.OnRezSingleAttachmentFromInv -= RezSingleAttachmentFromInventory; | ||
109 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; | ||
110 | client.OnObjectAttach -= AttachObject; | ||
111 | client.OnObjectDetach -= DetachObject; | ||
112 | client.OnDetachAttachmentIntoInv -= DetachSingleAttachmentToInv; | ||
113 | client.OnObjectDrop -= DetachSingleAttachmentToGround; | ||
114 | } | ||
115 | 100 | ||
116 | /// <summary> | 101 | /// <summary> |
117 | /// RezAttachments. This should only be called upon login on the first region. | 102 | /// RezAttachments. This should only be called upon login on the first region. |
@@ -174,7 +159,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
174 | // { | 159 | // { |
175 | grp.IsAttachment = false; | 160 | grp.IsAttachment = false; |
176 | grp.AbsolutePosition = grp.RootPart.AttachedPos; | 161 | grp.AbsolutePosition = grp.RootPart.AttachedPos; |
177 | UpdateKnownItem(sp.ControllingClient, grp); | 162 | UpdateKnownItem(sp, grp); |
178 | grp.IsAttachment = true; | 163 | grp.IsAttachment = true; |
179 | // } | 164 | // } |
180 | } | 165 | } |
@@ -197,68 +182,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
197 | sp.ClearAttachments(); | 182 | sp.ClearAttachments(); |
198 | } | 183 | } |
199 | 184 | ||
200 | /// <summary> | ||
201 | /// Called by client | ||
202 | /// </summary> | ||
203 | /// <param name="remoteClient"></param> | ||
204 | /// <param name="objectLocalID"></param> | ||
205 | /// <param name="AttachmentPt"></param> | ||
206 | /// <param name="silent"></param> | ||
207 | private void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) | ||
208 | { | ||
209 | // m_log.DebugFormat( | ||
210 | // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", | ||
211 | // objectLocalID, remoteClient.Name, AttachmentPt, silent); | ||
212 | |||
213 | if (!Enabled) | ||
214 | return; | ||
215 | |||
216 | try | ||
217 | { | ||
218 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
219 | |||
220 | if (sp == null) | ||
221 | { | ||
222 | m_log.ErrorFormat( | ||
223 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | // If we can't take it, we can't attach it! | ||
228 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); | ||
229 | if (part == null) | ||
230 | return; | ||
231 | |||
232 | if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) | ||
233 | { | ||
234 | remoteClient.SendAgentAlertMessage( | ||
235 | "You don't have sufficient permissions to attach this object", false); | ||
236 | |||
237 | return; | ||
238 | } | ||
239 | |||
240 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | ||
241 | // be removed when that functionality is implemented in opensim | ||
242 | AttachmentPt &= 0x7f; | ||
243 | |||
244 | // Calls attach with a Zero position | ||
245 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) | ||
246 | { | ||
247 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | ||
248 | |||
249 | // Save avatar attachment information | ||
250 | m_log.Debug( | ||
251 | "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | ||
252 | + ", AttachmentPoint: " + AttachmentPt); | ||
253 | |||
254 | } | ||
255 | } | ||
256 | catch (Exception e) | ||
257 | { | ||
258 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) | 185 | public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) |
263 | { | 186 | { |
264 | lock (sp.AttachmentsSyncLock) | 187 | lock (sp.AttachmentsSyncLock) |
@@ -320,7 +243,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
320 | UUID oldAttachmentItemID = attachments[0].GetFromItemID(); | 243 | UUID oldAttachmentItemID = attachments[0].GetFromItemID(); |
321 | 244 | ||
322 | if (oldAttachmentItemID != UUID.Zero) | 245 | if (oldAttachmentItemID != UUID.Zero) |
323 | DetachSingleAttachmentToInv(oldAttachmentItemID, sp); | 246 | DetachSingleAttachmentToInvInternal(sp, oldAttachmentItemID); |
324 | else | 247 | else |
325 | m_log.WarnFormat( | 248 | m_log.WarnFormat( |
326 | "[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!", | 249 | "[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!", |
@@ -330,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
330 | // Add the new attachment to inventory if we don't already have it. | 253 | // Add the new attachment to inventory if we don't already have it. |
331 | UUID newAttachmentItemID = group.GetFromItemID(); | 254 | UUID newAttachmentItemID = group.GetFromItemID(); |
332 | if (newAttachmentItemID == UUID.Zero) | 255 | if (newAttachmentItemID == UUID.Zero) |
333 | newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; | 256 | newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; |
334 | 257 | ||
335 | ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); | 258 | ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); |
336 | } | 259 | } |
@@ -339,58 +262,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
339 | } | 262 | } |
340 | 263 | ||
341 | return true; | 264 | return true; |
342 | } | ||
343 | |||
344 | private void RezMultipleAttachmentsFromInventory(IClientAPI remoteClient, List<KeyValuePair<UUID, uint>> rezlist) | ||
345 | { | ||
346 | if (!Enabled) | ||
347 | return; | ||
348 | |||
349 | ScenePresence sp; | ||
350 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) | ||
351 | RezMultipleAttachmentsFromInventory(sp, rezlist); | ||
352 | else | ||
353 | m_log.ErrorFormat( | ||
354 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", | ||
355 | remoteClient.Name, remoteClient.AgentId); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) | ||
360 | { | ||
361 | if (!Enabled) | ||
362 | return; | ||
363 | |||
364 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); | ||
365 | lock (sp.AttachmentsSyncLock) | ||
366 | { | ||
367 | foreach (KeyValuePair<UUID, uint> rez in rezlist) | ||
368 | { | ||
369 | RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | private ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
375 | { | ||
376 | if (!Enabled) | ||
377 | return null; | ||
378 | |||
379 | // m_log.DebugFormat( | ||
380 | // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", | ||
381 | // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); | ||
382 | |||
383 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
384 | |||
385 | if (sp == null) | ||
386 | { | ||
387 | m_log.ErrorFormat( | ||
388 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", | ||
389 | remoteClient.Name, remoteClient.AgentId); | ||
390 | return null; | ||
391 | } | ||
392 | |||
393 | return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); | ||
394 | } | 265 | } |
395 | 266 | ||
396 | public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) | 267 | public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) |
@@ -435,159 +306,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
435 | SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); | 306 | SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); |
436 | 307 | ||
437 | if (att == null) | 308 | if (att == null) |
438 | DetachSingleAttachmentToInv(itemID, sp.ControllingClient); | 309 | DetachSingleAttachmentToInv(sp, itemID); |
439 | 310 | ||
440 | return att; | 311 | return att; |
441 | } | 312 | } |
442 | 313 | ||
443 | private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | 314 | public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist) |
444 | IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) | ||
445 | { | ||
446 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
447 | if (invAccess != null) | ||
448 | { | ||
449 | lock (sp.AttachmentsSyncLock) | ||
450 | { | ||
451 | SceneObjectGroup objatt; | ||
452 | |||
453 | if (itemID != UUID.Zero) | ||
454 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
455 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
456 | false, false, sp.UUID, true); | ||
457 | else | ||
458 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
459 | null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
460 | false, false, sp.UUID, true); | ||
461 | |||
462 | // m_log.DebugFormat( | ||
463 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", | ||
464 | // objatt.Name, remoteClient.Name, AttachmentPt); | ||
465 | |||
466 | if (objatt != null) | ||
467 | { | ||
468 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. | ||
469 | objatt.HasGroupChanged = false; | ||
470 | bool tainted = false; | ||
471 | if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) | ||
472 | tainted = true; | ||
473 | |||
474 | // This will throw if the attachment fails | ||
475 | try | ||
476 | { | ||
477 | AttachObject(sp, objatt, attachmentPt, false); | ||
478 | } | ||
479 | catch (Exception e) | ||
480 | { | ||
481 | m_log.ErrorFormat( | ||
482 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
483 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
484 | |||
485 | // Make sure the object doesn't stick around and bail | ||
486 | sp.RemoveAttachment(objatt); | ||
487 | m_scene.DeleteSceneObject(objatt, false); | ||
488 | return null; | ||
489 | } | ||
490 | |||
491 | if (tainted) | ||
492 | objatt.HasGroupChanged = true; | ||
493 | |||
494 | // Fire after attach, so we don't get messy perms dialogs | ||
495 | // 4 == AttachedRez | ||
496 | objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); | ||
497 | objatt.ResumeScripts(); | ||
498 | |||
499 | // Do this last so that event listeners have access to all the effects of the attachment | ||
500 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); | ||
501 | |||
502 | return objatt; | ||
503 | } | ||
504 | else | ||
505 | { | ||
506 | m_log.WarnFormat( | ||
507 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
508 | itemID, sp.Name, attachmentPt); | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | return null; | ||
514 | } | ||
515 | |||
516 | /// <summary> | ||
517 | /// Update the user inventory to reflect an attachment | ||
518 | /// </summary> | ||
519 | /// <param name="sp"></param> | ||
520 | /// <param name="AttachmentPt"></param> | ||
521 | /// <param name="itemID"></param> | ||
522 | /// <param name="att"></param> | ||
523 | private void ShowAttachInUserInventory( | ||
524 | IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) | ||
525 | { | ||
526 | // m_log.DebugFormat( | ||
527 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", | ||
528 | // att.Name, sp.Name, AttachmentPt, itemID); | ||
529 | |||
530 | if (UUID.Zero == itemID) | ||
531 | { | ||
532 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | if (0 == AttachmentPt) | ||
537 | { | ||
538 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point."); | ||
539 | return; | ||
540 | } | ||
541 | |||
542 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); | ||
543 | item = m_scene.InventoryService.GetItem(item); | ||
544 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | ||
545 | if (changed && m_scene.AvatarFactory != null) | ||
546 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | ||
547 | } | ||
548 | |||
549 | public void DetachObject(uint objectLocalID, IClientAPI remoteClient) | ||
550 | { | ||
551 | // m_log.DebugFormat( | ||
552 | // "[ATTACHMENTS MODULE]: DetachObject() for object {0} on {1}", objectLocalID, remoteClient.Name); | ||
553 | |||
554 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); | ||
555 | if (group != null) | ||
556 | { | ||
557 | DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) | ||
562 | { | 315 | { |
563 | if (!Enabled) | 316 | if (!Enabled) |
564 | return; | 317 | return; |
565 | 318 | ||
566 | ScenePresence presence; | 319 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); |
567 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 320 | lock (sp.AttachmentsSyncLock) |
568 | { | 321 | { |
569 | lock (presence.AttachmentsSyncLock) | 322 | foreach (KeyValuePair<UUID, uint> rez in rezlist) |
570 | { | 323 | { |
571 | // Save avatar attachment information | 324 | RezSingleAttachmentFromInventory(sp, rez.Key, rez.Value); |
572 | m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); | ||
573 | |||
574 | bool changed = presence.Appearance.DetachAttachment(itemID); | ||
575 | if (changed && m_scene.AvatarFactory != null) | ||
576 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | ||
577 | |||
578 | DetachSingleAttachmentToInv(itemID, presence); | ||
579 | } | 325 | } |
580 | } | 326 | } |
581 | } | ||
582 | |||
583 | private void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient) | ||
584 | { | ||
585 | if (!Enabled) | ||
586 | return; | ||
587 | |||
588 | ScenePresence sp; | ||
589 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out sp)) | ||
590 | DetachSingleAttachmentToGround(sp, soLocalId); | ||
591 | } | 327 | } |
592 | 328 | ||
593 | public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) | 329 | public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId) |
@@ -617,27 +353,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
617 | { | 353 | { |
618 | if (!m_scene.Permissions.CanRezObject( | 354 | if (!m_scene.Permissions.CanRezObject( |
619 | so.PrimCount, sp.UUID, sp.AbsolutePosition)) | 355 | so.PrimCount, sp.UUID, sp.AbsolutePosition)) |
620 | return; | 356 | return; |
621 | 357 | ||
622 | bool changed = sp.Appearance.DetachAttachment(inventoryID); | 358 | bool changed = sp.Appearance.DetachAttachment(inventoryID); |
623 | if (changed && m_scene.AvatarFactory != null) | 359 | if (changed && m_scene.AvatarFactory != null) |
624 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | 360 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
625 | 361 | ||
626 | sp.RemoveAttachment(so); | 362 | sp.RemoveAttachment(so); |
627 | 363 | ||
628 | SceneObjectPart rootPart = so.RootPart; | 364 | SceneObjectPart rootPart = so.RootPart; |
629 | rootPart.FromItemID = UUID.Zero; | 365 | rootPart.FromItemID = UUID.Zero; |
630 | so.AbsolutePosition = sp.AbsolutePosition; | 366 | so.AbsolutePosition = sp.AbsolutePosition; |
631 | so.AttachedAvatar = UUID.Zero; | 367 | so.AttachedAvatar = UUID.Zero; |
632 | rootPart.SetParentLocalId(0); | 368 | rootPart.SetParentLocalId(0); |
633 | so.ClearPartAttachmentData(); | 369 | so.ClearPartAttachmentData(); |
634 | rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); | 370 | rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); |
635 | so.HasGroupChanged = true; | 371 | so.HasGroupChanged = true; |
636 | rootPart.Rezzed = DateTime.Now; | 372 | rootPart.Rezzed = DateTime.Now; |
637 | rootPart.RemFlag(PrimFlags.TemporaryOnRez); | 373 | rootPart.RemFlag(PrimFlags.TemporaryOnRez); |
638 | so.AttachToBackup(); | 374 | so.AttachToBackup(); |
639 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 375 | m_scene.EventManager.TriggerParcelPrimCountTainted(); |
640 | rootPart.ScheduleFullUpdate(); | 376 | rootPart.ScheduleFullUpdate(); |
641 | rootPart.ClearUndoState(); | 377 | rootPart.ClearUndoState(); |
642 | 378 | ||
643 | List<UUID> uuids = new List<UUID>(); | 379 | List<UUID> uuids = new List<UUID>(); |
@@ -648,46 +384,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
648 | 384 | ||
649 | m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); | 385 | m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); |
650 | } | 386 | } |
651 | |||
652 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | ||
653 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | ||
654 | private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp) | ||
655 | { | ||
656 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); | ||
657 | |||
658 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... | ||
659 | return; | ||
660 | |||
661 | // We can NOT use the dictionries here, as we are looking | ||
662 | // for an entity by the fromAssetID, which is NOT the prim UUID | ||
663 | EntityBase[] detachEntities = m_scene.GetEntities(); | ||
664 | SceneObjectGroup group; | ||
665 | 387 | ||
388 | public void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID) | ||
389 | { | ||
666 | lock (sp.AttachmentsSyncLock) | 390 | lock (sp.AttachmentsSyncLock) |
667 | { | 391 | { |
668 | foreach (EntityBase entity in detachEntities) | 392 | // Save avatar attachment information |
669 | { | 393 | m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); |
670 | if (entity is SceneObjectGroup) | ||
671 | { | ||
672 | group = (SceneObjectGroup)entity; | ||
673 | if (group.GetFromItemID() == itemID) | ||
674 | { | ||
675 | m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); | ||
676 | sp.RemoveAttachment(group); | ||
677 | |||
678 | // Prepare sog for storage | ||
679 | group.AttachedAvatar = UUID.Zero; | ||
680 | group.RootPart.SetParentLocalId(0); | ||
681 | group.IsAttachment = false; | ||
682 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
683 | 394 | ||
684 | UpdateKnownItem(sp.ControllingClient, group); | 395 | bool changed = sp.Appearance.DetachAttachment(itemID); |
685 | m_scene.DeleteSceneObject(group, false); | 396 | if (changed && m_scene.AvatarFactory != null) |
397 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | ||
686 | 398 | ||
687 | return; | 399 | DetachSingleAttachmentToInvInternal(sp, itemID); |
688 | } | ||
689 | } | ||
690 | } | ||
691 | } | 400 | } |
692 | } | 401 | } |
693 | 402 | ||
@@ -709,7 +418,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
709 | sog.AttachmentPoint = attachmentPoint; | 418 | sog.AttachmentPoint = attachmentPoint; |
710 | sog.HasGroupChanged = true; | 419 | sog.HasGroupChanged = true; |
711 | } | 420 | } |
712 | 421 | ||
422 | #endregion | ||
423 | |||
424 | #region AttachmentModule private methods | ||
425 | |||
426 | // This is public but is not part of the IAttachmentsModule interface. | ||
427 | // RegionCombiner module needs to poke at it to deliver client events. | ||
428 | // This breaks the encapsulation of the module and should get fixed somehow. | ||
429 | public void SubscribeToClientEvents(IClientAPI client) | ||
430 | { | ||
431 | client.OnRezSingleAttachmentFromInv += Client_OnRezSingleAttachmentFromInv; | ||
432 | client.OnRezMultipleAttachmentsFromInv += Client_OnRezMultipleAttachmentsFromInv; | ||
433 | client.OnObjectAttach += Client_OnObjectAttach; | ||
434 | client.OnObjectDetach += Client_OnObjectDetach; | ||
435 | client.OnDetachAttachmentIntoInv += Client_OnDetachAttachmentIntoInv; | ||
436 | client.OnObjectDrop += Client_OnObjectDrop; | ||
437 | } | ||
438 | |||
439 | // This is public but is not part of the IAttachmentsModule interface. | ||
440 | // RegionCombiner module needs to poke at it to deliver client events. | ||
441 | // This breaks the encapsulation of the module and should get fixed somehow. | ||
442 | public void UnsubscribeFromClientEvents(IClientAPI client) | ||
443 | { | ||
444 | client.OnRezSingleAttachmentFromInv -= Client_OnRezSingleAttachmentFromInv; | ||
445 | client.OnRezMultipleAttachmentsFromInv -= Client_OnRezMultipleAttachmentsFromInv; | ||
446 | client.OnObjectAttach -= Client_OnObjectAttach; | ||
447 | client.OnObjectDetach -= Client_OnObjectDetach; | ||
448 | client.OnDetachAttachmentIntoInv -= Client_OnDetachAttachmentIntoInv; | ||
449 | client.OnObjectDrop -= Client_OnObjectDrop; | ||
450 | } | ||
451 | |||
713 | /// <summary> | 452 | /// <summary> |
714 | /// Update the attachment asset for the new sog details if they have changed. | 453 | /// Update the attachment asset for the new sog details if they have changed. |
715 | /// </summary> | 454 | /// </summary> |
@@ -717,9 +456,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
717 | /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, | 456 | /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, |
718 | /// these details are not stored on the region. | 457 | /// these details are not stored on the region. |
719 | /// </remarks> | 458 | /// </remarks> |
720 | /// <param name="remoteClient"></param> | 459 | /// <param name="sp"></param> |
721 | /// <param name="grp"></param> | 460 | /// <param name="grp"></param> |
722 | private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp) | 461 | private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp) |
723 | { | 462 | { |
724 | if (grp.HasGroupChanged || grp.ContainsScripts()) | 463 | if (grp.HasGroupChanged || grp.ContainsScripts()) |
725 | { | 464 | { |
@@ -729,7 +468,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
729 | 468 | ||
730 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); | 469 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); |
731 | 470 | ||
732 | InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), remoteClient.AgentId); | 471 | InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), sp.UUID); |
733 | item = m_scene.InventoryService.GetItem(item); | 472 | item = m_scene.InventoryService.GetItem(item); |
734 | 473 | ||
735 | if (item != null) | 474 | if (item != null) |
@@ -739,7 +478,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
739 | grp.GetPartDescription(grp.LocalId), | 478 | grp.GetPartDescription(grp.LocalId), |
740 | (sbyte)AssetType.Object, | 479 | (sbyte)AssetType.Object, |
741 | Utils.StringToBytes(sceneObjectXml), | 480 | Utils.StringToBytes(sceneObjectXml), |
742 | remoteClient.AgentId); | 481 | sp.UUID); |
743 | m_scene.AssetService.Store(asset); | 482 | m_scene.AssetService.Store(asset); |
744 | 483 | ||
745 | item.AssetID = asset.FullID; | 484 | item.AssetID = asset.FullID; |
@@ -751,8 +490,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
751 | m_scene.InventoryService.UpdateItem(item); | 490 | m_scene.InventoryService.UpdateItem(item); |
752 | 491 | ||
753 | // this gets called when the agent logs off! | 492 | // this gets called when the agent logs off! |
754 | if (remoteClient != null) | 493 | if (sp.ControllingClient != null) |
755 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | 494 | sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); |
756 | } | 495 | } |
757 | } | 496 | } |
758 | else | 497 | else |
@@ -761,8 +500,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
761 | "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", | 500 | "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", |
762 | grp.UUID, grp.AttachmentPoint); | 501 | grp.UUID, grp.AttachmentPoint); |
763 | } | 502 | } |
764 | } | 503 | } |
765 | 504 | ||
766 | /// <summary> | 505 | /// <summary> |
767 | /// Attach this scene object to the given avatar. | 506 | /// Attach this scene object to the given avatar. |
768 | /// </summary> | 507 | /// </summary> |
@@ -776,19 +515,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
776 | /// <param name="attachOffset"></param> | 515 | /// <param name="attachOffset"></param> |
777 | /// <param name="silent"></param> | 516 | /// <param name="silent"></param> |
778 | private void AttachToAgent( | 517 | private void AttachToAgent( |
779 | IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) | 518 | IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) |
780 | { | 519 | { |
781 | // m_log.DebugFormat( | 520 | // m_log.DebugFormat( |
782 | // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", | 521 | // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", |
783 | // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); | 522 | // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); |
784 | 523 | ||
785 | so.DetachFromBackup(); | 524 | so.DetachFromBackup(); |
786 | 525 | ||
787 | // Remove from database and parcel prim count | 526 | // Remove from database and parcel prim count |
788 | m_scene.DeleteFromStorage(so.UUID); | 527 | m_scene.DeleteFromStorage(so.UUID); |
789 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 528 | m_scene.EventManager.TriggerParcelPrimCountTainted(); |
790 | 529 | ||
791 | so.AttachedAvatar = avatar.UUID; | 530 | so.AttachedAvatar = sp.UUID; |
792 | 531 | ||
793 | if (so.RootPart.PhysActor != null) | 532 | if (so.RootPart.PhysActor != null) |
794 | { | 533 | { |
@@ -799,10 +538,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
799 | so.AbsolutePosition = attachOffset; | 538 | so.AbsolutePosition = attachOffset; |
800 | so.RootPart.AttachedPos = attachOffset; | 539 | so.RootPart.AttachedPos = attachOffset; |
801 | so.IsAttachment = true; | 540 | so.IsAttachment = true; |
802 | so.RootPart.SetParentLocalId(avatar.LocalId); | 541 | so.RootPart.SetParentLocalId(sp.LocalId); |
803 | so.AttachmentPoint = attachmentpoint; | 542 | so.AttachmentPoint = attachmentpoint; |
804 | 543 | ||
805 | avatar.AddAttachment(so); | 544 | sp.AddAttachment(so); |
806 | 545 | ||
807 | if (!silent) | 546 | if (!silent) |
808 | { | 547 | { |
@@ -818,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
818 | so.IsSelected = false; // fudge.... | 557 | so.IsSelected = false; // fudge.... |
819 | so.ScheduleGroupForFullUpdate(); | 558 | so.ScheduleGroupForFullUpdate(); |
820 | } | 559 | } |
821 | 560 | ||
822 | // In case it is later dropped again, don't let | 561 | // In case it is later dropped again, don't let |
823 | // it get cleaned up | 562 | // it get cleaned up |
824 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); | 563 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); |
@@ -830,11 +569,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
830 | /// <param name="remoteClient"></param> | 569 | /// <param name="remoteClient"></param> |
831 | /// <param name="grp"></param> | 570 | /// <param name="grp"></param> |
832 | /// <returns>The user inventory item created that holds the attachment.</returns> | 571 | /// <returns>The user inventory item created that holds the attachment.</returns> |
833 | private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IClientAPI remoteClient, SceneObjectGroup grp) | 572 | private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) |
834 | { | 573 | { |
835 | // m_log.DebugFormat( | 574 | // m_log.DebugFormat( |
836 | // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", | 575 | // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", |
837 | // grp.Name, grp.LocalId, remoteClient.Name); | 576 | // grp.Name, grp.LocalId, remoteClient.Name); |
838 | 577 | ||
839 | Vector3 inventoryStoredPosition = new Vector3 | 578 | Vector3 inventoryStoredPosition = new Vector3 |
840 | (((grp.AbsolutePosition.X > (int)Constants.RegionSize) | 579 | (((grp.AbsolutePosition.X > (int)Constants.RegionSize) |
@@ -863,14 +602,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
863 | grp.GetPartDescription(grp.LocalId), | 602 | grp.GetPartDescription(grp.LocalId), |
864 | (sbyte)AssetType.Object, | 603 | (sbyte)AssetType.Object, |
865 | Utils.StringToBytes(sceneObjectXml), | 604 | Utils.StringToBytes(sceneObjectXml), |
866 | remoteClient.AgentId); | 605 | sp.UUID); |
867 | 606 | ||
868 | m_scene.AssetService.Store(asset); | 607 | m_scene.AssetService.Store(asset); |
869 | 608 | ||
870 | InventoryItemBase item = new InventoryItemBase(); | 609 | InventoryItemBase item = new InventoryItemBase(); |
871 | item.CreatorId = grp.RootPart.CreatorID.ToString(); | 610 | item.CreatorId = grp.RootPart.CreatorID.ToString(); |
872 | item.CreatorData = grp.RootPart.CreatorData; | 611 | item.CreatorData = grp.RootPart.CreatorData; |
873 | item.Owner = remoteClient.AgentId; | 612 | item.Owner = sp.UUID; |
874 | item.ID = UUID.Random(); | 613 | item.ID = UUID.Random(); |
875 | item.AssetID = asset.FullID; | 614 | item.AssetID = asset.FullID; |
876 | item.Description = asset.Description; | 615 | item.Description = asset.Description; |
@@ -878,13 +617,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
878 | item.AssetType = asset.Type; | 617 | item.AssetType = asset.Type; |
879 | item.InvType = (int)InventoryType.Object; | 618 | item.InvType = (int)InventoryType.Object; |
880 | 619 | ||
881 | InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object); | 620 | InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); |
882 | if (folder != null) | 621 | if (folder != null) |
883 | item.Folder = folder.ID; | 622 | item.Folder = folder.ID; |
884 | else // oopsies | 623 | else // oopsies |
885 | item.Folder = UUID.Zero; | 624 | item.Folder = UUID.Zero; |
886 | 625 | ||
887 | if ((remoteClient.AgentId != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) | 626 | if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) |
888 | { | 627 | { |
889 | item.BasePermissions = grp.RootPart.NextOwnerMask; | 628 | item.BasePermissions = grp.RootPart.NextOwnerMask; |
890 | item.CurrentPermissions = grp.RootPart.NextOwnerMask; | 629 | item.CurrentPermissions = grp.RootPart.NextOwnerMask; |
@@ -907,15 +646,290 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
907 | 646 | ||
908 | if (m_scene.AddInventoryItem(item)) | 647 | if (m_scene.AddInventoryItem(item)) |
909 | { | 648 | { |
910 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | 649 | sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); |
911 | } | 650 | } |
912 | else | 651 | else |
913 | { | 652 | { |
914 | if (m_dialogModule != null) | 653 | if (m_dialogModule != null) |
915 | m_dialogModule.SendAlertToUser(remoteClient, "Operation failed"); | 654 | m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed"); |
916 | } | 655 | } |
917 | 656 | ||
918 | return item; | 657 | return item; |
919 | } | 658 | } |
659 | |||
660 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | ||
661 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | ||
662 | private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID) | ||
663 | { | ||
664 | // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); | ||
665 | |||
666 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... | ||
667 | return; | ||
668 | |||
669 | // We can NOT use the dictionries here, as we are looking | ||
670 | // for an entity by the fromAssetID, which is NOT the prim UUID | ||
671 | EntityBase[] detachEntities = m_scene.GetEntities(); | ||
672 | SceneObjectGroup group; | ||
673 | |||
674 | lock (sp.AttachmentsSyncLock) | ||
675 | { | ||
676 | foreach (EntityBase entity in detachEntities) | ||
677 | { | ||
678 | if (entity is SceneObjectGroup) | ||
679 | { | ||
680 | group = (SceneObjectGroup)entity; | ||
681 | if (group.GetFromItemID() == itemID) | ||
682 | { | ||
683 | m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); | ||
684 | sp.RemoveAttachment(group); | ||
685 | |||
686 | // Prepare sog for storage | ||
687 | group.AttachedAvatar = UUID.Zero; | ||
688 | group.RootPart.SetParentLocalId(0); | ||
689 | group.IsAttachment = false; | ||
690 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
691 | |||
692 | UpdateKnownItem(sp, group); | ||
693 | m_scene.DeleteSceneObject(group, false); | ||
694 | |||
695 | return; | ||
696 | } | ||
697 | } | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | |||
702 | private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | ||
703 | IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt) | ||
704 | { | ||
705 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
706 | if (invAccess != null) | ||
707 | { | ||
708 | lock (sp.AttachmentsSyncLock) | ||
709 | { | ||
710 | SceneObjectGroup objatt; | ||
711 | |||
712 | if (itemID != UUID.Zero) | ||
713 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
714 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
715 | false, false, sp.UUID, true); | ||
716 | else | ||
717 | objatt = invAccess.RezObject(sp.ControllingClient, | ||
718 | null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
719 | false, false, sp.UUID, true); | ||
720 | |||
721 | // m_log.DebugFormat( | ||
722 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", | ||
723 | // objatt.Name, remoteClient.Name, AttachmentPt); | ||
724 | |||
725 | if (objatt != null) | ||
726 | { | ||
727 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. | ||
728 | objatt.HasGroupChanged = false; | ||
729 | bool tainted = false; | ||
730 | if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) | ||
731 | tainted = true; | ||
732 | |||
733 | // This will throw if the attachment fails | ||
734 | try | ||
735 | { | ||
736 | AttachObject(sp, objatt, attachmentPt, false); | ||
737 | } | ||
738 | catch (Exception e) | ||
739 | { | ||
740 | m_log.ErrorFormat( | ||
741 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
742 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
743 | |||
744 | // Make sure the object doesn't stick around and bail | ||
745 | sp.RemoveAttachment(objatt); | ||
746 | m_scene.DeleteSceneObject(objatt, false); | ||
747 | return null; | ||
748 | } | ||
749 | |||
750 | if (tainted) | ||
751 | objatt.HasGroupChanged = true; | ||
752 | |||
753 | // Fire after attach, so we don't get messy perms dialogs | ||
754 | // 4 == AttachedRez | ||
755 | objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); | ||
756 | objatt.ResumeScripts(); | ||
757 | |||
758 | // Do this last so that event listeners have access to all the effects of the attachment | ||
759 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); | ||
760 | |||
761 | return objatt; | ||
762 | } | ||
763 | else | ||
764 | { | ||
765 | m_log.WarnFormat( | ||
766 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
767 | itemID, sp.Name, attachmentPt); | ||
768 | } | ||
769 | } | ||
770 | } | ||
771 | |||
772 | return null; | ||
773 | } | ||
774 | |||
775 | /// <summary> | ||
776 | /// Update the user inventory to reflect an attachment | ||
777 | /// </summary> | ||
778 | /// <param name="sp"></param> | ||
779 | /// <param name="AttachmentPt"></param> | ||
780 | /// <param name="itemID"></param> | ||
781 | /// <param name="att"></param> | ||
782 | private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) | ||
783 | { | ||
784 | // m_log.DebugFormat( | ||
785 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", | ||
786 | // att.Name, sp.Name, AttachmentPt, itemID); | ||
787 | |||
788 | if (UUID.Zero == itemID) | ||
789 | { | ||
790 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | if (0 == AttachmentPt) | ||
795 | { | ||
796 | m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point."); | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); | ||
801 | item = m_scene.InventoryService.GetItem(item); | ||
802 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | ||
803 | if (changed && m_scene.AvatarFactory != null) | ||
804 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | ||
805 | } | ||
806 | |||
807 | #endregion | ||
808 | |||
809 | #region Client Event Handlers | ||
810 | |||
811 | private ISceneEntity Client_OnRezSingleAttachmentFromInv(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
812 | { | ||
813 | if (!Enabled) | ||
814 | return null; | ||
815 | |||
816 | // m_log.DebugFormat( | ||
817 | // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", | ||
818 | // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); | ||
819 | |||
820 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
821 | |||
822 | if (sp == null) | ||
823 | { | ||
824 | m_log.ErrorFormat( | ||
825 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", | ||
826 | remoteClient.Name, remoteClient.AgentId); | ||
827 | return null; | ||
828 | } | ||
829 | |||
830 | return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); | ||
831 | } | ||
832 | |||
833 | private void Client_OnRezMultipleAttachmentsFromInv(IClientAPI remoteClient, List<KeyValuePair<UUID, uint>> rezlist) | ||
834 | { | ||
835 | if (!Enabled) | ||
836 | return; | ||
837 | |||
838 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
839 | if (sp != null) | ||
840 | RezMultipleAttachmentsFromInventory(sp, rezlist); | ||
841 | else | ||
842 | m_log.ErrorFormat( | ||
843 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", | ||
844 | remoteClient.Name, remoteClient.AgentId); | ||
845 | } | ||
846 | |||
847 | private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) | ||
848 | { | ||
849 | // m_log.DebugFormat( | ||
850 | // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", | ||
851 | // objectLocalID, remoteClient.Name, AttachmentPt, silent); | ||
852 | |||
853 | if (!Enabled) | ||
854 | return; | ||
855 | |||
856 | try | ||
857 | { | ||
858 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
859 | |||
860 | if (sp == null) | ||
861 | { | ||
862 | m_log.ErrorFormat( | ||
863 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
864 | return; | ||
865 | } | ||
866 | |||
867 | // If we can't take it, we can't attach it! | ||
868 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); | ||
869 | if (part == null) | ||
870 | return; | ||
871 | |||
872 | if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) | ||
873 | { | ||
874 | remoteClient.SendAgentAlertMessage( | ||
875 | "You don't have sufficient permissions to attach this object", false); | ||
876 | |||
877 | return; | ||
878 | } | ||
879 | |||
880 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | ||
881 | // be removed when that functionality is implemented in opensim | ||
882 | AttachmentPt &= 0x7f; | ||
883 | |||
884 | // Calls attach with a Zero position | ||
885 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) | ||
886 | { | ||
887 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | ||
888 | |||
889 | // Save avatar attachment information | ||
890 | m_log.Debug( | ||
891 | "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | ||
892 | + ", AttachmentPoint: " + AttachmentPt); | ||
893 | |||
894 | } | ||
895 | } | ||
896 | catch (Exception e) | ||
897 | { | ||
898 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); | ||
899 | } | ||
900 | } | ||
901 | |||
902 | private void Client_OnObjectDetach(uint objectLocalID, IClientAPI remoteClient) | ||
903 | { | ||
904 | if (!Enabled) | ||
905 | return; | ||
906 | |||
907 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
908 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); | ||
909 | if (sp != null && group != null) | ||
910 | DetachSingleAttachmentToInv(sp, group.GetFromItemID()); | ||
911 | } | ||
912 | |||
913 | private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient) | ||
914 | { | ||
915 | if (!Enabled) | ||
916 | return; | ||
917 | |||
918 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
919 | if (sp != null) | ||
920 | DetachSingleAttachmentToInv(sp, itemID); | ||
921 | } | ||
922 | |||
923 | private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient) | ||
924 | { | ||
925 | if (!Enabled) | ||
926 | return; | ||
927 | |||
928 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
929 | if (sp != null) | ||
930 | DetachSingleAttachmentToGround(sp, soLocalId); | ||
931 | } | ||
932 | |||
933 | #endregion | ||
920 | } | 934 | } |
921 | } | 935 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 832c6eb..86cfb32 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -209,7 +209,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
209 | 209 | ||
210 | m_attMod.RezSingleAttachmentFromInventory( | 210 | m_attMod.RezSingleAttachmentFromInventory( |
211 | m_presence, attItemId, (uint)AttachmentPoint.Chest); | 211 | m_presence, attItemId, (uint)AttachmentPoint.Chest); |
212 | m_attMod.DetachSingleAttachmentToInv(attItemId, m_presence.ControllingClient); | 212 | m_attMod.DetachSingleAttachmentToInv(m_presence, attItemId); |
213 | 213 | ||
214 | // Check status on scene presence | 214 | // Check status on scene presence |
215 | Assert.That(m_presence.HasAttachments(), Is.False); | 215 | Assert.That(m_presence.HasAttachments(), Is.False); |