UuidGatherer.cs 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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. using System;
  28. using System.Collections.Generic;
  29. using System.IO;
  30. using System.Reflection;
  31. using System.Text.RegularExpressions;
  32. using System.Threading;
  33. using log4net;
  34. using OpenMetaverse;
  35. using OpenMetaverse.Assets;
  36. using OpenMetaverse.StructuredData;
  37. using OpenSim.Framework;
  38. using OpenSim.Region.Framework.Scenes.Serialization;
  39. using OpenSim.Services.Interfaces;
  40. using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
  41. namespace OpenSim.Region.Framework.Scenes
  42. {
  43. /// <summary>
  44. /// Gather uuids for a given entity.
  45. /// </summary>
  46. /// <remarks>
  47. /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts
  48. /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets
  49. /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be
  50. /// retrieved to work out which assets it references).
  51. /// </remarks>
  52. public class UuidGatherer
  53. {
  54. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  55. protected IAssetService m_assetService;
  56. // /// <summary>
  57. // /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate
  58. // /// asset was found by the asset service.
  59. // /// </summary>
  60. // private AssetBase m_requestedObjectAsset;
  61. //
  62. // /// <summary>
  63. // /// Signal whether we are currently waiting for the asset service to deliver an asset.
  64. // /// </summary>
  65. // private bool m_waitingForObjectAsset;
  66. public UuidGatherer(IAssetService assetService)
  67. {
  68. m_assetService = assetService;
  69. }
  70. /// <summary>
  71. /// Gather all the asset uuids associated with the asset referenced by a given uuid
  72. /// </summary>
  73. /// <remarks>
  74. /// This includes both those directly associated with
  75. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  76. /// within this object).
  77. /// This method assumes that the asset type associated with this asset in persistent storage is correct (which
  78. /// should always be the case). So with this method we always need to retrieve asset data even if the asset
  79. /// is of a type which is known not to reference any other assets
  80. /// </remarks>
  81. /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
  82. /// <param name="assetUuids">The assets gathered</param>
  83. public void GatherAssetUuids(UUID assetUuid, IDictionary<UUID, sbyte> assetUuids)
  84. {
  85. // avoid infinite loops
  86. if (assetUuids.ContainsKey(assetUuid))
  87. return;
  88. try
  89. {
  90. AssetBase assetBase = GetAsset(assetUuid);
  91. if (null != assetBase)
  92. {
  93. sbyte assetType = assetBase.Type;
  94. assetUuids[assetUuid] = assetType;
  95. if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
  96. {
  97. GetWearableAssetUuids(assetBase, assetUuids);
  98. }
  99. else if ((sbyte)AssetType.Gesture == assetType)
  100. {
  101. GetGestureAssetUuids(assetBase, assetUuids);
  102. }
  103. else if ((sbyte)AssetType.Notecard == assetType)
  104. {
  105. GetTextEmbeddedAssetUuids(assetBase, assetUuids);
  106. }
  107. else if ((sbyte)AssetType.LSLText == assetType)
  108. {
  109. GetTextEmbeddedAssetUuids(assetBase, assetUuids);
  110. }
  111. else if ((sbyte)OpenSimAssetType.Material == assetType)
  112. {
  113. GetMaterialAssetUuids(assetBase, assetUuids);
  114. }
  115. else if ((sbyte)AssetType.Object == assetType)
  116. {
  117. GetSceneObjectAssetUuids(assetBase, assetUuids);
  118. }
  119. }
  120. }
  121. catch (Exception)
  122. {
  123. m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid);
  124. throw;
  125. }
  126. }
  127. /// <summary>
  128. /// Gather all the asset uuids associated with the asset referenced by a given uuid
  129. /// </summary>
  130. /// <remarks>
  131. /// This includes both those directly associated with
  132. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  133. /// within this object).
  134. /// </remarks>
  135. /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
  136. /// <param name="assetType">The type of the asset for the uuid given</param>
  137. /// <param name="assetUuids">The assets gathered</param>
  138. public void GatherAssetUuids(UUID assetUuid, sbyte assetType, IDictionary<UUID, sbyte> assetUuids)
  139. {
  140. // avoid infinite loops
  141. if (assetUuids.ContainsKey(assetUuid))
  142. return;
  143. try
  144. {
  145. assetUuids[assetUuid] = assetType;
  146. if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
  147. {
  148. GetWearableAssetUuids(assetUuid, assetUuids);
  149. }
  150. else if ((sbyte)AssetType.Gesture == assetType)
  151. {
  152. GetGestureAssetUuids(assetUuid, assetUuids);
  153. }
  154. else if ((sbyte)AssetType.Notecard == assetType)
  155. {
  156. GetTextEmbeddedAssetUuids(assetUuid, assetUuids);
  157. }
  158. else if ((sbyte)AssetType.LSLText == assetType)
  159. {
  160. GetTextEmbeddedAssetUuids(assetUuid, assetUuids);
  161. }
  162. else if ((sbyte)OpenSimAssetType.Material == assetType)
  163. {
  164. GetMaterialAssetUuids(assetUuid, assetUuids);
  165. }
  166. else if ((sbyte)AssetType.Object == assetType)
  167. {
  168. GetSceneObjectAssetUuids(assetUuid, assetUuids);
  169. }
  170. }
  171. catch (Exception)
  172. {
  173. m_log.ErrorFormat(
  174. "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}",
  175. assetUuid, assetType);
  176. throw;
  177. }
  178. }
  179. /// <summary>
  180. /// Gather all the asset uuids associated with a given object.
  181. /// </summary>
  182. /// <remarks>
  183. /// This includes both those directly associated with
  184. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  185. /// within this object).
  186. /// </remarks>
  187. /// <param name="sceneObject">The scene object for which to gather assets</param>
  188. /// <param name="assetUuids">
  189. /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset.
  190. /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown.
  191. /// </param>
  192. public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, sbyte> assetUuids)
  193. {
  194. // m_log.DebugFormat(
  195. // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
  196. SceneObjectPart[] parts = sceneObject.Parts;
  197. for (int i = 0; i < parts.Length; i++)
  198. {
  199. SceneObjectPart part = parts[i];
  200. // m_log.DebugFormat(
  201. // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
  202. try
  203. {
  204. Primitive.TextureEntry textureEntry = part.Shape.Textures;
  205. if (textureEntry != null)
  206. {
  207. // Get the prim's default texture. This will be used for faces which don't have their own texture
  208. if (textureEntry.DefaultTexture != null)
  209. GatherTextureEntryAssets(textureEntry.DefaultTexture, assetUuids);
  210. if (textureEntry.FaceTextures != null)
  211. {
  212. // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture)
  213. foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
  214. {
  215. if (texture != null)
  216. GatherTextureEntryAssets(texture, assetUuids);
  217. }
  218. }
  219. }
  220. // If the prim is a sculpt then preserve this information too
  221. if (part.Shape.SculptTexture != UUID.Zero)
  222. assetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture;
  223. if (part.Shape.ProjectionTextureUUID != UUID.Zero)
  224. assetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture;
  225. if (part.CollisionSound != UUID.Zero)
  226. assetUuids[part.CollisionSound] = (sbyte)AssetType.Sound;
  227. if (part.ParticleSystem.Length > 0)
  228. {
  229. try
  230. {
  231. Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
  232. if (ps.Texture != UUID.Zero)
  233. assetUuids[ps.Texture] = (sbyte)AssetType.Texture;
  234. }
  235. catch (Exception)
  236. {
  237. m_log.WarnFormat(
  238. "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
  239. part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
  240. }
  241. }
  242. TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
  243. // Now analyze this prim's inventory items to preserve all the uuids that they reference
  244. foreach (TaskInventoryItem tii in taskDictionary.Values)
  245. {
  246. // m_log.DebugFormat(
  247. // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}",
  248. // tii.Name, tii.Type, part.Name, part.UUID);
  249. if (!assetUuids.ContainsKey(tii.AssetID))
  250. GatherAssetUuids(tii.AssetID, (sbyte)tii.Type, assetUuids);
  251. }
  252. // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed
  253. // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and
  254. // inventory transfer. There needs to be a way for a module to register a method without assuming a
  255. // Scene.EventManager is present.
  256. // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids);
  257. // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs
  258. GatherMaterialsUuids(part, assetUuids);
  259. }
  260. catch (Exception e)
  261. {
  262. m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e);
  263. m_log.DebugFormat(
  264. "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)",
  265. part.Shape.TextureEntry.Length);
  266. }
  267. }
  268. }
  269. /// <summary>
  270. /// Gather all the asset uuids found in one face of a Texture Entry.
  271. /// </summary>
  272. private void GatherTextureEntryAssets(Primitive.TextureEntryFace texture, IDictionary<UUID, sbyte> assetUuids)
  273. {
  274. assetUuids[texture.TextureID] = (sbyte)AssetType.Texture;
  275. if (texture.MaterialID != UUID.Zero)
  276. {
  277. GatherAssetUuids(texture.MaterialID, (sbyte)OpenSimAssetType.Material, assetUuids);
  278. }
  279. }
  280. /// <summary>
  281. /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps
  282. /// stored in legacy format in part.DynAttrs
  283. /// </summary>
  284. /// <param name="part"></param>
  285. /// <param name="assetUuids"></param>
  286. //public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, AssetType> assetUuids)
  287. public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, sbyte> assetUuids)
  288. {
  289. // scan thru the dynAttrs map of this part for any textures used as materials
  290. OSD osdMaterials = null;
  291. lock (part.DynAttrs)
  292. {
  293. if (part.DynAttrs.ContainsStore("OpenSim", "Materials"))
  294. {
  295. OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials");
  296. if (materialsStore == null)
  297. return;
  298. materialsStore.TryGetValue("Materials", out osdMaterials);
  299. }
  300. if (osdMaterials != null)
  301. {
  302. //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd));
  303. if (osdMaterials is OSDArray)
  304. {
  305. OSDArray matsArr = osdMaterials as OSDArray;
  306. foreach (OSDMap matMap in matsArr)
  307. {
  308. try
  309. {
  310. if (matMap.ContainsKey("Material"))
  311. {
  312. OSDMap mat = matMap["Material"] as OSDMap;
  313. if (mat.ContainsKey("NormMap"))
  314. {
  315. UUID normalMapId = mat["NormMap"].AsUUID();
  316. if (normalMapId != UUID.Zero)
  317. {
  318. assetUuids[normalMapId] = (sbyte)AssetType.Texture;
  319. //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString());
  320. }
  321. }
  322. if (mat.ContainsKey("SpecMap"))
  323. {
  324. UUID specularMapId = mat["SpecMap"].AsUUID();
  325. if (specularMapId != UUID.Zero)
  326. {
  327. assetUuids[specularMapId] = (sbyte)AssetType.Texture;
  328. //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString());
  329. }
  330. }
  331. }
  332. }
  333. catch (Exception e)
  334. {
  335. m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message);
  336. }
  337. }
  338. }
  339. }
  340. }
  341. }
  342. /// <summary>
  343. /// Get an asset synchronously, potentially using an asynchronous callback. If the
  344. /// asynchronous callback is used, we will wait for it to complete.
  345. /// </summary>
  346. /// <param name="uuid"></param>
  347. /// <returns></returns>
  348. protected virtual AssetBase GetAsset(UUID uuid)
  349. {
  350. return m_assetService.Get(uuid.ToString());
  351. // XXX: Switching to do this synchronously where the call was async before but we always waited for it
  352. // to complete anyway!
  353. // m_waitingForObjectAsset = true;
  354. // m_assetCache.Get(uuid.ToString(), this, AssetReceived);
  355. //
  356. // // The asset cache callback can either
  357. // //
  358. // // 1. Complete on the same thread (if the asset is already in the cache) or
  359. // // 2. Come in via a different thread (if we need to go fetch it).
  360. // //
  361. // // The code below handles both these alternatives.
  362. // lock (this)
  363. // {
  364. // if (m_waitingForObjectAsset)
  365. // {
  366. // Monitor.Wait(this);
  367. // m_waitingForObjectAsset = false;
  368. // }
  369. // }
  370. //
  371. // return m_requestedObjectAsset;
  372. }
  373. /// <summary>
  374. /// Record the asset uuids embedded within the given text (e.g. a script).
  375. /// </summary>
  376. /// <param name="textAssetUuid"></param>
  377. /// <param name="assetUuids">Dictionary in which to record the references</param>
  378. private void GetTextEmbeddedAssetUuids(UUID textAssetUuid, IDictionary<UUID, sbyte> assetUuids)
  379. {
  380. // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
  381. AssetBase textAsset = GetAsset(textAssetUuid);
  382. if (null != textAsset)
  383. GetTextEmbeddedAssetUuids(textAsset, assetUuids);
  384. }
  385. /// <summary>
  386. /// Record the asset uuids embedded within the given text (e.g. a script).
  387. /// </summary>
  388. /// <param name="textAsset"></param>
  389. /// <param name="assetUuids">Dictionary in which to record the references</param>
  390. private void GetTextEmbeddedAssetUuids(AssetBase textAsset, IDictionary<UUID, sbyte> assetUuids)
  391. {
  392. // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
  393. string script = Utils.BytesToString(textAsset.Data);
  394. // m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
  395. MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script);
  396. // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count);
  397. foreach (Match uuidMatch in uuidMatches)
  398. {
  399. UUID uuid = new UUID(uuidMatch.Value);
  400. // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
  401. // Embedded asset references (if not false positives) could be for many types of asset, so we will
  402. // label these as unknown.
  403. assetUuids[uuid] = (sbyte)AssetType.Unknown;
  404. }
  405. }
  406. /// <summary>
  407. /// Record the uuids referenced by the given wearable asset
  408. /// </summary>
  409. /// <param name="wearableAssetUuid"></param>
  410. /// <param name="assetUuids">Dictionary in which to record the references</param>
  411. private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, sbyte> assetUuids)
  412. {
  413. AssetBase assetBase = GetAsset(wearableAssetUuid);
  414. if (null != assetBase)
  415. GetWearableAssetUuids(assetBase, assetUuids);
  416. }
  417. /// <summary>
  418. /// Record the uuids referenced by the given wearable asset
  419. /// </summary>
  420. /// <param name="assetBase"></param>
  421. /// <param name="assetUuids">Dictionary in which to record the references</param>
  422. private void GetWearableAssetUuids(AssetBase assetBase, IDictionary<UUID, sbyte> assetUuids)
  423. {
  424. //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
  425. AssetWearable wearableAsset = new AssetBodypart(assetBase.FullID, assetBase.Data);
  426. wearableAsset.Decode();
  427. //m_log.DebugFormat(
  428. // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
  429. foreach (UUID uuid in wearableAsset.Textures.Values)
  430. {
  431. assetUuids[uuid] = (sbyte)AssetType.Texture;
  432. }
  433. }
  434. /// <summary>
  435. /// Get all the asset uuids associated with a given object. This includes both those directly associated with
  436. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  437. /// within this object).
  438. /// </summary>
  439. /// <param name="sceneObject"></param>
  440. /// <param name="assetUuids"></param>
  441. private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, sbyte> assetUuids)
  442. {
  443. AssetBase sceneObjectAsset = GetAsset(sceneObjectUuid);
  444. if (null != sceneObjectAsset)
  445. GetSceneObjectAssetUuids(sceneObjectAsset, assetUuids);
  446. }
  447. /// <summary>
  448. /// Get all the asset uuids associated with a given object. This includes both those directly associated with
  449. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  450. /// within this object).
  451. /// </summary>
  452. /// <param name="sceneObjectAsset"></param>
  453. /// <param name="assetUuids"></param>
  454. private void GetSceneObjectAssetUuids(AssetBase sceneObjectAsset, IDictionary<UUID, sbyte> assetUuids)
  455. {
  456. string xml = Utils.BytesToString(sceneObjectAsset.Data);
  457. CoalescedSceneObjects coa;
  458. if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
  459. {
  460. foreach (SceneObjectGroup sog in coa.Objects)
  461. GatherAssetUuids(sog, assetUuids);
  462. }
  463. else
  464. {
  465. SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
  466. if (null != sog)
  467. GatherAssetUuids(sog, assetUuids);
  468. }
  469. }
  470. /// <summary>
  471. /// Get the asset uuid associated with a gesture
  472. /// </summary>
  473. /// <param name="gestureUuid"></param>
  474. /// <param name="assetUuids"></param>
  475. private void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, sbyte> assetUuids)
  476. {
  477. AssetBase gestureAsset = GetAsset(gestureUuid);
  478. if (null == gestureAsset)
  479. return;
  480. GetGestureAssetUuids(gestureAsset, assetUuids);
  481. }
  482. /// <summary>
  483. /// Get the asset uuid associated with a gesture
  484. /// </summary>
  485. /// <param name="gestureAsset"></param>
  486. /// <param name="assetUuids"></param>
  487. private void GetGestureAssetUuids(AssetBase gestureAsset, IDictionary<UUID, sbyte> assetUuids)
  488. {
  489. using (MemoryStream ms = new MemoryStream(gestureAsset.Data))
  490. using (StreamReader sr = new StreamReader(ms))
  491. {
  492. sr.ReadLine(); // Unknown (Version?)
  493. sr.ReadLine(); // Unknown
  494. sr.ReadLine(); // Unknown
  495. sr.ReadLine(); // Name
  496. sr.ReadLine(); // Comment ?
  497. int count = Convert.ToInt32(sr.ReadLine()); // Item count
  498. for (int i = 0 ; i < count ; i++)
  499. {
  500. string type = sr.ReadLine();
  501. if (type == null)
  502. break;
  503. string name = sr.ReadLine();
  504. if (name == null)
  505. break;
  506. string id = sr.ReadLine();
  507. if (id == null)
  508. break;
  509. string unknown = sr.ReadLine();
  510. if (unknown == null)
  511. break;
  512. // If it can be parsed as a UUID, it is an asset ID
  513. UUID uuid;
  514. if (UUID.TryParse(id, out uuid))
  515. assetUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important
  516. }
  517. }
  518. }
  519. /// <summary>
  520. /// Get the asset uuid's referenced in a material.
  521. /// </summary>
  522. private void GetMaterialAssetUuids(UUID materialUuid, IDictionary<UUID, sbyte> assetUuids)
  523. {
  524. AssetBase assetBase = GetAsset(materialUuid);
  525. if (null == assetBase)
  526. return;
  527. GetMaterialAssetUuids(assetBase, assetUuids);
  528. }
  529. /// <summary>
  530. /// Get the asset uuid's referenced in a material.
  531. /// </summary>
  532. private void GetMaterialAssetUuids(AssetBase materialAsset, IDictionary<UUID, sbyte> assetUuids)
  533. {
  534. OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data);
  535. UUID normMap = mat["NormMap"].AsUUID();
  536. if (normMap != UUID.Zero)
  537. assetUuids[normMap] = (sbyte)AssetType.Texture;
  538. UUID specMap = mat["SpecMap"].AsUUID();
  539. if (specMap != UUID.Zero)
  540. assetUuids[specMap] = (sbyte)AssetType.Texture;
  541. }
  542. }
  543. public class HGUuidGatherer : UuidGatherer
  544. {
  545. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  546. protected string m_assetServerURL;
  547. public HGUuidGatherer(IAssetService assetService, string assetServerURL)
  548. : base(assetService)
  549. {
  550. m_assetServerURL = assetServerURL;
  551. if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))
  552. m_assetServerURL = m_assetServerURL + "/";
  553. }
  554. protected override AssetBase GetAsset(UUID uuid)
  555. {
  556. if (string.Empty == m_assetServerURL)
  557. return base.GetAsset(uuid);
  558. else
  559. return FetchAsset(uuid);
  560. }
  561. public AssetBase FetchAsset(UUID assetID)
  562. {
  563. // Test if it's already here
  564. AssetBase asset = m_assetService.Get(assetID.ToString());
  565. if (asset == null)
  566. {
  567. // It's not, so fetch it from abroad
  568. asset = m_assetService.Get(m_assetServerURL + assetID.ToString());
  569. if (asset != null)
  570. m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL);
  571. else
  572. m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL);
  573. }
  574. //else
  575. // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL);
  576. return asset;
  577. }
  578. }
  579. /// <summary>
  580. /// Gather uuids for a given entity.
  581. /// </summary>
  582. /// <remarks>
  583. /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts
  584. /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets
  585. /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be
  586. /// retrieved to work out which assets it references).
  587. /// </remarks>
  588. public class IteratingUuidGatherer
  589. {
  590. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  591. /// <summary>
  592. /// Is gathering complete?
  593. /// </summary>
  594. public bool Complete { get { return m_assetUuidsToInspect.Count <= 0; } }
  595. /// <summary>
  596. /// Gets the next UUID to inspect.
  597. /// </summary>
  598. /// <value>If there is no next UUID then returns null</value>
  599. public UUID? NextUuidToInspect
  600. {
  601. get
  602. {
  603. if (Complete)
  604. return null;
  605. else
  606. return m_assetUuidsToInspect.Peek();
  607. }
  608. }
  609. protected IAssetService m_assetService;
  610. protected IDictionary<UUID, sbyte> m_gatheredAssetUuids;
  611. protected Queue<UUID> m_assetUuidsToInspect;
  612. /// <summary>
  613. /// Initializes a new instance of the <see cref="OpenSim.Region.Framework.Scenes.UuidGatherer"/> class.
  614. /// </summary>
  615. /// <param name="assetService">
  616. /// Asset service.
  617. /// </param>
  618. /// <param name="collector">
  619. /// Gathered UUIDs will be collected in this dictinaory.
  620. /// It can be pre-populated if you want to stop the gatherer from analyzing assets that have already been fetched and inspected.
  621. /// </param>
  622. public IteratingUuidGatherer(IAssetService assetService, IDictionary<UUID, sbyte> collector)
  623. {
  624. m_assetService = assetService;
  625. m_gatheredAssetUuids = collector;
  626. // FIXME: Not efficient for searching, can improve.
  627. m_assetUuidsToInspect = new Queue<UUID>();
  628. }
  629. /// <summary>
  630. /// Adds the asset uuid for inspection during the gathering process.
  631. /// </summary>
  632. /// <returns><c>true</c>, if for inspection was added, <c>false</c> otherwise.</returns>
  633. /// <param name="uuid">UUID.</param>
  634. public bool AddForInspection(UUID uuid)
  635. {
  636. if (m_assetUuidsToInspect.Contains(uuid))
  637. return false;
  638. m_assetUuidsToInspect.Enqueue(uuid);
  639. return true;
  640. }
  641. /// <summary>
  642. /// Gather all the asset uuids associated with a given object.
  643. /// </summary>
  644. /// <remarks>
  645. /// This includes both those directly associated with
  646. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  647. /// within this object).
  648. /// </remarks>
  649. /// <param name="sceneObject">The scene object for which to gather assets</param>
  650. public void AddForInspection(SceneObjectGroup sceneObject)
  651. {
  652. // m_log.DebugFormat(
  653. // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID);
  654. SceneObjectPart[] parts = sceneObject.Parts;
  655. for (int i = 0; i < parts.Length; i++)
  656. {
  657. SceneObjectPart part = parts[i];
  658. // m_log.DebugFormat(
  659. // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID);
  660. try
  661. {
  662. Primitive.TextureEntry textureEntry = part.Shape.Textures;
  663. if (textureEntry != null)
  664. {
  665. // Get the prim's default texture. This will be used for faces which don't have their own texture
  666. if (textureEntry.DefaultTexture != null)
  667. RecordTextureEntryAssetUuids(textureEntry.DefaultTexture);
  668. if (textureEntry.FaceTextures != null)
  669. {
  670. // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture)
  671. foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
  672. {
  673. if (texture != null)
  674. RecordTextureEntryAssetUuids(texture);
  675. }
  676. }
  677. }
  678. // If the prim is a sculpt then preserve this information too
  679. if (part.Shape.SculptTexture != UUID.Zero)
  680. m_gatheredAssetUuids[part.Shape.SculptTexture] = (sbyte)AssetType.Texture;
  681. if (part.Shape.ProjectionTextureUUID != UUID.Zero)
  682. m_gatheredAssetUuids[part.Shape.ProjectionTextureUUID] = (sbyte)AssetType.Texture;
  683. if (part.CollisionSound != UUID.Zero)
  684. m_gatheredAssetUuids[part.CollisionSound] = (sbyte)AssetType.Sound;
  685. if (part.ParticleSystem.Length > 0)
  686. {
  687. try
  688. {
  689. Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0);
  690. if (ps.Texture != UUID.Zero)
  691. m_gatheredAssetUuids[ps.Texture] = (sbyte)AssetType.Texture;
  692. }
  693. catch (Exception)
  694. {
  695. m_log.WarnFormat(
  696. "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.",
  697. part.Name, part.UUID, sceneObject.Name, sceneObject.UUID);
  698. }
  699. }
  700. TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone();
  701. // Now analyze this prim's inventory items to preserve all the uuids that they reference
  702. foreach (TaskInventoryItem tii in taskDictionary.Values)
  703. {
  704. // m_log.DebugFormat(
  705. // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}",
  706. // tii.Name, tii.Type, part.Name, part.UUID);
  707. if (!m_gatheredAssetUuids.ContainsKey(tii.AssetID))
  708. AddForInspection(tii.AssetID, (sbyte)tii.Type);
  709. }
  710. // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed
  711. // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and
  712. // inventory transfer. There needs to be a way for a module to register a method without assuming a
  713. // Scene.EventManager is present.
  714. // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids);
  715. // still needed to retrieve textures used as materials for any parts containing legacy materials stored in DynAttrs
  716. RecordMaterialsUuids(part);
  717. }
  718. catch (Exception e)
  719. {
  720. m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e);
  721. m_log.DebugFormat(
  722. "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)",
  723. part.Shape.TextureEntry.Length);
  724. }
  725. }
  726. }
  727. /// <summary>
  728. /// Gathers the next set of assets returned by the next uuid to get from the asset service.
  729. /// </summary>
  730. /// <returns>false if gathering is already complete, true otherwise</returns>
  731. public bool GatherNext()
  732. {
  733. if (Complete)
  734. return false;
  735. GetAssetUuids(m_assetUuidsToInspect.Dequeue());
  736. return true;
  737. }
  738. /// <summary>
  739. /// Gathers all remaining asset UUIDS no matter how many calls are required to the asset service.
  740. /// </summary>
  741. /// <returns>false if gathering is already complete, true otherwise</returns>
  742. public bool GatherAll()
  743. {
  744. if (Complete)
  745. return false;
  746. while (GatherNext());
  747. return true;
  748. }
  749. /// <summary>
  750. /// Gather all the asset uuids associated with the asset referenced by a given uuid
  751. /// </summary>
  752. /// <remarks>
  753. /// This includes both those directly associated with
  754. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  755. /// within this object).
  756. /// This method assumes that the asset type associated with this asset in persistent storage is correct (which
  757. /// should always be the case). So with this method we always need to retrieve asset data even if the asset
  758. /// is of a type which is known not to reference any other assets
  759. /// </remarks>
  760. /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param>
  761. private void GetAssetUuids(UUID assetUuid)
  762. {
  763. // avoid infinite loops
  764. if (m_gatheredAssetUuids.ContainsKey(assetUuid))
  765. return;
  766. try
  767. {
  768. AssetBase assetBase = GetAsset(assetUuid);
  769. if (null != assetBase)
  770. {
  771. sbyte assetType = assetBase.Type;
  772. m_gatheredAssetUuids[assetUuid] = assetType;
  773. if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
  774. {
  775. RecordWearableAssetUuids(assetBase);
  776. }
  777. else if ((sbyte)AssetType.Gesture == assetType)
  778. {
  779. RecordGestureAssetUuids(assetBase);
  780. }
  781. else if ((sbyte)AssetType.Notecard == assetType)
  782. {
  783. RecordTextEmbeddedAssetUuids(assetBase);
  784. }
  785. else if ((sbyte)AssetType.LSLText == assetType)
  786. {
  787. RecordTextEmbeddedAssetUuids(assetBase);
  788. }
  789. else if ((sbyte)OpenSimAssetType.Material == assetType)
  790. {
  791. RecordMaterialAssetUuids(assetBase);
  792. }
  793. else if ((sbyte)AssetType.Object == assetType)
  794. {
  795. RecordSceneObjectAssetUuids(assetBase);
  796. }
  797. }
  798. }
  799. catch (Exception)
  800. {
  801. m_log.ErrorFormat("[UUID GATHERER]: Failed to gather uuids for asset id {0}", assetUuid);
  802. throw;
  803. }
  804. }
  805. private void AddForInspection(UUID assetUuid, sbyte assetType)
  806. {
  807. // Here, we want to collect uuids which require further asset fetches but mark the others as gathered
  808. try
  809. {
  810. m_gatheredAssetUuids[assetUuid] = assetType;
  811. if ((sbyte)AssetType.Bodypart == assetType || (sbyte)AssetType.Clothing == assetType)
  812. {
  813. AddForInspection(assetUuid);
  814. }
  815. else if ((sbyte)AssetType.Gesture == assetType)
  816. {
  817. AddForInspection(assetUuid);
  818. }
  819. else if ((sbyte)AssetType.Notecard == assetType)
  820. {
  821. AddForInspection(assetUuid);
  822. }
  823. else if ((sbyte)AssetType.LSLText == assetType)
  824. {
  825. AddForInspection(assetUuid);
  826. }
  827. else if ((sbyte)OpenSimAssetType.Material == assetType)
  828. {
  829. AddForInspection(assetUuid);
  830. }
  831. else if ((sbyte)AssetType.Object == assetType)
  832. {
  833. AddForInspection(assetUuid);
  834. }
  835. }
  836. catch (Exception)
  837. {
  838. m_log.ErrorFormat(
  839. "[ITERATABLE UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}",
  840. assetUuid, assetType);
  841. throw;
  842. }
  843. }
  844. /// <summary>
  845. /// Collect all the asset uuids found in one face of a Texture Entry.
  846. /// </summary>
  847. private void RecordTextureEntryAssetUuids(Primitive.TextureEntryFace texture)
  848. {
  849. m_gatheredAssetUuids[texture.TextureID] = (sbyte)AssetType.Texture;
  850. if (texture.MaterialID != UUID.Zero)
  851. AddForInspection(texture.MaterialID);
  852. }
  853. /// <summary>
  854. /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps
  855. /// stored in legacy format in part.DynAttrs
  856. /// </summary>
  857. /// <param name="part"></param>
  858. private void RecordMaterialsUuids(SceneObjectPart part)
  859. {
  860. // scan thru the dynAttrs map of this part for any textures used as materials
  861. OSD osdMaterials = null;
  862. lock (part.DynAttrs)
  863. {
  864. if (part.DynAttrs.ContainsStore("OpenSim", "Materials"))
  865. {
  866. OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials");
  867. if (materialsStore == null)
  868. return;
  869. materialsStore.TryGetValue("Materials", out osdMaterials);
  870. }
  871. if (osdMaterials != null)
  872. {
  873. //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd));
  874. if (osdMaterials is OSDArray)
  875. {
  876. OSDArray matsArr = osdMaterials as OSDArray;
  877. foreach (OSDMap matMap in matsArr)
  878. {
  879. try
  880. {
  881. if (matMap.ContainsKey("Material"))
  882. {
  883. OSDMap mat = matMap["Material"] as OSDMap;
  884. if (mat.ContainsKey("NormMap"))
  885. {
  886. UUID normalMapId = mat["NormMap"].AsUUID();
  887. if (normalMapId != UUID.Zero)
  888. {
  889. m_gatheredAssetUuids[normalMapId] = (sbyte)AssetType.Texture;
  890. //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString());
  891. }
  892. }
  893. if (mat.ContainsKey("SpecMap"))
  894. {
  895. UUID specularMapId = mat["SpecMap"].AsUUID();
  896. if (specularMapId != UUID.Zero)
  897. {
  898. m_gatheredAssetUuids[specularMapId] = (sbyte)AssetType.Texture;
  899. //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString());
  900. }
  901. }
  902. }
  903. }
  904. catch (Exception e)
  905. {
  906. m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message);
  907. }
  908. }
  909. }
  910. }
  911. }
  912. }
  913. /// <summary>
  914. /// Get an asset synchronously, potentially using an asynchronous callback. If the
  915. /// asynchronous callback is used, we will wait for it to complete.
  916. /// </summary>
  917. /// <param name="uuid"></param>
  918. /// <returns></returns>
  919. protected virtual AssetBase GetAsset(UUID uuid)
  920. {
  921. return m_assetService.Get(uuid.ToString());
  922. }
  923. /// <summary>
  924. /// Record the asset uuids embedded within the given text (e.g. a script).
  925. /// </summary>
  926. /// <param name="textAsset"></param>
  927. private void RecordTextEmbeddedAssetUuids(AssetBase textAsset)
  928. {
  929. // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId);
  930. string script = Utils.BytesToString(textAsset.Data);
  931. // m_log.DebugFormat("[ARCHIVER]: Script {0}", script);
  932. MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script);
  933. // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count);
  934. foreach (Match uuidMatch in uuidMatches)
  935. {
  936. UUID uuid = new UUID(uuidMatch.Value);
  937. // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid);
  938. AddForInspection(uuid);
  939. }
  940. }
  941. /// <summary>
  942. /// Record the uuids referenced by the given wearable asset
  943. /// </summary>
  944. /// <param name="assetBase"></param>
  945. private void RecordWearableAssetUuids(AssetBase assetBase)
  946. {
  947. //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data));
  948. AssetWearable wearableAsset = new AssetBodypart(assetBase.FullID, assetBase.Data);
  949. wearableAsset.Decode();
  950. //m_log.DebugFormat(
  951. // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count);
  952. foreach (UUID uuid in wearableAsset.Textures.Values)
  953. m_gatheredAssetUuids[uuid] = (sbyte)AssetType.Texture;
  954. }
  955. /// <summary>
  956. /// Get all the asset uuids associated with a given object. This includes both those directly associated with
  957. /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained
  958. /// within this object).
  959. /// </summary>
  960. /// <param name="sceneObjectAsset"></param>
  961. private void RecordSceneObjectAssetUuids(AssetBase sceneObjectAsset)
  962. {
  963. string xml = Utils.BytesToString(sceneObjectAsset.Data);
  964. CoalescedSceneObjects coa;
  965. if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa))
  966. {
  967. foreach (SceneObjectGroup sog in coa.Objects)
  968. AddForInspection(sog);
  969. }
  970. else
  971. {
  972. SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml);
  973. if (null != sog)
  974. AddForInspection(sog);
  975. }
  976. }
  977. /// <summary>
  978. /// Get the asset uuid associated with a gesture
  979. /// </summary>
  980. /// <param name="gestureAsset"></param>
  981. private void RecordGestureAssetUuids(AssetBase gestureAsset)
  982. {
  983. using (MemoryStream ms = new MemoryStream(gestureAsset.Data))
  984. using (StreamReader sr = new StreamReader(ms))
  985. {
  986. sr.ReadLine(); // Unknown (Version?)
  987. sr.ReadLine(); // Unknown
  988. sr.ReadLine(); // Unknown
  989. sr.ReadLine(); // Name
  990. sr.ReadLine(); // Comment ?
  991. int count = Convert.ToInt32(sr.ReadLine()); // Item count
  992. for (int i = 0 ; i < count ; i++)
  993. {
  994. string type = sr.ReadLine();
  995. if (type == null)
  996. break;
  997. string name = sr.ReadLine();
  998. if (name == null)
  999. break;
  1000. string id = sr.ReadLine();
  1001. if (id == null)
  1002. break;
  1003. string unknown = sr.ReadLine();
  1004. if (unknown == null)
  1005. break;
  1006. // If it can be parsed as a UUID, it is an asset ID
  1007. UUID uuid;
  1008. if (UUID.TryParse(id, out uuid))
  1009. m_gatheredAssetUuids[uuid] = (sbyte)AssetType.Animation; // the asset is either an Animation or a Sound, but this distinction isn't important
  1010. }
  1011. }
  1012. }
  1013. /// <summary>
  1014. /// Get the asset uuid's referenced in a material.
  1015. /// </summary>
  1016. private void RecordMaterialAssetUuids(AssetBase materialAsset)
  1017. {
  1018. OSDMap mat = (OSDMap)OSDParser.DeserializeLLSDXml(materialAsset.Data);
  1019. UUID normMap = mat["NormMap"].AsUUID();
  1020. if (normMap != UUID.Zero)
  1021. m_gatheredAssetUuids[normMap] = (sbyte)AssetType.Texture;
  1022. UUID specMap = mat["SpecMap"].AsUUID();
  1023. if (specMap != UUID.Zero)
  1024. m_gatheredAssetUuids[specMap] = (sbyte)AssetType.Texture;
  1025. }
  1026. }
  1027. public class IteratingHGUuidGatherer : IteratingUuidGatherer
  1028. {
  1029. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  1030. protected string m_assetServerURL;
  1031. public IteratingHGUuidGatherer(IAssetService assetService, string assetServerURL, IDictionary<UUID, sbyte> collector)
  1032. : base(assetService, collector)
  1033. {
  1034. m_assetServerURL = assetServerURL;
  1035. if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("="))
  1036. m_assetServerURL = m_assetServerURL + "/";
  1037. }
  1038. protected override AssetBase GetAsset(UUID uuid)
  1039. {
  1040. if (string.Empty == m_assetServerURL)
  1041. return base.GetAsset(uuid);
  1042. else
  1043. return FetchAsset(uuid);
  1044. }
  1045. public AssetBase FetchAsset(UUID assetID)
  1046. {
  1047. // Test if it's already here
  1048. AssetBase asset = m_assetService.Get(assetID.ToString());
  1049. if (asset == null)
  1050. {
  1051. // It's not, so fetch it from abroad
  1052. asset = m_assetService.Get(m_assetServerURL + assetID.ToString());
  1053. if (asset != null)
  1054. m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL);
  1055. else
  1056. m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL);
  1057. }
  1058. //else
  1059. // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL);
  1060. return asset;
  1061. }
  1062. }
  1063. }