diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | 1346 |
1 files changed, 1346 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs new file mode 100644 index 0000000..ec39726 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | |||
@@ -0,0 +1,1346 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Xml; | ||
30 | using System.IO; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Collections; | ||
33 | using System.Reflection; | ||
34 | using System.Threading; | ||
35 | using OpenMetaverse; | ||
36 | using log4net; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes.Scripting; | ||
40 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
41 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
42 | |||
43 | namespace OpenSim.Region.Framework.Scenes | ||
44 | { | ||
45 | public class SceneObjectPartInventory : IEntityInventory | ||
46 | { | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private string m_inventoryFileName = String.Empty; | ||
50 | private byte[] m_inventoryFileData = new byte[0]; | ||
51 | private uint m_inventoryFileNameSerial = 0; | ||
52 | |||
53 | /// <value> | ||
54 | /// The part to which the inventory belongs. | ||
55 | /// </value> | ||
56 | private SceneObjectPart m_part; | ||
57 | |||
58 | /// <summary> | ||
59 | /// Serial count for inventory file , used to tell if inventory has changed | ||
60 | /// no need for this to be part of Database backup | ||
61 | /// </summary> | ||
62 | protected uint m_inventorySerial = 0; | ||
63 | |||
64 | /// <summary> | ||
65 | /// Holds in memory prim inventory | ||
66 | /// </summary> | ||
67 | protected TaskInventoryDictionary m_items = new TaskInventoryDictionary(); | ||
68 | |||
69 | /// <summary> | ||
70 | /// Tracks whether inventory has changed since the last persistent backup | ||
71 | /// </summary> | ||
72 | internal bool HasInventoryChanged; | ||
73 | |||
74 | /// <value> | ||
75 | /// Inventory serial number | ||
76 | /// </value> | ||
77 | protected internal uint Serial | ||
78 | { | ||
79 | get { return m_inventorySerial; } | ||
80 | set { m_inventorySerial = value; } | ||
81 | } | ||
82 | |||
83 | /// <value> | ||
84 | /// Raw inventory data | ||
85 | /// </value> | ||
86 | protected internal TaskInventoryDictionary Items | ||
87 | { | ||
88 | get { return m_items; } | ||
89 | set | ||
90 | { | ||
91 | m_items = value; | ||
92 | m_inventorySerial++; | ||
93 | QueryScriptStates(); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | public int Count | ||
98 | { | ||
99 | get | ||
100 | { | ||
101 | lock (m_items) | ||
102 | return m_items.Count; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | /// <summary> | ||
107 | /// Constructor | ||
108 | /// </summary> | ||
109 | /// <param name="part"> | ||
110 | /// A <see cref="SceneObjectPart"/> | ||
111 | /// </param> | ||
112 | public SceneObjectPartInventory(SceneObjectPart part) | ||
113 | { | ||
114 | m_part = part; | ||
115 | } | ||
116 | |||
117 | /// <summary> | ||
118 | /// Force the task inventory of this prim to persist at the next update sweep | ||
119 | /// </summary> | ||
120 | public void ForceInventoryPersistence() | ||
121 | { | ||
122 | HasInventoryChanged = true; | ||
123 | } | ||
124 | |||
125 | /// <summary> | ||
126 | /// Reset UUIDs for all the items in the prim's inventory. | ||
127 | /// </summary> | ||
128 | /// <remarks> | ||
129 | /// This involves either generating | ||
130 | /// new ones or setting existing UUIDs to the correct parent UUIDs. | ||
131 | /// | ||
132 | /// If this method is called and there are inventory items, then we regard the inventory as having changed. | ||
133 | /// </remarks> | ||
134 | public void ResetInventoryIDs() | ||
135 | { | ||
136 | if (null == m_part) | ||
137 | return; | ||
138 | |||
139 | lock (m_items) | ||
140 | { | ||
141 | if (0 == m_items.Count) | ||
142 | return; | ||
143 | |||
144 | IList<TaskInventoryItem> items = GetInventoryItems(); | ||
145 | m_items.Clear(); | ||
146 | |||
147 | foreach (TaskInventoryItem item in items) | ||
148 | { | ||
149 | item.ResetIDs(m_part.UUID); | ||
150 | m_items.Add(item.ItemID, item); | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | public void ResetObjectID() | ||
156 | { | ||
157 | lock (Items) | ||
158 | { | ||
159 | IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); | ||
160 | Items.Clear(); | ||
161 | |||
162 | foreach (TaskInventoryItem item in items) | ||
163 | { | ||
164 | item.ParentPartID = m_part.UUID; | ||
165 | item.ParentID = m_part.UUID; | ||
166 | Items.Add(item.ItemID, item); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | /// <summary> | ||
172 | /// Change every item in this inventory to a new owner. | ||
173 | /// </summary> | ||
174 | /// <param name="ownerId"></param> | ||
175 | public void ChangeInventoryOwner(UUID ownerId) | ||
176 | { | ||
177 | lock (Items) | ||
178 | { | ||
179 | if (0 == Items.Count) | ||
180 | { | ||
181 | return; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | HasInventoryChanged = true; | ||
186 | m_part.ParentGroup.HasGroupChanged = true; | ||
187 | List<TaskInventoryItem> items = GetInventoryItems(); | ||
188 | foreach (TaskInventoryItem item in items) | ||
189 | { | ||
190 | if (ownerId != item.OwnerID) | ||
191 | item.LastOwnerID = item.OwnerID; | ||
192 | |||
193 | item.OwnerID = ownerId; | ||
194 | item.PermsMask = 0; | ||
195 | item.PermsGranter = UUID.Zero; | ||
196 | item.OwnerChanged = true; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /// <summary> | ||
201 | /// Change every item in this inventory to a new group. | ||
202 | /// </summary> | ||
203 | /// <param name="groupID"></param> | ||
204 | public void ChangeInventoryGroup(UUID groupID) | ||
205 | { | ||
206 | lock (Items) | ||
207 | { | ||
208 | if (0 == Items.Count) | ||
209 | { | ||
210 | return; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | // Don't let this set the HasGroupChanged flag for attachments | ||
215 | // as this happens during rez and we don't want a new asset | ||
216 | // for each attachment each time | ||
217 | if (!m_part.ParentGroup.IsAttachment) | ||
218 | { | ||
219 | HasInventoryChanged = true; | ||
220 | m_part.ParentGroup.HasGroupChanged = true; | ||
221 | } | ||
222 | |||
223 | List<TaskInventoryItem> items = GetInventoryItems(); | ||
224 | foreach (TaskInventoryItem item in items) | ||
225 | { | ||
226 | if (groupID != item.GroupID) | ||
227 | item.GroupID = groupID; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | private void QueryScriptStates() | ||
232 | { | ||
233 | if (m_part == null || m_part.ParentGroup == null || m_part.ParentGroup.Scene == null) | ||
234 | return; | ||
235 | |||
236 | lock (Items) | ||
237 | { | ||
238 | foreach (TaskInventoryItem item in Items.Values) | ||
239 | { | ||
240 | bool running; | ||
241 | if (TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running)) | ||
242 | item.ScriptRunning = running; | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | public bool TryGetScriptInstanceRunning(UUID itemId, out bool running) | ||
248 | { | ||
249 | running = false; | ||
250 | |||
251 | TaskInventoryItem item = GetInventoryItem(itemId); | ||
252 | |||
253 | if (item == null) | ||
254 | return false; | ||
255 | |||
256 | return TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running); | ||
257 | } | ||
258 | |||
259 | public static bool TryGetScriptInstanceRunning(Scene scene, TaskInventoryItem item, out bool running) | ||
260 | { | ||
261 | running = false; | ||
262 | |||
263 | if (item.InvType != (int)InventoryType.LSL) | ||
264 | return false; | ||
265 | |||
266 | IScriptModule[] engines = scene.RequestModuleInterfaces<IScriptModule>(); | ||
267 | if (engines == null) // No engine at all | ||
268 | return false; | ||
269 | |||
270 | foreach (IScriptModule e in engines) | ||
271 | { | ||
272 | if (e.HasScript(item.ItemID, out running)) | ||
273 | return true; | ||
274 | } | ||
275 | |||
276 | return false; | ||
277 | } | ||
278 | |||
279 | public int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) | ||
280 | { | ||
281 | int scriptsValidForStarting = 0; | ||
282 | |||
283 | List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); | ||
284 | foreach (TaskInventoryItem item in scripts) | ||
285 | if (CreateScriptInstance(item, startParam, postOnRez, engine, stateSource)) | ||
286 | scriptsValidForStarting++; | ||
287 | |||
288 | return scriptsValidForStarting; | ||
289 | } | ||
290 | |||
291 | public ArrayList GetScriptErrors(UUID itemID) | ||
292 | { | ||
293 | ArrayList ret = new ArrayList(); | ||
294 | |||
295 | IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); | ||
296 | |||
297 | foreach (IScriptModule e in engines) | ||
298 | { | ||
299 | if (e != null) | ||
300 | { | ||
301 | ArrayList errors = e.GetScriptErrors(itemID); | ||
302 | foreach (Object line in errors) | ||
303 | ret.Add(line); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | /// <summary> | ||
311 | /// Stop and remove all the scripts in this prim. | ||
312 | /// </summary> | ||
313 | /// <param name="sceneObjectBeingDeleted"> | ||
314 | /// Should be true if these scripts are being removed because the scene | ||
315 | /// object is being deleted. This will prevent spurious updates to the client. | ||
316 | /// </param> | ||
317 | public void RemoveScriptInstances(bool sceneObjectBeingDeleted) | ||
318 | { | ||
319 | List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); | ||
320 | foreach (TaskInventoryItem item in scripts) | ||
321 | RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); | ||
322 | } | ||
323 | |||
324 | /// <summary> | ||
325 | /// Stop all the scripts in this prim. | ||
326 | /// </summary> | ||
327 | public void StopScriptInstances() | ||
328 | { | ||
329 | GetInventoryItems(InventoryType.LSL).ForEach(i => StopScriptInstance(i)); | ||
330 | } | ||
331 | |||
332 | /// <summary> | ||
333 | /// Start a script which is in this prim's inventory. | ||
334 | /// </summary> | ||
335 | /// <param name="item"></param> | ||
336 | /// <returns>true if the script instance was created, false otherwise</returns> | ||
337 | public bool CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource) | ||
338 | { | ||
339 | // m_log.DebugFormat("[PRIM INVENTORY]: Starting script {0} {1} in prim {2} {3} in {4}", | ||
340 | // item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
341 | |||
342 | if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) | ||
343 | return false; | ||
344 | |||
345 | m_part.AddFlag(PrimFlags.Scripted); | ||
346 | |||
347 | if (m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts) | ||
348 | return false; | ||
349 | |||
350 | if (stateSource == 2 && // Prim crossing | ||
351 | m_part.ParentGroup.Scene.m_trustBinaries) | ||
352 | { | ||
353 | lock (m_items) | ||
354 | { | ||
355 | m_items[item.ItemID].PermsMask = 0; | ||
356 | m_items[item.ItemID].PermsGranter = UUID.Zero; | ||
357 | } | ||
358 | |||
359 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( | ||
360 | m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); | ||
361 | m_part.ParentGroup.AddActiveScriptCount(1); | ||
362 | m_part.ScheduleFullUpdate(); | ||
363 | return true; | ||
364 | } | ||
365 | |||
366 | AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); | ||
367 | if (null == asset) | ||
368 | { | ||
369 | m_log.ErrorFormat( | ||
370 | "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", | ||
371 | item.Name, item.ItemID, m_part.AbsolutePosition, | ||
372 | m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID); | ||
373 | |||
374 | return false; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | if (m_part.ParentGroup.m_savedScriptState != null) | ||
379 | item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); | ||
380 | |||
381 | lock (m_items) | ||
382 | { | ||
383 | m_items[item.ItemID].OldItemID = item.OldItemID; | ||
384 | m_items[item.ItemID].PermsMask = 0; | ||
385 | m_items[item.ItemID].PermsGranter = UUID.Zero; | ||
386 | } | ||
387 | |||
388 | string script = Utils.BytesToString(asset.Data); | ||
389 | m_part.ParentGroup.Scene.EventManager.TriggerRezScript( | ||
390 | m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); | ||
391 | if (!item.ScriptRunning) | ||
392 | m_part.ParentGroup.Scene.EventManager.TriggerStopScript( | ||
393 | m_part.LocalId, item.ItemID); | ||
394 | m_part.ParentGroup.AddActiveScriptCount(1); | ||
395 | m_part.ScheduleFullUpdate(); | ||
396 | |||
397 | return true; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID) | ||
402 | { | ||
403 | // m_log.DebugFormat( | ||
404 | // "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}", | ||
405 | // newID, oldID, loadedID); | ||
406 | |||
407 | IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); | ||
408 | if (engines.Length == 0) // No engine at all | ||
409 | return oldID; | ||
410 | |||
411 | UUID stateID = oldID; | ||
412 | if (!m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID)) | ||
413 | stateID = loadedID; | ||
414 | if (m_part.ParentGroup.m_savedScriptState.ContainsKey(stateID)) | ||
415 | { | ||
416 | XmlDocument doc = new XmlDocument(); | ||
417 | |||
418 | doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]); | ||
419 | |||
420 | ////////// CRUFT WARNING /////////////////////////////////// | ||
421 | // | ||
422 | // Old objects will have <ScriptState><State> ... | ||
423 | // This format is XEngine ONLY | ||
424 | // | ||
425 | // New objects have <State Engine="...." ...><ScriptState>... | ||
426 | // This can be passed to any engine | ||
427 | // | ||
428 | XmlNode n = doc.SelectSingleNode("ScriptState"); | ||
429 | if (n != null) // Old format data | ||
430 | { | ||
431 | XmlDocument newDoc = new XmlDocument(); | ||
432 | |||
433 | XmlElement rootN = newDoc.CreateElement("", "State", ""); | ||
434 | XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", ""); | ||
435 | uuidA.Value = stateID.ToString(); | ||
436 | rootN.Attributes.Append(uuidA); | ||
437 | XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", ""); | ||
438 | engineA.Value = "XEngine"; | ||
439 | rootN.Attributes.Append(engineA); | ||
440 | |||
441 | newDoc.AppendChild(rootN); | ||
442 | |||
443 | XmlNode stateN = newDoc.ImportNode(n, true); | ||
444 | rootN.AppendChild(stateN); | ||
445 | |||
446 | // This created document has only the minimun data | ||
447 | // necessary for XEngine to parse it successfully | ||
448 | |||
449 | // m_log.DebugFormat("[PRIM INVENTORY]: Adding legacy state {0} in {1}", stateID, newID); | ||
450 | |||
451 | m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml; | ||
452 | } | ||
453 | |||
454 | foreach (IScriptModule e in engines) | ||
455 | { | ||
456 | if (e != null) | ||
457 | { | ||
458 | if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[stateID])) | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | m_part.ParentGroup.m_savedScriptState.Remove(stateID); | ||
464 | } | ||
465 | |||
466 | return stateID; | ||
467 | } | ||
468 | |||
469 | public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) | ||
470 | { | ||
471 | TaskInventoryItem item = GetInventoryItem(itemId); | ||
472 | if (item != null) | ||
473 | { | ||
474 | return CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | m_log.ErrorFormat( | ||
479 | "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", | ||
480 | itemId, m_part.Name, m_part.UUID, | ||
481 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
482 | |||
483 | return false; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | /// <summary> | ||
488 | /// Stop and remove a script which is in this prim's inventory. | ||
489 | /// </summary> | ||
490 | /// <param name="itemId"></param> | ||
491 | /// <param name="sceneObjectBeingDeleted"> | ||
492 | /// Should be true if this script is being removed because the scene | ||
493 | /// object is being deleted. This will prevent spurious updates to the client. | ||
494 | /// </param> | ||
495 | public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted) | ||
496 | { | ||
497 | bool scriptPresent = false; | ||
498 | |||
499 | lock (m_items) | ||
500 | { | ||
501 | if (m_items.ContainsKey(itemId)) | ||
502 | scriptPresent = true; | ||
503 | } | ||
504 | |||
505 | if (scriptPresent) | ||
506 | { | ||
507 | if (!sceneObjectBeingDeleted) | ||
508 | m_part.RemoveScriptEvents(itemId); | ||
509 | |||
510 | m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId); | ||
511 | m_part.ParentGroup.AddActiveScriptCount(-1); | ||
512 | } | ||
513 | else | ||
514 | { | ||
515 | m_log.WarnFormat( | ||
516 | "[PRIM INVENTORY]: " + | ||
517 | "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", | ||
518 | itemId, m_part.Name, m_part.UUID, | ||
519 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | /// <summary> | ||
524 | /// Stop a script which is in this prim's inventory. | ||
525 | /// </summary> | ||
526 | /// <param name="itemId"></param> | ||
527 | /// <param name="sceneObjectBeingDeleted"> | ||
528 | /// Should be true if this script is being removed because the scene | ||
529 | /// object is being deleted. This will prevent spurious updates to the client. | ||
530 | /// </param> | ||
531 | public void StopScriptInstance(UUID itemId) | ||
532 | { | ||
533 | TaskInventoryItem scriptItem; | ||
534 | |||
535 | lock (m_items) | ||
536 | m_items.TryGetValue(itemId, out scriptItem); | ||
537 | |||
538 | if (scriptItem != null) | ||
539 | { | ||
540 | StopScriptInstance(scriptItem); | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | m_log.WarnFormat( | ||
545 | "[PRIM INVENTORY]: " + | ||
546 | "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", | ||
547 | itemId, m_part.Name, m_part.UUID, | ||
548 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | /// <summary> | ||
553 | /// Stop a script which is in this prim's inventory. | ||
554 | /// </summary> | ||
555 | /// <param name="itemId"></param> | ||
556 | /// <param name="sceneObjectBeingDeleted"> | ||
557 | /// Should be true if this script is being removed because the scene | ||
558 | /// object is being deleted. This will prevent spurious updates to the client. | ||
559 | /// </param> | ||
560 | public void StopScriptInstance(TaskInventoryItem item) | ||
561 | { | ||
562 | if (m_part.ParentGroup.Scene != null) | ||
563 | m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID); | ||
564 | |||
565 | // At the moment, even stopped scripts are counted as active, which is probably wrong. | ||
566 | // m_part.ParentGroup.AddActiveScriptCount(-1); | ||
567 | } | ||
568 | |||
569 | /// <summary> | ||
570 | /// Check if the inventory holds an item with a given name. | ||
571 | /// </summary> | ||
572 | /// <param name="name"></param> | ||
573 | /// <returns></returns> | ||
574 | private bool InventoryContainsName(string name) | ||
575 | { | ||
576 | lock (m_items) | ||
577 | { | ||
578 | foreach (TaskInventoryItem item in m_items.Values) | ||
579 | { | ||
580 | if (item.Name == name) | ||
581 | return true; | ||
582 | } | ||
583 | } | ||
584 | return false; | ||
585 | } | ||
586 | |||
587 | /// <summary> | ||
588 | /// For a given item name, return that name if it is available. Otherwise, return the next available | ||
589 | /// similar name (which is currently the original name with the next available numeric suffix). | ||
590 | /// </summary> | ||
591 | /// <param name="name"></param> | ||
592 | /// <returns></returns> | ||
593 | private string FindAvailableInventoryName(string name) | ||
594 | { | ||
595 | if (!InventoryContainsName(name)) | ||
596 | return name; | ||
597 | |||
598 | int suffix=1; | ||
599 | while (suffix < 256) | ||
600 | { | ||
601 | string tryName=String.Format("{0} {1}", name, suffix); | ||
602 | if (!InventoryContainsName(tryName)) | ||
603 | return tryName; | ||
604 | suffix++; | ||
605 | } | ||
606 | return String.Empty; | ||
607 | } | ||
608 | |||
609 | /// <summary> | ||
610 | /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative | ||
611 | /// name is chosen. | ||
612 | /// </summary> | ||
613 | /// <param name="item"></param> | ||
614 | public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop) | ||
615 | { | ||
616 | AddInventoryItem(item.Name, item, allowedDrop); | ||
617 | } | ||
618 | |||
619 | /// <summary> | ||
620 | /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced. | ||
621 | /// </summary> | ||
622 | /// <param name="item"></param> | ||
623 | public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) | ||
624 | { | ||
625 | List<TaskInventoryItem> il = GetInventoryItems(); | ||
626 | |||
627 | foreach (TaskInventoryItem i in il) | ||
628 | { | ||
629 | if (i.Name == item.Name) | ||
630 | { | ||
631 | if (i.InvType == (int)InventoryType.LSL) | ||
632 | RemoveScriptInstance(i.ItemID, false); | ||
633 | |||
634 | RemoveInventoryItem(i.ItemID); | ||
635 | break; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | AddInventoryItem(item.Name, item, allowedDrop); | ||
640 | } | ||
641 | |||
642 | /// <summary> | ||
643 | /// Add an item to this prim's inventory. | ||
644 | /// </summary> | ||
645 | /// <param name="name">The name that the new item should have.</param> | ||
646 | /// <param name="item"> | ||
647 | /// The item itself. The name within this structure is ignored in favour of the name | ||
648 | /// given in this method's arguments | ||
649 | /// </param> | ||
650 | /// <param name="allowedDrop"> | ||
651 | /// Item was only added to inventory because AllowedDrop is set | ||
652 | /// </param> | ||
653 | protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop) | ||
654 | { | ||
655 | name = FindAvailableInventoryName(name); | ||
656 | if (name == String.Empty) | ||
657 | return; | ||
658 | |||
659 | item.ParentID = m_part.UUID; | ||
660 | item.ParentPartID = m_part.UUID; | ||
661 | item.Name = name; | ||
662 | item.GroupID = m_part.GroupID; | ||
663 | |||
664 | lock (m_items) | ||
665 | m_items.Add(item.ItemID, item); | ||
666 | |||
667 | if (allowedDrop) | ||
668 | m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); | ||
669 | else | ||
670 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
671 | |||
672 | m_inventorySerial++; | ||
673 | //m_inventorySerial += 2; | ||
674 | HasInventoryChanged = true; | ||
675 | m_part.ParentGroup.HasGroupChanged = true; | ||
676 | } | ||
677 | |||
678 | /// <summary> | ||
679 | /// Restore a whole collection of items to the prim's inventory at once. | ||
680 | /// We assume that the items already have all their fields correctly filled out. | ||
681 | /// The items are not flagged for persistence to the database, since they are being restored | ||
682 | /// from persistence rather than being newly added. | ||
683 | /// </summary> | ||
684 | /// <param name="items"></param> | ||
685 | public void RestoreInventoryItems(ICollection<TaskInventoryItem> items) | ||
686 | { | ||
687 | lock (m_items) | ||
688 | { | ||
689 | foreach (TaskInventoryItem item in items) | ||
690 | { | ||
691 | m_items.Add(item.ItemID, item); | ||
692 | // m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
693 | } | ||
694 | m_inventorySerial++; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | /// <summary> | ||
699 | /// Returns an existing inventory item. Returns the original, so any changes will be live. | ||
700 | /// </summary> | ||
701 | /// <param name="itemID"></param> | ||
702 | /// <returns>null if the item does not exist</returns> | ||
703 | public TaskInventoryItem GetInventoryItem(UUID itemId) | ||
704 | { | ||
705 | TaskInventoryItem item; | ||
706 | |||
707 | lock (m_items) | ||
708 | m_items.TryGetValue(itemId, out item); | ||
709 | |||
710 | return item; | ||
711 | } | ||
712 | |||
713 | public TaskInventoryItem GetInventoryItem(string name) | ||
714 | { | ||
715 | lock (m_items) | ||
716 | { | ||
717 | foreach (TaskInventoryItem item in m_items.Values) | ||
718 | { | ||
719 | if (item.Name == name) | ||
720 | return item; | ||
721 | } | ||
722 | } | ||
723 | |||
724 | return null; | ||
725 | } | ||
726 | |||
727 | public List<TaskInventoryItem> GetInventoryItems(string name) | ||
728 | { | ||
729 | List<TaskInventoryItem> items = new List<TaskInventoryItem>(); | ||
730 | |||
731 | lock (m_items) | ||
732 | { | ||
733 | foreach (TaskInventoryItem item in m_items.Values) | ||
734 | { | ||
735 | if (item.Name == name) | ||
736 | items.Add(item); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | return items; | ||
741 | } | ||
742 | |||
743 | public bool GetRezReadySceneObjects(TaskInventoryItem item, out List<SceneObjectGroup> objlist, out List<Vector3> veclist) | ||
744 | { | ||
745 | AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); | ||
746 | |||
747 | if (null == rezAsset) | ||
748 | { | ||
749 | m_log.WarnFormat( | ||
750 | "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}", | ||
751 | item.AssetID, item.Name, m_part.Name); | ||
752 | objlist = null; | ||
753 | veclist = null; | ||
754 | return false; | ||
755 | } | ||
756 | |||
757 | Vector3 bbox; | ||
758 | float offsetHeight; | ||
759 | |||
760 | m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight); | ||
761 | |||
762 | for (int i = 0; i < objlist.Count; i++) | ||
763 | { | ||
764 | SceneObjectGroup group = objlist[i]; | ||
765 | |||
766 | group.ResetIDs(); | ||
767 | |||
768 | SceneObjectPart rootPart = group.GetPart(group.UUID); | ||
769 | |||
770 | // Since renaming the item in the inventory does not affect the name stored | ||
771 | // in the serialization, transfer the correct name from the inventory to the | ||
772 | // object itself before we rez. | ||
773 | // Only do these for the first object if we are rezzing a coalescence. | ||
774 | if (i == 0) | ||
775 | { | ||
776 | rootPart.Name = item.Name; | ||
777 | rootPart.Description = item.Description; | ||
778 | } | ||
779 | |||
780 | group.SetGroup(m_part.GroupID, null); | ||
781 | |||
782 | foreach (SceneObjectPart part in group.Parts) | ||
783 | { | ||
784 | // Convert between InventoryItem classes. You can never have too many similar but slightly different classes :) | ||
785 | InventoryItemBase dest = new InventoryItemBase(item.ItemID, item.OwnerID); | ||
786 | dest.BasePermissions = item.BasePermissions; | ||
787 | dest.CurrentPermissions = item.CurrentPermissions; | ||
788 | dest.EveryOnePermissions = item.EveryonePermissions; | ||
789 | dest.GroupPermissions = item.GroupPermissions; | ||
790 | dest.NextPermissions = item.NextPermissions; | ||
791 | dest.Flags = item.Flags; | ||
792 | |||
793 | part.ApplyPermissionsOnRez(dest, false, m_part.ParentGroup.Scene); | ||
794 | } | ||
795 | |||
796 | rootPart.TrimPermissions(); | ||
797 | } | ||
798 | |||
799 | return true; | ||
800 | } | ||
801 | |||
802 | /// <summary> | ||
803 | /// Update an existing inventory item. | ||
804 | /// </summary> | ||
805 | /// <param name="item">The updated item. An item with the same id must already exist | ||
806 | /// in this prim's inventory.</param> | ||
807 | /// <returns>false if the item did not exist, true if the update occurred successfully</returns> | ||
808 | public bool UpdateInventoryItem(TaskInventoryItem item) | ||
809 | { | ||
810 | return UpdateInventoryItem(item, true, true); | ||
811 | } | ||
812 | |||
813 | public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents) | ||
814 | { | ||
815 | return UpdateInventoryItem(item, fireScriptEvents, true); | ||
816 | } | ||
817 | |||
818 | public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) | ||
819 | { | ||
820 | TaskInventoryItem it = GetInventoryItem(item.ItemID); | ||
821 | if (it != null) | ||
822 | { | ||
823 | // m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name); | ||
824 | |||
825 | item.ParentID = m_part.UUID; | ||
826 | item.ParentPartID = m_part.UUID; | ||
827 | |||
828 | // If group permissions have been set on, check that the groupID is up to date in case it has | ||
829 | // changed since permissions were last set. | ||
830 | if (item.GroupPermissions != (uint)PermissionMask.None) | ||
831 | item.GroupID = m_part.GroupID; | ||
832 | |||
833 | if (item.AssetID == UUID.Zero) | ||
834 | item.AssetID = it.AssetID; | ||
835 | |||
836 | lock (m_items) | ||
837 | { | ||
838 | m_items[item.ItemID] = item; | ||
839 | m_inventorySerial++; | ||
840 | } | ||
841 | |||
842 | if (fireScriptEvents) | ||
843 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
844 | |||
845 | if (considerChanged) | ||
846 | { | ||
847 | HasInventoryChanged = true; | ||
848 | m_part.ParentGroup.HasGroupChanged = true; | ||
849 | } | ||
850 | |||
851 | return true; | ||
852 | } | ||
853 | else | ||
854 | { | ||
855 | m_log.ErrorFormat( | ||
856 | "[PRIM INVENTORY]: " + | ||
857 | "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", | ||
858 | item.ItemID, m_part.Name, m_part.UUID, | ||
859 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
860 | } | ||
861 | return false; | ||
862 | |||
863 | } | ||
864 | |||
865 | /// <summary> | ||
866 | /// Remove an item from this prim's inventory | ||
867 | /// </summary> | ||
868 | /// <param name="itemID"></param> | ||
869 | /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist | ||
870 | /// in this prim's inventory.</returns> | ||
871 | public int RemoveInventoryItem(UUID itemID) | ||
872 | { | ||
873 | TaskInventoryItem item = GetInventoryItem(itemID); | ||
874 | if (item != null) | ||
875 | { | ||
876 | int type = m_items[itemID].InvType; | ||
877 | if (type == 10) // Script | ||
878 | { | ||
879 | // route it through here, to handle script cleanup tasks | ||
880 | RemoveScriptInstance(itemID, false); | ||
881 | } | ||
882 | m_items.Remove(itemID); | ||
883 | m_inventorySerial++; | ||
884 | m_part.TriggerScriptChangedEvent(Changed.INVENTORY); | ||
885 | |||
886 | HasInventoryChanged = true; | ||
887 | m_part.ParentGroup.HasGroupChanged = true; | ||
888 | |||
889 | if (!ContainsScripts()) | ||
890 | m_part.RemFlag(PrimFlags.Scripted); | ||
891 | |||
892 | m_part.ScheduleFullUpdate(); | ||
893 | |||
894 | return type; | ||
895 | |||
896 | } | ||
897 | else | ||
898 | { | ||
899 | m_log.ErrorFormat( | ||
900 | "[PRIM INVENTORY]: " + | ||
901 | "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory", | ||
902 | itemID, m_part.Name, m_part.UUID, | ||
903 | m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); | ||
904 | } | ||
905 | |||
906 | return -1; | ||
907 | } | ||
908 | |||
909 | private bool CreateInventoryFile() | ||
910 | { | ||
911 | // m_log.DebugFormat( | ||
912 | // "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}", | ||
913 | // m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial); | ||
914 | |||
915 | if (m_inventoryFileName == String.Empty || | ||
916 | m_inventoryFileNameSerial < m_inventorySerial) | ||
917 | { | ||
918 | // Something changed, we need to create a new file | ||
919 | m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp"; | ||
920 | m_inventoryFileNameSerial = m_inventorySerial; | ||
921 | |||
922 | InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); | ||
923 | |||
924 | lock (m_items) | ||
925 | { | ||
926 | foreach (TaskInventoryItem item in m_items.Values) | ||
927 | { | ||
928 | // m_log.DebugFormat( | ||
929 | // "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}", | ||
930 | // item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId); | ||
931 | |||
932 | UUID ownerID = item.OwnerID; | ||
933 | uint everyoneMask = 0; | ||
934 | uint baseMask = item.BasePermissions; | ||
935 | uint ownerMask = item.CurrentPermissions; | ||
936 | uint groupMask = item.GroupPermissions; | ||
937 | |||
938 | invString.AddItemStart(); | ||
939 | invString.AddNameValueLine("item_id", item.ItemID.ToString()); | ||
940 | invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); | ||
941 | |||
942 | invString.AddPermissionsStart(); | ||
943 | |||
944 | invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); | ||
945 | invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); | ||
946 | invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask)); | ||
947 | invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); | ||
948 | invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); | ||
949 | |||
950 | invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); | ||
951 | invString.AddNameValueLine("owner_id", ownerID.ToString()); | ||
952 | |||
953 | invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); | ||
954 | |||
955 | invString.AddNameValueLine("group_id", item.GroupID.ToString()); | ||
956 | invString.AddSectionEnd(); | ||
957 | |||
958 | invString.AddNameValueLine("asset_id", item.AssetID.ToString()); | ||
959 | invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type)); | ||
960 | invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType)); | ||
961 | invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); | ||
962 | |||
963 | invString.AddSaleStart(); | ||
964 | invString.AddNameValueLine("sale_type", "not"); | ||
965 | invString.AddNameValueLine("sale_price", "0"); | ||
966 | invString.AddSectionEnd(); | ||
967 | |||
968 | invString.AddNameValueLine("name", item.Name + "|"); | ||
969 | invString.AddNameValueLine("desc", item.Description + "|"); | ||
970 | |||
971 | invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); | ||
972 | invString.AddSectionEnd(); | ||
973 | } | ||
974 | } | ||
975 | |||
976 | m_inventoryFileData = Utils.StringToBytes(invString.BuildString); | ||
977 | |||
978 | return true; | ||
979 | } | ||
980 | |||
981 | // No need to recreate, the existing file is fine | ||
982 | return false; | ||
983 | } | ||
984 | |||
985 | /// <summary> | ||
986 | /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client | ||
987 | /// </summary> | ||
988 | /// <param name="xferManager"></param> | ||
989 | public void RequestInventoryFile(IClientAPI client, IXfer xferManager) | ||
990 | { | ||
991 | lock (m_items) | ||
992 | { | ||
993 | // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing | ||
994 | // a new script if any previous deletion has left the prim inventory empty. | ||
995 | if (m_items.Count == 0) // No inventory | ||
996 | { | ||
997 | // m_log.DebugFormat( | ||
998 | // "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items", | ||
999 | // m_part.Name, m_part.LocalId, m_part.UUID, client.Name); | ||
1000 | |||
1001 | client.SendTaskInventory(m_part.UUID, 0, new byte[0]); | ||
1002 | return; | ||
1003 | } | ||
1004 | |||
1005 | CreateInventoryFile(); | ||
1006 | |||
1007 | // In principle, we should only do the rest if the inventory changed; | ||
1008 | // by sending m_inventorySerial to the client, it ought to know | ||
1009 | // that nothing changed and that it doesn't need to request the file. | ||
1010 | // Unfortunately, it doesn't look like the client optimizes this; | ||
1011 | // the client seems to always come back and request the Xfer, | ||
1012 | // no matter what value m_inventorySerial has. | ||
1013 | // FIXME: Could probably be > 0 here rather than > 2 | ||
1014 | if (m_inventoryFileData.Length > 2) | ||
1015 | { | ||
1016 | // Add the file for Xfer | ||
1017 | // m_log.DebugFormat( | ||
1018 | // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}", | ||
1019 | // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId); | ||
1020 | |||
1021 | xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData); | ||
1022 | } | ||
1023 | |||
1024 | // Tell the client we're ready to Xfer the file | ||
1025 | client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial, | ||
1026 | Util.StringToBytes256(m_inventoryFileName)); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | /// <summary> | ||
1031 | /// Process inventory backup | ||
1032 | /// </summary> | ||
1033 | /// <param name="datastore"></param> | ||
1034 | public void ProcessInventoryBackup(ISimulationDataService datastore) | ||
1035 | { | ||
1036 | if (HasInventoryChanged) | ||
1037 | { | ||
1038 | HasInventoryChanged = false; | ||
1039 | List<TaskInventoryItem> items = GetInventoryItems(); | ||
1040 | datastore.StorePrimInventory(m_part.UUID, items); | ||
1041 | |||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | public class InventoryStringBuilder | ||
1046 | { | ||
1047 | public string BuildString = String.Empty; | ||
1048 | |||
1049 | public InventoryStringBuilder(UUID folderID, UUID parentID) | ||
1050 | { | ||
1051 | BuildString += "\tinv_object\t0\n\t{\n"; | ||
1052 | AddNameValueLine("obj_id", folderID.ToString()); | ||
1053 | AddNameValueLine("parent_id", parentID.ToString()); | ||
1054 | AddNameValueLine("type", "category"); | ||
1055 | AddNameValueLine("name", "Contents|"); | ||
1056 | AddSectionEnd(); | ||
1057 | } | ||
1058 | |||
1059 | public void AddItemStart() | ||
1060 | { | ||
1061 | BuildString += "\tinv_item\t0\n"; | ||
1062 | AddSectionStart(); | ||
1063 | } | ||
1064 | |||
1065 | public void AddPermissionsStart() | ||
1066 | { | ||
1067 | BuildString += "\tpermissions 0\n"; | ||
1068 | AddSectionStart(); | ||
1069 | } | ||
1070 | |||
1071 | public void AddSaleStart() | ||
1072 | { | ||
1073 | BuildString += "\tsale_info\t0\n"; | ||
1074 | AddSectionStart(); | ||
1075 | } | ||
1076 | |||
1077 | protected void AddSectionStart() | ||
1078 | { | ||
1079 | BuildString += "\t{\n"; | ||
1080 | } | ||
1081 | |||
1082 | public void AddSectionEnd() | ||
1083 | { | ||
1084 | BuildString += "\t}\n"; | ||
1085 | } | ||
1086 | |||
1087 | public void AddLine(string addLine) | ||
1088 | { | ||
1089 | BuildString += addLine; | ||
1090 | } | ||
1091 | |||
1092 | public void AddNameValueLine(string name, string value) | ||
1093 | { | ||
1094 | BuildString += "\t\t"; | ||
1095 | BuildString += name + "\t"; | ||
1096 | BuildString += value + "\n"; | ||
1097 | } | ||
1098 | |||
1099 | public void Close() | ||
1100 | { | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | public uint MaskEffectivePermissions() | ||
1105 | { | ||
1106 | uint mask=0x7fffffff; | ||
1107 | |||
1108 | lock (m_items) | ||
1109 | { | ||
1110 | foreach (TaskInventoryItem item in m_items.Values) | ||
1111 | { | ||
1112 | if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0) | ||
1113 | mask &= ~((uint)PermissionMask.Copy >> 13); | ||
1114 | if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0) | ||
1115 | mask &= ~((uint)PermissionMask.Transfer >> 13); | ||
1116 | if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0) | ||
1117 | mask &= ~((uint)PermissionMask.Modify >> 13); | ||
1118 | |||
1119 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) | ||
1120 | mask &= ~(uint)PermissionMask.Copy; | ||
1121 | if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) | ||
1122 | mask &= ~(uint)PermissionMask.Transfer; | ||
1123 | if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0) | ||
1124 | mask &= ~(uint)PermissionMask.Modify; | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | return mask; | ||
1129 | } | ||
1130 | |||
1131 | public void ApplyNextOwnerPermissions() | ||
1132 | { | ||
1133 | lock (m_items) | ||
1134 | { | ||
1135 | foreach (TaskInventoryItem item in m_items.Values) | ||
1136 | { | ||
1137 | // m_log.DebugFormat ( | ||
1138 | // "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}", | ||
1139 | // item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions); | ||
1140 | |||
1141 | if (item.InvType == (int)InventoryType.Object) | ||
1142 | { | ||
1143 | uint perms = item.CurrentPermissions; | ||
1144 | PermissionsUtil.ApplyFoldedPermissions(perms, ref perms); | ||
1145 | item.CurrentPermissions = perms; | ||
1146 | } | ||
1147 | |||
1148 | item.CurrentPermissions &= item.NextPermissions; | ||
1149 | item.BasePermissions &= item.NextPermissions; | ||
1150 | item.EveryonePermissions &= item.NextPermissions; | ||
1151 | item.OwnerChanged = true; | ||
1152 | item.PermsMask = 0; | ||
1153 | item.PermsGranter = UUID.Zero; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | public void ApplyGodPermissions(uint perms) | ||
1159 | { | ||
1160 | lock (m_items) | ||
1161 | { | ||
1162 | foreach (TaskInventoryItem item in m_items.Values) | ||
1163 | { | ||
1164 | item.CurrentPermissions = perms; | ||
1165 | item.BasePermissions = perms; | ||
1166 | } | ||
1167 | } | ||
1168 | |||
1169 | m_inventorySerial++; | ||
1170 | HasInventoryChanged = true; | ||
1171 | } | ||
1172 | |||
1173 | /// <summary> | ||
1174 | /// Returns true if this part inventory contains any scripts. False otherwise. | ||
1175 | /// </summary> | ||
1176 | /// <returns></returns> | ||
1177 | public bool ContainsScripts() | ||
1178 | { | ||
1179 | lock (m_items) | ||
1180 | { | ||
1181 | foreach (TaskInventoryItem item in m_items.Values) | ||
1182 | { | ||
1183 | if (item.InvType == (int)InventoryType.LSL) | ||
1184 | { | ||
1185 | return true; | ||
1186 | } | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | return false; | ||
1191 | } | ||
1192 | |||
1193 | /// <summary> | ||
1194 | /// Returns the count of scripts in this parts inventory. | ||
1195 | /// </summary> | ||
1196 | /// <returns></returns> | ||
1197 | public int ScriptCount() | ||
1198 | { | ||
1199 | int count = 0; | ||
1200 | lock (m_items) | ||
1201 | { | ||
1202 | foreach (TaskInventoryItem item in m_items.Values) | ||
1203 | { | ||
1204 | if (item.InvType == (int)InventoryType.LSL) | ||
1205 | { | ||
1206 | count++; | ||
1207 | } | ||
1208 | } | ||
1209 | } | ||
1210 | |||
1211 | return count; | ||
1212 | } | ||
1213 | /// <summary> | ||
1214 | /// Returns the count of running scripts in this parts inventory. | ||
1215 | /// </summary> | ||
1216 | /// <returns></returns> | ||
1217 | public int RunningScriptCount() | ||
1218 | { | ||
1219 | IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); | ||
1220 | if (engines.Length == 0) | ||
1221 | return 0; | ||
1222 | |||
1223 | int count = 0; | ||
1224 | List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); | ||
1225 | |||
1226 | foreach (TaskInventoryItem item in scripts) | ||
1227 | { | ||
1228 | foreach (IScriptModule engine in engines) | ||
1229 | { | ||
1230 | if (engine != null) | ||
1231 | { | ||
1232 | if (engine.GetScriptState(item.ItemID)) | ||
1233 | { | ||
1234 | count++; | ||
1235 | } | ||
1236 | } | ||
1237 | } | ||
1238 | } | ||
1239 | return count; | ||
1240 | } | ||
1241 | |||
1242 | public List<UUID> GetInventoryList() | ||
1243 | { | ||
1244 | List<UUID> ret = new List<UUID>(); | ||
1245 | |||
1246 | lock (m_items) | ||
1247 | { | ||
1248 | foreach (TaskInventoryItem item in m_items.Values) | ||
1249 | ret.Add(item.ItemID); | ||
1250 | } | ||
1251 | |||
1252 | return ret; | ||
1253 | } | ||
1254 | |||
1255 | public List<TaskInventoryItem> GetInventoryItems() | ||
1256 | { | ||
1257 | List<TaskInventoryItem> ret = new List<TaskInventoryItem>(); | ||
1258 | |||
1259 | lock (m_items) | ||
1260 | ret = new List<TaskInventoryItem>(m_items.Values); | ||
1261 | |||
1262 | return ret; | ||
1263 | } | ||
1264 | |||
1265 | public List<TaskInventoryItem> GetInventoryItems(InventoryType type) | ||
1266 | { | ||
1267 | List<TaskInventoryItem> ret = new List<TaskInventoryItem>(); | ||
1268 | |||
1269 | lock (m_items) | ||
1270 | { | ||
1271 | foreach (TaskInventoryItem item in m_items.Values) | ||
1272 | if (item.InvType == (int)type) | ||
1273 | ret.Add(item); | ||
1274 | } | ||
1275 | |||
1276 | return ret; | ||
1277 | } | ||
1278 | |||
1279 | public Dictionary<UUID, string> GetScriptStates() | ||
1280 | { | ||
1281 | Dictionary<UUID, string> ret = new Dictionary<UUID, string>(); | ||
1282 | |||
1283 | if (m_part.ParentGroup.Scene == null) // Group not in a scene | ||
1284 | return ret; | ||
1285 | |||
1286 | IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); | ||
1287 | |||
1288 | if (engines.Length == 0) // No engine at all | ||
1289 | return ret; | ||
1290 | |||
1291 | List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); | ||
1292 | |||
1293 | foreach (TaskInventoryItem item in scripts) | ||
1294 | { | ||
1295 | foreach (IScriptModule e in engines) | ||
1296 | { | ||
1297 | if (e != null) | ||
1298 | { | ||
1299 | // m_log.DebugFormat( | ||
1300 | // "[PRIM INVENTORY]: Getting script state from engine {0} for {1} in part {2} in group {3} in {4}", | ||
1301 | // e.Name, item.Name, m_part.Name, m_part.ParentGroup.Name, m_part.ParentGroup.Scene.Name); | ||
1302 | |||
1303 | string n = e.GetXMLState(item.ItemID); | ||
1304 | if (n != String.Empty) | ||
1305 | { | ||
1306 | if (!ret.ContainsKey(item.ItemID)) | ||
1307 | ret[item.ItemID] = n; | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | return ret; | ||
1315 | } | ||
1316 | |||
1317 | public void ResumeScripts() | ||
1318 | { | ||
1319 | IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>(); | ||
1320 | if (engines.Length == 0) | ||
1321 | return; | ||
1322 | |||
1323 | List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL); | ||
1324 | |||
1325 | foreach (TaskInventoryItem item in scripts) | ||
1326 | { | ||
1327 | foreach (IScriptModule engine in engines) | ||
1328 | { | ||
1329 | if (engine != null) | ||
1330 | { | ||
1331 | // m_log.DebugFormat( | ||
1332 | // "[PRIM INVENTORY]: Resuming script {0} {1} for {2}, OwnerChanged {3}", | ||
1333 | // item.Name, item.ItemID, item.OwnerID, item.OwnerChanged); | ||
1334 | |||
1335 | engine.ResumeScript(item.ItemID); | ||
1336 | |||
1337 | if (item.OwnerChanged) | ||
1338 | engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); | ||
1339 | |||
1340 | item.OwnerChanged = false; | ||
1341 | } | ||
1342 | } | ||
1343 | } | ||
1344 | } | ||
1345 | } | ||
1346 | } | ||