clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | |||
42 | namespace OpenSim.Region.Framework.Scenes |
||
43 | { |
||
44 | /// <summary> |
||
45 | /// Gather uuids for a given entity. |
||
46 | /// </summary> |
||
47 | /// <remarks> |
||
48 | /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts |
||
49 | /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets |
||
50 | /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be |
||
51 | /// retrieved to work out which assets it references). |
||
52 | /// </remarks> |
||
53 | public class UuidGatherer |
||
54 | { |
||
55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
56 | |||
57 | protected IAssetService m_assetService; |
||
58 | |||
59 | // /// <summary> |
||
60 | // /// Used as a temporary store of an asset which represents an object. This can be a null if no appropriate |
||
61 | // /// asset was found by the asset service. |
||
62 | // /// </summary> |
||
63 | // private AssetBase m_requestedObjectAsset; |
||
64 | // |
||
65 | // /// <summary> |
||
66 | // /// Signal whether we are currently waiting for the asset service to deliver an asset. |
||
67 | // /// </summary> |
||
68 | // private bool m_waitingForObjectAsset; |
||
69 | |||
70 | public UuidGatherer(IAssetService assetService) |
||
71 | { |
||
72 | m_assetService = assetService; |
||
73 | } |
||
74 | |||
75 | /// <summary> |
||
76 | /// Gather all the asset uuids associated with the asset referenced by a given uuid |
||
77 | /// </summary> |
||
78 | /// <remarks> |
||
79 | /// This includes both those directly associated with |
||
80 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained |
||
81 | /// within this object). |
||
82 | /// </remarks> |
||
83 | /// <param name="assetUuid">The uuid of the asset for which to gather referenced assets</param> |
||
84 | /// <param name="assetType">The type of the asset for the uuid given</param> |
||
85 | /// <param name="assetUuids">The assets gathered</param> |
||
86 | public void GatherAssetUuids(UUID assetUuid, AssetType assetType, IDictionary<UUID, AssetType> assetUuids) |
||
87 | { |
||
88 | // avoid infinite loops |
||
89 | if (assetUuids.ContainsKey(assetUuid)) |
||
90 | return; |
||
91 | |||
92 | try |
||
93 | { |
||
94 | assetUuids[assetUuid] = assetType; |
||
95 | |||
96 | if (AssetType.Bodypart == assetType || AssetType.Clothing == assetType) |
||
97 | { |
||
98 | GetWearableAssetUuids(assetUuid, assetUuids); |
||
99 | } |
||
100 | else if (AssetType.Gesture == assetType) |
||
101 | { |
||
102 | GetGestureAssetUuids(assetUuid, assetUuids); |
||
103 | } |
||
104 | else if (AssetType.Notecard == assetType) |
||
105 | { |
||
106 | GetTextEmbeddedAssetUuids(assetUuid, assetUuids); |
||
107 | } |
||
108 | else if (AssetType.LSLText == assetType) |
||
109 | { |
||
110 | GetTextEmbeddedAssetUuids(assetUuid, assetUuids); |
||
111 | } |
||
112 | else if (AssetType.Object == assetType) |
||
113 | { |
||
114 | GetSceneObjectAssetUuids(assetUuid, assetUuids); |
||
115 | } |
||
116 | } |
||
117 | catch (Exception) |
||
118 | { |
||
119 | m_log.ErrorFormat( |
||
120 | "[UUID GATHERER]: Failed to gather uuids for asset id {0}, type {1}", |
||
121 | assetUuid, assetType); |
||
122 | throw; |
||
123 | } |
||
124 | } |
||
125 | |||
126 | /// <summary> |
||
127 | /// Gather all the asset uuids associated with a given object. |
||
128 | /// </summary> |
||
129 | /// <remarks> |
||
130 | /// This includes both those directly associated with |
||
131 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained |
||
132 | /// within this object). |
||
133 | /// </remarks> |
||
134 | /// <param name="sceneObject">The scene object for which to gather assets</param> |
||
135 | /// <param name="assetUuids"> |
||
136 | /// A dictionary which is populated with the asset UUIDs gathered and the type of that asset. |
||
137 | /// For assets where the type is not clear (e.g. UUIDs extracted from LSL and notecards), the type is Unknown. |
||
138 | /// </param> |
||
139 | public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary<UUID, AssetType> assetUuids) |
||
140 | { |
||
141 | // m_log.DebugFormat( |
||
142 | // "[ASSET GATHERER]: Getting assets for object {0}, {1}", sceneObject.Name, sceneObject.UUID); |
||
143 | |||
144 | SceneObjectPart[] parts = sceneObject.Parts; |
||
145 | for (int i = 0; i < parts.Length; i++) |
||
146 | { |
||
147 | SceneObjectPart part = parts[i]; |
||
148 | |||
149 | // m_log.DebugFormat( |
||
150 | // "[ARCHIVER]: Getting part {0}, {1} for object {2}", part.Name, part.UUID, sceneObject.UUID); |
||
151 | |||
152 | try |
||
153 | { |
||
154 | Primitive.TextureEntry textureEntry = part.Shape.Textures; |
||
155 | if (textureEntry != null) |
||
156 | { |
||
157 | // Get the prim's default texture. This will be used for faces which don't have their own texture |
||
158 | if (textureEntry.DefaultTexture != null) |
||
159 | assetUuids[textureEntry.DefaultTexture.TextureID] = AssetType.Texture; |
||
160 | |||
161 | if (textureEntry.FaceTextures != null) |
||
162 | { |
||
163 | // Loop through the rest of the texture faces (a non-null face means the face is different from DefaultTexture) |
||
164 | foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures) |
||
165 | { |
||
166 | if (texture != null) |
||
167 | assetUuids[texture.TextureID] = AssetType.Texture; |
||
168 | } |
||
169 | } |
||
170 | } |
||
171 | |||
172 | // If the prim is a sculpt then preserve this information too |
||
173 | if (part.Shape.SculptTexture != UUID.Zero) |
||
174 | assetUuids[part.Shape.SculptTexture] = AssetType.Texture; |
||
175 | |||
176 | if (part.Shape.ProjectionTextureUUID != UUID.Zero) |
||
177 | assetUuids[part.Shape.ProjectionTextureUUID] = AssetType.Texture; |
||
178 | |||
179 | if (part.CollisionSound != UUID.Zero) |
||
180 | assetUuids[part.CollisionSound] = AssetType.Sound; |
||
181 | |||
182 | if (part.ParticleSystem.Length > 0) |
||
183 | { |
||
184 | try |
||
185 | { |
||
186 | Primitive.ParticleSystem ps = new Primitive.ParticleSystem(part.ParticleSystem, 0); |
||
187 | if (ps.Texture != UUID.Zero) |
||
188 | assetUuids[ps.Texture] = AssetType.Texture; |
||
189 | } |
||
190 | catch (Exception e) |
||
191 | { |
||
192 | m_log.WarnFormat( |
||
193 | "[UUID GATHERER]: Could not check particle system for part {0} {1} in object {2} {3} since it is corrupt. Continuing.", |
||
194 | part.Name, part.UUID, sceneObject.Name, sceneObject.UUID); |
||
195 | } |
||
196 | } |
||
197 | |||
198 | TaskInventoryDictionary taskDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); |
||
199 | |||
200 | // Now analyze this prim's inventory items to preserve all the uuids that they reference |
||
201 | foreach (TaskInventoryItem tii in taskDictionary.Values) |
||
202 | { |
||
203 | // m_log.DebugFormat( |
||
204 | // "[ARCHIVER]: Analysing item {0} asset type {1} in {2} {3}", |
||
205 | // tii.Name, tii.Type, part.Name, part.UUID); |
||
206 | |||
207 | if (!assetUuids.ContainsKey(tii.AssetID)) |
||
208 | GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); |
||
209 | } |
||
210 | |||
211 | // FIXME: We need to make gathering modular but we cannot yet, since gatherers are not guaranteed |
||
212 | // to be called with scene objects that are in a scene (e.g. in the case of hg asset mapping and |
||
213 | // inventory transfer. There needs to be a way for a module to register a method without assuming a |
||
214 | // Scene.EventManager is present. |
||
215 | // part.ParentGroup.Scene.EventManager.TriggerGatherUuids(part, assetUuids); |
||
216 | |||
217 | GatherMaterialsUuids(part, assetUuids); |
||
218 | } |
||
219 | catch (Exception e) |
||
220 | { |
||
221 | m_log.ErrorFormat("[UUID GATHERER]: Failed to get part - {0}", e); |
||
222 | m_log.DebugFormat( |
||
223 | "[UUID GATHERER]: Texture entry length for prim was {0} (min is 46)", |
||
224 | part.Shape.TextureEntry.Length); |
||
225 | } |
||
226 | } |
||
227 | } |
||
228 | |||
229 | // /// <summary> |
||
230 | // /// The callback made when we request the asset for an object from the asset service. |
||
231 | // /// </summary> |
||
232 | // private void AssetReceived(string id, Object sender, AssetBase asset) |
||
233 | // { |
||
234 | // lock (this) |
||
235 | // { |
||
236 | // m_requestedObjectAsset = asset; |
||
237 | // m_waitingForObjectAsset = false; |
||
238 | // Monitor.Pulse(this); |
||
239 | // } |
||
240 | // } |
||
241 | |||
242 | /// <summary> |
||
243 | /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps |
||
244 | /// </summary> |
||
245 | /// <param name="part"></param> |
||
246 | /// <param name="assetUuids"></param> |
||
247 | public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, AssetType> assetUuids) |
||
248 | { |
||
249 | // scan thru the dynAttrs map of this part for any textures used as materials |
||
250 | OSD osdMaterials = null; |
||
251 | |||
252 | lock (part.DynAttrs) |
||
253 | { |
||
254 | if (part.DynAttrs.ContainsStore("OpenSim", "Materials")) |
||
255 | { |
||
256 | OSDMap materialsStore = part.DynAttrs.GetStore("OpenSim", "Materials"); |
||
257 | |||
258 | if (materialsStore == null) |
||
259 | return; |
||
260 | |||
261 | materialsStore.TryGetValue("Materials", out osdMaterials); |
||
262 | } |
||
263 | |||
264 | if (osdMaterials != null) |
||
265 | { |
||
266 | //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); |
||
267 | |||
268 | if (osdMaterials is OSDArray) |
||
269 | { |
||
270 | OSDArray matsArr = osdMaterials as OSDArray; |
||
271 | foreach (OSDMap matMap in matsArr) |
||
272 | { |
||
273 | try |
||
274 | { |
||
275 | if (matMap.ContainsKey("Material")) |
||
276 | { |
||
277 | OSDMap mat = matMap["Material"] as OSDMap; |
||
278 | if (mat.ContainsKey("NormMap")) |
||
279 | { |
||
280 | UUID normalMapId = mat["NormMap"].AsUUID(); |
||
281 | if (normalMapId != UUID.Zero) |
||
282 | { |
||
283 | assetUuids[normalMapId] = AssetType.Texture; |
||
284 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); |
||
285 | } |
||
286 | } |
||
287 | if (mat.ContainsKey("SpecMap")) |
||
288 | { |
||
289 | UUID specularMapId = mat["SpecMap"].AsUUID(); |
||
290 | if (specularMapId != UUID.Zero) |
||
291 | { |
||
292 | assetUuids[specularMapId] = AssetType.Texture; |
||
293 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); |
||
294 | } |
||
295 | } |
||
296 | } |
||
297 | |||
298 | } |
||
299 | catch (Exception e) |
||
300 | { |
||
301 | m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | } |
||
306 | } |
||
307 | } |
||
308 | |||
309 | /// <summary> |
||
310 | /// Get an asset synchronously, potentially using an asynchronous callback. If the |
||
311 | /// asynchronous callback is used, we will wait for it to complete. |
||
312 | /// </summary> |
||
313 | /// <param name="uuid"></param> |
||
314 | /// <returns></returns> |
||
315 | protected virtual AssetBase GetAsset(UUID uuid) |
||
316 | { |
||
317 | return m_assetService.Get(uuid.ToString()); |
||
318 | |||
319 | // XXX: Switching to do this synchronously where the call was async before but we always waited for it |
||
320 | // to complete anyway! |
||
321 | // m_waitingForObjectAsset = true; |
||
322 | // m_assetCache.Get(uuid.ToString(), this, AssetReceived); |
||
323 | // |
||
324 | // // The asset cache callback can either |
||
325 | // // |
||
326 | // // 1. Complete on the same thread (if the asset is already in the cache) or |
||
327 | // // 2. Come in via a different thread (if we need to go fetch it). |
||
328 | // // |
||
329 | // // The code below handles both these alternatives. |
||
330 | // lock (this) |
||
331 | // { |
||
332 | // if (m_waitingForObjectAsset) |
||
333 | // { |
||
334 | // Monitor.Wait(this); |
||
335 | // m_waitingForObjectAsset = false; |
||
336 | // } |
||
337 | // } |
||
338 | // |
||
339 | // return m_requestedObjectAsset; |
||
340 | } |
||
341 | |||
342 | /// <summary> |
||
343 | /// Record the asset uuids embedded within the given script. |
||
344 | /// </summary> |
||
345 | /// <param name="scriptUuid"></param> |
||
346 | /// <param name="assetUuids">Dictionary in which to record the references</param> |
||
347 | private void GetTextEmbeddedAssetUuids(UUID embeddingAssetId, IDictionary<UUID, AssetType> assetUuids) |
||
348 | { |
||
349 | // m_log.DebugFormat("[ASSET GATHERER]: Getting assets for uuid references in asset {0}", embeddingAssetId); |
||
350 | |||
351 | AssetBase embeddingAsset = GetAsset(embeddingAssetId); |
||
352 | |||
353 | if (null != embeddingAsset) |
||
354 | { |
||
355 | string script = Utils.BytesToString(embeddingAsset.Data); |
||
356 | // m_log.DebugFormat("[ARCHIVER]: Script {0}", script); |
||
357 | MatchCollection uuidMatches = Util.PermissiveUUIDPattern.Matches(script); |
||
358 | // m_log.DebugFormat("[ARCHIVER]: Found {0} matches in text", uuidMatches.Count); |
||
359 | |||
360 | foreach (Match uuidMatch in uuidMatches) |
||
361 | { |
||
362 | UUID uuid = new UUID(uuidMatch.Value); |
||
363 | // m_log.DebugFormat("[ARCHIVER]: Recording {0} in text", uuid); |
||
364 | |||
365 | // Embedded asset references (if not false positives) could be for many types of asset, so we will |
||
366 | // label these as unknown. |
||
367 | assetUuids[uuid] = AssetType.Unknown; |
||
368 | } |
||
369 | } |
||
370 | } |
||
371 | |||
372 | /// <summary> |
||
373 | /// Record the uuids referenced by the given wearable asset |
||
374 | /// </summary> |
||
375 | /// <param name="wearableAssetUuid"></param> |
||
376 | /// <param name="assetUuids">Dictionary in which to record the references</param> |
||
377 | private void GetWearableAssetUuids(UUID wearableAssetUuid, IDictionary<UUID, AssetType> assetUuids) |
||
378 | { |
||
379 | AssetBase assetBase = GetAsset(wearableAssetUuid); |
||
380 | |||
381 | if (null != assetBase) |
||
382 | { |
||
383 | //m_log.Debug(new System.Text.ASCIIEncoding().GetString(bodypartAsset.Data)); |
||
384 | AssetWearable wearableAsset = new AssetBodypart(wearableAssetUuid, assetBase.Data); |
||
385 | wearableAsset.Decode(); |
||
386 | |||
387 | //m_log.DebugFormat( |
||
388 | // "[ARCHIVER]: Wearable asset {0} references {1} assets", wearableAssetUuid, wearableAsset.Textures.Count); |
||
389 | |||
390 | foreach (UUID uuid in wearableAsset.Textures.Values) |
||
391 | { |
||
392 | assetUuids[uuid] = AssetType.Texture; |
||
393 | } |
||
394 | } |
||
395 | } |
||
396 | |||
397 | /// <summary> |
||
398 | /// Get all the asset uuids associated with a given object. This includes both those directly associated with |
||
399 | /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained |
||
400 | /// within this object). |
||
401 | /// </summary> |
||
402 | /// <param name="sceneObject"></param> |
||
403 | /// <param name="assetUuids"></param> |
||
404 | private void GetSceneObjectAssetUuids(UUID sceneObjectUuid, IDictionary<UUID, AssetType> assetUuids) |
||
405 | { |
||
406 | AssetBase objectAsset = GetAsset(sceneObjectUuid); |
||
407 | |||
408 | if (null != objectAsset) |
||
409 | { |
||
410 | string xml = Utils.BytesToString(objectAsset.Data); |
||
411 | |||
412 | CoalescedSceneObjects coa; |
||
413 | if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) |
||
414 | { |
||
415 | foreach (SceneObjectGroup sog in coa.Objects) |
||
416 | GatherAssetUuids(sog, assetUuids); |
||
417 | } |
||
418 | else |
||
419 | { |
||
420 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); |
||
421 | |||
422 | if (null != sog) |
||
423 | GatherAssetUuids(sog, assetUuids); |
||
424 | } |
||
425 | } |
||
426 | } |
||
427 | |||
428 | /// <summary> |
||
429 | /// Get the asset uuid associated with a gesture |
||
430 | /// </summary> |
||
431 | /// <param name="gestureUuid"></param> |
||
432 | /// <param name="assetUuids"></param> |
||
433 | private void GetGestureAssetUuids(UUID gestureUuid, IDictionary<UUID, AssetType> assetUuids) |
||
434 | { |
||
435 | AssetBase assetBase = GetAsset(gestureUuid); |
||
436 | if (null == assetBase) |
||
437 | return; |
||
438 | |||
439 | MemoryStream ms = new MemoryStream(assetBase.Data); |
||
440 | StreamReader sr = new StreamReader(ms); |
||
441 | |||
442 | sr.ReadLine(); // Unknown (Version?) |
||
443 | sr.ReadLine(); // Unknown |
||
444 | sr.ReadLine(); // Unknown |
||
445 | sr.ReadLine(); // Name |
||
446 | sr.ReadLine(); // Comment ? |
||
447 | int count = Convert.ToInt32(sr.ReadLine()); // Item count |
||
448 | |||
449 | for (int i = 0 ; i < count ; i++) |
||
450 | { |
||
451 | string type = sr.ReadLine(); |
||
452 | if (type == null) |
||
453 | break; |
||
454 | string name = sr.ReadLine(); |
||
455 | if (name == null) |
||
456 | break; |
||
457 | string id = sr.ReadLine(); |
||
458 | if (id == null) |
||
459 | break; |
||
460 | string unknown = sr.ReadLine(); |
||
461 | if (unknown == null) |
||
462 | break; |
||
463 | |||
464 | // If it can be parsed as a UUID, it is an asset ID |
||
465 | UUID uuid; |
||
466 | if (UUID.TryParse(id, out uuid)) |
||
467 | assetUuids[uuid] = AssetType.Animation; |
||
468 | } |
||
469 | } |
||
470 | } |
||
471 | |||
472 | public class HGUuidGatherer : UuidGatherer |
||
473 | { |
||
474 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
475 | |||
476 | protected string m_assetServerURL; |
||
477 | |||
478 | public HGUuidGatherer(IAssetService assetService, string assetServerURL) |
||
479 | : base(assetService) |
||
480 | { |
||
481 | m_assetServerURL = assetServerURL; |
||
482 | if (!m_assetServerURL.EndsWith("/") && !m_assetServerURL.EndsWith("=")) |
||
483 | m_assetServerURL = m_assetServerURL + "/"; |
||
484 | } |
||
485 | |||
486 | protected override AssetBase GetAsset(UUID uuid) |
||
487 | { |
||
488 | if (string.Empty == m_assetServerURL) |
||
489 | return base.GetAsset(uuid); |
||
490 | else |
||
491 | return FetchAsset(uuid); |
||
492 | } |
||
493 | |||
494 | public AssetBase FetchAsset(UUID assetID) |
||
495 | { |
||
496 | |||
497 | // Test if it's already here |
||
498 | AssetBase asset = m_assetService.Get(assetID.ToString()); |
||
499 | if (asset == null) |
||
500 | { |
||
501 | // It's not, so fetch it from abroad |
||
502 | asset = m_assetService.Get(m_assetServerURL + assetID.ToString()); |
||
503 | if (asset != null) |
||
504 | m_log.DebugFormat("[HGUUIDGatherer]: Copied asset {0} from {1} to local asset server", assetID, m_assetServerURL); |
||
505 | else |
||
506 | m_log.DebugFormat("[HGUUIDGatherer]: Failed to fetch asset {0} from {1}", assetID, m_assetServerURL); |
||
507 | } |
||
508 | //else |
||
509 | // m_log.DebugFormat("[HGUUIDGatherer]: Asset {0} from {1} was already here", assetID, m_assetServerURL); |
||
510 | |||
511 | return asset; |
||
512 | } |
||
513 | } |
||
514 | } |