SceneObjectPartInventory.cs 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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.Xml;
  29. using System.IO;
  30. using System.Collections.Generic;
  31. using System.Collections;
  32. using System.Reflection;
  33. using System.Threading;
  34. using OpenMetaverse;
  35. using log4net;
  36. using OpenSim.Framework;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes.Scripting;
  39. using OpenSim.Region.Framework.Scenes.Serialization;
  40. namespace OpenSim.Region.Framework.Scenes
  41. {
  42. public class SceneObjectPartInventory : IEntityInventory
  43. {
  44. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. private string m_inventoryFileName = String.Empty;
  46. private byte[] m_inventoryFileData = new byte[0];
  47. private uint m_inventoryFileNameSerial = 0;
  48. /// <value>
  49. /// The part to which the inventory belongs.
  50. /// </value>
  51. private SceneObjectPart m_part;
  52. /// <summary>
  53. /// Serial count for inventory file , used to tell if inventory has changed
  54. /// no need for this to be part of Database backup
  55. /// </summary>
  56. protected uint m_inventorySerial = 0;
  57. /// <summary>
  58. /// Holds in memory prim inventory
  59. /// </summary>
  60. protected TaskInventoryDictionary m_items = new TaskInventoryDictionary();
  61. /// <summary>
  62. /// Tracks whether inventory has changed since the last persistent backup
  63. /// </summary>
  64. internal bool HasInventoryChanged;
  65. /// <value>
  66. /// Inventory serial number
  67. /// </value>
  68. protected internal uint Serial
  69. {
  70. get { return m_inventorySerial; }
  71. set { m_inventorySerial = value; }
  72. }
  73. /// <value>
  74. /// Raw inventory data
  75. /// </value>
  76. protected internal TaskInventoryDictionary Items
  77. {
  78. get { return m_items; }
  79. set
  80. {
  81. m_items = value;
  82. m_inventorySerial++;
  83. }
  84. }
  85. /// <summary>
  86. /// Constructor
  87. /// </summary>
  88. /// <param name="part">
  89. /// A <see cref="SceneObjectPart"/>
  90. /// </param>
  91. public SceneObjectPartInventory(SceneObjectPart part)
  92. {
  93. m_part = part;
  94. }
  95. /// <summary>
  96. /// Force the task inventory of this prim to persist at the next update sweep
  97. /// </summary>
  98. public void ForceInventoryPersistence()
  99. {
  100. HasInventoryChanged = true;
  101. }
  102. /// <summary>
  103. /// Reset UUIDs for all the items in the prim's inventory.
  104. /// </summary>
  105. /// <remarks>
  106. /// This involves either generating
  107. /// new ones or setting existing UUIDs to the correct parent UUIDs.
  108. ///
  109. /// If this method is called and there are inventory items, then we regard the inventory as having changed.
  110. /// </remarks>
  111. public void ResetInventoryIDs()
  112. {
  113. if (null == m_part)
  114. return;
  115. lock (m_items)
  116. {
  117. if (0 == m_items.Count)
  118. return;
  119. IList<TaskInventoryItem> items = GetInventoryItems();
  120. m_items.Clear();
  121. foreach (TaskInventoryItem item in items)
  122. {
  123. item.ResetIDs(m_part.UUID);
  124. m_items.Add(item.ItemID, item);
  125. }
  126. }
  127. }
  128. public void ResetObjectID()
  129. {
  130. lock (Items)
  131. {
  132. IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
  133. Items.Clear();
  134. foreach (TaskInventoryItem item in items)
  135. {
  136. item.ParentPartID = m_part.UUID;
  137. item.ParentID = m_part.UUID;
  138. Items.Add(item.ItemID, item);
  139. }
  140. }
  141. }
  142. /// <summary>
  143. /// Change every item in this inventory to a new owner.
  144. /// </summary>
  145. /// <param name="ownerId"></param>
  146. public void ChangeInventoryOwner(UUID ownerId)
  147. {
  148. lock (Items)
  149. {
  150. if (0 == Items.Count)
  151. {
  152. return;
  153. }
  154. }
  155. HasInventoryChanged = true;
  156. m_part.ParentGroup.HasGroupChanged = true;
  157. List<TaskInventoryItem> items = GetInventoryItems();
  158. foreach (TaskInventoryItem item in items)
  159. {
  160. if (ownerId != item.OwnerID)
  161. item.LastOwnerID = item.OwnerID;
  162. item.OwnerID = ownerId;
  163. item.PermsMask = 0;
  164. item.PermsGranter = UUID.Zero;
  165. item.OwnerChanged = true;
  166. }
  167. }
  168. /// <summary>
  169. /// Change every item in this inventory to a new group.
  170. /// </summary>
  171. /// <param name="groupID"></param>
  172. public void ChangeInventoryGroup(UUID groupID)
  173. {
  174. lock (Items)
  175. {
  176. if (0 == Items.Count)
  177. {
  178. return;
  179. }
  180. }
  181. // Don't let this set the HasGroupChanged flag for attachments
  182. // as this happens during rez and we don't want a new asset
  183. // for each attachment each time
  184. if (!m_part.ParentGroup.IsAttachment)
  185. {
  186. HasInventoryChanged = true;
  187. m_part.ParentGroup.HasGroupChanged = true;
  188. }
  189. List<TaskInventoryItem> items = GetInventoryItems();
  190. foreach (TaskInventoryItem item in items)
  191. {
  192. if (groupID != item.GroupID)
  193. item.GroupID = groupID;
  194. }
  195. }
  196. /// <summary>
  197. /// Start all the scripts contained in this prim's inventory
  198. /// </summary>
  199. public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
  200. {
  201. List<TaskInventoryItem> scripts = GetInventoryScripts();
  202. foreach (TaskInventoryItem item in scripts)
  203. CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
  204. }
  205. public ArrayList GetScriptErrors(UUID itemID)
  206. {
  207. ArrayList ret = new ArrayList();
  208. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  209. if (engines == null) // No engine at all
  210. return ret;
  211. foreach (IScriptModule e in engines)
  212. {
  213. if (e != null)
  214. {
  215. ArrayList errors = e.GetScriptErrors(itemID);
  216. foreach (Object line in errors)
  217. ret.Add(line);
  218. }
  219. }
  220. return ret;
  221. }
  222. /// <summary>
  223. /// Stop all the scripts in this prim.
  224. /// </summary>
  225. /// <param name="sceneObjectBeingDeleted">
  226. /// Should be true if these scripts are being removed because the scene
  227. /// object is being deleted. This will prevent spurious updates to the client.
  228. /// </param>
  229. public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
  230. {
  231. List<TaskInventoryItem> scripts = GetInventoryScripts();
  232. foreach (TaskInventoryItem item in scripts)
  233. RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
  234. }
  235. /// <summary>
  236. /// Start a script which is in this prim's inventory.
  237. /// </summary>
  238. /// <param name="item"></param>
  239. /// <returns></returns>
  240. public void CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource)
  241. {
  242. // m_log.InfoFormat(
  243. // "[PRIM INVENTORY]: " +
  244. // "Starting script {0}, {1} in prim {2}, {3}",
  245. // item.Name, item.ItemID, Name, UUID);
  246. if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
  247. return;
  248. m_part.AddFlag(PrimFlags.Scripted);
  249. if (!m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts)
  250. {
  251. if (stateSource == 2 && // Prim crossing
  252. m_part.ParentGroup.Scene.m_trustBinaries)
  253. {
  254. lock (m_items)
  255. {
  256. m_items[item.ItemID].PermsMask = 0;
  257. m_items[item.ItemID].PermsGranter = UUID.Zero;
  258. }
  259. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  260. m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
  261. m_part.ParentGroup.AddActiveScriptCount(1);
  262. m_part.ScheduleFullUpdate();
  263. return;
  264. }
  265. AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  266. if (null == asset)
  267. {
  268. m_log.ErrorFormat(
  269. "[PRIM INVENTORY]: " +
  270. "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
  271. item.Name, item.ItemID, m_part.AbsolutePosition,
  272. m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID);
  273. }
  274. else
  275. {
  276. if (m_part.ParentGroup.m_savedScriptState != null)
  277. RestoreSavedScriptState(item.OldItemID, item.ItemID);
  278. lock (m_items)
  279. {
  280. m_items[item.ItemID].PermsMask = 0;
  281. m_items[item.ItemID].PermsGranter = UUID.Zero;
  282. }
  283. string script = Utils.BytesToString(asset.Data);
  284. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  285. m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
  286. m_part.ParentGroup.AddActiveScriptCount(1);
  287. m_part.ScheduleFullUpdate();
  288. }
  289. }
  290. }
  291. private void RestoreSavedScriptState(UUID oldID, UUID newID)
  292. {
  293. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  294. if (engines == null) // No engine at all
  295. return;
  296. if (m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
  297. {
  298. XmlDocument doc = new XmlDocument();
  299. doc.LoadXml(m_part.ParentGroup.m_savedScriptState[oldID]);
  300. ////////// CRUFT WARNING ///////////////////////////////////
  301. //
  302. // Old objects will have <ScriptState><State> ...
  303. // This format is XEngine ONLY
  304. //
  305. // New objects have <State Engine="...." ...><ScriptState>...
  306. // This can be passed to any engine
  307. //
  308. XmlNode n = doc.SelectSingleNode("ScriptState");
  309. if (n != null) // Old format data
  310. {
  311. XmlDocument newDoc = new XmlDocument();
  312. XmlElement rootN = newDoc.CreateElement("", "State", "");
  313. XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", "");
  314. uuidA.Value = oldID.ToString();
  315. rootN.Attributes.Append(uuidA);
  316. XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", "");
  317. engineA.Value = "XEngine";
  318. rootN.Attributes.Append(engineA);
  319. newDoc.AppendChild(rootN);
  320. XmlNode stateN = newDoc.ImportNode(n, true);
  321. rootN.AppendChild(stateN);
  322. // This created document has only the minimun data
  323. // necessary for XEngine to parse it successfully
  324. m_part.ParentGroup.m_savedScriptState[oldID] = newDoc.OuterXml;
  325. }
  326. foreach (IScriptModule e in engines)
  327. {
  328. if (e != null)
  329. {
  330. if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[oldID]))
  331. break;
  332. }
  333. }
  334. m_part.ParentGroup.m_savedScriptState.Remove(oldID);
  335. }
  336. }
  337. /// <summary>
  338. /// Start a script which is in this prim's inventory.
  339. /// </summary>
  340. /// <param name="itemId">
  341. /// A <see cref="UUID"/>
  342. /// </param>
  343. public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
  344. {
  345. TaskInventoryItem item = GetInventoryItem(itemId);
  346. if (item != null)
  347. CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
  348. else
  349. m_log.ErrorFormat(
  350. "[PRIM INVENTORY]: " +
  351. "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  352. itemId, m_part.Name, m_part.UUID,
  353. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  354. }
  355. /// <summary>
  356. /// Stop a script which is in this prim's inventory.
  357. /// </summary>
  358. /// <param name="itemId"></param>
  359. /// <param name="sceneObjectBeingDeleted">
  360. /// Should be true if this script is being removed because the scene
  361. /// object is being deleted. This will prevent spurious updates to the client.
  362. /// </param>
  363. public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
  364. {
  365. bool scriptPresent = false;
  366. lock (m_items)
  367. {
  368. if (m_items.ContainsKey(itemId))
  369. scriptPresent = true;
  370. }
  371. if (scriptPresent)
  372. {
  373. if (!sceneObjectBeingDeleted)
  374. m_part.RemoveScriptEvents(itemId);
  375. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
  376. m_part.ParentGroup.AddActiveScriptCount(-1);
  377. }
  378. else
  379. {
  380. m_log.ErrorFormat(
  381. "[PRIM INVENTORY]: " +
  382. "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  383. itemId, m_part.Name, m_part.UUID,
  384. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  385. }
  386. }
  387. /// <summary>
  388. /// Check if the inventory holds an item with a given name.
  389. /// </summary>
  390. /// <param name="name"></param>
  391. /// <returns></returns>
  392. private bool InventoryContainsName(string name)
  393. {
  394. lock (m_items)
  395. {
  396. foreach (TaskInventoryItem item in m_items.Values)
  397. {
  398. if (item.Name == name)
  399. return true;
  400. }
  401. }
  402. return false;
  403. }
  404. /// <summary>
  405. /// For a given item name, return that name if it is available. Otherwise, return the next available
  406. /// similar name (which is currently the original name with the next available numeric suffix).
  407. /// </summary>
  408. /// <param name="name"></param>
  409. /// <returns></returns>
  410. private string FindAvailableInventoryName(string name)
  411. {
  412. if (!InventoryContainsName(name))
  413. return name;
  414. int suffix=1;
  415. while (suffix < 256)
  416. {
  417. string tryName=String.Format("{0} {1}", name, suffix);
  418. if (!InventoryContainsName(tryName))
  419. return tryName;
  420. suffix++;
  421. }
  422. return String.Empty;
  423. }
  424. /// <summary>
  425. /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
  426. /// name is chosen.
  427. /// </summary>
  428. /// <param name="item"></param>
  429. public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
  430. {
  431. AddInventoryItem(item.Name, item, allowedDrop);
  432. }
  433. /// <summary>
  434. /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
  435. /// </summary>
  436. /// <param name="item"></param>
  437. public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
  438. {
  439. List<TaskInventoryItem> il = GetInventoryItems();
  440. foreach (TaskInventoryItem i in il)
  441. {
  442. if (i.Name == item.Name)
  443. {
  444. if (i.InvType == (int)InventoryType.LSL)
  445. RemoveScriptInstance(i.ItemID, false);
  446. RemoveInventoryItem(i.ItemID);
  447. break;
  448. }
  449. }
  450. AddInventoryItem(item.Name, item, allowedDrop);
  451. }
  452. /// <summary>
  453. /// Add an item to this prim's inventory.
  454. /// </summary>
  455. /// <param name="name">The name that the new item should have.</param>
  456. /// <param name="item">
  457. /// The item itself. The name within this structure is ignored in favour of the name
  458. /// given in this method's arguments
  459. /// </param>
  460. /// <param name="allowedDrop">
  461. /// Item was only added to inventory because AllowedDrop is set
  462. /// </param>
  463. protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
  464. {
  465. name = FindAvailableInventoryName(name);
  466. if (name == String.Empty)
  467. return;
  468. item.ParentID = m_part.UUID;
  469. item.ParentPartID = m_part.UUID;
  470. item.Name = name;
  471. item.GroupID = m_part.GroupID;
  472. lock (m_items)
  473. m_items.Add(item.ItemID, item);
  474. if (allowedDrop)
  475. m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
  476. else
  477. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  478. m_inventorySerial++;
  479. //m_inventorySerial += 2;
  480. HasInventoryChanged = true;
  481. m_part.ParentGroup.HasGroupChanged = true;
  482. }
  483. /// <summary>
  484. /// Restore a whole collection of items to the prim's inventory at once.
  485. /// We assume that the items already have all their fields correctly filled out.
  486. /// The items are not flagged for persistence to the database, since they are being restored
  487. /// from persistence rather than being newly added.
  488. /// </summary>
  489. /// <param name="items"></param>
  490. public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
  491. {
  492. lock (m_items)
  493. {
  494. foreach (TaskInventoryItem item in items)
  495. {
  496. m_items.Add(item.ItemID, item);
  497. // m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  498. }
  499. m_inventorySerial++;
  500. }
  501. }
  502. /// <summary>
  503. /// Returns an existing inventory item. Returns the original, so any changes will be live.
  504. /// </summary>
  505. /// <param name="itemID"></param>
  506. /// <returns>null if the item does not exist</returns>
  507. public TaskInventoryItem GetInventoryItem(UUID itemId)
  508. {
  509. TaskInventoryItem item;
  510. lock (m_items)
  511. m_items.TryGetValue(itemId, out item);
  512. return item;
  513. }
  514. /// <summary>
  515. /// Get inventory items by name.
  516. /// </summary>
  517. /// <param name="name"></param>
  518. /// <returns>
  519. /// A list of inventory items with that name.
  520. /// If no inventory item has that name then an empty list is returned.
  521. /// </returns>
  522. public IList<TaskInventoryItem> GetInventoryItems(string name)
  523. {
  524. IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
  525. lock (m_items)
  526. {
  527. foreach (TaskInventoryItem item in m_items.Values)
  528. {
  529. if (item.Name == name)
  530. items.Add(item);
  531. }
  532. }
  533. return items;
  534. }
  535. public SceneObjectGroup GetRezReadySceneObject(TaskInventoryItem item)
  536. {
  537. AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  538. if (null == rezAsset)
  539. {
  540. m_log.WarnFormat(
  541. "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
  542. item.AssetID, item.Name, m_part.Name);
  543. return null;
  544. }
  545. string xmlData = Utils.BytesToString(rezAsset.Data);
  546. SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
  547. group.ResetIDs();
  548. SceneObjectPart rootPart = group.GetChildPart(group.UUID);
  549. // Since renaming the item in the inventory does not affect the name stored
  550. // in the serialization, transfer the correct name from the inventory to the
  551. // object itself before we rez.
  552. rootPart.Name = item.Name;
  553. rootPart.Description = item.Description;
  554. SceneObjectPart[] partList = group.Parts;
  555. group.SetGroup(m_part.GroupID, null);
  556. // TODO: Remove magic number badness
  557. if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number
  558. {
  559. if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions())
  560. {
  561. foreach (SceneObjectPart part in partList)
  562. {
  563. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  564. part.EveryoneMask = item.EveryonePermissions;
  565. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  566. part.NextOwnerMask = item.NextPermissions;
  567. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  568. part.GroupMask = item.GroupPermissions;
  569. }
  570. group.ApplyNextOwnerPermissions();
  571. }
  572. }
  573. foreach (SceneObjectPart part in partList)
  574. {
  575. // TODO: Remove magic number badness
  576. if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number
  577. {
  578. part.LastOwnerID = part.OwnerID;
  579. part.OwnerID = item.OwnerID;
  580. part.Inventory.ChangeInventoryOwner(item.OwnerID);
  581. }
  582. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  583. part.EveryoneMask = item.EveryonePermissions;
  584. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  585. part.NextOwnerMask = item.NextPermissions;
  586. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  587. part.GroupMask = item.GroupPermissions;
  588. }
  589. rootPart.TrimPermissions();
  590. return group;
  591. }
  592. /// <summary>
  593. /// Update an existing inventory item.
  594. /// </summary>
  595. /// <param name="item">The updated item. An item with the same id must already exist
  596. /// in this prim's inventory.</param>
  597. /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
  598. public bool UpdateInventoryItem(TaskInventoryItem item)
  599. {
  600. return UpdateInventoryItem(item, true, true);
  601. }
  602. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
  603. {
  604. return UpdateInventoryItem(item, fireScriptEvents, true);
  605. }
  606. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
  607. {
  608. TaskInventoryItem it = GetInventoryItem(item.ItemID);
  609. if (it != null)
  610. {
  611. // m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
  612. item.ParentID = m_part.UUID;
  613. item.ParentPartID = m_part.UUID;
  614. // If group permissions have been set on, check that the groupID is up to date in case it has
  615. // changed since permissions were last set.
  616. if (item.GroupPermissions != (uint)PermissionMask.None)
  617. item.GroupID = m_part.GroupID;
  618. if (item.AssetID == UUID.Zero)
  619. item.AssetID = it.AssetID;
  620. lock (m_items)
  621. {
  622. m_items[item.ItemID] = item;
  623. m_inventorySerial++;
  624. }
  625. if (fireScriptEvents)
  626. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  627. if (considerChanged)
  628. {
  629. HasInventoryChanged = true;
  630. m_part.ParentGroup.HasGroupChanged = true;
  631. }
  632. return true;
  633. }
  634. else
  635. {
  636. m_log.ErrorFormat(
  637. "[PRIM INVENTORY]: " +
  638. "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
  639. item.ItemID, m_part.Name, m_part.UUID,
  640. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  641. }
  642. return false;
  643. }
  644. /// <summary>
  645. /// Remove an item from this prim's inventory
  646. /// </summary>
  647. /// <param name="itemID"></param>
  648. /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
  649. /// in this prim's inventory.</returns>
  650. public int RemoveInventoryItem(UUID itemID)
  651. {
  652. TaskInventoryItem item = GetInventoryItem(itemID);
  653. if (item != null)
  654. {
  655. int type = m_items[itemID].InvType;
  656. if (type == 10) // Script
  657. {
  658. m_part.RemoveScriptEvents(itemID);
  659. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
  660. }
  661. m_items.Remove(itemID);
  662. m_inventorySerial++;
  663. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  664. HasInventoryChanged = true;
  665. m_part.ParentGroup.HasGroupChanged = true;
  666. if (!ContainsScripts())
  667. m_part.RemFlag(PrimFlags.Scripted);
  668. m_part.ScheduleFullUpdate();
  669. return type;
  670. }
  671. else
  672. {
  673. m_log.ErrorFormat(
  674. "[PRIM INVENTORY]: " +
  675. "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
  676. itemID, m_part.Name, m_part.UUID,
  677. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  678. }
  679. return -1;
  680. }
  681. private bool CreateInventoryFile()
  682. {
  683. if (m_inventoryFileName == String.Empty ||
  684. m_inventoryFileNameSerial < m_inventorySerial)
  685. {
  686. // Something changed, we need to create a new file
  687. m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
  688. m_inventoryFileNameSerial = m_inventorySerial;
  689. InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
  690. lock (m_items)
  691. {
  692. foreach (TaskInventoryItem item in m_items.Values)
  693. {
  694. UUID ownerID = item.OwnerID;
  695. uint everyoneMask = 0;
  696. uint baseMask = item.BasePermissions;
  697. uint ownerMask = item.CurrentPermissions;
  698. uint groupMask = item.GroupPermissions;
  699. invString.AddItemStart();
  700. invString.AddNameValueLine("item_id", item.ItemID.ToString());
  701. invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
  702. invString.AddPermissionsStart();
  703. invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
  704. invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
  705. invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
  706. invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
  707. invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
  708. invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
  709. invString.AddNameValueLine("owner_id", ownerID.ToString());
  710. invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
  711. invString.AddNameValueLine("group_id", item.GroupID.ToString());
  712. invString.AddSectionEnd();
  713. invString.AddNameValueLine("asset_id", item.AssetID.ToString());
  714. invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
  715. invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
  716. invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
  717. invString.AddSaleStart();
  718. invString.AddNameValueLine("sale_type", "not");
  719. invString.AddNameValueLine("sale_price", "0");
  720. invString.AddSectionEnd();
  721. invString.AddNameValueLine("name", item.Name + "|");
  722. invString.AddNameValueLine("desc", item.Description + "|");
  723. invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
  724. invString.AddSectionEnd();
  725. }
  726. }
  727. m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
  728. return true;
  729. }
  730. // No need to recreate, the existing file is fine
  731. return false;
  732. }
  733. /// <summary>
  734. /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
  735. /// </summary>
  736. /// <param name="xferManager"></param>
  737. public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
  738. {
  739. CreateInventoryFile();
  740. if (m_inventorySerial == 0) // No inventory
  741. {
  742. client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
  743. return;
  744. }
  745. // In principle, we should only do the rest if the inventory changed;
  746. // by sending m_inventorySerial to the client, it ought to know
  747. // that nothing changed and that it doesn't need to request the file.
  748. // Unfortunately, it doesn't look like the client optimizes this;
  749. // the client seems to always come back and request the Xfer,
  750. // no matter what value m_inventorySerial has.
  751. if (m_inventoryFileData.Length > 2)
  752. // Add the file for Xfer
  753. xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
  754. // Tell the client we're ready to Xfer the file
  755. client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
  756. Util.StringToBytes256(m_inventoryFileName));
  757. }
  758. /// <summary>
  759. /// Process inventory backup
  760. /// </summary>
  761. /// <param name="datastore"></param>
  762. public void ProcessInventoryBackup(ISimulationDataService datastore)
  763. {
  764. if (HasInventoryChanged)
  765. {
  766. HasInventoryChanged = false;
  767. List<TaskInventoryItem> items = GetInventoryItems();
  768. datastore.StorePrimInventory(m_part.UUID, items);
  769. }
  770. }
  771. public class InventoryStringBuilder
  772. {
  773. public string BuildString = String.Empty;
  774. public InventoryStringBuilder(UUID folderID, UUID parentID)
  775. {
  776. BuildString += "\tinv_object\t0\n\t{\n";
  777. AddNameValueLine("obj_id", folderID.ToString());
  778. AddNameValueLine("parent_id", parentID.ToString());
  779. AddNameValueLine("type", "category");
  780. AddNameValueLine("name", "Contents|");
  781. AddSectionEnd();
  782. }
  783. public void AddItemStart()
  784. {
  785. BuildString += "\tinv_item\t0\n";
  786. AddSectionStart();
  787. }
  788. public void AddPermissionsStart()
  789. {
  790. BuildString += "\tpermissions 0\n";
  791. AddSectionStart();
  792. }
  793. public void AddSaleStart()
  794. {
  795. BuildString += "\tsale_info\t0\n";
  796. AddSectionStart();
  797. }
  798. protected void AddSectionStart()
  799. {
  800. BuildString += "\t{\n";
  801. }
  802. public void AddSectionEnd()
  803. {
  804. BuildString += "\t}\n";
  805. }
  806. public void AddLine(string addLine)
  807. {
  808. BuildString += addLine;
  809. }
  810. public void AddNameValueLine(string name, string value)
  811. {
  812. BuildString += "\t\t";
  813. BuildString += name + "\t";
  814. BuildString += value + "\n";
  815. }
  816. public void Close()
  817. {
  818. }
  819. }
  820. public uint MaskEffectivePermissions()
  821. {
  822. uint mask=0x7fffffff;
  823. lock (m_items)
  824. {
  825. foreach (TaskInventoryItem item in m_items.Values)
  826. {
  827. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
  828. mask &= ~((uint)PermissionMask.Copy >> 13);
  829. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
  830. mask &= ~((uint)PermissionMask.Transfer >> 13);
  831. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
  832. mask &= ~((uint)PermissionMask.Modify >> 13);
  833. if (item.InvType != (int)InventoryType.Object)
  834. {
  835. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
  836. mask &= ~((uint)PermissionMask.Copy >> 13);
  837. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
  838. mask &= ~((uint)PermissionMask.Transfer >> 13);
  839. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
  840. mask &= ~((uint)PermissionMask.Modify >> 13);
  841. }
  842. else
  843. {
  844. if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
  845. mask &= ~((uint)PermissionMask.Copy >> 13);
  846. if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
  847. mask &= ~((uint)PermissionMask.Transfer >> 13);
  848. if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
  849. mask &= ~((uint)PermissionMask.Modify >> 13);
  850. }
  851. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  852. mask &= ~(uint)PermissionMask.Copy;
  853. if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
  854. mask &= ~(uint)PermissionMask.Transfer;
  855. if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
  856. mask &= ~(uint)PermissionMask.Modify;
  857. }
  858. }
  859. return mask;
  860. }
  861. public void ApplyNextOwnerPermissions()
  862. {
  863. lock (m_items)
  864. {
  865. foreach (TaskInventoryItem item in m_items.Values)
  866. {
  867. if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
  868. {
  869. if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
  870. item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
  871. if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
  872. item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
  873. if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
  874. item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
  875. }
  876. item.CurrentPermissions &= item.NextPermissions;
  877. item.BasePermissions &= item.NextPermissions;
  878. item.EveryonePermissions &= item.NextPermissions;
  879. item.OwnerChanged = true;
  880. item.PermsMask = 0;
  881. item.PermsGranter = UUID.Zero;
  882. }
  883. }
  884. }
  885. public void ApplyGodPermissions(uint perms)
  886. {
  887. lock (m_items)
  888. {
  889. foreach (TaskInventoryItem item in m_items.Values)
  890. {
  891. item.CurrentPermissions = perms;
  892. item.BasePermissions = perms;
  893. }
  894. }
  895. m_inventorySerial++;
  896. HasInventoryChanged = true;
  897. }
  898. /// <summary>
  899. /// Returns true if this part inventory contains any scripts. False otherwise.
  900. /// </summary>
  901. /// <returns></returns>
  902. public bool ContainsScripts()
  903. {
  904. lock (m_items)
  905. {
  906. foreach (TaskInventoryItem item in m_items.Values)
  907. {
  908. if (item.InvType == (int)InventoryType.LSL)
  909. {
  910. return true;
  911. }
  912. }
  913. }
  914. return false;
  915. }
  916. public List<UUID> GetInventoryList()
  917. {
  918. List<UUID> ret = new List<UUID>();
  919. lock (m_items)
  920. {
  921. foreach (TaskInventoryItem item in m_items.Values)
  922. ret.Add(item.ItemID);
  923. }
  924. return ret;
  925. }
  926. public List<TaskInventoryItem> GetInventoryItems()
  927. {
  928. List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
  929. lock (m_items)
  930. ret = new List<TaskInventoryItem>(m_items.Values);
  931. return ret;
  932. }
  933. public List<TaskInventoryItem> GetInventoryScripts()
  934. {
  935. List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
  936. lock (m_items)
  937. {
  938. foreach (TaskInventoryItem item in m_items.Values)
  939. if (item.InvType == (int)InventoryType.LSL)
  940. ret.Add(item);
  941. }
  942. return ret;
  943. }
  944. public Dictionary<UUID, string> GetScriptStates()
  945. {
  946. Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
  947. if (m_part.ParentGroup.Scene == null) // Group not in a scene
  948. return ret;
  949. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  950. if (engines == null) // No engine at all
  951. return ret;
  952. List<TaskInventoryItem> scripts = GetInventoryScripts();
  953. foreach (TaskInventoryItem item in scripts)
  954. {
  955. foreach (IScriptModule e in engines)
  956. {
  957. if (e != null)
  958. {
  959. string n = e.GetXMLState(item.ItemID);
  960. if (n != String.Empty)
  961. {
  962. if (!ret.ContainsKey(item.ItemID))
  963. ret[item.ItemID] = n;
  964. break;
  965. }
  966. }
  967. }
  968. }
  969. return ret;
  970. }
  971. public void ResumeScripts()
  972. {
  973. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  974. if (engines == null)
  975. return;
  976. List<TaskInventoryItem> scripts = GetInventoryScripts();
  977. foreach (TaskInventoryItem item in scripts)
  978. {
  979. foreach (IScriptModule engine in engines)
  980. {
  981. if (engine != null)
  982. {
  983. if (item.OwnerChanged)
  984. engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
  985. item.OwnerChanged = false;
  986. engine.ResumeScript(item.ItemID);
  987. }
  988. }
  989. }
  990. }
  991. }
  992. }