aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar
diff options
context:
space:
mode:
authorDan Lake2011-10-19 14:41:44 -0700
committerDan Lake2011-10-19 14:41:44 -0700
commitda794f34a56f7c88904315ae538de8f3790e6891 (patch)
treeec15f9ad1a941441ab2c0cd24f50b7636bba7bce /OpenSim/Region/CoreModules/Avatar
parentAdd "scripts stop" and "scripts start" console commands. (diff)
downloadopensim-SC-da794f34a56f7c88904315ae538de8f3790e6891.zip
opensim-SC-da794f34a56f7c88904315ae538de8f3790e6891.tar.gz
opensim-SC-da794f34a56f7c88904315ae538de8f3790e6891.tar.bz2
opensim-SC-da794f34a56f7c88904315ae538de8f3790e6891.tar.xz
Renamed and rearranged AvatarFactoryModule to eliminate redundant lookups of scene presence by client ID.
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs616
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs12
2 files changed, 300 insertions, 328 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index d4e1736..0c7c690 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -42,7 +42,7 @@ using OpenSim.Services.Interfaces;
42 42
43namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory 43namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
44{ 44{
45 public class AvatarFactoryModule : IAvatarFactory, IRegionModule 45 public class AvatarFactoryModule : IAvatarFactoryModule, IRegionModule
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private Scene m_scene = null; 48 private Scene m_scene = null;
@@ -57,12 +57,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
57 57
58 private object m_setAppearanceLock = new object(); 58 private object m_setAppearanceLock = new object();
59 59
60 #region RegionModule Members 60 #region IRegionModule
61 61
62 public void Initialise(Scene scene, IConfigSource config) 62 public void Initialise(Scene scene, IConfigSource config)
63 { 63 {
64 scene.RegisterModuleInterface<IAvatarFactory>(this); 64 scene.RegisterModuleInterface<IAvatarFactoryModule>(this);
65 scene.EventManager.OnNewClient += NewClient; 65 scene.EventManager.OnNewClient += SubscribeToClientEvents;
66 66
67 IConfig sconfig = config.Configs["Startup"]; 67 IConfig sconfig = config.Configs["Startup"];
68 if (sconfig != null) 68 if (sconfig != null)
@@ -98,44 +98,201 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
98 get { return false; } 98 get { return false; }
99 } 99 }
100 100
101 public void NewClient(IClientAPI client) 101 private void SubscribeToClientEvents(IClientAPI client)
102 { 102 {
103 client.OnRequestWearables += SendWearables; 103 client.OnRequestWearables += Client_OnRequestWearables;
104 client.OnSetAppearance += SetAppearanceFromClient; 104 client.OnSetAppearance += Client_OnSetAppearance;
105 client.OnAvatarNowWearing += AvatarIsWearing; 105 client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
106 } 106 }
107 107
108 public void RemoveClient(IClientAPI client) 108 #endregion
109 { 109
110 // client.OnAvatarNowWearing -= AvatarIsWearing; 110 #region IAvatarFactoryModule
111 } 111
112 112 /// <summary>
113 #endregion 113 /// Set appearance data (texture asset IDs and slider settings)
114 114 /// </summary>
115 /// <param name="sp"></param>
116 /// <param name="texture"></param>
117 /// <param name="visualParam"></param>
118 public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams)
119 {
120 // m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId);
121
122 // TODO: This is probably not necessary any longer, just assume the
123 // textureEntry set implies that the appearance transaction is complete
124 bool changed = false;
125
126 // Process the texture entry transactionally, this doesn't guarantee that Appearance is
127 // going to be handled correctly but it does serialize the updates to the appearance
128 lock (m_setAppearanceLock)
129 {
130 // Process the visual params, this may change height as well
131 if (visualParams != null)
132 {
133 // string[] visualParamsStrings = new string[visualParams.Length];
134 // for (int i = 0; i < visualParams.Length; i++)
135 // visualParamsStrings[i] = visualParams[i].ToString();
136 // m_log.DebugFormat(
137 // "[AVFACTORY]: Setting visual params for {0} to {1}",
138 // client.Name, string.Join(", ", visualParamsStrings));
139
140 float oldHeight = sp.Appearance.AvatarHeight;
141 changed = sp.Appearance.SetVisualParams(visualParams);
142
143 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0)
144 ((ScenePresence)sp).SetHeight(sp.Appearance.AvatarHeight);
145 }
146
147 // Process the baked texture array
148 if (textureEntry != null)
149 {
150 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
151
152 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", sp.UUID);
153 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(sp, false); });
154
155 // This appears to be set only in the final stage of the appearance
156 // update transaction. In theory, we should be able to do an immediate
157 // appearance send and save here.
158
159 }
160 // save only if there were changes, send no matter what (doesn't hurt to send twice)
161 if (changed)
162 QueueAppearanceSave(sp.ControllingClient.AgentId);
163
164 QueueAppearanceSend(sp.ControllingClient.AgentId);
165 }
166
167 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
168 }
169
170 public bool SendAppearance(UUID agentId)
171 {
172 ScenePresence sp = m_scene.GetScenePresence(agentId);
173 if (sp == null)
174 {
175 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
176 return false;
177 }
178
179 // Send the appearance to everyone in the scene
180 sp.SendAppearanceToAllOtherAgents();
181
182 // Send animations back to the avatar as well
183 sp.Animator.SendAnimPack();
184
185 return true;
186 }
187
188 public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId)
189 {
190 ScenePresence sp = m_scene.GetScenePresence(agentId);
191
192 if (sp == null)
193 return new Dictionary<BakeType, Primitive.TextureEntryFace>();
194
195 return GetBakedTextureFaces(sp);
196 }
197
198 public bool SaveBakedTextures(UUID agentId)
199 {
200 ScenePresence sp = m_scene.GetScenePresence(agentId);
201
202 if (sp == null)
203 return false;
204
205 m_log.DebugFormat(
206 "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
207 sp.Name, m_scene.RegionInfo.RegionName);
208
209 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp);
210
211 if (bakedTextures.Count == 0)
212 return false;
213
214 foreach (BakeType bakeType in bakedTextures.Keys)
215 {
216 Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType];
217
218 if (bakedTextureFace == null)
219 {
220 m_log.WarnFormat(
221 "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently",
222 bakeType, sp.Name, m_scene.RegionInfo.RegionName);
223
224 continue;
225 }
226
227 AssetBase asset = m_scene.AssetService.Get(bakedTextureFace.TextureID.ToString());
228
229 if (asset != null)
230 {
231 asset.Temporary = false;
232 asset.Local = false;
233 m_scene.AssetService.Store(asset);
234 }
235 else
236 {
237 m_log.WarnFormat(
238 "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently",
239 bakedTextureFace.TextureID, bakeType, sp.Name, m_scene.RegionInfo.RegionName);
240 }
241 }
242 return true;
243 }
244
115 /// <summary> 245 /// <summary>
116 /// Check for the existence of the baked texture assets. 246 /// Check for the existence of the baked texture assets.
117 /// </summary> 247 /// </summary>
118 /// <param name="client"></param> 248 /// <param name="sp"></param>
119 public bool ValidateBakedTextureCache(IClientAPI client) 249 public bool ValidateBakedTextureCache(IScenePresence sp)
120 { 250 {
121 return ValidateBakedTextureCache(client, true); 251 return ValidateBakedTextureCache(sp, true);
122 } 252 }
123 253
254 /// <summary>
255 /// Queue up a request to send appearance, makes it possible to
256 /// accumulate changes without sending out each one separately.
257 /// </summary>
258 public void QueueAppearanceSend(UUID agentid)
259 {
260 // m_log.WarnFormat("[AVFACTORY]: Queue appearance send for {0}", agentid);
261
262 // 10000 ticks per millisecond, 1000 milliseconds per second
263 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000);
264 lock (m_sendqueue)
265 {
266 m_sendqueue[agentid] = timestamp;
267 m_updateTimer.Start();
268 }
269 }
270
271 public void QueueAppearanceSave(UUID agentid)
272 {
273 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid);
274
275 // 10000 ticks per millisecond, 1000 milliseconds per second
276 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
277 lock (m_savequeue)
278 {
279 m_savequeue[agentid] = timestamp;
280 m_updateTimer.Start();
281 }
282 }
283
284 #endregion
285
286 #region AvatarFactoryModule private methods
287
124 /// <summary> 288 /// <summary>
125 /// Check for the existence of the baked texture assets. Request a rebake 289 /// Check for the existence of the baked texture assets. Request a rebake
126 /// unless checkonly is true. 290 /// unless checkonly is true.
127 /// </summary> 291 /// </summary>
128 /// <param name="client"></param> 292 /// <param name="client"></param>
129 /// <param name="checkonly"></param> 293 /// <param name="checkonly"></param>
130 private bool ValidateBakedTextureCache(IClientAPI client, bool checkonly) 294 private bool ValidateBakedTextureCache(IScenePresence sp, bool checkonly)
131 { 295 {
132 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
133 if (sp == null)
134 {
135 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}", client.AgentId);
136 return false;
137 }
138
139 bool defonly = true; // are we only using default textures 296 bool defonly = true; // are we only using default textures
140 297
141 // Process the texture entry 298 // Process the texture entry
@@ -161,7 +318,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
161 318
162 defonly = false; // found a non-default texture reference 319 defonly = false; // found a non-default texture reference
163 320
164 if (!CheckBakedTextureAsset(client, face.TextureID, idx)) 321 if (!CheckBakedTextureAsset(sp, face.TextureID, idx))
165 { 322 {
166 // the asset didn't exist if we are only checking, then we found a bad 323 // the asset didn't exist if we are only checking, then we found a bad
167 // one and we're done otherwise, ask for a rebake 324 // one and we're done otherwise, ask for a rebake
@@ -170,109 +327,34 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
170 327
171 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID); 328 m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake", face.TextureID);
172 329
173 client.SendRebakeAvatarTextures(face.TextureID); 330 sp.ControllingClient.SendRebakeAvatarTextures(face.TextureID);
174 } 331 }
175 } 332 }
176 333
177 m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0}", client.AgentId); 334 m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0}", sp.UUID);
178 335
179 // If we only found default textures, then the appearance is not cached 336 // If we only found default textures, then the appearance is not cached
180 return (defonly ? false : true); 337 return (defonly ? false : true);
181 } 338 }
182 339
183 /// <summary> 340 /// <summary>
184 /// Set appearance data (texture asset IDs and slider settings) received from the client
185 /// </summary>
186 /// <param name="client"></param>
187 /// <param name="texture"></param>
188 /// <param name="visualParam"></param>
189 public void SetAppearanceFromClient(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
190 {
191 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
192 if (sp == null)
193 {
194 m_log.WarnFormat("[AVFACTORY]: SetAppearance unable to find presence for {0}", client.AgentId);
195 return;
196 }
197
198// m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId);
199
200 // TODO: This is probably not necessary any longer, just assume the
201 // textureEntry set implies that the appearance transaction is complete
202 bool changed = false;
203
204 // Process the texture entry transactionally, this doesn't guarantee that Appearance is
205 // going to be handled correctly but it does serialize the updates to the appearance
206 lock (m_setAppearanceLock)
207 {
208 // Process the visual params, this may change height as well
209 if (visualParams != null)
210 {
211// string[] visualParamsStrings = new string[visualParams.Length];
212// for (int i = 0; i < visualParams.Length; i++)
213// visualParamsStrings[i] = visualParams[i].ToString();
214// m_log.DebugFormat(
215// "[AVFACTORY]: Setting visual params for {0} to {1}",
216// client.Name, string.Join(", ", visualParamsStrings));
217
218 float oldHeight = sp.Appearance.AvatarHeight;
219 changed = sp.Appearance.SetVisualParams(visualParams);
220
221 if (sp.Appearance.AvatarHeight != oldHeight && sp.Appearance.AvatarHeight > 0)
222 sp.SetHeight(sp.Appearance.AvatarHeight);
223 }
224
225 // Process the baked texture array
226 if (textureEntry != null)
227 {
228 changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
229
230 m_log.InfoFormat("[AVFACTORY]: received texture update for {0}", client.AgentId);
231 Util.FireAndForget(delegate(object o) { ValidateBakedTextureCache(client, false); });
232
233 // This appears to be set only in the final stage of the appearance
234 // update transaction. In theory, we should be able to do an immediate
235 // appearance send and save here.
236
237 }
238 // save only if there were changes, send no matter what (doesn't hurt to send twice)
239 if (changed)
240 QueueAppearanceSave(client.AgentId);
241
242 QueueAppearanceSend(client.AgentId);
243 }
244
245 // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
246 }
247
248 /// <summary>
249 /// Checks for the existance of a baked texture asset and 341 /// Checks for the existance of a baked texture asset and
250 /// requests the viewer rebake if the asset is not found 342 /// requests the viewer rebake if the asset is not found
251 /// </summary> 343 /// </summary>
252 /// <param name="client"></param> 344 /// <param name="sp"></param>
253 /// <param name="textureID"></param> 345 /// <param name="textureID"></param>
254 /// <param name="idx"></param> 346 /// <param name="idx"></param>
255 private bool CheckBakedTextureAsset(IClientAPI client, UUID textureID, int idx) 347 private bool CheckBakedTextureAsset(IScenePresence sp, UUID textureID, int idx)
256 { 348 {
257 if (m_scene.AssetService.Get(textureID.ToString()) == null) 349 if (m_scene.AssetService.Get(textureID.ToString()) == null)
258 { 350 {
259 m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}", 351 m_log.WarnFormat("[AVFACTORY]: Missing baked texture {0} ({1}) for avatar {2}",
260 textureID, idx, client.Name); 352 textureID, idx, sp.Name);
261 return false; 353 return false;
262 } 354 }
263 return true; 355 return true;
264 } 356 }
265 357
266 public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId)
267 {
268 ScenePresence sp = m_scene.GetScenePresence(agentId);
269
270 if (sp == null)
271 return new Dictionary<BakeType, Primitive.TextureEntryFace>();
272
273 return GetBakedTextureFaces(sp);
274 }
275
276 private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp) 358 private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp)
277 { 359 {
278 if (sp.IsChildAgent) 360 if (sp.IsChildAgent)
@@ -302,136 +384,6 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
302 return bakedTextures; 384 return bakedTextures;
303 } 385 }
304 386
305 public bool SaveBakedTextures(UUID agentId)
306 {
307 ScenePresence sp = m_scene.GetScenePresence(agentId);
308
309 if (sp == null)
310 return false;
311
312 m_log.DebugFormat(
313 "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
314 sp.Name, m_scene.RegionInfo.RegionName);
315
316 Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp);
317
318 if (bakedTextures.Count == 0)
319 return false;
320
321 foreach (BakeType bakeType in bakedTextures.Keys)
322 {
323 Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType];
324
325 if (bakedTextureFace == null)
326 {
327 m_log.WarnFormat(
328 "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently",
329 bakeType, sp.Name, m_scene.RegionInfo.RegionName);
330
331 continue;
332 }
333
334 AssetBase asset = m_scene.AssetService.Get(bakedTextureFace.TextureID.ToString());
335
336 if (asset != null)
337 {
338 asset.Temporary = false;
339 asset.Local = false;
340 m_scene.AssetService.Store(asset);
341 }
342 else
343 {
344 m_log.WarnFormat(
345 "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently",
346 bakedTextureFace.TextureID, bakeType, sp.Name, m_scene.RegionInfo.RegionName);
347 }
348 }
349
350// for (int i = 0; i < faceTextures.Length; i++)
351// {
352//// m_log.DebugFormat(
353//// "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
354//// acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
355//
356// if (faceTextures[i] == null)
357// continue;
358//
359// AssetBase asset = m_scene.AssetService.Get(faceTextures[i].TextureID.ToString());
360//
361// if (asset != null)
362// {
363// asset.Temporary = false;
364// m_scene.AssetService.Store(asset);
365// }
366// else
367// {
368// m_log.WarnFormat(
369// "[AV FACTORY]: Baked texture {0} for {1} in {2} not found when trying to save permanently",
370// faceTextures[i].TextureID, sp.Name, m_scene.RegionInfo.RegionName);
371// }
372// }
373
374 return true;
375 }
376
377 #region UpdateAppearanceTimer
378
379 /// <summary>
380 /// Queue up a request to send appearance, makes it possible to
381 /// accumulate changes without sending out each one separately.
382 /// </summary>
383 public void QueueAppearanceSend(UUID agentid)
384 {
385 // m_log.WarnFormat("[AVFACTORY]: Queue appearance send for {0}", agentid);
386
387 // 10000 ticks per millisecond, 1000 milliseconds per second
388 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000);
389 lock (m_sendqueue)
390 {
391 m_sendqueue[agentid] = timestamp;
392 m_updateTimer.Start();
393 }
394 }
395
396 public void QueueAppearanceSave(UUID agentid)
397 {
398 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid);
399
400 // 10000 ticks per millisecond, 1000 milliseconds per second
401 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
402 lock (m_savequeue)
403 {
404 m_savequeue[agentid] = timestamp;
405 m_updateTimer.Start();
406 }
407 }
408
409 private void SaveAppearance(UUID agentid)
410 {
411 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
412 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
413 // number seperators.
414 Culture.SetCurrentCulture();
415
416 ScenePresence sp = m_scene.GetScenePresence(agentid);
417 if (sp == null)
418 {
419 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
420 return;
421 }
422
423 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid);
424
425 // This could take awhile since it needs to pull inventory
426 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
427 // assets and item asset id changes to complete.
428 // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
429 // multiple save requests.
430 SetAppearanceAssets(sp.UUID, sp.Appearance);
431
432 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
433 }
434
435 private void HandleAppearanceUpdateTimer(object sender, EventArgs ea) 387 private void HandleAppearanceUpdateTimer(object sender, EventArgs ea)
436 { 388 {
437 long now = DateTime.Now.Ticks; 389 long now = DateTime.Now.Ticks;
@@ -464,43 +416,122 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
464 416
465 if (m_savequeue.Count == 0 && m_sendqueue.Count == 0) 417 if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
466 m_updateTimer.Stop(); 418 m_updateTimer.Stop();
467 } 419 }
468 420
469 #endregion 421 private void SaveAppearance(UUID agentid)
470 422 {
423 // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
424 // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
425 // number seperators.
426 Culture.SetCurrentCulture();
427
428 ScenePresence sp = m_scene.GetScenePresence(agentid);
429 if (sp == null)
430 {
431 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
432 return;
433 }
434
435 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid);
436
437 // This could take awhile since it needs to pull inventory
438 // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
439 // assets and item asset id changes to complete.
440 // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
441 // multiple save requests.
442 SetAppearanceAssets(sp.UUID, sp.Appearance);
443
444 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
445 }
446
447 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
448 {
449 IInventoryService invService = m_scene.InventoryService;
450
451 if (invService.GetRootFolder(userID) != null)
452 {
453 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
454 {
455 for (int j = 0; j < appearance.Wearables[j].Count; j++)
456 {
457 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
458 continue;
459
460 // Ignore ruth's assets
461 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
462 continue;
463 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
464 baseItem = invService.GetItem(baseItem);
465
466 if (baseItem != null)
467 {
468 appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
469 }
470 else
471 {
472 m_log.ErrorFormat(
473 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
474 appearance.Wearables[i][j].ItemID, (WearableType)i);
475
476 appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID);
477 }
478 }
479 }
480 }
481 else
482 {
483 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
484 }
485 }
486
487 #endregion
488
489 #region Client Event Handlers
471 /// <summary> 490 /// <summary>
472 /// Tell the client for this scene presence what items it should be wearing now 491 /// Tell the client for this scene presence what items it should be wearing now
473 /// </summary> 492 /// </summary>
474 public void SendWearables(IClientAPI client) 493 /// <param name="client"></param>
475 { 494 private void Client_OnRequestWearables(IClientAPI client)
495 {
496 // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId);
476 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 497 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
477 if (sp == null) 498 if (sp != null)
478 { 499 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++);
479 m_log.WarnFormat("[AVFACTORY]: SendWearables unable to find presence for {0}", client.AgentId); 500 else
480 return; 501 m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId);
481 } 502 }
482 503
483// m_log.DebugFormat("[AVFACTORY]: Received request for wearables of {0}", client.Name); 504 /// <summary>
484 505 /// Set appearance data (texture asset IDs and slider settings) received from a client
485 client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++); 506 /// </summary>
507 /// <param name="client"></param>
508 /// <param name="texture"></param>
509 /// <param name="visualParam"></param>
510 private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams)
511 {
512 // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
513 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
514 if (sp != null)
515 SetAppearance(sp, textureEntry, visualParams);
516 else
517 m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
486 } 518 }
487 519
488 /// <summary> 520 /// <summary>
489 /// Update what the avatar is wearing using an item from their inventory. 521 /// Update what the avatar is wearing using an item from their inventory.
490 /// </summary> 522 /// </summary>
491 /// <param name="sender"></param> 523 /// <param name="client"></param>
492 /// <param name="e"></param> 524 /// <param name="e"></param>
493 public void AvatarIsWearing(IClientAPI client, AvatarWearingArgs e) 525 private void Client_OnAvatarNowWearing(IClientAPI client, AvatarWearingArgs e)
494 { 526 {
527 // m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing called for {0} ({1})", client.Name, client.AgentId);
495 ScenePresence sp = m_scene.GetScenePresence(client.AgentId); 528 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
496 if (sp == null) 529 if (sp == null)
497 { 530 {
498 m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing unable to find presence for {0}", client.AgentId); 531 m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing unable to find presence for {0}", client.AgentId);
499 return; 532 return;
500 } 533 }
501 534
502 // m_log.WarnFormat("[AVFACTORY]: AvatarIsWearing called for {0}", client.AgentId);
503
504 // we need to clean out the existing textures 535 // we need to clean out the existing textures
505 sp.Appearance.ResetAppearance(); 536 sp.Appearance.ResetAppearance();
506 537
@@ -527,65 +558,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
527 // of visual param and baked texture changes. When those complete, the new appearance will be sent 558 // of visual param and baked texture changes. When those complete, the new appearance will be sent
528 559
529 QueueAppearanceSave(client.AgentId); 560 QueueAppearanceSave(client.AgentId);
530 } 561 }
531 } 562 }
532 563 #endregion
533 public bool SendAppearance(UUID agentId)
534 {
535 ScenePresence sp = m_scene.GetScenePresence(agentId);
536 if (sp == null)
537 {
538 m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
539 return false;
540 }
541
542 // Send the appearance to everyone in the scene
543 sp.SendAppearanceToAllOtherAgents();
544
545 // Send animations back to the avatar as well
546 sp.Animator.SendAnimPack();
547
548 return true;
549 }
550
551 private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
552 {
553 IInventoryService invService = m_scene.InventoryService;
554
555 if (invService.GetRootFolder(userID) != null)
556 {
557 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
558 {
559 for (int j = 0; j < appearance.Wearables[j].Count; j++)
560 {
561 if (appearance.Wearables[i][j].ItemID == UUID.Zero)
562 continue;
563
564 // Ignore ruth's assets
565 if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
566 continue;
567 InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
568 baseItem = invService.GetItem(baseItem);
569
570 if (baseItem != null)
571 {
572 appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
573 }
574 else
575 {
576 m_log.ErrorFormat(
577 "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
578 appearance.Wearables[i][j].ItemID, (WearableType)i);
579
580 appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID);
581 }
582 }
583 }
584 }
585 else
586 {
587 m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
588 }
589 }
590 } 564 }
591} 565}
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
index 7b2f14e..931d52f 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs
@@ -55,15 +55,13 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
55 AvatarFactoryModule afm = new AvatarFactoryModule(); 55 AvatarFactoryModule afm = new AvatarFactoryModule();
56 TestScene scene = SceneHelpers.SetupScene(); 56 TestScene scene = SceneHelpers.SetupScene();
57 SceneHelpers.SetupSceneModules(scene, afm); 57 SceneHelpers.SetupSceneModules(scene, afm);
58 IClientAPI tc = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; 58 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
59 59
60 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT]; 60 byte[] visualParams = new byte[AvatarAppearance.VISUALPARAM_COUNT];
61 for (byte i = 0; i < visualParams.Length; i++) 61 for (byte i = 0; i < visualParams.Length; i++)
62 visualParams[i] = i; 62 visualParams[i] = i;
63 63
64 afm.SetAppearanceFromClient(tc, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams); 64 afm.SetAppearance(sp, new Primitive.TextureEntry(TestHelpers.ParseTail(0x10)), visualParams);
65
66 ScenePresence sp = scene.GetScenePresence(userId);
67 65
68 // TODO: Check baked texture 66 // TODO: Check baked texture
69 Assert.AreEqual(visualParams, sp.Appearance.VisualParams); 67 Assert.AreEqual(visualParams, sp.Appearance.VisualParams);
@@ -84,8 +82,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
84 82
85 AvatarFactoryModule afm = new AvatarFactoryModule(); 83 AvatarFactoryModule afm = new AvatarFactoryModule();
86 TestScene scene = SceneHelpers.SetupScene(assetCache); 84 TestScene scene = SceneHelpers.SetupScene(assetCache);
87 SceneHelpers.SetupSceneModules(scene, afm); 85 SceneHelpers.SetupSceneModules(scene, afm);
88 IClientAPI tc = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; 86 ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
89 87
90 // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules 88 // TODO: Use the actual BunchOfCaps functionality once we slot in the CapabilitiesModules
91 AssetBase uploadedAsset; 89 AssetBase uploadedAsset;
@@ -104,7 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
104 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex); 102 Primitive.TextureEntryFace eyesFace = bakedTextureEntry.CreateFace(eyesFaceIndex);
105 eyesFace.TextureID = eyesTextureId; 103 eyesFace.TextureID = eyesTextureId;
106 104
107 afm.SetAppearanceFromClient(tc, bakedTextureEntry, visualParams); 105 afm.SetAppearance(sp, bakedTextureEntry, visualParams);
108 afm.SaveBakedTextures(userId); 106 afm.SaveBakedTextures(userId);
109// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId); 107// Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = afm.GetBakedTextureFaces(userId);
110 108