/// <summary>
        /// Serialize coalesced objects to Xml
        /// </summary>
        /// <param name="coa"></param>
        /// <param name="doScriptStates">
        /// If true then serialize script states.  This will halt any running scripts
        /// </param>
        /// <returns></returns>
        public static string ToXml(CoalescedSceneObjects coa, bool doScriptStates)
        {            
            using (StringWriter sw = new StringWriter())
            {
                using (XmlTextWriter writer = new XmlTextWriter(sw))
                {                                        
                    Vector3 size;
                    
                    List<SceneObjectGroup> coaObjects = coa.Objects;
                    
//                    m_log.DebugFormat(
//                        "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", 
//                        coaObjects.Count);
                    
                    // This is weak - we're relying on the set of coalesced objects still being identical
                    Vector3[] offsets = coa.GetSizeAndOffsets(out size);

                    writer.WriteStartElement("CoalescedObject");
                    
                    writer.WriteAttributeString("x", size.X.ToString());
                    writer.WriteAttributeString("y", size.Y.ToString());
                    writer.WriteAttributeString("z", size.Z.ToString());                    
                    
                    // Embed the offsets into the group XML
                    for (int i = 0; i < coaObjects.Count; i++)
                    {
                        SceneObjectGroup obj = coaObjects[i];
                        
//                        m_log.DebugFormat(
//                            "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", 
//                            i, obj.Name);                        
                        
                        writer.WriteStartElement("SceneObjectGroup");
                        writer.WriteAttributeString("offsetx", offsets[i].X.ToString());
                        writer.WriteAttributeString("offsety", offsets[i].Y.ToString());
                        writer.WriteAttributeString("offsetz", offsets[i].Z.ToString());
                        
                        SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, doScriptStates);
                        
                        writer.WriteEndElement(); // SceneObjectGroup
                    }  
                    
                    writer.WriteEndElement(); // CoalescedObject
                }

                string output = sw.ToString();
                
//                Console.WriteLine(output);
                
                return output;
            }
        }
        protected void ConstructDefaultIarBytesForTestLoad()
        {
//            log4net.Config.XmlConfigurator.Configure();
            
            InventoryArchiverModule archiverModule = new InventoryArchiverModule();
            Scene scene = SceneSetupHelpers.SetupScene();
            SceneSetupHelpers.SetupSceneModules(scene, archiverModule);            
            
            UserProfileTestUtils.CreateUserWithInventory(scene, m_uaLL1, "hampshire");

            MemoryStream archiveWriteStream = new MemoryStream();
            
            // Create scene object asset
            UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
            SceneObjectGroup object1 = SceneSetupHelpers.CreateSceneObject(1, ownerId, "Ray Gun Object", 0x50);         

            UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
            AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1);
            scene.AssetService.Store(asset1);            

            // Create scene object item
            InventoryItemBase item1 = new InventoryItemBase();
            item1.Name = m_item1Name;
            item1.ID = UUID.Parse("00000000-0000-0000-0000-000000000020");            
            item1.AssetID = asset1.FullID;
            item1.GroupID = UUID.Random();
            item1.CreatorIdAsUuid = m_uaLL1.PrincipalID;
            item1.Owner = m_uaLL1.PrincipalID;
            item1.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID;            
            scene.AddInventoryItem(item1);
            
            // Create coalesced objects asset
            SceneObjectGroup cobj1 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object1", 0x120);
            cobj1.AbsolutePosition = new Vector3(15, 30, 45);
            
            SceneObjectGroup cobj2 = SceneSetupHelpers.CreateSceneObject(1, m_uaLL1.PrincipalID, "Object2", 0x140);
            cobj2.AbsolutePosition = new Vector3(25, 50, 75);               
            
            CoalescedSceneObjects coa = new CoalescedSceneObjects(m_uaLL1.PrincipalID, cobj1, cobj2);
            
            AssetBase coaAsset = AssetHelpers.CreateAsset(0x160, coa);
            scene.AssetService.Store(coaAsset);            
            
            // Create coalesced objects inventory item
            InventoryItemBase coaItem = new InventoryItemBase();
            coaItem.Name = m_coaItemName;
            coaItem.ID = UUID.Parse("00000000-0000-0000-0000-000000000180");            
            coaItem.AssetID = coaAsset.FullID;
            coaItem.GroupID = UUID.Random();
            coaItem.CreatorIdAsUuid = m_uaLL1.PrincipalID;
            coaItem.Owner = m_uaLL1.PrincipalID;
            coaItem.Folder = scene.InventoryService.GetRootFolder(m_uaLL1.PrincipalID).ID;            
            scene.AddInventoryItem(coaItem);            
            
            archiverModule.ArchiveInventory(
                Guid.NewGuid(), m_uaLL1.FirstName, m_uaLL1.LastName, "/*", "hampshire", archiveWriteStream);            
            
            m_iarStreamBytes = archiveWriteStream.ToArray();
        }
        public void TestRezCoalescedObject()
        {
            TestHelpers.InMethod();
//            log4net.Config.XmlConfigurator.Configure();
            
            // Create asset
            SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20);
            object1.AbsolutePosition = new Vector3(15, 30, 45);
            
            SceneObjectGroup object2 = SceneHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40);
            object2.AbsolutePosition = new Vector3(25, 50, 75);                 
            
            CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2);

            UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
            AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, coa);
            m_scene.AssetService.Store(asset1);

            // Create item
            UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
            string item1Name = "My Little Dog";
            InventoryItemBase item1 = new InventoryItemBase();
            item1.Name = item1Name;
            item1.AssetID = asset1.FullID;
            item1.ID = item1Id;
            InventoryFolderBase objsFolder 
                = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0];
            item1.Folder = objsFolder.ID;
            m_scene.AddInventoryItem(item1);
            
            SceneObjectGroup so 
                = m_iam.RezObject(
                    m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false);            
            
            Assert.That(so, Is.Not.Null);
            
            Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2));
          
            SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name);
            Assert.That(retrievedObj1Part, Is.Null);
            
            retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name);
            Assert.That(retrievedObj1Part, Is.Not.Null);
            Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name));
            
            // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom
            // object is unit square.
            Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f)));
            
            SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name);
            Assert.That(retrievedObj2Part, Is.Not.Null);            
            Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name));
            Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f)));
        }        
        public static bool TryFromXml(string xml, out CoalescedSceneObjects coa)
        {
//            m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
            
            coa = null;
            
            using (StringReader sr = new StringReader(xml))
            {                
                using (XmlTextReader reader = new XmlTextReader(sr))
                {
                    try
                    {
                        reader.Read();
                        if (reader.Name != "CoalescedObject")
                        {
    //                        m_log.DebugFormat(
    //                            "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", 
    //                            reader.Name);
                            
                            return false;
                        }
                        
                        coa = new CoalescedSceneObjects(UUID.Zero);                    
                        reader.Read();                                            
                        
                        while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject")
                        {
                            if (reader.Name == "SceneObjectGroup")
                            {
                                string soXml = reader.ReadOuterXml();
                                coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml));
                            }
                        }
                        
                        reader.ReadEndElement(); // CoalescedObject
                    }
                    catch (Exception e)
                    {
                        m_log.ErrorFormat(
                            "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", 
                            e.Message, e.StackTrace);
                        
                        return false;
                    }                        
                }
            }
            
            return true;
        }
 /// <summary>
 /// Serialize coalesced objects to Xml
 /// </summary>
 /// <param name="coa"></param>
 /// <param name="doScriptStates">
 /// If true then serialize script states.  This will halt any running scripts
 /// </param>
 /// <returns></returns>
 public static string ToXml(CoalescedSceneObjects coa)
 {
     return ToXml(coa, true);
 }
 /// <summary>
 /// Create an asset from the given scene object.
 /// </summary>
 /// <param name="assetUuidTailZ">
 /// The hexadecimal last part of the UUID for the asset created.  A UUID of the form "00000000-0000-0000-0000-{0:XD12}"
 /// will be used.
 /// </param>
 /// <param name="coa"></param>
 /// <returns></returns>
 public static AssetBase CreateAsset(int assetUuidTail, CoalescedSceneObjects coa)
 {
     return CreateAsset(new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", assetUuidTail)), coa);
 } 
 /// <summary>
 /// Create an asset from the given scene object.
 /// </summary>
 /// <param name="assetUuid"></param>
 /// <param name="coa"></param>
 /// <returns></returns>
 public static AssetBase CreateAsset(UUID assetUuid, CoalescedSceneObjects coa)
 {
     return CreateAsset(
         assetUuid, 
         AssetType.Object, 
         Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)), 
         coa.CreatorId);
 }         
示例#8
0
        /// <summary>
        /// Copy a bundle of objects to inventory.  If there is only one object, then this will create an object
        /// item.  If there are multiple objects then these will be saved as a single coalesced item.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="folderID"></param>
        /// <param name="objlist"></param>
        /// <param name="remoteClient"></param>
        /// <param name="asAttachment">Should be true if the bundle is being copied as an attachment.  This prevents
        /// attempted serialization of any script state which would abort any operating scripts.</param>
        /// <returns>The inventory item created by the copy</returns>
        protected InventoryItemBase CopyBundleToInventory(
            DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient,
            bool asAttachment)
        {
            CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);                
//            Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();

            foreach (SceneObjectGroup objectGroup in objlist)
            {
                if (objectGroup.RootPart.KeyframeMotion != null)
                    objectGroup.RootPart.KeyframeMotion.Stop();
                objectGroup.RootPart.KeyframeMotion = null;
//                Vector3 inventoryStoredPosition = new Vector3
//                            (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
//                                  ? 250
//                                  : objectGroup.AbsolutePosition.X)
//                             ,
//                             (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
//                                 ? 250
//                                 : objectGroup.AbsolutePosition.Y,
//                             objectGroup.AbsolutePosition.Z);
//
//                originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;
//
//                objectGroup.AbsolutePosition = inventoryStoredPosition;

                // Make sure all bits but the ones we want are clear
                // on take.
                // This will be applied to the current perms, so
                // it will do what we want.
                objectGroup.RootPart.NextOwnerMask &=
                        ((uint)PermissionMask.Copy |
                         (uint)PermissionMask.Transfer |
                         (uint)PermissionMask.Modify |
                         (uint)PermissionMask.Export);
                objectGroup.RootPart.NextOwnerMask |=
                        (uint)PermissionMask.Move;
                
                coa.Add(objectGroup);
            }

            string itemXml;

            // If we're being called from a script, then trying to serialize that same script's state will not complete
            // in any reasonable time period.  Therefore, we'll avoid it.  The worst that can happen is that if
            // the client/server crashes rather than logging out normally, the attachment's scripts will resume
            // without state on relog.  Arguably, this is what we want anyway.
            if (objlist.Count > 1)
                itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment);
            else
                itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
            
//            // Restore the position of each group now that it has been stored to inventory.
//            foreach (SceneObjectGroup objectGroup in objlist)
//                objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];

            InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);

//            m_log.DebugFormat(
//                "[INVENTORY ACCESS MODULE]: Created item is {0}",
//                item != null ? item.ID.ToString() : "NULL");

            if (item == null)
                return null;
                            
            // Can't know creator is the same, so null it in inventory
            if (objlist.Count > 1)
            {
                item.CreatorId = UUID.Zero.ToString();
                item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
            }
            else
            {
                item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
                item.CreatorData = objlist[0].RootPart.CreatorData;
                item.SaleType = objlist[0].RootPart.ObjectSaleType;
                item.SalePrice = objlist[0].RootPart.SalePrice;                    
            }              

            AssetBase asset = CreateAsset(
                objlist[0].GetPartName(objlist[0].RootPart.LocalId),
                objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
                (sbyte)AssetType.Object,
                Utils.StringToBytes(itemXml),
                objlist[0].OwnerID.ToString());
            m_Scene.AssetService.Store(asset);
            
            item.AssetID = asset.FullID;

            if (DeRezAction.SaveToExistingUserInventoryItem == action)
            {
                m_Scene.InventoryService.UpdateItem(item);
            }
            else
            {
                AddPermissions(item, objlist[0], objlist, remoteClient);

                item.CreationDate = Util.UnixTimeSinceEpoch();
                item.Description = asset.Description;
                item.Name = asset.Name;
                item.AssetType = asset.Type;

                m_Scene.AddInventoryItem(item);

                if (remoteClient != null && item.Owner == remoteClient.AgentId)
                {
                    remoteClient.SendInventoryItemCreateUpdate(item, 0);
                }
                else
                {
                    ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
                    if (notifyUser != null)
                    {
                        notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
                    }
                }
            }

            // This is a hook to do some per-asset post-processing for subclasses that need that
            if (remoteClient != null)
                ExportAsset(remoteClient.AgentId, asset.FullID);
            
            return item;
        }
        /// <summary>
        /// Copy a bundle of objects to inventory.  If there is only one object, then this will create an object
        /// item.  If there are multiple objects then these will be saved as a single coalesced item.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="folderID"></param>
        /// <param name="objlist"></param>
        /// <param name="remoteClient"></param>
        /// <returns></returns>
        protected UUID CopyBundleToInventory(
            DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient)
        {
            UUID assetID = UUID.Zero;
            
            CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);                
            Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();

            foreach (SceneObjectGroup objectGroup in objlist)
            {
                Vector3 inventoryStoredPosition = new Vector3
                            (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize)
                                  ? 250
                                  : objectGroup.AbsolutePosition.X)
                             ,
                             (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize)
                                 ? 250
                                 : objectGroup.AbsolutePosition.Y,
                             objectGroup.AbsolutePosition.Z);

                originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition;

                objectGroup.AbsolutePosition = inventoryStoredPosition;

                // Make sure all bits but the ones we want are clear
                // on take.
                // This will be applied to the current perms, so
                // it will do what we want.
                objectGroup.RootPart.NextOwnerMask &=
                        ((uint)PermissionMask.Copy |
                         (uint)PermissionMask.Transfer |
                         (uint)PermissionMask.Modify);
                objectGroup.RootPart.NextOwnerMask |=
                        (uint)PermissionMask.Move;
                
                coa.Add(objectGroup);
            }

            string itemXml;

            if (objlist.Count > 1)
                itemXml = CoalescedSceneObjectsSerializer.ToXml(coa);
            else
                itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]);
            
            // Restore the position of each group now that it has been stored to inventory.
            foreach (SceneObjectGroup objectGroup in objlist)
                objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];

            InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);
            if (item == null)
                return UUID.Zero;
                            
            // Can't know creator is the same, so null it in inventory
            if (objlist.Count > 1)
            {
                item.CreatorId = UUID.Zero.ToString();
                item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
            }
            else
            {
                item.CreatorId = objlist[0].RootPart.CreatorID.ToString();                
                item.SaleType = objlist[0].RootPart.ObjectSaleType;
                item.SalePrice = objlist[0].RootPart.SalePrice;                    
            }              

            AssetBase asset = CreateAsset(
                objlist[0].GetPartName(objlist[0].RootPart.LocalId),
                objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
                (sbyte)AssetType.Object,
                Utils.StringToBytes(itemXml),
                objlist[0].OwnerID.ToString());
            m_Scene.AssetService.Store(asset);
            
            item.AssetID = asset.FullID;  
            assetID = asset.FullID;                              

            if (DeRezAction.SaveToExistingUserInventoryItem == action)
            {
                m_Scene.InventoryService.UpdateItem(item);
            }
            else
            {
                AddPermissions(item, objlist[0], objlist, remoteClient);

                item.CreationDate = Util.UnixTimeSinceEpoch();
                item.Description = asset.Description;
                item.Name = asset.Name;
                item.AssetType = asset.Type;

                m_Scene.AddInventoryItem(item);

                if (remoteClient != null && item.Owner == remoteClient.AgentId)
                {
                    remoteClient.SendInventoryItemCreateUpdate(item, 0);
                }
                else
                {
                    ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
                    if (notifyUser != null)
                    {
                        notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
                    }
                }
            }

            // This is a hook to do some per-asset post-processing for subclasses that need that
            ExportAsset(remoteClient.AgentId, assetID);
            
            return assetID;
        }
        public static bool TryFromXml(string xml, out CoalescedSceneObjects coa)
        {
//            m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
            
            coa = null;
            
            try
            {
                // Quickly check if this is a coalesced object, without fully parsing the XML
                using (StringReader sr = new StringReader(xml))
                {                
                    using (XmlTextReader reader = new XmlTextReader(sr))
                    {
                        reader.MoveToContent(); // skip possible xml declaration

                        if (reader.Name != "CoalescedObject")
                        {
    //                        m_log.DebugFormat(
    //                            "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", 
    //                            reader.Name);
                            
                            return false;
                        }
                    }
                }

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xml);
                XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
                if (e == null)
                    return false;
                        
                coa = new CoalescedSceneObjects(UUID.Zero);

                XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
                int i = 0;
                
                foreach (XmlNode n in groups)
                {
                    SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
                    if (so != null)
                    {
                        coa.Add(so);
                    }
                    else
                    {
                        // XXX: Possibly we should fail outright here rather than continuing if a particular component of the 
                        // coalesced object fails to load.
                        m_log.WarnFormat(
                            "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed.  Continuing.", 
                            i);
                    }

                    i++;
                }
            }
            catch (Exception e)
            {
                m_log.Error("[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed ",  e);
                Util.LogFailedXML("[COALESCED SCENE OBJECTS SERIALIZER]:", xml);
                return false;
            }                        
            
            return true;
        }
        public static bool TryFromXml(string xml, out CoalescedSceneObjects coa)
        {
//            m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
            
            coa = null;
            int i = 0;
            
            using (StringReader sr = new StringReader(xml))
            {                
                using (XmlTextReader reader = new XmlTextReader(sr))
                {
                    try
                    {
                        reader.Read();
                        if (reader.Name != "CoalescedObject")
                        {
    //                        m_log.DebugFormat(
    //                            "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", 
    //                            reader.Name);
                            
                            return false;
                        }
                        
                        coa = new CoalescedSceneObjects(UUID.Zero);                    
                        reader.Read();                                            
                        
                        while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject")
                        {
                            if (reader.Name == "SceneObjectGroup")
                            {
                                string soXml = reader.ReadOuterXml();

                                SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);

                                if (so != null)
                                {
                                    coa.Add(so);
                                }
                                else
                                {
                                    // XXX: Possibly we should fail outright here rather than continuing if a particular component of the 
                                    // coalesced object fails to load.
                                    m_log.WarnFormat(
                                        "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed.  Continuing.", 
                                        i);
                                }

                                i++;
                            }
                        }
                        
                        reader.ReadEndElement(); // CoalescedObject
                    }
                    catch (Exception e)
                    {
                        m_log.ErrorFormat(
                            "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", 
                            e.Message, e.StackTrace);
                        
                        return false;
                    }                        
                }
            }
            
            return true;
        }
        /// <summary>
        /// Copy a bundle of objects to inventory.  If there is only one object, then this will create an object
        /// item.  If there are multiple objects then these will be saved as a single coalesced item.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="folderID"></param>
        /// <param name="objlist"></param>
        /// <param name="remoteClient"></param>
        /// <param name="asAttachment">Should be true if the bundle is being copied as an attachment.  This prevents
        /// attempted serialization of any script state which would abort any operating scripts.</param>
        /// <returns>The inventory item created by the copy</returns>
        protected InventoryItemBase CopyBundleToInventory(
            DeRezAction action, UUID folderID, List<SceneObjectGroup> objlist, IClientAPI remoteClient,
            bool asAttachment)
        {
            CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero);
            Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>();
            Dictionary<UUID, Quaternion> originalRotations = new Dictionary<UUID, Quaternion>();
            // this possible is not needed if keyframes are saved
            Dictionary<UUID, KeyframeMotion> originalKeyframes = new Dictionary<UUID, KeyframeMotion>();
 
            foreach (SceneObjectGroup objectGroup in objlist)
            {
                if (objectGroup.RootPart.KeyframeMotion != null)
                {
                    objectGroup.RootPart.KeyframeMotion.Suspend();
                }
                objectGroup.RootPart.SetForce(Vector3.Zero);
                objectGroup.RootPart.SetAngularImpulse(Vector3.Zero, false);

                originalKeyframes[objectGroup.UUID] = objectGroup.RootPart.KeyframeMotion;
                objectGroup.RootPart.KeyframeMotion = null;

                Vector3 inventoryStoredPosition = objectGroup.AbsolutePosition;
                originalPositions[objectGroup.UUID] = inventoryStoredPosition;
                Quaternion inventoryStoredRotation = objectGroup.GroupRotation;
                originalRotations[objectGroup.UUID] = inventoryStoredRotation;

                // Restore attachment data after trip through the sim
                if (objectGroup.RootPart.AttachPoint > 0)
                {
                    inventoryStoredPosition = objectGroup.RootPart.AttachedPos;
                    inventoryStoredRotation = objectGroup.RootPart.AttachRotation;
                }

                // Trees could be attached and it's been done, but it makes
                // no sense. State must be preserved because it's the tree type
                if (objectGroup.RootPart.Shape.PCode != (byte) PCode.Tree &&
                    objectGroup.RootPart.Shape.PCode != (byte) PCode.NewTree)
                {
                    objectGroup.RootPart.Shape.State = objectGroup.RootPart.AttachPoint;
                    if (objectGroup.RootPart.AttachPoint > 0)
                        objectGroup.RootPart.Shape.LastAttachPoint = objectGroup.RootPart.AttachPoint;
                }

                objectGroup.AbsolutePosition = inventoryStoredPosition;
                objectGroup.RootPart.RotationOffset = inventoryStoredRotation;

                // Make sure all bits but the ones we want are clear
                // on take.
                // This will be applied to the current perms, so
                // it will do what we want.
                objectGroup.RootPart.NextOwnerMask &=
                        ((uint)PermissionMask.Copy |
                         (uint)PermissionMask.Transfer |
                         (uint)PermissionMask.Modify |
                         (uint)PermissionMask.Export);
                objectGroup.RootPart.NextOwnerMask |=
                        (uint)PermissionMask.Move;
                
                coa.Add(objectGroup);
            }

            string itemXml;

            // If we're being called from a script, then trying to serialize that same script's state will not complete
            // in any reasonable time period.  Therefore, we'll avoid it.  The worst that can happen is that if
            // the client/server crashes rather than logging out normally, the attachment's scripts will resume
            // without state on relog.  Arguably, this is what we want anyway.
            if (objlist.Count > 1)
                itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment);
            else
                itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment);
            
            // Restore the position of each group now that it has been stored to inventory.
            foreach (SceneObjectGroup objectGroup in objlist)
            {
                objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID];
                objectGroup.RootPart.RotationOffset = originalRotations[objectGroup.UUID];
                objectGroup.RootPart.KeyframeMotion = originalKeyframes[objectGroup.UUID];
                if (objectGroup.RootPart.KeyframeMotion != null)
                    objectGroup.RootPart.KeyframeMotion.Resume();
            }

            InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID);

//            m_log.DebugFormat(
//                "[INVENTORY ACCESS MODULE]: Created item is {0}",
//                item != null ? item.ID.ToString() : "NULL");

            if (item == null)
                return null;

            item.CreatorId = objlist[0].RootPart.CreatorID.ToString();
            item.CreatorData = objlist[0].RootPart.CreatorData;
                            
            if (objlist.Count > 1)
            {
                item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems;
                
                // If the objects have different creators then don't specify a creator at all
                foreach (SceneObjectGroup objectGroup in objlist)
                {
                    if ((objectGroup.RootPart.CreatorID.ToString() != item.CreatorId)
                        || (objectGroup.RootPart.CreatorData.ToString() != item.CreatorData))
                    {
                        item.CreatorId = UUID.Zero.ToString();
                        item.CreatorData = string.Empty;
                        break;
                    }
                }
            }
            else
            {
                item.SaleType = objlist[0].RootPart.ObjectSaleType;
                item.SalePrice = objlist[0].RootPart.SalePrice;                    
            }              

            AssetBase asset = CreateAsset(
                objlist[0].GetPartName(objlist[0].RootPart.LocalId),
                objlist[0].GetPartDescription(objlist[0].RootPart.LocalId),
                (sbyte)AssetType.Object,
                Utils.StringToBytes(itemXml),
                objlist[0].OwnerID.ToString());
            m_Scene.AssetService.Store(asset);
            
            item.AssetID = asset.FullID;

            if (DeRezAction.SaveToExistingUserInventoryItem == action)
            {
                m_Scene.InventoryService.UpdateItem(item);
            }
            else
            {
                item.CreationDate = Util.UnixTimeSinceEpoch();
                item.Description = asset.Description;
                item.Name = asset.Name;
                item.AssetType = asset.Type;

                //preserve perms on return
                if(DeRezAction.Return == action)
                    AddPermissions(item, objlist[0], objlist, null);
                else
                    AddPermissions(item, objlist[0], objlist, remoteClient);

                m_Scene.AddInventoryItem(item);

                if (remoteClient != null && item.Owner == remoteClient.AgentId)
                {
                    remoteClient.SendInventoryItemCreateUpdate(item, 0);
                }
                else
                {
                    ScenePresence notifyUser = m_Scene.GetScenePresence(item.Owner);
                    if (notifyUser != null)
                    {
                        notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
                    }
                }
            }

            // This is a hook to do some per-asset post-processing for subclasses that need that
            if (remoteClient != null)
                ExportAsset(remoteClient.AgentId, asset.FullID);
            
            return item;
        }