SceneObjectPartInventory.cs 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826
  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.Text;
  29. using System.Xml;
  30. using System.Collections.Generic;
  31. using System.Collections;
  32. using System.Reflection;
  33. using OpenMetaverse;
  34. using log4net;
  35. using OpenSim.Framework;
  36. using OpenSim.Region.Framework.Interfaces;
  37. using PermissionMask = OpenSim.Framework.PermissionMask;
  38. namespace OpenSim.Region.Framework.Scenes
  39. {
  40. public class SceneObjectPartInventory : IEntityInventory , IDisposable
  41. {
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. private byte[] m_inventoryFileData = Array.Empty<byte>();
  44. private byte[] m_inventoryFileNameBytes = Array.Empty<byte>();
  45. private string m_inventoryFileName = "";
  46. private uint m_inventoryFileNameSerial = 0;
  47. private bool m_inventoryPrivileged = false;
  48. private object m_inventoryFileLock = new object();
  49. private Dictionary<UUID, ArrayList> m_scriptErrors = new Dictionary<UUID, ArrayList>();
  50. /// <value>
  51. /// The part to which the inventory belongs.
  52. /// </value>
  53. private SceneObjectPart m_part;
  54. /// <summary>
  55. /// Serial count for inventory file , used to tell if inventory has changed
  56. /// no need for this to be part of Database backup
  57. /// </summary>
  58. protected uint m_inventorySerial = 0;
  59. /// <summary>
  60. /// Holds in memory prim inventory
  61. /// </summary>
  62. protected TaskInventoryDictionary m_items = new TaskInventoryDictionary();
  63. protected Dictionary<UUID, TaskInventoryItem> m_scripts = null;
  64. /// <summary>
  65. /// Tracks whether inventory has changed since the last persistent backup
  66. /// </summary>
  67. internal bool HasInventoryChanged;
  68. /// <value>
  69. /// Inventory serial number
  70. /// </value>
  71. protected internal uint Serial
  72. {
  73. get { return m_inventorySerial; }
  74. set { m_inventorySerial = value; }
  75. }
  76. /// <value>
  77. /// Raw inventory data
  78. /// </value>
  79. protected internal TaskInventoryDictionary Items
  80. {
  81. get
  82. {
  83. return m_items;
  84. }
  85. set
  86. {
  87. m_items = value;
  88. m_inventorySerial++;
  89. gatherScriptsAndQueryStates();
  90. }
  91. }
  92. public int Count
  93. {
  94. get
  95. {
  96. m_items.LockItemsForRead(true);
  97. int c = m_items.Count;
  98. m_items.LockItemsForRead(false);
  99. return c;
  100. }
  101. }
  102. /// <summary>
  103. /// Constructor
  104. /// </summary>
  105. /// <param name="part">
  106. /// A <see cref="SceneObjectPart"/>
  107. /// </param>
  108. public SceneObjectPartInventory(SceneObjectPart part)
  109. {
  110. m_part = part;
  111. }
  112. ~SceneObjectPartInventory()
  113. {
  114. Dispose(false);
  115. }
  116. private bool disposed = false;
  117. public void Dispose()
  118. {
  119. Dispose(true);
  120. GC.SuppressFinalize(this);
  121. }
  122. protected void Dispose(bool disposing)
  123. {
  124. // Check to see if Dispose has already been called.
  125. if (!disposed)
  126. {
  127. if (m_items != null)
  128. {
  129. m_items.Dispose();
  130. m_items = null;
  131. }
  132. disposed = true;
  133. }
  134. }
  135. /// <summary>
  136. /// Force the task inventory of this prim to persist at the next update sweep
  137. /// </summary>
  138. public void ForceInventoryPersistence()
  139. {
  140. HasInventoryChanged = true;
  141. }
  142. /// <summary>
  143. /// Reset UUIDs for all the items in the prim's inventory.
  144. /// </summary>
  145. /// <remarks>
  146. /// This involves either generating
  147. /// new ones or setting existing UUIDs to the correct parent UUIDs.
  148. ///
  149. /// If this method is called and there are inventory items, then we regard the inventory as having changed.
  150. /// </remarks>
  151. public void ResetInventoryIDs()
  152. {
  153. if (m_part == null)
  154. return;
  155. m_items.LockItemsForWrite(true);
  156. if (m_items.Count == 0)
  157. {
  158. m_items.LockItemsForWrite(false);
  159. return;
  160. }
  161. UUID partID = m_part.UUID;
  162. IList<TaskInventoryItem> items = new List<TaskInventoryItem>(m_items.Values);
  163. m_items.Clear();
  164. if(m_scripts == null)
  165. {
  166. for (int i = 0; i < items.Count; ++i)
  167. {
  168. TaskInventoryItem item = items[i];
  169. item.ResetIDs(partID);
  170. m_items.Add(item.ItemID, item);
  171. }
  172. }
  173. else
  174. {
  175. m_scripts.Clear();
  176. for (int i = 0; i < items.Count; ++i)
  177. {
  178. TaskInventoryItem item = items[i];
  179. item.ResetIDs(partID);
  180. m_items.Add(item.ItemID, item);
  181. if (item.InvType == (int)InventoryType.LSL)
  182. m_scripts.Add(item.ItemID, item);
  183. }
  184. }
  185. m_inventorySerial++;
  186. m_items.LockItemsForWrite(false);
  187. }
  188. public void ResetObjectID()
  189. {
  190. if (m_part == null)
  191. return;
  192. UUID partID = m_part.UUID;
  193. m_items.LockItemsForWrite(true);
  194. if (m_items.Count == 0)
  195. {
  196. m_items.LockItemsForWrite(false);
  197. return;
  198. }
  199. foreach(TaskInventoryItem item in m_items.Values)
  200. {
  201. item.ParentPartID = partID;
  202. item.ParentID = partID;
  203. }
  204. m_inventorySerial++;
  205. m_items.LockItemsForWrite(false);
  206. }
  207. /// <summary>
  208. /// Change every item in this inventory to a new owner.
  209. /// </summary>
  210. /// <param name="ownerId"></param>
  211. public void ChangeInventoryOwner(UUID ownerId)
  212. {
  213. if(m_part == null)
  214. return;
  215. m_items.LockItemsForWrite(true);
  216. if (m_items.Count == 0)
  217. {
  218. m_items.LockItemsForWrite(false);
  219. return;
  220. }
  221. foreach (TaskInventoryItem item in m_items.Values)
  222. {
  223. if (ownerId != item.OwnerID)
  224. item.LastOwnerID = item.OwnerID;
  225. item.OwnerID = ownerId;
  226. item.PermsMask = 0;
  227. item.PermsGranter = UUID.Zero;
  228. item.OwnerChanged = true;
  229. }
  230. HasInventoryChanged = true;
  231. m_part.ParentGroup.HasGroupChanged = true;
  232. m_inventorySerial++;
  233. m_items.LockItemsForWrite(false);
  234. }
  235. /// <summary>
  236. /// Change every item in this inventory to a new group.
  237. /// </summary>
  238. /// <param name="groupID"></param>
  239. public void ChangeInventoryGroup(UUID groupID)
  240. {
  241. if(m_part == null)
  242. return;
  243. m_items.LockItemsForWrite(true);
  244. if (m_items.Count == 0)
  245. {
  246. m_items.LockItemsForWrite(false);
  247. return;
  248. }
  249. m_inventorySerial++;
  250. // Don't let this set the HasGroupChanged flag for attachments
  251. // as this happens during rez and we don't want a new asset
  252. // for each attachment each time
  253. if (!m_part.ParentGroup.IsAttachment)
  254. {
  255. HasInventoryChanged = true;
  256. m_part.ParentGroup.HasGroupChanged = true;
  257. }
  258. foreach (TaskInventoryItem item in m_items.Values)
  259. item.GroupID = groupID;
  260. m_items.LockItemsForWrite(false);
  261. }
  262. private void gatherScriptsAndQueryStates()
  263. {
  264. m_items.LockItemsForWrite(true);
  265. m_scripts = new Dictionary<UUID, TaskInventoryItem>();
  266. foreach (TaskInventoryItem item in m_items.Values)
  267. {
  268. if (item.InvType == (int)InventoryType.LSL)
  269. m_scripts[item.ItemID] = item;
  270. }
  271. if (m_scripts.Count == 0)
  272. {
  273. m_items.LockItemsForWrite(false);
  274. m_scripts = null;
  275. return;
  276. }
  277. m_items.LockItemsForWrite(false);
  278. if (m_part.ParentGroup == null || m_part.ParentGroup.Scene == null)
  279. return;
  280. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  281. if (scriptEngines.Length == 0) // No engine at all
  282. return;
  283. bool running;
  284. m_items.LockItemsForRead(true);
  285. foreach (TaskInventoryItem item in m_scripts.Values)
  286. {
  287. //running = false;
  288. foreach (IScriptModule e in scriptEngines)
  289. {
  290. if (e.HasScript(item.ItemID, out running))
  291. {
  292. item.ScriptRunning = running;
  293. break;
  294. }
  295. }
  296. //item.ScriptRunning = running;
  297. }
  298. m_items.LockItemsForRead(false);
  299. }
  300. public bool TryGetScriptInstanceRunning(UUID itemId, out bool running)
  301. {
  302. running = false;
  303. TaskInventoryItem item = GetInventoryItem(itemId);
  304. if (item == null)
  305. return false;
  306. return TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running);
  307. }
  308. public static bool TryGetScriptInstanceRunning(Scene scene, TaskInventoryItem item, out bool running)
  309. {
  310. running = false;
  311. if (item.InvType != (int)InventoryType.LSL)
  312. return false;
  313. IScriptModule[] scriptEngines = scene.RequestModuleInterfaces<IScriptModule>();
  314. if (scriptEngines.Length == 0) // No engine at all
  315. return false;
  316. foreach (IScriptModule e in scriptEngines)
  317. {
  318. if (e.HasScript(item.ItemID, out running))
  319. return true;
  320. }
  321. return false;
  322. }
  323. public int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
  324. {
  325. m_items.LockItemsForRead(true);
  326. if(m_scripts == null || m_scripts.Count == 0)
  327. {
  328. m_items.LockItemsForRead(false);
  329. return 0;
  330. }
  331. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  332. m_items.LockItemsForRead(false);
  333. int scriptsValidForStarting = 0;
  334. for (int i = 0; i < scripts.Count; ++i)
  335. {
  336. if (CreateScriptInstance(scripts[i], startParam, postOnRez, engine, stateSource))
  337. scriptsValidForStarting++;
  338. }
  339. return scriptsValidForStarting;
  340. }
  341. public ArrayList GetScriptErrors(UUID itemID)
  342. {
  343. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  344. ArrayList ret = new ArrayList();
  345. foreach (IScriptModule e in scriptEngines)
  346. {
  347. if (e != null)
  348. {
  349. ArrayList errors = e.GetScriptErrors(itemID);
  350. foreach (Object line in errors)
  351. ret.Add(line);
  352. }
  353. }
  354. return ret;
  355. }
  356. /// <summary>
  357. /// Stop and remove all the scripts in this prim.
  358. /// </summary>
  359. /// <param name="sceneObjectBeingDeleted">
  360. /// Should be true if these scripts are being removed because the scene
  361. /// object is being deleted. This will prevent spurious updates to the client.
  362. /// </param>
  363. public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
  364. {
  365. m_items.LockItemsForRead(true);
  366. if (m_scripts == null || m_scripts.Count == 0)
  367. {
  368. m_items.LockItemsForRead(false);
  369. return;
  370. }
  371. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  372. m_items.LockItemsForRead(false);
  373. foreach (TaskInventoryItem item in scripts)
  374. {
  375. RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
  376. m_part.RemoveScriptEvents(item.ItemID);
  377. }
  378. }
  379. /// <summary>
  380. /// Stop all the scripts in this prim.
  381. /// </summary>
  382. public void StopScriptInstances()
  383. {
  384. m_items.LockItemsForRead(true);
  385. if (m_scripts == null || m_scripts.Count == 0)
  386. {
  387. m_items.LockItemsForRead(false);
  388. return;
  389. }
  390. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  391. m_items.LockItemsForRead(false);
  392. foreach (TaskInventoryItem item in scripts)
  393. StopScriptInstance(item);
  394. }
  395. /// <summary>
  396. /// Start a script which is in this prim's inventory.
  397. /// </summary>
  398. /// <param name="item"></param>
  399. /// <returns>true if the script instance was created, false otherwise</returns>
  400. public bool CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource)
  401. {
  402. //m_log.DebugFormat("[PRIM INVENTORY]: Starting script {0} {1} in prim {2} {3} in {4}",
  403. // item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  404. if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item, m_part))
  405. {
  406. StoreScriptError(item.ItemID, "no permission");
  407. return false;
  408. }
  409. m_part.AddFlag(PrimFlags.Scripted);
  410. if (m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts)
  411. return false;
  412. UUID itemID = item.ItemID;
  413. m_items.LockItemsForRead(true);
  414. if (!m_items.TryGetValue(item.ItemID, out TaskInventoryItem it))
  415. {
  416. m_items.LockItemsForRead(false);
  417. StoreScriptError(itemID, String.Format("TaskItem ID {0} could not be found", item.ItemID));
  418. m_log.ErrorFormat(
  419. "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since taskitem ID {4} could not be found",
  420. item.Name, item.ItemID, m_part.AbsolutePosition,
  421. m_part.ParentGroup.Scene.RegionInfo.RegionName, item.ItemID);
  422. return false;
  423. }
  424. m_items.LockItemsForRead(false);
  425. if (stateSource == 2 && m_part.ParentGroup.Scene.m_trustBinaries)
  426. {
  427. // Prim crossing
  428. m_items.LockItemsForWrite(true);
  429. it.PermsMask = 0;
  430. it.PermsGranter = UUID.Zero;
  431. m_items.LockItemsForWrite(false);
  432. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  433. m_part.LocalId, itemID, String.Empty, startParam, postOnRez, engine, stateSource);
  434. StoreScriptErrors(itemID, null);
  435. m_part.ParentGroup.AddActiveScriptCount(1);
  436. m_part.ScheduleFullUpdate();
  437. return true;
  438. }
  439. AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  440. if (asset == null)
  441. {
  442. StoreScriptError(itemID, String.Format("asset ID {0} could not be found", item.AssetID));
  443. m_log.ErrorFormat(
  444. "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
  445. item.Name, item.ItemID, m_part.AbsolutePosition,
  446. m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID);
  447. return false;
  448. }
  449. if (m_part.ParentGroup.m_savedScriptState != null)
  450. item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, itemID);
  451. m_items.LockItemsForWrite(true);
  452. it.OldItemID = item.OldItemID;
  453. it.PermsMask = 0;
  454. it.PermsGranter = UUID.Zero;
  455. m_items.LockItemsForWrite(false);
  456. string script = Utils.BytesToString(asset.Data);
  457. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  458. m_part.LocalId, itemID, script, startParam, postOnRez, engine, stateSource);
  459. StoreScriptErrors(itemID, null);
  460. //if (item.ScriptRunning)
  461. m_part.ParentGroup.AddActiveScriptCount(1);
  462. return true;
  463. }
  464. private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID)
  465. {
  466. //m_log.DebugFormat(
  467. // "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}",
  468. // newID, oldID, loadedID);
  469. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  470. if (scriptEngines.Length == 0) // No engine at all
  471. return oldID;
  472. UUID stateID = oldID;
  473. if (!m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
  474. stateID = loadedID;
  475. if (m_part.ParentGroup.m_savedScriptState.ContainsKey(stateID))
  476. {
  477. XmlDocument doc = new XmlDocument();
  478. doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]);
  479. ////////// CRUFT WARNING ///////////////////////////////////
  480. //
  481. // Old objects will have <ScriptState><State> ...
  482. // This format is XEngine ONLY
  483. //
  484. // New objects have <State Engine="...." ...><ScriptState>...
  485. // This can be passed to any engine
  486. //
  487. XmlNode n = doc.SelectSingleNode("ScriptState");
  488. if (n != null) // Old format data
  489. {
  490. XmlDocument newDoc = new XmlDocument();
  491. XmlElement rootN = newDoc.CreateElement("", "State", "");
  492. XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", "");
  493. uuidA.Value = stateID.ToString();
  494. rootN.Attributes.Append(uuidA);
  495. XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", "");
  496. engineA.Value = "XEngine";
  497. rootN.Attributes.Append(engineA);
  498. newDoc.AppendChild(rootN);
  499. XmlNode stateN = newDoc.ImportNode(n, true);
  500. rootN.AppendChild(stateN);
  501. // This created document has only the minimun data
  502. // necessary for XEngine to parse it successfully
  503. //m_log.DebugFormat("[PRIM INVENTORY]: Adding legacy state {0} in {1}", stateID, newID);
  504. m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml;
  505. }
  506. foreach (IScriptModule e in scriptEngines)
  507. {
  508. if (e != null)
  509. {
  510. if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[stateID]))
  511. break;
  512. }
  513. }
  514. m_part.ParentGroup.m_savedScriptState.Remove(stateID);
  515. }
  516. return stateID;
  517. }
  518. /// <summary>
  519. /// Start a script which is in this prim's inventory.
  520. /// Some processing may occur in the background, but this routine returns asap.
  521. /// </summary>
  522. /// <param name="itemId">
  523. /// A <see cref="UUID"/>
  524. /// </param>
  525. public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
  526. {
  527. lock (m_scriptErrors)
  528. {
  529. // Indicate to CreateScriptInstanceInternal() we don't want it to wait for completion
  530. m_scriptErrors.Remove(itemId);
  531. }
  532. CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
  533. return true;
  534. }
  535. private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
  536. {
  537. m_items.LockItemsForRead(true);
  538. if (m_items.TryGetValue(itemId, out TaskInventoryItem it))
  539. {
  540. m_items.LockItemsForRead(false);
  541. CreateScriptInstance(it, startParam, postOnRez, engine, stateSource);
  542. }
  543. else
  544. {
  545. m_items.LockItemsForRead(false);
  546. string msg = String.Format("couldn't be found for prim {0}, {1} at {2} in {3}", m_part.Name, m_part.UUID,
  547. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  548. StoreScriptError(itemId, msg);
  549. m_log.ErrorFormat(
  550. "[PRIM INVENTORY]: " +
  551. "Couldn't start script with ID {0} since it {1}", itemId, msg);
  552. }
  553. }
  554. /// <summary>
  555. /// Start a script which is in this prim's inventory and return any compilation error messages.
  556. /// </summary>
  557. /// <param name="itemId">
  558. /// A <see cref="UUID"/>
  559. /// </param>
  560. public ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
  561. {
  562. ArrayList errors;
  563. // Indicate to CreateScriptInstanceInternal() we want it to
  564. // post any compilation/loading error messages
  565. lock (m_scriptErrors)
  566. {
  567. m_scriptErrors[itemId] = null;
  568. }
  569. // Perform compilation/loading
  570. CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource);
  571. // Wait for and retrieve any errors
  572. lock (m_scriptErrors)
  573. {
  574. while ((errors = m_scriptErrors[itemId]) == null)
  575. {
  576. if (!System.Threading.Monitor.Wait(m_scriptErrors, 15000))
  577. {
  578. m_log.ErrorFormat(
  579. "[PRIM INVENTORY]: " +
  580. "timedout waiting for script {0} errors", itemId);
  581. errors = m_scriptErrors[itemId];
  582. if (errors == null)
  583. {
  584. errors = new ArrayList(1);
  585. errors.Add("timedout waiting for errors");
  586. }
  587. break;
  588. }
  589. }
  590. m_scriptErrors.Remove(itemId);
  591. }
  592. return errors;
  593. }
  594. // Signal to CreateScriptInstanceEr() that compilation/loading is complete
  595. private void StoreScriptErrors(UUID itemId, ArrayList errors)
  596. {
  597. lock (m_scriptErrors)
  598. {
  599. // If compilation/loading initiated via CreateScriptInstance(),
  600. // it does not want the errors, so just get out
  601. if (!m_scriptErrors.ContainsKey(itemId))
  602. {
  603. return;
  604. }
  605. // Initiated via CreateScriptInstanceEr(), if we know what the
  606. // errors are, save them and wake CreateScriptInstanceEr().
  607. if (errors != null)
  608. {
  609. m_scriptErrors[itemId] = errors;
  610. System.Threading.Monitor.PulseAll(m_scriptErrors);
  611. return;
  612. }
  613. }
  614. // Initiated via CreateScriptInstanceEr() but we don't know what
  615. // the errors are yet, so retrieve them from the script engine.
  616. // This may involve some waiting internal to GetScriptErrors().
  617. errors = GetScriptErrors(itemId);
  618. // Get a default non-null value to indicate success.
  619. if (errors == null)
  620. {
  621. errors = new ArrayList();
  622. }
  623. // Post to CreateScriptInstanceEr() and wake it up
  624. lock (m_scriptErrors)
  625. {
  626. m_scriptErrors[itemId] = errors;
  627. System.Threading.Monitor.PulseAll(m_scriptErrors);
  628. }
  629. }
  630. // Like StoreScriptErrors(), but just posts a single string message
  631. private void StoreScriptError(UUID itemId, string message)
  632. {
  633. ArrayList errors = new ArrayList(1);
  634. errors.Add(message);
  635. StoreScriptErrors(itemId, errors);
  636. }
  637. /// <summary>
  638. /// Stop and remove a script which is in this prim's inventory.
  639. /// </summary>
  640. /// <param name="itemId"></param>
  641. /// <param name="sceneObjectBeingDeleted">
  642. /// Should be true if this script is being removed because the scene
  643. /// object is being deleted. This will prevent spurious updates to the client.
  644. /// </param>
  645. public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
  646. {
  647. if (m_items.ContainsKey(itemId))
  648. {
  649. if (!sceneObjectBeingDeleted)
  650. m_part.RemoveScriptEvents(itemId);
  651. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
  652. m_part.ParentGroup.AddActiveScriptCount(-1);
  653. }
  654. else
  655. {
  656. m_log.WarnFormat(
  657. "[PRIM INVENTORY]: " +
  658. "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  659. itemId, m_part.Name, m_part.UUID,
  660. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  661. }
  662. }
  663. /// <summary>
  664. /// Stop a script which is in this prim's inventory.
  665. /// </summary>
  666. /// <param name="itemId"></param>
  667. /// <param name="sceneObjectBeingDeleted">
  668. /// Should be true if this script is being removed because the scene
  669. /// object is being deleted. This will prevent spurious updates to the client.
  670. /// </param>
  671. public void StopScriptInstance(UUID itemId)
  672. {
  673. m_items.LockItemsForRead(true);
  674. m_items.TryGetValue(itemId, out TaskInventoryItem scriptItem);
  675. m_items.LockItemsForRead(false);
  676. if (scriptItem != null)
  677. {
  678. StopScriptInstance(scriptItem);
  679. }
  680. else
  681. {
  682. m_log.WarnFormat(
  683. "[PRIM INVENTORY]: " +
  684. "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  685. itemId, m_part.Name, m_part.UUID,
  686. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  687. }
  688. }
  689. /// <summary>
  690. /// Stop a script which is in this prim's inventory.
  691. /// </summary>
  692. /// <param name="itemId"></param>
  693. /// <param name="sceneObjectBeingDeleted">
  694. /// Should be true if this script is being removed because the scene
  695. /// object is being deleted. This will prevent spurious updates to the client.
  696. /// </param>
  697. public void StopScriptInstance(TaskInventoryItem item)
  698. {
  699. if (m_part.ParentGroup.Scene != null)
  700. m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID);
  701. // At the moment, even stopped scripts are counted as active, which is probably wrong.
  702. // m_part.ParentGroup.AddActiveScriptCount(-1);
  703. }
  704. public void SendReleaseScriptsControl()
  705. {
  706. m_items.LockItemsForRead(true);
  707. if (m_scripts == null || m_scripts.Count == 0)
  708. {
  709. m_items.LockItemsForRead(false);
  710. return;
  711. }
  712. List<UUID> grants = new List<UUID>();
  713. List<UUID> items = new List<UUID>();
  714. foreach (TaskInventoryItem item in m_scripts.Values)
  715. {
  716. if (((item.PermsMask & 4) == 0))
  717. continue;
  718. grants.Add(item.PermsGranter);
  719. items.Add(item.ItemID);
  720. }
  721. m_items.LockItemsForRead(false);
  722. if (grants.Count > 0)
  723. {
  724. for (int i = 0; i < grants.Count; ++i)
  725. {
  726. ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(grants[i]);
  727. if (presence != null && !presence.IsDeleted && presence.ParentPart != m_part) // last check mb needed for vehicle crossing ???
  728. presence.UnRegisterControlEventsToScript(m_part.LocalId, items[i]);
  729. }
  730. }
  731. }
  732. public void RemoveScriptsPermissions(int permissions)
  733. {
  734. m_items.LockItemsForWrite(true);
  735. if (m_scripts == null || m_scripts.Count == 0)
  736. {
  737. m_items.LockItemsForWrite(false);
  738. return;
  739. }
  740. bool removeControl = ((permissions & 4) != 0); //takecontrol
  741. List<UUID> grants = new List<UUID>();
  742. List<UUID> items = new List<UUID>();
  743. permissions = ~permissions;
  744. foreach (TaskInventoryItem item in m_scripts.Values)
  745. {
  746. int curmask = item.PermsMask;
  747. UUID curGrant = item.PermsGranter;
  748. if (removeControl && ((curmask & 4) != 0))
  749. {
  750. grants.Add(curGrant);
  751. items.Add(item.ItemID);
  752. }
  753. curmask &= permissions;
  754. item.PermsMask = curmask;
  755. if(curmask == 0)
  756. item.PermsGranter = UUID.Zero;
  757. }
  758. m_items.LockItemsForWrite(false);
  759. if(grants.Count > 0)
  760. {
  761. for(int i = 0; i< grants.Count;++i)
  762. {
  763. ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(grants[i]);
  764. if (presence != null && !presence.IsDeleted)
  765. presence.UnRegisterControlEventsToScript(m_part.LocalId, items[i]);
  766. }
  767. }
  768. }
  769. public void RemoveScriptsPermissions(ScenePresence sp, int permissions)
  770. {
  771. m_items.LockItemsForWrite(true);
  772. if (m_scripts == null || m_scripts.Count == 0)
  773. {
  774. m_items.LockItemsForWrite(false);
  775. return;
  776. }
  777. bool removeControl = ((permissions & 4) != 0); //takecontrol
  778. UUID grant = sp.UUID;
  779. List<UUID> items = new List<UUID>();
  780. permissions = ~permissions;
  781. foreach (TaskInventoryItem item in m_scripts.Values)
  782. {
  783. if(grant != item.PermsGranter)
  784. continue;
  785. int curmask = item.PermsMask;
  786. if (removeControl && ((curmask & 4) != 0))
  787. items.Add(item.ItemID);
  788. curmask &= permissions;
  789. item.PermsMask = curmask;
  790. if(curmask == 0)
  791. item.PermsGranter = UUID.Zero;
  792. }
  793. m_items.LockItemsForWrite(false);
  794. if(items.Count > 0)
  795. {
  796. for(int i = 0; i < items.Count; ++i)
  797. {
  798. if (!sp.IsDeleted)
  799. sp.UnRegisterControlEventsToScript(m_part.LocalId, items[i]);
  800. }
  801. }
  802. }
  803. /// <summary>
  804. /// Check if the inventory holds an item with a given name.
  805. /// </summary>
  806. /// <param name="name"></param>
  807. /// <returns></returns>
  808. private bool InventoryContainsName(string name)
  809. {
  810. m_items.LockItemsForRead(true);
  811. foreach (TaskInventoryItem item in m_items.Values)
  812. {
  813. if (item.Name == name)
  814. {
  815. m_items.LockItemsForRead(false);
  816. return true;
  817. }
  818. }
  819. m_items.LockItemsForRead(false);
  820. return false;
  821. }
  822. /// <summary>
  823. /// For a given item name, return that name if it is available. Otherwise, return the next available
  824. /// similar name (which is currently the original name with the next available numeric suffix).
  825. /// </summary>
  826. /// <param name="name"></param>
  827. /// <returns></returns>
  828. private string FindAvailableInventoryName(string name)
  829. {
  830. if (!InventoryContainsName(name))
  831. return name;
  832. int suffix=1;
  833. while (suffix < 256)
  834. {
  835. string tryName=String.Format("{0} {1}", name, suffix);
  836. if (!InventoryContainsName(tryName))
  837. return tryName;
  838. suffix++;
  839. }
  840. return String.Empty;
  841. }
  842. /// <summary>
  843. /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
  844. /// name is chosen.
  845. /// </summary>
  846. /// <param name="item"></param>
  847. public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
  848. {
  849. AddInventoryItem(item.Name, item, allowedDrop);
  850. }
  851. /// <summary>
  852. /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
  853. /// </summary>
  854. /// <param name="item"></param>
  855. public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
  856. {
  857. m_items.LockItemsForRead(true);
  858. List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
  859. m_items.LockItemsForRead(false);
  860. foreach (TaskInventoryItem i in il)
  861. {
  862. if (i.Name == item.Name)
  863. {
  864. if (i.InvType == (int)InventoryType.LSL)
  865. RemoveScriptInstance(i.ItemID, false);
  866. RemoveInventoryItem(i.ItemID);
  867. break;
  868. }
  869. }
  870. AddInventoryItem(item.Name, item, allowedDrop);
  871. }
  872. /// <summary>
  873. /// Add an item to this prim's inventory.
  874. /// </summary>
  875. /// <param name="name">The name that the new item should have.</param>
  876. /// <param name="item">
  877. /// The item itself. The name within this structure is ignored in favour of the name
  878. /// given in this method's arguments
  879. /// </param>
  880. /// <param name="allowedDrop">
  881. /// Item was only added to inventory because AllowedDrop is set
  882. /// </param>
  883. protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
  884. {
  885. name = FindAvailableInventoryName(name);
  886. if (name.Length == 0)
  887. return;
  888. item.ParentID = m_part.UUID;
  889. item.ParentPartID = m_part.UUID;
  890. item.Name = name;
  891. item.GroupID = m_part.GroupID;
  892. m_items.LockItemsForWrite(true);
  893. m_items.Add(item.ItemID, item);
  894. if (item.InvType == (int)InventoryType.LSL)
  895. {
  896. if (m_scripts == null)
  897. m_scripts = new Dictionary<UUID, TaskInventoryItem>();
  898. m_scripts.Add(item.ItemID, item);
  899. }
  900. m_items.LockItemsForWrite(false);
  901. if (allowedDrop)
  902. m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP, item.ItemID);
  903. else
  904. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  905. m_part.AggregateInnerPerms();
  906. m_inventorySerial++;
  907. HasInventoryChanged = true;
  908. m_part.ParentGroup.HasGroupChanged = true;
  909. }
  910. /// <summary>
  911. /// Restore a whole collection of items to the prim's inventory at once.
  912. /// We assume that the items already have all their fields correctly filled out.
  913. /// The items are not flagged for persistence to the database, since they are being restored
  914. /// from persistence rather than being newly added.
  915. /// </summary>
  916. /// <param name="items"></param>
  917. public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
  918. {
  919. m_items.LockItemsForWrite(true);
  920. foreach (TaskInventoryItem item in items)
  921. {
  922. m_items.Add(item.ItemID, item);
  923. if (item.InvType == (int)InventoryType.LSL)
  924. {
  925. if (m_scripts == null)
  926. m_scripts = new Dictionary<UUID, TaskInventoryItem>();
  927. m_scripts.Add(item.ItemID, item);
  928. }
  929. }
  930. m_items.LockItemsForWrite(false);
  931. m_part.AggregateInnerPerms();
  932. m_inventorySerial++;
  933. }
  934. /// <summary>
  935. /// Returns an existing inventory item. Returns the original, so any changes will be live.
  936. /// </summary>
  937. /// <param name="itemID"></param>
  938. /// <returns>null if the item does not exist</returns>
  939. public TaskInventoryItem GetInventoryItem(UUID itemId)
  940. {
  941. TaskInventoryItem item;
  942. m_items.LockItemsForRead(true);
  943. m_items.TryGetValue(itemId, out item);
  944. m_items.LockItemsForRead(false);
  945. return item;
  946. }
  947. public TaskInventoryItem GetInventoryItem(string name)
  948. {
  949. m_items.LockItemsForRead(true);
  950. foreach (TaskInventoryItem item in m_items.Values)
  951. {
  952. if (item.Name == name)
  953. {
  954. m_items.LockItemsForRead(false);
  955. return item;
  956. }
  957. }
  958. m_items.LockItemsForRead(false);
  959. return null;
  960. }
  961. public TaskInventoryItem GetInventoryItem(string name, int type)
  962. {
  963. m_items.LockItemsForRead(true);
  964. foreach (TaskInventoryItem item in m_items.Values)
  965. {
  966. if (item.Type == type && item.Name == name)
  967. {
  968. m_items.LockItemsForRead(false);
  969. return item;
  970. }
  971. }
  972. m_items.LockItemsForRead(false);
  973. return null;
  974. }
  975. public List<TaskInventoryItem> GetInventoryItems(string name)
  976. {
  977. List<TaskInventoryItem> items = new List<TaskInventoryItem>();
  978. m_items.LockItemsForRead(true);
  979. foreach (TaskInventoryItem item in m_items.Values)
  980. {
  981. if (item.Name == name)
  982. items.Add(item);
  983. }
  984. m_items.LockItemsForRead(false);
  985. return items;
  986. }
  987. public bool GetRezReadySceneObjects(TaskInventoryItem item, out List<SceneObjectGroup> objlist, out List<Vector3> veclist, out Vector3 bbox, out float offsetHeight)
  988. {
  989. return GetRezReadySceneObjects(item, item.OwnerID, m_part.GroupID, out objlist, out veclist, out bbox, out offsetHeight);
  990. }
  991. public bool GetRezReadySceneObjects(TaskInventoryItem item, UUID NewOwner, UUID NewGroup, out List<SceneObjectGroup> objlist, out List<Vector3> veclist, out Vector3 bbox, out float offsetHeight)
  992. {
  993. AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  994. if (null == rezAsset)
  995. {
  996. m_log.WarnFormat(
  997. "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
  998. item.AssetID, item.Name, m_part.Name);
  999. objlist = null;
  1000. veclist = null;
  1001. bbox = Vector3.Zero;
  1002. offsetHeight = 0;
  1003. return false;
  1004. }
  1005. m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight);
  1006. for (int i = 0; i < objlist.Count; i++)
  1007. {
  1008. SceneObjectGroup group = objlist[i];
  1009. /*
  1010. group.RootPart.AttachPoint = group.RootPart.Shape.State;
  1011. group.RootPart.AttachedPos = group.AbsolutePosition;
  1012. group.RootPart.AttachRotation = group.GroupRotation;
  1013. */
  1014. group.ResetIDs();
  1015. SceneObjectPart rootPart = group.GetPart(group.UUID);
  1016. // Since renaming the item in the inventory does not affect the name stored
  1017. // in the serialization, transfer the correct name from the inventory to the
  1018. // object itself before we rez.
  1019. // Only do these for the first object if we are rezzing a coalescence.
  1020. // nahh dont mess with coalescence objects,
  1021. // the name in inventory can be change for inventory purpuses only
  1022. if (objlist.Count == 1)
  1023. {
  1024. rootPart.Name = item.Name;
  1025. rootPart.Description = item.Description;
  1026. }
  1027. group.SetGroup(NewGroup, null);
  1028. SceneObjectPart[] partList = group.Parts;
  1029. bool slamThings = (item.CurrentPermissions & (uint)PermissionMask.Slam) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0;
  1030. if ((rootPart.OwnerID != NewOwner) || slamThings)
  1031. {
  1032. if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions())
  1033. {
  1034. foreach (SceneObjectPart part in partList)
  1035. {
  1036. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  1037. part.EveryoneMask = item.EveryonePermissions;
  1038. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  1039. part.NextOwnerMask = item.NextPermissions;
  1040. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  1041. part.GroupMask = item.GroupPermissions;
  1042. }
  1043. group.ApplyNextOwnerPermissions();
  1044. }
  1045. }
  1046. foreach (SceneObjectPart part in partList)
  1047. {
  1048. if ((part.OwnerID.NotEqual(NewOwner)))
  1049. {
  1050. if(part.GroupID.NotEqual(part.OwnerID))
  1051. part.LastOwnerID = part.OwnerID;
  1052. part.OwnerID = NewOwner;
  1053. part.Inventory.ChangeInventoryOwner(NewOwner);
  1054. }
  1055. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  1056. part.EveryoneMask = item.EveryonePermissions;
  1057. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  1058. part.NextOwnerMask = item.NextPermissions;
  1059. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  1060. part.GroupMask = item.GroupPermissions;
  1061. }
  1062. rootPart.TrimPermissions();
  1063. group.InvalidateDeepEffectivePerms();
  1064. }
  1065. return true;
  1066. }
  1067. /// <summary>
  1068. /// Update an existing inventory item.
  1069. /// </summary>
  1070. /// <param name="item">The updated item. An item with the same id must already exist
  1071. /// in this prim's inventory.</param>
  1072. /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
  1073. public bool UpdateInventoryItem(TaskInventoryItem item)
  1074. {
  1075. return UpdateInventoryItem(item, true, true);
  1076. }
  1077. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
  1078. {
  1079. return UpdateInventoryItem(item, fireScriptEvents, true);
  1080. }
  1081. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
  1082. {
  1083. m_items.LockItemsForWrite(true);
  1084. if (m_items.ContainsKey(item.ItemID))
  1085. {
  1086. //m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
  1087. item.ParentID = m_part.UUID;
  1088. item.ParentPartID = m_part.UUID;
  1089. // If group permissions have been set on, check that the groupID is up to date in case it has
  1090. // changed since permissions were last set.
  1091. if (item.GroupPermissions != (uint)PermissionMask.None)
  1092. item.GroupID = m_part.GroupID;
  1093. if(item.OwnerID.IsZero()) // viewer to internal enconding of group owned
  1094. item.OwnerID = item.GroupID;
  1095. if (item.AssetID.IsZero())
  1096. item.AssetID = m_items[item.ItemID].AssetID;
  1097. m_items[item.ItemID] = item;
  1098. if(item.InvType == (int)InventoryType.LSL)
  1099. {
  1100. if(m_scripts == null)
  1101. m_scripts = new Dictionary<UUID, TaskInventoryItem>();
  1102. m_scripts[item.ItemID] = item;
  1103. }
  1104. m_inventorySerial++;
  1105. if (fireScriptEvents)
  1106. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  1107. if (considerChanged)
  1108. {
  1109. m_part.ParentGroup.InvalidateDeepEffectivePerms();
  1110. HasInventoryChanged = true;
  1111. m_part.ParentGroup.HasGroupChanged = true;
  1112. }
  1113. m_items.LockItemsForWrite(false);
  1114. return true;
  1115. }
  1116. else
  1117. {
  1118. m_log.ErrorFormat(
  1119. "[PRIM INVENTORY]: " +
  1120. "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
  1121. item.ItemID, m_part.Name, m_part.UUID,
  1122. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  1123. }
  1124. m_items.LockItemsForWrite(false);
  1125. return false;
  1126. }
  1127. /// <summary>
  1128. /// Remove an item from this prim's inventory
  1129. /// </summary>
  1130. /// <param name="itemID"></param>
  1131. /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
  1132. /// in this prim's inventory.</returns>
  1133. public int RemoveInventoryItem(UUID itemID)
  1134. {
  1135. m_items.LockItemsForRead(true);
  1136. if (m_items.ContainsKey(itemID))
  1137. {
  1138. int type = m_items[itemID].InvType;
  1139. m_items.LockItemsForRead(false);
  1140. if (type == (int)InventoryType.LSL) // Script
  1141. {
  1142. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
  1143. }
  1144. m_items.LockItemsForWrite(true);
  1145. m_items.Remove(itemID);
  1146. if(m_scripts != null)
  1147. {
  1148. m_scripts.Remove(itemID);
  1149. if(m_scripts.Count == 0)
  1150. m_scripts = null;
  1151. }
  1152. if (m_scripts == null)
  1153. {
  1154. m_part.RemFlag(PrimFlags.Scripted);
  1155. }
  1156. m_inventorySerial++;
  1157. m_items.LockItemsForWrite(false);
  1158. m_part.ParentGroup.InvalidateDeepEffectivePerms();
  1159. HasInventoryChanged = true;
  1160. m_part.ParentGroup.HasGroupChanged = true;
  1161. m_part.ScheduleFullUpdate();
  1162. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  1163. return type;
  1164. }
  1165. else
  1166. {
  1167. m_items.LockItemsForRead(false);
  1168. m_log.ErrorFormat(
  1169. "[PRIM INVENTORY]: " +
  1170. "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
  1171. itemID, m_part.Name, m_part.UUID);
  1172. }
  1173. return -1;
  1174. }
  1175. /// <summary>
  1176. /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
  1177. /// </summary>
  1178. /// <param name="xferManager"></param>
  1179. public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
  1180. {
  1181. lock (m_inventoryFileLock)
  1182. {
  1183. bool changed = false;
  1184. m_items.LockItemsForRead(true);
  1185. if (m_inventorySerial == 0) // No inventory
  1186. {
  1187. m_items.LockItemsForRead(false);
  1188. client.SendTaskInventory(m_part.UUID, 0, Array.Empty<byte>());
  1189. return;
  1190. }
  1191. if (m_items.Count == 0) // No inventory
  1192. {
  1193. m_items.LockItemsForRead(false);
  1194. client.SendTaskInventory(m_part.UUID, 0, Array.Empty<byte>());
  1195. return;
  1196. }
  1197. if (m_inventoryFileNameSerial != m_inventorySerial)
  1198. {
  1199. m_inventoryFileNameSerial = m_inventorySerial;
  1200. changed = true;
  1201. }
  1202. m_items.LockItemsForRead(false);
  1203. if (m_inventoryFileData.Length < 2)
  1204. changed = true;
  1205. bool includeAssets = m_part.ParentGroup.Scene.Permissions.CanEditObjectInventory(m_part.UUID, client.AgentId);
  1206. if (m_inventoryPrivileged != includeAssets)
  1207. changed = true;
  1208. if (!changed)
  1209. {
  1210. xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
  1211. client.SendTaskInventory(m_part.UUID, (short)m_inventoryFileNameSerial,
  1212. m_inventoryFileNameBytes);
  1213. return;
  1214. }
  1215. m_inventoryPrivileged = includeAssets;
  1216. InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
  1217. m_items.LockItemsForRead(true);
  1218. foreach (TaskInventoryItem item in m_items.Values)
  1219. {
  1220. invString.AddItemStart();
  1221. invString.AddNameValueLine("item_id", item.ItemID.ToString());
  1222. invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
  1223. invString.AddPermissionsStart();
  1224. invString.AddNameValueLine("base_mask", Utils.UIntToHexString(item.BasePermissions));
  1225. invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(item.CurrentPermissions));
  1226. invString.AddNameValueLine("group_mask", Utils.UIntToHexString(item.GroupPermissions));
  1227. invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(item.EveryonePermissions));
  1228. invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
  1229. invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
  1230. invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
  1231. invString.AddNameValueLine("group_id", item.GroupID.ToString());
  1232. if(item.GroupID.IsNotZero() && item.OwnerID.Equals(item.GroupID))
  1233. {
  1234. invString.AddNameValueLine("owner_id", UUID.ZeroString);
  1235. invString.AddNameValueLine("group_owned","1");
  1236. }
  1237. else
  1238. {
  1239. invString.AddNameValueLine("owner_id", item.OwnerID.ToString());
  1240. invString.AddNameValueLine("group_owned","0");
  1241. }
  1242. invString.AddSectionEnd();
  1243. if (includeAssets)
  1244. invString.AddNameValueLine("asset_id", item.AssetID.ToString());
  1245. else
  1246. invString.AddNameValueLine("asset_id", UUID.ZeroString);
  1247. invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
  1248. invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
  1249. invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
  1250. invString.AddSaleStart();
  1251. invString.AddNameValueLine("sale_type", "not");
  1252. invString.AddNameValueLine("sale_price", "0");
  1253. invString.AddSectionEnd();
  1254. invString.AddNameValueLine("name", item.Name + "|");
  1255. invString.AddNameValueLine("desc", item.Description + "|");
  1256. invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
  1257. invString.AddSectionEnd();
  1258. }
  1259. m_items.LockItemsForRead(false);
  1260. m_inventoryFileData = Utils.StringToBytes(invString.GetString());
  1261. if (m_inventoryFileData.Length > 2)
  1262. {
  1263. m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
  1264. m_inventoryFileNameBytes = Util.StringToBytes256(m_inventoryFileName);
  1265. xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
  1266. client.SendTaskInventory(m_part.UUID, (short)m_inventoryFileNameSerial,m_inventoryFileNameBytes);
  1267. return;
  1268. }
  1269. client.SendTaskInventory(m_part.UUID, 0, Array.Empty<byte>());
  1270. }
  1271. }
  1272. /// <summary>
  1273. /// Process inventory backup
  1274. /// </summary>
  1275. /// <param name="datastore"></param>
  1276. public void ProcessInventoryBackup(ISimulationDataService datastore)
  1277. {
  1278. // Removed this because linking will cause an immediate delete of the new
  1279. // child prim from the database and the subsequent storing of the prim sees
  1280. // the inventory of it as unchanged and doesn't store it at all. The overhead
  1281. // of storing prim inventory needlessly is much less than the aggravation
  1282. // of prim inventory loss.
  1283. // if (HasInventoryChanged)
  1284. // {
  1285. m_items.LockItemsForRead(true);
  1286. ICollection<TaskInventoryItem> itemsvalues = m_items.Values;
  1287. HasInventoryChanged = false;
  1288. m_items.LockItemsForRead(false);
  1289. try
  1290. {
  1291. datastore.StorePrimInventory(m_part.UUID, itemsvalues);
  1292. }
  1293. catch {}
  1294. // }
  1295. }
  1296. public class InventoryStringBuilder
  1297. {
  1298. private StringBuilder BuildString = new StringBuilder(1024);
  1299. public InventoryStringBuilder(UUID folderID, UUID parentID)
  1300. {
  1301. BuildString.Append("\tinv_object\t0\n\t{\n");
  1302. AddNameValueLine("obj_id", folderID.ToString());
  1303. AddNameValueLine("parent_id", parentID.ToString());
  1304. AddNameValueLine("type", "category");
  1305. AddNameValueLine("name", "Contents|\n\t}");
  1306. }
  1307. public void AddItemStart()
  1308. {
  1309. BuildString.Append("\tinv_item\t0\n\t{\n");
  1310. }
  1311. public void AddPermissionsStart()
  1312. {
  1313. BuildString.Append("\tpermissions 0\n\t{\n");
  1314. }
  1315. public void AddSaleStart()
  1316. {
  1317. BuildString.Append("\tsale_info\t0\n\t{\n");
  1318. }
  1319. protected void AddSectionStart()
  1320. {
  1321. BuildString.Append("\t{\n");
  1322. }
  1323. public void AddSectionEnd()
  1324. {
  1325. BuildString.Append("\t}\n");
  1326. }
  1327. public void AddLine(string addLine)
  1328. {
  1329. BuildString.Append(addLine);
  1330. }
  1331. public void AddNameValueLine(string name, string value)
  1332. {
  1333. BuildString.Append("\t\t");
  1334. BuildString.Append(name);
  1335. BuildString.Append('\t');
  1336. BuildString.Append(value);
  1337. BuildString.Append('\n');
  1338. }
  1339. public String GetString()
  1340. {
  1341. return BuildString.ToString();
  1342. }
  1343. public void Close()
  1344. {
  1345. }
  1346. }
  1347. public void AggregateInnerPerms(ref uint owner, ref uint group, ref uint everyone)
  1348. {
  1349. foreach (TaskInventoryItem item in m_items.Values)
  1350. {
  1351. if(item.InvType == (sbyte)InventoryType.Landmark)
  1352. continue;
  1353. owner &= item.CurrentPermissions;
  1354. group &= item.GroupPermissions;
  1355. everyone &= item.EveryonePermissions;
  1356. }
  1357. }
  1358. public uint MaskEffectivePermissions()
  1359. {
  1360. // used to propagate permissions restrictions outwards
  1361. // Modify does not propagate outwards.
  1362. uint mask=0x7fffffff;
  1363. foreach (TaskInventoryItem item in m_items.Values)
  1364. {
  1365. if(item.InvType == (sbyte)InventoryType.Landmark)
  1366. continue;
  1367. // apply current to normal permission bits
  1368. uint newperms = item.CurrentPermissions;
  1369. if ((newperms & (uint)PermissionMask.Copy) == 0)
  1370. mask &= ~(uint)PermissionMask.Copy;
  1371. if ((newperms & (uint)PermissionMask.Transfer) == 0)
  1372. mask &= ~(uint)PermissionMask.Transfer;
  1373. if ((newperms & (uint)PermissionMask.Export) == 0)
  1374. mask &= ~((uint)PermissionMask.Export);
  1375. // apply next owner restricted by current to folded bits
  1376. newperms &= item.NextPermissions;
  1377. if ((newperms & (uint)PermissionMask.Copy) == 0)
  1378. mask &= ~((uint)PermissionMask.FoldedCopy);
  1379. if ((newperms & (uint)PermissionMask.Transfer) == 0)
  1380. mask &= ~((uint)PermissionMask.FoldedTransfer);
  1381. if ((newperms & (uint)PermissionMask.Export) == 0)
  1382. mask &= ~((uint)PermissionMask.FoldedExport);
  1383. }
  1384. return mask;
  1385. }
  1386. public void ApplyNextOwnerPermissions()
  1387. {
  1388. foreach (TaskInventoryItem item in m_items.Values)
  1389. {
  1390. item.CurrentPermissions &= item.NextPermissions;
  1391. item.BasePermissions &= item.NextPermissions;
  1392. item.EveryonePermissions &= item.NextPermissions;
  1393. item.OwnerChanged = true;
  1394. item.PermsMask = 0;
  1395. item.PermsGranter = UUID.Zero;
  1396. }
  1397. }
  1398. public void ApplyGodPermissions(uint perms)
  1399. {
  1400. foreach (TaskInventoryItem item in m_items.Values)
  1401. {
  1402. item.CurrentPermissions = perms;
  1403. item.BasePermissions = perms;
  1404. }
  1405. m_inventorySerial++;
  1406. HasInventoryChanged = true;
  1407. }
  1408. /// <summary>
  1409. /// Returns true if this part inventory contains any scripts. False otherwise.
  1410. /// </summary>
  1411. /// <returns></returns>
  1412. public bool ContainsScripts()
  1413. {
  1414. m_items.LockItemsForRead(true);
  1415. bool res = (m_scripts != null && m_scripts.Count >0);
  1416. m_items.LockItemsForRead(false);
  1417. return res;
  1418. }
  1419. /// <summary>
  1420. /// Returns the count of scripts in this parts inventory.
  1421. /// </summary>
  1422. /// <returns></returns>
  1423. public int ScriptCount()
  1424. {
  1425. int count = 0;
  1426. m_items.LockItemsForRead(true);
  1427. if(m_scripts != null)
  1428. count = m_scripts.Count;
  1429. m_items.LockItemsForRead(false);
  1430. return count;
  1431. }
  1432. /// <summary>
  1433. /// Returns the count of running scripts in this parts inventory.
  1434. /// </summary>
  1435. /// <returns></returns>
  1436. public int RunningScriptCount()
  1437. {
  1438. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  1439. if (scriptEngines.Length == 0)
  1440. return 0;
  1441. int count = 0;
  1442. m_items.LockItemsForRead(true);
  1443. if (m_scripts == null || m_scripts.Count == 0)
  1444. {
  1445. m_items.LockItemsForRead(false);
  1446. return 0;
  1447. }
  1448. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  1449. m_items.LockItemsForRead(false);
  1450. foreach (TaskInventoryItem item in scripts)
  1451. {
  1452. foreach (IScriptModule engine in scriptEngines)
  1453. {
  1454. if (engine != null)
  1455. {
  1456. if (engine.HasScript(item.ItemID, out bool running))
  1457. {
  1458. if(running)
  1459. count++;
  1460. break;
  1461. }
  1462. }
  1463. }
  1464. }
  1465. return count;
  1466. }
  1467. public List<UUID> GetInventoryList()
  1468. {
  1469. m_items.LockItemsForRead(true);
  1470. List<UUID> ret = new List<UUID>(m_items.Count);
  1471. foreach (TaskInventoryItem item in m_items.Values)
  1472. ret.Add(item.ItemID);
  1473. m_items.LockItemsForRead(false);
  1474. return ret;
  1475. }
  1476. public List<TaskInventoryItem> GetInventoryItems()
  1477. {
  1478. m_items.LockItemsForRead(true);
  1479. List<TaskInventoryItem> ret = new List<TaskInventoryItem>(m_items.Values);
  1480. m_items.LockItemsForRead(false);
  1481. return ret;
  1482. }
  1483. public List<TaskInventoryItem> GetInventoryItems(InventoryType type)
  1484. {
  1485. m_items.LockItemsForRead(true);
  1486. List<TaskInventoryItem> ret = new List<TaskInventoryItem>(m_items.Count);
  1487. foreach (TaskInventoryItem item in m_items.Values)
  1488. if (item.InvType == (int)type)
  1489. ret.Add(item);
  1490. m_items.LockItemsForRead(false);
  1491. return ret;
  1492. }
  1493. public Dictionary<UUID, string> GetScriptStates()
  1494. {
  1495. return GetScriptStates(false);
  1496. }
  1497. public Dictionary<UUID, string> GetScriptStates(bool oldIDs)
  1498. {
  1499. Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
  1500. if (m_part.ParentGroup.Scene == null) // Group not in a scene
  1501. return ret;
  1502. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  1503. if (scriptEngines.Length == 0) // No engine at all
  1504. return ret;
  1505. m_items.LockItemsForRead(true);
  1506. if (m_scripts == null || m_scripts.Count == 0)
  1507. {
  1508. m_items.LockItemsForRead(false);
  1509. return ret;
  1510. }
  1511. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  1512. m_items.LockItemsForRead(false);
  1513. foreach (TaskInventoryItem item in scripts)
  1514. {
  1515. foreach (IScriptModule e in scriptEngines)
  1516. {
  1517. if (e != null)
  1518. {
  1519. //m_log.DebugFormat(
  1520. // "[PRIM INVENTORY]: Getting script state from engine {0} for {1} in part {2} in group {3} in {4}",
  1521. // e.Name, item.Name, m_part.Name, m_part.ParentGroup.Name, m_part.ParentGroup.Scene.Name);
  1522. string n = e.GetXMLState(item.ItemID);
  1523. if (n != String.Empty)
  1524. {
  1525. if (oldIDs)
  1526. {
  1527. if (!ret.ContainsKey(item.OldItemID))
  1528. ret[item.OldItemID] = n;
  1529. }
  1530. else
  1531. {
  1532. if (!ret.ContainsKey(item.ItemID))
  1533. ret[item.ItemID] = n;
  1534. }
  1535. break;
  1536. }
  1537. }
  1538. }
  1539. }
  1540. return ret;
  1541. }
  1542. public void ResumeScripts()
  1543. {
  1544. IScriptModule[] scriptEngines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  1545. if (scriptEngines.Length == 0)
  1546. return;
  1547. m_items.LockItemsForRead(true);
  1548. if (m_scripts == null || m_scripts.Count == 0)
  1549. {
  1550. m_items.LockItemsForRead(false);
  1551. return;
  1552. }
  1553. List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(m_scripts.Values);
  1554. m_items.LockItemsForRead(false);
  1555. foreach (TaskInventoryItem item in scripts)
  1556. {
  1557. foreach (IScriptModule engine in scriptEngines)
  1558. {
  1559. if (engine != null)
  1560. {
  1561. //m_log.DebugFormat(
  1562. // "[PRIM INVENTORY]: Resuming script {0} {1} for {2}, OwnerChanged {3}",
  1563. // item.Name, item.ItemID, item.OwnerID, item.OwnerChanged);
  1564. if(!engine.ResumeScript(item.ItemID))
  1565. continue;
  1566. if (item.OwnerChanged)
  1567. engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
  1568. item.OwnerChanged = false;
  1569. }
  1570. }
  1571. }
  1572. }
  1573. }
  1574. }