aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs868
1 files changed, 456 insertions, 412 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index a98ce85..654e202 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -325,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
325 } 325 }
326 } 326 }
327 327
328 // This is pethod scoped and will be returned. It will be the 328 // This is method scoped and will be returned. It will be the
329 // last created asset id 329 // last created asset id
330 UUID assetID = UUID.Zero; 330 UUID assetID = UUID.Zero;
331 331
@@ -354,9 +354,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
354 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); 354 CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
355 Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); 355 Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
356 356
357 Dictionary<UUID, string> xmlStrings =
358 new Dictionary<UUID, string>();
359
360 foreach (SceneObjectGroup objectGroup in objlist) 357 foreach (SceneObjectGroup objectGroup in objlist)
361 { 358 {
362 Vector3 inventoryStoredPosition = new Vector3 359 Vector3 inventoryStoredPosition = new Vector3
@@ -369,12 +366,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
369 : objectGroup.AbsolutePosition.Y, 366 : objectGroup.AbsolutePosition.Y,
370 objectGroup.AbsolutePosition.Z); 367 objectGroup.AbsolutePosition.Z);
371 368
372 Vector3 originalPosition = objectGroup.AbsolutePosition; 369 originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
373
374 // Restore attachment data after trip through the sim
375 if (objectGroup.RootPart.AttachPoint > 0)
376 inventoryStoredPosition = objectGroup.RootPart.AttachOffset;
377 objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
378 370
379 objectGroup.AbsolutePosition = inventoryStoredPosition; 371 objectGroup.AbsolutePosition = inventoryStoredPosition;
380 372
@@ -388,60 +380,159 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
388 (uint)PermissionMask.Modify); 380 (uint)PermissionMask.Modify);
389 objectGroup.RootPart.NextOwnerMask |= 381 objectGroup.RootPart.NextOwnerMask |=
390 (uint)PermissionMask.Move; 382 (uint)PermissionMask.Move;
383
384 coa.Add(objectGroup);
385 }
391 386
392 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); 387 string itemXml;
393 388
394 objectGroup.AbsolutePosition = originalPosition; 389 if (objlist.Count > 1)
390 itemXml = CoalescedSceneObjectsSerializer.ToXml(coa);
391 else
392 itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]);
393
394 // Restore the position of each group now that it has been stored to inventory.
395 foreach (SceneObjectGroup objectGroup in objlist)
396 objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
395 397
396 xmlStrings[objectGroup.UUID] = sceneObjectXml; 398 InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
399 if (item == null)
400 return UUID.Zero;
401
402 // Can't know creator is the same, so null it in inventory
403 if (objlist.Count > 1)
404 {
405 item.CreatorId = UUID.Zero.ToString();
406 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
397 } 407 }
408 else
409 {
410 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
411 item.SaleType = objlist[0].RootPart.ObjectSaleType;
412 item.SalePrice = objlist[0].RootPart.SalePrice;
413 }
398 414
399 string itemXml; 415 AssetBase asset = CreateAsset(
416 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
417 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
418 (sbyte)AssetType.Object,
419 Utils.StringToBytes(itemXml),
420 objlist[0].OwnerID.ToString());
421 m_Scene.AssetService.Store(asset);
422
423 item.AssetID = asset.FullID;
424 assetID = asset.FullID;
400 425
401 if (objlist.Count > 1) 426 if (DeRezAction.SaveToExistingUserInventoryItem == action)
402 { 427 {
403 float minX, minY, minZ; 428 m_Scene.InventoryService.UpdateItem(item);
404 float maxX, maxY, maxZ; 429 }
430 else
431 {
432 AddPermissions(item, objlist[0], objlist, remoteClient);
405 433
406 Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, 434 item.CreationDate = Util.UnixTimeSinceEpoch();
407 out minX, out maxX, out minY, out maxY, 435 item.Description = asset.Description;
408 out minZ, out maxZ); 436 item.Name = asset.Name;
437 item.AssetType = asset.Type;
409 438
410 // CreateWrapper 439 m_Scene.AddInventoryItem(item);
411 XmlDocument itemDoc = new XmlDocument();
412 XmlElement root = itemDoc.CreateElement("", "CoalescedObject", "");
413 itemDoc.AppendChild(root);
414 440
415 // Embed the offsets into the group XML 441 if (remoteClient != null && item.Owner == remoteClient.AgentId)
416 for ( int i = 0 ; i < objlist.Count ; i++ )
417 { 442 {
418 XmlDocument doc = new XmlDocument(); 443 remoteClient.SendInventoryItemCreateUpdate(item, 0);
419 SceneObjectGroup g = objlist[i]; 444 }
420 doc.LoadXml(xmlStrings[g.UUID]); 445 else
421 XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); 446 {
422 e.SetAttribute("offsetx", offsets[i].X.ToString()); 447 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
423 e.SetAttribute("offsety", offsets[i].Y.ToString()); 448 if (notifyUser != null)
424 e.SetAttribute("offsetz", offsets[i].Z.ToString()); 449 {
425 450 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
426 XmlNode objectNode = itemDoc.ImportNode(e, true); 451 }
427 root.AppendChild(objectNode);
428 } 452 }
453 }
454
455 // This is a hook to do some per-asset post-processing for subclasses that need that
456 if (remoteClient != null)
457 ExportAsset(remoteClient.AgentId, assetID);
458
459 return assetID;
460 }
429 461
430 float sizeX = maxX - minX; 462 protected virtual void ExportAsset(UUID agentID, UUID assetID)
431 float sizeY = maxY - minY; 463 {
432 float sizeZ = maxZ - minZ; 464 // nothing to do here
465 }
433 466
434 root.SetAttribute("x", sizeX.ToString()); 467 /// <summary>
435 root.SetAttribute("y", sizeY.ToString()); 468 /// Add relevant permissions for an object to the item.
436 root.SetAttribute("z", sizeZ.ToString()); 469 /// </summary>
470 /// <param name="item"></param>
471 /// <param name="so"></param>
472 /// <param name="objsForEffectivePermissions"></param>
473 /// <param name="remoteClient"></param>
474 /// <returns></returns>
475 protected InventoryItemBase AddPermissions(
476 InventoryItemBase item, SceneObjectGroup so, List<SceneObjectGroup> objsForEffectivePermissions,
477 IClientAPI remoteClient)
478 {
479 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7;
480 foreach (SceneObjectGroup grp in objsForEffectivePermissions)
481 effectivePerms &= grp.GetEffectivePermissions();
482 effectivePerms |= (uint)PermissionMask.Move;
437 483
438 itemXml = itemDoc.InnerXml; 484 if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions())
485 {
486 uint perms = effectivePerms;
487 uint nextPerms = (perms & 7) << 13;
488 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
489 perms &= ~(uint)PermissionMask.Copy;
490 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
491 perms &= ~(uint)PermissionMask.Transfer;
492 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
493 perms &= ~(uint)PermissionMask.Modify;
494
495 item.BasePermissions = perms & so.RootPart.NextOwnerMask;
496 item.CurrentPermissions = item.BasePermissions;
497 item.NextPermissions = perms & so.RootPart.NextOwnerMask;
498 item.EveryOnePermissions = so.RootPart.EveryoneMask & so.RootPart.NextOwnerMask;
499 item.GroupPermissions = so.RootPart.GroupMask & so.RootPart.NextOwnerMask;
500
501 // Magic number badness. Maybe this deserves an enum.
502 // bit 4 (16) is the "Slam" bit, it means treat as passed
503 // and apply next owner perms on rez
504 item.CurrentPermissions |= 16; // Slam!
439 } 505 }
440 else 506 else
441 { 507 {
442 itemXml = xmlStrings[objlist[0].UUID]; 508 item.BasePermissions = effectivePerms;
443 } 509 item.CurrentPermissions = effectivePerms;
510 item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms;
511 item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms;
512 item.GroupPermissions = so.RootPart.GroupMask & effectivePerms;
444 513
514 item.CurrentPermissions &=
515 ((uint)PermissionMask.Copy |
516 (uint)PermissionMask.Transfer |
517 (uint)PermissionMask.Modify |
518 (uint)PermissionMask.Move |
519 7); // Preserve folded permissions
520 }
521
522 return item;
523 }
524
525 /// <summary>
526 /// Create an item using details for the given scene object.
527 /// </summary>
528 /// <param name="action"></param>
529 /// <param name="remoteClient"></param>
530 /// <param name="so"></param>
531 /// <param name="folderID"></param>
532 /// <returns></returns>
533 protected InventoryItemBase CreateItemForObject(
534 DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID)
535 {
445 // Get the user info of the item destination 536 // Get the user info of the item destination
446 // 537 //
447 UUID userID = UUID.Zero; 538 UUID userID = UUID.Zero;
@@ -453,7 +544,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
453 // Saving changes requires a local user 544 // Saving changes requires a local user
454 // 545 //
455 if (remoteClient == null) 546 if (remoteClient == null)
456 return UUID.Zero; 547 return null;
457 548
458 userID = remoteClient.AgentId; 549 userID = remoteClient.AgentId;
459 } 550 }
@@ -461,13 +552,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
461 { 552 {
462 // All returns / deletes go to the object owner 553 // All returns / deletes go to the object owner
463 // 554 //
464 555 userID = so.RootPart.OwnerID;
465 userID = objlist[0].RootPart.OwnerID;
466 } 556 }
467 557
468 if (userID == UUID.Zero) // Can't proceed 558 if (userID == UUID.Zero) // Can't proceed
469 { 559 {
470 return UUID.Zero; 560 return null;
471 } 561 }
472 562
473 // If we're returning someone's item, it goes back to the 563 // If we're returning someone's item, it goes back to the
@@ -475,13 +565,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
475 // Delete is treated like return in this case 565 // Delete is treated like return in this case
476 // Deleting your own items makes them go to trash 566 // Deleting your own items makes them go to trash
477 // 567 //
478 568
479 InventoryFolderBase folder = null; 569 InventoryFolderBase folder = null;
480 InventoryItemBase item = null; 570 InventoryItemBase item = null;
481 571
482 if (DeRezAction.SaveToExistingUserInventoryItem == action) 572 if (DeRezAction.SaveToExistingUserInventoryItem == action)
483 { 573 {
484 item = new InventoryItemBase(objlist[0].RootPart.FromUserInventoryItemID, userID); 574 item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID);
485 item = m_Scene.InventoryService.GetItem(item); 575 item = m_Scene.InventoryService.GetItem(item);
486 576
487 //item = userInfo.RootFolder.FindItem( 577 //item = userInfo.RootFolder.FindItem(
@@ -491,8 +581,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
491 { 581 {
492 m_log.DebugFormat( 582 m_log.DebugFormat(
493 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", 583 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
494 objlist[0].Name, objlist[0].UUID); 584 so.Name, so.UUID);
495 return UUID.Zero; 585
586 return null;
496 } 587 }
497 } 588 }
498 else 589 else
@@ -504,19 +595,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
504 // Deleting someone else's item 595 // Deleting someone else's item
505 // 596 //
506 if (remoteClient == null || 597 if (remoteClient == null ||
507 objlist[0].OwnerID != remoteClient.AgentId) 598 so.OwnerID != remoteClient.AgentId)
508 { 599 {
509
510 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 600 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
511 } 601 }
512 else 602 else
513 { 603 {
514 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder); 604 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.TrashFolder);
515 } 605 }
516 } 606 }
517 else if (action == DeRezAction.Return) 607 else if (action == DeRezAction.Return)
518 { 608 {
519
520 // Dump to lost + found unconditionally 609 // Dump to lost + found unconditionally
521 // 610 //
522 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); 611 folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder);
@@ -532,8 +621,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
532 } 621 }
533 else 622 else
534 { 623 {
535 if (remoteClient == null || 624 if (remoteClient == null || so.OwnerID != remoteClient.AgentId)
536 objlist[0].OwnerID != remoteClient.AgentId)
537 { 625 {
538 // Taking copy of another person's item. Take to 626 // Taking copy of another person's item. Take to
539 // Objects folder. 627 // Objects folder.
@@ -554,9 +642,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
554 // 642 //
555 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy) 643 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy)
556 { 644 {
557 if (objlist[0].RootPart.FromFolderID != UUID.Zero && objlist[0].OwnerID == remoteClient.AgentId) 645 if (so.RootPart.FromFolderID != UUID.Zero)
558 { 646 {
559 InventoryFolderBase f = new InventoryFolderBase(objlist[0].RootPart.FromFolderID, userID); 647 InventoryFolderBase f = new InventoryFolderBase(so.RootPart.FromFolderID, userID);
560 folder = m_Scene.InventoryService.GetFolder(f); 648 folder = m_Scene.InventoryService.GetFolder(f);
561 } 649 }
562 } 650 }
@@ -567,380 +655,375 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
567 655
568 if (folder == null) // Nowhere to put it 656 if (folder == null) // Nowhere to put it
569 { 657 {
570 return UUID.Zero; 658 return null;
571 } 659 }
572 } 660 }
573 661
574 item = new InventoryItemBase(); 662 item = new InventoryItemBase();
575 // Can't know creator is the same, so null it in inventory
576 if (objlist.Count > 1)
577 {
578 item.CreatorId = UUID.Zero.ToString();
579 item.CreatorData = String.Empty;
580 }
581 else
582 {
583 item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
584 item.CreatorData = objlist[0].RootPart.CreatorData;
585 }
586 item.ID = UUID.Random(); 663 item.ID = UUID.Random();
587 item.InvType = (int)InventoryType.Object; 664 item.InvType = (int)InventoryType.Object;
588 item.Folder = folder.ID; 665 item.Folder = folder.ID;
589 item.Owner = userID; 666 item.Owner = userID;
590 if (objlist.Count > 1) 667 }
668
669 return item;
670 }
671
672 public virtual SceneObjectGroup RezObject(
673 IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
674 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
675 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
676 {
677// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID);
678 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
679 item = m_Scene.InventoryService.GetItem(item);
680
681 if (item == null)
682 {
683
684 return null;
685 }
686
687
688
689
690
691
692
693 item.Owner = remoteClient.AgentId;
694
695 return RezObject(
696 remoteClient, item, item.AssetID,
697 RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
698 RezSelected, RemoveItem, fromTaskID, attachment);
699 }
700
701 public virtual SceneObjectGroup RezObject(
702 IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart,
703 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
704 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
705 {
706 AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString());
707
708 if (rezAsset == null)
709 {
710 if (item != null)
591 { 711 {
592 item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; 712 m_log.WarnFormat(
713 "[InventoryAccessModule]: Could not find asset {0} for item {1} {2} for {3} in RezObject()",
714 assetID, item.Name, item.ID, remoteClient.Name);
593 } 715 }
594 else 716 else
595 { 717 {
596 item.SaleType = objlist[0].RootPart.ObjectSaleType; 718 m_log.WarnFormat(
597 item.SalePrice = objlist[0].RootPart.SalePrice; 719 "[InventoryAccessModule]: Could not find asset {0} for {1} in RezObject()",
720 assetID, remoteClient.Name);
598 } 721 }
722
723 return null;
599 } 724 }
600 725
601 AssetBase asset = CreateAsset( 726 SceneObjectGroup group = null;
602 objlist[0].GetPartName(objlist[0].RootPart.LocalId),
603 objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
604 (sbyte)AssetType.Object,
605 Utils.StringToBytes(itemXml),
606 objlist[0].OwnerID.ToString());
607 m_Scene.AssetService.Store(asset);
608 assetID = asset.FullID;
609 727
610 if (DeRezAction.SaveToExistingUserInventoryItem == action) 728 string xmlData = Utils.BytesToString(rezAsset.Data);
729 List<SceneObjectGroup> objlist =
730 new List<SceneObjectGroup>();
731 List<Vector3> veclist = new List<Vector3>();
732 byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
733 Vector3 pos;
734
735 XmlDocument doc = new XmlDocument();
736 doc.LoadXml(xmlData);
737 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
738 if (e == null || attachment) // Single
611 { 739 {
612 item.AssetID = asset.FullID; 740 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
613 m_Scene.InventoryService.UpdateItem(item); 741
742 objlist.Add(g);
743 veclist.Add(new Vector3(0, 0, 0));
744
745 float offsetHeight = 0;
746 pos = m_Scene.GetNewRezLocation(
747 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
748 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
749 pos.Z += offsetHeight;
614 } 750 }
615 else 751 else
616 { 752 {
617 item.AssetID = asset.FullID; 753 XmlElement coll = (XmlElement)e;
754 float bx = Convert.ToSingle(coll.GetAttribute("x"));
755 float by = Convert.ToSingle(coll.GetAttribute("y"));
756 float bz = Convert.ToSingle(coll.GetAttribute("z"));
757 Vector3 bbox = new Vector3(bx, by, bz);
618 758
619 uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move) | 7; 759 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
620 foreach (SceneObjectGroup grp in objlist) 760 RayTargetID, Quaternion.Identity,
621 effectivePerms &= grp.GetEffectivePermissions(); 761 BypassRayCast, bRayEndIsIntersection, true,
622 effectivePerms |= (uint)PermissionMask.Move; 762 bbox, false);
623 763
624 if (remoteClient != null && (remoteClient.AgentId != objlist[0].RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) 764 pos -= bbox / 2;
625 { 765
626 uint perms = effectivePerms; 766 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
627 uint nextPerms = (perms & 7) << 13; 767 foreach (XmlNode n in groups)
628 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
629 perms &= ~(uint)PermissionMask.Copy;
630 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
631 perms &= ~(uint)PermissionMask.Transfer;
632 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
633 perms &= ~(uint)PermissionMask.Modify;
634
635 item.BasePermissions = perms & objlist[0].RootPart.NextOwnerMask;
636 item.CurrentPermissions = item.BasePermissions;
637 item.NextPermissions = perms & objlist[0].RootPart.NextOwnerMask;
638 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & objlist[0].RootPart.NextOwnerMask;
639 item.GroupPermissions = objlist[0].RootPart.GroupMask & objlist[0].RootPart.NextOwnerMask;
640
641 item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
642 }
643 else
644 { 768 {
645 item.BasePermissions = effectivePerms; 769 SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
646 item.CurrentPermissions = effectivePerms; 770
647 item.NextPermissions = objlist[0].RootPart.NextOwnerMask & effectivePerms; 771 objlist.Add(g);
648 item.EveryOnePermissions = objlist[0].RootPart.EveryoneMask & effectivePerms; 772 XmlElement el = (XmlElement)n;
649 item.GroupPermissions = objlist[0].RootPart.GroupMask & effectivePerms; 773
650 774 string rawX = el.GetAttribute("offsetx");
651 item.CurrentPermissions &= 775 string rawY = el.GetAttribute("offsety");
652 ((uint)PermissionMask.Copy | 776 string rawZ = el.GetAttribute("offsetz");
653 (uint)PermissionMask.Transfer | 777//
654 (uint)PermissionMask.Modify | 778// m_log.DebugFormat(
655 (uint)PermissionMask.Move | 779// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>",
656 7); // Preserve folded permissions 780// g.Name, rawX, rawY, rawZ);
781
782 float x = Convert.ToSingle(rawX);
783 float y = Convert.ToSingle(rawY);
784 float z = Convert.ToSingle(rawZ);
785 veclist.Add(new Vector3(x, y, z));
657 } 786 }
787 }
658 788
659 item.CreationDate = Util.UnixTimeSinceEpoch(); 789 if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, attachment))
660 item.Description = asset.Description; 790 return null;
661 item.Name = asset.Name;
662 item.AssetType = asset.Type;
663 791
664 m_Scene.AddInventoryItem(item); 792 for (int i = 0; i < objlist.Count; i++)
793 {
794 group = objlist[i];
665 795
666 if (remoteClient != null && item.Owner == remoteClient.AgentId) 796// Vector3 storedPosition = group.AbsolutePosition;
797 if (group.UUID == UUID.Zero)
667 { 798 {
668 remoteClient.SendInventoryItemCreateUpdate(item, 0); 799 m_log.Debug("[InventoryAccessModule]: Object has UUID.Zero! Position 3");
669 } 800 }
670 else 801
802 if (!attachment)
671 { 803 {
672 ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner); 804 // If it's rezzed in world, select it. Much easier to
673 if (notifyUser != null) 805 // find small items.
806 //
807 foreach (SceneObjectPart part in group.Parts)
674 { 808 {
675 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0); 809 part.CreateSelected = true;
676 } 810 }
677 } 811 }
812
813 group.ResetIDs();
814
815 if (attachment)
816 {
817 group.RootPart.Flags |= PrimFlags.Phantom;
818 group.IsAttachment = true;
819 }
820
821 // If we're rezzing an attachment then don't ask
822 // AddNewSceneObject() to update the client since
823 // we'll be doing that later on. Scheduling more than
824 // one full update during the attachment
825 // process causes some clients to fail to display the
826 // attachment properly.
827 m_Scene.AddNewSceneObject(group, true, false);
828
829 // if attachment we set it's asset id so object updates
830 // can reflect that, if not, we set it's position in world.
831 if (!attachment)
832 {
833 group.ScheduleGroupForFullUpdate();
834
835 group.AbsolutePosition = pos + veclist[i];
836 }
837
838 SceneObjectPart rootPart = group.RootPart;
839
840 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
841
842 if (!attachment)
843 {
844 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
845 group.ClearPartAttachmentData();
846
847 // Fire on_rez
848 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
849 rootPart.ParentGroup.ResumeScripts();
850
851 rootPart.ScheduleFullUpdate();
852 }
853
854// m_log.DebugFormat(
855// "[InventoryAccessModule]: Rezzed {0} {1} {2} for {3}",
856// group.Name, group.LocalId, group.UUID, remoteClient.Name);
678 } 857 }
679 858
680 // This is a hook to do some per-asset post-processing for subclasses that need that 859 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
681 if (remoteClient != null) 860 // TODO: Remove the magic number badness
682 ExportAsset(remoteClient.AgentId, assetID); 861 if (item != null)
683 862 DoPostRezWhenFromItem(item, attachment);
684 return assetID;
685 }
686 863
687 protected virtual void ExportAsset(UUID agentID, UUID assetID) 864 if ((rootPart.OwnerID != item.Owner) ||
688 { 865 (item.CurrentPermissions & 16) != 0 || // Magic number
689 // nothing to do here 866 (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)
867 {
868 //Need to kill the for sale here
869 rootPart.ObjectSaleType = 0;
870 rootPart.SalePrice = 10;
871
872 return group;
690 } 873 }
691 874
692 /// <summary> 875 /// <summary>
693 /// Rez an object into the scene from the user's inventory 876 /// Do pre-rez processing when the object comes from an item.
694 /// </summary> 877 /// </summary>
695 /// FIXME: It would be really nice if inventory access modules didn't also actually do the work of rezzing
696 /// things to the scene. The caller should be doing that, I think.
697 /// <param name="remoteClient"></param> 878 /// <param name="remoteClient"></param>
698 /// <param name="itemID"></param> 879 /// <param name="item"></param>
699 /// <param name="RayEnd"></param> 880 /// <param name="objlist"></param>
700 /// <param name="RayStart"></param> 881 /// <param name="pos"></param>
701 /// <param name="RayTargetID"></param> 882 /// <param name="isAttachment"></param>
702 /// <param name="BypassRayCast"></param> 883 /// <returns>true if we can processed with rezzing, false if we need to abort</returns>
703 /// <param name="RayEndIsIntersection"></param> 884 private bool DoPreRezWhenFromItem(
704 /// <param name="RezSelected"></param> 885 IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment)
705 /// <param name="RemoveItem"></param>
706 /// <param name="fromTaskID"></param>
707 /// <param name="attachment"></param>
708 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns>
709 public virtual SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
710 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
711 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
712 { 886 {
713 // Work out position details 887 UUID fromUserInventoryItemId = UUID.Zero;
714 byte bRayEndIsIntersection = (byte)0;
715 888
716 if (RayEndIsIntersection) 889 // If we have permission to copy then link the rezzed object back to the user inventory
890 // item that it came from. This allows us to enable 'save object to inventory'
891 if (!m_Scene.Permissions.BypassPermissions())
717 { 892 {
718 bRayEndIsIntersection = (byte)1; 893 if ((item.CurrentPermissions & (uint)PermissionMask.Copy)
894 == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
895 {
896 fromUserInventoryItemId = item.ID;
897 }
719 } 898 }
720 else 899 else
721 { 900 {
722 bRayEndIsIntersection = (byte)0; 901 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
902 {
903 // Brave new fullperm world
904 fromUserInventoryItemId = item.ID;
905 }
723 } 906 }
724 907
725 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); 908 int primcount = 0;
909 foreach (SceneObjectGroup g in objlist)
910 primcount += g.PrimCount;
726 911
912 if (!m_Scene.Permissions.CanRezObject(
913 primcount, remoteClient.AgentId, pos)
914 && !isAttachment)
915 {
916 // The client operates in no fail mode. It will
917 // have already removed the item from the folder
918 // if it's no copy.
919 // Put it back if it's not an attachment
920 //
921 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
922 remoteClient.SendBulkUpdateInventory(item);
727 923
728 Vector3 pos = m_Scene.GetNewRezLocation( 924 return false;
729 RayStart, RayEnd, RayTargetID, Quaternion.Identity, 925 }
730 BypassRayCast, bRayEndIsIntersection, true, scale, false);
731
732 // Rez object
733 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
734 item = m_Scene.InventoryService.GetItem(item);
735 926
736 if (item != null) 927 for (int i = 0; i < objlist.Count; i++)
737 { 928 {
738 if (item.ID == UUID.Zero) 929 SceneObjectGroup so = objlist[i];
930 SceneObjectPart rootPart = so.RootPart;
931
932 // Since renaming the item in the inventory does not
933 // affect the name stored in the serialization, transfer
934 // the correct name from the inventory to the
935 // object itself before we rez.
936 //
937 // Only do these for the first object if we are rezzing a coalescence.
938 if (i == 0)
739 { 939 {
740 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 1"); 940 rootPart.Name = item.Name;
941 rootPart.Description = item.Description;
942 rootPart.ObjectSaleType = item.SaleType;
943 rootPart.SalePrice = item.SalePrice;
741 } 944 }
742 item.Owner = remoteClient.AgentId;
743
744 AssetBase rezAsset = m_Scene.AssetService.Get(item.AssetID.ToString());
745
746 SceneObjectGroup group = null;
747 945
748 if (rezAsset != null) 946 rootPart.FromFolderID = item.Folder;
947
948 if ((rootPart.OwnerID != item.Owner) ||
949 (item.CurrentPermissions & 16) != 0)
749 { 950 {
750 UUID itemId = UUID.Zero; 951 //Need to kill the for sale here
751 952 rootPart.ObjectSaleType = 0;
752 // If we have permission to copy then link the rezzed object back to the user inventory 953 rootPart.SalePrice = 10;
753 // item that it came from. This allows us to enable 'save object to inventory' 954
754 if (!m_Scene.Permissions.BypassPermissions()) 955 if (m_Scene.Permissions.PropagatePermissions())
755 {
756 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy && (item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
757 {
758 itemId = item.ID;
759 }
760 }
761 else
762 { 956 {
763 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) 957 foreach (SceneObjectPart part in so.Parts)
764 { 958 {
765 // Brave new fullperm world 959 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
766 itemId = item.ID; 960 {
961 part.EveryoneMask = item.EveryOnePermissions;
962 part.NextOwnerMask = item.NextPermissions;
963 }
964 part.GroupMask = 0; // DO NOT propagate here
767 } 965 }
966
967 so.ApplyNextOwnerPermissions();
768 } 968 }
969 }
970
971 foreach (SceneObjectPart part in so.Parts)
972 {
973 part.FromUserInventoryItemID = fromUserInventoryItemId;
769 974
770 if (item.ID == UUID.Zero) 975 if ((part.OwnerID != item.Owner) ||
771 { 976 (item.CurrentPermissions & 16) != 0)
772 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 2");
773 }
774
775 string xmlData = Utils.BytesToString(rezAsset.Data);
776 List<SceneObjectGroup> objlist =
777 new List<SceneObjectGroup>();
778 List<Vector3> veclist = new List<Vector3>();
779
780 XmlDocument doc = new XmlDocument();
781 doc.LoadXml(xmlData);
782 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
783 if (e == null || attachment) // Single
784 { 977 {
785 SceneObjectGroup g = 978 part.LastOwnerID = part.OwnerID;
786 SceneObjectSerializer.FromOriginalXmlFormat( 979 part.OwnerID = item.Owner;
787 itemId, xmlData); 980 part.Inventory.ChangeInventoryOwner(item.Owner);
788 objlist.Add(g); 981 part.GroupMask = 0; // DO NOT propagate here
789 veclist.Add(new Vector3(0, 0, 0));
790
791 float offsetHeight = 0;
792 pos = m_Scene.GetNewRezLocation(
793 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
794 BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false);
795 pos.Z += offsetHeight;
796 } 982 }
797 else 983 part.EveryoneMask = item.EveryOnePermissions;
798 { 984 part.NextOwnerMask = item.NextPermissions;
799 XmlElement coll = (XmlElement)e; 985 }
800 float bx = Convert.ToSingle(coll.GetAttribute("x")); 986
801 float by = Convert.ToSingle(coll.GetAttribute("y")); 987 rootPart.TrimPermissions();
802 float bz = Convert.ToSingle(coll.GetAttribute("z"));
803 Vector3 bbox = new Vector3(bx, by, bz);
804
805 pos = m_Scene.GetNewRezLocation(RayStart, RayEnd,
806 RayTargetID, Quaternion.Identity,
807 BypassRayCast, bRayEndIsIntersection, true,
808 bbox, false);
809
810 pos -= bbox / 2;
811 988
812 XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); 989 if (isAttachment)
813 foreach (XmlNode n in groups) 990 so.SetFromItemID(item.ID);
814 { 991 }
815 SceneObjectGroup g =
816 SceneObjectSerializer.FromOriginalXmlFormat(
817 itemId, n.OuterXml);
818 objlist.Add(g);
819 XmlElement el = (XmlElement)n;
820 float x = Convert.ToSingle(el.GetAttribute("offsetx"));
821 float y = Convert.ToSingle(el.GetAttribute("offsety"));
822 float z = Convert.ToSingle(el.GetAttribute("offsetz"));
823 veclist.Add(new Vector3(x, y, z));
824 }
825 }
826 992
827 int primcount = 0; 993 return true;
828 foreach (SceneObjectGroup g in objlist) 994 }
829 primcount += g.PrimCount;
830 995
831 if (!m_Scene.Permissions.CanRezObject( 996 /// <summary>
832 primcount, remoteClient.AgentId, pos) 997 /// Do post-rez processing when the object comes from an item.
833 && !attachment) 998 /// </summary>
999 /// <param name="item"></param>
1000 /// <param name="isAttachment"></param>
1001 private void DoPostRezWhenFromItem(InventoryItemBase item, bool isAttachment)
1002 {
1003 if (!m_Scene.Permissions.BypassPermissions())
1004 {
1005 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1006 {
1007 // If this is done on attachments, no
1008 // copy ones will be lost, so avoid it
1009 //
1010 if (!isAttachment)
834 { 1011 {
835 // The client operates in no fail mode. It will 1012 List<UUID> uuids = new List<UUID>();
836 // have already removed the item from the folder 1013 uuids.Add(item.ID);
837 // if it's no copy. 1014 m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
838 // Put it back if it's not an attachment
839 //
840 if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment))
841 remoteClient.SendBulkUpdateInventory(item);
842 return null;
843 } 1015 }
844 1016 }
845 for (int i = 0 ; i < objlist.Count ; i++ ) 1017 }
846 { 1018 if ((rootPart.OwnerID != item.Owner) ||
847 group = objlist[i];
848
849 Vector3 storedPosition = group.AbsolutePosition;
850 if (group.UUID == UUID.Zero)
851 {
852 m_log.Debug("[InventoryAccessModule]: Inventory object has UUID.Zero! Position 3");
853 }
854 group.RootPart.FromFolderID = item.Folder;
855
856 // If it's rezzed in world, select it. Much easier to
857 // find small items.
858 //
859 if (!attachment)
860 {
861 group.RootPart.CreateSelected = true;
862 foreach (SceneObjectPart child in group.Parts)
863 child.CreateSelected = true;
864 }
865
866 group.ResetIDs();
867
868 if (attachment)
869 {
870 group.RootPart.Flags |= PrimFlags.Phantom;
871 group.RootPart.IsAttachment = true;
872
873 // If we're rezzing an attachment then don't ask
874 // AddNewSceneObject() to update the client since
875 // we'll be doing that later on. Scheduling more
876 // than one full update during the attachment
877 // process causes some clients to fail to display
878 // the attachment properly.
879 // Also, don't persist attachments.
880 m_Scene.AddNewSceneObject(group, false, false);
881 }
882 else
883 {
884 m_Scene.AddNewSceneObject(group, true, false);
885 }
886
887 // if attachment we set it's asset id so object updates
888 // can reflect that, if not, we set it's position in world.
889 if (!attachment)
890 {
891 group.ScheduleGroupForFullUpdate();
892
893 group.AbsolutePosition = pos + veclist[i];
894 }
895 else
896 {
897 group.SetFromItemID(itemID);
898 }
899
900 SceneObjectPart rootPart = null;
901
902 try
903 {
904 rootPart = group.GetChildPart(group.UUID);
905 }
906 catch (NullReferenceException)
907 {
908 string isAttachment = "";
909
910 if (attachment)
911 isAttachment = " Object was an attachment";
912
913 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment);
914 }
915
916 // Since renaming the item in the inventory does not
917 // affect the name stored in the serialization, transfer
918 // the correct name from the inventory to the
919 // object itself before we rez.
920 // On coalesced objects, do the first one
921 if (((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) || i == 0)
922 {
923 rootPart.Name = item.Name;
924 rootPart.Description = item.Description;
925 }
926 if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0)
927 {
928 rootPart.ObjectSaleType = item.SaleType;
929 rootPart.SalePrice = item.SalePrice;
930 }
931
932 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
933 // TODO: Remove the magic number badness
934
935 if ((rootPart.OwnerID != item.Owner) ||
936 (item.CurrentPermissions & 16) != 0 || // Magic number 1019 (item.CurrentPermissions & 16) != 0 || // Magic number
937 (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) 1020 (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0)
938 { 1021 {
939 //Need to kill the for sale here 1022 //Need to kill the for sale here
940 rootPart.ObjectSaleType = 0; 1023 rootPart.ObjectSaleType = 0;
941 rootPart.SalePrice = 10; 1024 rootPart.SalePrice = 10;
942 1025
943 if (m_Scene.Permissions.PropagatePermissions()) 1026 if (m_Scene.Permissions.PropagatePermissions())
944 { 1027 {
945 foreach (SceneObjectPart part in group.Parts) 1028 foreach (SceneObjectPart part in group.Parts)
946 { 1029 {
@@ -965,58 +1048,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
965 group.ApplyNextOwnerPermissions(); 1048 group.ApplyNextOwnerPermissions();
966 } 1049 }
967 } 1050 }
968 1051 foreach (SceneObjectPart part in group.Parts)
969 foreach (SceneObjectPart part in group.Parts) 1052 {
970 { 1053 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
971 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) 1054 part.EveryoneMask = item.EveryOnePermissions;
972 part.EveryoneMask = item.EveryOnePermissions; 1055 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
973 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) 1056 part.NextOwnerMask = item.NextPermissions;
974 part.NextOwnerMask = item.NextPermissions; 1057 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
975 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) 1058 part.GroupMask = item.GroupPermissions;
976 part.GroupMask = item.GroupPermissions;
977 }
978
979 rootPart.TrimPermissions();
980
981 if (!attachment)
982 {
983 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
984 {
985 // Save attachment data
986 group.RootPart.AttachPoint = group.RootPart.Shape.State;
987 group.RootPart.AttachOffset = storedPosition;
988
989 group.ClearPartAttachmentData();
990 }
991
992 // Fire on_rez
993 group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1);
994 rootPart.ParentGroup.ResumeScripts();
995
996 rootPart.ScheduleFullUpdate();
997 }
998 }
999
1000 if (!m_Scene.Permissions.BypassPermissions())
1001 {
1002 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1003 {
1004 // If this is done on attachments, no
1005 // copy ones will be lost, so avoid it
1006 //
1007 if (!attachment)
1008 {
1009 List<UUID> uuids = new List<UUID>();
1010 uuids.Add(item.ID);
1011 m_Scene.InventoryService.DeleteItems(item.Owner, uuids);
1012 }
1013 }
1014 }
1015 }
1016 return group;
1017 } 1059 }
1018
1019 return null;
1020 } 1060 }
1021 1061
1022 protected void AddUserData(SceneObjectGroup sog) 1062 protected void AddUserData(SceneObjectGroup sog)
@@ -1033,11 +1073,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1033 public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID) 1073 public virtual bool CanGetAgentInventoryItem(IClientAPI remoteClient, UUID itemID, UUID requestID)
1034 { 1074 {
1035 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID); 1075 InventoryItemBase assetRequestItem = GetItem(remoteClient.AgentId, itemID);
1076
1036 if (assetRequestItem == null) 1077 if (assetRequestItem == null)
1037 { 1078 {
1038 ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>(); 1079 ILibraryService lib = m_Scene.RequestModuleInterface<ILibraryService>();
1080
1039 if (lib != null) 1081 if (lib != null)
1040 assetRequestItem = lib.LibraryRootFolder.FindItem(itemID); 1082 assetRequestItem = lib.LibraryRootFolder.FindItem(itemID);
1083
1041 if (assetRequestItem == null) 1084 if (assetRequestItem == null)
1042 return false; 1085 return false;
1043 } 1086 }
@@ -1068,6 +1111,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
1068 m_log.WarnFormat( 1111 m_log.WarnFormat(
1069 "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", 1112 "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}",
1070 Name, requestID, itemID, assetRequestItem.AssetID); 1113 Name, requestID, itemID, assetRequestItem.AssetID);
1114
1071 return false; 1115 return false;
1072 } 1116 }
1073 1117