AvatarFactoryModule.cs 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Concurrent;
  30. using System.Reflection;
  31. using System.Threading;
  32. using System.Text;
  33. using System.Timers;
  34. using log4net;
  35. using Nini.Config;
  36. using OpenMetaverse;
  37. using OpenSim.Framework;
  38. using OpenSim.Framework.Monitoring;
  39. using OpenSim.Region.Framework.Interfaces;
  40. using OpenSim.Region.Framework.Scenes;
  41. using OpenSim.Services.Interfaces;
  42. using Mono.Addins;
  43. using PermissionMask = OpenSim.Framework.PermissionMask;
  44. namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
  45. {
  46. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarFactoryModule")]
  47. public class AvatarFactoryModule : IAvatarFactoryModule, INonSharedRegionModule
  48. {
  49. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  50. public const string BAKED_TEXTURES_REPORT_FORMAT = "{0,-9} {1}";
  51. private Scene m_scene = null;
  52. private int m_savetime = 5; // seconds to wait before saving changed appearance
  53. private int m_sendtime = 2; // seconds to wait before sending changed appearance
  54. private bool m_reusetextures = false;
  55. private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
  56. private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
  57. private ConcurrentDictionary<UUID,long> m_savequeue = new ConcurrentDictionary<UUID,long>();
  58. private ConcurrentDictionary<UUID,long> m_sendqueue = new ConcurrentDictionary<UUID,long>();
  59. private object m_updatesLock = new object();
  60. private int m_updatesbusy = 0;
  61. private object m_setAppearanceLock = new object();
  62. #region Region Module interface
  63. public void Initialise(IConfigSource config)
  64. {
  65. IConfig appearanceConfig = config.Configs["Appearance"];
  66. if (appearanceConfig != null)
  67. {
  68. m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
  69. m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
  70. m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures);
  71. // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
  72. }
  73. }
  74. public void AddRegion(Scene scene)
  75. {
  76. if (m_scene == null)
  77. m_scene = scene;
  78. scene.RegisterModuleInterface<IAvatarFactoryModule>(this);
  79. scene.EventManager.OnNewClient += SubscribeToClientEvents;
  80. }
  81. public void RemoveRegion(Scene scene)
  82. {
  83. if (scene == m_scene)
  84. {
  85. scene.UnregisterModuleInterface<IAvatarFactoryModule>(this);
  86. scene.EventManager.OnNewClient -= SubscribeToClientEvents;
  87. }
  88. m_scene = null;
  89. }
  90. public void RegionLoaded(Scene scene)
  91. {
  92. m_updateTimer.Enabled = false;
  93. m_updateTimer.AutoReset = true;
  94. m_updateTimer.Interval = m_checkTime; // 500 milliseconds wait to start async ops
  95. m_updateTimer.Elapsed += new ElapsedEventHandler(HandleAppearanceUpdateTimer);
  96. }
  97. public void Close()
  98. {
  99. }
  100. public string Name
  101. {
  102. get { return "Default Avatar Factory"; }
  103. }
  104. public bool IsSharedModule
  105. {
  106. get { return false; }
  107. }
  108. public Type ReplaceableInterface
  109. {
  110. get { return null; }
  111. }
  112. private void SubscribeToClientEvents(IClientAPI client)
  113. {
  114. client.OnRequestWearables += Client_OnRequestWearables;
  115. client.OnSetAppearance += Client_OnSetAppearance;
  116. client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
  117. //client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
  118. }
  119. #endregion
  120. #region IAvatarFactoryModule
  121. /// </summary>
  122. /// <param name="sp"></param>
  123. /// <param name="texture"></param>
  124. /// <param name="visualParam"></param>
  125. public void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems)
  126. {
  127. SetAppearance(sp, appearance.Texture, appearance.VisualParams, cacheItems);
  128. }
  129. public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
  130. {
  131. float oldoff = sp.Appearance.AvatarFeetOffset;
  132. Vector3 oldbox = sp.Appearance.AvatarBoxSize;
  133. SetAppearance(sp, textureEntry, visualParams, cacheItems);
  134. sp.Appearance.SetSize(avSize);
  135. float off = sp.Appearance.AvatarFeetOffset;
  136. Vector3 box = sp.Appearance.AvatarBoxSize;
  137. if (oldoff != off || oldbox != box)
  138. ((ScenePresence)sp).SetSize(box, off);
  139. }
  140. /// <summary>
  141. /// Set appearance data (texture asset IDs and slider settings)
  142. /// </summary>
  143. /// <param name="sp"></param>
  144. /// <param name="texture"></param>
  145. /// <param name="visualParam"></param>
  146. public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems)
  147. {
  148. // m_log.DebugFormat(
  149. // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
  150. // sp.Name, textureEntry, visualParams);
  151. // TODO: This is probably not necessary any longer, just assume the
  152. // textureEntry set implies that the appearance transaction is complete
  153. bool changed = false;
  154. // Process the texture entry transactionally, this doesn't guarantee that Appearance is
  155. // going to be handled correctly but it does serialize the updates to the appearance
  156. lock (m_setAppearanceLock)
  157. {
  158. // Process the visual params, this may change height as well
  159. if (visualParams != null)
  160. {
  161. changed = sp.Appearance.SetVisualParams(visualParams);
  162. }
  163. // Process the baked texture array
  164. if (textureEntry != null)
  165. {
  166. m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
  167. // WriteBakedTexturesReport(sp, m_log.DebugFormat);
  168. changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
  169. // WriteBakedTexturesReport(sp, m_log.DebugFormat);
  170. UpdateBakedTextureCache(sp, cacheItems);
  171. // This appears to be set only in the final stage of the appearance
  172. // update transaction. In theory, we should be able to do an immediate
  173. // appearance send and save here.
  174. }
  175. // NPC should send to clients immediately and skip saving appearance
  176. if (((ScenePresence)sp).PresenceType == PresenceType.Npc)
  177. {
  178. SendAppearance((ScenePresence)sp);
  179. return;
  180. }
  181. // save only if there were changes, send no matter what (doesn't hurt to send twice)
  182. if (changed)
  183. QueueAppearanceSave(sp.ControllingClient.AgentId);
  184. QueueAppearanceSend(sp.ControllingClient.AgentId);
  185. }
  186. // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
  187. }
  188. private void SendAppearance(ScenePresence sp)
  189. {
  190. // Send the appearance to everyone in the scene
  191. sp.SendAppearanceToAllOtherAgents();
  192. // Send animations back to the avatar as well
  193. if(sp.Animator != null)
  194. sp.Animator.SendAnimPack();
  195. }
  196. public bool SendAppearance(UUID agentId)
  197. {
  198. ScenePresence sp = m_scene.GetScenePresence(agentId);
  199. if (sp == null || sp.IsDeleted)
  200. return false;
  201. SendAppearance(sp);
  202. return true;
  203. }
  204. public Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(UUID agentId)
  205. {
  206. ScenePresence sp = m_scene.GetScenePresence(agentId);
  207. if (sp == null)
  208. return new Dictionary<BakeType, Primitive.TextureEntryFace>();
  209. return GetBakedTextureFaces(sp);
  210. }
  211. public WearableCacheItem[] GetCachedItems(UUID agentId)
  212. {
  213. ScenePresence sp = m_scene.GetScenePresence(agentId);
  214. WearableCacheItem[] items = sp.Appearance.WearableCacheItems;
  215. //foreach (WearableCacheItem item in items)
  216. //{
  217. //}
  218. return items;
  219. }
  220. public bool SaveBakedTextures(UUID agentId)
  221. {
  222. ScenePresence sp = m_scene.GetScenePresence(agentId);
  223. if (sp == null)
  224. return false;
  225. m_log.DebugFormat(
  226. "[AV FACTORY]: Permanently saving baked textures for {0} in {1}",
  227. sp.Name, m_scene.RegionInfo.RegionName);
  228. Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp);
  229. if (bakedTextures.Count == 0)
  230. return false;
  231. IAssetCache cache = sp.Scene.RequestModuleInterface<IAssetCache>();
  232. if(cache == null)
  233. return true; // no baked local caching so nothing to do
  234. foreach (BakeType bakeType in bakedTextures.Keys)
  235. {
  236. Primitive.TextureEntryFace bakedTextureFace = bakedTextures[bakeType];
  237. if (bakedTextureFace == null || bakedTextureFace.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  238. continue;
  239. AssetBase asset;
  240. cache.Get(bakedTextureFace.TextureID.ToString(), out asset);
  241. if (asset != null && asset.Local)
  242. {
  243. // cache does not update asset contents
  244. cache.Expire(bakedTextureFace.TextureID.ToString());
  245. // Replace an HG ID with the simple asset ID so that we can persist textures for foreign HG avatars
  246. asset.ID = asset.FullID.ToString();
  247. asset.Temporary = false;
  248. asset.Local = false;
  249. m_scene.AssetService.Store(asset);
  250. }
  251. if (asset == null)
  252. {
  253. m_log.WarnFormat(
  254. "[AV FACTORY]: Baked texture id {0} not found for bake {1} for avatar {2} in {3} when trying to save permanently",
  255. bakedTextureFace.TextureID, bakeType, sp.Name, m_scene.RegionInfo.RegionName);
  256. }
  257. }
  258. return true;
  259. }
  260. /// <summary>
  261. /// Queue up a request to send appearance.
  262. /// </summary>
  263. /// <remarks>
  264. /// Makes it possible to accumulate changes without sending out each one separately.
  265. /// </remarks>
  266. /// <param name="agentId"></param>
  267. public void QueueAppearanceSend(UUID agentid)
  268. {
  269. // m_log.DebugFormat("[AVFACTORY]: Queue appearance send for {0}", agentid);
  270. // 10000 ticks per millisecond, 1000 milliseconds per second
  271. long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_sendtime * 1000 * 10000);
  272. m_sendqueue[agentid] = timestamp;
  273. m_updateTimer.Start();
  274. }
  275. public void QueueAppearanceSave(UUID agentid)
  276. {
  277. // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
  278. // 10000 ticks per millisecond, 1000 milliseconds per second
  279. long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
  280. m_savequeue[agentid] = timestamp;
  281. m_updateTimer.Start();
  282. }
  283. // called on textures update
  284. public bool UpdateBakedTextureCache(IScenePresence sp, WearableCacheItem[] cacheItems)
  285. {
  286. if(cacheItems == null || cacheItems.Length == 0)
  287. return false;
  288. // npcs dont have baked cache
  289. if (((ScenePresence)sp).IsNPC)
  290. return true;
  291. // uploaded baked textures will be in assets local cache
  292. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  293. int validDirtyBakes = 0;
  294. int hits = 0;
  295. // our main cacheIDs mapper is p.Appearance.WearableCacheItems
  296. bool hadSkirt = false;
  297. WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
  298. if (wearableCache == null)
  299. wearableCache = WearableCacheItem.GetDefaultCacheItem();
  300. else
  301. {
  302. hadSkirt = (wearableCache[19].TextureID != UUID.Zero);
  303. }
  304. HashSet<uint> updatedFaces = new HashSet<uint>();
  305. List<UUID> missing = new List<UUID>();
  306. // Process received baked textures
  307. for (int i = 0; i < cacheItems.Length; i++)
  308. {
  309. uint idx = cacheItems[i].TextureIndex;
  310. if(idx >= AvatarAppearance.TEXTURE_COUNT)
  311. {
  312. hits++;
  313. continue;
  314. }
  315. updatedFaces.Add(idx);
  316. wearableCache[idx].TextureAsset = null; // just in case
  317. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  318. if (face == null || face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  319. {
  320. wearableCache[idx].CacheId = UUID.Zero;
  321. wearableCache[idx].TextureID = UUID.Zero;
  322. if (idx == 19)
  323. {
  324. hits++;
  325. if(hadSkirt)
  326. validDirtyBakes++;
  327. }
  328. continue;
  329. }
  330. if (cache != null)
  331. {
  332. AssetBase asb = null;
  333. cache.Get(face.TextureID.ToString(), out asb);
  334. wearableCache[idx].TextureAsset = asb;
  335. }
  336. if (wearableCache[idx].TextureAsset != null)
  337. {
  338. if ( wearableCache[idx].TextureID != face.TextureID ||
  339. wearableCache[idx].CacheId != cacheItems[i].CacheId)
  340. validDirtyBakes++;
  341. wearableCache[idx].TextureID = face.TextureID;
  342. wearableCache[idx].CacheId = cacheItems[i].CacheId;
  343. hits++;
  344. }
  345. else
  346. {
  347. wearableCache[idx].CacheId = UUID.Zero;
  348. wearableCache[idx].TextureID = UUID.Zero;
  349. missing.Add(face.TextureID);
  350. continue;
  351. }
  352. }
  353. // this may be a current fs bug
  354. for (int i = AvatarAppearance.BAKES_COUNT_PV7; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  355. {
  356. uint idx = AvatarAppearance.BAKE_INDICES[i];
  357. if(updatedFaces.Contains(idx))
  358. continue;
  359. sp.Appearance.Texture.FaceTextures[idx] = null;
  360. wearableCache[idx].CacheId = UUID.Zero;
  361. wearableCache[idx].TextureID = UUID.Zero;
  362. wearableCache[idx].TextureAsset = null;
  363. }
  364. sp.Appearance.WearableCacheItems = wearableCache;
  365. if (missing.Count > 0)
  366. {
  367. foreach (UUID id in missing)
  368. sp.ControllingClient.SendRebakeAvatarTextures(id);
  369. }
  370. bool changed = false;
  371. if (validDirtyBakes > 0 && hits == cacheItems.Length)
  372. {
  373. // if we got a full set of baked textures save all in BakedTextureModule
  374. IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
  375. if (m_BakedTextureModule != null)
  376. {
  377. m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}",
  378. hits.ToString(), validDirtyBakes.ToString(), missing.Count);
  379. m_BakedTextureModule.Store(sp.UUID, wearableCache);
  380. changed = true;
  381. }
  382. }
  383. else
  384. m_log.DebugFormat("[UpdateBakedCache] cache hits: {0} changed entries: {1} rebakes {2}",
  385. hits.ToString(), validDirtyBakes.ToString(), missing.Count);
  386. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  387. {
  388. int j = AvatarAppearance.BAKE_INDICES[iter];
  389. sp.Appearance.WearableCacheItems[j].TextureAsset = null;
  390. // m_log.Debug("[UpdateBCache] {" + iter + "/" +
  391. // sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" +
  392. // sp.Appearance.WearableCacheItems[j].CacheId + ", t-" +
  393. // sp.Appearance.WearableCacheItems[j].TextureID);
  394. }
  395. return changed;
  396. }
  397. // called when we get a new root avatar
  398. public bool ValidateBakedTextureCache(IScenePresence sp)
  399. {
  400. if (((ScenePresence)sp).IsNPC)
  401. return true;
  402. int hits = 0;
  403. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  404. if (cache == null)
  405. return false;
  406. IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
  407. lock (m_setAppearanceLock)
  408. {
  409. WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
  410. // big debug
  411. // m_log.DebugFormat("[AVFACTORY]: ValidateBakedTextureCache start for {0} {1}", sp.Name, sp.UUID);
  412. /*
  413. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  414. {
  415. int j = AvatarAppearance.BAKE_INDICES[iter];
  416. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[j];
  417. if (wearableCache == null)
  418. {
  419. if (face != null)
  420. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- " + face.TextureID);
  421. else
  422. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- No texture");
  423. }
  424. else
  425. {
  426. if (face != null)
  427. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " ft- " + face.TextureID +
  428. "}: cc-" +
  429. wearableCache[j].CacheId + ", ct-" +
  430. wearableCache[j].TextureID
  431. );
  432. else
  433. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - No texture" +
  434. "}: cc-" +
  435. wearableCache[j].CacheId + ", ct-" +
  436. wearableCache[j].TextureID
  437. );
  438. }
  439. }
  440. */
  441. bool wearableCacheValid = false;
  442. if (wearableCache == null)
  443. {
  444. wearableCache = WearableCacheItem.GetDefaultCacheItem();
  445. }
  446. else
  447. {
  448. wearableCacheValid = true;
  449. Primitive.TextureEntryFace face;
  450. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  451. {
  452. int idx = AvatarAppearance.BAKE_INDICES[i];
  453. face = sp.Appearance.Texture.FaceTextures[idx];
  454. if(face == null || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  455. {
  456. wearableCache[idx].CacheId = UUID.Zero;
  457. wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
  458. hits++;
  459. continue;
  460. }
  461. if (face.TextureID == wearableCache[idx].TextureID &&
  462. face.TextureID != UUID.Zero)
  463. {
  464. if (cache.Check((wearableCache[idx].TextureID).ToString()))
  465. {
  466. hits++;
  467. continue;
  468. }
  469. }
  470. wearableCache[idx].CacheId = UUID.Zero;
  471. wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
  472. wearableCacheValid = false;
  473. }
  474. }
  475. bool checkExternal = false;
  476. if (!wearableCacheValid)
  477. checkExternal = bakedModule != null;
  478. if (checkExternal)
  479. {
  480. WearableCacheItem[] bakedModuleCache = null;
  481. hits = 0;
  482. // m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule");
  483. try
  484. {
  485. bakedModuleCache = bakedModule.Get(sp.UUID);
  486. }
  487. catch (Exception e)
  488. {
  489. m_log.ErrorFormat(e.ToString());
  490. bakedModuleCache = null;
  491. }
  492. if (bakedModuleCache != null)
  493. {
  494. m_log.Debug("[ValidateBakedCache] got bakedModule " + bakedModuleCache.Length + " cached textures");
  495. for (int i = 0; i < bakedModuleCache.Length; i++)
  496. {
  497. int j = (int)bakedModuleCache[i].TextureIndex;
  498. if (j < AvatarAppearance.TEXTURE_COUNT && bakedModuleCache[i].TextureAsset != null)
  499. {
  500. wearableCache[j].TextureID = bakedModuleCache[i].TextureID;
  501. wearableCache[j].CacheId = bakedModuleCache[i].CacheId;
  502. wearableCache[j].TextureAsset = bakedModuleCache[i].TextureAsset;
  503. bakedModuleCache[i].TextureAsset.Temporary = true;
  504. bakedModuleCache[i].TextureAsset.Local = true;
  505. cache.Cache(bakedModuleCache[i].TextureAsset);
  506. }
  507. }
  508. // force the ones we got
  509. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  510. {
  511. int idx = AvatarAppearance.BAKE_INDICES[i];
  512. if (wearableCache[idx].TextureAsset == null)
  513. {
  514. if(idx == 19)
  515. {
  516. sp.Appearance.Texture.FaceTextures[idx] = null;
  517. hits++;
  518. }
  519. else if(sp.Appearance.Texture.FaceTextures[idx] == null ||
  520. sp.Appearance.Texture.FaceTextures[idx].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  521. hits++;
  522. wearableCache[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
  523. wearableCache[idx].CacheId = UUID.Zero;
  524. continue;
  525. }
  526. Primitive.TextureEntryFace face = sp.Appearance.Texture.GetFace((uint)idx);
  527. face.TextureID = wearableCache[idx].TextureID;
  528. hits++;
  529. wearableCache[idx].TextureAsset = null;
  530. }
  531. }
  532. }
  533. sp.Appearance.WearableCacheItems = wearableCache;
  534. }
  535. // debug
  536. // m_log.DebugFormat("[ValidateBakedCache]: Completed texture check for {0} {1} with {2} hits", sp.Name, sp.UUID, hits);
  537. /*
  538. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  539. {
  540. int j = AvatarAppearance.BAKE_INDICES[iter];
  541. m_log.Debug("[ValidateBakedCache] {" + iter + "/" +
  542. sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" +
  543. sp.Appearance.WearableCacheItems[j].CacheId + ", t-" +
  544. sp.Appearance.WearableCacheItems[j].TextureID);
  545. }
  546. */
  547. return (hits >= AvatarAppearance.BAKE_INDICES.Length); // skirt is optional
  548. }
  549. public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
  550. {
  551. if (((ScenePresence)sp).IsNPC)
  552. return 0;
  553. int texturesRebaked = 0;
  554. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  555. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  556. {
  557. int idx = AvatarAppearance.BAKE_INDICES[i];
  558. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  559. // if there is no texture entry, skip it
  560. if (face == null)
  561. continue;
  562. if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  563. continue;
  564. if (missingTexturesOnly)
  565. {
  566. if (cache != null && cache.Check(face.TextureID.ToString()))
  567. {
  568. continue;
  569. }
  570. else
  571. {
  572. m_log.DebugFormat(
  573. "[AVFACTORY]: Missing baked texture {0} ({1}) for {2}, requesting rebake.",
  574. face.TextureID, idx, sp.Name);
  575. }
  576. }
  577. else
  578. {
  579. m_log.DebugFormat(
  580. "[AVFACTORY]: Requesting rebake of {0} ({1}) for {2}.",
  581. face.TextureID, idx, sp.Name);
  582. }
  583. texturesRebaked++;
  584. sp.ControllingClient.SendRebakeAvatarTextures(face.TextureID);
  585. }
  586. return texturesRebaked;
  587. }
  588. #endregion
  589. #region AvatarFactoryModule private methods
  590. private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp)
  591. {
  592. if (sp.IsChildAgent)
  593. return new Dictionary<BakeType, Primitive.TextureEntryFace>();
  594. Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures
  595. = new Dictionary<BakeType, Primitive.TextureEntryFace>();
  596. AvatarAppearance appearance = sp.Appearance;
  597. Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures;
  598. foreach (int i in Enum.GetValues(typeof(BakeType)))
  599. {
  600. BakeType bakeType = (BakeType)i;
  601. if (bakeType == BakeType.NumberOfEntries)
  602. break;
  603. if (bakeType == BakeType.Unknown)
  604. continue;
  605. // m_log.DebugFormat(
  606. // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
  607. // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
  608. int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType);
  609. Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture
  610. bakedTextures[bakeType] = texture;
  611. }
  612. return bakedTextures;
  613. }
  614. private void HandleAppearanceUpdateTimer(object sender, EventArgs ea)
  615. {
  616. if(Monitor.TryEnter(m_updatesLock))
  617. {
  618. UUID id;
  619. long now = DateTime.Now.Ticks;
  620. foreach (KeyValuePair<UUID, long> kvp in m_sendqueue)
  621. {
  622. long sendTime = kvp.Value;
  623. if (sendTime > now)
  624. continue;
  625. id = kvp.Key;
  626. m_sendqueue.TryRemove(id, out sendTime);
  627. SendAppearance(id);
  628. }
  629. if(m_updatesbusy == 0)
  630. {
  631. m_updatesbusy = -1;
  632. List<UUID> saves = new List<UUID>(m_savequeue.Count);
  633. foreach (KeyValuePair<UUID, long> kvp in m_savequeue)
  634. {
  635. long sendTime = kvp.Value;
  636. if (sendTime > now)
  637. continue;
  638. id = kvp.Key;
  639. m_savequeue.TryRemove(id, out sendTime);
  640. saves.Add(id);
  641. }
  642. m_updatesbusy = 0;
  643. if (saves.Count > 0)
  644. {
  645. ++m_updatesbusy;
  646. WorkManager.RunInThreadPool(
  647. delegate
  648. {
  649. SaveAppearance(saves);
  650. saves = null;
  651. --m_updatesbusy;
  652. }, null, string.Format("SaveAppearance ({0})", m_scene.Name));
  653. }
  654. }
  655. if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
  656. m_updateTimer.Stop();
  657. Monitor.Exit(m_updatesLock);
  658. }
  659. }
  660. private void SaveAppearance(List<UUID> ids)
  661. {
  662. // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
  663. foreach(UUID id in ids)
  664. {
  665. ScenePresence sp = m_scene.GetScenePresence(id);
  666. if(sp == null)
  667. continue;
  668. // This could take awhile since it needs to pull inventory
  669. // 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
  670. // assets and item asset id changes to complete.
  671. // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
  672. // multiple save requests.
  673. SetAppearanceAssets(id, sp.Appearance);
  674. m_scene.AvatarService.SetAppearance(id, sp.Appearance);
  675. //m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
  676. }
  677. }
  678. /// <summary>
  679. /// For a given set of appearance items, check whether the items are valid and add their asset IDs to
  680. /// appearance data.
  681. /// </summary>
  682. /// <param name='userID'></param>
  683. /// <param name='appearance'></param>
  684. private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
  685. {
  686. IInventoryService invService = m_scene.InventoryService;
  687. if (invService.GetRootFolder(userID) != null)
  688. {
  689. for (int i = 0; i < appearance.Wearables.Length; i++)
  690. {
  691. for (int j = 0; j < appearance.Wearables[i].Count; j++)
  692. {
  693. if (appearance.Wearables[i][j].ItemID == UUID.Zero)
  694. {
  695. m_log.WarnFormat(
  696. "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.",
  697. i, j, userID);
  698. continue;
  699. }
  700. // Ignore ruth's assets
  701. if (i < AvatarWearable.DefaultWearables.Length)
  702. {
  703. if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
  704. continue;
  705. }
  706. InventoryItemBase baseItem = invService.GetItem(userID, appearance.Wearables[i][j].ItemID);
  707. if (baseItem != null)
  708. {
  709. appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
  710. }
  711. else
  712. {
  713. m_log.WarnFormat(
  714. "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
  715. appearance.Wearables[i][j].ItemID, (WearableType)i);
  716. appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID);
  717. }
  718. }
  719. }
  720. }
  721. else
  722. {
  723. m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
  724. }
  725. // IInventoryService invService = m_scene.InventoryService;
  726. // bool resetwearable = false;
  727. // if (invService.GetRootFolder(userID) != null)
  728. // {
  729. // for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
  730. // {
  731. // for (int j = 0; j < appearance.Wearables[i].Count; j++)
  732. // {
  733. // // Check if the default wearables are not set
  734. // if (appearance.Wearables[i][j].ItemID == UUID.Zero)
  735. // {
  736. // switch ((WearableType) i)
  737. // {
  738. // case WearableType.Eyes:
  739. // case WearableType.Hair:
  740. // case WearableType.Shape:
  741. // case WearableType.Skin:
  742. // //case WearableType.Underpants:
  743. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  744. // resetwearable = true;
  745. // m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values.");
  746. // resetwearable = true;
  747. // break;
  748. //
  749. // }
  750. // continue;
  751. // }
  752. //
  753. // // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1
  754. // if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
  755. // {
  756. // switch ((WearableType)i)
  757. // {
  758. // case WearableType.Eyes:
  759. // case WearableType.Hair:
  760. // case WearableType.Shape:
  761. // case WearableType.Skin:
  762. // //case WearableType.Underpants:
  763. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  764. //
  765. // m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i);
  766. // resetwearable = true;
  767. // break;
  768. //
  769. // }
  770. // continue;
  771. // }
  772. //
  773. // InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
  774. // baseItem = invService.GetItem(baseItem);
  775. //
  776. // if (baseItem != null)
  777. // {
  778. // appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
  779. // int unmodifiedWearableIndexForClosure = i;
  780. // m_scene.AssetService.Get(baseItem.AssetID.ToString(), this,
  781. // delegate(string x, object y, AssetBase z)
  782. // {
  783. // if (z == null)
  784. // {
  785. // TryAndRepairBrokenWearable(
  786. // (WearableType)unmodifiedWearableIndexForClosure, invService,
  787. // userID, appearance);
  788. // }
  789. // });
  790. // }
  791. // else
  792. // {
  793. // m_log.ErrorFormat(
  794. // "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
  795. // appearance.Wearables[i][j].ItemID, (WearableType)i);
  796. //
  797. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  798. // resetwearable = true;
  799. //
  800. // }
  801. // }
  802. // }
  803. //
  804. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  805. // if (appearance.Wearables[(int) WearableType.Eyes] == null)
  806. // {
  807. // m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes));
  808. //
  809. // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
  810. // resetwearable = true;
  811. // }
  812. // else
  813. // {
  814. // if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero)
  815. // {
  816. // m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}",
  817. // appearance.Wearables[(int) WearableType.Eyes][0].ItemID,
  818. // appearance.Wearables[(int) WearableType.Eyes][0].AssetID);
  819. // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
  820. // resetwearable = true;
  821. //
  822. // }
  823. //
  824. // }
  825. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  826. // if (appearance.Wearables[(int)WearableType.Shape] == null)
  827. // {
  828. // m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape));
  829. //
  830. // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
  831. // resetwearable = true;
  832. // }
  833. // else
  834. // {
  835. // if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero)
  836. // {
  837. // m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}",
  838. // appearance.Wearables[(int)WearableType.Shape][0].ItemID,
  839. // appearance.Wearables[(int)WearableType.Shape][0].AssetID);
  840. // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
  841. // resetwearable = true;
  842. //
  843. // }
  844. //
  845. // }
  846. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  847. // if (appearance.Wearables[(int)WearableType.Hair] == null)
  848. // {
  849. // m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair));
  850. //
  851. // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
  852. // resetwearable = true;
  853. // }
  854. // else
  855. // {
  856. // if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero)
  857. // {
  858. // m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}",
  859. // appearance.Wearables[(int)WearableType.Hair][0].ItemID,
  860. // appearance.Wearables[(int)WearableType.Hair][0].AssetID);
  861. // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
  862. // resetwearable = true;
  863. //
  864. // }
  865. //
  866. // }
  867. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  868. // if (appearance.Wearables[(int)WearableType.Skin] == null)
  869. // {
  870. // m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin));
  871. //
  872. // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
  873. // resetwearable = true;
  874. // }
  875. // else
  876. // {
  877. // if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero)
  878. // {
  879. // m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}",
  880. // appearance.Wearables[(int)WearableType.Skin][0].ItemID,
  881. // appearance.Wearables[(int)WearableType.Skin][0].AssetID);
  882. // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
  883. // resetwearable = true;
  884. //
  885. // }
  886. //
  887. // }
  888. // if (resetwearable)
  889. // {
  890. // ScenePresence presence = null;
  891. // if (m_scene.TryGetScenePresence(userID, out presence))
  892. // {
  893. // presence.ControllingClient.SendWearables(presence.Appearance.Wearables,
  894. // presence.Appearance.Serial++);
  895. // }
  896. // }
  897. //
  898. // }
  899. // else
  900. // {
  901. // m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
  902. // }
  903. }
  904. private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance)
  905. {
  906. UUID defaultwearable = GetDefaultItem(type);
  907. if (defaultwearable != UUID.Zero)
  908. {
  909. UUID newInvItem = UUID.Random();
  910. InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID)
  911. {
  912. AssetID = defaultwearable,
  913. AssetType = (int)FolderType.BodyPart,
  914. CreatorId = userID.ToString(),
  915. //InvType = (int)InventoryType.Wearable,
  916. Description = "Failed Wearable Replacement",
  917. Folder = invService.GetFolderForType(userID, FolderType.BodyPart).ID,
  918. Flags = (uint) type, Name = Enum.GetName(typeof (WearableType), type),
  919. BasePermissions = (uint) PermissionMask.Copy,
  920. CurrentPermissions = (uint) PermissionMask.Copy,
  921. EveryOnePermissions = (uint) PermissionMask.Copy,
  922. GroupPermissions = (uint) PermissionMask.Copy,
  923. NextPermissions = (uint) PermissionMask.Copy
  924. };
  925. invService.AddItem(itembase);
  926. UUID LinkInvItem = UUID.Random();
  927. itembase = new InventoryItemBase(LinkInvItem, userID)
  928. {
  929. AssetID = newInvItem,
  930. AssetType = (int)AssetType.Link,
  931. CreatorId = userID.ToString(),
  932. InvType = (int) InventoryType.Wearable,
  933. Description = "Failed Wearable Replacement",
  934. Folder = invService.GetFolderForType(userID, FolderType.CurrentOutfit).ID,
  935. Flags = (uint) type,
  936. Name = Enum.GetName(typeof (WearableType), type),
  937. BasePermissions = (uint) PermissionMask.Copy,
  938. CurrentPermissions = (uint) PermissionMask.Copy,
  939. EveryOnePermissions = (uint) PermissionMask.Copy,
  940. GroupPermissions = (uint) PermissionMask.Copy,
  941. NextPermissions = (uint) PermissionMask.Copy
  942. };
  943. invService.AddItem(itembase);
  944. appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type));
  945. ScenePresence presence = null;
  946. if (m_scene.TryGetScenePresence(userID, out presence))
  947. {
  948. m_scene.SendInventoryUpdate(presence.ControllingClient,
  949. invService.GetFolderForType(userID, FolderType.CurrentOutfit), false, true);
  950. }
  951. }
  952. }
  953. private UUID GetDefaultItem(WearableType wearable)
  954. {
  955. // These are ruth
  956. UUID ret = UUID.Zero;
  957. switch (wearable)
  958. {
  959. case WearableType.Eyes:
  960. ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7");
  961. break;
  962. case WearableType.Hair:
  963. ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66");
  964. break;
  965. case WearableType.Pants:
  966. ret = new UUID("00000000-38f9-1111-024e-222222111120");
  967. break;
  968. case WearableType.Shape:
  969. ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
  970. break;
  971. case WearableType.Shirt:
  972. ret = new UUID("00000000-38f9-1111-024e-222222111110");
  973. break;
  974. case WearableType.Skin:
  975. ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb");
  976. break;
  977. case WearableType.Undershirt:
  978. ret = new UUID("16499ebb-3208-ec27-2def-481881728f47");
  979. break;
  980. case WearableType.Underpants:
  981. ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d");
  982. break;
  983. }
  984. return ret;
  985. }
  986. #endregion
  987. #region Client Event Handlers
  988. /// <summary>
  989. /// Tell the client for this scene presence what items it should be wearing now
  990. /// </summary>
  991. /// <param name="client"></param>
  992. private void Client_OnRequestWearables(IClientAPI client)
  993. {
  994. Util.FireAndForget(delegate(object x)
  995. {
  996. Thread.Sleep(4000);
  997. // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId);
  998. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  999. if (sp != null)
  1000. client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++);
  1001. else
  1002. m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId);
  1003. }, null, "AvatarFactoryModule.OnClientRequestWearables");
  1004. }
  1005. /// <summary>
  1006. /// Set appearance data (texture asset IDs and slider settings) received from a client
  1007. /// </summary>
  1008. /// <param name="client"></param>
  1009. /// <param name="texture"></param>
  1010. /// <param name="visualParam"></param>
  1011. private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
  1012. {
  1013. // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
  1014. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1015. if (sp != null)
  1016. SetAppearance(sp, textureEntry, visualParams, avSize, cacheItems);
  1017. else
  1018. m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
  1019. }
  1020. /// <summary>
  1021. /// Update what the avatar is wearing using an item from their inventory.
  1022. /// </summary>
  1023. /// <param name="client"></param>
  1024. /// <param name="e"></param>
  1025. private void Client_OnAvatarNowWearing(IClientAPI client, AvatarWearingArgs e)
  1026. {
  1027. // m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing called for {0} ({1})", client.Name, client.AgentId);
  1028. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1029. if (sp == null)
  1030. {
  1031. m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing unable to find presence for {0}", client.AgentId);
  1032. return;
  1033. }
  1034. // operate on a copy of the appearance so we don't have to lock anything yet
  1035. AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false);
  1036. foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
  1037. {
  1038. // If the wearable type is larger than the current array, expand it
  1039. if (avatAppearance.Wearables.Length <= wear.Type)
  1040. {
  1041. int currentLength = avatAppearance.Wearables.Length;
  1042. AvatarWearable[] wears = avatAppearance.Wearables;
  1043. Array.Resize(ref wears, wear.Type + 1);
  1044. for (int i = currentLength ; i <= wear.Type ; i++)
  1045. wears[i] = new AvatarWearable();
  1046. avatAppearance.Wearables = wears;
  1047. }
  1048. avatAppearance.Wearables[wear.Type].Add(wear.ItemID, UUID.Zero);
  1049. }
  1050. avatAppearance.GetAssetsFrom(sp.Appearance);
  1051. lock (m_setAppearanceLock)
  1052. {
  1053. // Update only those fields that we have changed. This is important because the viewer
  1054. // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing
  1055. // shouldn't overwrite the changes made in SetAppearance.
  1056. sp.Appearance.Wearables = avatAppearance.Wearables;
  1057. // We don't need to send the appearance here since the "iswearing" will trigger a new set
  1058. // of visual param and baked texture changes. When those complete, the new appearance will be sent
  1059. QueueAppearanceSave(client.AgentId);
  1060. }
  1061. }
  1062. /*
  1063. /// <summary>
  1064. /// Respond to the cached textures request from the client
  1065. /// </summary>
  1066. /// <param name="client"></param>
  1067. /// <param name="serial"></param>
  1068. /// <param name="cachedTextureRequest"></param>
  1069. private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest)
  1070. {
  1071. // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId);
  1072. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1073. List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
  1074. foreach (CachedTextureRequestArg request in cachedTextureRequest)
  1075. {
  1076. UUID texture = UUID.Zero;
  1077. int index = request.BakedTextureIndex;
  1078. if (m_reusetextures)
  1079. {
  1080. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
  1081. if (face != null)
  1082. texture = face.TextureID;
  1083. }
  1084. CachedTextureResponseArg response = new CachedTextureResponseArg();
  1085. response.BakedTextureIndex = index;
  1086. response.BakedTextureID = texture;
  1087. response.HostName = null;
  1088. cachedTextureResponse.Add(response);
  1089. }
  1090. client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
  1091. }
  1092. */
  1093. #endregion
  1094. public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
  1095. {
  1096. outputAction("For {0} in {1}", null, sp.Name, m_scene.RegionInfo.RegionName);
  1097. outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, "Bake Type", "UUID");
  1098. Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID);
  1099. foreach (BakeType bt in bakedTextures.Keys)
  1100. {
  1101. string rawTextureID;
  1102. if (bakedTextures[bt] == null)
  1103. {
  1104. rawTextureID = "not set";
  1105. }
  1106. else
  1107. {
  1108. if(bakedTextures[bt].TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  1109. rawTextureID = "not set";
  1110. else
  1111. {
  1112. rawTextureID = bakedTextures[bt].TextureID.ToString();
  1113. if (m_scene.AssetService.Get(rawTextureID) == null)
  1114. rawTextureID += " (not found)";
  1115. else
  1116. rawTextureID += " (uploaded)";
  1117. }
  1118. }
  1119. outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID);
  1120. }
  1121. bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
  1122. outputAction("{0} baked appearance texture is {1}", null, sp.Name, bakedTextureValid ? "OK" : "incomplete");
  1123. }
  1124. public void SetPreferencesHoverZ(UUID agentId, float val)
  1125. {
  1126. ScenePresence sp = m_scene.GetScenePresence(agentId);
  1127. if (sp == null || sp.IsDeleted || sp.IsNPC || sp.IsInTransit)
  1128. return;
  1129. float last = sp.Appearance.AvatarPreferencesHoverZ;
  1130. if(val != last)
  1131. {
  1132. sp.Appearance.AvatarPreferencesHoverZ = val;
  1133. //sp.SendAppearanceToAgentNF(sp);
  1134. QueueAppearanceSend(agentId);
  1135. }
  1136. }
  1137. }
  1138. }