/// <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); }
/// <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; }