/// <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> /// Load an asset /// </summary> /// <param name="assetFilename"></param> /// <param name="data"></param> /// <returns>true if asset was successfully loaded, false otherwise</returns> private bool LoadAsset(string assetPath, byte[] data) { //IRegionSerialiser serialiser = scene.RequestModuleInterface<IRegionSerialiser>(); // Right now we're nastily obtaining the UUID from the filename string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length); int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR); if (i == -1) { m_log.ErrorFormat( "[INVENTORY ARCHIVER]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping", assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR); return(false); } string extension = filename.Substring(i); string rawUuid = filename.Remove(filename.Length - extension.Length); UUID assetId = new UUID(rawUuid); if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension)) { sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; if (assetType == (sbyte)AssetType.Unknown) { m_log.WarnFormat("[INVENTORY ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, assetId); } else if (assetType == (sbyte)AssetType.Object) { if (m_creatorIdForAssetId.ContainsKey(assetId)) { string xmlData = Utils.BytesToString(data); List <SceneObjectGroup> sceneObjects = new List <SceneObjectGroup>(); CoalescedSceneObjects coa = null; if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa)) { // m_log.DebugFormat( // "[INVENTORY ARCHIVER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count); if (coa.Objects.Count == 0) { m_log.WarnFormat( "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of coalesced object from asset {0} as it has zero loaded components", assetId); return(false); } sceneObjects.AddRange(coa.Objects); } else { SceneObjectGroup deserializedObject = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); if (deserializedObject != null) { sceneObjects.Add(deserializedObject); } else { m_log.WarnFormat( "[INVENTORY ARCHIVE READ REQUEST]: Aborting load of object from asset {0} as deserialization failed", assetId); return(false); } } foreach (SceneObjectGroup sog in sceneObjects) { foreach (SceneObjectPart sop in sog.Parts) { if (string.IsNullOrEmpty(sop.CreatorData)) { sop.CreatorID = m_creatorIdForAssetId[assetId]; } } } if (coa != null) { data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa)); } else { data = Utils.StringToBytes(SceneObjectSerializer.ToOriginalXmlFormat(sceneObjects[0])); } } } //m_log.DebugFormat("[INVENTORY ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); AssetBase asset = new AssetBase(assetId, "From IAR", assetType, UUID.Zero.ToString()); asset.Data = data; m_AssetService.Store(asset); return(true); } else { m_log.ErrorFormat( "[INVENTORY ARCHIVER]: Tried to dearchive data with path {0} with an unknown type extension {1}", assetPath, extension); return(false); } }
/// <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); }
/// <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 <SceneObjectGroup, KeyframeMotion> group2Keyframe = new Dictionary <SceneObjectGroup, KeyframeMotion>(); foreach (SceneObjectGroup objectGroup in objlist) { if (objectGroup.RootPart.KeyframeMotion != null) { objectGroup.RootPart.KeyframeMotion.Pause(); group2Keyframe.Add(objectGroup, objectGroup.RootPart.KeyframeMotion); 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); } 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; 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); } } } // Restore KeyframeMotion foreach (SceneObjectGroup objectGroup in group2Keyframe.Keys) { objectGroup.RootPart.KeyframeMotion = group2Keyframe[objectGroup]; objectGroup.RootPart.KeyframeMotion.Start(); } // 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); }