diff options
author | UbitUmarov | 2019-09-11 13:51:43 +0100 |
---|---|---|
committer | UbitUmarov | 2019-09-11 13:51:43 +0100 |
commit | 9d6c996570377f137f93d16c388746f949b9a841 (patch) | |
tree | 11076440a1101266dda5651b5160693e25c7b8d0 /OpenSim/Region/CoreModules/Avatar/AvatarFactory | |
parent | disable AvatarHoverHeight useless and viewer side broken (without SSA) (diff) | |
download | opensim-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-x | OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 466 |
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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Collections.Concurrent; | ||
30 | using System.Reflection; | 31 | using System.Reflection; |
31 | using System.Threading; | 32 | using System.Threading; |
32 | using System.Text; | 33 | using System.Text; |
@@ -35,6 +36,7 @@ using log4net; | |||
35 | using Nini.Config; | 36 | using Nini.Config; |
36 | using OpenMetaverse; | 37 | using OpenMetaverse; |
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
39 | using OpenSim.Framework.Monitoring; | ||
38 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes; | 41 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Services.Interfaces; | 42 | using 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 | } |