diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/UuidGatherer.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs new file mode 100644 index 0000000..9ec4e1d --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs | |||
@@ -0,0 +1,608 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Text.RegularExpressions; | ||
33 | using System.Threading; | ||
34 | using log4net; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.Assets; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; | ||
42 | |||
43 | namespace OpenSim.Region.Framework.Scenes | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Gather uuids for a given entity. | ||
47 | /// </summary> | ||
48 | /// <remarks> | ||
49 | /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts | ||
50 | /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets | ||
51 | /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be | ||
52 | /// retrieved to work out which assets it references). | ||
53 | /// </remarks> | ||
54 | public class UuidGatherer | ||
55 | { | ||
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
57 | |||
58 | /// <summary> | ||
59 | /// Is gathering complete? | ||
60 | /// </summary> | ||
61 | public bool Complete { get { return m_assetUuidsToInspect.Count <= 0; } } | ||
62 | |||
63 | /// <summary> | ||
64 | /// The dictionary of UUIDs gathered so far. If Complete == true then this is all the reachable UUIDs. | ||
65 | /// </summary> | ||
66 | /// <value>The gathered uuids.</value> | ||
67 | public IDictionary<UUID, sbyte> GatheredUuids { get; private set; } | ||
68 | |||
69 | /// <summary> | ||
70 | /// Gets the next UUID to inspect. | ||
71 | /// </summary> | ||
72 | /// <value>If there is no next UUID then returns null</value> | ||
73 | public UUID? NextUuidToInspect | ||
74 | { | ||
75 | get | ||
76 | { | ||
77 | if (Complete) | ||
78 | return null; | ||
79 | else | ||
80 | return m_assetUuidsToInspect.Peek(); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | protected IAssetService m_assetService; | ||
85 | |||
86 | protected Queue<UUID> m_assetUuidsToInspect; | ||
87 | |||
88 | /// <summary> | ||
89 | /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class. | ||
90 | /// </summary> | ||
91 | /// <remarks>In this case the collection of gathered assets will start out blank.</remarks> | ||
92 | /// <param name="assetService"> | ||
93 | /// Asset service. | ||
94 | /// </param> | ||
95 | public UuidGatherer(IAssetService assetService) : this(assetService, new Dictionary<UUID, sbyte>()) {} | ||
96 | |||
97 | /// <summary> | ||
98 | /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class. | ||
99 | /// </summary> | ||
100 | /// <param name="assetService"> | ||
101 | /// Asset service. | ||
102 | /// </param> | ||
103 | /// <param name="collector"> | ||
104 | /// Gathered UUIDs will be collected in this dictinaory. | ||
105 | /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected. | ||
106 | /// </param> | ||
107 | public UuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector) | ||
108 | { | ||
109 | m_assetService = assetService; | ||
110 | GatheredUuids = collector; | ||
111 | |||
112 | // FIXME: Not efficient for searching, can improve. | ||
113 | m_assetUuidsToInspect = new Queue<UUID>(); | ||
114 | } | ||
115 | |||
116 | /// <summary> | ||
117 | /// Adds the asset uuid for inspection during the gathering process. | ||
118 | /// </summary> | ||
119 | /// <returns><c>true</c>, if for inspection was added, <c>false</c> otherwise.</returns> | ||
120 | /// <param name="uuid">UUID.</param> | ||
121 | public bool AddForInspection(UUID uuid) | ||
122 | { | ||
123 | if (m_assetUuidsToInspect.Contains(uuid)) | ||
124 | return false; | ||
125 | |||
126 | // m_log.DebugFormat("[UUID GATHERER]: Adding asset {0} for inspection", uuid); | ||
127 | |||
128 | m_assetUuidsToInspect.Enqueue(uuid); | ||
129 | |||
130 | return true; | ||
131 | } | ||
132 | |||
133 | /// <summary> | ||
134 | /// Gather all the asset uuids associated with a given object. | ||
135 | /// </summary> | ||
136 | /// <remarks> | ||
137 | /// This includes both those directly associated with | ||
138 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
139 | /// within this object). | ||
140 | /// </remarks> | ||
141 | /// <param name="sceneObject">The scene object for which to gather assets</param> | ||
142 | public void AddForInspection(SceneObjectGroup sceneObject) | ||
143 | { | ||
144 | // m_log.DebugFormat( | ||
145 | // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); | ||
146 | |||
147 | SceneObjectPart[] parts = sceneObject.Parts; | ||
148 | for (int i = 0; i < parts.Length; i++) | ||
149 | { | ||
150 | SceneObjectPart part = parts[i]; | ||
151 | |||
152 | // m_log.DebugFormat( | ||
153 | // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); | ||
154 | |||
155 | try | ||
156 | { | ||
157 | Primitive.TextureEntry textureEntry = part.Shape.Textures; | ||
158 | if (textureEntry != null) | ||
159 | { | ||
160 | // Get the prim's default texture. This will be used for faces which don't have their own texture | ||
161 | if (textureEntry.DefaultTexture != null) | ||
162 | RecordTextureEntryAssetUuids(textureEntry.DefaultTexture); | ||
163 | |||
164 | if (textureEntry.FaceTextures != null) | ||
165 | { | ||
166 | // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture) | ||
167 | foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) | ||
168 | { | ||
169 | if (texture != null) | ||
170 | RecordTextureEntryAssetUuids(texture); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | // If the prim is a sculpt then preserve this information too | ||
176 | if (part.Shape.SculptTexture != UUID.Zero) | ||
177 | GatheredUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; | ||
178 | |||
179 | if (part.Shape.ProjectionTextureUUID != UUID.Zero) | ||
180 | GatheredUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; | ||
181 | |||
182 | if (part.CollisionSound != UUID.Zero) | ||
183 | GatheredUuids[part.CollisionSound] = (sbyte)AssetType.Sound; | ||
184 | |||
185 | if (part.ParticleSystem.Length > 0) | ||
186 | { | ||
187 | try | ||
188 | { | ||
189 | Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); | ||
190 | if (ps.Texture != UUID.Zero) | ||
191 | GatheredUuids[ps.Texture] = (sbyte)AssetType.Texture; | ||
192 | } | ||
193 | catch (Exception) | ||
194 | { | ||
195 | m_log.WarnFormat( | ||
196 | "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", | ||
197 | part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); | ||
202 | |||
203 | // Now analyze this prim's inventory items to preserve all the uuids that they reference | ||
204 | foreach (TaskInventoryItem tii in taskDictionary.Values) | ||
205 | { | ||
206 | // m_log.DebugFormat( | ||
207 | // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", | ||
208 | // tii.Name, tii.Type, part.Name, part.UUID); | ||
209 | |||
210 | if (!GatheredUuids.ContainsKey(tii.AssetID)) | ||
211 | AddForInspection(tii.AssetID, (sbyte)tii.Type); | ||
212 | } | ||
213 | |||
214 | // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed | ||
215 | // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and | ||
216 | // inventory transfer. There needs to be a way for a module to register a method without assuming a | ||
217 | // Scene.EventManager is present. | ||
218 | // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); | ||
219 | |||
220 | |||
221 | // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs | ||
222 | RecordMaterialsUuids(part); | ||
223 | } | ||
224 | catch (Exception e) | ||
225 | { | ||
226 | m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); | ||
227 | m_log.DebugFormat( | ||
228 | "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", | ||
229 | part.Shape.TextureEntry.Length); | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /// <summary> | ||
235 | /// Gathers the next set of assets returned by the next uuid to get from the asset service. | ||
236 | /// </summary> | ||
237 | /// <returns>false if gathering is already complete, true otherwise</returns> | ||
238 | public bool GatherNext() | ||
239 | { | ||
240 | if (Complete) | ||
241 | return false; | ||
242 | |||
243 | UUID nextToInspect = m_assetUuidsToInspect.Dequeue(); | ||
244 | |||
245 | // m_log.DebugFormat("[UUID GATHERER]: Inspecting asset {0}", nextToInspect); | ||
246 | |||
247 | GetAssetUuids(nextToInspect); | ||
248 | |||
249 | return true; | ||
250 | } | ||
251 | |||
252 | /// <summary> | ||
253 | /// Gathers all remaining asset UUIDS no matter how many calls are required to the asset service. | ||
254 | /// </summary> | ||
255 | /// <returns>false if gathering is already complete, true otherwise</returns> | ||
256 | public bool GatherAll() | ||
257 | { | ||
258 | if (Complete) | ||
259 | return false; | ||
260 | |||
261 | while (GatherNext()); | ||
262 | |||
263 | return true; | ||
264 | } | ||
265 | |||
266 | /// <summary> | ||
267 | /// Gather all the asset uuids associated with the asset referenced by a given uuid | ||
268 | /// </summary> | ||
269 | /// <remarks> | ||
270 | /// This includes both those directly associated with | ||
271 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
272 | /// within this object). | ||
273 | /// This method assumes that the asset type associated with this asset in persistent storage is correct (which | ||
274 | /// should always be the case). So with this method we always need to retrieve asset data even if the asset | ||
275 | /// is of a type which is known not to reference any other assets | ||
276 | /// </remarks> | ||
277 | /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param> | ||
278 | private void GetAssetUuids(UUID assetUuid) | ||
279 | { | ||
280 | // avoid infinite loops | ||
281 | if (GatheredUuids.ContainsKey(assetUuid)) | ||
282 | return; | ||
283 | |||
284 | try | ||
285 | { | ||
286 | AssetBase assetBase = GetAsset(assetUuid); | ||
287 | |||
288 | if (null != assetBase) | ||
289 | { | ||
290 | sbyte assetType = assetBase.Type; | ||
291 | GatheredUuids[assetUuid] = assetType; | ||
292 | |||
293 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) | ||
294 | { | ||
295 | RecordWearableAssetUuids(assetBase); | ||
296 | } | ||
297 | else if ((sbyte)AssetType.Gesture == assetType) | ||
298 | { | ||
299 | RecordGestureAssetUuids(assetBase); | ||
300 | } | ||
301 | else if ((sbyte)AssetType.Notecard == assetType) | ||
302 | { | ||
303 | RecordTextEmbeddedAssetUuids(assetBase); | ||
304 | } | ||
305 | else if ((sbyte)AssetType.LSLText == assetType) | ||
306 | { | ||
307 | RecordTextEmbeddedAssetUuids(assetBase); | ||
308 | } | ||
309 | else if ((sbyte)OpenSimAssetType.Material == assetType) | ||
310 | { | ||
311 | RecordMaterialAssetUuids(assetBase); | ||
312 | } | ||
313 | else if ((sbyte)AssetType.Object == assetType) | ||
314 | { | ||
315 | RecordSceneObjectAssetUuids(assetBase); | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | catch (Exception) | ||
320 | { | ||
321 | m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid); | ||
322 | throw; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | private void AddForInspection(UUID assetUuid, sbyte assetType) | ||
327 | { | ||
328 | // Here, we want to collect uuids which require further asset fetches but mark the others as gathered | ||
329 | try | ||
330 | { | ||
331 | if ((sbyte)AssetType.Bodypart == assetType | ||
332 | || (sbyte)AssetType.Clothing == assetType | ||
333 | || (sbyte)AssetType.Gesture == assetType | ||
334 | || (sbyte)AssetType.Notecard == assetType | ||
335 | || (sbyte)AssetType.LSLText == assetType | ||
336 | || (sbyte)OpenSimAssetType.Material == assetType | ||
337 | || (sbyte)AssetType.Object == assetType) | ||
338 | { | ||
339 | AddForInspection(assetUuid); | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | GatheredUuids[assetUuid] = assetType; | ||
344 | } | ||
345 | } | ||
346 | catch (Exception) | ||
347 | { | ||
348 | m_log.ErrorFormat( | ||
349 | "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}", | ||
350 | assetUuid, assetType); | ||
351 | throw; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | /// <summary> | ||
356 | /// Collect all the asset uuids found in one face of a Texture Entry. | ||
357 | /// </summary> | ||
358 | private void RecordTextureEntryAssetUuids(Primitive.TextureEntryFace texture) | ||
359 | { | ||
360 | GatheredUuids[texture.TextureID] = (sbyte)AssetType.Texture; | ||
361 | |||
362 | if (texture.MaterialID != UUID.Zero) | ||
363 | AddForInspection(texture.MaterialID); | ||
364 | } | ||
365 | |||
366 | /// <summary> | ||
367 | /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps | ||
368 | /// stored in legacy format in part.DynAttrs | ||
369 | /// </summary> | ||
370 | /// <param name="part"></param> | ||
371 | private void RecordMaterialsUuids(SceneObjectPart part) | ||
372 | { | ||
373 | // scan thru the dynAttrs map of this part for any textures used as materials | ||
374 | OSD osdMaterials = null; | ||
375 | |||
376 | lock (part.DynAttrs) | ||
377 | { | ||
378 | if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) | ||
379 | { | ||
380 | OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); | ||
381 | |||
382 | if (materialsStore == null) | ||
383 | return; | ||
384 | |||
385 | materialsStore.TryGetValue("Materials", out osdMaterials); | ||
386 | } | ||
387 | |||
388 | if (osdMaterials != null) | ||
389 | { | ||
390 | //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); | ||
391 | |||
392 | if (osdMaterials is OSDArray) | ||
393 | { | ||
394 | OSDArray matsArr = osdMaterials as OSDArray; | ||
395 | foreach (OSDMap matMap in matsArr) | ||
396 | { | ||
397 | try | ||
398 | { | ||
399 | if (matMap.ContainsKey("Material")) | ||
400 | { | ||
401 | OSDMap mat = matMap["Material"] as OSDMap; | ||
402 | if (mat.ContainsKey("NormMap")) | ||
403 | { | ||
404 | UUID normalMapId = mat["NormMap"].AsUUID(); | ||
405 | if (normalMapId != UUID.Zero) | ||
406 | { | ||
407 | GatheredUuids[normalMapId] = (sbyte)AssetType.Texture; | ||
408 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); | ||
409 | } | ||
410 | } | ||
411 | if (mat.ContainsKey("SpecMap")) | ||
412 | { | ||
413 | UUID specularMapId = mat["SpecMap"].AsUUID(); | ||
414 | if (specularMapId != UUID.Zero) | ||
415 | { | ||
416 | GatheredUuids[specularMapId] = (sbyte)AssetType.Texture; | ||
417 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | |||
422 | } | ||
423 | catch (Exception e) | ||
424 | { | ||
425 | m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); | ||
426 | } | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
433 | /// <summary> | ||
434 | /// Get an asset synchronously, potentially using an asynchronous callback. If the | ||
435 | /// asynchronous callback is used, we will wait for it to complete. | ||
436 | /// </summary> | ||
437 | /// <param name="uuid"></param> | ||
438 | /// <returns></returns> | ||
439 | protected virtual AssetBase GetAsset(UUID uuid) | ||
440 | { | ||
441 | return m_assetService.Get(uuid.ToString()); | ||
442 | } | ||
443 | |||
444 | /// <summary> | ||
445 | /// Record the asset uuids embedded within the given text (e.g. a script). | ||
446 | /// </summary> | ||
447 | /// <param name="textAsset"></param> | ||
448 | private void RecordTextEmbeddedAssetUuids(AssetBase textAsset) | ||
449 | { | ||
450 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); | ||
451 | |||
452 | string text = Utils.BytesToString(textAsset.Data); | ||
453 | // m_log.DebugFormat("[UUID GATHERER]: Text {0}", text); | ||
454 | MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(text); | ||
455 | // m_log.DebugFormat("[UUID GATHERER]: Found {0} matches in text", uuidMatches.Count); | ||
456 | |||
457 | foreach (Match uuidMatch in uuidMatches) | ||
458 | { | ||
459 | UUID uuid = new UUID(uuidMatch.Value); | ||
460 | // m_log.DebugFormat("[UUID GATHERER]: Recording {0} in text", uuid); | ||
461 | |||
462 | AddForInspection(uuid); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /// <summary> | ||
467 | /// Record the uuids referenced by the given wearable asset | ||
468 | /// </summary> | ||
469 | /// <param name="assetBase"></param> | ||
470 | private void RecordWearableAssetUuids(AssetBase assetBase) | ||
471 | { | ||
472 | //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data)); | ||
473 | AssetWearable wearableAsset = new AssetBodypart(assetBase.FullID, assetBase.Data); | ||
474 | wearableAsset.Decode(); | ||
475 | |||
476 | //m_log.DebugFormat( | ||
477 | // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count); | ||
478 | |||
479 | foreach (UUID uuid in wearableAsset.Textures.Values) | ||
480 | GatheredUuids[uuid] = (sbyte)AssetType.Texture; | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Get all the asset uuids associated with a given object. This includes both those directly associated with | ||
485 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
486 | /// within this object). | ||
487 | /// </summary> | ||
488 | /// <param name="sceneObjectAsset"></param> | ||
489 | private void RecordSceneObjectAssetUuids(AssetBase sceneObjectAsset) | ||
490 | { | ||
491 | string xml = Utils.BytesToString(sceneObjectAsset.Data); | ||
492 | |||
493 | CoalescedSceneObjects coa; | ||
494 | if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) | ||
495 | { | ||
496 | foreach (SceneObjectGroup sog in coa.Objects) | ||
497 | AddForInspection(sog); | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); | ||
502 | |||
503 | if (null != sog) | ||
504 | AddForInspection(sog); | ||
505 | } | ||
506 | } | ||
507 | |||
508 | /// <summary> | ||
509 | /// Get the asset uuid associated with a gesture | ||
510 | /// </summary> | ||
511 | /// <param name="gestureAsset"></param> | ||
512 | private void RecordGestureAssetUuids(AssetBase gestureAsset) | ||
513 | { | ||
514 | using (MemoryStream ms = new MemoryStream(gestureAsset.Data)) | ||
515 | using (StreamReader sr = new StreamReader(ms)) | ||
516 | { | ||
517 | sr.ReadLine(); // Unknown (Version?) | ||
518 | sr.ReadLine(); // Unknown | ||
519 | sr.ReadLine(); // Unknown | ||
520 | sr.ReadLine(); // Name | ||
521 | sr.ReadLine(); // Comment ? | ||
522 | int count = Convert.ToInt32(sr.ReadLine()); // Item count | ||
523 | |||
524 | for (int i = 0 ; i < count ; i++) | ||
525 | { | ||
526 | string type = sr.ReadLine(); | ||
527 | if (type == null) | ||
528 | break; | ||
529 | string name = sr.ReadLine(); | ||
530 | if (name == null) | ||
531 | break; | ||
532 | string id = sr.ReadLine(); | ||
533 | if (id == null) | ||
534 | break; | ||
535 | string unknown = sr.ReadLine(); | ||
536 | if (unknown == null) | ||
537 | break; | ||
538 | |||
539 | // If it can be parsed as a UUID, it is an asset ID | ||
540 | UUID uuid; | ||
541 | if (UUID.TryParse(id, out uuid)) | ||
542 | GatheredUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | |||
547 | /// <summary> | ||
548 | /// Get the asset uuid's referenced in a material. | ||
549 | /// </summary> | ||
550 | private void RecordMaterialAssetUuids(AssetBase materialAsset) | ||
551 | { | ||
552 | OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data); | ||
553 | |||
554 | UUID normMap = mat["NormMap"].AsUUID(); | ||
555 | if (normMap != UUID.Zero) | ||
556 | GatheredUuids[normMap] = (sbyte)AssetType.Texture; | ||
557 | |||
558 | UUID specMap = mat["SpecMap"].AsUUID(); | ||
559 | if (specMap != UUID.Zero) | ||
560 | GatheredUuids[specMap] = (sbyte)AssetType.Texture; | ||
561 | } | ||
562 | } | ||
563 | |||
564 | public class HGUuidGatherer : UuidGatherer | ||
565 | { | ||
566 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
567 | |||
568 | protected string m_assetServerURL; | ||
569 | |||
570 | public HGUuidGatherer(IAssetService assetService, string assetServerURL) | ||
571 | : this(assetService, assetServerURL, new Dictionary<UUID, sbyte>()) {} | ||
572 | |||
573 | public HGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector) | ||
574 | : base(assetService, collector) | ||
575 | { | ||
576 | m_assetServerURL = assetServerURL; | ||
577 | if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("=")) | ||
578 | m_assetServerURL = m_assetServerURL + "/"; | ||
579 | } | ||
580 | |||
581 | protected override AssetBase GetAsset(UUID uuid) | ||
582 | { | ||
583 | if (string.Empty == m_assetServerURL) | ||
584 | return base.GetAsset(uuid); | ||
585 | else | ||
586 | return FetchAsset(uuid); | ||
587 | } | ||
588 | |||
589 | public AssetBase FetchAsset(UUID assetID) | ||
590 | { | ||
591 | // Test if it's already here | ||
592 | AssetBase asset = m_assetService.Get(assetID.ToString()); | ||
593 | if (asset == null) | ||
594 | { | ||
595 | // It's not, so fetch it from abroad | ||
596 | asset = m_assetService.Get(m_assetServerURL + assetID.ToString()); | ||
597 | if (asset != null) | ||
598 | m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL); | ||
599 | else | ||
600 | m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL); | ||
601 | } | ||
602 | //else | ||
603 | // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL); | ||
604 | |||
605 | return asset; | ||
606 | } | ||
607 | } | ||
608 | } | ||