diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 0589748577..1829c8d47e 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -1614,12 +1614,12 @@ namespace OpenSim.ApplicationPlugins.RemoteController } // Attachments - Dictionary attachments = avatarAppearance.Attachments; + List attachments = avatarAppearance.GetAttachments(); - foreach (KeyValuePair attachment in attachments) + foreach (AvatarAttachment attachment in attachments) { - int attachpoint = attachment.Value.AttachPoint; - UUID itemID = attachment.Value.ItemID; + int attachpoint = attachment.AttachPoint; + UUID itemID = attachment.ItemID; if (itemID != UUID.Zero) { diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs index 8271d76b44..3f6d4d640b 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestAppearanceServices.cs @@ -27,6 +27,7 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Xml; using OpenMetaverse; using OpenSim.Framework; @@ -765,25 +766,19 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset); FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset); - Hashtable attachments = rdata.userAppearance.GetAttachments(); + Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); - if (attachments != null) + rdata.writer.WriteStartElement("Attachments"); + List attachments = rdata.userAppearance.GetAttachments(); + foreach (AvatarAttachment attach in attachments) { - - Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId); - - rdata.writer.WriteStartElement("Attachments"); - for (int i = 0; i < attachments.Count; i++) - { - Hashtable attachment = attachments[i] as Hashtable; - rdata.writer.WriteStartElement("Attachment"); - rdata.writer.WriteAttributeString("AtPoint", i.ToString()); - rdata.writer.WriteAttributeString("Item", (string) attachment["item"]); - rdata.writer.WriteAttributeString("Asset", (string) attachment["asset"]); - rdata.writer.WriteEndElement(); - } + rdata.writer.WriteStartElement("Attachment"); + rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString()); + rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString()); + rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString()); rdata.writer.WriteEndElement(); } + rdata.writer.WriteEndElement(); Primitive.TextureEntry texture = rdata.userAppearance.Texture; diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index be98380cfd..640a6462e7 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs @@ -206,16 +206,18 @@ namespace OpenSim.Framework args["service_session_id"] = OSD.FromString(ServiceSessionID); args["start_pos"] = OSD.FromString(startpos.ToString()); - args["appearance_serial"] = OSD.FromInteger(Appearance.Serial); args["client_ip"] = OSD.FromString(IPAddress); args["viewer"] = OSD.FromString(Viewer); args["channel"] = OSD.FromString(Channel); args["mac"] = OSD.FromString(Mac); args["id0"] = OSD.FromString(Id0); -/* + // Eventually this code should be deprecated, use full appearance + // packing in packed_appearance if (Appearance != null) { + args["appearance_serial"] = OSD.FromInteger(Appearance.Serial); + //System.Console.WriteLine("XXX Before packing Wearables"); if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0)) { @@ -230,20 +232,19 @@ namespace OpenSim.Framework } //System.Console.WriteLine("XXX Before packing Attachments"); - Dictionary attachments = Appearance.Attachments; + List attachments = Appearance.GetAttachments(); if ((attachments != null) && (attachments.Count > 0)) { OSDArray attachs = new OSDArray(attachments.Count); - foreach (KeyValuePair kvp in attachments) + foreach (AvatarAttachment attach in attachments) { - AvatarAttachment adata = new AvatarAttachment(kvp.Value); - attachs.Add(adata.Pack()); + attachs.Add(attach.Pack()); //System.Console.WriteLine("XXX att.pt=" + kvp.Key + "; itemID=" + kvp.Value[0] + "; assetID=" + kvp.Value[1]); } args["attachments"] = attachs; } } -*/ + if (Appearance != null) { OSDMap appmap = Appearance.Pack(); @@ -339,15 +340,40 @@ namespace OpenSim.Framework try { // Unpack various appearance elements Appearance = new AvatarAppearance(AgentID); - if (args["packed_appearance"] != null) + + // Eventually this code should be deprecated, use full appearance + // packing in packed_appearance + if (args["appearance_serial"] != null) + Appearance.Serial = args["appearance_serial"].AsInteger(); + + if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array) { - if (args["packed_appearance"].Type == OSDType.Map) + OSDArray wears = (OSDArray)(args["wearables"]); + for (int i = 0; i < wears.Count / 2; i++) { - Appearance.Unpack((OSDMap)args["packed_appearance"]); - m_log.WarnFormat("[AGENTCIRCUITDATA] unpacked appearance"); + AvatarWearable awear = new AvatarWearable(wears[i*2].AsUUID(),wears[(i*2)+1].AsUUID()); + Appearance.SetWearable(i,awear); } - else - m_log.WarnFormat("[AGENTCIRCUITDATA] packed_appearance is not a map:\n{0}",args["packed_appearance"].ToString()); + } + + if ((args["attachments"] != null) && (args["attachments"]).Type == OSDType.Array) + { + OSDArray attachs = (OSDArray)(args["attachments"]); + foreach (OSD o in attachs) + { + if (o.Type == OSDType.Map) + { + Appearance.AppendAttachment(new AvatarAttachment((OSDMap)o)); + } + } + } + + if (args.ContainsKey("packed_appearance") && (args["packed_appearance"].Type == OSDType.Map)) + { + Appearance.Unpack((OSDMap)args["packed_appearance"]); +// DEBUG ON + m_log.WarnFormat("[AGENTCIRCUITDATA] unpacked appearance"); +// DEBUG OFF } // DEBUG ON else @@ -358,36 +384,6 @@ namespace OpenSim.Framework m_log.ErrorFormat("[AGENTCIRCUITDATA] failed to unpack appearance; {0}",e.Message); } - -/* - if (args["appearance_serial"] != null) - Appearance.Serial = args["appearance_serial"].AsInteger(); - - if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array) - { - OSDArray wears = (OSDArray)(args["wearables"]); - for (int i = 0; i < wears.Count / 2; i++) - { - Appearance.Wearables[i].ItemID = wears[i*2].AsUUID(); - Appearance.Wearables[i].AssetID = wears[(i*2)+1].AsUUID(); - } - } - - if ((args["attachments"] != null) && (args["attachments"]).Type == OSDType.Array) - { - OSDArray attachs = (OSDArray)(args["attachments"]); - AvatarAttachment[] attachments = new AvatarAttachment[attachs.Count]; - int i = 0; - foreach (OSD o in attachs) - { - if (o.Type == OSDType.Map) - { - attachments[i++] = new AvatarAttachment((OSDMap)o); - } - } - Appearance.SetAttachments(attachments); - } -*/ ServiceURLs = new Dictionary(); if (args.ContainsKey("service_urls") && args["service_urls"] != null && (args["service_urls"]).Type == OSDType.Array) { diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 4738d881ed..a4bb7654e2 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -143,13 +143,14 @@ namespace OpenSim.Framework public readonly static int VISUALPARAM_COUNT = 218; public readonly static int TEXTURE_COUNT = 21; + public readonly static byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; protected UUID m_owner; protected int m_serial = 1; protected byte[] m_visualparams; protected Primitive.TextureEntry m_texture; protected AvatarWearable[] m_wearables; - protected Dictionary m_attachments; + protected Dictionary> m_attachments; protected float m_avatarHeight = 0; protected float m_hipOffset = 0; @@ -183,11 +184,6 @@ namespace OpenSim.Framework set { m_wearables = value; } } - public virtual Dictionary Attachments - { - get { return m_attachments; } - } - public virtual UUID BodyItem { get { return m_wearables[AvatarWearable.BODY].ItemID; } set { m_wearables[AvatarWearable.BODY].ItemID = value; } @@ -336,7 +332,7 @@ namespace OpenSim.Framework // DEBUG ON m_log.WarnFormat("[AVATAR APPEARANCE] create empty appearance for {0}",owner); // DEBUG OFF - m_serial = 0; + m_serial = 1; m_owner = owner; SetDefaultWearables(); @@ -344,7 +340,7 @@ namespace OpenSim.Framework SetDefaultParams(); SetHeight(); - m_attachments = new Dictionary(); + m_attachments = new Dictionary>(); } public AvatarAppearance(UUID avatarID, OSDMap map) @@ -382,7 +378,7 @@ namespace OpenSim.Framework SetHeight(); - m_attachments = new Dictionary(); + m_attachments = new Dictionary>(); } public AvatarAppearance(AvatarAppearance appearance) @@ -392,7 +388,7 @@ namespace OpenSim.Framework // DEBUG OFF if (appearance == null) { - m_serial = 0; + m_serial = 1; m_owner = UUID.Zero; SetDefaultWearables(); @@ -400,7 +396,7 @@ namespace OpenSim.Framework SetDefaultParams(); SetHeight(); - m_attachments = new Dictionary(); + m_attachments = new Dictionary>(); return; } @@ -427,9 +423,10 @@ namespace OpenSim.Framework if (appearance.VisualParams != null) m_visualparams = (byte[])appearance.VisualParams.Clone(); - m_attachments = new Dictionary(); - foreach (KeyValuePair kvp in appearance.Attachments) - m_attachments[kvp.Key] = new AvatarAttachment(kvp.Value); + // Copy the attachment, force append mode since that ensures consistency + m_attachments = new Dictionary>(); + foreach (AvatarAttachment attachment in appearance.GetAttachments()) + AppendAttachment(new AvatarAttachment(attachment)); } protected virtual void SetDefaultWearables() @@ -449,14 +446,8 @@ namespace OpenSim.Framework protected virtual void SetDefaultTexture() { m_texture = new Primitive.TextureEntry(new UUID("C228D1CF-4B5D-4BA8-84F4-899A0796AA97")); - // The initialization of these seems to force a rebake regardless of whether it is needed - // m_textures.CreateFace(0).TextureID = new UUID("00000000-0000-1111-9999-000000000012"); - // m_textures.CreateFace(1).TextureID = Util.BLANK_TEXTURE_UUID; - // m_textures.CreateFace(2).TextureID = Util.BLANK_TEXTURE_UUID; - // m_textures.CreateFace(3).TextureID = new UUID("6522E74D-1660-4E7F-B601-6F48C1659A77"); - // m_textures.CreateFace(4).TextureID = new UUID("7CA39B4C-BD19-4699-AFF7-F93FD03D3E7B"); - // m_textures.CreateFace(5).TextureID = new UUID("00000000-0000-1111-9999-000000000010"); - // m_textures.CreateFace(6).TextureID = new UUID("00000000-0000-1111-9999-000000000011"); + for (uint i = 0; i < TEXTURE_COUNT; i++) + m_texture.CreateFace(i).TextureID = new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE); } /// @@ -473,7 +464,7 @@ namespace OpenSim.Framework // made. We determine if any of the textures actually // changed to know if the appearance should be saved later bool changed = false; - for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) + for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) { Primitive.TextureEntryFace newface = textureEntry.FaceTextures[i]; Primitive.TextureEntryFace oldface = m_texture.FaceTextures[i]; @@ -487,14 +478,14 @@ namespace OpenSim.Framework if (oldface != null && oldface.TextureID == newface.TextureID) continue; } - m_texture.FaceTextures[i] = (newface != null) ? new Primitive.TextureEntryFace(newface) : null; changed = true; // DEBUG ON if (newface != null) - m_log.WarnFormat("[SCENEPRESENCE] index {0}, new texture id {1}",i,newface.TextureID); + m_log.WarnFormat("[AVATAR APPEARANCE] index {0}, new texture id {1}",i,newface.TextureID); // DEBUG OFF } + m_texture = textureEntry; return changed; } @@ -517,8 +508,8 @@ namespace OpenSim.Framework if (visualParams[i] != m_visualparams[i]) { // DEBUG ON - m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}", - i,m_visualparams[i],visualParams[i]); +// m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}", +// i,m_visualparams[i],visualParams[i]); // DEBUG OFF m_visualparams[i] = visualParams[i]; changed = true; @@ -569,6 +560,9 @@ namespace OpenSim.Framework public override String ToString() { String s = ""; + + s += String.Format("Serial: {0}\n",m_serial); + for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++) if (m_texture.FaceTextures[i] != null) s += String.Format("Texture: {0} --> {1}\n",i,m_texture.FaceTextures[i].TextureID); @@ -585,12 +579,41 @@ namespace OpenSim.Framework } // DEBUG OFF - public void SetAttachments(AvatarAttachment[] data) + /// + /// Get a list of the attachments, note that there may be + /// duplicate attachpoints + /// + public List GetAttachments() { - foreach (AvatarAttachment attach in data) - m_attachments[attach.AttachPoint] = new AvatarAttachment(attach); + List alist = new List(); + foreach (KeyValuePair> kvp in m_attachments) + { + foreach (AvatarAttachment attach in kvp.Value) + alist.Add(new AvatarAttachment(attach)); + } + + return alist; + } + + internal void AppendAttachment(AvatarAttachment attach) + { + if (! m_attachments.ContainsKey(attach.AttachPoint)) + m_attachments[attach.AttachPoint] = new List(); + m_attachments[attach.AttachPoint].Add(attach); } + internal void ReplaceAttachment(AvatarAttachment attach) + { + m_attachments[attach.AttachPoint] = new List(); + m_attachments[attach.AttachPoint].Add(attach); + } + + /// + /// Add an attachment, if the attachpoint has the + /// 0x80 bit set then we assume this is an append + /// operation otherwise we replace whatever is + /// currently attached at the attachpoint + /// public void SetAttachment(int attachpoint, UUID item, UUID asset) { if (attachpoint == 0) @@ -603,67 +626,47 @@ namespace OpenSim.Framework return; } - m_attachments[attachpoint] = new AvatarAttachment(attachpoint,item,asset); - } - - public Hashtable GetAttachments() - { - if (m_attachments.Count == 0) - return null; - - Hashtable ret = new Hashtable(); - - foreach (KeyValuePair kvp in m_attachments) + // check if this is an append or a replace, 0x80 marks it as an append + if ((attachpoint & 0x80) > 0) { - Hashtable data = new Hashtable(); - data["item"] = kvp.Value.ItemID.ToString(); - data["asset"] = kvp.Value.AssetID.ToString(); - - ret[kvp.Key] = data; + // strip the append bit + int point = attachpoint & 0x7F; + AppendAttachment(new AvatarAttachment(point, item, asset)); + } + else + { + ReplaceAttachment(new AvatarAttachment(attachpoint,item,asset)); } - - return ret; - } - - public List GetAttachedPoints() - { - return new List(m_attachments.Keys); - } - - public UUID GetAttachedItem(int attachpoint) - { - if (!m_attachments.ContainsKey(attachpoint)) - return UUID.Zero; - - return m_attachments[attachpoint].ItemID; - } - - public UUID GetAttachedAsset(int attachpoint) - { - if (!m_attachments.ContainsKey(attachpoint)) - return UUID.Zero; - - return m_attachments[attachpoint].AssetID; } public int GetAttachpoint(UUID itemID) { - foreach (KeyValuePair kvp in m_attachments) + foreach (KeyValuePair> kvp in m_attachments) { - if (kvp.Value.ItemID == itemID) - { + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) return kvp.Key; - } } + return 0; } public void DetachAttachment(UUID itemID) { - int attachpoint = GetAttachpoint(itemID); + foreach (KeyValuePair> kvp in m_attachments) + { + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) + { + // Remove it from the list of attachments at that attach point + m_attachments[kvp.Key].RemoveAt(index); - if (attachpoint > 0) - m_attachments.Remove(attachpoint); + // And remove the list if there are no more attachments here + if (m_attachments[kvp.Key].Count == 0) + m_attachments.Remove(kvp.Key); + return; + } + } } public void ClearAttachments() @@ -671,6 +674,8 @@ namespace OpenSim.Framework m_attachments.Clear(); } + #region Packing Functions + /// /// Create an OSDMap from the appearance data /// @@ -695,7 +700,7 @@ namespace OpenSim.Framework if (m_texture.FaceTextures[i] != null) textures.Add(OSD.FromUUID(m_texture.FaceTextures[i].TextureID)); else - textures.Add(OSD.FromUUID(UUID.Zero)); + textures.Add(OSD.FromUUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); } data["textures"] = textures; @@ -705,8 +710,8 @@ namespace OpenSim.Framework // Attachments OSDArray attachs = new OSDArray(m_attachments.Count); - foreach (KeyValuePair kvp in m_attachments) - attachs.Add(kvp.Value.Pack()); + foreach (AvatarAttachment attach in GetAttachments()) + attachs.Add(attach.Pack()); data["attachments"] = attachs; return data; @@ -718,8 +723,8 @@ namespace OpenSim.Framework /// public void Unpack(OSDMap data) { - if ((data != null) && (data["appearance_serial"] != null)) - m_serial = data["appearance_serial"].AsInteger(); + if ((data != null) && (data["serial"] != null)) + m_serial = data["serial"].AsInteger(); if ((data != null) && (data["height"] != null)) m_avatarHeight = (float)data["height"].AsReal(); if ((data != null) && (data["hipoffset"] != null)) @@ -747,12 +752,10 @@ namespace OpenSim.Framework OSDArray textures = (OSDArray)(data["textures"]); for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT && i < textures.Count; i++) { + UUID textureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE; if (textures[i] != null) - { - UUID textureID = textures[i].AsUUID(); - if (textureID != UUID.Zero) - m_texture.CreateFace((uint)i).TextureID = textureID; - } + textureID = textures[i].AsUUID(); + m_texture.CreateFace((uint)i).TextureID = new UUID(textureID); } } else @@ -773,15 +776,12 @@ namespace OpenSim.Framework } // Attachments - m_attachments = new Dictionary(); + m_attachments = new Dictionary>(); if ((data != null) && (data["attachments"] != null) && (data["attachments"]).Type == OSDType.Array) { OSDArray attachs = (OSDArray)(data["attachments"]); for (int i = 0; i < attachs.Count; i++) - { - AvatarAttachment attach = new AvatarAttachment((OSDMap)attachs[i]); - m_attachments[attach.AttachPoint] = attach; - } + AppendAttachment(new AvatarAttachment((OSDMap)attachs[i])); } } catch (Exception e) @@ -790,6 +790,9 @@ namespace OpenSim.Framework } } + #endregion + + #region VPElement /// /// Viewer Params Array Element for AgentSetAppearance @@ -1553,5 +1556,6 @@ namespace OpenSim.Framework SKIRT_SKIRT_GREEN = 216, SKIRT_SKIRT_BLUE = 217 } + #endregion } } diff --git a/OpenSim/Framework/Capabilities/Caps.cs b/OpenSim/Framework/Capabilities/Caps.cs index 6b64e120db..872de9a082 100644 --- a/OpenSim/Framework/Capabilities/Caps.cs +++ b/OpenSim/Framework/Capabilities/Caps.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; using log4net; +using Nini.Config; using OpenMetaverse; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; @@ -112,6 +113,8 @@ namespace OpenSim.Framework.Capabilities private string m_regionName; private object m_fetchLock = new Object(); + private bool m_persistBakedTextures = false; + public bool SSLCaps { get { return m_httpListener.UseSSL; } @@ -145,6 +148,15 @@ namespace OpenSim.Framework.Capabilities m_httpListenPort = httpPort; + m_persistBakedTextures = false; + IConfigSource config = m_Scene.Config; + if (config != null) + { + IConfig sconfig = config.Configs["Startup"]; + if (sconfig != null) + m_persistBakedTextures = sconfig.GetBoolean("PersistBakedTextures",m_persistBakedTextures); + } + if (httpServer != null && httpServer.UseSSL) { m_httpListenPort = httpServer.SSLPort; @@ -983,7 +995,7 @@ namespace OpenSim.Framework.Capabilities asset = new AssetBase(assetID, "Baked Texture", (sbyte)AssetType.Texture, m_agentID.ToString()); asset.Data = data; asset.Temporary = true; - asset.Local = true; + asset.Local = ! m_persistBakedTextures; // Local assets aren't persisted, non-local are m_assetCache.Store(asset); } diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index fdebba3d2e..66487f72e0 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -28,6 +28,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Reflection; +using log4net; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -310,6 +312,12 @@ namespace OpenSim.Framework // Appearance public AvatarAppearance Appearance; +// DEBUG ON + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); +// DEBUG OFF + /* public byte[] AgentTextures; public byte[] VisualParams; @@ -323,6 +331,10 @@ namespace OpenSim.Framework public virtual OSDMap Pack() { +// DEBUG ON + m_log.WarnFormat("[CHILDAGENTDATAUPDATE] Pack data"); +// DEBUG OFF + OSDMap args = new OSDMap(); args["message_type"] = OSD.FromString("AgentData"); @@ -387,31 +399,40 @@ namespace OpenSim.Framework // args["agent_textures"] = textures; //} -/* - if ((AgentTextures != null) && (AgentTextures.Length > 0)) - args["texture_entry"] = OSD.FromBinary(AgentTextures); + // The code to pack textures, visuals, wearables and attachments + // should be removed; packed appearance contains the full appearance + // This is retained for backward compatibility only + if (Appearance.Texture != null) + { + byte[] rawtextures = Appearance.Texture.GetBytes(); + args["texture_entry"] = OSD.FromBinary(rawtextures); + } - if ((VisualParams != null) && (VisualParams.Length > 0)) - args["visual_params"] = OSD.FromBinary(VisualParams); + if ((Appearance.VisualParams != null) && (Appearance.VisualParams.Length > 0)) + args["visual_params"] = OSD.FromBinary(Appearance.VisualParams); // We might not pass this in all cases... - if ((Wearables != null) && (Wearables.Length > 0)) + if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0)) { - OSDArray wears = new OSDArray(Wearables.Length); - foreach (UUID uuid in Wearables) - wears.Add(OSD.FromUUID(uuid)); + OSDArray wears = new OSDArray(Appearance.Wearables.Length * 2); + foreach (AvatarWearable awear in Appearance.Wearables) + { + wears.Add(OSD.FromUUID(awear.ItemID)); + wears.Add(OSD.FromUUID(awear.AssetID)); + } args["wearables"] = wears; } - - if ((Attachments != null) && (Attachments.Length > 0)) + List attachments = Appearance.GetAttachments(); + if ((attachments != null) && (attachments.Count > 0)) { - OSDArray attachs = new OSDArray(Attachments.Length); - foreach (AvatarAttachment att in Attachments) + OSDArray attachs = new OSDArray(attachments.Count); + foreach (AvatarAttachment att in attachments) attachs.Add(att.Pack()); args["attachments"] = attachs; } -*/ + // End of code to remove + if ((Controllers != null) && (Controllers.Length > 0)) { OSDArray controls = new OSDArray(Controllers.Length); @@ -435,6 +456,10 @@ namespace OpenSim.Framework /// public virtual void Unpack(OSDMap args) { +// DEBUG ON + m_log.WarnFormat("[CHILDAGENTDATAUPDATE] Unpack data"); +// DEBUG OFF + if (args.ContainsKey("region_id")) UUID.TryParse(args["region_id"].AsString(), out RegionID); @@ -547,41 +572,54 @@ namespace OpenSim.Framework // AgentTextures[i++] = o.AsUUID(); //} - if (args["packed_appearance"] != null) - Appearance = new AvatarAppearance(AgentID,(OSDMap)args["packed_appearance"]); - else - Appearance = new AvatarAppearance(AgentID); - -/* + Appearance = new AvatarAppearance(AgentID); + + // The code to unpack textures, visuals, wearables and attachments + // should be removed; packed appearance contains the full appearance + // This is retained for backward compatibility only if (args["texture_entry"] != null) - AgentTextures = args["texture_entry"].AsBinary(); + { + byte[] rawtextures = args["texture_entry"].AsBinary(); + Primitive.TextureEntry textures = new Primitive.TextureEntry(rawtextures,0,rawtextures.Length); + Appearance.SetTextureEntries(textures); + } if (args["visual_params"] != null) - VisualParams = args["visual_params"].AsBinary(); + Appearance.SetVisualParams(args["visual_params"].AsBinary()); if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array) { OSDArray wears = (OSDArray)(args["wearables"]); - Wearables = new UUID[wears.Count]; - int i = 0; - foreach (OSD o in wears) - Wearables[i++] = o.AsUUID(); + for (int i = 0; i < wears.Count / 2; i++) + { + AvatarWearable awear = new AvatarWearable(wears[i*2].AsUUID(),wears[(i*2)+1].AsUUID()); + Appearance.SetWearable(i,awear); + } } if ((args["attachments"] != null) && (args["attachments"]).Type == OSDType.Array) { OSDArray attachs = (OSDArray)(args["attachments"]); - Attachments = new AvatarAttachment[attachs.Count]; - int i = 0; foreach (OSD o in attachs) { if (o.Type == OSDType.Map) { - Attachments[i++] = new AvatarAttachment((OSDMap)o); + // We know all of these must end up as attachments so we + // append rather than replace to ensure multiple attachments + // per point continues to work + Appearance.AppendAttachment(new AvatarAttachment((OSDMap)o)); } } } -*/ + // end of code to remove + + if (args.ContainsKey("packed_appearance") && (args["packed_appearance"]).Type == OSDType.Map) + Appearance = new AvatarAppearance(AgentID,(OSDMap)args["packed_appearance"]); +// DEBUG ON + else + m_log.WarnFormat("[CHILDAGENTDATAUPDATE] No packed appearance"); +// DEBUG OFF + if ((args["controllers"] != null) && (args["controllers"]).Type == OSDType.Array) { OSDArray controls = (OSDArray)(args["controllers"]); diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index ad6b1deba4..e89368a4b6 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -123,15 +123,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); // Save avatar attachment information - ScenePresence presence; - if (m_scene.AvatarService != null && m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) - { - m_log.Info( - "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId - + ", AttachmentPoint: " + AttachmentPt); + m_log.Info( + "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + + ", AttachmentPoint: " + AttachmentPt); - m_scene.AvatarService.SetAppearance(remoteClient.AgentId, presence.Appearance); - } + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } } catch (Exception e) @@ -382,8 +379,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments item = m_scene.InventoryService.GetItem(item); presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */); - if (m_scene.AvatarService != null) - m_scene.AvatarService.SetAppearance(remoteClient.AgentId, presence.Appearance); + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } } @@ -405,11 +402,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments presence.Appearance.DetachAttachment(itemID); // Save avatar attachment information - if (m_scene.AvatarService != null) - { - m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); - m_scene.AvatarService.SetAppearance(remoteClient.AgentId, presence.Appearance); - } + m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } DetachSingleAttachmentToInv(itemID, remoteClient); @@ -435,10 +430,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments presence.Appearance.DetachAttachment(itemID); - if (m_scene.AvatarService != null) - { - m_scene.AvatarService.SetAppearance(remoteClient.AgentId, presence.Appearance); - } + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); + part.ParentGroup.DetachToGround(); List uuids = new List(); diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 9f7ff7f5a0..bfbbcf84f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -32,23 +32,45 @@ using Nini.Config; using OpenMetaverse; using OpenSim.Framework; +using System.Threading; +using System.Timers; +using System.Collections.Generic; + using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory { - public class AvatarFactoryModule : IRegionModule + public class AvatarFactoryModule : IAvatarFactory, IRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly byte[] BAKE_INDICES = new byte[] { 8, 9, 10, 11, 19, 20 }; private Scene m_scene = null; - private bool m_startAnimationSet = false; + private int m_savetime = 5; // seconds to wait before saving changed appearance + private int m_sendtime = 2; // seconds to wait before sending changed appearance - public void Initialise(Scene scene, IConfigSource source) + private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates + private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); + private Dictionary m_savequeue = new Dictionary(); + private Dictionary m_sendqueue = new Dictionary(); + + #region RegionModule Members + + public void Initialise(Scene scene, IConfigSource config) { + scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += NewClient; + + if (config != null) + { + IConfig sconfig = config.Configs["Startup"]; + if (sconfig != null) + { + m_savetime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); + m_sendtime = Convert.ToInt32(sconfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); + } + } if (m_scene == null) m_scene = scene; @@ -56,6 +78,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory public void PostInitialise() { + m_updateTimer.Enabled = false; + m_updateTimer.AutoReset = true; + m_updateTimer.Interval = m_checkTime; // 500 milliseconds wait to start async ops + m_updateTimer.Elapsed += new ElapsedEventHandler(HandleAppearanceUpdateTimer); } public void Close() @@ -84,6 +110,36 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // client.OnAvatarNowWearing -= AvatarIsWearing; } + #endregion + + public bool ValidateBakedTextureCache(IClientAPI client) + { + ScenePresence sp = m_scene.GetScenePresence(client.AgentId); + if (sp == null) + { + m_log.WarnFormat("[AVFACTORY] SetAppearance unable to find presence for {0}",client.AgentId); + return false; + } + + bool cached = true; + + // Process the texture entry + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) + { + int idx = AvatarAppearance.BAKE_INDICES[i]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) + if (! CheckBakedTextureAsset(client,face.TextureID,idx)) + { + sp.Appearance.Texture.FaceTextures[idx] = null; + cached = false; + } + } + + return cached; + } + + /// /// Set appearance data (textureentry and slider settings) received from the client /// @@ -91,6 +147,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) { +// DEBUG ON + m_log.WarnFormat("[AVFACTORY] SetAppearance for {0}",client.AgentId); +// DEBUG OFF + ScenePresence sp = m_scene.GetScenePresence(client.AgentId); if (sp == null) { @@ -98,85 +158,179 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return; } -// DEBUG ON - m_log.WarnFormat("[AVFACTORY] SetAppearance for {0}",client.AgentId); -// DEBUG OFF - -/* - if (m_physicsActor != null) - { - if (!IsChildAgent) - { - // This may seem like it's redundant, remove the avatar from the physics scene - // just to add it back again, but it saves us from having to update - // 3 variables 10 times a second. - bool flyingTemp = m_physicsActor.Flying; - RemoveFromPhysicalScene(); - //m_scene.PhysicsScene.RemoveAvatar(m_physicsActor); - - //PhysicsActor = null; - - AddToPhysicalScene(flyingTemp); - } - } -*/ - #region Bake Cache Check - bool changed = false; // Process the texture entry if (textureEntry != null) { - for (int i = 0; i < BAKE_INDICES.Length; i++) - { - int j = BAKE_INDICES[i]; - Primitive.TextureEntryFace face = textureEntry.FaceTextures[j]; - - if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) - { - if (m_scene.AssetService.Get(face.TextureID.ToString()) == null) - { - m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}",face.TextureID,j,this.Name); - client.SendRebakeAvatarTextures(face.TextureID); - } - } - } changed = sp.Appearance.SetTextureEntries(textureEntry); - + + for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++) + { + int idx = AvatarAppearance.BAKE_INDICES[i]; + Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx]; + if (face != null && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE) + Util.FireAndForget(delegate(object o) { + if (! CheckBakedTextureAsset(client,face.TextureID,idx)) + client.SendRebakeAvatarTextures(face.TextureID); + }); + } } - #endregion Bake Cache Check - - changed = sp.Appearance.SetVisualParams(visualParams) || changed; - - // If nothing changed (this happens frequently) just return - if (changed) + // Process the visual params, this may change height as well + if (visualParams != null) { -// DEBUG ON - m_log.Warn("[AVFACTORY] Appearance changed"); -// DEBUG OFF - sp.Appearance.SetAppearance(textureEntry, visualParams); - if (sp.Appearance.AvatarHeight > 0) - sp.SetHeight(sp.Appearance.AvatarHeight); - - m_scene.AvatarService.SetAppearance(client.AgentId, sp.Appearance); + if (sp.Appearance.SetVisualParams(visualParams)) + { + changed = true; + if (sp.Appearance.AvatarHeight > 0) + sp.SetHeight(sp.Appearance.AvatarHeight); + } } -// DEBUG ON - else - m_log.Warn("[AVFACTORY] Appearance did not change"); -// DEBUG OFF + + // If something changed in the appearance then queue an appearance save + if (changed) + QueueAppearanceSave(client.AgentId); + // And always queue up an appearance update to send out + QueueAppearanceSend(client.AgentId); + + // Send the appearance back to the avatar + // AvatarAppearance avp = sp.Appearance; + // sp.ControllingClient.SendAvatarDataImmediate(sp); + // sp.ControllingClient.SendAppearance(avp.Owner,avp.VisualParams,avp.Texture.GetBytes()); + } + + /// + /// Checks for the existance of a baked texture asset and + /// requests the viewer rebake if the asset is not found + /// + /// + /// + /// + private bool CheckBakedTextureAsset(IClientAPI client, UUID textureID, int idx) + { + if (m_scene.AssetService.Get(textureID.ToString()) == null) + { + m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}", + textureID,idx,client.Name); + return false; + } + return true; + } + + #region UpdateAppearanceTimer + + public void QueueAppearanceSend(UUID agentid) + { +// DEBUG ON + m_log.WarnFormat("[AVFACTORY] Queue appearance send for {0}",agentid); +// DEBUG OFF + + // 100 nanoseconds (ticks) we should wait + long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 10000000); + lock (m_sendqueue) + { + m_sendqueue[agentid] = timestamp; + m_updateTimer.Start(); + } + } + + public void QueueAppearanceSave(UUID agentid) + { +// DEBUG ON + m_log.WarnFormat("[AVFACTORY] Queue appearance save for {0}",agentid); +// DEBUG OFF + + // 100 nanoseconds (ticks) we should wait + long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 10000000); + lock (m_savequeue) + { + m_savequeue[agentid] = timestamp; + m_updateTimer.Start(); + } + } + + private void HandleAppearanceSend(UUID agentid) + { + ScenePresence sp = m_scene.GetScenePresence(agentid); + if (sp == null) + { + m_log.WarnFormat("[AVFACTORY] Agent {0} no longer in the scene",agentid); + return; + } + +// DEBUG ON + m_log.WarnFormat("[AVFACTORY] Handle appearance send for {0}",agentid); +// DEBUG OFF + + // Send the appearance to everyone in the scene sp.SendAppearanceToAllOtherAgents(); + sp.ControllingClient.SendAvatarDataImmediate(sp); + + // Send the appearance back to the avatar + // AvatarAppearance avp = sp.Appearance; + // sp.ControllingClient.SendAppearance(avp.Owner,avp.VisualParams,avp.Texture.GetBytes()); + +/* +// this needs to be fixed, the flag should be on scene presence not the region module + // Start the animations if necessary if (!m_startAnimationSet) { sp.Animator.UpdateMovementAnimations(); m_startAnimationSet = true; } - - client.SendAvatarDataImmediate(sp); - client.SendAppearance(sp.Appearance.Owner,sp.Appearance.VisualParams,sp.Appearance.Texture.GetBytes()); +*/ } + private void HandleAppearanceSave(UUID agentid) + { + ScenePresence sp = m_scene.GetScenePresence(agentid); + if (sp == null) + { + m_log.WarnFormat("[AVFACTORY] Agent {0} no longer in the scene",agentid); + return; + } + + m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); + } + + private void HandleAppearanceUpdateTimer(object sender, EventArgs ea) + { + long now = DateTime.Now.Ticks; + + lock (m_sendqueue) + { + Dictionary sends = new Dictionary(m_sendqueue); + foreach (KeyValuePair kvp in sends) + { + if (kvp.Value < now) + { + Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); }); + m_sendqueue.Remove(kvp.Key); + } + } + } + + lock (m_savequeue) + { + Dictionary saves = new Dictionary(m_savequeue); + foreach (KeyValuePair kvp in saves) + { + if (kvp.Value < now) + { + Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); }); + m_savequeue.Remove(kvp.Key); + } + } + } + + if (m_savequeue.Count == 0 && m_sendqueue.Count == 0) + m_updateTimer.Stop(); + } + + #endregion + /// /// Tell the client for this scene presence what items it should be wearing now /// @@ -215,14 +369,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance); - //if (!TryGetAvatarAppearance(client.AgentId, out avatAppearance)) - //{ - // m_log.Warn("[AVFACTORY]: We didn't seem to find the appearance, falling back to ScenePresence"); - // avatAppearance = sp.Appearance; - //} - - //m_log.DebugFormat("[AVFACTORY]: Received wearables for {0}", client.Name); - foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) { if (wear.Type < AvatarWearable.MAX_WEARABLES) @@ -232,10 +378,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory } } + // This could take awhile since it needs to pull inventory SetAppearanceAssets(sp.UUID, ref avatAppearance); - m_scene.AvatarService.SetAppearance(client.AgentId, avatAppearance); sp.Appearance = avatAppearance; + m_scene.AvatarService.SetAppearance(client.AgentId, sp.Appearance); } private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) diff --git a/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs new file mode 100644 index 0000000000..22795fc97d --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IAvatarFactory.cs @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using OpenMetaverse; +using OpenSim.Framework; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IAvatarFactory + { + bool ValidateBakedTextureCache(IClientAPI client); + void QueueAppearanceSend(UUID agentid); + void QueueAppearanceSave(UUID agentid); + } +} diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 6367fcf641..3343d081ab 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -119,6 +119,7 @@ namespace OpenSim.Region.Framework.Scenes protected IXMLRPC m_xmlrpcModule; protected IWorldComm m_worldCommModule; + protected IAvatarFactory m_AvatarFactory; protected IConfigSource m_config; protected IRegionSerialiserModule m_serialiser; protected IDialogModule m_dialogModule; @@ -398,6 +399,11 @@ namespace OpenSim.Region.Framework.Scenes public IAttachmentsModule AttachmentsModule { get; set; } + public IAvatarFactory AvatarFactory + { + get { return m_AvatarFactory; } + } + public ICapabilitiesModule CapsModule { get { return m_capsModule; } @@ -1153,6 +1159,7 @@ namespace OpenSim.Region.Framework.Scenes m_xmlrpcModule = RequestModuleInterface(); m_worldCommModule = RequestModuleInterface(); XferManager = RequestModuleInterface(); + m_AvatarFactory = RequestModuleInterface(); AttachmentsModule = RequestModuleInterface(); m_serialiser = RequestModuleInterface(); m_dialogModule = RequestModuleInterface(); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 6576e6415d..9402f8bc5f 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -704,20 +704,14 @@ namespace OpenSim.Region.Framework.Scenes // we created a new ScenePresence (a new child agent) in a fresh region. // Request info about all the (root) agents in this region // Note: This won't send data *to* other clients in that region (children don't send) + +// MIC: This gets called again in CompleteMovement SendInitialFullUpdateToAllClients(); RegisterToEvents(); SetDirectionVectors(); } -/* - public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, byte[] visualParams, - AvatarWearable[] wearables) - : this(client, world, reginfo) - { - m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams); - } -*/ public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance) : this(client, world, reginfo) { @@ -1081,7 +1075,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void CompleteMovement(IClientAPI client) { - //m_log.Debug("[SCENE PRESENCE]: CompleteMovement"); +// DEBUG ON + m_log.WarnFormat("[SCENE PRESENCE]: CompleteMovement for {0}",UUID); +// DEBUG OFF Vector3 look = Velocity; if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) @@ -2381,12 +2377,20 @@ namespace OpenSim.Region.Framework.Scenes // 2 stage check is needed. if (remoteAvatar == null) return; + IClientAPI cl=remoteAvatar.ControllingClient; if (cl == null) return; + if (m_appearance.Texture == null) return; + if (LocalId == remoteAvatar.LocalId) + { + m_log.WarnFormat("[SP] An agent is attempting to send data to itself; {0}",UUID); + return; + } + if (IsChildAgent) { m_log.WarnFormat("[SCENEPRESENCE] A child agent is attempting to send out avatar data"); @@ -2407,20 +2411,23 @@ namespace OpenSim.Region.Framework.Scenes m_scene.ForEachScenePresence(delegate(ScenePresence avatar) { ++avUpdates; - // only send if this is the root (children are only "listening posts" in a foreign region) + + // Don't update ourselves + if (avatar.LocalId == LocalId) + return; + + // If this is a root agent, then get info about the avatar if (!IsChildAgent) { SendFullUpdateToOtherClient(avatar); } - if (avatar.LocalId != LocalId) + // If the other avatar is a root + if (!avatar.IsChildAgent) { - if (!avatar.IsChildAgent) - { - avatar.SendFullUpdateToOtherClient(this); - avatar.SendAppearanceToOtherAgent(this); - avatar.Animator.SendAnimPackToClient(ControllingClient); - } + avatar.SendFullUpdateToOtherClient(this); + avatar.SendAppearanceToOtherAgent(this); + avatar.Animator.SendAnimPackToClient(ControllingClient); } }); @@ -2465,7 +2472,19 @@ namespace OpenSim.Region.Framework.Scenes // m_scene.GetAvatarAppearance(m_controllingClient, out m_appearance); m_controllingClient.SendAvatarDataImmediate(this); - m_controllingClient.SendAppearance(m_appearance.Owner,m_appearance.VisualParams,m_appearance.Texture.GetBytes()); + if (m_scene.AvatarFactory != null) + { + if (m_scene.AvatarFactory.ValidateBakedTextureCache(m_controllingClient)) + { + m_log.WarnFormat("[SP] baked textures are in the ache for {0}",Name); + m_controllingClient.SendAppearance( + m_appearance.Owner,m_appearance.VisualParams,m_appearance.Texture.GetBytes()); + } + } + else + { + m_log.WarnFormat("[SP] AvatarFactory not set"); + } SendInitialFullUpdateToAllClients(); } @@ -2497,9 +2516,16 @@ namespace OpenSim.Region.Framework.Scenes /// public void SendAppearanceToOtherAgent(ScenePresence avatar) { + if (LocalId == avatar.LocalId) + { + m_log.WarnFormat("[SP] An agent is attempting to send data to itself; {0}",UUID); + return; + } + // DEBUG ON - m_log.WarnFormat("[SP] Send appearance from {0} to {1}",m_uuid,avatar.ControllingClient.AgentId); +// m_log.WarnFormat("[SP] Send appearance from {0} to {1}",m_uuid,avatar.ControllingClient.AgentId); // DEBUG OFF + avatar.ControllingClient.SendAppearance( m_appearance.Owner, m_appearance.VisualParams, m_appearance.Texture.GetBytes()); } @@ -3656,15 +3682,16 @@ namespace OpenSim.Region.Framework.Scenes return; } - List attPoints = m_appearance.GetAttachedPoints(); - foreach (int p in attPoints) + List attachments = m_appearance.GetAttachments(); + foreach (AvatarAttachment attach in attachments) { if (m_isDeleted) return; - UUID itemID = m_appearance.GetAttachedItem(p); + int p = attach.AttachPoint; + UUID itemID = attach.ItemID; - //UUID assetID = m_appearance.GetAttachedAsset(p); + //UUID assetID = attach.AssetID; // For some reason assetIDs are being written as Zero's in the DB -- need to track tat down // But they're not used anyway, the item is being looked up for now, so let's proceed. //if (UUID.Zero == assetID) diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs index 0786bd9821..922eaafeda 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs @@ -29,6 +29,7 @@ using System.Collections; using System.Collections.Generic; using System.Security; using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; @@ -81,16 +82,12 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule get { List attachments = new List(); - Hashtable internalAttachments = GetSP().Appearance.GetAttachments(); - if (internalAttachments != null) + List internalAttachments = GetSP().Appearance.GetAttachments(); + foreach (AvatarAttachment attach in internalAttachments) { - foreach (DictionaryEntry element in internalAttachments) - { - Hashtable attachInfo = (Hashtable)element.Value; - attachments.Add(new SPAvatarAttachment(m_rootScene, this, (int) element.Key, - new UUID((string) attachInfo["item"]), - new UUID((string) attachInfo["asset"]), m_security)); - } + attachments.Add(new SPAvatarAttachment(m_rootScene, this, attach.AttachPoint, + new UUID(attach.ItemID), + new UUID(attach.AssetID), m_security)); } return attachments.ToArray(); diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs index 93b977b534..eaa653439e 100644 --- a/OpenSim/Services/Interfaces/IAvatarService.cs +++ b/OpenSim/Services/Interfaces/IAvatarService.cs @@ -178,17 +178,11 @@ namespace OpenSim.Services.Interfaces Data["UnderShirtAsset"] = appearance.UnderShirtAsset.ToString(); // Attachments - Hashtable attachs = appearance.GetAttachments(); - if (attachs != null) - foreach (DictionaryEntry dentry in attachs) - { - if (dentry.Value != null) - { - Hashtable tab = (Hashtable)dentry.Value; - if (tab.ContainsKey("item") && tab["item"] != null) - Data["_ap_" + dentry.Key] = tab["item"].ToString(); - } - } + List attachments = appearance.GetAttachments(); + foreach (AvatarAttachment attach in attachments) + { + Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); + } } public AvatarAppearance ToAvatarAppearance(UUID owner) diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 82267edcc9..5ced7d586a 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -255,6 +255,20 @@ ; OpenJPEG if false ; UseCSJ2K = true + ; Persist avatar baked textures + ; Persisting baked textures can speed up login and region border + ; crossings especially with large numbers of users, though it + ; will store potentially large numbers of textures in your asset + ; database + PersistBakedTextures = false + + ; Control the delay before appearance is sent to other avatars and + ; saved in the avatar service. Attempts to limit the impact caused + ; by the very chatty dialog that sets appearance when an avatar + ; logs in or teleports into a region; values are in seconds + DelayBeforeAppearanceSave = 5 + DelayBeforeAppearanceSend = 2 + [SMTP] enabled=false