aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar
diff options
context:
space:
mode:
authorTom2011-09-14 19:11:32 -0700
committerTom2011-09-14 19:11:32 -0700
commit5484c9b585a2a6289456e9492ac2989d489b555c (patch)
treec9b79199722fe09c993c237dce40febf731264e3 /OpenSim/Region/CoreModules/Avatar
parentMerge fixes, and fix the build (diff)
parentDon't try and delete attachments for child agent close (diff)
downloadopensim-SC-5484c9b585a2a6289456e9492ac2989d489b555c.zip
opensim-SC-5484c9b585a2a6289456e9492ac2989d489b555c.tar.gz
opensim-SC-5484c9b585a2a6289456e9492ac2989d489b555c.tar.bz2
opensim-SC-5484c9b585a2a6289456e9492ac2989d489b555c.tar.xz
Bring us up to date.
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs494
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs51
2 files changed, 314 insertions, 231 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 218b7b8..2bf418d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -144,20 +144,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
144 144
145 public void SaveChangedAttachments(IScenePresence sp) 145 public void SaveChangedAttachments(IScenePresence sp)
146 { 146 {
147// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
148
147 foreach (SceneObjectGroup grp in sp.GetAttachments()) 149 foreach (SceneObjectGroup grp in sp.GetAttachments())
148 { 150 {
149 if (grp.HasGroupChanged) // Resizer scripts? 151// if (grp.HasGroupChanged) // Resizer scripts?
150 { 152// {
151 grp.IsAttachment = false; 153 grp.IsAttachment = false;
152 grp.AbsolutePosition = grp.RootPart.AttachedPos; 154 grp.AbsolutePosition = grp.RootPart.AttachedPos;
153 UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID); 155 UpdateKnownItem(sp.ControllingClient, grp);
154 grp.IsAttachment = true; 156 grp.IsAttachment = true;
155 } 157// }
156 } 158 }
157 } 159 }
158 160
159 public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent) 161 public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent)
160 { 162 {
163// m_log.DebugFormat(
164// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
165// m_scene.RegionInfo.RegionName, sp.Name, silent);
166
161 foreach (SceneObjectGroup sop in sp.GetAttachments()) 167 foreach (SceneObjectGroup sop in sp.GetAttachments())
162 { 168 {
163 sop.Scene.DeleteSceneObject(sop, silent); 169 sop.Scene.DeleteSceneObject(sop, silent);
@@ -220,7 +226,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
220 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); 226 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId);
221 227
222 // Save avatar attachment information 228 // Save avatar attachment information
223 m_log.Info( 229 m_log.Debug(
224 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId 230 "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
225 + ", AttachmentPoint: " + AttachmentPt); 231 + ", AttachmentPoint: " + AttachmentPt);
226 232
@@ -248,75 +254,83 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
248 254
249 private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) 255 private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent)
250 { 256 {
251// m_log.DebugFormat( 257 lock (sp.AttachmentsSyncLock)
252// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
253// group.Name, group.LocalId, sp.Name, AttachmentPt, silent);
254
255 if (sp.GetAttachments(attachmentPt).Contains(group))
256 {
257// m_log.WarnFormat(
258// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
259// group.Name, group.LocalId, sp.Name, AttachmentPt);
260
261 return false;
262 }
263
264 Vector3 attachPos = group.AbsolutePosition;
265
266 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
267 // be removed when that functionality is implemented in opensim
268 attachmentPt &= 0x7f;
269
270 // If the attachment point isn't the same as the one previously used
271 // set it's offset position = 0 so that it appears on the attachment point
272 // and not in a weird location somewhere unknown.
273 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
274 {
275 attachPos = Vector3.Zero;
276 }
277
278 // AttachmentPt 0 means the client chose to 'wear' the attachment.
279 if (attachmentPt == 0)
280 { 258 {
281 // Check object for stored attachment point 259// m_log.DebugFormat(
282 attachmentPt = group.AttachmentPoint; 260// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
283 } 261// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
284 262
285 // if we still didn't find a suitable attachment point....... 263 if (sp.GetAttachments(attachmentPt).Contains(group))
286 if (attachmentPt == 0) 264 {
287 { 265 // m_log.WarnFormat(
288 // Stick it on left hand with Zero Offset from the attachment point. 266 // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
289 attachmentPt = (uint)AttachmentPoint.LeftHand; 267 // group.Name, group.LocalId, sp.Name, AttachmentPt);
290 attachPos = Vector3.Zero; 268
291 } 269 return false;
292 270 }
293 group.AttachmentPoint = attachmentPt; 271
294 group.AbsolutePosition = attachPos; 272 Vector3 attachPos = group.AbsolutePosition;
295 273
296 // Remove any previous attachments 274 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
297 UUID itemID = UUID.Zero; 275 // be removed when that functionality is implemented in opensim
298 276 attachmentPt &= 0x7f;
299 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt); 277
300 278 // If the attachment point isn't the same as the one previously used
301 // At the moment we can only deal with a single attachment 279 // set it's offset position = 0 so that it appears on the attachment point
302 // We also don't want to do any of the inventory operations for an NPC. 280 // and not in a weird location somewhere unknown.
303 if (sp.PresenceType != PresenceType.Npc) 281 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
304 { 282 {
305 if (attachments.Count != 0) 283 attachPos = Vector3.Zero;
306 itemID = attachments[0].GetFromItemID(); 284 }
285
286 // AttachmentPt 0 means the client chose to 'wear' the attachment.
287 if (attachmentPt == 0)
288 {
289 // Check object for stored attachment point
290 attachmentPt = group.AttachmentPoint;
291 }
292
293 // if we still didn't find a suitable attachment point.......
294 if (attachmentPt == 0)
295 {
296 // Stick it on left hand with Zero Offset from the attachment point.
297 attachmentPt = (uint)AttachmentPoint.LeftHand;
298 attachPos = Vector3.Zero;
299 }
300
301 group.AttachmentPoint = attachmentPt;
302 group.AbsolutePosition = attachPos;
303
304 // We also don't want to do any of the inventory operations for an NPC.
305 if (sp.PresenceType != PresenceType.Npc)
306 {
307 // Remove any previous attachments
308 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
307 309
308 if (itemID != UUID.Zero) 310 // At the moment we can only deal with a single attachment
309 DetachSingleAttachmentToInv(itemID, sp); 311 if (attachments.Count != 0)
312 {
313 UUID oldAttachmentItemID = attachments[0].GetFromItemID();
314
315 if (oldAttachmentItemID != UUID.Zero)
316 DetachSingleAttachmentToInv(oldAttachmentItemID, sp);
317 else
318 m_log.WarnFormat(
319 "[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!",
320 attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
321 }
310 322
311 itemID = group.GetFromItemID(); 323 // Add the new attachment to inventory if we don't already have it.
312 if (itemID == UUID.Zero) 324 UUID newAttachmentItemID = group.GetFromItemID();
313 itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID; 325 if (newAttachmentItemID == UUID.Zero)
326 newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID;
327
328 ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
329 }
314 330
315 ShowAttachInUserInventory(sp, attachmentPt, itemID, group); 331 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
316 } 332 }
317 333
318 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
319
320 return true; 334 return true;
321 } 335 }
322 336
@@ -325,20 +339,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
325 RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, 339 RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header,
326 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) 340 RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects)
327 { 341 {
328 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) 342 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
343
344 if (sp == null)
329 { 345 {
330 RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt); 346 m_log.ErrorFormat(
347 "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()",
348 remoteClient.Name, remoteClient.AgentId);
349 return;
350 }
351
352 lock (sp.AttachmentsSyncLock)
353 {
354// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name);
355
356 foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects)
357 {
358 RezSingleAttachmentFromInventory(sp, obj.ItemID, obj.AttachmentPt);
359 }
331 } 360 }
332 } 361 }
333 362
334 public ISceneEntity RezSingleAttachmentFromInventory( 363 public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
335 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
336 {
337 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true);
338 }
339
340 public ISceneEntity RezSingleAttachmentFromInventory(
341 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
342 { 364 {
343 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null); 365 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null);
344 } 366 }
@@ -347,21 +369,59 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
347 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) 369 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
348 { 370 {
349 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); 371 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
350 if (sp == null) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", remoteClient.Name, remoteClient.AgentId); return null; } 372
373 if (sp == null)
374 {
375 m_log.ErrorFormat(
376 "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()",
377 remoteClient.Name, remoteClient.AgentId);
378 return null;
379 }
380
381 return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt);
382 }
383
384 public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt)
385 {
386// m_log.DebugFormat(
387// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
388// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
389
351 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 390 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
352 // be removed when that functionality is implemented in opensim 391 // be removed when that functionality is implemented in opensim
353 AttachmentPt &= 0x7f; 392 AttachmentPt &= 0x7f;
354 393
355 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); 394 // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such).
395 // This often happens during login - not sure the exact reason.
396 // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the
397 // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login
398 // before anything has actually been attached.
399 bool alreadyOn = false;
400 List<SceneObjectGroup> existingAttachments = sp.GetAttachments();
401 foreach (SceneObjectGroup so in existingAttachments)
402 {
403 if (so.GetFromItemID() == itemID)
404 {
405 alreadyOn = true;
406 break;
407 }
408 }
356 409
357 if (updateInventoryStatus) 410// if (sp.Appearance.GetAttachmentForItem(itemID) != null)
411 if (alreadyOn)
358 { 412 {
359 if (att == null) 413// m_log.WarnFormat(
360 DetachSingleAttachmentToInv(itemID, sp.ControllingClient); 414// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn",
361 else 415// sp.Name, itemID, AttachmentPt);
362 ShowAttachInUserInventory(att, sp, itemID, AttachmentPt); 416
417 return null;
363 } 418 }
364 419
420 SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, null);
421
422 if (att == null)
423 DetachSingleAttachmentToInv(itemID, sp.ControllingClient);
424
365 return att; 425 return att;
366 } 426 }
367 427
@@ -371,50 +431,67 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
371 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 431 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
372 if (invAccess != null) 432 if (invAccess != null)
373 { 433 {
374 SceneObjectGroup objatt; 434 lock (sp.AttachmentsSyncLock)
375
376 if (itemID != UUID.Zero)
377 objatt = invAccess.RezObject(sp.ControllingClient,
378 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
379 false, false, sp.UUID, true);
380 else
381 objatt = invAccess.RezObject(sp.ControllingClient,
382 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
383 false, false, sp.UUID, true);
384
385// m_log.DebugFormat(
386// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
387// objatt.Name, remoteClient.Name, AttachmentPt);
388
389 if (objatt != null)
390 { 435 {
391 // Loading the inventory from XML will have set this, but 436 SceneObjectGroup objatt;
392 // there is no way the object could have changed yet, 437
393 // since scripts aren't running yet. So, clear it here. 438 if (itemID != UUID.Zero)
394 objatt.HasGroupChanged = false; 439 objatt = invAccess.RezObject(sp.ControllingClient,
395 bool tainted = false; 440 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
396 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) 441 false, false, sp.UUID, true);
397 tainted = true; 442 else
398 443 objatt = invAccess.RezObject(sp.ControllingClient,
399 // This will throw if the attachment fails 444 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
400 try 445 false, false, sp.UUID, true);
446
447 // m_log.DebugFormat(
448 // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
449 // objatt.Name, remoteClient.Name, AttachmentPt);
450
451 if (objatt != null)
401 { 452 {
402 AttachObject(sp, objatt, attachmentPt, false); 453 // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
454 objatt.HasGroupChanged = false;
455 bool tainted = false;
456 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
457 tainted = true;
458
459 // This will throw if the attachment fails
460 try
461 {
462 AttachObject(sp, objatt, attachmentPt, false);
463 }
464 catch (Exception e)
465 {
466 m_log.ErrorFormat(
467 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
468 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
469
470 // Make sure the object doesn't stick around and bail
471 sp.RemoveAttachment(objatt);
472 m_scene.DeleteSceneObject(objatt, false);
473 return null;
474 }
475
476 if (tainted)
477 objatt.HasGroupChanged = true;
478
479 // Fire after attach, so we don't get messy perms dialogs
480 // 4 == AttachedRez
481 objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
482 objatt.ResumeScripts();
483
484 // Do this last so that event listeners have access to all the effects of the attachment
485 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
486
487 return objatt;
403 } 488 }
404 catch (Exception e) 489 else
405 { 490 {
406 m_log.ErrorFormat( 491 m_log.WarnFormat(
407 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", 492 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
408 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); 493 itemID, sp.Name, attachmentPt);
409
410 // Make sure the object doesn't stick around and bail
411 sp.RemoveAttachment(objatt);
412 m_scene.DeleteSceneObject(objatt, false);
413 return null;
414 } 494 }
415
416 if (tainted)
417 objatt.HasGroupChanged = true;
418 495
419 if (doc != null) 496 if (doc != null)
420 { 497 {
@@ -430,47 +507,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
430 // Do this last so that event listeners have access to all the effects of the attachment 507 // Do this last so that event listeners have access to all the effects of the attachment
431 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); 508 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
432 } 509 }
433 else
434 {
435 m_log.WarnFormat(
436 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
437 itemID, sp.Name, attachmentPt);
438 }
439
440 return objatt;
441 } 510 }
442 511
443 return null; 512 return null;
444 } 513 }
445
446 /// <summary>
447 /// Update the user inventory to the attachment of an item
448 /// </summary>
449 /// <param name="att"></param>
450 /// <param name="sp"></param>
451 /// <param name="itemID"></param>
452 /// <param name="attachmentPoint"></param>
453 /// <returns></returns>
454 private UUID ShowAttachInUserInventory(
455 SceneObjectGroup att, IScenePresence sp, UUID itemID, uint attachmentPoint)
456 {
457// m_log.DebugFormat(
458// "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} {2} (item ID {3}) at {4}",
459// sp.Name, att.Name, att.LocalId, itemID, AttachmentPt);
460
461 if (!att.IsDeleted)
462 attachmentPoint = att.AttachmentPoint;
463
464 InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
465 if (m_scene.InventoryService != null)
466 item = m_scene.InventoryService.GetItem(item);
467
468 bool changed = sp.Appearance.SetAttachment((int)attachmentPoint, itemID, item.AssetID);
469 if (changed && m_scene.AvatarFactory != null)
470 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
471
472 return att.UUID;
473 }
474 514
475 /// <summary> 515 /// <summary>
476 /// Update the user inventory to reflect an attachment 516 /// Update the user inventory to reflect an attachment
@@ -483,8 +523,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
483 IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 523 IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att)
484 { 524 {
485// m_log.DebugFormat( 525// m_log.DebugFormat(
486// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 526// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
487// att.Name, remoteClient.Name, AttachmentPt, itemID); 527// att.Name, sp.Name, AttachmentPt, itemID);
488 528
489 if (UUID.Zero == itemID) 529 if (UUID.Zero == itemID)
490 { 530 {
@@ -518,6 +558,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
518 558
519 public void DetachObject(uint objectLocalID, IClientAPI remoteClient) 559 public void DetachObject(uint objectLocalID, IClientAPI remoteClient)
520 { 560 {
561// m_log.DebugFormat(
562// "[ATTACHMENTS MODULE]: DetachObject() for object {0} on {1}", objectLocalID, remoteClient.Name);
563
521 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); 564 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
522 if (group != null) 565 if (group != null)
523 { 566 {
@@ -530,14 +573,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
530 ScenePresence presence; 573 ScenePresence presence;
531 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 574 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
532 { 575 {
533 // Save avatar attachment information 576 lock (presence.AttachmentsSyncLock)
534 m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); 577 {
535 578 // Save avatar attachment information
536 bool changed = presence.Appearance.DetachAttachment(itemID); 579 m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID);
537 if (changed && m_scene.AvatarFactory != null)
538 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
539 580
540 DetachSingleAttachmentToInv(itemID, presence); 581 bool changed = presence.Appearance.DetachAttachment(itemID);
582 if (changed && m_scene.AvatarFactory != null)
583 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
584
585 DetachSingleAttachmentToInv(itemID, presence);
586 }
541 } 587 }
542 } 588 }
543 589
@@ -545,7 +591,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
545 { 591 {
546// m_log.DebugFormat( 592// m_log.DebugFormat(
547// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", 593// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
548// remoteClient.Name, sceneObjectID); 594// remoteClient.Name, soLocalId);
549 595
550 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); 596 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
551 597
@@ -564,24 +610,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
564 ScenePresence presence; 610 ScenePresence presence;
565 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 611 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
566 { 612 {
567 if (!m_scene.Permissions.CanRezObject( 613 lock (presence.AttachmentsSyncLock)
568 so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) 614 {
569 return; 615 if (!m_scene.Permissions.CanRezObject(
616 so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition))
617 return;
570 618
571 bool changed = presence.Appearance.DetachAttachment(inventoryID); 619 bool changed = presence.Appearance.DetachAttachment(inventoryID);
572 if (changed && m_scene.AvatarFactory != null) 620 if (changed && m_scene.AvatarFactory != null)
573 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); 621 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
574 622
575 presence.RemoveAttachment(so); 623 presence.RemoveAttachment(so);
576 DetachSceneObjectToGround(so, presence); 624 DetachSceneObjectToGround(so, presence);
577 625
578 List<UUID> uuids = new List<UUID>(); 626 List<UUID> uuids = new List<UUID>();
579 uuids.Add(inventoryID); 627 uuids.Add(inventoryID);
580 m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids); 628 m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids);
581 remoteClient.SendRemoveInventoryItem(inventoryID); 629 remoteClient.SendRemoveInventoryItem(inventoryID);
582 } 630 }
583 631
584 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); 632 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero);
633 }
585 } 634 }
586 635
587 /// <summary> 636 /// <summary>
@@ -615,6 +664,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
615 // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? 664 // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
616 private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp) 665 private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp)
617 { 666 {
667// m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
668
618 if (itemID == UUID.Zero) // If this happened, someone made a mistake.... 669 if (itemID == UUID.Zero) // If this happened, someone made a mistake....
619 return; 670 return;
620 671
@@ -623,40 +674,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
623 EntityBase[] detachEntities = m_scene.GetEntities(); 674 EntityBase[] detachEntities = m_scene.GetEntities();
624 SceneObjectGroup group; 675 SceneObjectGroup group;
625 676
626 foreach (EntityBase entity in detachEntities) 677 lock (sp.AttachmentsSyncLock)
627 { 678 {
628 if (entity is SceneObjectGroup) 679 foreach (EntityBase entity in detachEntities)
629 { 680 {
630 group = (SceneObjectGroup)entity; 681 if (entity is SceneObjectGroup)
631 if (group.GetFromItemID() == itemID)
632 { 682 {
633 m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); 683 group = (SceneObjectGroup)entity; if (group.GetFromItemID() == itemID) { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
634 // CM / XMREngine!!!! Needed to conclude attach event 684 // CM / XMREngine!!!! Needed to conclude attach event
635 //SceneObjectSerializer.ToOriginalXmlFormat(group); 685 //SceneObjectSerializer.ToOriginalXmlFormat(group);
636 group.DetachToInventoryPrep(); 686 group.DetachToInventoryPrep();
637 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 687 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
638 688
639 // Prepare sog for storage 689 // Prepare sog for storage
640 group.AttachedAvatar = UUID.Zero; 690 group.AttachedAvatar = UUID.Zero;
641 691 group.RootPart.SetParentLocalId(0);
642 group.ForEachPart( 692 group.IsAttachment = false;
643 delegate(SceneObjectPart part) 693 group.AbsolutePosition = group.RootPart.AttachedPos;
644 {
645 // If there are any scripts,
646 // then always trigger a new object and state persistence in UpdateKnownItem()
647 if (part.Inventory.ContainsScripts())
648 group.HasGroupChanged = true;
649 }
650 );
651
652 group.RootPart.SetParentLocalId(0);
653 group.IsAttachment = false;
654 group.AbsolutePosition = group.RootPart.AttachedPos;
655 694
656 UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); 695 UpdateKnownItem(sp.ControllingClient, group);
657 m_scene.DeleteSceneObject(group, false); 696 m_scene.DeleteSceneObject(group, false);
658 697
659 return; 698 return;
699 }
660 } 700 }
661 } 701 }
662 } 702 }
@@ -687,28 +727,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
687 /// </remarks> 727 /// </remarks>
688 /// <param name="remoteClient"></param> 728 /// <param name="remoteClient"></param>
689 /// <param name="grp"></param> 729 /// <param name="grp"></param>
690 /// <param name="itemID"></param> 730 private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp)
691 /// <param name="agentID"></param>
692 public void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID)
693 { 731 {
694 if (grp != null) 732 if (grp.HasGroupChanged || grp.ContainsScripts())
695 { 733 {
696 if (!grp.HasGroupChanged)
697 {
698 m_log.DebugFormat(
699 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
700 grp.UUID, grp.AttachmentPoint);
701
702 return;
703 }
704
705 m_log.DebugFormat( 734 m_log.DebugFormat(
706 "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", 735 "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
707 grp.UUID, grp.AttachmentPoint); 736 grp.UUID, grp.AttachmentPoint);
708 737
709 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); 738 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
710 739
711 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 740 InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), remoteClient.AgentId);
712 item = m_scene.InventoryService.GetItem(item); 741 item = m_scene.InventoryService.GetItem(item);
713 742
714 if (item != null) 743 if (item != null)
@@ -734,6 +763,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
734 remoteClient.SendInventoryItemCreateUpdate(item, 0); 763 remoteClient.SendInventoryItemCreateUpdate(item, 0);
735 } 764 }
736 } 765 }
766 else
767 {
768 m_log.DebugFormat(
769 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
770 grp.UUID, grp.AttachmentPoint);
771 }
737 } 772 }
738 773
739 /// <summary> 774 /// <summary>
@@ -751,7 +786,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
751 private void AttachToAgent( 786 private void AttachToAgent(
752 IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 787 IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
753 { 788 {
754// m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", 789// m_log.DebugFormat(
790// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
755// so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); 791// so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
756 792
757 so.DetachFromBackup(); 793 so.DetachFromBackup();
@@ -788,14 +824,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
788 } 824 }
789 825
790 /// <summary> 826 /// <summary>
791 /// Add a scene object that was previously free in the scene as an attachment to an avatar. 827 /// Add a scene object as a new attachment in the user inventory.
792 /// </summary> 828 /// </summary>
793 /// <param name="remoteClient"></param> 829 /// <param name="remoteClient"></param>
794 /// <param name="grp"></param> 830 /// <param name="grp"></param>
795 /// <returns>The user inventory item created that holds the attachment.</returns> 831 /// <returns>The user inventory item created that holds the attachment.</returns>
796 private InventoryItemBase AddSceneObjectAsAttachment(IClientAPI remoteClient, SceneObjectGroup grp) 832 private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IClientAPI remoteClient, SceneObjectGroup grp)
797 { 833 {
798// m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId); 834// m_log.DebugFormat(
835// "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
836// grp.Name, grp.LocalId, remoteClient.Name);
799 837
800 Vector3 inventoryStoredPosition = new Vector3 838 Vector3 inventoryStoredPosition = new Vector3
801 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 839 (((grp.AbsolutePosition.X > (int)Constants.RegionSize)
@@ -879,4 +917,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
879 return item; 917 return item;
880 } 918 }
881 } 919 }
882} 920} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index 363e258..ff3358f 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -58,12 +58,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
58 private AttachmentsModule m_attMod; 58 private AttachmentsModule m_attMod;
59 private ScenePresence m_presence; 59 private ScenePresence m_presence;
60 60
61 [SetUp] 61 [TestFixtureSetUp]
62 public void Init() 62 public void FixtureInit()
63 { 63 {
64 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. 64 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
65 Util.FireAndForgetMethod = FireAndForgetMethod.None; 65 Util.FireAndForgetMethod = FireAndForgetMethod.None;
66 }
66 67
68 [SetUp]
69 public void Init()
70 {
67 IConfigSource config = new IniConfigSource(); 71 IConfigSource config = new IniConfigSource();
68 config.AddConfig("Modules"); 72 config.AddConfig("Modules");
69 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); 73 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
@@ -73,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
73 SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule()); 77 SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule());
74 } 78 }
75 79
76 [TearDown] 80 [TestFixtureTearDown]
77 public void TearDown() 81 public void TearDown()
78 { 82 {
79 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple 83 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
@@ -150,6 +154,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
150 Assert.That(attSo.IsTemporary, Is.False); 154 Assert.That(attSo.IsTemporary, Is.False);
151 155
152 // Check appearance status 156 // Check appearance status
157 Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(1));
153 Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest)); 158 Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest));
154 } 159 }
155 160
@@ -215,6 +220,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
215 Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0)); 220 Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0));
216 } 221 }
217 222
223 /// <summary>
224 /// Test that attachments don't hang about in the scene when the agent is closed
225 /// </summary>
226 [Test]
227 public void TestRemoveAttachmentsOnAvatarExit()
228 {
229 TestHelpers.InMethod();
230// log4net.Config.XmlConfigurator.Configure();
231
232 UUID userId = TestHelpers.ParseTail(0x1);
233 UUID attItemId = TestHelpers.ParseTail(0x2);
234 UUID attAssetId = TestHelpers.ParseTail(0x3);
235 string attName = "att";
236
237 UserAccountHelpers.CreateUserWithInventory(scene, userId);
238 InventoryItemBase attItem
239 = UserInventoryHelpers.CreateInventoryItem(
240 scene, attName, attItemId, attAssetId, userId, InventoryType.Object);
241
242 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
243 acd.Appearance = new AvatarAppearance();
244 acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
245 ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
246
247 SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
248
249 scene.IncomingCloseAgent(presence.UUID);
250
251 // Check that we can't retrieve this attachment from the scene.
252 Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
253 }
254
218 [Test] 255 [Test]
219 public void TestRezAttachmentsOnAvatarEntrance() 256 public void TestRezAttachmentsOnAvatarEntrance()
220 { 257 {
@@ -246,6 +283,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
246 Assert.That(attSo.IsAttachment); 283 Assert.That(attSo.IsAttachment);
247 Assert.That(attSo.UsesPhysics, Is.False); 284 Assert.That(attSo.UsesPhysics, Is.False);
248 Assert.That(attSo.IsTemporary, Is.False); 285 Assert.That(attSo.IsTemporary, Is.False);
286
287 // Check appearance status
288 List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments();
289 Assert.That(retreivedAttachments.Count, Is.EqualTo(1));
290 Assert.That(retreivedAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest));
291 Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItemId));
292 Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attAssetId));
293 Assert.That(presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest));
249 } 294 }
250 295
251 // I'm commenting this test because scene setup NEEDS InventoryService to 296 // I'm commenting this test because scene setup NEEDS InventoryService to