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;

0.9.1.0-post-fixes
UbitUmarov 2019-09-11 13:51:43 +01:00
parent 6aa369d858
commit 9d6c996570
22 changed files with 441 additions and 412 deletions

View File

@ -51,27 +51,28 @@ namespace OpenSim.Framework
// this is viewer capabilities and weared things dependent // this is viewer capabilities and weared things dependent
// should be only used as initial default value ( V1 viewers ) // should be only used as initial default value ( V1 viewers )
public readonly static int VISUALPARAM_COUNT = 218; public const int VISUALPARAM_COUNT = 218;
// public readonly static int TEXTURE_COUNT = 21 // regions and viewer compatibility
// 21 bad, make it be updated as libovm gets update public readonly static int TEXTURE_COUNT = 45;
// also keeping in sync with it public const int TEXTURE_COUNT_PV7 = 26;
public readonly static int TEXTURE_COUNT = Primitive.TextureEntry.MAX_FACES; public const int BAKES_COUNT_PV7 = 6;
public const int MAXWEARABLE_PV7 = 16;
public const int MAXWEARABLE_LEGACY = 14;
public readonly static byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; public readonly static byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20, 40, 41, 42, 43, 44 };
protected int m_serial = 0; protected int m_serial = 0;
protected byte[] m_visualparams; protected byte[] m_visualparams;
protected Primitive.TextureEntry m_texture; protected Primitive.TextureEntry m_texture;
protected AvatarWearable[] m_wearables; protected AvatarWearable[] m_wearables;
protected Dictionary<int, List<AvatarAttachment>> m_attachments; protected Dictionary<int, List<AvatarAttachment>> m_attachments;
protected float m_avatarHeight = 0; protected WearableCacheItem[] m_cacheitems;
protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value
protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f); protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f);
protected float m_avatarHeight = 0;
protected float m_avatarFeetOffset = 0; protected float m_avatarFeetOffset = 0;
protected float m_avatarAnimOffset = 0; protected float m_avatarAnimOffset = 0;
protected WearableCacheItem[] m_cacheitems;
protected bool m_cacheItemsDirty = true;
public virtual int Serial public virtual int Serial
{ {
@ -128,11 +129,7 @@ namespace OpenSim.Framework
set { m_cacheitems = value; } set { m_cacheitems = value; }
} }
public virtual bool WearableCacheItemsDirty public virtual float AvatarPreferencesHoverZ { get; set; }
{
get { return m_cacheItemsDirty; }
set { m_cacheItemsDirty = value; }
}
public AvatarAppearance() public AvatarAppearance()
{ {
@ -204,12 +201,14 @@ namespace OpenSim.Framework
SetDefaultParams(); SetDefaultParams();
// SetHeight(); // SetHeight();
SetSize(new Vector3(0.45f, 0.6f, 1.9f)); SetSize(new Vector3(0.45f, 0.6f, 1.9f));
AvatarPreferencesHoverZ = 0;
m_attachments = new Dictionary<int, List<AvatarAttachment>>(); m_attachments = new Dictionary<int, List<AvatarAttachment>>();
return; return;
} }
m_serial = appearance.Serial; m_serial = appearance.Serial;
AvatarPreferencesHoverZ = appearance.AvatarPreferencesHoverZ;
if (copyWearables && (appearance.Wearables != null)) if (copyWearables && (appearance.Wearables != null))
{ {
@ -228,7 +227,7 @@ namespace OpenSim.Framework
m_texture = null; m_texture = null;
if (appearance.Texture != null) if (appearance.Texture != null)
{ {
byte[] tbytes = appearance.Texture.GetBytes(); byte[] tbytes = appearance.Texture.GetBakesBytes();
m_texture = new Primitive.TextureEntry(tbytes,0,tbytes.Length); m_texture = new Primitive.TextureEntry(tbytes,0,tbytes.Length);
if (copyBaked && appearance.m_cacheitems != null) if (copyBaked && appearance.m_cacheitems != null)
m_cacheitems = (WearableCacheItem[])appearance.m_cacheitems.Clone(); m_cacheitems = (WearableCacheItem[])appearance.m_cacheitems.Clone();
@ -295,6 +294,7 @@ namespace OpenSim.Framework
m_serial = 0; m_serial = 0;
SetDefaultTexture(); SetDefaultTexture();
AvatarPreferencesHoverZ = 0;
//for (int i = 0; i < BAKE_INDICES.Length; i++) //for (int i = 0; i < BAKE_INDICES.Length; i++)
// { // {
@ -330,9 +330,6 @@ namespace OpenSim.Framework
protected virtual void SetDefaultTexture() protected virtual void SetDefaultTexture()
{ {
m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
// for (uint i = 0; i < TEXTURE_COUNT; i++)
// m_texture.CreateFace(i).TextureID = new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE);
} }
/// <summary> /// <summary>
@ -347,31 +344,31 @@ namespace OpenSim.Framework
if (textureEntry == null) if (textureEntry == null)
return false; return false;
// There are much simpler versions of this copy that could be
// made. We determine if any of the textures actually
// changed to know if the appearance should be saved later
bool changed = false; bool changed = false;
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) Primitive.TextureEntryFace newface;
{ Primitive.TextureEntryFace tmpFace;
Primitive.TextureEntryFace newface = textureEntry.FaceTextures[i];
Primitive.TextureEntryFace oldface = m_texture.FaceTextures[i];
if (newface == null) //make sure textureEntry.DefaultTexture is the unused one(DEFAULT_AVATAR_TEXTURE).
Primitive.TextureEntry converted = new Primitive.TextureEntry(AppearanceManager.DEFAULT_AVATAR_TEXTURE);
for (uint i = 0; i < TEXTURE_COUNT; ++i)
{
newface = textureEntry.GetFace(i);
if (newface.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
{ {
if (oldface == null) tmpFace = converted.GetFace(i);
continue; tmpFace.TextureID = newface.TextureID; // we need a full high level copy, assuming all other parameters are the same.
if (m_texture.FaceTextures[i] == null || newface.TextureID != m_texture.FaceTextures[i].TextureID)
changed = true;
} }
else else
{ { if (m_texture.FaceTextures[i] == null)
if (oldface != null && oldface.TextureID == newface.TextureID)
continue; continue;
if(m_texture.FaceTextures[i].TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
changed = true;
} }
changed = true;
} }
if(changed)
m_texture = textureEntry; m_texture = converted;
return changed; return changed;
} }
@ -736,42 +733,69 @@ namespace OpenSim.Framework
data["serial"] = OSD.FromInteger(m_serial); data["serial"] = OSD.FromInteger(m_serial);
data["height"] = OSD.FromReal(m_avatarHeight); data["height"] = OSD.FromReal(m_avatarHeight);
data["aphz"] = OSD.FromReal(AvatarPreferencesHoverZ);
if (m_texture == null)
return data;
bool sendPV8 = false;
if(ctx != null)
sendPV8 = ctx.OutboundVersion >= 0.8;
// Wearables // Wearables
// OSDArray wears;
// This will send as many or as few wearables as we have, unless a count int count;
// is given. Used for legacy (pre 0.4) versions. if (ctx == null)
int count = ctx.WearablesCount; count = MAXWEARABLE_LEGACY;
if (ctx.WearablesCount == -1) else
count = m_wearables.Length;
OSDArray wears = new OSDArray(count);
for (int i = 0; i < count; i++)
{ {
AvatarWearable dummyWearable = new AvatarWearable(); int wbcount = ctx.WearablesCount;
if (wbcount == -1)
wbcount = m_wearables.Length;
if (i < m_wearables.Length) count = wbcount;
wears.Add(m_wearables[i].Pack()); if(count > MAXWEARABLE_PV7)
else {
wears.Add(dummyWearable.Pack()); count = MAXWEARABLE_PV7;
if(sendPV8)
{
wears = new OSDArray(wbcount - MAXWEARABLE_PV7);
for (int i = MAXWEARABLE_PV7; i < wbcount; ++i)
wears.Add(m_wearables[i].Pack());
data["wrbls8"] = wears;
}
}
} }
wears = new OSDArray(count);
for (int i = 0; i < count; i++)
wears.Add(m_wearables[i].Pack());
data["wearables"] = wears; data["wearables"] = wears;
// Avatar Textures // Avatar Textures and preferences hover
OSDArray textures = new OSDArray(AvatarAppearance.TEXTURE_COUNT); OSDArray textures;
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) if (sendPV8)
{ {
if (m_texture.FaceTextures[i] != null) byte[] te = m_texture.GetBakesBytes();
textures.Add(OSD.FromUUID(m_texture.FaceTextures[i].TextureID)); data["te8"] = OSD.FromBinary(te);
else }
textures.Add(OSD.FromUUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); else
{
textures = new OSDArray(TEXTURE_COUNT_PV7);
for (uint i = 0; i < TEXTURE_COUNT_PV7; i++)
textures.Add(OSD.FromUUID(m_texture.GetFace(i).TextureID));
data["textures"] = textures;
} }
data["textures"] = textures;
if (m_cacheitems != null) if (m_cacheitems != null)
{ {
OSDArray baked = WearableCacheItem.BakedToOSD(m_cacheitems); OSDArray baked = WearableCacheItem.BakedToOSD(m_cacheitems, 0, BAKES_COUNT_PV7);
if (baked != null) if (baked != null && baked.Count > 0)
data["bakedcache"] = baked; data["bakedcache"] = baked;
baked = WearableCacheItem.BakedToOSD(m_cacheitems, BAKES_COUNT_PV7, -1);
if (baked != null && baked.Count > 0)
data["bc8"] = baked;
} }
// Visual Parameters // Visual Parameters
@ -810,48 +834,88 @@ namespace OpenSim.Framework
OSD tmpOSD; OSD tmpOSD;
if (data.TryGetValue("serial", out tmpOSD)) if (data.TryGetValue("serial", out tmpOSD))
m_serial = tmpOSD.AsInteger(); m_serial = tmpOSD.AsInteger();
if(data.TryGetValue("aphz", out tmpOSD))
AvatarPreferencesHoverZ = (float)tmpOSD.AsReal();
if (data.TryGetValue("height", out tmpOSD)) if (data.TryGetValue("height", out tmpOSD))
// m_avatarHeight = (float)data["height"].AsReal(); SetSize(new Vector3(0.45f, 0.6f, (float)tmpOSD.AsReal()));
SetSize(new Vector3(0.45f,0.6f, (float)tmpOSD.AsReal()));
try try
{ {
// Wearables // Wearables
OSD tmpOSD8;
OSDArray wears8 = null;
int wears8Count = 0;
if (data.TryGetValue("wrbls8", out tmpOSD8) && (tmpOSD8 is OSDArray))
{
wears8 = (OSDArray)tmpOSD;
wears8Count = wears8.Count;
}
if (data.TryGetValue("wearables", out tmpOSD) && (tmpOSD is OSDArray)) if (data.TryGetValue("wearables", out tmpOSD) && (tmpOSD is OSDArray))
{ {
OSDArray wears = (OSDArray)tmpOSD; OSDArray wears = (OSDArray)tmpOSD;
m_wearables = new AvatarWearable[wears.Count]; m_wearables = new AvatarWearable[wears.Count + wears8Count];
for (int i = 0; i < wears.Count; i++) for (int i = 0; i < wears.Count; ++i)
m_wearables[i] = new AvatarWearable((OSDArray)wears[i]); m_wearables[i] = new AvatarWearable((OSDArray)wears[i]);
if (wears8Count > 0)
{
for (int i = wears.Count; i < wears8Count + wears.Count; ++i)
m_wearables[i] = new AvatarWearable((OSDArray)wears[i]);
}
} }
else else
{ {
m_log.Warn("[AVATAR APPEARANCE]: failed to unpack wearables"); m_log.Warn("[AVATAR APPEARANCE]: failed to unpack wearables");
} }
// Avatar Textures
if (data.TryGetValue("textures", out tmpOSD) && (tmpOSD is OSDArray)) if (data.TryGetValue("textures", out tmpOSD) && (tmpOSD is OSDArray))
{ {
OSDArray textures = (OSDArray)tmpOSD; OSDArray textures = (OSDArray)tmpOSD;
for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT && i < textures.Count; i++) for (int i = 0; i < textures.Count && i < TEXTURE_COUNT_PV7; ++i)
{ {
UUID textureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
tmpOSD = textures[i]; tmpOSD = textures[i];
if (tmpOSD != null) if (tmpOSD != null)
textureID = tmpOSD.AsUUID(); m_texture.CreateFace((uint)i).TextureID = tmpOSD.AsUUID();
m_texture.CreateFace((uint)i).TextureID = new UUID(textureID);
} }
} }
else if (data.TryGetValue("te8", out tmpOSD))
{ {
m_log.Warn("[AVATAR APPEARANCE]: failed to unpack textures"); byte[] teb = tmpOSD.AsBinary();
Primitive.TextureEntry te = new Primitive.TextureEntry(teb, 0, teb.Length);
m_texture = te;
} }
if (data.TryGetValue("bakedcache", out tmpOSD) && (tmpOSD is OSDArray)) if (data.TryGetValue("bakedcache", out tmpOSD) && (tmpOSD is OSDArray))
{ {
OSDArray bakedOSDArray = (OSDArray)tmpOSD; OSDArray bakedOSDArray = (OSDArray)tmpOSD;
m_cacheitems = WearableCacheItem.BakedFromOSD(bakedOSDArray); m_cacheitems = WearableCacheItem.GetDefaultCacheItem();
bakedOSDArray = (OSDArray)tmpOSD;
foreach (OSDMap item in bakedOSDArray)
{
int idx = item["textureindex"].AsInteger();
if (idx < 0 || idx >= m_cacheitems.Length)
continue;
m_cacheitems[idx].CacheId = item["cacheid"].AsUUID();
m_cacheitems[idx].TextureID = item["textureid"].AsUUID();
m_cacheitems[idx].TextureAsset = null;
}
if (data.TryGetValue("bc8", out tmpOSD) && (tmpOSD is OSDArray))
{
bakedOSDArray = (OSDArray)tmpOSD;
foreach (OSDMap item in bakedOSDArray)
{
int idx = item["textureindex"].AsInteger();
if (idx < 0 || idx >= m_cacheitems.Length)
continue;
m_cacheitems[idx].CacheId = item["cacheid"].AsUUID();
m_cacheitems[idx].TextureID = item["textureid"].AsUUID();
m_cacheitems[idx].TextureAsset = null;
}
}
} }
// Visual Parameters // Visual Parameters
@ -888,6 +952,32 @@ namespace OpenSim.Framework
#endregion #endregion
public bool CanTeleport(float version)
{
if (version >= 0.8)
return true;
if (m_wearables.Length <= MAXWEARABLE_PV7)
return true;
for(int i = MAXWEARABLE_PV7; i < m_wearables.Length; ++i)
{
if(m_wearables[i].Count > 0)
return false;
}
// also check baked
for(int i = BAKES_COUNT_PV7; i < BAKE_INDICES.Length; i++)
{
int idx = BAKE_INDICES[i];
if (m_texture.FaceTextures[idx] == null)
continue;
UUID tid = m_texture.FaceTextures[idx].TextureID;
if(tid == AppearanceManager.DEFAULT_AVATAR_TEXTURE || tid == UUID.Zero)
continue;
return false;
}
return true;
}
#region VPElement #region VPElement
/// <summary> /// <summary>

View File

@ -67,10 +67,14 @@ namespace OpenSim.Framework
public static readonly int ALPHA = 13; public static readonly int ALPHA = 13;
public static readonly int TATTOO = 14; public static readonly int TATTOO = 14;
public static readonly int LEGACY_VERSION_MAX_WEARABLES = 15; public static readonly int LEGACY_VERSION_MAX_WEARABLES = 15;
// public static readonly int PHYSICS = 15;
// public static int MAX_WEARABLES = 16; public static readonly int PHYSICS = 15;
public static int MAX_WEARABLES_PV7 = 16;
public static readonly int UNIVERSAL = 16;
public static int MAX_WEARABLES = 17;
public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9"); public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9");

View File

@ -1107,7 +1107,7 @@ namespace OpenSim.Framework
/// <param name="agentID">The id of the agent associated with the appearance</param> /// <param name="agentID">The id of the agent associated with the appearance</param>
/// <param name="visualParams"></param> /// <param name="visualParams"></param>
/// <param name="textureEntry"></param> /// <param name="textureEntry"></param>
void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry, float hoverheight);
void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures); void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures);

View File

@ -220,12 +220,6 @@ namespace OpenSim.Framework.Tests
AvAppearance.VisualParams = VisualParams; AvAppearance.VisualParams = VisualParams;
List<byte> wearbyte = new List<byte>();
for (int i = 0; i < VisualParams.Length; i++)
{
wearbyte.Add(VisualParams[i]);
}
AvAppearance.SetAppearance(AvAppearance.Texture, (byte[])VisualParams.Clone()); AvAppearance.SetAppearance(AvAppearance.Texture, (byte[])VisualParams.Clone());
} }

View File

@ -85,8 +85,8 @@ namespace OpenSim
/// - this is an older teleport protocol used in OpenSimulator 0.7.5 and before. /// - this is an older teleport protocol used in OpenSimulator 0.7.5 and before.
/// </remarks> /// </remarks>
public readonly static float SimulationServiceVersionAcceptedMin = 0.3f; public readonly static float SimulationServiceVersionAcceptedMin = 0.3f;
public readonly static float SimulationServiceVersionAcceptedMax = 0.7f; public readonly static float SimulationServiceVersionAcceptedMax = 0.8f;
public readonly static float SimulationServiceVersionSupportedMin = 0.3f; public readonly static float SimulationServiceVersionSupportedMin = 0.3f;
public readonly static float SimulationServiceVersionSupportedMax = 0.7f; public readonly static float SimulationServiceVersionSupportedMax = 0.8f;
} }
} }

View File

@ -128,31 +128,27 @@ namespace OpenSim.Framework
return arr; return arr;
} }
public static OSDArray BakedToOSD(WearableCacheItem[] pcacheItems) public static OSDArray BakedToOSD(WearableCacheItem[] pcacheItems, int start, int end)
{ {
if (pcacheItems.Length < AvatarAppearance.BAKE_INDICES[AvatarAppearance.BAKE_INDICES.Length - 1]) OSDArray arr = new OSDArray();
if(start < 0)
start = 0;
if (end < 0 || end > AvatarAppearance.BAKE_INDICES.Length)
end = AvatarAppearance.BAKE_INDICES.Length;
if (start > end)
return null; return null;
OSDArray arr = new OSDArray(); for (int i = start; i < end; i++)
for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
{ {
int idx = AvatarAppearance.BAKE_INDICES[i]; int idx = AvatarAppearance.BAKE_INDICES[i];
if(idx >= pcacheItems.Length)
continue;
WearableCacheItem item = pcacheItems[idx]; WearableCacheItem item = pcacheItems[idx];
OSDMap itemmap = new OSDMap(); OSDMap itemmap = new OSDMap();
itemmap.Add("textureindex", OSD.FromUInteger(item.TextureIndex)); itemmap.Add("textureindex", OSD.FromUInteger(item.TextureIndex));
itemmap.Add("cacheid", OSD.FromUUID(item.CacheId)); itemmap.Add("cacheid", OSD.FromUUID(item.CacheId));
itemmap.Add("textureid", OSD.FromUUID(item.TextureID)); 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); arr.Add(itemmap);
} }
return arr; return arr;
@ -167,22 +163,11 @@ namespace OpenSim.Framework
foreach (OSDMap item in itemarray) foreach (OSDMap item in itemarray)
{ {
int idx = item["textureindex"].AsInteger(); int idx = item["textureindex"].AsInteger();
if (idx < 0 || idx > pcache.Length) if (idx < 0 || idx >= pcache.Length)
continue; continue;
pcache[idx].CacheId = item["cacheid"].AsUUID(); pcache[idx].CacheId = item["cacheid"].AsUUID();
pcache[idx].TextureID = item["textureid"].AsUUID(); pcache[idx].TextureID = item["textureid"].AsUUID();
/* pcache[idx].TextureAsset = null;
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; return pcache;

View File

@ -989,11 +989,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
//RegionInfo4 block //RegionInfo4 block
//RegionFlagsExtended //RegionFlagsExtended
zc.AddZeros(1); // we dont have this //zc.AddZeros(1); // if we dont have this else
//zc.AddByte(1); zc.AddByte(1);
//zc.AddUInt64(regionFlags); // we have nothing other base flags zc.AddUInt64(regionFlags); // we have nothing other base flags
//RegionProtocols //RegionProtocols
//zc.AddUInt64(0); // bit 0 signals server side texture baking" // bit 0 signals server side texture baking
// bit 63 signals more than 6 baked textures support"
zc.AddUInt64(1UL << 63);
buf.DataLength = zc.Finish(); buf.DataLength = zc.Finish();
m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown); m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Unknown);
@ -4434,7 +4436,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
//0xff, 0xff, 0, 1, 158 // ID 158 (low frequency bigendian) zeroencoded //0xff, 0xff, 0, 1, 158 // ID 158 (low frequency bigendian) zeroencoded
}; };
public void SendAppearance(UUID targetID, byte[] visualParams, byte[] textureEntry) public void SendAppearance(UUID targetID, byte[] visualParams, byte[] textureEntry, float hover)
{ {
// doing post zero encode, because odds of beeing bad are not that low // doing post zero encode, because odds of beeing bad are not that low
UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint); UDPPacketBuffer buf = m_udpServer.GetNewUDPBuffer(m_udpClient.RemoteEndPoint);
@ -4469,7 +4471,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// no AppearanceData // no AppearanceData
data[pos++] = 0; data[pos++] = 0;
// no AppearanceHover // no AppearanceHover
data[pos++] = 0; data[pos++] = 1;
Utils.FloatToBytesSafepos(0, data, pos); pos += 4;
Utils.FloatToBytesSafepos(0, data, pos); pos += 4;
Utils.FloatToBytesSafepos(hover, data, pos); pos += 4;
buf.DataLength = pos; buf.DataLength = pos;
m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority, null, false, true); m_udpServer.SendUDPPacket(m_udpClient, buf, ThrottleOutPacketType.Task | ThrottleOutPacketType.HighPriority, null, false, true);

View File

@ -27,6 +27,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Text; using System.Text;
@ -35,6 +36,7 @@ using log4net;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
@ -59,8 +61,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
private Dictionary<UUID,long> m_savequeue = new Dictionary<UUID,long>(); private ConcurrentDictionary<UUID,long> m_savequeue = new ConcurrentDictionary<UUID,long>();
private Dictionary<UUID,long> m_sendqueue = new Dictionary<UUID,long>(); private ConcurrentDictionary<UUID,long> m_sendqueue = new ConcurrentDictionary<UUID,long>();
private object m_updatesLock = new object();
private int m_updatesbusy = 0;
private object m_setAppearanceLock = new object(); private object m_setAppearanceLock = new object();
@ -134,7 +138,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
client.OnRequestWearables += Client_OnRequestWearables; client.OnRequestWearables += Client_OnRequestWearables;
client.OnSetAppearance += Client_OnSetAppearance; client.OnSetAppearance += Client_OnSetAppearance;
client.OnAvatarNowWearing += Client_OnAvatarNowWearing; client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
client.OnCachedTextureRequest += Client_OnCachedTextureRequest; //client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
} }
#endregion #endregion
@ -232,20 +236,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
sp.SendAppearanceToAllOtherAgents(); sp.SendAppearanceToAllOtherAgents();
// Send animations back to the avatar as well // Send animations back to the avatar as well
sp.Animator.SendAnimPack(); if(sp.Animator != null)
sp.Animator.SendAnimPack();
} }
public bool SendAppearance(UUID agentId) public bool SendAppearance(UUID agentId)
{ {
// m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId);
ScenePresence sp = m_scene.GetScenePresence(agentId); ScenePresence sp = m_scene.GetScenePresence(agentId);
if (sp == null) if (sp == null || sp.IsDeleted)
{
// This is expected if the user has gone away.
// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
return false; return false;
}
SendAppearance(sp); SendAppearance(sp);
return true; return true;
@ -338,11 +337,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// 10000 ticks per millisecond, 1000 milliseconds per second // 10000 ticks per millisecond, 1000 milliseconds per second
long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000); long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000);
lock (m_sendqueue) m_sendqueue[agentid] = timestamp;
{ m_updateTimer.Start();
m_sendqueue[agentid] = timestamp;
m_updateTimer.Start();
}
} }
public void QueueAppearanceSave(UUID agentid) public void QueueAppearanceSave(UUID agentid)
@ -351,11 +347,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// 10000 ticks per millisecond, 1000 milliseconds per second // 10000 ticks per millisecond, 1000 milliseconds per second
long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
lock (m_savequeue) m_savequeue[agentid] = timestamp;
{ m_updateTimer.Start();
m_savequeue[agentid] = timestamp;
m_updateTimer.Start();
}
} }
// called on textures update // called on textures update
@ -370,106 +363,90 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// uploaded baked textures will be in assets local cache // uploaded baked textures will be in assets local cache
IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>(); IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
int validDirtyBakes = 0; int validDirtyBakes = 0;
int hits = 0; int hits = 0;
// our main cacheIDs mapper is p.Appearance.WearableCacheItems // our main cacheIDs mapper is p.Appearance.WearableCacheItems
WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; bool hadSkirt = false;
WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
if (wearableCache == null) if (wearableCache == null)
{
wearableCache = WearableCacheItem.GetDefaultCacheItem(); wearableCache = WearableCacheItem.GetDefaultCacheItem();
else
{
hadSkirt = (wearableCache[19].TextureID != UUID.Zero);
} }
HashSet<uint> updatedFaces = new HashSet<uint>();
List<UUID> missing = new List<UUID>(); List<UUID> missing = new List<UUID>();
bool haveSkirt = (wearableCache[19].TextureID != UUID.Zero);
bool haveNewSkirt = false;
// Process received baked textures // Process received baked textures
for (int i = 0; i < cacheItems.Length; i++) for (int i = 0; i < cacheItems.Length; i++)
{ {
int idx = (int)cacheItems[i].TextureIndex; uint idx = cacheItems[i].TextureIndex;
if(idx >= AvatarAppearance.TEXTURE_COUNT)
{
hits++;
continue;
}
updatedFaces.Add(idx);
wearableCache[idx].TextureAsset = null; // just in case
Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
// No face if (face == null || face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
if (face == null)
{ {
// for some reason viewer is cleaning this
if(idx != 19) // skirt is optional
{
sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx);
sp.Appearance.Texture.FaceTextures[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
}
wearableCache[idx].CacheId = UUID.Zero; wearableCache[idx].CacheId = UUID.Zero;
wearableCache[idx].TextureID = UUID.Zero; wearableCache[idx].TextureID = UUID.Zero;
wearableCache[idx].TextureAsset = null; if (idx == 19)
{
hits++;
if(hadSkirt)
validDirtyBakes++;
}
continue; continue;
} }
if (cache != null)
{
AssetBase asb = null;
cache.Get(face.TextureID.ToString(), out asb);
wearableCache[idx].TextureAsset = asb;
}
if (wearableCache[idx].TextureAsset != null)
{
if ( wearableCache[idx].TextureID != face.TextureID ||
wearableCache[idx].CacheId != cacheItems[i].CacheId)
validDirtyBakes++;
wearableCache[idx].TextureID = face.TextureID;
wearableCache[idx].CacheId = cacheItems[i].CacheId;
hits++;
}
else else
{ {
if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE) wearableCache[idx].CacheId = UUID.Zero;
{ wearableCache[idx].TextureID = UUID.Zero;
wearableCache[idx].CacheId = UUID.Zero; missing.Add(face.TextureID);
wearableCache[idx].TextureID = UUID.Zero; continue;
wearableCache[idx].TextureAsset = null;
continue;
}
if(idx == 19)
haveNewSkirt = true;
/*
if (face.TextureID == wearableCache[idx].TextureID && m_BakedTextureModule != null)
{
if (wearableCache[idx].CacheId != cacheItems[i].CacheId)
{
wearableCache[idx].CacheId = cacheItems[i].CacheId;
validDirtyBakes++;
//assuming this can only happen if asset is in cache
}
hits++;
continue;
}
*/
wearableCache[idx].TextureAsset = null;
if (cache != null)
{
AssetBase asb = null;
cache.Get(face.TextureID.ToString(), out asb);
wearableCache[idx].TextureAsset = asb;
}
if (wearableCache[idx].TextureAsset != null)
{
if ( wearableCache[idx].TextureID != face.TextureID ||
wearableCache[idx].CacheId != cacheItems[i].CacheId)
validDirtyBakes++;
wearableCache[idx].TextureID = face.TextureID;
wearableCache[idx].CacheId = cacheItems[i].CacheId;
hits++;
}
else
{
wearableCache[idx].CacheId = UUID.Zero;
wearableCache[idx].TextureID = UUID.Zero;
wearableCache[idx].TextureAsset = null;
missing.Add(face.TextureID);
continue;
}
} }
} }
// handle optional skirt case // this may be a current fs bug
if(!haveNewSkirt && haveSkirt) for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
{ {
wearableCache[19].CacheId = UUID.Zero; uint idx = AvatarAppearance.BAKE_INDICES[i];
wearableCache[19].TextureID = UUID.Zero; if(updatedFaces.Contains(idx))
wearableCache[19].TextureAsset = null; continue;
validDirtyBakes++;
sp.Appearance.Texture.FaceTextures[idx] = null;
wearableCache[idx].CacheId = UUID.Zero;
wearableCache[idx].TextureID = UUID.Zero;
wearableCache[idx].TextureAsset = null;
} }
sp.Appearance.WearableCacheItems = wearableCache; sp.Appearance.WearableCacheItems = wearableCache;
@ -480,15 +457,18 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
sp.ControllingClient.SendRebakeAvatarTextures(id); sp.ControllingClient.SendRebakeAvatarTextures(id);
} }
bool changed = false;
if (validDirtyBakes > 0 && hits == cacheItems.Length) if (validDirtyBakes > 0 && hits == cacheItems.Length)
{ {
// if we got a full set of baked textures save all in BakedTextureModule // if we got a full set of baked textures save all in BakedTextureModule
IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
if (m_BakedTextureModule != null) if (m_BakedTextureModule != null)
{ {
m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}", m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}",
hits.ToString(), validDirtyBakes.ToString(), missing.Count); hits.ToString(), validDirtyBakes.ToString(), missing.Count);
m_BakedTextureModule.Store(sp.UUID, wearableCache); m_BakedTextureModule.Store(sp.UUID, wearableCache);
changed = true;
} }
} }
else else
@ -505,26 +485,25 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// sp.Appearance.WearableCacheItems[j].TextureID); // sp.Appearance.WearableCacheItems[j].TextureID);
} }
return (hits == cacheItems.Length); return changed;
} }
// called when we get a new root avatar // called when we get a new root avatar
public bool ValidateBakedTextureCache(IScenePresence sp) public bool ValidateBakedTextureCache(IScenePresence sp)
{ {
int hits = 0;
if (((ScenePresence)sp).IsNPC) if (((ScenePresence)sp).IsNPC)
return true; return true;
int hits = 0;
IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
if (cache == null)
return false;
IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
lock (m_setAppearanceLock) lock (m_setAppearanceLock)
{ {
IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
WearableCacheItem[] bakedModuleCache = null;
if (cache == null)
return false;
WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems; WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
// big debug // big debug
@ -566,70 +545,47 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
} }
else else
{ {
// we may have received a full cache
// check same coerence and store
wearableCacheValid = true; wearableCacheValid = true;
Primitive.TextureEntryFace face;
for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
{ {
int idx = AvatarAppearance.BAKE_INDICES[i]; int idx = AvatarAppearance.BAKE_INDICES[i];
Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; face = sp.Appearance.Texture.FaceTextures[idx];
if (face != null)
{
if (face.TextureID == wearableCache[idx].TextureID &&
face.TextureID != UUID.Zero)
{
if (wearableCache[idx].TextureAsset != null)
{
hits++;
wearableCache[idx].TextureAsset.Temporary = true;
wearableCache[idx].TextureAsset.Local = true;
cache.Cache(wearableCache[idx].TextureAsset);
wearableCache[idx].TextureAsset = null;
continue;
}
if (cache.Check((wearableCache[idx].TextureID).ToString()))
{
hits++;
continue;
}
}
wearableCacheValid = false;
}
}
wearableCacheValid = (wearableCacheValid && (hits >= AvatarAppearance.BAKE_INDICES.Length - 1)); if(face == null || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
if (wearableCacheValid) {
{ wearableCache[idx].CacheId = UUID.Zero;
// m_log.Debug("[ValidateBakedCache] have valid local cache"); wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
hits++;
continue;
}
if (face.TextureID == wearableCache[idx].TextureID &&
face.TextureID != UUID.Zero)
{
if (cache.Check((wearableCache[idx].TextureID).ToString()))
{
hits++;
continue;
}
}
wearableCache[idx].CacheId = UUID.Zero;
wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
wearableCacheValid = false;
} }
else
wearableCache[19].TextureAsset = null; // clear optional skirt
} }
bool checkExternal = false; bool checkExternal = false;
if (!wearableCacheValid) if (!wearableCacheValid)
{ checkExternal = bakedModule != null;
hits = 0;
// only use external bake module on login condition check
// ScenePresence ssp = null;
// if (sp is ScenePresence)
{
// ssp = (ScenePresence)sp;
// checkExternal = (((uint)ssp.TeleportFlags & (uint)TeleportFlags.ViaLogin) != 0) &&
// bakedModule != null;
// or do it anytime we dont have the cache
checkExternal = bakedModule != null;
}
}
if (checkExternal) if (checkExternal)
{ {
WearableCacheItem[] bakedModuleCache = null;
bool gotbacked = false; bool gotbacked = false;
hits = 0;
// m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule"); // m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule");
try try
{ {
bakedModuleCache = bakedModule.Get(sp.UUID); bakedModuleCache = bakedModule.Get(sp.UUID);
@ -647,8 +603,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
for (int i = 0; i < bakedModuleCache.Length; i++) for (int i = 0; i < bakedModuleCache.Length; i++)
{ {
int j = (int)bakedModuleCache[i].TextureIndex; int j = (int)bakedModuleCache[i].TextureIndex;
if (j < AvatarAppearance.TEXTURE_COUNT && bakedModuleCache[i].TextureAsset != null)
if (bakedModuleCache[i].TextureAsset != null)
{ {
wearableCache[j].TextureID = bakedModuleCache[i].TextureID; wearableCache[j].TextureID = bakedModuleCache[i].TextureID;
wearableCache[j].CacheId = bakedModuleCache[i].CacheId; wearableCache[j].CacheId = bakedModuleCache[i].CacheId;
@ -658,33 +613,27 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
cache.Cache(bakedModuleCache[i].TextureAsset); cache.Cache(bakedModuleCache[i].TextureAsset);
} }
} }
gotbacked = true;
}
if (gotbacked)
{
// force the ones we got // force the ones we got
for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
{ {
int idx = AvatarAppearance.BAKE_INDICES[i]; int idx = AvatarAppearance.BAKE_INDICES[i];
if(wearableCache[idx].TextureAsset == null) if (wearableCache[idx].TextureAsset == null)
{ {
if(idx == 19) if(idx == 19)
{ {
sp.Appearance.Texture.FaceTextures[idx] = null; sp.Appearance.Texture.FaceTextures[idx] = null;
hits++; hits++;
} }
else if(sp.Appearance.Texture.FaceTextures[idx] == null ||
sp.Appearance.Texture.FaceTextures[idx].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
hits++;
wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
wearableCache[idx].CacheId = UUID.Zero;
continue; continue;
} }
Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; Primitive.TextureEntryFace face = sp.Appearance.Texture.GetFace((uint)idx);
if (face == null)
{
face = sp.Appearance.Texture.CreateFace((uint)idx);
sp.Appearance.Texture.FaceTextures[idx] = face;
}
face.TextureID = wearableCache[idx].TextureID; face.TextureID = wearableCache[idx].TextureID;
hits++; hits++;
wearableCache[idx].TextureAsset = null; wearableCache[idx].TextureAsset = null;
@ -708,7 +657,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
sp.Appearance.WearableCacheItems[j].TextureID); sp.Appearance.WearableCacheItems[j].TextureID);
} }
*/ */
return (hits >= AvatarAppearance.BAKE_INDICES.Length - 1); // skirt is optional return (hits >= AvatarAppearance.BAKE_INDICES.Length); // skirt is optional
} }
public int RequestRebake(IScenePresence sp, bool missingTexturesOnly) public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
@ -776,13 +725,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
foreach (int i in Enum.GetValues(typeof(BakeType))) foreach (int i in Enum.GetValues(typeof(BakeType)))
{ {
BakeType bakeType = (BakeType)i; BakeType bakeType = (BakeType)i;
if (bakeType == BakeType.NumberOfEntries)
break;
if (bakeType == BakeType.Unknown) if (bakeType == BakeType.Unknown)
continue; continue;
// m_log.DebugFormat( // m_log.DebugFormat(
// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}", // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType);
Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture 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
private void HandleAppearanceUpdateTimer(object sender, EventArgs ea) private void HandleAppearanceUpdateTimer(object sender, EventArgs ea)
{ {
long now = DateTime.Now.Ticks; if(Monitor.TryEnter(m_updatesLock))
lock (m_sendqueue)
{ {
Dictionary<UUID, long> sends = new Dictionary<UUID, long>(m_sendqueue); UUID id;
foreach (KeyValuePair<UUID, long> kvp in sends) long now = DateTime.Now.Ticks;
foreach (KeyValuePair<UUID, long> kvp in m_sendqueue)
{ {
// We have to load the key and value into local parameters to avoid a race condition if we loop
// around and load kvp with a different value before FireAndForget has launched its thread.
UUID avatarID = kvp.Key;
long sendTime = kvp.Value; long sendTime = kvp.Value;
if (sendTime > now)
continue;
// m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now); id = kvp.Key;
m_sendqueue.TryRemove(id, out sendTime);
if (sendTime < now) SendAppearance(id);
{
Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance");
m_sendqueue.Remove(avatarID);
}
} }
}
lock (m_savequeue) if(m_updatesbusy == 0)
{
Dictionary<UUID, long> saves = new Dictionary<UUID, long>(m_savequeue);
foreach (KeyValuePair<UUID, long> kvp in saves)
{ {
// We have to load the key and value into local parameters to avoid a race condition if we loop m_updatesbusy = -1;
// around and load kvp with a different value before FireAndForget has launched its thread. List<UUID> saves = new List<UUID>(m_savequeue.Count);
UUID avatarID = kvp.Key; foreach (KeyValuePair<UUID, long> kvp in m_savequeue)
long sendTime = kvp.Value;
if (sendTime < now)
{ {
Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance"); long sendTime = kvp.Value;
m_savequeue.Remove(avatarID); if (sendTime > now)
continue;
id = kvp.Key;
m_savequeue.TryRemove(id, out sendTime);
saves.Add(id);
}
m_updatesbusy = 0;
if (saves.Count > 0)
{
++m_updatesbusy;
WorkManager.RunInThreadPool(
delegate
{
SaveAppearance(saves);
saves = null;
--m_updatesbusy;
}, null, string.Format("SaveAppearance ({0})", m_scene.Name));
} }
} }
// We must lock both queues here so that QueueAppearanceSave() or *Send() don't m_updateTimer.Start() on if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
// another thread inbetween the first count calls and m_updateTimer.Stop() on this thread. m_updateTimer.Stop();
lock (m_sendqueue)
if (m_savequeue.Count == 0 && m_sendqueue.Count == 0) Monitor.Exit(m_updatesLock);
m_updateTimer.Stop();
} }
} }
private void SaveAppearance(UUID agentid) private void SaveAppearance(List<UUID> ids)
{ {
// We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
// in a culture where decimal points are commas and then reloaded in a culture which just treats them as
// number seperators.
Culture.SetCurrentCulture();
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);
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 foreach(UUID id in ids)
// 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 {
// assets and item asset id changes to complete. ScenePresence sp = m_scene.GetScenePresence(id);
// I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids if(sp == null)
// multiple save requests. continue;
SetAppearanceAssets(sp.UUID, sp.Appearance); // 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
// assets and item asset id changes to complete.
// I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
// multiple save requests.
// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); SetAppearanceAssets(id, sp.Appearance);
// foreach (AvatarAttachment att in attachments)
// {
// m_log.DebugFormat(
// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
// sp.Name, att.ItemID, att.AttachPoint);
// }
m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); m_scene.AvatarService.SetAppearance(id, sp.Appearance);
//m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
// Trigger this here because it's the final step in the set/queue/save process for appearance setting. }
// Everything has been updated and stored. Ensures bakes have been persisted (if option is set to persist bakes).
m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
} }
/// <summary> /// <summary>
@ -1231,7 +1170,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId); // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
ScenePresence sp = m_scene.GetScenePresence(client.AgentId); ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
if (sp != null) if (sp != null)
SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems); SetAppearance(sp, textureEntry, visualParams, avSize, cacheItems);
else else
m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId); m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
} }
@ -1251,9 +1190,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
return; return;
} }
// we need to clean out the existing textures
sp.Appearance.ResetAppearance();
// operate on a copy of the appearance so we don't have to lock anything yet // operate on a copy of the appearance so we don't have to lock anything yet
AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false); AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false);
@ -1280,15 +1216,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing
// shouldn't overwrite the changes made in SetAppearance. // shouldn't overwrite the changes made in SetAppearance.
sp.Appearance.Wearables = avatAppearance.Wearables; sp.Appearance.Wearables = avatAppearance.Wearables;
sp.Appearance.Texture = avatAppearance.Texture;
// We don't need to send the appearance here since the "iswearing" will trigger a new set // We don't need to send the appearance here since the "iswearing" will trigger a new set
// of visual param and baked texture changes. When those complete, the new appearance will be sent // of visual param and baked texture changes. When those complete, the new appearance will be sent
QueueAppearanceSave(client.AgentId); QueueAppearanceSave(client.AgentId);
} }
} }
/*
/// <summary> /// <summary>
/// Respond to the cached textures request from the client /// Respond to the cached textures request from the client
/// </summary> /// </summary>
@ -1308,23 +1242,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
if (m_reusetextures) 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]; Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
if (face != null) if (face != null)
texture = face.TextureID; texture = face.TextureID;
// m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
} }
CachedTextureResponseArg response = new CachedTextureResponseArg(); CachedTextureResponseArg response = new CachedTextureResponseArg();
@ -1334,21 +1254,16 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
cachedTextureResponse.Add(response); cachedTextureResponse.Add(response);
} }
// m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
// The serial number appears to be used to match requests and responses
// in the texture transaction. We just send back the serial number
// that was provided in the request. The viewer bumps this for us.
client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
} }
*/
#endregion #endregion
public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
{ {
outputAction("For {0} in {1}", sp.Name, m_scene.RegionInfo.RegionName); outputAction("For {0} in {1}", null, sp.Name, m_scene.RegionInfo.RegionName);
outputAction(BAKED_TEXTURES_REPORT_FORMAT, "Bake Type", "UUID"); outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, "Bake Type", "UUID");
Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID); Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID);
@ -1362,19 +1277,38 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
} }
else else
{ {
rawTextureID = bakedTextures[bt].TextureID.ToString(); if(bakedTextures[bt].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
rawTextureID = "not set";
if (m_scene.AssetService.Get(rawTextureID) == null)
rawTextureID += " (not found)";
else else
rawTextureID += " (uploaded)"; {
rawTextureID = bakedTextures[bt].TextureID.ToString();
if (m_scene.AssetService.Get(rawTextureID) == null)
rawTextureID += " (not found)";
else
rawTextureID += " (uploaded)";
}
} }
outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID); outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID);
} }
bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp); bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); outputAction("{0} baked appearance texture is {1}", null, sp.Name, bakedTextureValid ? "OK" : "incomplete");
}
public void SetPreferencesHoverZ(UUID agentId, float val)
{
ScenePresence sp = m_scene.GetScenePresence(agentId);
if (sp == null || sp.IsDeleted || sp.IsNPC || sp.IsInTransit)
return;
float last = sp.Appearance.AvatarPreferencesHoverZ;
if(val != last)
{
sp.Appearance.AvatarPreferencesHoverZ = val;
//sp.SendAppearanceToAgentNF(sp);
QueueAppearanceSend(agentId);
}
} }
} }
} }

View File

@ -53,6 +53,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]";
private static readonly string OutfitTPError = "destination region does not support the Outfit you are wearing. Please retry with a simpler one";
public const bool WaitForAgentArrivedAtDestinationDefault = true; public const bool WaitForAgentArrivedAtDestinationDefault = true;
@ -720,6 +721,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return; return;
} }
if (!sp.Appearance.CanTeleport(ctx.OutboundVersion))
{
sp.ControllingClient.SendTeleportFailed(OutfitTPError);
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because: {3}",
sp.Name, sp.Scene.Name, finalDestination.RegionName, "incompatible wearable");
return;
}
// Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target // Before this point, teleport 'failure' is due to checkable pre-conditions such as whether the target
// simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these // simulator can be found and is explicitly prepared to allow access. Therefore, we will not count these
// as server attempts. // as server attempts.
@ -1489,6 +1501,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0); m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0);
return false; return false;
} }
if (!agent.Appearance.CanTeleport(ctx.OutboundVersion))
{
reason = OutfitTPError;
m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0);
return false;
}
return true; return true;
} }
@ -1545,7 +1564,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
failureReason = "Access Denied"; failureReason = "Access Denied";
return null; return null;
} }
return neighbourRegion; return neighbourRegion;
} }
@ -1599,9 +1617,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
agent.ControllingClient.SendAlertMessage(failureReason); agent.ControllingClient.SendAlertMessage(failureReason);
return agent; return agent;
} }
if (!agent.Appearance.CanTeleport(ctx.OutboundVersion))
{
if (agent.ControllingClient != null)
agent.ControllingClient.SendAlertMessage(OutfitTPError);
return agent;
}
// agent.IsInTransit = true; // agent.IsInTransit = true;
CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx); CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx);
agent.IsInTransit = false; agent.IsInTransit = false;
return agent; return agent;
@ -2601,7 +2624,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
string reason = String.Empty; string reason = String.Empty;
EntityTransferContext ctx = new EntityTransferContext(); EntityTransferContext ctx = new EntityTransferContext();
bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, ctx, out reason); bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, null, out reason);
if (regionAccepted) if (regionAccepted)
{ {

View File

@ -37,7 +37,7 @@ namespace OpenSim.Region.Framework.Interfaces
{ {
void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems); void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems);
void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems); void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems);
void SetPreferencesHoverZ(UUID agentId, float val);
/// <summary> /// <summary>
/// Send the appearance of an avatar to others in the scene. /// Send the appearance of an avatar to others in the scene.
/// </summary> /// </summary>

View File

@ -4358,16 +4358,7 @@ namespace OpenSim.Region.Framework.Scenes
public void SendAppearanceToAgentNF(ScenePresence avatar) public void SendAppearanceToAgentNF(ScenePresence avatar)
{ {
if(avatar.UUID == UUID) avatar.ControllingClient.SendAppearance(UUID, Appearance.VisualParams, Appearance.Texture.GetBakesBytes(), Appearance.AvatarPreferencesHoverZ);
{
avatar.ControllingClient.SendAppearance(
UUID, Appearance.VisualParams, Appearance.Texture.GetBytes());
}
else
{
avatar.ControllingClient.SendAppearance(
UUID, Appearance.VisualParams, Appearance.Texture.GetBakesBytes());
}
} }
public void SendAnimPackToAgent(ScenePresence p) public void SendAnimPackToAgent(ScenePresence p)

View File

@ -961,7 +961,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
} }
public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) public void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry, float hoverheight)
{ {
} }

View File

@ -413,13 +413,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name); sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name);
AvatarWearable[] wearables = sp.Appearance.Wearables; AvatarWearable[] wearables = sp.Appearance.Wearables;
if(wearables.Count() == 0) if(wearables.Length == 0)
{ {
MainConsole.Instance.Output("avatar has no wearables"); MainConsole.Instance.Output("avatar has no wearables");
return; return;
} }
for (int i = 0; i < wearables.Count(); i++) for (int i = 0; i < wearables.Length; i++)
{ {
AvatarWearable aw = wearables[i]; AvatarWearable aw = wearables[i];
@ -477,8 +477,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
cdt.AddColumn("Type", 10); cdt.AddColumn("Type", 10);
cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize); cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize);
cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize); cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize);
AvatarWearable[] wearables = sp.Appearance.Wearables;
for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) for (int i = 0; i < wearables.Length; i++)
{ {
AvatarWearable aw = sp.Appearance.Wearables[i]; AvatarWearable aw = sp.Appearance.Wearables[i];

View File

@ -664,7 +664,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{ {
} }
public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry, float hover)
{ {
} }

View File

@ -129,7 +129,7 @@ namespace OpenSim.Server.Handlers.AgentPreferences
AgentPrefs data = new AgentPrefs(userID); AgentPrefs data = new AgentPrefs(userID);
data.AccessPrefs = request["AccessPrefs"].ToString(); data.AccessPrefs = request["AccessPrefs"].ToString();
data.HoverHeight = double.Parse(request["HoverHeight"].ToString()); data.HoverHeight = float.Parse(request["HoverHeight"].ToString());
data.Language = request["Language"].ToString(); data.Language = request["Language"].ToString();
data.LanguageIsPublic = bool.Parse(request["LanguageIsPublic"].ToString()); data.LanguageIsPublic = bool.Parse(request["LanguageIsPublic"].ToString());
data.PermEveryone = int.Parse(request["PermEveryone"].ToString()); data.PermEveryone = int.Parse(request["PermEveryone"].ToString());

View File

@ -116,6 +116,8 @@ namespace OpenSim.Services.Connectors.Simulation
try try
{ {
OSDMap args = aCircuit.PackAgentCircuitData(ctx); OSDMap args = aCircuit.PackAgentCircuitData(ctx);
if(ctx == null)
ctx = new EntityTransferContext();
args["context"] = ctx.Pack(); args["context"] = ctx.Pack();
PackData(args, source, aCircuit, destination, flags); PackData(args, source, aCircuit, destination, flags);

View File

@ -45,7 +45,7 @@ namespace OpenSim.Services.Interfaces
if (kvp.ContainsKey("AccessPrefs")) if (kvp.ContainsKey("AccessPrefs"))
AccessPrefs = kvp["AccessPrefs"]; AccessPrefs = kvp["AccessPrefs"];
if (kvp.ContainsKey("HoverHeight")) if (kvp.ContainsKey("HoverHeight"))
HoverHeight = double.Parse(kvp["HoverHeight"]); HoverHeight = float.Parse(kvp["HoverHeight"]);
if (kvp.ContainsKey("Language")) if (kvp.ContainsKey("Language"))
Language = kvp["Language"]; Language = kvp["Language"];
if (kvp.ContainsKey("LanguageIsPublic")) if (kvp.ContainsKey("LanguageIsPublic"))
@ -65,7 +65,7 @@ namespace OpenSim.Services.Interfaces
if (kvp.ContainsKey("AccessPrefs")) if (kvp.ContainsKey("AccessPrefs"))
AccessPrefs = kvp["AccessPrefs"].ToString(); AccessPrefs = kvp["AccessPrefs"].ToString();
if (kvp.ContainsKey("HoverHeight")) if (kvp.ContainsKey("HoverHeight"))
HoverHeight = double.Parse(kvp["HoverHeight"].ToString()); HoverHeight = float.Parse(kvp["HoverHeight"].ToString());
if (kvp.ContainsKey("Language")) if (kvp.ContainsKey("Language"))
Language = kvp["Language"].ToString(); Language = kvp["Language"].ToString();
if (kvp.ContainsKey("LanguageIsPublic")) if (kvp.ContainsKey("LanguageIsPublic"))
@ -95,7 +95,7 @@ namespace OpenSim.Services.Interfaces
public UUID PrincipalID = UUID.Zero; public UUID PrincipalID = UUID.Zero;
public string AccessPrefs = "M"; public string AccessPrefs = "M";
//public int GodLevel; // *TODO: Implement GodLevel (Unused by the viewer, afaict - 6/11/2015) //public int GodLevel; // *TODO: Implement GodLevel (Unused by the viewer, afaict - 6/11/2015)
public double HoverHeight = 0.0; public float HoverHeight = 0.0f;
public string Language = "en-us"; public string Language = "en-us";
public bool LanguageIsPublic = true; public bool LanguageIsPublic = true;
// DefaultObjectPermMasks // DefaultObjectPermMasks

View File

@ -570,7 +570,7 @@ namespace OpenSim.Tests.Common
{ {
} }
public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry) public virtual void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry, float hover)
{ {
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.