diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | 222 |
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) |