/// <summary>
        /// Set appearance data (textureentry and slider settings) received from the client
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="visualParam"></param>
        public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCache[] wearables)
        {
            IScenePresence sp = m_scene.GetScenePresence (client.AgentId);
            IAvatarAppearanceModule appearance = sp.RequestModuleInterface<IAvatarAppearanceModule> ();
            if (sp == null)
            {
                m_log.WarnFormat("[AvatarFactory]: SetAppearance unable to find presence for {0}", client.AgentId);
                return;
            }

            //m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId);

            // Process the texture entry transactionally, this doesn't guarantee that Appearance is
            // going to be handled correctly but it does serialize the updates to the appearance
            lock (m_setAppearanceLock)
            {
                bool texturesChanged = false;
                bool visualParamsChanged = false;

                if (textureEntry != null)
                {
                    List<UUID> ChangedTextures = new List<UUID>();
                    texturesChanged = appearance.Appearance.SetTextureEntries (textureEntry, out ChangedTextures);

                    // m_log.WarnFormat("[AVFACTORY]: Prepare to check textures for {0}",client.AgentId);

                    //Do this async as it accesses the asset service (could be remote) multiple times
                    Util.FireAndForget(delegate(object o) 
                    {
                        //Validate all the textures now that we've updated
                        ValidateBakedTextureCache(client, false);
                        //The client wants us to cache the baked textures
                        CacheWearableData(sp, textureEntry, wearables); 
                    });

                    // m_log.WarnFormat("[AVFACTORY]: Complete texture check for {0}",client.AgentId);
                }
                // Process the visual params, this may change height as well
                if (visualParams != null)
                {
                    //Now update the visual params and see if they have changed
                    visualParamsChanged = appearance.Appearance.SetVisualParams (visualParams);

                    //Fix the height only if the parameters have changed
                    if (visualParamsChanged && appearance.Appearance.AvatarHeight > 0)
                        sp.SetHeight (appearance.Appearance.AvatarHeight);
                }

                // Process the baked texture array
                if (textureEntry != null)
                {
                    //Check for banned clients here
                    Aurora.Framework.IBanViewersModule module = client.Scene.RequestModuleInterface<Aurora.Framework.IBanViewersModule>();
                    if (module != null)
                        module.CheckForBannedViewer(client, textureEntry);
                }

                // If something changed in the appearance then queue an appearance save
                if(texturesChanged || visualParamsChanged)
                {
                    if(texturesChanged)
                        QueueTexturesAppearanceSave(client.AgentId);
                    else
                        QueueAppearanceSave(client.AgentId);
                }
                appearance.Appearance.Serial++;
            }
            // And always queue up an appearance update to send out
            QueueAppearanceSend(client.AgentId);

            // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
        }
        /// <summary>
        /// Tell the Avatar Service about these baked textures and items
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="textureEntry"></param>
        /// <param name="wearables"></param>
        private void CacheWearableData(IScenePresence sp, Primitive.TextureEntry textureEntry, WearableCache[] wearables)
        {
            if (textureEntry == null || wearables.Length == 0)
                return;

            AvatarWearable cachedWearable = new AvatarWearable();
            cachedWearable.MaxItems = 0; //Unlimited items
            for (int i = 0; i < wearables.Length; i++)
            {
                WearableCache item = wearables[i];
                if (textureEntry.FaceTextures[item.TextureIndex] != null)
                {
                    cachedWearable.Add(item.CacheID, textureEntry.FaceTextures[item.TextureIndex].TextureID);
                }
            }
            m_scene.AvatarService.CacheWearableData(sp.UUID, cachedWearable);
        }
        /// <summary>
        /// Set appearance data (textureentry and slider settings) received from the client
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="visualParam"></param>
        public void SetAppearance(byte[] texture, List<byte> visualParam, WearableCache[] cachedItems, uint serial)
        {
            Primitive.TextureEntry textureEnt = new Primitive.TextureEntry(texture, 0, texture.Length);
            m_appearance.SetAppearance(textureEnt, visualParam.ToArray());
            if (m_appearance.AvatarHeight > 0)
                SetHeight(m_appearance.AvatarHeight);

            Dictionary<UUID, UUID> bakedTextures = new Dictionary<UUID,UUID>();
            foreach (WearableCache cache in cachedItems)
            {
                //V2 changed to send the actual texture index, and not the baked texture index
                int index = cache.TextureIndex >= 5 ? cache.TextureIndex :
                    (int)AppearanceManager.BakeTypeToAgentTextureIndex((BakeType)cache.TextureIndex);

                if(m_appearance.Texture != null && m_appearance.Texture.FaceTextures[index] != null)
                    bakedTextures.Add(cache.CacheID, m_appearance.Texture.FaceTextures[index].TextureID);
            }

            // Cof version number.
            m_appearance.Serial = (int)serial;

            if (!this.IsInTransit)
            {
                // Don't update the database with changes while a teleport/crossing is in progress.
                IAvatarFactory ava = m_scene.RequestModuleInterface<IAvatarFactory>();
                if (ava != null)
                {
                    ava.UpdateDatabase(m_uuid, m_appearance, SendAppearanceToAllOtherAgents, bakedTextures);
                }
            }

            if (!m_startAnimationSet)
            {
                UpdateMovementAnimations();
                m_startAnimationSet = true;
            }

            //
            // Handle initial attachment rez.  We need to do this for V1. V2 wants to manage its own
            // but we dont really have a good way to tell its a V2 client.
            //
            if (Interlocked.CompareExchange(ref _attachmentRezCalled, 1, 0) == 0)
            {
                //retrieve all attachments
                CachedUserInfo userInfo = m_scene.CommsManager.UserService.GetUserDetails(m_uuid);
                if (userInfo == null)
                    return;
                // If this is after a login in this region and not done yet, add the initial attachments
                if (ScenePresence.CheckNeedsInitialAttachmentRezAndReset(m_uuid))
                {
                    if (!IsChildAgent && (HasAttachments() == false))
                    {
                        ControllingClient.RunAttachmentOperation(() =>
                        {
                            this.InitialAttachmentRez();
                        });
                    }
                }
            }

            if (!IsBot)
                SendAvatarData(m_controllingClient, false);
        }