/// <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); }