aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs222
1 files changed, 178 insertions, 44 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index d02a305..b6a1564 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
104 public void NewClient(IClientAPI client) 104 public void NewClient(IClientAPI client)
105 { 105 {
106 client.OnRequestWearables += SendWearables; 106 client.OnRequestWearables += SendWearables;
107 client.OnSetAppearance += SetAppearance; 107 client.OnSetAppearance += SetAppearanceFromClient;
108 client.OnAvatarNowWearing += AvatarIsWearing; 108 client.OnAvatarNowWearing += AvatarIsWearing;
109 } 109 }
110 110
@@ -116,16 +116,20 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
116 #endregion 116 #endregion
117 117
118 /// <summary> 118 /// <summary>
119 /// Check for the existence of the baked texture assets. Request a rebake 119 /// Check for the existence of the baked texture assets.
120 /// unless checkonly is true.
121 /// </summary> 120 /// </summary>
122 /// <param name="client"></param> 121 /// <param name="client"></param>
123 /// <param name="checkonly"></param>
124 public bool ValidateBakedTextureCache(IClientAPI client) 122 public bool ValidateBakedTextureCache(IClientAPI client)
125 { 123 {
126 return ValidateBakedTextureCache(client, true); 124 return ValidateBakedTextureCache(client, true);
127 } 125 }
128 126
127 /// <summary>
128 /// Check for the existence of the baked texture assets. Request a rebake
129 /// unless checkonly is true.
130 /// </summary>
131 /// <param name="client"></param>
132 /// <param name="checkonly"></param>
129 private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly) 133 private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly)
130 { 134 {
131 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 135 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
@@ -147,6 +151,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
147 if (face == null) 151 if (face == null)
148 continue; 152 continue;
149 153
154// m_log.DebugFormat(
155// "[AVFACTORY]: Looking for texture {0}, id {1} for {2} {3}",
156// face.TextureID, idx, client.Name, client.AgentId);
157
150 // if the texture is one of the "defaults" then skip it 158 // if the texture is one of the "defaults" then skip it
151 // this should probably be more intelligent (skirt texture doesnt matter 159 // this should probably be more intelligent (skirt texture doesnt matter
152 // if the avatar isnt wearing a skirt) but if any of the main baked 160 // if the avatar isnt wearing a skirt) but if any of the main baked
@@ -156,13 +164,15 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
156 164
157 defonly = false; // found a non-default texture reference 165 defonly = false; // found a non-default texture reference
158 166
159 if (! CheckBakedTextureAsset(client,face.TextureID,idx)) 167 if (!CheckBakedTextureAsset(client, face.TextureID, idx))
160 { 168 {
161 // the asset didn't exist if we are only checking, then we found a bad 169 // the asset didn't exist if we are only checking, then we found a bad
162 // one and we're done otherwise, ask for a rebake 170 // one and we're done otherwise, ask for a rebake
163 if (checkonly) return false; 171 if (checkonly)
172 return false;
164 173
165 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID); 174 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID);
175
166 client.SendRebakeAvatarTextures(face.TextureID); 176 client.SendRebakeAvatarTextures(face.TextureID);
167 } 177 }
168 } 178 }
@@ -174,16 +184,17 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
174 } 184 }
175 185
176 /// <summary> 186 /// <summary>
177 /// Set appearance data (textureentry and slider settings) received from the client 187 /// Set appearance data (texture asset IDs and slider settings) received from the client
178 /// </summary> 188 /// </summary>
189 /// <param name="client"></param>
179 /// <param name="texture"></param> 190 /// <param name="texture"></param>
180 /// <param name="visualParam"></param> 191 /// <param name="visualParam"></param>
181 public void SetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams) 192 public void SetAppearanceFromClient(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
182 { 193 {
183 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 194 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
184 if (sp == null) 195 if (sp == null)
185 { 196 {
186 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}",client.AgentId); 197 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}", client.AgentId);
187 return; 198 return;
188 } 199 }
189 200
@@ -211,18 +222,18 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
211 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed; 222 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
212 223
213 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId); 224 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId);
214 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client,false); }); 225 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client, false); });
215 226
216 // This appears to be set only in the final stage of the appearance 227 // This appears to be set only in the final stage of the appearance
217 // update transaction. In theory, we should be able to do an immediate 228 // update transaction. In theory, we should be able to do an immediate
218 // appearance send and save here. 229 // appearance send and save here.
219 230
220 // save only if there were changes, send no matter what (doesn't hurt to send twice)
221 if (changed)
222 QueueAppearanceSave(client.AgentId);
223 QueueAppearanceSend(client.AgentId);
224 } 231 }
232 // save only if there were changes, send no matter what (doesn't hurt to send twice)
233 if (changed)
234 QueueAppearanceSave(client.AgentId);
225 235
236 QueueAppearanceSend(client.AgentId);
226 } 237 }
227 238
228 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString()); 239 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
@@ -246,6 +257,117 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
246 return true; 257 return true;
247 } 258 }
248 259
260 public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId)
261 {
262 ScenePresence sp = m_scene.GetScenePresence(agentId);
263
264 if (sp == null)
265 return new Dictionary<BakeType, Primitive.TextureEntryFace>();
266
267 return GetBakedTextureFaces(sp);
268 }
269
270 private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp)
271 {
272 if (sp.IsChildAgent)
273 return new Dictionary<BakeType, Primitive.TextureEntryFace>();
274
275 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures
276 = new Dictionary<BakeType, Primitive.TextureEntryFace>();
277
278 AvatarAppearance appearance = sp.Appearance;
279 Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures;
280
281 foreach (int i in Enum.GetValues(typeof(BakeType)))
282 {
283 BakeType bakeType = (BakeType)i;
284
285 if (bakeType == BakeType.Unknown)
286 continue;
287
288// m_log.DebugFormat(
289// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
290// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
291
292 int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType);
293 bakedTextures[bakeType] = faceTextures[ftIndex];
294 }
295
296 return bakedTextures;
297 }
298
299 public bool SaveBakedTextures(UUID agentId)
300 {
301 ScenePresence sp = m_scene.GetScenePresence(agentId);
302
303 if (sp == null)
304 return false;
305
306 m_log.DebugFormat(
307 "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
308 sp.Name, m_scene.RegionInfo.RegionName);
309
310 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp);
311
312 if (bakedTextures.Count == 0)
313 return false;
314
315 foreach (BakeType bakeType in bakedTextures.Keys)
316 {
317 Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType];
318
319 if (bakedTextureFace == null)
320 {
321 m_log.WarnFormat(
322 "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently",
323 bakeType, sp.Name, m_scene.RegionInfo.RegionName);
324
325 continue;
326 }
327
328 AssetBase asset = m_scene.AssetService.Get(bakedTextureFace.TextureID.ToString());
329
330 if (asset != null)
331 {
332 asset.Temporary = false;
333 asset.Local = false;
334 m_scene.AssetService.Store(asset);
335 }
336 else
337 {
338 m_log.WarnFormat(
339 "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently",
340 bakedTextureFace.TextureID, bakeType, sp.Name, m_scene.RegionInfo.RegionName);
341 }
342 }
343
344// for (int i = 0; i < faceTextures.Length; i++)
345// {
346//// m_log.DebugFormat(
347//// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
348//// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
349//
350// if (faceTextures[i] == null)
351// continue;
352//
353// AssetBase asset = m_scene.AssetService.Get(faceTextures[i].TextureID.ToString());
354//
355// if (asset != null)
356// {
357// asset.Temporary = false;
358// m_scene.AssetService.Store(asset);
359// }
360// else
361// {
362// m_log.WarnFormat(
363// "[AV FACTORY]: Baked texture {0} for {1} in {2} not found when trying to save permanently",
364// faceTextures[i].TextureID, sp.Name, m_scene.RegionInfo.RegionName);
365// }
366// }
367
368 return true;
369 }
370
249 #region UpdateAppearanceTimer 371 #region UpdateAppearanceTimer
250 372
251 /// <summary> 373 /// <summary>
@@ -278,26 +400,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
278 } 400 }
279 } 401 }
280 402
281 private void HandleAppearanceSend(UUID agentid) 403 private void SaveAppearance(UUID agentid)
282 { 404 {
283 ScenePresence sp = m_scene.GetScenePresence(agentid); 405 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
284 if (sp == null) 406 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
285 { 407 // number seperators.
286 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); 408 Culture.SetCurrentCulture();
287 return;
288 }
289
290 // m_log.WarnFormat("[AVFACTORY]: Handle appearance send for {0}", agentid);
291 409
292 // Send the appearance to everyone in the scene
293 sp.SendAppearanceToAllOtherAgents();
294
295 // Send animations back to the avatar as well
296 sp.Animator.SendAnimPack();
297 }
298
299 private void HandleAppearanceSave(UUID agentid)
300 {
301 ScenePresence sp = m_scene.GetScenePresence(agentid); 410 ScenePresence sp = m_scene.GetScenePresence(agentid);
302 if (sp == null) 411 if (sp == null)
303 { 412 {
@@ -321,7 +430,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
321 { 430 {
322 if (kvp.Value < now) 431 if (kvp.Value < now)
323 { 432 {
324 Util.FireAndForget(delegate(object o) { HandleAppearanceSend(kvp.Key); }); 433 Util.FireAndForget(delegate(object o) { SendAppearance(kvp.Key); });
325 m_sendqueue.Remove(kvp.Key); 434 m_sendqueue.Remove(kvp.Key);
326 } 435 }
327 } 436 }
@@ -334,7 +443,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
334 { 443 {
335 if (kvp.Value < now) 444 if (kvp.Value < now)
336 { 445 {
337 Util.FireAndForget(delegate(object o) { HandleAppearanceSave(kvp.Key); }); 446 Util.FireAndForget(delegate(object o) { SaveAppearance(kvp.Key); });
338 m_savequeue.Remove(kvp.Key); 447 m_savequeue.Remove(kvp.Key);
339 } 448 }
340 } 449 }
@@ -380,11 +489,11 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
380 // m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}", client.AgentId); 489 // m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}", client.AgentId);
381 490
382 // we need to clean out the existing textures 491 // we need to clean out the existing textures
383 sp.Appearance.ResetAppearance(); 492 sp.Appearance.ResetAppearance();
384 493
385 // operate on a copy of the appearance so we don't have to lock anything 494 // operate on a copy of the appearance so we don't have to lock anything yet
386 AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false); 495 AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false);
387 496
388 foreach (AvatarWearingArgs.Wearable wear in e.NowWearing) 497 foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
389 { 498 {
390 if (wear.Type < AvatarWearable.MAX_WEARABLES) 499 if (wear.Type < AvatarWearable.MAX_WEARABLES)
@@ -396,12 +505,37 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
396 // This could take awhile since it needs to pull inventory 505 // This could take awhile since it needs to pull inventory
397 SetAppearanceAssets(sp.UUID, ref avatAppearance); 506 SetAppearanceAssets(sp.UUID, ref avatAppearance);
398 507
399 // could get fancier with the locks here, but in the spirit of "last write wins" 508 lock (m_setAppearanceLock)
400 // this should work correctly, also, we don't need to send the appearance here 509 {
401 // since the "iswearing" will trigger a new set of visual param and baked texture changes 510 // Update only those fields that we have changed. This is important because the viewer
402 // when those complete, the new appearance will be sent 511 // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing
403 sp.Appearance = avatAppearance; 512 // shouldn't overwrite the changes made in SetAppearance.
404 QueueAppearanceSave(client.AgentId); 513 sp.Appearance.Wearables = avatAppearance.Wearables;
514 sp.Appearance.Texture = avatAppearance.Texture;
515
516 // We don't need to send the appearance here since the "iswearing" will trigger a new set
517 // of visual param and baked texture changes. When those complete, the new appearance will be sent
518
519 QueueAppearanceSave(client.AgentId);
520 }
521 }
522
523 public bool SendAppearance(UUID agentId)
524 {
525 ScenePresence sp = m_scene.GetScenePresence(agentId);
526 if (sp == null)
527 {
528 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
529 return false;
530 }
531
532 // Send the appearance to everyone in the scene
533 sp.SendAppearanceToAllOtherAgents();
534
535 // Send animations back to the avatar as well
536 sp.Animator.SendAnimPack();
537
538 return true;
405 } 539 }
406 540
407 private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance) 541 private void SetAppearanceAssets(UUID userID, ref AvatarAppearance appearance)