diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/UuidGatherer.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 702 |
1 files changed, 49 insertions, 653 deletions
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 2c5353f..69dc133 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs | |||
@@ -55,616 +55,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
55 | { | 55 | { |
56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 56 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
57 | 57 | ||
58 | protected IAssetService m_assetService; | ||
59 | |||
60 | // /// <summary> | ||
61 | // /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate | ||
62 | // /// asset was found by the asset service. | ||
63 | // /// </summary> | ||
64 | // private AssetBase m_requestedObjectAsset; | ||
65 | // | ||
66 | // /// <summary> | ||
67 | // /// Signal whether we are currently waiting for the asset service to deliver an asset. | ||
68 | // /// </summary> | ||
69 | // private bool m_waitingForObjectAsset; | ||
70 | |||
71 | public UuidGatherer(IAssetService assetService) | ||
72 | { | ||
73 | m_assetService = assetService; | ||
74 | } | ||
75 | |||
76 | /// <summary> | ||
77 | /// Gather all the asset uuids associated with the asset referenced by a given uuid | ||
78 | /// </summary> | ||
79 | /// <remarks> | ||
80 | /// This includes both those directly associated with | ||
81 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
82 | /// within this object). | ||
83 | /// This method assumes that the asset type associated with this asset in persistent storage is correct (which | ||
84 | /// should always be the case). So with this method we always need to retrieve asset data even if the asset | ||
85 | /// is of a type which is known not to reference any other assets | ||
86 | /// </remarks> | ||
87 | /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param> | ||
88 | /// <param name="assetUuids">The assets gathered</param> | ||
89 | public void GatherAssetUuids(UUID assetUuid, IDictionary<UUID, sbyte> assetUuids) | ||
90 | { | ||
91 | // avoid infinite loops | ||
92 | if (assetUuids.ContainsKey(assetUuid)) | ||
93 | return; | ||
94 | |||
95 | try | ||
96 | { | ||
97 | AssetBase assetBase = GetAsset(assetUuid); | ||
98 | |||
99 | if (null != assetBase) | ||
100 | { | ||
101 | sbyte assetType = assetBase.Type; | ||
102 | assetUuids[assetUuid] = assetType; | ||
103 | |||
104 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) | ||
105 | { | ||
106 | GetWearableAssetUuids(assetBase, assetUuids); | ||
107 | } | ||
108 | else if ((sbyte)AssetType.Gesture == assetType) | ||
109 | { | ||
110 | GetGestureAssetUuids(assetBase, assetUuids); | ||
111 | } | ||
112 | else if ((sbyte)AssetType.Notecard == assetType) | ||
113 | { | ||
114 | GetTextEmbeddedAssetUuids(assetBase, assetUuids); | ||
115 | } | ||
116 | else if ((sbyte)AssetType.LSLText == assetType) | ||
117 | { | ||
118 | GetTextEmbeddedAssetUuids(assetBase, assetUuids); | ||
119 | } | ||
120 | else if ((sbyte)OpenSimAssetType.Material == assetType) | ||
121 | { | ||
122 | GetMaterialAssetUuids(assetBase, assetUuids); | ||
123 | } | ||
124 | else if ((sbyte)AssetType.Object == assetType) | ||
125 | { | ||
126 | GetSceneObjectAssetUuids(assetBase, assetUuids); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | catch (Exception) | ||
131 | { | ||
132 | m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid); | ||
133 | throw; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /// <summary> | ||
138 | /// Gather all the asset uuids associated with the asset referenced by a given uuid | ||
139 | /// </summary> | ||
140 | /// <remarks> | ||
141 | /// This includes both those directly associated with | ||
142 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
143 | /// within this object). | ||
144 | /// </remarks> | ||
145 | /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param> | ||
146 | /// <param name="assetType">The type of the asset for the uuid given</param> | ||
147 | /// <param name="assetUuids">The assets gathered</param> | ||
148 | public void GatherAssetUuids(UUID assetUuid, sbyte assetType, IDictionary<UUID, sbyte> assetUuids) | ||
149 | { | ||
150 | // avoid infinite loops | ||
151 | if (assetUuids.ContainsKey(assetUuid)) | ||
152 | return; | ||
153 | |||
154 | try | ||
155 | { | ||
156 | assetUuids[assetUuid] = assetType; | ||
157 | |||
158 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) | ||
159 | { | ||
160 | GetWearableAssetUuids(assetUuid, assetUuids); | ||
161 | } | ||
162 | else if ((sbyte)AssetType.Gesture == assetType) | ||
163 | { | ||
164 | GetGestureAssetUuids(assetUuid, assetUuids); | ||
165 | } | ||
166 | else if ((sbyte)AssetType.Notecard == assetType) | ||
167 | { | ||
168 | GetTextEmbeddedAssetUuids(assetUuid, assetUuids); | ||
169 | } | ||
170 | else if ((sbyte)AssetType.LSLText == assetType) | ||
171 | { | ||
172 | GetTextEmbeddedAssetUuids(assetUuid, assetUuids); | ||
173 | } | ||
174 | else if ((sbyte)OpenSimAssetType.Material == assetType) | ||
175 | { | ||
176 | GetMaterialAssetUuids(assetUuid, assetUuids); | ||
177 | } | ||
178 | else if ((sbyte)AssetType.Object == assetType) | ||
179 | { | ||
180 | GetSceneObjectAssetUuids(assetUuid, assetUuids); | ||
181 | } | ||
182 | } | ||
183 | catch (Exception) | ||
184 | { | ||
185 | m_log.ErrorFormat( | ||
186 | "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}", | ||
187 | assetUuid, assetType); | ||
188 | throw; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /// <summary> | ||
193 | /// Gather all the asset uuids associated with a given object. | ||
194 | /// </summary> | ||
195 | /// <remarks> | ||
196 | /// This includes both those directly associated with | ||
197 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
198 | /// within this object). | ||
199 | /// </remarks> | ||
200 | /// <param name="sceneObject">The scene object for which to gather assets</param> | ||
201 | /// <param name="assetUuids"> | ||
202 | /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset. | ||
203 | /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown. | ||
204 | /// </param> | ||
205 | public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, sbyte> assetUuids) | ||
206 | { | ||
207 | // m_log.DebugFormat( | ||
208 | // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); | ||
209 | |||
210 | SceneObjectPart[] parts = sceneObject.Parts; | ||
211 | for (int i = 0; i < parts.Length; i++) | ||
212 | { | ||
213 | SceneObjectPart part = parts[i]; | ||
214 | |||
215 | // m_log.DebugFormat( | ||
216 | // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); | ||
217 | |||
218 | try | ||
219 | { | ||
220 | Primitive.TextureEntry textureEntry = part.Shape.Textures; | ||
221 | if (textureEntry != null) | ||
222 | { | ||
223 | // Get the prim's default texture. This will be used for faces which don't have their own texture | ||
224 | if (textureEntry.DefaultTexture != null) | ||
225 | GatherTextureEntryAssets(textureEntry.DefaultTexture, assetUuids); | ||
226 | |||
227 | if (textureEntry.FaceTextures != null) | ||
228 | { | ||
229 | // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture) | ||
230 | foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) | ||
231 | { | ||
232 | if (texture != null) | ||
233 | GatherTextureEntryAssets(texture, assetUuids); | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | // If the prim is a sculpt then preserve this information too | ||
239 | if (part.Shape.SculptTexture != UUID.Zero) | ||
240 | assetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; | ||
241 | |||
242 | if (part.Shape.ProjectionTextureUUID != UUID.Zero) | ||
243 | assetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; | ||
244 | |||
245 | if (part.CollisionSound != UUID.Zero) | ||
246 | assetUuids[part.CollisionSound] = (sbyte)AssetType.Sound; | ||
247 | |||
248 | if (part.ParticleSystem.Length > 0) | ||
249 | { | ||
250 | try | ||
251 | { | ||
252 | Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); | ||
253 | if (ps.Texture != UUID.Zero) | ||
254 | assetUuids[ps.Texture] = (sbyte)AssetType.Texture; | ||
255 | } | ||
256 | catch (Exception) | ||
257 | { | ||
258 | m_log.WarnFormat( | ||
259 | "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", | ||
260 | part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); | ||
265 | |||
266 | // Now analyze this prim's inventory items to preserve all the uuids that they reference | ||
267 | foreach (TaskInventoryItem tii in taskDictionary.Values) | ||
268 | { | ||
269 | // m_log.DebugFormat( | ||
270 | // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", | ||
271 | // tii.Name, tii.Type, part.Name, part.UUID); | ||
272 | |||
273 | if (!assetUuids.ContainsKey(tii.AssetID)) | ||
274 | GatherAssetUuids(tii.AssetID, (sbyte)tii.Type, assetUuids); | ||
275 | } | ||
276 | |||
277 | // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed | ||
278 | // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and | ||
279 | // inventory transfer. There needs to be a way for a module to register a method without assuming a | ||
280 | // Scene.EventManager is present. | ||
281 | // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); | ||
282 | |||
283 | |||
284 | // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs | ||
285 | GatherMaterialsUuids(part, assetUuids); | ||
286 | } | ||
287 | catch (Exception e) | ||
288 | { | ||
289 | m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); | ||
290 | m_log.DebugFormat( | ||
291 | "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", | ||
292 | part.Shape.TextureEntry.Length); | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /// <summary> | ||
298 | /// Gather all the asset uuids found in one face of a Texture Entry. | ||
299 | /// </summary> | ||
300 | private void GatherTextureEntryAssets(Primitive.TextureEntryFace texture, IDictionary<UUID, sbyte> assetUuids) | ||
301 | { | ||
302 | assetUuids[texture.TextureID] = (sbyte)AssetType.Texture; | ||
303 | |||
304 | if (texture.MaterialID != UUID.Zero) | ||
305 | { | ||
306 | GatherAssetUuids(texture.MaterialID, (sbyte)OpenSimAssetType.Material, assetUuids); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | /// <summary> | ||
311 | /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps | ||
312 | /// stored in legacy format in part.DynAttrs | ||
313 | /// </summary> | ||
314 | /// <param name="part"></param> | ||
315 | /// <param name="assetUuids"></param> | ||
316 | //public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, AssetType> assetUuids) | ||
317 | public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, sbyte> assetUuids) | ||
318 | { | ||
319 | // scan thru the dynAttrs map of this part for any textures used as materials | ||
320 | OSD osdMaterials = null; | ||
321 | |||
322 | lock (part.DynAttrs) | ||
323 | { | ||
324 | if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) | ||
325 | { | ||
326 | OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); | ||
327 | |||
328 | if (materialsStore == null) | ||
329 | return; | ||
330 | |||
331 | materialsStore.TryGetValue("Materials", out osdMaterials); | ||
332 | } | ||
333 | |||
334 | if (osdMaterials != null) | ||
335 | { | ||
336 | //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); | ||
337 | |||
338 | if (osdMaterials is OSDArray) | ||
339 | { | ||
340 | OSDArray matsArr = osdMaterials as OSDArray; | ||
341 | foreach (OSDMap matMap in matsArr) | ||
342 | { | ||
343 | try | ||
344 | { | ||
345 | if (matMap.ContainsKey("Material")) | ||
346 | { | ||
347 | OSDMap mat = matMap["Material"] as OSDMap; | ||
348 | if (mat.ContainsKey("NormMap")) | ||
349 | { | ||
350 | UUID normalMapId = mat["NormMap"].AsUUID(); | ||
351 | if (normalMapId != UUID.Zero) | ||
352 | { | ||
353 | assetUuids[normalMapId] = (sbyte)AssetType.Texture; | ||
354 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); | ||
355 | } | ||
356 | } | ||
357 | if (mat.ContainsKey("SpecMap")) | ||
358 | { | ||
359 | UUID specularMapId = mat["SpecMap"].AsUUID(); | ||
360 | if (specularMapId != UUID.Zero) | ||
361 | { | ||
362 | assetUuids[specularMapId] = (sbyte)AssetType.Texture; | ||
363 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | } | ||
369 | catch (Exception e) | ||
370 | { | ||
371 | m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | } | ||
378 | |||
379 | /// <summary> | ||
380 | /// Get an asset synchronously, potentially using an asynchronous callback. If the | ||
381 | /// asynchronous callback is used, we will wait for it to complete. | ||
382 | /// </summary> | ||
383 | /// <param name="uuid"></param> | ||
384 | /// <returns></returns> | ||
385 | protected virtual AssetBase GetAsset(UUID uuid) | ||
386 | { | ||
387 | return m_assetService.Get(uuid.ToString()); | ||
388 | |||
389 | // XXX: Switching to do this synchronously where the call was async before but we always waited for it | ||
390 | // to complete anyway! | ||
391 | // m_waitingForObjectAsset = true; | ||
392 | // m_assetCache.Get(uuid.ToString(), this, AssetReceived); | ||
393 | // | ||
394 | // // The asset cache callback can either | ||
395 | // // | ||
396 | // // 1. Complete on the same thread (if the asset is already in the cache) or | ||
397 | // // 2. Come in via a different thread (if we need to go fetch it). | ||
398 | // // | ||
399 | // // The code below handles both these alternatives. | ||
400 | // lock (this) | ||
401 | // { | ||
402 | // if (m_waitingForObjectAsset) | ||
403 | // { | ||
404 | // Monitor.Wait(this); | ||
405 | // m_waitingForObjectAsset = false; | ||
406 | // } | ||
407 | // } | ||
408 | // | ||
409 | // return m_requestedObjectAsset; | ||
410 | } | ||
411 | |||
412 | /// <summary> | ||
413 | /// Record the asset uuids embedded within the given text (e.g. a script). | ||
414 | /// </summary> | ||
415 | /// <param name="textAssetUuid"></param> | ||
416 | /// <param name="assetUuids">Dictionary in which to record the references</param> | ||
417 | private void GetTextEmbeddedAssetUuids(UUID textAssetUuid, IDictionary<UUID, sbyte> assetUuids) | ||
418 | { | ||
419 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); | ||
420 | |||
421 | AssetBase textAsset = GetAsset(textAssetUuid); | ||
422 | |||
423 | if (null != textAsset) | ||
424 | GetTextEmbeddedAssetUuids(textAsset, assetUuids); | ||
425 | } | ||
426 | |||
427 | /// <summary> | 58 | /// <summary> |
428 | /// Record the asset uuids embedded within the given text (e.g. a script). | 59 | /// Is gathering complete? |
429 | /// </summary> | ||
430 | /// <param name="textAsset"></param> | ||
431 | /// <param name="assetUuids">Dictionary in which to record the references</param> | ||
432 | private void GetTextEmbeddedAssetUuids(AssetBase textAsset, IDictionary<UUID, sbyte> assetUuids) | ||
433 | { | ||
434 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); | ||
435 | |||
436 | string script = Utils.BytesToString(textAsset.Data); | ||
437 | // m_log.DebugFormat("[ARCHIVER]: Script {0}", script); | ||
438 | MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script); | ||
439 | // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count); | ||
440 | |||
441 | foreach (Match uuidMatch in uuidMatches) | ||
442 | { | ||
443 | UUID uuid = new UUID(uuidMatch.Value); | ||
444 | // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); | ||
445 | |||
446 | // Embedded asset references (if not false positives) could be for many types of asset, so we will | ||
447 | // label these as unknown. | ||
448 | assetUuids[uuid] = (sbyte)AssetType.Unknown; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | /// <summary> | ||
453 | /// Record the uuids referenced by the given wearable asset | ||
454 | /// </summary> | ||
455 | /// <param name="wearableAssetUuid"></param> | ||
456 | /// <param name="assetUuids">Dictionary in which to record the references</param> | ||
457 | private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, sbyte> assetUuids) | ||
458 | { | ||
459 | AssetBase assetBase = GetAsset(wearableAssetUuid); | ||
460 | |||
461 | if (null != assetBase) | ||
462 | GetWearableAssetUuids(assetBase, assetUuids); | ||
463 | } | ||
464 | |||
465 | /// <summary> | ||
466 | /// Record the uuids referenced by the given wearable asset | ||
467 | /// </summary> | ||
468 | /// <param name="assetBase"></param> | ||
469 | /// <param name="assetUuids">Dictionary in which to record the references</param> | ||
470 | private void GetWearableAssetUuids(AssetBase assetBase, IDictionary<UUID, sbyte> assetUuids) | ||
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 | { | ||
481 | assetUuids[uuid] = (sbyte)AssetType.Texture; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | /// <summary> | ||
486 | /// Get all the asset uuids associated with a given object. This includes both those directly associated with | ||
487 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
488 | /// within this object). | ||
489 | /// </summary> | ||
490 | /// <param name="sceneObject"></param> | ||
491 | /// <param name="assetUuids"></param> | ||
492 | private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, sbyte> assetUuids) | ||
493 | { | ||
494 | AssetBase sceneObjectAsset = GetAsset(sceneObjectUuid); | ||
495 | |||
496 | if (null != sceneObjectAsset) | ||
497 | GetSceneObjectAssetUuids(sceneObjectAsset, assetUuids); | ||
498 | } | ||
499 | |||
500 | /// <summary> | ||
501 | /// Get all the asset uuids associated with a given object. This includes both those directly associated with | ||
502 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained | ||
503 | /// within this object). | ||
504 | /// </summary> | ||
505 | /// <param name="sceneObjectAsset"></param> | ||
506 | /// <param name="assetUuids"></param> | ||
507 | private void GetSceneObjectAssetUuids(AssetBase sceneObjectAsset, IDictionary<UUID, sbyte> assetUuids) | ||
508 | { | ||
509 | string xml = Utils.BytesToString(sceneObjectAsset.Data); | ||
510 | |||
511 | CoalescedSceneObjects coa; | ||
512 | if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) | ||
513 | { | ||
514 | foreach (SceneObjectGroup sog in coa.Objects) | ||
515 | GatherAssetUuids(sog, assetUuids); | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); | ||
520 | |||
521 | if (null != sog) | ||
522 | GatherAssetUuids(sog, assetUuids); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | /// <summary> | ||
527 | /// Get the asset uuid associated with a gesture | ||
528 | /// </summary> | ||
529 | /// <param name="gestureUuid"></param> | ||
530 | /// <param name="assetUuids"></param> | ||
531 | private void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, sbyte> assetUuids) | ||
532 | { | ||
533 | AssetBase gestureAsset = GetAsset(gestureUuid); | ||
534 | if (null == gestureAsset) | ||
535 | return; | ||
536 | |||
537 | GetGestureAssetUuids(gestureAsset, assetUuids); | ||
538 | } | ||
539 | |||
540 | /// <summary> | ||
541 | /// Get the asset uuid associated with a gesture | ||
542 | /// </summary> | ||
543 | /// <param name="gestureAsset"></param> | ||
544 | /// <param name="assetUuids"></param> | ||
545 | private void GetGestureAssetUuids(AssetBase gestureAsset, IDictionary<UUID, sbyte> assetUuids) | ||
546 | { | ||
547 | using (MemoryStream ms = new MemoryStream(gestureAsset.Data)) | ||
548 | using (StreamReader sr = new StreamReader(ms)) | ||
549 | { | ||
550 | sr.ReadLine(); // Unknown (Version?) | ||
551 | sr.ReadLine(); // Unknown | ||
552 | sr.ReadLine(); // Unknown | ||
553 | sr.ReadLine(); // Name | ||
554 | sr.ReadLine(); // Comment ? | ||
555 | int count = Convert.ToInt32(sr.ReadLine()); // Item count | ||
556 | |||
557 | for (int i = 0 ; i < count ; i++) | ||
558 | { | ||
559 | string type = sr.ReadLine(); | ||
560 | if (type == null) | ||
561 | break; | ||
562 | string name = sr.ReadLine(); | ||
563 | if (name == null) | ||
564 | break; | ||
565 | string id = sr.ReadLine(); | ||
566 | if (id == null) | ||
567 | break; | ||
568 | string unknown = sr.ReadLine(); | ||
569 | if (unknown == null) | ||
570 | break; | ||
571 | |||
572 | // If it can be parsed as a UUID, it is an asset ID | ||
573 | UUID uuid; | ||
574 | if (UUID.TryParse(id, out uuid)) | ||
575 | assetUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /// <summary> | ||
581 | /// Get the asset uuid's referenced in a material. | ||
582 | /// </summary> | ||
583 | private void GetMaterialAssetUuids(UUID materialUuid, IDictionary<UUID, sbyte> assetUuids) | ||
584 | { | ||
585 | AssetBase assetBase = GetAsset(materialUuid); | ||
586 | if (null == assetBase) | ||
587 | return; | ||
588 | |||
589 | GetMaterialAssetUuids(assetBase, assetUuids); | ||
590 | } | ||
591 | |||
592 | /// <summary> | ||
593 | /// Get the asset uuid's referenced in a material. | ||
594 | /// </summary> | 60 | /// </summary> |
595 | private void GetMaterialAssetUuids(AssetBase materialAsset, IDictionary<UUID, sbyte> assetUuids) | 61 | public bool Complete { get { return m_assetUuidsToInspect.Count <= 0; } } |
596 | { | ||
597 | OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data); | ||
598 | |||
599 | UUID normMap = mat["NormMap"].AsUUID(); | ||
600 | if (normMap != UUID.Zero) | ||
601 | assetUuids[normMap] = (sbyte)AssetType.Texture; | ||
602 | |||
603 | UUID specMap = mat["SpecMap"].AsUUID(); | ||
604 | if (specMap != UUID.Zero) | ||
605 | assetUuids[specMap] = (sbyte)AssetType.Texture; | ||
606 | } | ||
607 | } | ||
608 | |||
609 | public class HGUuidGatherer : UuidGatherer | ||
610 | { | ||
611 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
612 | |||
613 | protected string m_assetServerURL; | ||
614 | |||
615 | public HGUuidGatherer(IAssetService assetService, string assetServerURL) | ||
616 | : base(assetService) | ||
617 | { | ||
618 | m_assetServerURL = assetServerURL; | ||
619 | if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("=")) | ||
620 | m_assetServerURL = m_assetServerURL + "/"; | ||
621 | } | ||
622 | |||
623 | protected override AssetBase GetAsset(UUID uuid) | ||
624 | { | ||
625 | if (string.Empty == m_assetServerURL) | ||
626 | return base.GetAsset(uuid); | ||
627 | else | ||
628 | return FetchAsset(uuid); | ||
629 | } | ||
630 | |||
631 | public AssetBase FetchAsset(UUID assetID) | ||
632 | { | ||
633 | // Test if it's already here | ||
634 | AssetBase asset = m_assetService.Get(assetID.ToString()); | ||
635 | if (asset == null) | ||
636 | { | ||
637 | // It's not, so fetch it from abroad | ||
638 | asset = m_assetService.Get(m_assetServerURL + assetID.ToString()); | ||
639 | if (asset != null) | ||
640 | m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL); | ||
641 | else | ||
642 | m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL); | ||
643 | } | ||
644 | //else | ||
645 | // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL); | ||
646 | |||
647 | return asset; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | /// <summary> | ||
652 | /// Gather uuids for a given entity. | ||
653 | /// </summary> | ||
654 | /// <remarks> | ||
655 | /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts | ||
656 | /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets | ||
657 | /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be | ||
658 | /// retrieved to work out which assets it references). | ||
659 | /// </remarks> | ||
660 | public class IteratingUuidGatherer | ||
661 | { | ||
662 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
663 | 62 | ||
664 | /// <summary> | 63 | /// <summary> |
665 | /// Is gathering complete? | 64 | /// The dictionary of UUIDs gathered so far. If Complete == true then this is all the reachable UUIDs. |
666 | /// </summary> | 65 | /// </summary> |
667 | public bool Complete { get { return m_assetUuidsToInspect.Count <= 0; } } | 66 | /// <value>The gathered uuids.</value> |
67 | public IDictionary<UUID, sbyte> GatheredUuids { get; private set; } | ||
668 | 68 | ||
669 | /// <summary> | 69 | /// <summary> |
670 | /// Gets the next UUID to inspect. | 70 | /// Gets the next UUID to inspect. |
@@ -683,13 +83,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
683 | 83 | ||
684 | protected IAssetService m_assetService; | 84 | protected IAssetService m_assetService; |
685 | 85 | ||
686 | protected IDictionary<UUID, sbyte> m_gatheredAssetUuids; | ||
687 | |||
688 | protected Queue<UUID> m_assetUuidsToInspect; | 86 | protected Queue<UUID> m_assetUuidsToInspect; |
689 | 87 | ||
690 | /// <summary> | 88 | /// <summary> |
691 | /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class. | 89 | /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class. |
692 | /// </summary> | 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> | ||
693 | /// <param name="assetService"> | 100 | /// <param name="assetService"> |
694 | /// Asset service. | 101 | /// Asset service. |
695 | /// </param> | 102 | /// </param> |
@@ -697,10 +104,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
697 | /// Gathered UUIDs will be collected in this dictinaory. | 104 | /// Gathered UUIDs will be collected in this dictinaory. |
698 | /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected. | 105 | /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected. |
699 | /// </param> | 106 | /// </param> |
700 | public IteratingUuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector) | 107 | public UuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector) |
701 | { | 108 | { |
702 | m_assetService = assetService; | 109 | m_assetService = assetService; |
703 | m_gatheredAssetUuids = collector; | 110 | GatheredUuids = collector; |
704 | 111 | ||
705 | // FIXME: Not efficient for searching, can improve. | 112 | // FIXME: Not efficient for searching, can improve. |
706 | m_assetUuidsToInspect = new Queue<UUID>(); | 113 | m_assetUuidsToInspect = new Queue<UUID>(); |
@@ -765,13 +172,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
765 | 172 | ||
766 | // If the prim is a sculpt then preserve this information too | 173 | // If the prim is a sculpt then preserve this information too |
767 | if (part.Shape.SculptTexture != UUID.Zero) | 174 | if (part.Shape.SculptTexture != UUID.Zero) |
768 | m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; | 175 | GatheredUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture; |
769 | 176 | ||
770 | if (part.Shape.ProjectionTextureUUID != UUID.Zero) | 177 | if (part.Shape.ProjectionTextureUUID != UUID.Zero) |
771 | m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; | 178 | GatheredUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture; |
772 | 179 | ||
773 | if (part.CollisionSound != UUID.Zero) | 180 | if (part.CollisionSound != UUID.Zero) |
774 | m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound; | 181 | GatheredUuids[part.CollisionSound] = (sbyte)AssetType.Sound; |
775 | 182 | ||
776 | if (part.ParticleSystem.Length > 0) | 183 | if (part.ParticleSystem.Length > 0) |
777 | { | 184 | { |
@@ -779,7 +186,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
779 | { | 186 | { |
780 | Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); | 187 | Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); |
781 | if (ps.Texture != UUID.Zero) | 188 | if (ps.Texture != UUID.Zero) |
782 | m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture; | 189 | GatheredUuids[ps.Texture] = (sbyte)AssetType.Texture; |
783 | } | 190 | } |
784 | catch (Exception) | 191 | catch (Exception) |
785 | { | 192 | { |
@@ -798,7 +205,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
798 | // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", | 205 | // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", |
799 | // tii.Name, tii.Type, part.Name, part.UUID); | 206 | // tii.Name, tii.Type, part.Name, part.UUID); |
800 | 207 | ||
801 | if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID)) | 208 | if (!GatheredUuids.ContainsKey(tii.AssetID)) |
802 | AddForInspection(tii.AssetID, (sbyte)tii.Type); | 209 | AddForInspection(tii.AssetID, (sbyte)tii.Type); |
803 | } | 210 | } |
804 | 211 | ||
@@ -865,7 +272,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
865 | private void GetAssetUuids(UUID assetUuid) | 272 | private void GetAssetUuids(UUID assetUuid) |
866 | { | 273 | { |
867 | // avoid infinite loops | 274 | // avoid infinite loops |
868 | if (m_gatheredAssetUuids.ContainsKey(assetUuid)) | 275 | if (GatheredUuids.ContainsKey(assetUuid)) |
869 | return; | 276 | return; |
870 | 277 | ||
871 | try | 278 | try |
@@ -875,7 +282,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
875 | if (null != assetBase) | 282 | if (null != assetBase) |
876 | { | 283 | { |
877 | sbyte assetType = assetBase.Type; | 284 | sbyte assetType = assetBase.Type; |
878 | m_gatheredAssetUuids[assetUuid] = assetType; | 285 | GatheredUuids[assetUuid] = assetType; |
879 | 286 | ||
880 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) | 287 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) |
881 | { | 288 | { |
@@ -915,29 +322,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
915 | // Here, we want to collect uuids which require further asset fetches but mark the others as gathered | 322 | // Here, we want to collect uuids which require further asset fetches but mark the others as gathered |
916 | try | 323 | try |
917 | { | 324 | { |
918 | m_gatheredAssetUuids[assetUuid] = assetType; | 325 | GatheredUuids[assetUuid] = assetType; |
919 | 326 | ||
920 | if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType) | 327 | if ((sbyte)AssetType.Bodypart == assetType |
921 | { | 328 | || (sbyte)AssetType.Clothing == assetType |
922 | AddForInspection(assetUuid); | 329 | || (sbyte)AssetType.Gesture == assetType |
923 | } | 330 | || (sbyte)AssetType.Notecard == assetType |
924 | else if ((sbyte)AssetType.Gesture == assetType) | 331 | || (sbyte)AssetType.LSLText == assetType |
925 | { | 332 | || (sbyte)OpenSimAssetType.Material == assetType |
926 | AddForInspection(assetUuid); | 333 | || (sbyte)AssetType.Object == assetType) |
927 | } | ||
928 | else if ((sbyte)AssetType.Notecard == assetType) | ||
929 | { | ||
930 | AddForInspection(assetUuid); | ||
931 | } | ||
932 | else if ((sbyte)AssetType.LSLText == assetType) | ||
933 | { | ||
934 | AddForInspection(assetUuid); | ||
935 | } | ||
936 | else if ((sbyte)OpenSimAssetType.Material == assetType) | ||
937 | { | ||
938 | AddForInspection(assetUuid); | ||
939 | } | ||
940 | else if ((sbyte)AssetType.Object == assetType) | ||
941 | { | 334 | { |
942 | AddForInspection(assetUuid); | 335 | AddForInspection(assetUuid); |
943 | } | 336 | } |
@@ -956,7 +349,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
956 | /// </summary> | 349 | /// </summary> |
957 | private void RecordTextureEntryAssetUuids(Primitive.TextureEntryFace texture) | 350 | private void RecordTextureEntryAssetUuids(Primitive.TextureEntryFace texture) |
958 | { | 351 | { |
959 | m_gatheredAssetUuids[texture.TextureID] = (sbyte)AssetType.Texture; | 352 | GatheredUuids[texture.TextureID] = (sbyte)AssetType.Texture; |
960 | 353 | ||
961 | if (texture.MaterialID != UUID.Zero) | 354 | if (texture.MaterialID != UUID.Zero) |
962 | AddForInspection(texture.MaterialID); | 355 | AddForInspection(texture.MaterialID); |
@@ -1003,7 +396,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1003 | UUID normalMapId = mat["NormMap"].AsUUID(); | 396 | UUID normalMapId = mat["NormMap"].AsUUID(); |
1004 | if (normalMapId != UUID.Zero) | 397 | if (normalMapId != UUID.Zero) |
1005 | { | 398 | { |
1006 | m_gatheredAssetUuids[normalMapId] = (sbyte)AssetType.Texture; | 399 | GatheredUuids[normalMapId] = (sbyte)AssetType.Texture; |
1007 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); | 400 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); |
1008 | } | 401 | } |
1009 | } | 402 | } |
@@ -1012,7 +405,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1012 | UUID specularMapId = mat["SpecMap"].AsUUID(); | 405 | UUID specularMapId = mat["SpecMap"].AsUUID(); |
1013 | if (specularMapId != UUID.Zero) | 406 | if (specularMapId != UUID.Zero) |
1014 | { | 407 | { |
1015 | m_gatheredAssetUuids[specularMapId] = (sbyte)AssetType.Texture; | 408 | GatheredUuids[specularMapId] = (sbyte)AssetType.Texture; |
1016 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); | 409 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); |
1017 | } | 410 | } |
1018 | } | 411 | } |
@@ -1048,15 +441,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1048 | { | 441 | { |
1049 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); | 442 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); |
1050 | 443 | ||
1051 | string script = Utils.BytesToString(textAsset.Data); | 444 | string text = Utils.BytesToString(textAsset.Data); |
1052 | // m_log.DebugFormat("[ARCHIVER]: Script {0}", script); | 445 | // m_log.DebugFormat("[UUID GATHERER]: Text {0}", text); |
1053 | MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script); | 446 | MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(text); |
1054 | // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count); | 447 | // m_log.DebugFormat("[UUID GATHERER]: Found {0} matches in text", uuidMatches.Count); |
1055 | 448 | ||
1056 | foreach (Match uuidMatch in uuidMatches) | 449 | foreach (Match uuidMatch in uuidMatches) |
1057 | { | 450 | { |
1058 | UUID uuid = new UUID(uuidMatch.Value); | 451 | UUID uuid = new UUID(uuidMatch.Value); |
1059 | // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); | 452 | // m_log.DebugFormat("[UUID GATHERER]: Recording {0} in text", uuid); |
1060 | 453 | ||
1061 | AddForInspection(uuid); | 454 | AddForInspection(uuid); |
1062 | } | 455 | } |
@@ -1076,7 +469,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1076 | // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count); | 469 | // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count); |
1077 | 470 | ||
1078 | foreach (UUID uuid in wearableAsset.Textures.Values) | 471 | foreach (UUID uuid in wearableAsset.Textures.Values) |
1079 | m_gatheredAssetUuids[uuid] = (sbyte)AssetType.Texture; | 472 | GatheredUuids[uuid] = (sbyte)AssetType.Texture; |
1080 | } | 473 | } |
1081 | 474 | ||
1082 | /// <summary> | 475 | /// <summary> |
@@ -1138,7 +531,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1138 | // If it can be parsed as a UUID, it is an asset ID | 531 | // If it can be parsed as a UUID, it is an asset ID |
1139 | UUID uuid; | 532 | UUID uuid; |
1140 | if (UUID.TryParse(id, out uuid)) | 533 | if (UUID.TryParse(id, out uuid)) |
1141 | m_gatheredAssetUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important | 534 | GatheredUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important |
1142 | } | 535 | } |
1143 | } | 536 | } |
1144 | } | 537 | } |
@@ -1152,21 +545,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
1152 | 545 | ||
1153 | UUID normMap = mat["NormMap"].AsUUID(); | 546 | UUID normMap = mat["NormMap"].AsUUID(); |
1154 | if (normMap != UUID.Zero) | 547 | if (normMap != UUID.Zero) |
1155 | m_gatheredAssetUuids[normMap] = (sbyte)AssetType.Texture; | 548 | GatheredUuids[normMap] = (sbyte)AssetType.Texture; |
1156 | 549 | ||
1157 | UUID specMap = mat["SpecMap"].AsUUID(); | 550 | UUID specMap = mat["SpecMap"].AsUUID(); |
1158 | if (specMap != UUID.Zero) | 551 | if (specMap != UUID.Zero) |
1159 | m_gatheredAssetUuids[specMap] = (sbyte)AssetType.Texture; | 552 | GatheredUuids[specMap] = (sbyte)AssetType.Texture; |
1160 | } | 553 | } |
1161 | } | 554 | } |
1162 | 555 | ||
1163 | public class IteratingHGUuidGatherer : IteratingUuidGatherer | 556 | public class HGUuidGatherer : UuidGatherer |
1164 | { | 557 | { |
1165 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 558 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
1166 | 559 | ||
1167 | protected string m_assetServerURL; | 560 | protected string m_assetServerURL; |
1168 | 561 | ||
1169 | public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector) | 562 | public HGUuidGatherer(IAssetService assetService, string assetServerURL) |
563 | : this(assetService, assetServerURL, new Dictionary<UUID, sbyte>()) {} | ||
564 | |||
565 | public HGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector) | ||
1170 | : base(assetService, collector) | 566 | : base(assetService, collector) |
1171 | { | 567 | { |
1172 | m_assetServerURL = assetServerURL; | 568 | m_assetServerURL = assetServerURL; |