AvatarFactoryModule.cs 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380
  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.Reflection;
  30. using System.Threading;
  31. using System.Text;
  32. using System.Timers;
  33. using log4net;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenSim.Framework;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Services.Interfaces;
  40. using Mono.Addins;
  41. using PermissionMask = OpenSim.Framework.PermissionMask;
  42. namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
  43. {
  44. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarFactoryModule")]
  45. public class AvatarFactoryModule : IAvatarFactoryModule, INonSharedRegionModule
  46. {
  47. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  48. public const string BAKED_TEXTURES_REPORT_FORMAT = "{0,-9} {1}";
  49. private Scene m_scene = null;
  50. private int m_savetime = 5; // seconds to wait before saving changed appearance
  51. private int m_sendtime = 2; // seconds to wait before sending changed appearance
  52. private bool m_reusetextures = false;
  53. private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates
  54. private System.Timers.Timer m_updateTimer = new System.Timers.Timer();
  55. private Dictionary<UUID,long> m_savequeue = new Dictionary<UUID,long>();
  56. private Dictionary<UUID,long> m_sendqueue = new Dictionary<UUID,long>();
  57. private object m_setAppearanceLock = new object();
  58. #region Region Module interface
  59. public void Initialise(IConfigSource config)
  60. {
  61. IConfig appearanceConfig = config.Configs["Appearance"];
  62. if (appearanceConfig != null)
  63. {
  64. m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime)));
  65. m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime)));
  66. m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures);
  67. // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime);
  68. }
  69. }
  70. public void AddRegion(Scene scene)
  71. {
  72. if (m_scene == null)
  73. m_scene = scene;
  74. scene.RegisterModuleInterface<IAvatarFactoryModule>(this);
  75. scene.EventManager.OnNewClient += SubscribeToClientEvents;
  76. }
  77. public void RemoveRegion(Scene scene)
  78. {
  79. if (scene == m_scene)
  80. {
  81. scene.UnregisterModuleInterface<IAvatarFactoryModule>(this);
  82. scene.EventManager.OnNewClient -= SubscribeToClientEvents;
  83. }
  84. m_scene = null;
  85. }
  86. public void RegionLoaded(Scene scene)
  87. {
  88. m_updateTimer.Enabled = false;
  89. m_updateTimer.AutoReset = true;
  90. m_updateTimer.Interval = m_checkTime; // 500 milliseconds wait to start async ops
  91. m_updateTimer.Elapsed += new ElapsedEventHandler(HandleAppearanceUpdateTimer);
  92. }
  93. public void Close()
  94. {
  95. }
  96. public string Name
  97. {
  98. get { return "Default Avatar Factory"; }
  99. }
  100. public bool IsSharedModule
  101. {
  102. get { return false; }
  103. }
  104. public Type ReplaceableInterface
  105. {
  106. get { return null; }
  107. }
  108. private void SubscribeToClientEvents(IClientAPI client)
  109. {
  110. client.OnRequestWearables += Client_OnRequestWearables;
  111. client.OnSetAppearance += Client_OnSetAppearance;
  112. client.OnAvatarNowWearing += Client_OnAvatarNowWearing;
  113. client.OnCachedTextureRequest += Client_OnCachedTextureRequest;
  114. }
  115. #endregion
  116. #region IAvatarFactoryModule
  117. /// </summary>
  118. /// <param name="sp"></param>
  119. /// <param name="texture"></param>
  120. /// <param name="visualParam"></param>
  121. public void SetAppearance(IScenePresence sp, AvatarAppearance appearance, WearableCacheItem[] cacheItems)
  122. {
  123. SetAppearance(sp, appearance.Texture, appearance.VisualParams, cacheItems);
  124. }
  125. public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
  126. {
  127. float oldoff = sp.Appearance.AvatarFeetOffset;
  128. Vector3 oldbox = sp.Appearance.AvatarBoxSize;
  129. SetAppearance(sp, textureEntry, visualParams, cacheItems);
  130. sp.Appearance.SetSize(avSize);
  131. float off = sp.Appearance.AvatarFeetOffset;
  132. Vector3 box = sp.Appearance.AvatarBoxSize;
  133. if (oldoff != off || oldbox != box)
  134. ((ScenePresence)sp).SetSize(box, off);
  135. }
  136. /// <summary>
  137. /// Set appearance data (texture asset IDs and slider settings)
  138. /// </summary>
  139. /// <param name="sp"></param>
  140. /// <param name="texture"></param>
  141. /// <param name="visualParam"></param>
  142. public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams, WearableCacheItem[] cacheItems)
  143. {
  144. // m_log.DebugFormat(
  145. // "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
  146. // sp.Name, textureEntry, visualParams);
  147. // TODO: This is probably not necessary any longer, just assume the
  148. // textureEntry set implies that the appearance transaction is complete
  149. bool changed = false;
  150. // Process the texture entry transactionally, this doesn't guarantee that Appearance is
  151. // going to be handled correctly but it does serialize the updates to the appearance
  152. lock (m_setAppearanceLock)
  153. {
  154. // Process the visual params, this may change height as well
  155. if (visualParams != null)
  156. {
  157. changed = sp.Appearance.SetVisualParams(visualParams);
  158. }
  159. // Process the baked texture array
  160. if (textureEntry != null)
  161. {
  162. m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
  163. // WriteBakedTexturesReport(sp, m_log.DebugFormat);
  164. changed = sp.Appearance.SetTextureEntries(textureEntry) || changed;
  165. // WriteBakedTexturesReport(sp, m_log.DebugFormat);
  166. UpdateBakedTextureCache(sp, cacheItems);
  167. // This appears to be set only in the final stage of the appearance
  168. // update transaction. In theory, we should be able to do an immediate
  169. // appearance send and save here.
  170. }
  171. // NPC should send to clients immediately and skip saving appearance
  172. if (((ScenePresence)sp).PresenceType == PresenceType.Npc)
  173. {
  174. SendAppearance((ScenePresence)sp);
  175. return;
  176. }
  177. // save only if there were changes, send no matter what (doesn't hurt to send twice)
  178. if (changed)
  179. QueueAppearanceSave(sp.ControllingClient.AgentId);
  180. QueueAppearanceSend(sp.ControllingClient.AgentId);
  181. }
  182. // m_log.WarnFormat("[AVFACTORY]: complete SetAppearance for {0}:\n{1}",client.AgentId,sp.Appearance.ToString());
  183. }
  184. private void SendAppearance(ScenePresence sp)
  185. {
  186. // Send the appearance to everyone in the scene
  187. sp.SendAppearanceToAllOtherAgents();
  188. // Send animations back to the avatar as well
  189. sp.Animator.SendAnimPack();
  190. }
  191. public bool SendAppearance(UUID agentId)
  192. {
  193. // m_log.DebugFormat("[AVFACTORY]: Sending appearance for {0}", agentId);
  194. ScenePresence sp = m_scene.GetScenePresence(agentId);
  195. if (sp == null)
  196. {
  197. // This is expected if the user has gone away.
  198. // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
  199. return false;
  200. }
  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)
  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. lock (m_sendqueue)
  273. {
  274. m_sendqueue[agentid] = timestamp;
  275. m_updateTimer.Start();
  276. }
  277. }
  278. public void QueueAppearanceSave(UUID agentid)
  279. {
  280. // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
  281. // 10000 ticks per millisecond, 1000 milliseconds per second
  282. long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
  283. lock (m_savequeue)
  284. {
  285. m_savequeue[agentid] = timestamp;
  286. m_updateTimer.Start();
  287. }
  288. }
  289. // called on textures update
  290. public bool UpdateBakedTextureCache(IScenePresence sp, WearableCacheItem[] cacheItems)
  291. {
  292. if(cacheItems == null)
  293. return false;
  294. // npcs dont have baked cache
  295. if (((ScenePresence)sp).IsNPC)
  296. return true;
  297. // uploaded baked textures will be in assets local cache
  298. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  299. IBakedTextureModule m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
  300. int validDirtyBakes = 0;
  301. int hits = 0;
  302. // our main cacheIDs mapper is p.Appearance.WearableCacheItems
  303. WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
  304. if (wearableCache == null)
  305. {
  306. wearableCache = WearableCacheItem.GetDefaultCacheItem();
  307. }
  308. List<UUID> missing = new List<UUID>();
  309. bool haveSkirt = (wearableCache[19].TextureID != UUID.Zero);
  310. bool haveNewSkirt = false;
  311. // Process received baked textures
  312. for (int i = 0; i < cacheItems.Length; i++)
  313. {
  314. int idx = (int)cacheItems[i].TextureIndex;
  315. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  316. // No face
  317. if (face == null)
  318. {
  319. // for some reason viewer is cleaning this
  320. if(idx != 19) // skirt is optional
  321. {
  322. sp.Appearance.Texture.FaceTextures[idx] = sp.Appearance.Texture.CreateFace((uint) idx);
  323. sp.Appearance.Texture.FaceTextures[idx].TextureID = AppearanceManager.DEFAULT_AVATAR_TEXTURE;
  324. }
  325. wearableCache[idx].CacheId = UUID.Zero;
  326. wearableCache[idx].TextureID = UUID.Zero;
  327. wearableCache[idx].TextureAsset = null;
  328. continue;
  329. }
  330. else
  331. {
  332. if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  333. {
  334. wearableCache[idx].CacheId = UUID.Zero;
  335. wearableCache[idx].TextureID = UUID.Zero;
  336. wearableCache[idx].TextureAsset = null;
  337. continue;
  338. }
  339. if(idx == 19)
  340. haveNewSkirt = true;
  341. /*
  342. if (face.TextureID == wearableCache[idx].TextureID && m_BakedTextureModule != null)
  343. {
  344. if (wearableCache[idx].CacheId != cacheItems[i].CacheId)
  345. {
  346. wearableCache[idx].CacheId = cacheItems[i].CacheId;
  347. validDirtyBakes++;
  348. //assuming this can only happen if asset is in cache
  349. }
  350. hits++;
  351. continue;
  352. }
  353. */
  354. wearableCache[idx].TextureAsset = null;
  355. if (cache != null)
  356. {
  357. AssetBase asb = null;
  358. cache.Get(face.TextureID.ToString(), out asb);
  359. wearableCache[idx].TextureAsset = asb;
  360. }
  361. if (wearableCache[idx].TextureAsset != null)
  362. {
  363. if ( wearableCache[idx].TextureID != face.TextureID ||
  364. wearableCache[idx].CacheId != cacheItems[i].CacheId)
  365. validDirtyBakes++;
  366. wearableCache[idx].TextureID = face.TextureID;
  367. wearableCache[idx].CacheId = cacheItems[i].CacheId;
  368. hits++;
  369. }
  370. else
  371. {
  372. wearableCache[idx].CacheId = UUID.Zero;
  373. wearableCache[idx].TextureID = UUID.Zero;
  374. wearableCache[idx].TextureAsset = null;
  375. missing.Add(face.TextureID);
  376. continue;
  377. }
  378. }
  379. }
  380. // handle optional skirt case
  381. if(!haveNewSkirt && haveSkirt)
  382. {
  383. wearableCache[19].CacheId = UUID.Zero;
  384. wearableCache[19].TextureID = UUID.Zero;
  385. wearableCache[19].TextureAsset = null;
  386. validDirtyBakes++;
  387. }
  388. sp.Appearance.WearableCacheItems = wearableCache;
  389. if (missing.Count > 0)
  390. {
  391. foreach (UUID id in missing)
  392. sp.ControllingClient.SendRebakeAvatarTextures(id);
  393. }
  394. if (validDirtyBakes > 0 && hits == cacheItems.Length)
  395. {
  396. // if we got a full set of baked textures save all in BakedTextureModule
  397. if (m_BakedTextureModule != null)
  398. {
  399. m_log.DebugFormat("[UpdateBakedCache] Uploading to Bakes Server: cache hits: {0} changed entries: {1} rebakes {2}",
  400. hits.ToString(), validDirtyBakes.ToString(), missing.Count);
  401. m_BakedTextureModule.Store(sp.UUID, wearableCache);
  402. }
  403. }
  404. else
  405. m_log.DebugFormat("[UpdateBakedCache] cache hits: {0} changed entries: {1} rebakes {2}",
  406. hits.ToString(), validDirtyBakes.ToString(), missing.Count);
  407. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  408. {
  409. int j = AvatarAppearance.BAKE_INDICES[iter];
  410. sp.Appearance.WearableCacheItems[j].TextureAsset = null;
  411. // m_log.Debug("[UpdateBCache] {" + iter + "/" +
  412. // sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" +
  413. // sp.Appearance.WearableCacheItems[j].CacheId + ", t-" +
  414. // sp.Appearance.WearableCacheItems[j].TextureID);
  415. }
  416. return (hits == cacheItems.Length);
  417. }
  418. // called when we get a new root avatar
  419. public bool ValidateBakedTextureCache(IScenePresence sp)
  420. {
  421. int hits = 0;
  422. if (((ScenePresence)sp).IsNPC)
  423. return true;
  424. lock (m_setAppearanceLock)
  425. {
  426. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  427. IBakedTextureModule bakedModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
  428. WearableCacheItem[] bakedModuleCache = null;
  429. if (cache == null)
  430. return false;
  431. WearableCacheItem[] wearableCache = sp.Appearance.WearableCacheItems;
  432. // big debug
  433. // m_log.DebugFormat("[AVFACTORY]: ValidateBakedTextureCache start for {0} {1}", sp.Name, sp.UUID);
  434. /*
  435. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  436. {
  437. int j = AvatarAppearance.BAKE_INDICES[iter];
  438. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[j];
  439. if (wearableCache == null)
  440. {
  441. if (face != null)
  442. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- " + face.TextureID);
  443. else
  444. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t- No texture");
  445. }
  446. else
  447. {
  448. if (face != null)
  449. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " ft- " + face.TextureID +
  450. "}: cc-" +
  451. wearableCache[j].CacheId + ", ct-" +
  452. wearableCache[j].TextureID
  453. );
  454. else
  455. m_log.Debug("[ValidateBakedCache] {" + iter + "/" + j + " t - No texture" +
  456. "}: cc-" +
  457. wearableCache[j].CacheId + ", ct-" +
  458. wearableCache[j].TextureID
  459. );
  460. }
  461. }
  462. */
  463. bool wearableCacheValid = false;
  464. if (wearableCache == null)
  465. {
  466. wearableCache = WearableCacheItem.GetDefaultCacheItem();
  467. }
  468. else
  469. {
  470. // we may have received a full cache
  471. // check same coerence and store
  472. wearableCacheValid = true;
  473. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  474. {
  475. int idx = AvatarAppearance.BAKE_INDICES[i];
  476. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  477. if (face != null)
  478. {
  479. if (face.TextureID == wearableCache[idx].TextureID &&
  480. face.TextureID != UUID.Zero)
  481. {
  482. if (wearableCache[idx].TextureAsset != null)
  483. {
  484. hits++;
  485. wearableCache[idx].TextureAsset.Temporary = true;
  486. wearableCache[idx].TextureAsset.Local = true;
  487. cache.Cache(wearableCache[idx].TextureAsset);
  488. wearableCache[idx].TextureAsset = null;
  489. continue;
  490. }
  491. if (cache.Check((wearableCache[idx].TextureID).ToString()))
  492. {
  493. hits++;
  494. continue;
  495. }
  496. }
  497. wearableCacheValid = false;
  498. }
  499. }
  500. wearableCacheValid = (wearableCacheValid && (hits >= AvatarAppearance.BAKE_INDICES.Length - 1));
  501. if (wearableCacheValid)
  502. {
  503. // m_log.Debug("[ValidateBakedCache] have valid local cache");
  504. }
  505. else
  506. wearableCache[19].TextureAsset = null; // clear optional skirt
  507. }
  508. bool checkExternal = false;
  509. if (!wearableCacheValid)
  510. {
  511. hits = 0;
  512. // only use external bake module on login condition check
  513. // ScenePresence ssp = null;
  514. // if (sp is ScenePresence)
  515. {
  516. // ssp = (ScenePresence)sp;
  517. // checkExternal = (((uint)ssp.TeleportFlags & (uint)TeleportFlags.ViaLogin) != 0) &&
  518. // bakedModule != null;
  519. // or do it anytime we dont have the cache
  520. checkExternal = bakedModule != null;
  521. }
  522. }
  523. if (checkExternal)
  524. {
  525. bool gotbacked = false;
  526. // m_log.Debug("[ValidateBakedCache] local cache invalid, checking bakedModule");
  527. try
  528. {
  529. bakedModuleCache = bakedModule.Get(sp.UUID);
  530. }
  531. catch (Exception e)
  532. {
  533. m_log.ErrorFormat(e.ToString());
  534. bakedModuleCache = null;
  535. }
  536. if (bakedModuleCache != null)
  537. {
  538. m_log.Debug("[ValidateBakedCache] got bakedModule " + bakedModuleCache.Length + " cached textures");
  539. for (int i = 0; i < bakedModuleCache.Length; i++)
  540. {
  541. int j = (int)bakedModuleCache[i].TextureIndex;
  542. if (bakedModuleCache[i].TextureAsset != null)
  543. {
  544. wearableCache[j].TextureID = bakedModuleCache[i].TextureID;
  545. wearableCache[j].CacheId = bakedModuleCache[i].CacheId;
  546. wearableCache[j].TextureAsset = bakedModuleCache[i].TextureAsset;
  547. bakedModuleCache[i].TextureAsset.Temporary = true;
  548. bakedModuleCache[i].TextureAsset.Local = true;
  549. cache.Cache(bakedModuleCache[i].TextureAsset);
  550. }
  551. }
  552. gotbacked = true;
  553. }
  554. if (gotbacked)
  555. {
  556. // force the ones we got
  557. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  558. {
  559. int idx = AvatarAppearance.BAKE_INDICES[i];
  560. if(wearableCache[idx].TextureAsset == null)
  561. {
  562. if(idx == 19)
  563. {
  564. sp.Appearance.Texture.FaceTextures[idx] = null;
  565. hits++;
  566. }
  567. continue;
  568. }
  569. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  570. if (face == null)
  571. {
  572. face = sp.Appearance.Texture.CreateFace((uint)idx);
  573. sp.Appearance.Texture.FaceTextures[idx] = face;
  574. }
  575. face.TextureID = wearableCache[idx].TextureID;
  576. hits++;
  577. wearableCache[idx].TextureAsset = null;
  578. }
  579. }
  580. }
  581. sp.Appearance.WearableCacheItems = wearableCache;
  582. }
  583. // debug
  584. // m_log.DebugFormat("[ValidateBakedCache]: Completed texture check for {0} {1} with {2} hits", sp.Name, sp.UUID, hits);
  585. /*
  586. for (int iter = 0; iter < AvatarAppearance.BAKE_INDICES.Length; iter++)
  587. {
  588. int j = AvatarAppearance.BAKE_INDICES[iter];
  589. m_log.Debug("[ValidateBakedCache] {" + iter + "/" +
  590. sp.Appearance.WearableCacheItems[j].TextureIndex + "}: c-" +
  591. sp.Appearance.WearableCacheItems[j].CacheId + ", t-" +
  592. sp.Appearance.WearableCacheItems[j].TextureID);
  593. }
  594. */
  595. return (hits >= AvatarAppearance.BAKE_INDICES.Length - 1); // skirt is optional
  596. }
  597. public int RequestRebake(IScenePresence sp, bool missingTexturesOnly)
  598. {
  599. if (((ScenePresence)sp).IsNPC)
  600. return 0;
  601. int texturesRebaked = 0;
  602. IAssetCache cache = m_scene.RequestModuleInterface<IAssetCache>();
  603. for (int i = 0; i < AvatarAppearance.BAKE_INDICES.Length; i++)
  604. {
  605. int idx = AvatarAppearance.BAKE_INDICES[i];
  606. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[idx];
  607. // if there is no texture entry, skip it
  608. if (face == null)
  609. continue;
  610. if (face.TextureID == UUID.Zero || face.TextureID == AppearanceManager.DEFAULT_AVATAR_TEXTURE)
  611. continue;
  612. if (missingTexturesOnly)
  613. {
  614. if (cache != null && cache.Check(face.TextureID.ToString()))
  615. {
  616. continue;
  617. }
  618. else
  619. {
  620. m_log.DebugFormat(
  621. "[AVFACTORY]: Missing baked texture {0} ({1}) for {2}, requesting rebake.",
  622. face.TextureID, idx, sp.Name);
  623. }
  624. }
  625. else
  626. {
  627. m_log.DebugFormat(
  628. "[AVFACTORY]: Requesting rebake of {0} ({1}) for {2}.",
  629. face.TextureID, idx, sp.Name);
  630. }
  631. texturesRebaked++;
  632. sp.ControllingClient.SendRebakeAvatarTextures(face.TextureID);
  633. }
  634. return texturesRebaked;
  635. }
  636. #endregion
  637. #region AvatarFactoryModule private methods
  638. private Dictionary<BakeType, Primitive.TextureEntryFace> GetBakedTextureFaces(ScenePresence sp)
  639. {
  640. if (sp.IsChildAgent)
  641. return new Dictionary<BakeType, Primitive.TextureEntryFace>();
  642. Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures
  643. = new Dictionary<BakeType, Primitive.TextureEntryFace>();
  644. AvatarAppearance appearance = sp.Appearance;
  645. Primitive.TextureEntryFace[] faceTextures = appearance.Texture.FaceTextures;
  646. foreach (int i in Enum.GetValues(typeof(BakeType)))
  647. {
  648. BakeType bakeType = (BakeType)i;
  649. if (bakeType == BakeType.Unknown)
  650. continue;
  651. // m_log.DebugFormat(
  652. // "[AVFACTORY]: NPC avatar {0} has texture id {1} : {2}",
  653. // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]);
  654. int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType);
  655. Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture
  656. bakedTextures[bakeType] = texture;
  657. }
  658. return bakedTextures;
  659. }
  660. private void HandleAppearanceUpdateTimer(object sender, EventArgs ea)
  661. {
  662. long now = DateTime.Now.Ticks;
  663. lock (m_sendqueue)
  664. {
  665. Dictionary<UUID, long> sends = new Dictionary<UUID, long>(m_sendqueue);
  666. foreach (KeyValuePair<UUID, long> kvp in sends)
  667. {
  668. // We have to load the key and value into local parameters to avoid a race condition if we loop
  669. // around and load kvp with a different value before FireAndForget has launched its thread.
  670. UUID avatarID = kvp.Key;
  671. long sendTime = kvp.Value;
  672. // m_log.DebugFormat("[AVFACTORY]: Handling queued appearance updates for {0}, update delta to now is {1}", avatarID, sendTime - now);
  673. if (sendTime < now)
  674. {
  675. Util.FireAndForget(o => SendAppearance(avatarID), null, "AvatarFactoryModule.SendAppearance");
  676. m_sendqueue.Remove(avatarID);
  677. }
  678. }
  679. }
  680. lock (m_savequeue)
  681. {
  682. Dictionary<UUID, long> saves = new Dictionary<UUID, long>(m_savequeue);
  683. foreach (KeyValuePair<UUID, long> kvp in saves)
  684. {
  685. // We have to load the key and value into local parameters to avoid a race condition if we loop
  686. // around and load kvp with a different value before FireAndForget has launched its thread.
  687. UUID avatarID = kvp.Key;
  688. long sendTime = kvp.Value;
  689. if (sendTime < now)
  690. {
  691. Util.FireAndForget(o => SaveAppearance(avatarID), null, "AvatarFactoryModule.SaveAppearance");
  692. m_savequeue.Remove(avatarID);
  693. }
  694. }
  695. // We must lock both queues here so that QueueAppearanceSave() or *Send() don't m_updateTimer.Start() on
  696. // another thread inbetween the first count calls and m_updateTimer.Stop() on this thread.
  697. lock (m_sendqueue)
  698. if (m_savequeue.Count == 0 && m_sendqueue.Count == 0)
  699. m_updateTimer.Stop();
  700. }
  701. }
  702. private void SaveAppearance(UUID agentid)
  703. {
  704. // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved
  705. // in a culture where decimal points are commas and then reloaded in a culture which just treats them as
  706. // number seperators.
  707. Culture.SetCurrentCulture();
  708. ScenePresence sp = m_scene.GetScenePresence(agentid);
  709. if (sp == null)
  710. {
  711. // This is expected if the user has gone away.
  712. // m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
  713. return;
  714. }
  715. // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
  716. // This could take awhile since it needs to pull inventory
  717. // 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
  718. // assets and item asset id changes to complete.
  719. // I don't think we need to worry about doing this within m_setAppearanceLock since the queueing avoids
  720. // multiple save requests.
  721. SetAppearanceAssets(sp.UUID, sp.Appearance);
  722. // List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
  723. // foreach (AvatarAttachment att in attachments)
  724. // {
  725. // m_log.DebugFormat(
  726. // "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
  727. // sp.Name, att.ItemID, att.AttachPoint);
  728. // }
  729. m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
  730. // Trigger this here because it's the final step in the set/queue/save process for appearance setting.
  731. // Everything has been updated and stored. Ensures bakes have been persisted (if option is set to persist bakes).
  732. m_scene.EventManager.TriggerAvatarAppearanceChanged(sp);
  733. }
  734. /// <summary>
  735. /// For a given set of appearance items, check whether the items are valid and add their asset IDs to
  736. /// appearance data.
  737. /// </summary>
  738. /// <param name='userID'></param>
  739. /// <param name='appearance'></param>
  740. private void SetAppearanceAssets(UUID userID, AvatarAppearance appearance)
  741. {
  742. IInventoryService invService = m_scene.InventoryService;
  743. if (invService.GetRootFolder(userID) != null)
  744. {
  745. for (int i = 0; i < appearance.Wearables.Length; i++)
  746. {
  747. for (int j = 0; j < appearance.Wearables[i].Count; j++)
  748. {
  749. if (appearance.Wearables[i][j].ItemID == UUID.Zero)
  750. {
  751. m_log.WarnFormat(
  752. "[AVFACTORY]: Wearable item {0}:{1} for user {2} unexpectedly UUID.Zero. Ignoring.",
  753. i, j, userID);
  754. continue;
  755. }
  756. // Ignore ruth's assets
  757. if (i < AvatarWearable.DefaultWearables.Length)
  758. {
  759. if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
  760. continue;
  761. }
  762. InventoryItemBase baseItem = invService.GetItem(userID, appearance.Wearables[i][j].ItemID);
  763. if (baseItem != null)
  764. {
  765. appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
  766. }
  767. else
  768. {
  769. m_log.WarnFormat(
  770. "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
  771. appearance.Wearables[i][j].ItemID, (WearableType)i);
  772. appearance.Wearables[i].RemoveItem(appearance.Wearables[i][j].ItemID);
  773. }
  774. }
  775. }
  776. }
  777. else
  778. {
  779. m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
  780. }
  781. // IInventoryService invService = m_scene.InventoryService;
  782. // bool resetwearable = false;
  783. // if (invService.GetRootFolder(userID) != null)
  784. // {
  785. // for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
  786. // {
  787. // for (int j = 0; j < appearance.Wearables[i].Count; j++)
  788. // {
  789. // // Check if the default wearables are not set
  790. // if (appearance.Wearables[i][j].ItemID == UUID.Zero)
  791. // {
  792. // switch ((WearableType) i)
  793. // {
  794. // case WearableType.Eyes:
  795. // case WearableType.Hair:
  796. // case WearableType.Shape:
  797. // case WearableType.Skin:
  798. // //case WearableType.Underpants:
  799. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  800. // resetwearable = true;
  801. // m_log.Warn("[AVFACTORY]: UUID.Zero Wearables, passing fake values.");
  802. // resetwearable = true;
  803. // break;
  804. //
  805. // }
  806. // continue;
  807. // }
  808. //
  809. // // Ignore ruth's assets except for the body parts! missing body parts fail avatar appearance on V1
  810. // if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
  811. // {
  812. // switch ((WearableType)i)
  813. // {
  814. // case WearableType.Eyes:
  815. // case WearableType.Hair:
  816. // case WearableType.Shape:
  817. // case WearableType.Skin:
  818. // //case WearableType.Underpants:
  819. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  820. //
  821. // m_log.WarnFormat("[AVFACTORY]: {0} Default Wearables, passing existing values.", (WearableType)i);
  822. // resetwearable = true;
  823. // break;
  824. //
  825. // }
  826. // continue;
  827. // }
  828. //
  829. // InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
  830. // baseItem = invService.GetItem(baseItem);
  831. //
  832. // if (baseItem != null)
  833. // {
  834. // appearance.Wearables[i].Add(appearance.Wearables[i][j].ItemID, baseItem.AssetID);
  835. // int unmodifiedWearableIndexForClosure = i;
  836. // m_scene.AssetService.Get(baseItem.AssetID.ToString(), this,
  837. // delegate(string x, object y, AssetBase z)
  838. // {
  839. // if (z == null)
  840. // {
  841. // TryAndRepairBrokenWearable(
  842. // (WearableType)unmodifiedWearableIndexForClosure, invService,
  843. // userID, appearance);
  844. // }
  845. // });
  846. // }
  847. // else
  848. // {
  849. // m_log.ErrorFormat(
  850. // "[AVFACTORY]: Can't find inventory item {0} for {1}, setting to default",
  851. // appearance.Wearables[i][j].ItemID, (WearableType)i);
  852. //
  853. // TryAndRepairBrokenWearable((WearableType)i, invService, userID, appearance);
  854. // resetwearable = true;
  855. //
  856. // }
  857. // }
  858. // }
  859. //
  860. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  861. // if (appearance.Wearables[(int) WearableType.Eyes] == null)
  862. // {
  863. // m_log.WarnFormat("[AVFACTORY]: {0} Eyes are Null, passing existing values.", (WearableType.Eyes));
  864. //
  865. // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
  866. // resetwearable = true;
  867. // }
  868. // else
  869. // {
  870. // if (appearance.Wearables[(int) WearableType.Eyes][0].ItemID == UUID.Zero)
  871. // {
  872. // m_log.WarnFormat("[AVFACTORY]: Eyes are UUID.Zero are broken, {0} {1}",
  873. // appearance.Wearables[(int) WearableType.Eyes][0].ItemID,
  874. // appearance.Wearables[(int) WearableType.Eyes][0].AssetID);
  875. // TryAndRepairBrokenWearable(WearableType.Eyes, invService, userID, appearance);
  876. // resetwearable = true;
  877. //
  878. // }
  879. //
  880. // }
  881. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  882. // if (appearance.Wearables[(int)WearableType.Shape] == null)
  883. // {
  884. // m_log.WarnFormat("[AVFACTORY]: {0} shape is Null, passing existing values.", (WearableType.Shape));
  885. //
  886. // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
  887. // resetwearable = true;
  888. // }
  889. // else
  890. // {
  891. // if (appearance.Wearables[(int)WearableType.Shape][0].ItemID == UUID.Zero)
  892. // {
  893. // m_log.WarnFormat("[AVFACTORY]: Shape is UUID.Zero and broken, {0} {1}",
  894. // appearance.Wearables[(int)WearableType.Shape][0].ItemID,
  895. // appearance.Wearables[(int)WearableType.Shape][0].AssetID);
  896. // TryAndRepairBrokenWearable(WearableType.Shape, invService, userID, appearance);
  897. // resetwearable = true;
  898. //
  899. // }
  900. //
  901. // }
  902. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  903. // if (appearance.Wearables[(int)WearableType.Hair] == null)
  904. // {
  905. // m_log.WarnFormat("[AVFACTORY]: {0} Hair is Null, passing existing values.", (WearableType.Hair));
  906. //
  907. // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
  908. // resetwearable = true;
  909. // }
  910. // else
  911. // {
  912. // if (appearance.Wearables[(int)WearableType.Hair][0].ItemID == UUID.Zero)
  913. // {
  914. // m_log.WarnFormat("[AVFACTORY]: Hair is UUID.Zero and broken, {0} {1}",
  915. // appearance.Wearables[(int)WearableType.Hair][0].ItemID,
  916. // appearance.Wearables[(int)WearableType.Hair][0].AssetID);
  917. // TryAndRepairBrokenWearable(WearableType.Hair, invService, userID, appearance);
  918. // resetwearable = true;
  919. //
  920. // }
  921. //
  922. // }
  923. // // I don't know why we have to test for this again... but the above switches do not capture these scenarios for some reason....
  924. // if (appearance.Wearables[(int)WearableType.Skin] == null)
  925. // {
  926. // m_log.WarnFormat("[AVFACTORY]: {0} Skin is Null, passing existing values.", (WearableType.Skin));
  927. //
  928. // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
  929. // resetwearable = true;
  930. // }
  931. // else
  932. // {
  933. // if (appearance.Wearables[(int)WearableType.Skin][0].ItemID == UUID.Zero)
  934. // {
  935. // m_log.WarnFormat("[AVFACTORY]: Skin is UUID.Zero and broken, {0} {1}",
  936. // appearance.Wearables[(int)WearableType.Skin][0].ItemID,
  937. // appearance.Wearables[(int)WearableType.Skin][0].AssetID);
  938. // TryAndRepairBrokenWearable(WearableType.Skin, invService, userID, appearance);
  939. // resetwearable = true;
  940. //
  941. // }
  942. //
  943. // }
  944. // if (resetwearable)
  945. // {
  946. // ScenePresence presence = null;
  947. // if (m_scene.TryGetScenePresence(userID, out presence))
  948. // {
  949. // presence.ControllingClient.SendWearables(presence.Appearance.Wearables,
  950. // presence.Appearance.Serial++);
  951. // }
  952. // }
  953. //
  954. // }
  955. // else
  956. // {
  957. // m_log.WarnFormat("[AVFACTORY]: user {0} has no inventory, appearance isn't going to work", userID);
  958. // }
  959. }
  960. private void TryAndRepairBrokenWearable(WearableType type, IInventoryService invService, UUID userID,AvatarAppearance appearance)
  961. {
  962. UUID defaultwearable = GetDefaultItem(type);
  963. if (defaultwearable != UUID.Zero)
  964. {
  965. UUID newInvItem = UUID.Random();
  966. InventoryItemBase itembase = new InventoryItemBase(newInvItem, userID)
  967. {
  968. AssetID = defaultwearable,
  969. AssetType = (int)FolderType.BodyPart,
  970. CreatorId = userID.ToString(),
  971. //InvType = (int)InventoryType.Wearable,
  972. Description = "Failed Wearable Replacement",
  973. Folder = invService.GetFolderForType(userID, FolderType.BodyPart).ID,
  974. Flags = (uint) type, Name = Enum.GetName(typeof (WearableType), type),
  975. BasePermissions = (uint) PermissionMask.Copy,
  976. CurrentPermissions = (uint) PermissionMask.Copy,
  977. EveryOnePermissions = (uint) PermissionMask.Copy,
  978. GroupPermissions = (uint) PermissionMask.Copy,
  979. NextPermissions = (uint) PermissionMask.Copy
  980. };
  981. invService.AddItem(itembase);
  982. UUID LinkInvItem = UUID.Random();
  983. itembase = new InventoryItemBase(LinkInvItem, userID)
  984. {
  985. AssetID = newInvItem,
  986. AssetType = (int)AssetType.Link,
  987. CreatorId = userID.ToString(),
  988. InvType = (int) InventoryType.Wearable,
  989. Description = "Failed Wearable Replacement",
  990. Folder = invService.GetFolderForType(userID, FolderType.CurrentOutfit).ID,
  991. Flags = (uint) type,
  992. Name = Enum.GetName(typeof (WearableType), type),
  993. BasePermissions = (uint) PermissionMask.Copy,
  994. CurrentPermissions = (uint) PermissionMask.Copy,
  995. EveryOnePermissions = (uint) PermissionMask.Copy,
  996. GroupPermissions = (uint) PermissionMask.Copy,
  997. NextPermissions = (uint) PermissionMask.Copy
  998. };
  999. invService.AddItem(itembase);
  1000. appearance.Wearables[(int)type] = new AvatarWearable(newInvItem, GetDefaultItem(type));
  1001. ScenePresence presence = null;
  1002. if (m_scene.TryGetScenePresence(userID, out presence))
  1003. {
  1004. m_scene.SendInventoryUpdate(presence.ControllingClient,
  1005. invService.GetFolderForType(userID, FolderType.CurrentOutfit), false, true);
  1006. }
  1007. }
  1008. }
  1009. private UUID GetDefaultItem(WearableType wearable)
  1010. {
  1011. // These are ruth
  1012. UUID ret = UUID.Zero;
  1013. switch (wearable)
  1014. {
  1015. case WearableType.Eyes:
  1016. ret = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7");
  1017. break;
  1018. case WearableType.Hair:
  1019. ret = new UUID("d342e6c0-b9d2-11dc-95ff-0800200c9a66");
  1020. break;
  1021. case WearableType.Pants:
  1022. ret = new UUID("00000000-38f9-1111-024e-222222111120");
  1023. break;
  1024. case WearableType.Shape:
  1025. ret = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
  1026. break;
  1027. case WearableType.Shirt:
  1028. ret = new UUID("00000000-38f9-1111-024e-222222111110");
  1029. break;
  1030. case WearableType.Skin:
  1031. ret = new UUID("77c41e39-38f9-f75a-024e-585989bbabbb");
  1032. break;
  1033. case WearableType.Undershirt:
  1034. ret = new UUID("16499ebb-3208-ec27-2def-481881728f47");
  1035. break;
  1036. case WearableType.Underpants:
  1037. ret = new UUID("4ac2e9c7-3671-d229-316a-67717730841d");
  1038. break;
  1039. }
  1040. return ret;
  1041. }
  1042. #endregion
  1043. #region Client Event Handlers
  1044. /// <summary>
  1045. /// Tell the client for this scene presence what items it should be wearing now
  1046. /// </summary>
  1047. /// <param name="client"></param>
  1048. private void Client_OnRequestWearables(IClientAPI client)
  1049. {
  1050. Util.FireAndForget(delegate(object x)
  1051. {
  1052. Thread.Sleep(4000);
  1053. // m_log.DebugFormat("[AVFACTORY]: Client_OnRequestWearables called for {0} ({1})", client.Name, client.AgentId);
  1054. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1055. if (sp != null)
  1056. client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial++);
  1057. else
  1058. m_log.WarnFormat("[AVFACTORY]: Client_OnRequestWearables unable to find presence for {0}", client.AgentId);
  1059. }, null, "AvatarFactoryModule.OnClientRequestWearables");
  1060. }
  1061. /// <summary>
  1062. /// Set appearance data (texture asset IDs and slider settings) received from a client
  1063. /// </summary>
  1064. /// <param name="client"></param>
  1065. /// <param name="texture"></param>
  1066. /// <param name="visualParam"></param>
  1067. private void Client_OnSetAppearance(IClientAPI client, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
  1068. {
  1069. // m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance called for {0} ({1})", client.Name, client.AgentId);
  1070. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1071. if (sp != null)
  1072. SetAppearance(sp, textureEntry, visualParams,avSize, cacheItems);
  1073. else
  1074. m_log.WarnFormat("[AVFACTORY]: Client_OnSetAppearance unable to find presence for {0}", client.AgentId);
  1075. }
  1076. /// <summary>
  1077. /// Update what the avatar is wearing using an item from their inventory.
  1078. /// </summary>
  1079. /// <param name="client"></param>
  1080. /// <param name="e"></param>
  1081. private void Client_OnAvatarNowWearing(IClientAPI client, AvatarWearingArgs e)
  1082. {
  1083. // m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing called for {0} ({1})", client.Name, client.AgentId);
  1084. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1085. if (sp == null)
  1086. {
  1087. m_log.WarnFormat("[AVFACTORY]: Client_OnAvatarNowWearing unable to find presence for {0}", client.AgentId);
  1088. return;
  1089. }
  1090. // we need to clean out the existing textures
  1091. sp.Appearance.ResetAppearance();
  1092. // operate on a copy of the appearance so we don't have to lock anything yet
  1093. AvatarAppearance avatAppearance = new AvatarAppearance(sp.Appearance, false);
  1094. foreach (AvatarWearingArgs.Wearable wear in e.NowWearing)
  1095. {
  1096. // If the wearable type is larger than the current array, expand it
  1097. if (avatAppearance.Wearables.Length <= wear.Type)
  1098. {
  1099. int currentLength = avatAppearance.Wearables.Length;
  1100. AvatarWearable[] wears = avatAppearance.Wearables;
  1101. Array.Resize(ref wears, wear.Type + 1);
  1102. for (int i = currentLength ; i <= wear.Type ; i++)
  1103. wears[i] = new AvatarWearable();
  1104. avatAppearance.Wearables = wears;
  1105. }
  1106. avatAppearance.Wearables[wear.Type].Add(wear.ItemID, UUID.Zero);
  1107. }
  1108. avatAppearance.GetAssetsFrom(sp.Appearance);
  1109. lock (m_setAppearanceLock)
  1110. {
  1111. // Update only those fields that we have changed. This is important because the viewer
  1112. // often sends AvatarIsWearing and SetAppearance packets at once, and AvatarIsWearing
  1113. // shouldn't overwrite the changes made in SetAppearance.
  1114. sp.Appearance.Wearables = avatAppearance.Wearables;
  1115. sp.Appearance.Texture = avatAppearance.Texture;
  1116. // We don't need to send the appearance here since the "iswearing" will trigger a new set
  1117. // of visual param and baked texture changes. When those complete, the new appearance will be sent
  1118. QueueAppearanceSave(client.AgentId);
  1119. }
  1120. }
  1121. /// <summary>
  1122. /// Respond to the cached textures request from the client
  1123. /// </summary>
  1124. /// <param name="client"></param>
  1125. /// <param name="serial"></param>
  1126. /// <param name="cachedTextureRequest"></param>
  1127. private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest)
  1128. {
  1129. // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId);
  1130. ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
  1131. List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>();
  1132. foreach (CachedTextureRequestArg request in cachedTextureRequest)
  1133. {
  1134. UUID texture = UUID.Zero;
  1135. int index = request.BakedTextureIndex;
  1136. if (m_reusetextures)
  1137. {
  1138. // this is the most insanely dumb way to do this... however it seems to
  1139. // actually work. if the appearance has been reset because wearables have
  1140. // changed then the texture entries are zero'd out until the bakes are
  1141. // uploaded. on login, if the textures exist in the cache (eg if you logged
  1142. // into the simulator recently, then the appearance will pull those and send
  1143. // them back in the packet and you won't have to rebake. if the textures aren't
  1144. // in the cache then the intial makeroot() call in scenepresence will zero
  1145. // them out.
  1146. //
  1147. // a better solution (though how much better is an open question) is to
  1148. // store the hashes in the appearance and compare them. Thats's coming.
  1149. Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index];
  1150. if (face != null)
  1151. texture = face.TextureID;
  1152. // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index);
  1153. }
  1154. CachedTextureResponseArg response = new CachedTextureResponseArg();
  1155. response.BakedTextureIndex = index;
  1156. response.BakedTextureID = texture;
  1157. response.HostName = null;
  1158. cachedTextureResponse.Add(response);
  1159. }
  1160. // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial);
  1161. // The serial number appears to be used to match requests and responses
  1162. // in the texture transaction. We just send back the serial number
  1163. // that was provided in the request. The viewer bumps this for us.
  1164. client.SendCachedTextureResponse(sp, serial, cachedTextureResponse);
  1165. }
  1166. #endregion
  1167. public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction)
  1168. {
  1169. outputAction("For {0} in {1}", sp.Name, m_scene.RegionInfo.RegionName);
  1170. outputAction(BAKED_TEXTURES_REPORT_FORMAT, "Bake Type", "UUID");
  1171. Dictionary<BakeType, Primitive.TextureEntryFace> bakedTextures = GetBakedTextureFaces(sp.UUID);
  1172. foreach (BakeType bt in bakedTextures.Keys)
  1173. {
  1174. string rawTextureID;
  1175. if (bakedTextures[bt] == null)
  1176. {
  1177. rawTextureID = "not set";
  1178. }
  1179. else
  1180. {
  1181. rawTextureID = bakedTextures[bt].TextureID.ToString();
  1182. if (m_scene.AssetService.Get(rawTextureID) == null)
  1183. rawTextureID += " (not found)";
  1184. else
  1185. rawTextureID += " (uploaded)";
  1186. }
  1187. outputAction(BAKED_TEXTURES_REPORT_FORMAT, null, bt, rawTextureID);
  1188. }
  1189. bool bakedTextureValid = m_scene.AvatarFactory.ValidateBakedTextureCache(sp);
  1190. outputAction("{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
  1191. }
  1192. }
  1193. }