diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/AvatarFactory')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 544 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs | 93 |
2 files changed, 606 insertions, 31 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 0a69979..cfb082b 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | |||
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes; | |||
40 | using OpenSim.Services.Interfaces; | 40 | using OpenSim.Services.Interfaces; |
41 | 41 | ||
42 | using Mono.Addins; | 42 | using Mono.Addins; |
43 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
43 | 44 | ||
44 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 45 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
45 | { | 46 | { |
@@ -54,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
54 | 55 | ||
55 | private int m_savetime = 5; // seconds to wait before saving changed appearance | 56 | private int m_savetime = 5; // seconds to wait before saving changed appearance |
56 | private int m_sendtime = 2; // seconds to wait before sending changed appearance | 57 | private int m_sendtime = 2; // seconds to wait before sending changed appearance |
58 | private bool m_reusetextures = false; | ||
57 | 59 | ||
58 | private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates | 60 | private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates |
59 | private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); | 61 | private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); |
@@ -72,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
72 | { | 74 | { |
73 | m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); | 75 | m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); |
74 | m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); | 76 | m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); |
77 | m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures); | ||
78 | |||
75 | // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); | 79 | // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); |
76 | } | 80 | } |
77 | 81 | ||
@@ -130,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
130 | client.OnRequestWearables += Client_OnRequestWearables; | 134 | client.OnRequestWearables += Client_OnRequestWearables; |
131 | client.OnSetAppearance += Client_OnSetAppearance; | 135 | client.OnSetAppearance += Client_OnSetAppearance; |
132 | client.OnAvatarNowWearing += Client_OnAvatarNowWearing; | 136 | client.OnAvatarNowWearing += Client_OnAvatarNowWearing; |
137 | client.OnCachedTextureRequest += Client_OnCachedTextureRequest; | ||
133 | } | 138 | } |
134 | 139 | ||
135 | #endregion | 140 | #endregion |
@@ -140,9 +145,24 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
140 | /// <param name="sp"></param> | 145 | /// <param name="sp"></param> |
141 | /// <param name="texture"></param> | 146 | /// <param name="texture"></param> |
142 | /// <param name="visualParam"></param> | 147 | /// <param name="visualParam"></param> |
143 | public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) | 148 | public void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems) |
144 | { | 149 | { |
145 | SetAppearance(sp, appearance.Texture, appearance.VisualParams); | 150 | SetAppearance(sp, appearance.Texture, appearance.VisualParams, cacheItems); |
151 | } | ||
152 | |||
153 | |||
154 | public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) | ||
155 | { | ||
156 | float oldoff = sp.Appearance.AvatarFeetOffset; | ||
157 | Vector3 oldbox = sp.Appearance.AvatarBoxSize; | ||
158 | |||
159 | SetAppearance(sp, textureEntry, visualParams, cacheItems); | ||
160 | sp.Appearance.SetSize(avSize); | ||
161 | |||
162 | float off = sp.Appearance.AvatarFeetOffset; | ||
163 | Vector3 box = sp.Appearance.AvatarBoxSize; | ||
164 | if (oldoff != off || oldbox != box) | ||
165 | ((ScenePresence)sp).SetSize(box, off); | ||
146 | } | 166 | } |
147 | 167 | ||
148 | /// <summary> | 168 | /// <summary> |
@@ -151,7 +171,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
151 | /// <param name="sp"></param> | 171 | /// <param name="sp"></param> |
152 | /// <param name="texture"></param> | 172 | /// <param name="texture"></param> |
153 | /// <param name="visualParam"></param> | 173 | /// <param name="visualParam"></param> |
154 | public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) | 174 | public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems) |
155 | { | 175 | { |
156 | // m_log.DebugFormat( | 176 | // m_log.DebugFormat( |
157 | // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", | 177 | // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", |
@@ -174,18 +194,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
174 | // m_log.DebugFormat( | 194 | // m_log.DebugFormat( |
175 | // "[AVFACTORY]: Setting visual params for {0} to {1}", | 195 | // "[AVFACTORY]: Setting visual params for {0} to {1}", |
176 | // client.Name, string.Join(", ", visualParamsStrings)); | 196 | // client.Name, string.Join(", ", visualParamsStrings)); |
177 | 197 | /* | |
178 | float oldHeight = sp.Appearance.AvatarHeight; | 198 | float oldHeight = sp.Appearance.AvatarHeight; |
179 | changed = sp.Appearance.SetVisualParams(visualParams); | 199 | changed = sp.Appearance.SetVisualParams(visualParams); |
180 | 200 | ||
181 | if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0) | 201 | if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0) |
182 | ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight); | 202 | ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight); |
183 | } | 203 | */ |
204 | // float oldoff = sp.Appearance.AvatarFeetOffset; | ||
205 | // Vector3 oldbox = sp.Appearance.AvatarBoxSize; | ||
206 | changed = sp.Appearance.SetVisualParams(visualParams); | ||
207 | // float off = sp.Appearance.AvatarFeetOffset; | ||
208 | // Vector3 box = sp.Appearance.AvatarBoxSize; | ||
209 | // if(oldoff != off || oldbox != box) | ||
210 | // ((ScenePresence)sp).SetSize(box,off); | ||
184 | 211 | ||
212 | } | ||
213 | |||
185 | // Process the baked texture array | 214 | // Process the baked texture array |
186 | if (textureEntry != null) | 215 | if (textureEntry != null) |
187 | { | 216 | { |
188 | // m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); | 217 | m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); |
189 | 218 | ||
190 | // WriteBakedTexturesReport(sp, m_log.DebugFormat); | 219 | // WriteBakedTexturesReport(sp, m_log.DebugFormat); |
191 | 220 | ||
@@ -222,7 +251,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
222 | private void SendAppearance(ScenePresence sp) | 251 | private void SendAppearance(ScenePresence sp) |
223 | { | 252 | { |
224 | // Send the appearance to everyone in the scene | 253 | // Send the appearance to everyone in the scene |
225 | sp.SendAppearanceToAllOtherAgents(); | 254 | sp.SendAppearanceToAllOtherClients(); |
226 | 255 | ||
227 | // Send animations back to the avatar as well | 256 | // Send animations back to the avatar as well |
228 | sp.Animator.SendAnimPack(); | 257 | sp.Animator.SendAnimPack(); |
@@ -254,6 +283,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
254 | return GetBakedTextureFaces(sp); | 283 | return GetBakedTextureFaces(sp); |
255 | } | 284 | } |
256 | 285 | ||
286 | public WearableCacheItem[] GetCachedItems(UUID agentId) | ||
287 | { | ||
288 | ScenePresence sp = m_scene.GetScenePresence(agentId); | ||
289 | WearableCacheItem[] items = sp.Appearance.WearableCacheItems; | ||
290 | //foreach (WearableCacheItem item in items) | ||
291 | //{ | ||
292 | |||
293 | //} | ||
294 | return items; | ||
295 | } | ||
296 | |||
257 | public bool SaveBakedTextures(UUID agentId) | 297 | public bool SaveBakedTextures(UUID agentId) |
258 | { | 298 | { |
259 | ScenePresence sp = m_scene.GetScenePresence(agentId); | 299 | ScenePresence sp = m_scene.GetScenePresence(agentId); |
@@ -287,6 +327,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
287 | 327 | ||
288 | if (asset != null) | 328 | if (asset != null) |
289 | { | 329 | { |
330 | // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars | ||
331 | asset.ID = asset.FullID.ToString(); | ||
332 | |||
290 | asset.Temporary = false; | 333 | asset.Temporary = false; |
291 | asset.Local = false; | 334 | asset.Local = false; |
292 | m_scene.AssetService.Store(asset); | 335 | m_scene.AssetService.Store(asset); |
@@ -323,7 +366,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
323 | 366 | ||
324 | public void QueueAppearanceSave(UUID agentid) | 367 | public void QueueAppearanceSave(UUID agentid) |
325 | { | 368 | { |
326 | // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); | 369 | // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); |
327 | 370 | ||
328 | // 10000 ticks per millisecond, 1000 milliseconds per second | 371 | // 10000 ticks per millisecond, 1000 milliseconds per second |
329 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); | 372 | long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); |
@@ -337,6 +380,53 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
337 | public bool ValidateBakedTextureCache(IScenePresence sp) | 380 | public bool ValidateBakedTextureCache(IScenePresence sp) |
338 | { | 381 | { |
339 | bool defonly = true; // are we only using default textures | 382 | bool defonly = true; // are we only using default textures |
383 | IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>(); | ||
384 | IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
385 | WearableCacheItem[] wearableCache = null; | ||
386 | |||
387 | // Cache wearable data for teleport. | ||
388 | // Only makes sense if there's a bake module and a cache module | ||
389 | if (bakedModule != null && cache != null) | ||
390 | { | ||
391 | try | ||
392 | { | ||
393 | wearableCache = bakedModule.Get(sp.UUID); | ||
394 | } | ||
395 | catch (Exception) | ||
396 | { | ||
397 | |||
398 | } | ||
399 | if (wearableCache != null) | ||
400 | { | ||
401 | for (int i = 0; i < wearableCache.Length; i++) | ||
402 | { | ||
403 | cache.Cache(wearableCache[i].TextureAsset); | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | /* | ||
408 | IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>(); | ||
409 | if (invService.GetRootFolder(userID) != null) | ||
410 | { | ||
411 | WearableCacheItem[] wearableCache = null; | ||
412 | if (bakedModule != null) | ||
413 | { | ||
414 | try | ||
415 | { | ||
416 | wearableCache = bakedModule.Get(userID); | ||
417 | appearance.WearableCacheItems = wearableCache; | ||
418 | appearance.WearableCacheItemsDirty = false; | ||
419 | foreach (WearableCacheItem item in wearableCache) | ||
420 | { | ||
421 | appearance.Texture.FaceTextures[item.TextureIndex].TextureID = item.TextureID; | ||
422 | } | ||
423 | } | ||
424 | catch (Exception) | ||
425 | { | ||
426 | |||
427 | } | ||
428 | } | ||
429 | */ | ||
340 | 430 | ||
341 | // Process the texture entry | 431 | // Process the texture entry |
342 | for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) | 432 | for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) |
@@ -344,10 +434,32 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
344 | int idx = AvatarAppearance.BAKE_INDICES[i]; | 434 | int idx = AvatarAppearance.BAKE_INDICES[i]; |
345 | Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; | 435 | Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; |
346 | 436 | ||
347 | // if there is no texture entry, skip it | 437 | // No face, so lets check our baked service cache, teleport or login. |
348 | if (face == null) | 438 | if (face == null) |
349 | continue; | 439 | { |
350 | 440 | if (wearableCache != null) | |
441 | { | ||
442 | // If we find the an appearance item, set it as the textureentry and the face | ||
443 | WearableCacheItem searchitem = WearableCacheItem.SearchTextureIndex((uint) idx, wearableCache); | ||
444 | if (searchitem != null) | ||
445 | { | ||
446 | sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx); | ||
447 | sp.Appearance.Texture.FaceTextures[idx].TextureID = searchitem.TextureID; | ||
448 | face = sp.Appearance.Texture.FaceTextures[idx]; | ||
449 | } | ||
450 | else | ||
451 | { | ||
452 | // if there is no texture entry and no baked cache, skip it | ||
453 | continue; | ||
454 | } | ||
455 | } | ||
456 | else | ||
457 | { | ||
458 | //No texture entry face and no cache. Skip this face. | ||
459 | continue; | ||
460 | } | ||
461 | } | ||
462 | |||
351 | // m_log.DebugFormat( | 463 | // m_log.DebugFormat( |
352 | // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", | 464 | // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", |
353 | // face.TextureID, idx, client.Name, client.AgentId); | 465 | // face.TextureID, idx, client.Name, client.AgentId); |
@@ -374,6 +486,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
374 | public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) | 486 | public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) |
375 | { | 487 | { |
376 | int texturesRebaked = 0; | 488 | int texturesRebaked = 0; |
489 | // IImprovedAssetCache cache = m_scene.RequestModuleInterface<IImprovedAssetCache>(); | ||
377 | 490 | ||
378 | for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) | 491 | for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) |
379 | { | 492 | { |
@@ -480,7 +593,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
480 | 593 | ||
481 | if (sendTime < now) | 594 | if (sendTime < now) |
482 | { | 595 | { |
483 | Util.FireAndForget(o => SendAppearance(avatarID)); | 596 | Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance"); |
484 | m_sendqueue.Remove(avatarID); | 597 | m_sendqueue.Remove(avatarID); |
485 | } | 598 | } |
486 | } | 599 | } |
@@ -498,7 +611,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
498 | 611 | ||
499 | if (sendTime < now) | 612 | if (sendTime < now) |
500 | { | 613 | { |
501 | Util.FireAndForget(o => SaveAppearance(avatarID)); | 614 | Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance"); |
502 | m_savequeue.Remove(avatarID); | 615 | m_savequeue.Remove(avatarID); |
503 | } | 616 | } |
504 | } | 617 | } |
@@ -526,7 +639,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
526 | return; | 639 | return; |
527 | } | 640 | } |
528 | 641 | ||
529 | // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); | 642 | // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); |
530 | 643 | ||
531 | // This could take awhile since it needs to pull inventory | 644 | // This could take awhile since it needs to pull inventory |
532 | // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape | 645 | // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape |
@@ -535,6 +648,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
535 | // multiple save requests. | 648 | // multiple save requests. |
536 | SetAppearanceAssets(sp.UUID, sp.Appearance); | 649 | SetAppearanceAssets(sp.UUID, sp.Appearance); |
537 | 650 | ||
651 | // List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); | ||
652 | // foreach (AvatarAttachment att in attachments) | ||
653 | // { | ||
654 | // m_log.DebugFormat( | ||
655 | // "[AVFACTORY]: For {0} saving attachment {1} at point {2}", | ||
656 | // sp.Name, att.ItemID, att.AttachPoint); | ||
657 | // } | ||
658 | |||
538 | m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); | 659 | m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); |
539 | 660 | ||
540 | // Trigger this here because it's the final step in the set/queue/save process for appearance setting. | 661 | // Trigger this here because it's the final step in the set/queue/save process for appearance setting. |
@@ -542,6 +663,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
542 | m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); | 663 | m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); |
543 | } | 664 | } |
544 | 665 | ||
666 | /// <summary> | ||
667 | /// For a given set of appearance items, check whether the items are valid and add their asset IDs to | ||
668 | /// appearance data. | ||
669 | /// </summary> | ||
670 | /// <param name='userID'></param> | ||
671 | /// <param name='appearance'></param> | ||
545 | private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) | 672 | private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance) |
546 | { | 673 | { |
547 | IInventoryService invService = m_scene.InventoryService; | 674 | IInventoryService invService = m_scene.InventoryService; |
@@ -553,7 +680,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
553 | for (int j = 0; j < appearance.Wearables[i].Count; j++) | 680 | for (int j = 0; j < appearance.Wearables[i].Count; j++) |
554 | { | 681 | { |
555 | if (appearance.Wearables[i][j].ItemID == UUID.Zero) | 682 | if (appearance.Wearables[i][j].ItemID == UUID.Zero) |
683 | { | ||
684 | m_log.WarnFormat( | ||
685 | "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.", | ||
686 | i, j, userID); | ||
687 | |||
556 | continue; | 688 | continue; |
689 | } | ||
557 | 690 | ||
558 | // Ignore ruth's assets | 691 | // Ignore ruth's assets |
559 | if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) | 692 | if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) |
@@ -568,7 +701,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
568 | } | 701 | } |
569 | else | 702 | else |
570 | { | 703 | { |
571 | m_log.ErrorFormat( | 704 | m_log.WarnFormat( |
572 | "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", | 705 | "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", |
573 | appearance.Wearables[i][j].ItemID, (WearableType)i); | 706 | appearance.Wearables[i][j].ItemID, (WearableType)i); |
574 | 707 | ||
@@ -581,8 +714,311 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
581 | { | 714 | { |
582 | m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); | 715 | m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); |
583 | } | 716 | } |
717 | |||
718 | // IInventoryService invService = m_scene.InventoryService; | ||
719 | // bool resetwearable = false; | ||
720 | // if (invService.GetRootFolder(userID) != null) | ||
721 | // { | ||
722 | // for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) | ||
723 | // { | ||
724 | // for (int j = 0; j < appearance.Wearables[i].Count; j++) | ||
725 | // { | ||
726 | // // Check if the default wearables are not set | ||
727 | // if (appearance.Wearables[i][j].ItemID == UUID.Zero) | ||
728 | // { | ||
729 | // switch ((WearableType) i) | ||
730 | // { | ||
731 | // case WearableType.Eyes: | ||
732 | // case WearableType.Hair: | ||
733 | // case WearableType.Shape: | ||
734 | // case WearableType.Skin: | ||
735 | // //case WearableType.Underpants: | ||
736 | // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); | ||
737 | // resetwearable = true; | ||
738 | // m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values."); | ||
739 | // resetwearable = true; | ||
740 | // break; | ||
741 | // | ||
742 | // } | ||
743 | // continue; | ||
744 | // } | ||
745 | // | ||
746 | // // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1 | ||
747 | // if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID) | ||
748 | // { | ||
749 | // switch ((WearableType)i) | ||
750 | // { | ||
751 | // case WearableType.Eyes: | ||
752 | // case WearableType.Hair: | ||
753 | // case WearableType.Shape: | ||
754 | // case WearableType.Skin: | ||
755 | // //case WearableType.Underpants: | ||
756 | // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); | ||
757 | // | ||
758 | // m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i); | ||
759 | // resetwearable = true; | ||
760 | // break; | ||
761 | // | ||
762 | // } | ||
763 | // continue; | ||
764 | // } | ||
765 | // | ||
766 | // InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID); | ||
767 | // baseItem = invService.GetItem(baseItem); | ||
768 | // | ||
769 | // if (baseItem != null) | ||
770 | // { | ||
771 | // appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID); | ||
772 | // int unmodifiedWearableIndexForClosure = i; | ||
773 | // m_scene.AssetService.Get(baseItem.AssetID.ToString(), this, | ||
774 | // delegate(string x, object y, AssetBase z) | ||
775 | // { | ||
776 | // if (z == null) | ||
777 | // { | ||
778 | // TryAndRepairBrokenWearable( | ||
779 | // (WearableType)unmodifiedWearableIndexForClosure, invService, | ||
780 | // userID, appearance); | ||
781 | // } | ||
782 | // }); | ||
783 | // } | ||
784 | // else | ||
785 | // { | ||
786 | // m_log.ErrorFormat( | ||
787 | // "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default", | ||
788 | // appearance.Wearables[i][j].ItemID, (WearableType)i); | ||
789 | // | ||
790 | // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance); | ||
791 | // resetwearable = true; | ||
792 | // | ||
793 | // } | ||
794 | // } | ||
795 | // } | ||
796 | // | ||
797 | // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
798 | // if (appearance.Wearables[(int) WearableType.Eyes] == null) | ||
799 | // { | ||
800 | // m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes)); | ||
801 | // | ||
802 | // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); | ||
803 | // resetwearable = true; | ||
804 | // } | ||
805 | // else | ||
806 | // { | ||
807 | // if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero) | ||
808 | // { | ||
809 | // m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}", | ||
810 | // appearance.Wearables[(int) WearableType.Eyes][0].ItemID, | ||
811 | // appearance.Wearables[(int) WearableType.Eyes][0].AssetID); | ||
812 | // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance); | ||
813 | // resetwearable = true; | ||
814 | // | ||
815 | // } | ||
816 | // | ||
817 | // } | ||
818 | // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
819 | // if (appearance.Wearables[(int)WearableType.Shape] == null) | ||
820 | // { | ||
821 | // m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape)); | ||
822 | // | ||
823 | // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); | ||
824 | // resetwearable = true; | ||
825 | // } | ||
826 | // else | ||
827 | // { | ||
828 | // if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero) | ||
829 | // { | ||
830 | // m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}", | ||
831 | // appearance.Wearables[(int)WearableType.Shape][0].ItemID, | ||
832 | // appearance.Wearables[(int)WearableType.Shape][0].AssetID); | ||
833 | // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance); | ||
834 | // resetwearable = true; | ||
835 | // | ||
836 | // } | ||
837 | // | ||
838 | // } | ||
839 | // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
840 | // if (appearance.Wearables[(int)WearableType.Hair] == null) | ||
841 | // { | ||
842 | // m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair)); | ||
843 | // | ||
844 | // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); | ||
845 | // resetwearable = true; | ||
846 | // } | ||
847 | // else | ||
848 | // { | ||
849 | // if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero) | ||
850 | // { | ||
851 | // m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}", | ||
852 | // appearance.Wearables[(int)WearableType.Hair][0].ItemID, | ||
853 | // appearance.Wearables[(int)WearableType.Hair][0].AssetID); | ||
854 | // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance); | ||
855 | // resetwearable = true; | ||
856 | // | ||
857 | // } | ||
858 | // | ||
859 | // } | ||
860 | // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason.... | ||
861 | // if (appearance.Wearables[(int)WearableType.Skin] == null) | ||
862 | // { | ||
863 | // m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin)); | ||
864 | // | ||
865 | // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); | ||
866 | // resetwearable = true; | ||
867 | // } | ||
868 | // else | ||
869 | // { | ||
870 | // if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero) | ||
871 | // { | ||
872 | // m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}", | ||
873 | // appearance.Wearables[(int)WearableType.Skin][0].ItemID, | ||
874 | // appearance.Wearables[(int)WearableType.Skin][0].AssetID); | ||
875 | // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance); | ||
876 | // resetwearable = true; | ||
877 | // | ||
878 | // } | ||
879 | // | ||
880 | // } | ||
881 | // if (resetwearable) | ||
882 | // { | ||
883 | // ScenePresence presence = null; | ||
884 | // if (m_scene.TryGetScenePresence(userID, out presence)) | ||
885 | // { | ||
886 | // presence.ControllingClient.SendWearables(presence.Appearance.Wearables, | ||
887 | // presence.Appearance.Serial++); | ||
888 | // } | ||
889 | // } | ||
890 | // | ||
891 | // } | ||
892 | // else | ||
893 | // { | ||
894 | // m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID); | ||
895 | // } | ||
896 | } | ||
897 | |||
898 | private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance) | ||
899 | { | ||
900 | UUID defaultwearable = GetDefaultItem(type); | ||
901 | if (defaultwearable != UUID.Zero) | ||
902 | { | ||
903 | UUID newInvItem = UUID.Random(); | ||
904 | InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID) | ||
905 | { | ||
906 | AssetID = | ||
907 | defaultwearable, | ||
908 | AssetType | ||
909 | = | ||
910 | (int) | ||
911 | FolderType | ||
912 | .BodyPart, | ||
913 | CreatorId | ||
914 | = | ||
915 | userID | ||
916 | .ToString | ||
917 | (), | ||
918 | //InvType = (int)InventoryType.Wearable, | ||
919 | |||
920 | Description | ||
921 | = | ||
922 | "Failed Wearable Replacement", | ||
923 | Folder = | ||
924 | invService | ||
925 | .GetFolderForType | ||
926 | (userID, | ||
927 | FolderType | ||
928 | .BodyPart) | ||
929 | .ID, | ||
930 | Flags = (uint) type, | ||
931 | Name = Enum.GetName(typeof (WearableType), type), | ||
932 | BasePermissions = (uint) PermissionMask.Copy, | ||
933 | CurrentPermissions = (uint) PermissionMask.Copy, | ||
934 | EveryOnePermissions = (uint) PermissionMask.Copy, | ||
935 | GroupPermissions = (uint) PermissionMask.Copy, | ||
936 | NextPermissions = (uint) PermissionMask.Copy | ||
937 | }; | ||
938 | invService.AddItem(itembase); | ||
939 | UUID LinkInvItem = UUID.Random(); | ||
940 | itembase = new InventoryItemBase(LinkInvItem, userID) | ||
941 | { | ||
942 | AssetID = | ||
943 | newInvItem, | ||
944 | AssetType | ||
945 | = | ||
946 | (int) | ||
947 | AssetType | ||
948 | .Link, | ||
949 | CreatorId | ||
950 | = | ||
951 | userID | ||
952 | .ToString | ||
953 | (), | ||
954 | InvType = (int) InventoryType.Wearable, | ||
955 | |||
956 | Description | ||
957 | = | ||
958 | "Failed Wearable Replacement", | ||
959 | Folder = | ||
960 | invService | ||
961 | .GetFolderForType | ||
962 | (userID, | ||
963 | FolderType | ||
964 | .CurrentOutfit) | ||
965 | .ID, | ||
966 | Flags = (uint) type, | ||
967 | Name = Enum.GetName(typeof (WearableType), type), | ||
968 | BasePermissions = (uint) PermissionMask.Copy, | ||
969 | CurrentPermissions = (uint) PermissionMask.Copy, | ||
970 | EveryOnePermissions = (uint) PermissionMask.Copy, | ||
971 | GroupPermissions = (uint) PermissionMask.Copy, | ||
972 | NextPermissions = (uint) PermissionMask.Copy | ||
973 | }; | ||
974 | invService.AddItem(itembase); | ||
975 | appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type)); | ||
976 | ScenePresence presence = null; | ||
977 | if (m_scene.TryGetScenePresence(userID, out presence)) | ||
978 | { | ||
979 | m_scene.SendInventoryUpdate(presence.ControllingClient, | ||
980 | invService.GetFolderForType(userID, | ||
981 | FolderType | ||
982 | .CurrentOutfit), | ||
983 | false, true); | ||
984 | } | ||
985 | } | ||
584 | } | 986 | } |
585 | 987 | ||
988 | private UUID GetDefaultItem(WearableType wearable) | ||
989 | { | ||
990 | // These are ruth | ||
991 | UUID ret = UUID.Zero; | ||
992 | switch (wearable) | ||
993 | { | ||
994 | case WearableType.Eyes: | ||
995 | ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); | ||
996 | break; | ||
997 | case WearableType.Hair: | ||
998 | ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66"); | ||
999 | break; | ||
1000 | case WearableType.Pants: | ||
1001 | ret = new UUID("00000000-38f9-1111-024e-222222111120"); | ||
1002 | break; | ||
1003 | case WearableType.Shape: | ||
1004 | ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); | ||
1005 | break; | ||
1006 | case WearableType.Shirt: | ||
1007 | ret = new UUID("00000000-38f9-1111-024e-222222111110"); | ||
1008 | break; | ||
1009 | case WearableType.Skin: | ||
1010 | ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb"); | ||
1011 | break; | ||
1012 | case WearableType.Undershirt: | ||
1013 | ret = new UUID("16499ebb-3208-ec27-2def-481881728f47"); | ||
1014 | break; | ||
1015 | case WearableType.Underpants: | ||
1016 | ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d"); | ||
1017 | break; | ||
1018 | } | ||
1019 | |||
1020 | return ret; | ||
1021 | } | ||
586 | #endregion | 1022 | #endregion |
587 | 1023 | ||
588 | #region Client Event Handlers | 1024 | #region Client Event Handlers |
@@ -592,12 +1028,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
592 | /// <param name="client"></param> | 1028 | /// <param name="client"></param> |
593 | private void Client_OnRequestWearables(IClientAPI client) | 1029 | private void Client_OnRequestWearables(IClientAPI client) |
594 | { | 1030 | { |
595 | // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId); | 1031 | Util.FireAndForget(delegate(object x) |
596 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | 1032 | { |
597 | if (sp != null) | 1033 | Thread.Sleep(4000); |
598 | client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); | 1034 | |
599 | else | 1035 | // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId); |
600 | m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId); | 1036 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
1037 | if (sp != null) | ||
1038 | client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); | ||
1039 | else | ||
1040 | m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId); | ||
1041 | }, null, "AvatarFactoryModule.OnClientRequestWearables"); | ||
601 | } | 1042 | } |
602 | 1043 | ||
603 | /// <summary> | 1044 | /// <summary> |
@@ -606,12 +1047,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
606 | /// <param name="client"></param> | 1047 | /// <param name="client"></param> |
607 | /// <param name="texture"></param> | 1048 | /// <param name="texture"></param> |
608 | /// <param name="visualParam"></param> | 1049 | /// <param name="visualParam"></param> |
609 | private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) | 1050 | private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems) |
610 | { | 1051 | { |
611 | // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); | 1052 | // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); |
612 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | 1053 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); |
613 | if (sp != null) | 1054 | if (sp != null) |
614 | SetAppearance(sp, textureEntry, visualParams); | 1055 | SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems); |
615 | else | 1056 | else |
616 | m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); | 1057 | m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); |
617 | } | 1058 | } |
@@ -659,6 +1100,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
659 | QueueAppearanceSave(client.AgentId); | 1100 | QueueAppearanceSave(client.AgentId); |
660 | } | 1101 | } |
661 | } | 1102 | } |
1103 | |||
1104 | /// <summary> | ||
1105 | /// Respond to the cached textures request from the client | ||
1106 | /// </summary> | ||
1107 | /// <param name="client"></param> | ||
1108 | /// <param name="serial"></param> | ||
1109 | /// <param name="cachedTextureRequest"></param> | ||
1110 | private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest) | ||
1111 | { | ||
1112 | // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); | ||
1113 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | ||
1114 | |||
1115 | List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>(); | ||
1116 | foreach (CachedTextureRequestArg request in cachedTextureRequest) | ||
1117 | { | ||
1118 | UUID texture = UUID.Zero; | ||
1119 | int index = request.BakedTextureIndex; | ||
1120 | |||
1121 | if (m_reusetextures) | ||
1122 | { | ||
1123 | // this is the most insanely dumb way to do this... however it seems to | ||
1124 | // actually work. if the appearance has been reset because wearables have | ||
1125 | // changed then the texture entries are zero'd out until the bakes are | ||
1126 | // uploaded. on login, if the textures exist in the cache (eg if you logged | ||
1127 | // into the simulator recently, then the appearance will pull those and send | ||
1128 | // them back in the packet and you won't have to rebake. if the textures aren't | ||
1129 | // in the cache then the intial makeroot() call in scenepresence will zero | ||
1130 | // them out. | ||
1131 | // | ||
1132 | // a better solution (though how much better is an open question) is to | ||
1133 | // store the hashes in the appearance and compare them. Thats's coming. | ||
1134 | |||
1135 | Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; | ||
1136 | if (face != null) | ||
1137 | texture = face.TextureID; | ||
1138 | |||
1139 | // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); | ||
1140 | } | ||
1141 | |||
1142 | CachedTextureResponseArg response = new CachedTextureResponseArg(); | ||
1143 | response.BakedTextureIndex = index; | ||
1144 | response.BakedTextureID = texture; | ||
1145 | response.HostName = null; | ||
1146 | |||
1147 | cachedTextureResponse.Add(response); | ||
1148 | } | ||
1149 | |||
1150 | // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial); | ||
1151 | // The serial number appears to be used to match requests and responses | ||
1152 | // in the texture transaction. We just send back the serial number | ||
1153 | // that was provided in the request. The viewer bumps this for us. | ||
1154 | client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); | ||
1155 | } | ||
1156 | |||
1157 | |||
662 | #endregion | 1158 | #endregion |
663 | 1159 | ||
664 | public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) | 1160 | public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) |
@@ -690,7 +1186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
690 | } | 1186 | } |
691 | 1187 | ||
692 | bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); | 1188 | bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); |
693 | outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); | 1189 | outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); |
694 | } | 1190 | } |
695 | } | 1191 | } |
696 | } | 1192 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index 1830d41..9513408 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs | |||
@@ -34,7 +34,6 @@ using OpenSim.Framework; | |||
34 | using OpenSim.Region.CoreModules.Asset; | 34 | using OpenSim.Region.CoreModules.Asset; |
35 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Tests.Common; | 36 | using OpenSim.Tests.Common; |
37 | using OpenSim.Tests.Common.Mock; | ||
38 | 37 | ||
39 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | 38 | namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory |
40 | { | 39 | { |
@@ -48,23 +47,103 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
48 | public void TestSetAppearance() | 47 | public void TestSetAppearance() |
49 | { | 48 | { |
50 | TestHelpers.InMethod(); | 49 | TestHelpers.InMethod(); |
51 | // log4net.Config.XmlConfigurator.Configure(); | 50 | // TestHelpers.EnableLogging(); |
52 | 51 | ||
53 | UUID userId = TestHelpers.ParseTail(0x1); | 52 | UUID userId = TestHelpers.ParseTail(0x1); |
53 | UUID bakedTextureID = TestHelpers.ParseTail(0x2); | ||
54 | 54 | ||
55 | // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly | ||
56 | // to the AssetService, which will then store temporary and local assets permanently | ||
57 | CoreAssetCache assetCache = new CoreAssetCache(); | ||
58 | |||
55 | AvatarFactoryModule afm = new AvatarFactoryModule(); | 59 | AvatarFactoryModule afm = new AvatarFactoryModule(); |
56 | TestScene scene = new SceneHelpers().SetupScene(); | 60 | TestScene scene = new SceneHelpers(assetCache).SetupScene(); |
57 | SceneHelpers.SetupSceneModules(scene, afm); | 61 | SceneHelpers.SetupSceneModules(scene, afm); |
58 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); | 62 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); |
59 | 63 | ||
64 | // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules | ||
65 | AssetBase bakedTextureAsset; | ||
66 | bakedTextureAsset | ||
67 | = new AssetBase( | ||
68 | bakedTextureID, "Test Baked Texture", (sbyte)AssetType.Texture, userId.ToString()); | ||
69 | bakedTextureAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet | ||
70 | bakedTextureAsset.Temporary = true; | ||
71 | bakedTextureAsset.Local = true; | ||
72 | scene.AssetService.Store(bakedTextureAsset); | ||
73 | |||
60 | byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; | 74 | byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; |
61 | for (byte i = 0; i < visualParams.Length; i++) | 75 | for (byte i = 0; i < visualParams.Length; i++) |
62 | visualParams[i] = i; | 76 | visualParams[i] = i; |
63 | 77 | ||
64 | afm.SetAppearance(sp, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); | 78 | Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); |
79 | uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); | ||
80 | Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); | ||
81 | |||
82 | int rebakeRequestsReceived = 0; | ||
83 | ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++; | ||
84 | |||
85 | // This is the alpha texture | ||
86 | eyesFace.TextureID = bakedTextureID; | ||
87 | afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); | ||
88 | |||
89 | Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); | ||
90 | |||
91 | AssetBase eyesBake = scene.AssetService.Get(bakedTextureID.ToString()); | ||
92 | Assert.That(eyesBake, Is.Not.Null); | ||
93 | Assert.That(eyesBake.Temporary, Is.True); | ||
94 | Assert.That(eyesBake.Local, Is.True); | ||
95 | } | ||
96 | |||
97 | /// <summary> | ||
98 | /// Test appearance setting where the baked texture UUID are library alpha textures. | ||
99 | /// </summary> | ||
100 | /// <remarks> | ||
101 | /// For a mesh avatar, it appears these 'baked textures' are used. So these should not trigger a request to | ||
102 | /// rebake. | ||
103 | /// </remarks> | ||
104 | [Test] | ||
105 | public void TestSetAppearanceAlphaBakedTextures() | ||
106 | { | ||
107 | TestHelpers.InMethod(); | ||
108 | // TestHelpers.EnableLogging(); | ||
109 | |||
110 | UUID userId = TestHelpers.ParseTail(0x1); | ||
111 | UUID alphaTextureID = new UUID("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); | ||
112 | |||
113 | // We need an asset cache because otherwise the LocalAssetServiceConnector will short-circuit directly | ||
114 | // to the AssetService, which will then store temporary and local assets permanently | ||
115 | CoreAssetCache assetCache = new CoreAssetCache(); | ||
116 | |||
117 | AvatarFactoryModule afm = new AvatarFactoryModule(); | ||
118 | TestScene scene = new SceneHelpers(assetCache).SetupScene(); | ||
119 | SceneHelpers.SetupSceneModules(scene, afm); | ||
120 | ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); | ||
121 | |||
122 | AssetBase libraryAsset; | ||
123 | libraryAsset | ||
124 | = new AssetBase( | ||
125 | alphaTextureID, "Default Alpha Layer Texture", (sbyte)AssetType.Texture, userId.ToString()); | ||
126 | libraryAsset.Data = new byte[] { 2 }; // Not necessary to have a genuine JPEG2000 asset here yet | ||
127 | libraryAsset.Temporary = false; | ||
128 | libraryAsset.Local = false; | ||
129 | scene.AssetService.Store(libraryAsset); | ||
130 | |||
131 | byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; | ||
132 | for (byte i = 0; i < visualParams.Length; i++) | ||
133 | visualParams[i] = i; | ||
134 | |||
135 | Primitive.TextureEntry bakedTextureEntry = new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)); | ||
136 | uint eyesFaceIndex = (uint)AppearanceManager.BakeTypeToAgentTextureIndex(BakeType.Eyes); | ||
137 | Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); | ||
138 | |||
139 | int rebakeRequestsReceived = 0; | ||
140 | ((TestClient)sp.ControllingClient).OnReceivedSendRebakeAvatarTextures += id => rebakeRequestsReceived++; | ||
65 | 141 | ||
66 | // TODO: Check baked texture | 142 | // This is the alpha texture |
67 | Assert.AreEqual(visualParams, sp.Appearance.VisualParams); | 143 | eyesFace.TextureID = alphaTextureID; |
144 | afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); | ||
145 | |||
146 | Assert.That(rebakeRequestsReceived, Is.EqualTo(0)); | ||
68 | } | 147 | } |
69 | 148 | ||
70 | [Test] | 149 | [Test] |
@@ -102,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
102 | Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); | 181 | Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); |
103 | eyesFace.TextureID = eyesTextureId; | 182 | eyesFace.TextureID = eyesTextureId; |
104 | 183 | ||
105 | afm.SetAppearance(sp, bakedTextureEntry, visualParams); | 184 | afm.SetAppearance(sp, bakedTextureEntry, visualParams, null); |
106 | afm.SaveBakedTextures(userId); | 185 | afm.SaveBakedTextures(userId); |
107 | // Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); | 186 | // Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); |
108 | 187 | ||