clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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.Collections.Generic; |
||
30 | using System.Reflection; |
||
31 | using System.Timers; |
||
32 | using log4net; |
||
33 | using OpenMetaverse; |
||
34 | using OpenSim.Framework; |
||
35 | using OpenSim.Region.Framework.Interfaces; |
||
36 | |||
37 | namespace OpenSim.Region.Framework.Scenes |
||
38 | { |
||
39 | class DeleteToInventoryHolder |
||
40 | { |
||
41 | public DeRezAction action; |
||
42 | public IClientAPI remoteClient; |
||
43 | public List<SceneObjectGroup> objectGroups; |
||
44 | public UUID folderID; |
||
45 | public bool permissionToDelete; |
||
46 | } |
||
47 | |||
48 | /// <summary> |
||
49 | /// Asynchronously derez objects. This is used to derez large number of objects to inventory without holding |
||
50 | /// up the main client thread. |
||
51 | /// </summary> |
||
52 | public class AsyncSceneObjectGroupDeleter |
||
53 | { |
||
54 | private static readonly ILog m_log |
||
55 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
56 | |||
57 | /// <value> |
||
58 | /// Is the deleter currently enabled? |
||
59 | /// </value> |
||
60 | public bool Enabled; |
||
61 | |||
62 | private Timer m_inventoryTicker = new Timer(2000); |
||
63 | private readonly Queue<DeleteToInventoryHolder> m_inventoryDeletes = new Queue<DeleteToInventoryHolder>(); |
||
64 | private Scene m_scene; |
||
65 | |||
66 | public AsyncSceneObjectGroupDeleter(Scene scene) |
||
67 | { |
||
68 | m_scene = scene; |
||
69 | |||
70 | m_inventoryTicker.AutoReset = false; |
||
71 | m_inventoryTicker.Elapsed += InventoryRunDeleteTimer; |
||
72 | } |
||
73 | |||
74 | /// <summary> |
||
75 | /// Delete the given object from the scene |
||
76 | /// </summary> |
||
77 | public void DeleteToInventory(DeRezAction action, UUID folderID, |
||
78 | List<SceneObjectGroup> objectGroups, IClientAPI remoteClient, |
||
79 | bool permissionToDelete) |
||
80 | { |
||
81 | if (Enabled) |
||
82 | lock (m_inventoryTicker) |
||
83 | m_inventoryTicker.Stop(); |
||
84 | |||
85 | lock (m_inventoryDeletes) |
||
86 | { |
||
87 | DeleteToInventoryHolder dtis = new DeleteToInventoryHolder(); |
||
88 | dtis.action = action; |
||
89 | dtis.folderID = folderID; |
||
90 | dtis.objectGroups = objectGroups; |
||
91 | dtis.remoteClient = remoteClient; |
||
92 | dtis.permissionToDelete = permissionToDelete; |
||
93 | |||
94 | m_inventoryDeletes.Enqueue(dtis); |
||
95 | } |
||
96 | |||
97 | if (Enabled) |
||
98 | lock (m_inventoryTicker) |
||
99 | m_inventoryTicker.Start(); |
||
100 | |||
101 | // Visually remove it, even if it isnt really gone yet. This means that if we crash before the object |
||
102 | // has gone to inventory, it will reappear in the region again on restart instead of being lost. |
||
103 | // This is not ideal since the object will still be available for manipulation when it should be, but it's |
||
104 | // better than losing the object for now. |
||
105 | if (permissionToDelete) |
||
106 | { |
||
107 | foreach (SceneObjectGroup g in objectGroups) |
||
108 | g.DeleteGroupFromScene(false); |
||
109 | } |
||
110 | } |
||
111 | |||
112 | private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e) |
||
113 | { |
||
114 | // m_log.Debug("[ASYNC DELETER]: Starting send to inventory loop"); |
||
115 | |||
116 | // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved |
||
117 | // in a culture where decimal points are commas and then reloaded in a culture which just treats them as |
||
118 | // number seperators. |
||
119 | Culture.SetCurrentCulture(); |
||
120 | |||
121 | while (InventoryDeQueueAndDelete()) |
||
122 | { |
||
123 | //m_log.Debug("[ASYNC DELETER]: Sent item successfully to inventory, continuing..."); |
||
124 | } |
||
125 | } |
||
126 | |||
127 | /// <summary> |
||
128 | /// Move the next object in the queue to inventory. Then delete it properly from the scene. |
||
129 | /// </summary> |
||
130 | /// <returns></returns> |
||
131 | public bool InventoryDeQueueAndDelete() |
||
132 | { |
||
133 | DeleteToInventoryHolder x = null; |
||
134 | |||
135 | try |
||
136 | { |
||
137 | lock (m_inventoryDeletes) |
||
138 | { |
||
139 | int left = m_inventoryDeletes.Count; |
||
140 | if (left > 0) |
||
141 | { |
||
142 | x = m_inventoryDeletes.Dequeue(); |
||
143 | |||
144 | // m_log.DebugFormat( |
||
145 | // "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", |
||
146 | // left, x.action, x.objectGroups.Count); |
||
147 | |||
148 | try |
||
149 | { |
||
150 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); |
||
151 | if (invAccess != null) |
||
152 | invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient, false); |
||
153 | |||
154 | if (x.permissionToDelete) |
||
155 | { |
||
156 | foreach (SceneObjectGroup g in x.objectGroups) |
||
157 | m_scene.DeleteSceneObject(g, true); |
||
158 | } |
||
159 | } |
||
160 | catch (Exception e) |
||
161 | { |
||
162 | m_log.ErrorFormat( |
||
163 | "[ASYNC DELETER]: Exception background sending object: {0}{1}", e.Message, e.StackTrace); |
||
164 | } |
||
165 | |||
166 | return true; |
||
167 | } |
||
168 | } |
||
169 | } |
||
170 | catch (Exception e) |
||
171 | { |
||
172 | // We can't put the object group details in here since the root part may have disappeared (which is where these sit). |
||
173 | // FIXME: This needs to be fixed. |
||
174 | m_log.ErrorFormat( |
||
175 | "[ASYNC DELETER]: Queued sending of scene object to agent {0} {1} failed: {2} {3}", |
||
176 | (x != null ? x.remoteClient.Name : "unavailable"), |
||
177 | (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), |
||
178 | e.Message, |
||
179 | e.StackTrace); |
||
180 | } |
||
181 | |||
182 | // m_log.Debug("[ASYNC DELETER]: No objects left in inventory send queue."); |
||
183 | |||
184 | return false; |
||
185 | } |
||
186 | } |
||
187 | } |