diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index c384336dd7..25ae0ecd22 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -183,7 +183,7 @@ namespace OpenSim.Framework m_attachments = new Dictionary>(); } - public AvatarAppearance(AvatarAppearance appearance) : this(appearance, true) + public AvatarAppearance(AvatarAppearance appearance): this(appearance, true) { } @@ -221,6 +221,8 @@ namespace OpenSim.Framework { byte[] tbytes = appearance.Texture.GetBytes(); m_texture = new Primitive.TextureEntry(tbytes,0,tbytes.Length); + if (appearance.m_cacheitems != null) + m_cacheitems = (WearableCacheItem[]) appearance.m_cacheitems.Clone(); } m_visualparams = null; @@ -723,6 +725,13 @@ namespace OpenSim.Framework } data["textures"] = textures; + if (m_cacheitems != null) + { + OSDArray baked = WearableCacheItem.BakedToOSD(m_cacheitems); + if (baked != null) + data["bakedcache"] = baked; + } + // Visual Parameters OSDBinary visualparams = new OSDBinary(m_visualparams); data["visualparams"] = visualparams; @@ -789,6 +798,12 @@ namespace OpenSim.Framework m_log.Warn("[AVATAR APPEARANCE]: failed to unpack textures"); } + if ((data != null) && (data["bakedcache"] != null) && (data["bakedcache"]).Type == OSDType.Array) + { + OSDArray bakedOSDArray = (OSDArray)(data["bakedcache"]); + m_cacheitems = WearableCacheItem.BakedFromOSD(bakedOSDArray); + } + // Visual Parameters SetDefaultParams(); if ((data != null) && (data["visualparams"] != null)) diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs index a890d3b9f0..f49697dc0a 100644 --- a/OpenSim/Framework/WearableCacheItem.cs +++ b/OpenSim/Framework/WearableCacheItem.cs @@ -49,7 +49,6 @@ namespace OpenSim.Framework retitems[i] = new WearableCacheItem() {CacheId = UUID.Zero, TextureID = UUID.Zero, TextureIndex = i}; return retitems; } - public static WearableCacheItem[] FromOSD(OSD pInput, IImprovedAssetCache dataCache) { @@ -100,6 +99,7 @@ namespace OpenSim.Framework return ret.ToArray(); } + public static OSD ToOSD(WearableCacheItem[] pcacheItems, IImprovedAssetCache dataCache) { OSDArray arr = new OSDArray(); @@ -126,6 +126,64 @@ namespace OpenSim.Framework } return arr; } + + public static OSDArray BakedToOSD(WearableCacheItem[] pcacheItems) + { + if (pcacheItems.Length < AvatarAppearance.BAKE_INDICES[AvatarAppearance.BAKE_INDICES.Length - 1]) + return null; + + OSDArray arr = new OSDArray(); + + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) + { + int idx = AvatarAppearance.BAKE_INDICES[i]; + + WearableCacheItem item = pcacheItems[idx]; + + OSDMap itemmap = new OSDMap(); + itemmap.Add("textureindex", OSD.FromUInteger(item.TextureIndex)); + itemmap.Add("cacheid", OSD.FromUUID(item.CacheId)); + itemmap.Add("textureid", OSD.FromUUID(item.TextureID)); + if (item.TextureAsset != null) + { + itemmap.Add("assetdata", OSD.FromBinary(item.TextureAsset.Data)); + itemmap.Add("assetcreator", OSD.FromString(item.TextureAsset.CreatorID)); + itemmap.Add("assetname", OSD.FromString(item.TextureAsset.Name)); + } + arr.Add(itemmap); + } + return arr; + } + + public static WearableCacheItem[] BakedFromOSD(OSD pInput) + { + WearableCacheItem[] pcache = WearableCacheItem.GetDefaultCacheItem(); + + if (pInput.Type == OSDType.Array) + { + OSDArray itemarray = (OSDArray)pInput; + foreach (OSDMap item in itemarray) + { + int idx = (int)item["textureindex"].AsUInteger(); + if (idx < 0 || idx > pcache.Length) + continue; + pcache[idx].CacheId = item["cacheid"].AsUUID(); + pcache[idx].TextureID = item["textureid"].AsUUID(); + if (item.ContainsKey("assetdata")) + { + AssetBase asset = new AssetBase(item["textureid"].AsUUID(), "BakedTexture", (sbyte)AssetType.Texture, UUID.Zero.ToString()); + asset.Temporary = true; + asset.Local = true; + asset.Data = item["assetdata"].AsBinary(); + pcache[idx].TextureAsset = asset; + } + else + pcache[idx].TextureAsset = null; + } + } + return pcache; + } + public static WearableCacheItem SearchTextureIndex(uint pTextureIndex,WearableCacheItem[] pcacheItems) { for (int i = 0; i < pcacheItems.Length; i++) diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index e34bac9499..186d82b0e4 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -487,140 +487,137 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { IAssetService cache = m_scene.AssetService; IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); - WearableCacheItem[] wearableCache = null; WearableCacheItem[] bakedModuleCache = null; - wearableCache = WearableCacheItem.GetDefaultCacheItem(); + if (cache == null) + return false; + WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; + // big debug m_log.DebugFormat("[AVFACTORY]: ValidateBakedTextureCache start for {0} {1}", sp.Name, sp.UUID); - // debug for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++) { int j = AvatarAppearance.BAKE_INDICES[iter]; - Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[iter]; - if (face != null) - m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - " + face.TextureID); + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[j]; + if (wearableCache == null) + { + if (face != null) + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- " + face.TextureID); + else + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- No texture"); + } else - m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - No texture"); + { + if (face != null) + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " ft- " + face.TextureID + + "}: cc-" + + wearableCache[j].CacheId + ", ct-" + + wearableCache[j].TextureID + ); + else + m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - No texture" + + "}: cc-" + + wearableCache[j].CacheId + ", ct-" + + wearableCache[j].TextureID + ); + } } - - bool gotbacked = false; - // Cache wearable data for teleport. - // Only makes sense if there's a bake module and a cache module - if (bakedModule != null && cache != null) + bool wearableCacheValid = false; + if (wearableCache == null) { - m_log.Debug("[ValidateBakedCache] calling bakedModule"); - try + wearableCache = WearableCacheItem.GetDefaultCacheItem(); + } + else + { + // we may have received a full cache + // check same coerence and store + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { - bakedModuleCache = bakedModule.Get(sp.UUID); - } - catch (Exception) - { - bakedModuleCache = null; - } - - if (bakedModuleCache != null) - { - m_log.Debug("[ValidateBakedCache] got bakedModule cache " + bakedModuleCache.Length); - - for (int i = 0; i < bakedModuleCache.Length; i++) + int idx = AvatarAppearance.BAKE_INDICES[i]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + if (face != null && face.TextureID == wearableCache[idx].TextureID && wearableCache[idx].TextureAsset != null) { - int j = (int)bakedModuleCache[i].TextureIndex; - - if (bakedModuleCache[i].TextureAsset != null) - { - wearableCache[j].TextureID = bakedModuleCache[i].TextureID; - wearableCache[j].CacheId = bakedModuleCache[i].CacheId; - wearableCache[j].TextureAsset = bakedModuleCache[i].TextureAsset; - bakedModuleCache[i].TextureAsset.Temporary = true; - bakedModuleCache[i].TextureAsset.Local = true; - cache.Store(bakedModuleCache[i].TextureAsset); - - } + hits++; + wearableCache[idx].TextureAsset.Temporary = true; + wearableCache[idx].TextureAsset.Local = true; + cache.Store(wearableCache[idx].TextureAsset); } - gotbacked = true; } + + wearableCacheValid = (hits >= AvatarAppearance.BAKE_INDICES.Length - 1); // skirt is optional + if (wearableCacheValid) + m_log.Debug("[ValidateBakedCache] have valid local cache"); } - // Process the baked textures - for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) + if (!wearableCacheValid) { - int idx = AvatarAppearance.BAKE_INDICES[i]; - Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + hits = 0; + bool gotbacked = false; + + if (bakedModule != null) + { + m_log.Debug("[ValidateBakedCache] local cache invalid, calling bakedModule"); + try + { + bakedModuleCache = bakedModule.Get(sp.UUID); + } + catch (Exception) + { + bakedModuleCache = null; + } + + if (bakedModuleCache != null) + { + m_log.Debug("[ValidateBakedCache] got bakedModule cache " + bakedModuleCache.Length); + + for (int i = 0; i < bakedModuleCache.Length; i++) + { + int j = (int)bakedModuleCache[i].TextureIndex; + + if (bakedModuleCache[i].TextureAsset != null) + { + wearableCache[j].TextureID = bakedModuleCache[i].TextureID; + wearableCache[j].CacheId = bakedModuleCache[i].CacheId; + wearableCache[j].TextureAsset = bakedModuleCache[i].TextureAsset; + bakedModuleCache[i].TextureAsset.Temporary = true; + bakedModuleCache[i].TextureAsset.Local = true; + cache.Store(bakedModuleCache[i].TextureAsset); + + } + } + gotbacked = true; + } + } - // on tp viewer assumes servers did the cache work - // and tp propagation of baked textures is broken somewhere - // so make grid cache be mandatory if (gotbacked) { - // m_log.Debug("[ValidateBakedCache] bakedModule cache override"); - if (sp.Appearance.Texture.FaceTextures[idx] == null) - sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint)idx); - sp.Appearance.Texture.FaceTextures[idx].TextureID = wearableCache[idx].TextureID; - face = sp.Appearance.Texture.FaceTextures[idx]; - - // this should be removed - if (face.TextureID != UUID.Zero && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) - hits++; - - continue; - } - else - { - // No face, so lets check our cache - if (face == null || face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) + // force the ones we got + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) { - sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint)idx); - if (wearableCache[idx].TextureID != UUID.Zero) - { - sp.Appearance.Texture.FaceTextures[idx].TextureID = wearableCache[idx].TextureID; - face = sp.Appearance.Texture.FaceTextures[idx]; - // let run to end of loop to check cache - } - else - { - sp.Appearance.Texture.FaceTextures[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE; - face = sp.Appearance.Texture.FaceTextures[idx]; - // lets try not invalidating the cache entry - // wearableCache[idx].CacheId = UUID.Zero; - // wearableCache[idx].TextureAsset = null; - continue; - } - } + int idx = AvatarAppearance.BAKE_INDICES[i]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; - if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) - continue; + if (sp.Appearance.Texture.FaceTextures[idx] == null) + sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint)idx); + sp.Appearance.Texture.FaceTextures[idx].TextureID = wearableCache[idx].TextureID; + face = sp.Appearance.Texture.FaceTextures[idx]; - if (wearableCache[idx].TextureID != face.TextureID) - { - wearableCache[idx].CacheId = UUID.Zero; - wearableCache[idx].TextureID = UUID.Zero; - wearableCache[idx].TextureAsset = null; - continue; - } - - wearableCache[idx].TextureAsset = null; - if (cache != null) - { - wearableCache[idx].TextureAsset = m_scene.AssetService.GetCached(face.TextureID.ToString()); - if (wearableCache[idx].TextureAsset == null) - { - wearableCache[idx].CacheId = UUID.Zero; - wearableCache[idx].TextureID = UUID.Zero; - } - else + // this should be removed + if (face.TextureID != UUID.Zero && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) hits++; + continue; } } } sp.Appearance.WearableCacheItems = wearableCache; + } - m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1} {2}", sp.Name, sp.UUID, hits); // debug + m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1} {2}", sp.Name, sp.UUID, hits); for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++) { int j = AvatarAppearance.BAKE_INDICES[iter];