From 4c2171ec827aa426375ccecf4bd2d7e009719d74 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 16 Jun 2008 21:59:39 +0000 Subject: * Allow archiver to save and load objects within other objects to arbitrary levels * This currently has various bugs which are more to do with the way its been hacked together than the feature itself (e.g. on save-oar, ghost prims will appear of the saved contained items). These will be found and eliminated in subsequent patches. * Not yet ready for use --- .../Archiver/ArchiveWriteRequestPreparation.cs | 130 ++++++++++++++++----- 1 file changed, 99 insertions(+), 31 deletions(-) (limited to 'OpenSim/Region/Environment/Modules/World/Archiver/ArchiveWriteRequestPreparation.cs') diff --git a/OpenSim/Region/Environment/Modules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/Environment/Modules/World/Archiver/ArchiveWriteRequestPreparation.cs index a93e58d..1b78f4c 100644 --- a/OpenSim/Region/Environment/Modules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/Environment/Modules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -47,64 +47,132 @@ namespace OpenSim.Region.Environment.Modules.World.Archiver private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected Scene m_scene; - protected string m_savePath; + protected string m_savePath; + + /// + /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate + /// asset was found by the asset service. + /// + protected AssetBase m_requestedObjectAsset; + + /// + /// Signal whether we are currently waiting for the asset service to deliver an asset. + /// + protected bool m_waitingForObjectAsset; + /// + /// Constructor + /// public ArchiveWriteRequestPreparation(Scene scene, string savePath) { m_scene = scene; m_savePath = savePath; } - - public void ArchiveRegion() + + /// + /// The callback made when we request the asset for an object from the asset service. + /// + public void AssetRequestCallback(LLUUID assetID, AssetBase asset) { - Dictionary assetUuids = new Dictionary(); - - List entities = m_scene.GetEntities(); - - foreach (EntityBase entity in entities) + lock (this) { - if (entity is SceneObjectGroup) + m_requestedObjectAsset = asset; + m_waitingForObjectAsset = false; + Monitor.Pulse(this); + } + } + + /// + /// Get all the asset uuids associated with a given object. This includes both those directly associated with + /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained + /// within this object). + /// + /// + /// + protected void GetSceneObjectAssetUuids(SceneObjectGroup sceneObject, IDictionary assetUuids) + { + m_log.DebugFormat( + "[ARCHIVER]: Getting assets for object {0}, {1}", sceneObject.RootPart.Name, sceneObject.UUID); + + foreach (SceneObjectPart part in sceneObject.GetParts()) + { + m_log.DebugFormat( + "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); + + // XXX: Not a great way to iterate through face textures, but there's no + // other way to tell how many faces there actually are + int i = 0; + foreach (LLObject.TextureEntryFace texture in part.Shape.Textures.FaceTextures) { - SceneObjectGroup sceneObject = (SceneObjectGroup)entity; + if (texture != null) + { + m_log.DebugFormat("[ARCHIVER]: Got face {0}", i++); + assetUuids[texture.TextureID] = 1; + } + } - foreach (SceneObjectPart part in sceneObject.GetParts()) + foreach (TaskInventoryItem tii in part.TaskInventory.Values) + { + if (!assetUuids.ContainsKey(tii.AssetID)) { - // XXX: Not a great way to iterate through face textures, but there's no - // other way to tell how many faces there actually are - //int i = 0; - foreach (LLObject.TextureEntryFace texture in part.Shape.Textures.FaceTextures) + assetUuids[tii.AssetID] = 1; + + if (tii.Type != (int)InventoryType.Object) { - if (texture != null) - { - //m_log.DebugFormat("[ARCHIVER]: Got face {0}", i++); - assetUuids[texture.TextureID] = 1; - } + m_log.DebugFormat("[ARCHIVER]: Recording asset {0} in object {1}", tii.AssetID, part.UUID); } - - foreach (TaskInventoryItem tit in part.TaskInventory.Values) + else { - if (tit.Type != (int)InventoryType.Object) + m_waitingForObjectAsset = true; + m_scene.AssetCache.GetAsset(tii.AssetID, AssetRequestCallback, true); + + // The asset cache callback can either + // + // 1. Complete on the same thread (if the asset is already in the cache) or + // 2. Come in via a different thread (if we need to go fetch it). + // + // The code below handles both these alternatives. + lock (this) { - m_log.DebugFormat("[ARCHIVER]: Recording asset {0} in object {1}", tit.AssetID, part.UUID); - assetUuids[tit.AssetID] = 1; + if (m_waitingForObjectAsset) + { + Monitor.Wait(this); + m_waitingForObjectAsset = false; + } } - else + + if (null != m_requestedObjectAsset) { - // TODO: Need to unpack every tit and go through its textures & items, recursively - // this will mean going through the 'assets' received multiple times so that we can - // unpack objects within objects before recursively requesting the inner assets + string xml = Helpers.FieldToUTF8String(m_requestedObjectAsset.Data); + SceneObjectGroup sog = new SceneObjectGroup(m_scene, m_scene.RegionInfo.RegionHandle, xml); + GetSceneObjectAssetUuids(sog, assetUuids); } } } } } + } + + public void ArchiveRegion() + { + Dictionary assetUuids = new Dictionary(); + + List entities = m_scene.GetEntities(); + + foreach (EntityBase entity in entities) + { + if (entity is SceneObjectGroup) + { + GetSceneObjectAssetUuids((SceneObjectGroup)entity, assetUuids); + } + } string serializedEntities = SerializeObjects(entities); if (serializedEntities != null && serializedEntities.Length > 0) { m_log.DebugFormat("[ARCHIVER]: Successfully got serialization for {0} entities", entities.Count); - m_log.DebugFormat("[ARCHIVER]: Requiring save of {0} textures", assetUuids.Count); + m_log.DebugFormat("[ARCHIVER]: Requiring save of {0} assets", assetUuids.Count); // Asynchronously request all the assets required to perform this archive operation ArchiveWriteRequestExecution awre = new ArchiveWriteRequestExecution(serializedEntities, m_savePath); -- cgit v1.1