From 681fbda4b6b9700421b82dc639f954c60871542e Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Fri, 24 May 2013 13:18:16 -0700 Subject: This is an experimental patch that adds support for comparing texture hashes for the purpose of accurately responding to AgentTextureCached packets. There is a change to IClientAPI to report the wearbles hashes that come in through the SetAppearance packet. Added storage of the texture hashes in the appearance. While these are added to the Pack/Unpack (with support for missing values) routines (which means Simian will store them properly), they are not currently persisted in Robust. --- .../Avatar/AvatarFactory/AvatarFactoryModule.cs | 102 ++++++++++++--------- 1 file changed, 57 insertions(+), 45 deletions(-) (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index b640b48..482bf6f 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -147,7 +147,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, AvatarAppearance appearance) { - SetAppearance(sp, appearance.Texture, appearance.VisualParams); + DoSetAppearance(sp, appearance.Texture, appearance.VisualParams, new List()); } /// @@ -158,9 +158,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) { -// m_log.DebugFormat( -// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", -// sp.Name, textureEntry, visualParams); + DoSetAppearance(sp, textureEntry, visualParams, new List()); + } + + /// + /// Set appearance data (texture asset IDs and slider settings) + /// + /// + /// + /// + protected void DoSetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, List hashes) + { + // m_log.DebugFormat( + // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", + // sp.Name, textureEntry, visualParams); // TODO: This is probably not necessary any longer, just assume the // textureEntry set implies that the appearance transaction is complete @@ -190,18 +201,22 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Process the baked texture array if (textureEntry != null) { -// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); - -// WriteBakedTexturesReport(sp, m_log.DebugFormat); + // m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); + // WriteBakedTexturesReport(sp, m_log.DebugFormat); changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; -// WriteBakedTexturesReport(sp, m_log.DebugFormat); + // WriteBakedTexturesReport(sp, m_log.DebugFormat); // If bake textures are missing and this is not an NPC, request a rebake from client if (!ValidateBakedTextureCache(sp) && (((ScenePresence)sp).PresenceType != PresenceType.Npc)) RequestRebake(sp, true); + // Save the wearble hashes in the appearance + sp.Appearance.ResetTextureHashes(); + foreach (CachedTextureRequestArg arg in hashes) + sp.Appearance.SetTextureHash(arg.BakedTextureIndex,arg.WearableHashID); + // This appears to be set only in the final stage of the appearance // update transaction. In theory, we should be able to do an immediate // appearance send and save here. @@ -235,13 +250,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory public bool SendAppearance(UUID agentId) { -// m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId); + // m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId); ScenePresence sp = m_scene.GetScenePresence(agentId); if (sp == null) { // This is expected if the user has gone away. -// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); + // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); return false; } @@ -318,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void QueueAppearanceSend(UUID agentid) { -// m_log.DebugFormat("[AVFACTORY]: Queue appearance send for {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Queue appearance send for {0}", agentid); // 10000 ticks per millisecond, 1000 milliseconds per second long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000); @@ -331,7 +346,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory public void QueueAppearanceSave(UUID agentid) { -// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid); // 10000 ticks per millisecond, 1000 milliseconds per second long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); @@ -356,9 +371,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (face == null) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); + // m_log.DebugFormat( + // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", + // face.TextureID, idx, client.Name, client.AgentId); // if the texture is one of the "defaults" then skip it // this should probably be more intelligent (skirt texture doesnt matter @@ -373,7 +388,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return false; } -// m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); + // m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); // If we only found default textures, then the appearance is not cached return (defonly ? false : true); @@ -392,9 +407,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (face == null) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", -// face.TextureID, idx, client.Name, client.AgentId); + // m_log.DebugFormat( + // "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}", + // face.TextureID, idx, client.Name, client.AgentId); // if the texture is one of the "defaults" then skip it // this should probably be more intelligent (skirt texture doesnt matter @@ -458,9 +473,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakeType == BakeType.Unknown) continue; -// m_log.DebugFormat( -// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", -// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); + // m_log.DebugFormat( + // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", + // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture @@ -484,7 +499,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory UUID avatarID = kvp.Key; long sendTime = kvp.Value; -// m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); + // m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); if (sendTime < now) { @@ -530,11 +545,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (sp == null) { // This is expected if the user has gone away. -// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); + // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); return; } -// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); + // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid); // This could take awhile since it needs to pull inventory // 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 @@ -622,12 +637,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// /// /// - private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) + private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, List hashes) { // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); ScenePresence sp = m_scene.GetScenePresence(client.AgentId); if (sp != null) - SetAppearance(sp, textureEntry, visualParams); + DoSetAppearance(sp, textureEntry, visualParams, hashes); else m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); } @@ -684,7 +699,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List cachedTextureRequest) { - // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); + // m_log.DebugFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); ScenePresence sp = m_scene.GetScenePresence(client.AgentId); List cachedTextureResponse = new List(); @@ -695,23 +710,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (m_reusetextures) { - // this is the most insanely dumb way to do this... however it seems to - // actually work. if the appearance has been reset because wearables have - // changed then the texture entries are zero'd out until the bakes are - // uploaded. on login, if the textures exist in the cache (eg if you logged - // into the simulator recently, then the appearance will pull those and send - // them back in the packet and you won't have to rebake. if the textures aren't - // in the cache then the intial makeroot() call in scenepresence will zero - // them out. - // - // a better solution (though how much better is an open question) is to - // store the hashes in the appearance and compare them. Thats's coming. - - Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; - if (face != null) - texture = face.TextureID; - - // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); + if (sp.Appearance.GetTextureHash(index) == request.WearableHashID) + { + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; + if (face != null) + texture = face.TextureID; + } + else + { + // We know that that hash is wrong, null it out + // and wait for the setappearance call + sp.Appearance.SetTextureHash(index,UUID.Zero); + } + + // m_log.WarnFormat("[AVFACTORY]: use texture {0} for index {1}; hash={2}",texture,index,request.WearableHashID); } CachedTextureResponseArg response = new CachedTextureResponseArg(); -- cgit v1.1