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.
user_profiles
Mic Bowman 2013-05-24 13:18:16 -07:00
parent 440905ad14
commit 681fbda4b6
5 changed files with 146 additions and 83 deletions

View File

@ -53,6 +53,7 @@ namespace OpenSim.Framework
protected AvatarWearable[] m_wearables;
protected Dictionary<int, List<AvatarAttachment>> m_attachments;
protected float m_avatarHeight = 0;
protected UUID[] m_texturehashes;
public virtual int Serial
{
@ -98,6 +99,8 @@ namespace OpenSim.Framework
SetDefaultParams();
SetHeight();
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
ResetTextureHashes();
}
public AvatarAppearance(OSDMap map)
@ -108,32 +111,6 @@ namespace OpenSim.Framework
SetHeight();
}
public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
{
// m_log.WarnFormat("[AVATAR APPEARANCE] create initialized appearance");
m_serial = 0;
if (wearables != null)
m_wearables = wearables;
else
SetDefaultWearables();
if (textureEntry != null)
m_texture = textureEntry;
else
SetDefaultTexture();
if (visualParams != null)
m_visualparams = visualParams;
else
SetDefaultParams();
SetHeight();
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
}
public AvatarAppearance(AvatarAppearance appearance) : this(appearance, true)
{
}
@ -151,6 +128,8 @@ namespace OpenSim.Framework
SetHeight();
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
ResetTextureHashes();
return;
}
@ -166,6 +145,10 @@ namespace OpenSim.Framework
SetWearable(i,appearance.Wearables[i]);
}
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
m_texturehashes[i] = new UUID(appearance.m_texturehashes[i]);
m_texture = null;
if (appearance.Texture != null)
{
@ -200,6 +183,37 @@ namespace OpenSim.Framework
}
}
public void ResetTextureHashes()
{
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
m_texturehashes[i] = UUID.Zero;
}
public UUID GetTextureHash(int textureIndex)
{
return m_texturehashes[NormalizeBakedTextureIndex(textureIndex)];
}
public void SetTextureHash(int textureIndex, UUID textureHash)
{
m_texturehashes[NormalizeBakedTextureIndex(textureIndex)] = new UUID(textureHash);
}
/// <summary>
/// Normalizes the texture index to the actual bake index, this is done to
/// accommodate older viewers that send the BAKE_INDICES index rather than
/// the actual texture index
/// </summary>
private int NormalizeBakedTextureIndex(int textureIndex)
{
// Earlier viewer send the index into the baked index array, just trying to be careful here
if (textureIndex < BAKE_INDICES.Length)
return BAKE_INDICES[textureIndex];
return textureIndex;
}
public void ClearWearables()
{
m_wearables = new AvatarWearable[AvatarWearable.MAX_WEARABLES];
@ -223,12 +237,7 @@ namespace OpenSim.Framework
m_serial = 0;
SetDefaultTexture();
//for (int i = 0; i < BAKE_INDICES.Length; i++)
// {
// int idx = BAKE_INDICES[i];
// m_texture.FaceTextures[idx].TextureID = UUID.Zero;
// }
ResetTextureHashes();
}
protected virtual void SetDefaultParams()
@ -598,6 +607,12 @@ namespace OpenSim.Framework
data["serial"] = OSD.FromInteger(m_serial);
data["height"] = OSD.FromReal(m_avatarHeight);
// Hashes
OSDArray hashes = new OSDArray(AvatarAppearance.TEXTURE_COUNT);
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
hashes.Add(OSD.FromUUID(m_texturehashes[i]));
data["hashes"] = hashes;
// Wearables
OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES);
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
@ -642,6 +657,25 @@ namespace OpenSim.Framework
try
{
// Hashes
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
if ((data != null) && (data["hashes"] != null) && (data["hashes"]).Type == OSDType.Array)
{
OSDArray hashes = (OSDArray)(data["hashes"]);
for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
{
UUID hashID = UUID.Zero;
if (i < hashes.Count && hashes[i] != null)
hashID = hashes[i].AsUUID();
m_texturehashes[i] = hashID;
}
}
else
{
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
m_texturehashes[i] = UUID.Zero;
}
// Wearables
SetDefaultWearables();
if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array)

View File

@ -66,7 +66,7 @@ namespace OpenSim.Framework
public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest);
public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams);
public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, List<CachedTextureRequestArg> cachedTextureData);
public delegate void StartAnim(IClientAPI remoteClient, UUID animID);

View File

@ -6214,7 +6214,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (appear.ObjectData.TextureEntry.Length > 1)
te = new Primitive.TextureEntry(appear.ObjectData.TextureEntry, 0, appear.ObjectData.TextureEntry.Length);
handlerSetAppearance(sender, te, visualparams);
List<CachedTextureRequestArg> hashes = new List<CachedTextureRequestArg>();
for (int i = 0; i < appear.WearableData.Length; i++)
{
CachedTextureRequestArg arg = new CachedTextureRequestArg();
arg.BakedTextureIndex = appear.WearableData[i].TextureIndex;
arg.WearableHashID = appear.WearableData[i].CacheID;
hashes.Add(arg);
}
handlerSetAppearance(sender, te, visualparams, hashes);
}
catch (Exception e)
{
@ -11487,11 +11496,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
requestArgs.Add(arg);
}
try
{
CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
if (handlerCachedTextureRequest != null)
{
handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
}
}
catch (Exception e)
{
m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e);
return false;
}
return true;
}

View File

@ -147,7 +147,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
/// <param name="visualParam"></param>
public void SetAppearance(IScenePresence sp, AvatarAppearance appearance)
{
SetAppearance(sp, appearance.Texture, appearance.VisualParams);
DoSetAppearance(sp, appearance.Texture, appearance.VisualParams, new List<CachedTextureRequestArg>());
}
/// <summary>
@ -157,6 +157,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
/// <param name="texture"></param>
/// <param name="visualParam"></param>
public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams)
{
DoSetAppearance(sp, textureEntry, visualParams, new List<CachedTextureRequestArg>());
}
/// <summary>
/// Set appearance data (texture asset IDs and slider settings)
/// </summary>
/// <param name="sp"></param>
/// <param name="texture"></param>
/// <param name="visualParam"></param>
protected void DoSetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, List<CachedTextureRequestArg> hashes)
{
// m_log.DebugFormat(
// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
@ -191,7 +202,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
if (textureEntry != null)
{
// 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;
@ -202,6 +212,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
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.
@ -622,12 +637,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
/// <param name="client"></param>
/// <param name="texture"></param>
/// <param name="visualParam"></param>
private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, List<CachedTextureRequestArg> 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
/// <param name="cachedTextureRequest"></param>
private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> 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<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
@ -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.
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]: reuse texture {0} for index {1}",texture,index);
// m_log.WarnFormat("[AVFACTORY]: use texture {0} for index {1}; hash={2}",texture,index,request.WearableHashID);
}
CachedTextureResponseArg response = new CachedTextureResponseArg();

View File

@ -907,7 +907,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
// Mimicking LLClientView which gets always set appearance from client.
AvatarAppearance appearance;
m_scene.GetAvatarAppearance(this, out appearance);
OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone());
OnSetAppearance(this, appearance.Texture, (byte[])appearance.VisualParams.Clone(), new List<CachedTextureRequestArg>());
}
public void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args)