aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/AvatarFactory
diff options
context:
space:
mode:
authorUbitUmarov2019-09-11 13:51:43 +0100
committerUbitUmarov2019-09-11 13:51:43 +0100
commit9d6c996570377f137f93d16c388746f949b9a841 (patch)
tree11076440a1101266dda5651b5160693e25c7b8d0 /OpenSim/Region/CoreModules/Avatar/AvatarFactory
parentdisable AvatarHoverHeight useless and viewer side broken (without SSA) (diff)
downloadopensim-SC-9d6c996570377f137f93d16c388746f949b9a841.zip
opensim-SC-9d6c996570377f137f93d16c388746f949b9a841.tar.gz
opensim-SC-9d6c996570377f137f93d16c388746f949b9a841.tar.bz2
opensim-SC-9d6c996570377f137f93d16c388746f949b9a841.tar.xz
extent supported number of avatar textures/bakes/wearables, tell viewers about it on lludp RegionHandShake; propagate agenthover; block teleports/crossings based on worn wearables and peer version;
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/AvatarFactory')
-rwxr-xr-xOpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs466
1 files changed, 200 insertions, 266 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 777d020..2013938 100755
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Collections.Concurrent;
30using System.Reflection; 31using System.Reflection;
31using System.Threading; 32using System.Threading;
32using System.Text; 33using System.Text;
@@ -35,6 +36,7 @@ using log4net;
35using Nini.Config; 36using Nini.Config;
36using OpenMetaverse; 37using OpenMetaverse;
37using OpenSim.Framework; 38using OpenSim.Framework;
39using OpenSim.Framework.Monitoring;
38using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes; 41using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
@@ -59,8 +61,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
59 61
60 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates 62 private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
61 private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); 63 private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
62 private Dictionary<UUID,long> m_savequeue = new Dictionary<UUID,long>(); 64 private ConcurrentDictionary<UUID,long> m_savequeue = new ConcurrentDictionary<UUID,long>();
63 private Dictionary<UUID,long> m_sendqueue = new Dictionary<UUID,long>(); 65 private ConcurrentDictionary<UUID,long> m_sendqueue = new ConcurrentDictionary<UUID,long>();
66 private object m_updatesLock = new object();
67 private int m_updatesbusy = 0;
64 68
65 private object m_setAppearanceLock = new object(); 69 private object m_setAppearanceLock = new object();
66 70
@@ -134,7 +138,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
134 client.OnRequestWearables += Client_OnRequestWearables; 138 client.OnRequestWearables += Client_OnRequestWearables;
135 client.OnSetAppearance += Client_OnSetAppearance; 139 client.OnSetAppearance += Client_OnSetAppearance;
136 client.OnAvatarNowWearing += Client_OnAvatarNowWearing; 140 client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
137 client.OnCachedTextureRequest += Client_OnCachedTextureRequest; 141 //client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
138 } 142 }
139 143
140 #endregion 144 #endregion
@@ -232,20 +236,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
232 sp.SendAppearanceToAllOtherAgents(); 236 sp.SendAppearanceToAllOtherAgents();
233 237
234 // Send animations back to the avatar as well 238 // Send animations back to the avatar as well
235 sp.Animator.SendAnimPack(); 239 if(sp.Animator != null)
240 sp.Animator.SendAnimPack();
236 } 241 }
237 242
238 public bool SendAppearance(UUID agentId) 243 public bool SendAppearance(UUID agentId)
239 { 244 {
240// m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId);
241
242 ScenePresence sp = m_scene.GetScenePresence(agentId); 245 ScenePresence sp = m_scene.GetScenePresence(agentId);
243 if (sp == null) 246 if (sp == null || sp.IsDeleted)
244 {
245 // This is expected if the user has gone away.
246// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
247 return false; 247 return false;
248 }
249 248
250 SendAppearance(sp); 249 SendAppearance(sp);
251 return true; 250 return true;
@@ -338,11 +337,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
338 337
339 // 10000 ticks per millisecond, 1000 milliseconds per second 338 // 10000 ticks per millisecond, 1000 milliseconds per second
340 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000); 339 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000);
341 lock (m_sendqueue) 340 m_sendqueue[agentid] = timestamp;
342 { 341 m_updateTimer.Start();
343 m_sendqueue[agentid] = timestamp;
344 m_updateTimer.Start();
345 }
346 } 342 }
347 343
348 public void QueueAppearanceSave(UUID agentid) 344 public void QueueAppearanceSave(UUID agentid)
@@ -351,11 +347,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
351 347
352 // 10000 ticks per millisecond, 1000 milliseconds per second 348 // 10000 ticks per millisecond, 1000 milliseconds per second
353 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); 349 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
354 lock (m_savequeue) 350 m_savequeue[agentid] = timestamp;
355 { 351 m_updateTimer.Start();
356 m_savequeue[agentid] = timestamp;
357 m_updateTimer.Start();
358 }
359 } 352 }
360 353
361 // called on textures update 354 // called on textures update
@@ -370,106 +363,90 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
370 363
371 // uploaded baked textures will be in assets local cache 364 // uploaded baked textures will be in assets local cache
372 IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>(); 365 IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
373 IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
374 366
375 int validDirtyBakes = 0; 367 int validDirtyBakes = 0;
376 int hits = 0; 368 int hits = 0;
377 369
378 // our main cacheIDs mapper is p.Appearance.WearableCacheItems 370 // our main cacheIDs mapper is p.Appearance.WearableCacheItems
379 WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; 371 bool hadSkirt = false;
380 372
373 WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
381 if (wearableCache == null) 374 if (wearableCache == null)
382 {
383 wearableCache = WearableCacheItem.GetDefaultCacheItem(); 375 wearableCache = WearableCacheItem.GetDefaultCacheItem();
376 else
377 {
378 hadSkirt = (wearableCache[19].TextureID != UUID.Zero);
384 } 379 }
385 380
381 HashSet<uint> updatedFaces = new HashSet<uint>();
386 List<UUID> missing = new List<UUID>(); 382 List<UUID> missing = new List<UUID>();
387 383
388 bool haveSkirt = (wearableCache[19].TextureID != UUID.Zero);
389 bool haveNewSkirt = false;
390
391 // Process received baked textures 384 // Process received baked textures
392 for (int i = 0; i < cacheItems.Length; i++) 385 for (int i = 0; i < cacheItems.Length; i++)
393 { 386 {
394 int idx = (int)cacheItems[i].TextureIndex; 387 uint idx = cacheItems[i].TextureIndex;
388 if(idx >= AvatarAppearance.TEXTURE_COUNT)
389 {
390 hits++;
391 continue;
392 }
393
394 updatedFaces.Add(idx);
395
396 wearableCache[idx].TextureAsset = null; // just in case
395 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; 397 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
396 398
397 // No face 399 if (face == null || face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
398 if (face == null)
399 { 400 {
400 // for some reason viewer is cleaning this
401 if(idx != 19) // skirt is optional
402 {
403 sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx);
404 sp.Appearance.Texture.FaceTextures[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
405 }
406 wearableCache[idx].CacheId = UUID.Zero; 401 wearableCache[idx].CacheId = UUID.Zero;
407 wearableCache[idx].TextureID = UUID.Zero; 402 wearableCache[idx].TextureID = UUID.Zero;
408 wearableCache[idx].TextureAsset = null; 403 if (idx == 19)
409 continue;
410 }
411 else
412 {
413 if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
414 {
415 wearableCache[idx].CacheId = UUID.Zero;
416 wearableCache[idx].TextureID = UUID.Zero;
417 wearableCache[idx].TextureAsset = null;
418 continue;
419 }
420
421 if(idx == 19)
422 haveNewSkirt = true;
423/*
424 if (face.TextureID == wearableCache[idx].TextureID && m_BakedTextureModule != null)
425 { 404 {
426 if (wearableCache[idx].CacheId != cacheItems[i].CacheId)
427 {
428 wearableCache[idx].CacheId = cacheItems[i].CacheId;
429 validDirtyBakes++;
430
431 //assuming this can only happen if asset is in cache
432 }
433 hits++; 405 hits++;
434 continue; 406 if(hadSkirt)
435 } 407 validDirtyBakes++;
436*/
437 wearableCache[idx].TextureAsset = null;
438 if (cache != null)
439 {
440 AssetBase asb = null;
441 cache.Get(face.TextureID.ToString(), out asb);
442 wearableCache[idx].TextureAsset = asb;
443 } 408 }
409 continue;
410 }
444 411
445 if (wearableCache[idx].TextureAsset != null) 412 if (cache != null)
446 { 413 {
447 if ( wearableCache[idx].TextureID != face.TextureID || 414 AssetBase asb = null;
448 wearableCache[idx].CacheId != cacheItems[i].CacheId) 415 cache.Get(face.TextureID.ToString(), out asb);
449 validDirtyBakes++; 416 wearableCache[idx].TextureAsset = asb;
417 }
450 418
451 wearableCache[idx].TextureID = face.TextureID; 419 if (wearableCache[idx].TextureAsset != null)
452 wearableCache[idx].CacheId = cacheItems[i].CacheId; 420 {
453 hits++; 421 if ( wearableCache[idx].TextureID != face.TextureID ||
454 } 422 wearableCache[idx].CacheId != cacheItems[i].CacheId)
455 else 423 validDirtyBakes++;
456 { 424
457 wearableCache[idx].CacheId = UUID.Zero; 425 wearableCache[idx].TextureID = face.TextureID;
458 wearableCache[idx].TextureID = UUID.Zero; 426 wearableCache[idx].CacheId = cacheItems[i].CacheId;
459 wearableCache[idx].TextureAsset = null; 427 hits++;
460 missing.Add(face.TextureID); 428 }
461 continue; 429 else
462 } 430 {
431 wearableCache[idx].CacheId = UUID.Zero;
432 wearableCache[idx].TextureID = UUID.Zero;
433 missing.Add(face.TextureID);
434 continue;
463 } 435 }
464 } 436 }
465 437
466 // handle optional skirt case 438 // this may be a current fs bug
467 if(!haveNewSkirt && haveSkirt) 439 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
468 { 440 {
469 wearableCache[19].CacheId = UUID.Zero; 441 uint idx = AvatarAppearance.BAKE_INDICES[i];
470 wearableCache[19].TextureID = UUID.Zero; 442 if(updatedFaces.Contains(idx))
471 wearableCache[19].TextureAsset = null; 443 continue;
472 validDirtyBakes++; 444
445 sp.Appearance.Texture.FaceTextures[idx] = null;
446
447 wearableCache[idx].CacheId = UUID.Zero;
448 wearableCache[idx].TextureID = UUID.Zero;
449 wearableCache[idx].TextureAsset = null;
473 } 450 }
474 451
475 sp.Appearance.WearableCacheItems = wearableCache; 452 sp.Appearance.WearableCacheItems = wearableCache;
@@ -480,15 +457,18 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
480 sp.ControllingClient.SendRebakeAvatarTextures(id); 457 sp.ControllingClient.SendRebakeAvatarTextures(id);
481 } 458 }
482 459
460 bool changed = false;
483 if (validDirtyBakes > 0 && hits == cacheItems.Length) 461 if (validDirtyBakes > 0 && hits == cacheItems.Length)
484 { 462 {
485 // if we got a full set of baked textures save all in BakedTextureModule 463 // if we got a full set of baked textures save all in BakedTextureModule
464 IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
486 if (m_BakedTextureModule != null) 465 if (m_BakedTextureModule != null)
487 { 466 {
488 m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}", 467 m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}",
489 hits.ToString(), validDirtyBakes.ToString(), missing.Count); 468 hits.ToString(), validDirtyBakes.ToString(), missing.Count);
490 469
491 m_BakedTextureModule.Store(sp.UUID, wearableCache); 470 m_BakedTextureModule.Store(sp.UUID, wearableCache);
471 changed = true;
492 } 472 }
493 } 473 }
494 else 474 else
@@ -505,26 +485,25 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
505// sp.Appearance.WearableCacheItems[j].TextureID); 485// sp.Appearance.WearableCacheItems[j].TextureID);
506 } 486 }
507 487
508 return (hits == cacheItems.Length); 488 return changed;
509 } 489 }
510 490
511 // called when we get a new root avatar 491 // called when we get a new root avatar
512 public bool ValidateBakedTextureCache(IScenePresence sp) 492 public bool ValidateBakedTextureCache(IScenePresence sp)
513 { 493 {
514 int hits = 0;
515
516 if (((ScenePresence)sp).IsNPC) 494 if (((ScenePresence)sp).IsNPC)
517 return true; 495 return true;
518 496
519 lock (m_setAppearanceLock) 497 int hits = 0;
520 {
521 IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
522 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
523 WearableCacheItem[] bakedModuleCache = null;
524 498
525 if (cache == null) 499 IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
526 return false; 500 if (cache == null)
501 return false;
527 502
503 IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
504
505 lock (m_setAppearanceLock)
506 {
528 WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; 507 WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
529 508
530 // big debug 509 // big debug
@@ -566,70 +545,47 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
566 } 545 }
567 else 546 else
568 { 547 {
569 // we may have received a full cache
570 // check same coerence and store
571 wearableCacheValid = true; 548 wearableCacheValid = true;
549 Primitive.TextureEntryFace face;
572 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 550 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
573 { 551 {
574 int idx = AvatarAppearance.BAKE_INDICES[i]; 552 int idx = AvatarAppearance.BAKE_INDICES[i];
575 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; 553 face = sp.Appearance.Texture.FaceTextures[idx];
576 if (face != null) 554
555 if(face == null || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
577 { 556 {
578 if (face.TextureID == wearableCache[idx].TextureID && 557 wearableCache[idx].CacheId = UUID.Zero;
579 face.TextureID != UUID.Zero) 558 wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
559 hits++;
560 continue;
561 }
562
563 if (face.TextureID == wearableCache[idx].TextureID &&
564 face.TextureID != UUID.Zero)
565 {
566 if (cache.Check((wearableCache[idx].TextureID).ToString()))
580 { 567 {
581 if (wearableCache[idx].TextureAsset != null) 568 hits++;
582 { 569 continue;
583 hits++;
584 wearableCache[idx].TextureAsset.Temporary = true;
585 wearableCache[idx].TextureAsset.Local = true;
586 cache.Cache(wearableCache[idx].TextureAsset);
587 wearableCache[idx].TextureAsset = null;
588 continue;
589 }
590
591 if (cache.Check((wearableCache[idx].TextureID).ToString()))
592 {
593 hits++;
594 continue;
595 }
596 } 570 }
597 wearableCacheValid = false;
598 } 571 }
572 wearableCache[idx].CacheId = UUID.Zero;
573 wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
574 wearableCacheValid = false;
599 } 575 }
600
601 wearableCacheValid = (wearableCacheValid && (hits >= AvatarAppearance.BAKE_INDICES.Length - 1));
602 if (wearableCacheValid)
603 {
604// m_log.Debug("[ValidateBakedCache] have valid local cache");
605 }
606 else
607 wearableCache[19].TextureAsset = null; // clear optional skirt
608 } 576 }
609 577
610 bool checkExternal = false; 578 bool checkExternal = false;
611
612 if (!wearableCacheValid) 579 if (!wearableCacheValid)
613 { 580 checkExternal = bakedModule != null;
614 hits = 0;
615 // only use external bake module on login condition check
616// ScenePresence ssp = null;
617// if (sp is ScenePresence)
618 {
619// ssp = (ScenePresence)sp;
620// checkExternal = (((uint)ssp.TeleportFlags & (uint)TeleportFlags.ViaLogin) != 0) &&
621// bakedModule != null;
622
623 // or do it anytime we dont have the cache
624 checkExternal = bakedModule != null;
625 }
626 }
627 581
628 if (checkExternal) 582 if (checkExternal)
629 { 583 {
584 WearableCacheItem[] bakedModuleCache = null;
630 bool gotbacked = false; 585 bool gotbacked = false;
586 hits = 0;
631 587
632// m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule"); 588 // m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule");
633 try 589 try
634 { 590 {
635 bakedModuleCache = bakedModule.Get(sp.UUID); 591 bakedModuleCache = bakedModule.Get(sp.UUID);
@@ -647,8 +603,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
647 for (int i = 0; i < bakedModuleCache.Length; i++) 603 for (int i = 0; i < bakedModuleCache.Length; i++)
648 { 604 {
649 int j = (int)bakedModuleCache[i].TextureIndex; 605 int j = (int)bakedModuleCache[i].TextureIndex;
650 606 if (j < AvatarAppearance.TEXTURE_COUNT && bakedModuleCache[i].TextureAsset != null)
651 if (bakedModuleCache[i].TextureAsset != null)
652 { 607 {
653 wearableCache[j].TextureID = bakedModuleCache[i].TextureID; 608 wearableCache[j].TextureID = bakedModuleCache[i].TextureID;
654 wearableCache[j].CacheId = bakedModuleCache[i].CacheId; 609 wearableCache[j].CacheId = bakedModuleCache[i].CacheId;
@@ -658,33 +613,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
658 cache.Cache(bakedModuleCache[i].TextureAsset); 613 cache.Cache(bakedModuleCache[i].TextureAsset);
659 } 614 }
660 } 615 }
661 gotbacked = true;
662 }
663 616
664 if (gotbacked)
665 {
666 // force the ones we got 617 // force the ones we got
667 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) 618 for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
668 { 619 {
669 int idx = AvatarAppearance.BAKE_INDICES[i]; 620 int idx = AvatarAppearance.BAKE_INDICES[i];
670 if(wearableCache[idx].TextureAsset == null) 621 if (wearableCache[idx].TextureAsset == null)
671 { 622 {
672 if(idx == 19) 623 if(idx == 19)
673 { 624 {
674 sp.Appearance.Texture.FaceTextures[idx] = null; 625 sp.Appearance.Texture.FaceTextures[idx] = null;
675 hits++; 626 hits++;
676 } 627 }
628 else if(sp.Appearance.Texture.FaceTextures[idx] == null ||
629 sp.Appearance.Texture.FaceTextures[idx].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
630 hits++;
631 wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
632 wearableCache[idx].CacheId = UUID.Zero;
677 continue; 633 continue;
678 } 634 }
679 635
680 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; 636 Primitive.TextureEntryFace face = sp.Appearance.Texture.GetFace((uint)idx);
681
682 if (face == null)
683 {
684 face = sp.Appearance.Texture.CreateFace((uint)idx);
685 sp.Appearance.Texture.FaceTextures[idx] = face;
686 }
687
688 face.TextureID = wearableCache[idx].TextureID; 637 face.TextureID = wearableCache[idx].TextureID;
689 hits++; 638 hits++;
690 wearableCache[idx].TextureAsset = null; 639 wearableCache[idx].TextureAsset = null;
@@ -708,7 +657,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
708 sp.Appearance.WearableCacheItems[j].TextureID); 657 sp.Appearance.WearableCacheItems[j].TextureID);
709 } 658 }
710*/ 659*/
711 return (hits >= AvatarAppearance.BAKE_INDICES.Length - 1); // skirt is optional 660 return (hits >= AvatarAppearance.BAKE_INDICES.Length); // skirt is optional
712 } 661 }
713 662
714 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) 663 public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
@@ -776,13 +725,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
776 foreach (int i in Enum.GetValues(typeof(BakeType))) 725 foreach (int i in Enum.GetValues(typeof(BakeType)))
777 { 726 {
778 BakeType bakeType = (BakeType)i; 727 BakeType bakeType = (BakeType)i;
728 if (bakeType == BakeType.NumberOfEntries)
729 break;
779 730
780 if (bakeType == BakeType.Unknown) 731 if (bakeType == BakeType.Unknown)
781 continue; 732 continue;
782 733
783// m_log.DebugFormat( 734 // m_log.DebugFormat(
784// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", 735 // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
785// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); 736 // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
786 737
787 int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); 738 int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType);
788 Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture 739 Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture
@@ -794,90 +745,78 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
794 745
795 private void HandleAppearanceUpdateTimer(object sender, EventArgs ea) 746 private void HandleAppearanceUpdateTimer(object sender, EventArgs ea)
796 { 747 {
797 long now = DateTime.Now.Ticks; 748 if(Monitor.TryEnter(m_updatesLock))
798
799 lock (m_sendqueue)
800 { 749 {
801 Dictionary<UUID, long> sends = new Dictionary<UUID, long>(m_sendqueue); 750 UUID id;
802 foreach (KeyValuePair<UUID, long> kvp in sends) 751 long now = DateTime.Now.Ticks;
752
753 foreach (KeyValuePair<UUID, long> kvp in m_sendqueue)
803 { 754 {
804 // We have to load the key and value into local parameters to avoid a race condition if we loop
805 // around and load kvp with a different value before FireAndForget has launched its thread.
806 UUID avatarID = kvp.Key;
807 long sendTime = kvp.Value; 755 long sendTime = kvp.Value;
756 if (sendTime > now)
757 continue;
808 758
809// m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); 759 id = kvp.Key;
810 760 m_sendqueue.TryRemove(id, out sendTime);
811 if (sendTime < now) 761 SendAppearance(id);
812 {
813 Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance");
814 m_sendqueue.Remove(avatarID);
815 }
816 } 762 }
817 }
818 763
819 lock (m_savequeue) 764 if(m_updatesbusy == 0)
820 {
821 Dictionary<UUID, long> saves = new Dictionary<UUID, long>(m_savequeue);
822 foreach (KeyValuePair<UUID, long> kvp in saves)
823 { 765 {
824 // We have to load the key and value into local parameters to avoid a race condition if we loop 766 m_updatesbusy = -1;
825 // around and load kvp with a different value before FireAndForget has launched its thread. 767 List<UUID> saves = new List<UUID>(m_savequeue.Count);
826 UUID avatarID = kvp.Key; 768 foreach (KeyValuePair<UUID, long> kvp in m_savequeue)
827 long sendTime = kvp.Value; 769 {
770 long sendTime = kvp.Value;
771 if (sendTime > now)
772 continue;
773
774 id = kvp.Key;
775 m_savequeue.TryRemove(id, out sendTime);
776 saves.Add(id);
777 }
828 778
829 if (sendTime < now) 779 m_updatesbusy = 0;
780 if (saves.Count > 0)
830 { 781 {
831 Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance"); 782 ++m_updatesbusy;
832 m_savequeue.Remove(avatarID); 783 WorkManager.RunInThreadPool(
784 delegate
785 {
786 SaveAppearance(saves);
787 saves = null;
788 --m_updatesbusy;
789 }, null, string.Format("SaveAppearance ({0})", m_scene.Name));
833 } 790 }
834 } 791 }
835 792
836 // We must lock both queues here so that QueueAppearanceSave() or *Send() don't m_updateTimer.Start() on 793 if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
837 // another thread inbetween the first count calls and m_updateTimer.Stop() on this thread. 794 m_updateTimer.Stop();
838 lock (m_sendqueue) 795
839 if (m_savequeue.Count == 0 && m_sendqueue.Count == 0) 796 Monitor.Exit(m_updatesLock);
840 m_updateTimer.Stop();
841 } 797 }
842 } 798 }
843 799
844 private void SaveAppearance(UUID agentid) 800 private void SaveAppearance(List<UUID> ids)
845 { 801 {
846 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
847 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
848 // number seperators.
849 Culture.SetCurrentCulture();
850
851 ScenePresence sp = m_scene.GetScenePresence(agentid);
852 if (sp == null)
853 {
854 // This is expected if the user has gone away.
855// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
856 return;
857 }
858
859// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); 802// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
860 803
861 // This could take awhile since it needs to pull inventory 804 foreach(UUID id in ids)
862 // 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 805 {
863 // assets and item asset id changes to complete. 806 ScenePresence sp = m_scene.GetScenePresence(id);
864 // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids 807 if(sp == null)
865 // multiple save requests. 808 continue;
866 SetAppearanceAssets(sp.UUID, sp.Appearance); 809 // This could take awhile since it needs to pull inventory
867 810 // 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
868// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); 811 // assets and item asset id changes to complete.
869// foreach (AvatarAttachment att in attachments) 812 // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
870// { 813 // multiple save requests.
871// m_log.DebugFormat(
872// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
873// sp.Name, att.ItemID, att.AttachPoint);
874// }
875 814
876 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); 815 SetAppearanceAssets(id, sp.Appearance);
877 816
878 // Trigger this here because it's the final step in the set/queue/save process for appearance setting. 817 m_scene.AvatarService.SetAppearance(id, sp.Appearance);
879 // Everything has been updated and stored. Ensures bakes have been persisted (if option is set to persist bakes). 818 //m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
880 m_scene.EventManager.TriggerAvatarAppearanceChanged(sp); 819 }
881 } 820 }
882 821
883 /// <summary> 822 /// <summary>
@@ -1231,7 +1170,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1231 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); 1170 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
1232 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 1171 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
1233 if (sp != null) 1172 if (sp != null)
1234 SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems); 1173 SetAppearance(sp, textureEntry, visualParams, avSize, cacheItems);
1235 else 1174 else
1236 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); 1175 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
1237 } 1176 }
@@ -1251,9 +1190,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1251 return; 1190 return;
1252 } 1191 }
1253 1192
1254 // we need to clean out the existing textures
1255 sp.Appearance.ResetAppearance();
1256
1257 // operate on a copy of the appearance so we don't have to lock anything yet 1193 // operate on a copy of the appearance so we don't have to lock anything yet
1258 AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false); 1194 AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false);
1259 1195
@@ -1280,15 +1216,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1280 // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing 1216 // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing
1281 // shouldn't overwrite the changes made in SetAppearance. 1217 // shouldn't overwrite the changes made in SetAppearance.
1282 sp.Appearance.Wearables = avatAppearance.Wearables; 1218 sp.Appearance.Wearables = avatAppearance.Wearables;
1283 sp.Appearance.Texture = avatAppearance.Texture;
1284
1285 // We don't need to send the appearance here since the "iswearing" will trigger a new set 1219 // We don't need to send the appearance here since the "iswearing" will trigger a new set
1286 // of visual param and baked texture changes. When those complete, the new appearance will be sent 1220 // of visual param and baked texture changes. When those complete, the new appearance will be sent
1287
1288 QueueAppearanceSave(client.AgentId); 1221 QueueAppearanceSave(client.AgentId);
1289 } 1222 }
1290 } 1223 }
1291 1224
1225/*
1292 /// <summary> 1226 /// <summary>
1293 /// Respond to the cached textures request from the client 1227 /// Respond to the cached textures request from the client
1294 /// </summary> 1228 /// </summary>
@@ -1308,23 +1242,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1308 1242
1309 if (m_reusetextures) 1243 if (m_reusetextures)
1310 { 1244 {
1311 // this is the most insanely dumb way to do this... however it seems to
1312 // actually work. if the appearance has been reset because wearables have
1313 // changed then the texture entries are zero'd out until the bakes are
1314 // uploaded. on login, if the textures exist in the cache (eg if you logged
1315 // into the simulator recently, then the appearance will pull those and send
1316 // them back in the packet and you won't have to rebake. if the textures aren't
1317 // in the cache then the intial makeroot() call in scenepresence will zero
1318 // them out.
1319 //
1320 // a better solution (though how much better is an open question) is to
1321 // store the hashes in the appearance and compare them. Thats's coming.
1322
1323 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; 1245 Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
1324 if (face != null) 1246 if (face != null)
1325 texture = face.TextureID; 1247 texture = face.TextureID;
1326
1327 // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
1328 } 1248 }
1329 1249
1330 CachedTextureResponseArg response = new CachedTextureResponseArg(); 1250 CachedTextureResponseArg response = new CachedTextureResponseArg();
@@ -1334,21 +1254,16 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1334 1254
1335 cachedTextureResponse.Add(response); 1255 cachedTextureResponse.Add(response);
1336 } 1256 }
1337
1338 // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
1339 // The serial number appears to be used to match requests and responses
1340 // in the texture transaction. We just send back the serial number
1341 // that was provided in the request. The viewer bumps this for us.
1342 client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); 1257 client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
1343 } 1258 }
1344 1259*/
1345 1260
1346 #endregion 1261 #endregion
1347 1262
1348 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) 1263 public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
1349 { 1264 {
1350 outputAction("For {0} in {1}", sp.Name, m_scene.RegionInfo.RegionName); 1265 outputAction("For {0} in {1}", null, sp.Name, m_scene.RegionInfo.RegionName);
1351 outputAction(BAKED_TEXTURES_REPORT_FORMAT, "Bake Type", "UUID"); 1266 outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, "Bake Type", "UUID");
1352 1267
1353 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID); 1268 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID);
1354 1269
@@ -1362,19 +1277,38 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
1362 } 1277 }
1363 else 1278 else
1364 { 1279 {
1365 rawTextureID = bakedTextures[bt].TextureID.ToString(); 1280 if(bakedTextures[bt].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
1366 1281 rawTextureID = "not set";
1367 if (m_scene.AssetService.Get(rawTextureID) == null)
1368 rawTextureID += " (not found)";
1369 else 1282 else
1370 rawTextureID += " (uploaded)"; 1283 {
1284 rawTextureID = bakedTextures[bt].TextureID.ToString();
1285
1286 if (m_scene.AssetService.Get(rawTextureID) == null)
1287 rawTextureID += " (not found)";
1288 else
1289 rawTextureID += " (uploaded)";
1290 }
1371 } 1291 }
1372 1292
1373 outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID); 1293 outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID);
1374 } 1294 }
1375 1295
1376 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); 1296 bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
1377 outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); 1297 outputAction("{0} baked appearance texture is {1}", null, sp.Name, bakedTextureValid ? "OK" : "incomplete");
1298 }
1299
1300 public void SetPreferencesHoverZ(UUID agentId, float val)
1301 {
1302 ScenePresence sp = m_scene.GetScenePresence(agentId);
1303 if (sp == null || sp.IsDeleted || sp.IsNPC || sp.IsInTransit)
1304 return;
1305 float last = sp.Appearance.AvatarPreferencesHoverZ;
1306 if(val != last)
1307 {
1308 sp.Appearance.AvatarPreferencesHoverZ = val;
1309 //sp.SendAppearanceToAgentNF(sp);
1310 QueueAppearanceSend(agentId);
1311 }
1378 } 1312 }
1379 } 1313 }
1380} 1314}