aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs726
1 files changed, 363 insertions, 363 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
index ad9ff45..8081e2c 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/EventQueueManager.cs
@@ -1,364 +1,364 @@
1/* 1/*
2* Copyright (c) Contributors, http://opensimulator.org/ 2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders. 3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4* 4*
5* Redistribution and use in source and binary forms, with or without 5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met: 6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright 7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer. 8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright 9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the 10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution. 11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the 12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products 13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission. 14* derived from this software without specific prior written permission.
15* 15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY 16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 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 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. 25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26* 26*
27*/ 27*/
28 28
29 29
30using System; 30using System;
31using System.Collections; 31using System.Collections;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Threading; 33using System.Threading;
34using libsecondlife; 34using libsecondlife;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Region.Environment.Scenes.Scripting; 36using OpenSim.Region.Environment.Scenes.Scripting;
37 37
38namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase 38namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase
39{ 39{
40 /// <summary> 40 /// <summary>
41 /// EventQueueManager handles event queues 41 /// EventQueueManager handles event queues
42 /// Events are queued and executed in separate thread 42 /// Events are queued and executed in separate thread
43 /// </summary> 43 /// </summary>
44 [Serializable] 44 [Serializable]
45 public class EventQueueManager 45 public class EventQueueManager
46 { 46 {
47 47
48 // 48 //
49 // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine". 49 // Class is instanced in "ScriptEngine" and used by "EventManager" also instanced in "ScriptEngine".
50 // 50 //
51 // Class purpose is to queue and execute functions that are received by "EventManager": 51 // Class purpose is to queue and execute functions that are received by "EventManager":
52 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution. 52 // - allowing "EventManager" to release its event thread immediately, thus not interrupting server execution.
53 // - allowing us to prioritize and control execution of script functions. 53 // - allowing us to prioritize and control execution of script functions.
54 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety. 54 // Class can use multiple threads for simultaneous execution. Mutexes are used for thread safety.
55 // 55 //
56 // 1. Hold an execution queue for scripts 56 // 1. Hold an execution queue for scripts
57 // 2. Use threads to process queue, each thread executes one script function on each pass. 57 // 2. Use threads to process queue, each thread executes one script function on each pass.
58 // 3. Catch any script error and process it 58 // 3. Catch any script error and process it
59 // 59 //
60 // 60 //
61 // Notes: 61 // Notes:
62 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts. 62 // * Current execution load balancing is optimized for 1 thread, and can cause unfair execute balancing between scripts.
63 // Not noticeable unless server is under high load. 63 // Not noticeable unless server is under high load.
64 // * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet, 64 // * This class contains the number of threads used for script executions. Since we are not microthreading scripts yet,
65 // increase number of threads to allow more concurrent script executions in OpenSim. 65 // increase number of threads to allow more concurrent script executions in OpenSim.
66 // 66 //
67 67
68 68
69 /// <summary> 69 /// <summary>
70 /// List of threads processing event queue 70 /// List of threads processing event queue
71 /// </summary> 71 /// </summary>
72 private List<Thread> eventQueueThreads = new List<Thread>(); 72 private List<Thread> eventQueueThreads = new List<Thread>();
73 73
74 private object queueLock = new object(); // Mutex lock object 74 private object queueLock = new object(); // Mutex lock object
75 75
76 /// <summary> 76 /// <summary>
77 /// How many ms to sleep if queue is empty 77 /// How many ms to sleep if queue is empty
78 /// </summary> 78 /// </summary>
79 private int nothingToDoSleepms = 50; 79 private int nothingToDoSleepms = 50;
80 80
81 /// <summary> 81 /// <summary>
82 /// How many threads to process queue with 82 /// How many threads to process queue with
83 /// </summary> 83 /// </summary>
84 private int numberOfThreads = 2; 84 private int numberOfThreads = 2;
85 85
86 /// <summary> 86 /// <summary>
87 /// Queue containing events waiting to be executed 87 /// Queue containing events waiting to be executed
88 /// </summary> 88 /// </summary>
89 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>(); 89 private Queue<QueueItemStruct> eventQueue = new Queue<QueueItemStruct>();
90 90
91 /// <summary> 91 /// <summary>
92 /// Queue item structure 92 /// Queue item structure
93 /// </summary> 93 /// </summary>
94 private struct QueueItemStruct 94 private struct QueueItemStruct
95 { 95 {
96 public uint localID; 96 public uint localID;
97 public LLUUID itemID; 97 public LLUUID itemID;
98 public string functionName; 98 public string functionName;
99 public object[] param; 99 public object[] param;
100 } 100 }
101 101
102 /// <summary> 102 /// <summary>
103 /// List of localID locks for mutex processing of script events 103 /// List of localID locks for mutex processing of script events
104 /// </summary> 104 /// </summary>
105 private List<uint> objectLocks = new List<uint>(); 105 private List<uint> objectLocks = new List<uint>();
106 106
107 private object tryLockLock = new object(); // Mutex lock object 107 private object tryLockLock = new object(); // Mutex lock object
108 108
109 private ScriptEngine m_ScriptEngine; 109 private ScriptEngine m_ScriptEngine;
110 110
111 public EventQueueManager(ScriptEngine _ScriptEngine) 111 public EventQueueManager(ScriptEngine _ScriptEngine)
112 { 112 {
113 m_ScriptEngine = _ScriptEngine; 113 m_ScriptEngine = _ScriptEngine;
114 114
115 // 115 //
116 // Start event queue processing threads (worker threads) 116 // Start event queue processing threads (worker threads)
117 // 117 //
118 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++) 118 for (int ThreadCount = 0; ThreadCount <= numberOfThreads; ThreadCount++)
119 { 119 {
120 Thread EventQueueThread = new Thread(EventQueueThreadLoop); 120 Thread EventQueueThread = new Thread(EventQueueThreadLoop);
121 eventQueueThreads.Add(EventQueueThread); 121 eventQueueThreads.Add(EventQueueThread);
122 EventQueueThread.IsBackground = true; 122 EventQueueThread.IsBackground = true;
123 EventQueueThread.Priority = ThreadPriority.BelowNormal; 123 EventQueueThread.Priority = ThreadPriority.BelowNormal;
124 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount; 124 EventQueueThread.Name = "EventQueueManagerThread_" + ThreadCount;
125 EventQueueThread.Start(); 125 EventQueueThread.Start();
126 } 126 }
127 } 127 }
128 128
129 ~EventQueueManager() 129 ~EventQueueManager()
130 { 130 {
131 // Kill worker threads 131 // Kill worker threads
132 foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads)) 132 foreach (Thread EventQueueThread in new ArrayList(eventQueueThreads))
133 { 133 {
134 if (EventQueueThread != null && EventQueueThread.IsAlive == true) 134 if (EventQueueThread != null && EventQueueThread.IsAlive == true)
135 { 135 {
136 try 136 try
137 { 137 {
138 EventQueueThread.Abort(); 138 EventQueueThread.Abort();
139 EventQueueThread.Join(); 139 EventQueueThread.Join();
140 } 140 }
141 catch (Exception) 141 catch (Exception)
142 { 142 {
143 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString()); 143 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Exception killing worker thread: " + e.ToString());
144 } 144 }
145 } 145 }
146 } 146 }
147 eventQueueThreads.Clear(); 147 eventQueueThreads.Clear();
148 // Todo: Clean up our queues 148 // Todo: Clean up our queues
149 eventQueue.Clear(); 149 eventQueue.Clear();
150 } 150 }
151 151
152 /// <summary> 152 /// <summary>
153 /// Queue processing thread loop 153 /// Queue processing thread loop
154 /// </summary> 154 /// </summary>
155 private void EventQueueThreadLoop() 155 private void EventQueueThreadLoop()
156 { 156 {
157 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned"); 157 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Worker thread spawned");
158 try 158 try
159 { 159 {
160 QueueItemStruct BlankQIS = new QueueItemStruct(); 160 QueueItemStruct BlankQIS = new QueueItemStruct();
161 while (true) 161 while (true)
162 { 162 {
163 try 163 try
164 { 164 {
165 QueueItemStruct QIS = BlankQIS; 165 QueueItemStruct QIS = BlankQIS;
166 bool GotItem = false; 166 bool GotItem = false;
167 167
168 if (eventQueue.Count == 0) 168 if (eventQueue.Count == 0)
169 { 169 {
170 // Nothing to do? Sleep a bit waiting for something to do 170 // Nothing to do? Sleep a bit waiting for something to do
171 Thread.Sleep(nothingToDoSleepms); 171 Thread.Sleep(nothingToDoSleepms);
172 } 172 }
173 else 173 else
174 { 174 {
175 // Something in queue, process 175 // Something in queue, process
176 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName); 176 //myScriptEngine.m_logger.Verbose("ScriptEngine", "Processing event for localID: " + QIS.localID + ", itemID: " + QIS.itemID + ", FunctionName: " + QIS.FunctionName);
177 177
178 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD 178 // OBJECT BASED LOCK - TWO THREADS WORKING ON SAME OBJECT IS NOT GOOD
179 lock (queueLock) 179 lock (queueLock)
180 { 180 {
181 GotItem = false; 181 GotItem = false;
182 for (int qc = 0; qc < eventQueue.Count; qc++) 182 for (int qc = 0; qc < eventQueue.Count; qc++)
183 { 183 {
184 // Get queue item 184 // Get queue item
185 QIS = eventQueue.Dequeue(); 185 QIS = eventQueue.Dequeue();
186 186
187 // Check if object is being processed by someone else 187 // Check if object is being processed by someone else
188 if (TryLock(QIS.localID) == false) 188 if (TryLock(QIS.localID) == false)
189 { 189 {
190 // Object is already being processed, requeue it 190 // Object is already being processed, requeue it
191 eventQueue.Enqueue(QIS); 191 eventQueue.Enqueue(QIS);
192 } 192 }
193 else 193 else
194 { 194 {
195 // We have lock on an object and can process it 195 // We have lock on an object and can process it
196 GotItem = true; 196 GotItem = true;
197 break; 197 break;
198 } 198 }
199 } // go through queue 199 } // go through queue
200 } // lock 200 } // lock
201 201
202 if (GotItem == true) 202 if (GotItem == true)
203 { 203 {
204 // Execute function 204 // Execute function
205 try 205 try
206 { 206 {
207#if DEBUG 207#if DEBUG
208 m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n" 208 m_ScriptEngine.Log.Debug("ScriptEngine", "Executing event:\r\n"
209 + "QIS.localID: " + QIS.localID 209 + "QIS.localID: " + QIS.localID
210 + ", QIS.itemID: " + QIS.itemID 210 + ", QIS.itemID: " + QIS.itemID
211 + ", QIS.functionName: " + QIS.functionName); 211 + ", QIS.functionName: " + QIS.functionName);
212#endif 212#endif
213 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID, 213 m_ScriptEngine.m_ScriptManager.ExecuteEvent(QIS.localID, QIS.itemID,
214 QIS.functionName, QIS.param); 214 QIS.functionName, QIS.param);
215 } 215 }
216 catch (Exception e) 216 catch (Exception e)
217 { 217 {
218 // DISPLAY ERROR INWORLD 218 // DISPLAY ERROR INWORLD
219 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n"; 219 string text = "Error executing script function \"" + QIS.functionName + "\":\r\n";
220 //if (e.InnerException != null) 220 //if (e.InnerException != null)
221 //{ 221 //{
222 // Send inner exception 222 // Send inner exception
223 text += e.InnerException.Message.ToString(); 223 text += e.InnerException.Message.ToString();
224 //} 224 //}
225 //else 225 //else
226 //{ 226 //{
227 text += "\r\n"; 227 text += "\r\n";
228 // Send normal 228 // Send normal
229 text += e.Message.ToString(); 229 text += e.Message.ToString();
230 //} 230 //}
231 try 231 try
232 { 232 {
233 if (text.Length > 1500) 233 if (text.Length > 1500)
234 text = text.Substring(0, 1500); 234 text = text.Substring(0, 1500);
235 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID); 235 IScriptHost m_host = m_ScriptEngine.World.GetSceneObjectPart(QIS.localID);
236 //if (m_host != null) 236 //if (m_host != null)
237 //{ 237 //{
238 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0, 238 m_ScriptEngine.World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0,
239 m_host.AbsolutePosition, m_host.Name, m_host.UUID); 239 m_host.AbsolutePosition, m_host.Name, m_host.UUID);
240 } 240 }
241 catch 241 catch
242 { 242 {
243 //} 243 //}
244 //else 244 //else
245 //{ 245 //{
246 // T oconsole 246 // T oconsole
247 m_ScriptEngine.Log.Error("ScriptEngine", 247 m_ScriptEngine.Log.Error("ScriptEngine",
248 "Unable to send text in-world:\r\n" + text); 248 "Unable to send text in-world:\r\n" + text);
249 } 249 }
250 } 250 }
251 finally 251 finally
252 { 252 {
253 ReleaseLock(QIS.localID); 253 ReleaseLock(QIS.localID);
254 } 254 }
255 } 255 }
256 } // Something in queue 256 } // Something in queue
257 } 257 }
258 catch (ThreadAbortException tae) 258 catch (ThreadAbortException tae)
259 { 259 {
260 throw tae; 260 throw tae;
261 } 261 }
262 catch (Exception e) 262 catch (Exception e)
263 { 263 {
264 m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString()); 264 m_ScriptEngine.Log.Error("ScriptEngine", "Exception in EventQueueThreadLoop: " + e.ToString());
265 } 265 }
266 } // while 266 } // while
267 } // try 267 } // try
268 catch (ThreadAbortException) 268 catch (ThreadAbortException)
269 { 269 {
270 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message); 270 //myScriptEngine.Log.Verbose("ScriptEngine", "EventQueueManager Worker thread killed: " + tae.Message);
271 } 271 }
272 } 272 }
273 273
274 /// <summary> 274 /// <summary>
275 /// Try to get a mutex lock on localID 275 /// Try to get a mutex lock on localID
276 /// </summary> 276 /// </summary>
277 /// <param name="localID"></param> 277 /// <param name="localID"></param>
278 /// <returns></returns> 278 /// <returns></returns>
279 private bool TryLock(uint localID) 279 private bool TryLock(uint localID)
280 { 280 {
281 lock (tryLockLock) 281 lock (tryLockLock)
282 { 282 {
283 if (objectLocks.Contains(localID) == true) 283 if (objectLocks.Contains(localID) == true)
284 { 284 {
285 return false; 285 return false;
286 } 286 }
287 else 287 else
288 { 288 {
289 objectLocks.Add(localID); 289 objectLocks.Add(localID);
290 return true; 290 return true;
291 } 291 }
292 } 292 }
293 } 293 }
294 294
295 /// <summary> 295 /// <summary>
296 /// Release mutex lock on localID 296 /// Release mutex lock on localID
297 /// </summary> 297 /// </summary>
298 /// <param name="localID"></param> 298 /// <param name="localID"></param>
299 private void ReleaseLock(uint localID) 299 private void ReleaseLock(uint localID)
300 { 300 {
301 lock (tryLockLock) 301 lock (tryLockLock)
302 { 302 {
303 if (objectLocks.Contains(localID) == true) 303 if (objectLocks.Contains(localID) == true)
304 { 304 {
305 objectLocks.Remove(localID); 305 objectLocks.Remove(localID);
306 } 306 }
307 } 307 }
308 } 308 }
309 309
310 310
311 /// <summary> 311 /// <summary>
312 /// Add event to event execution queue 312 /// Add event to event execution queue
313 /// </summary> 313 /// </summary>
314 /// <param name="localID"></param> 314 /// <param name="localID"></param>
315 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 315 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
316 /// <param name="param">Array of parameters to match event mask</param> 316 /// <param name="param">Array of parameters to match event mask</param>
317 public void AddToObjectQueue(uint localID, string FunctionName, params object[] param) 317 public void AddToObjectQueue(uint localID, string FunctionName, params object[] param)
318 { 318 {
319 // Determine all scripts in Object and add to their queue 319 // Determine all scripts in Object and add to their queue
320 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName); 320 //myScriptEngine.m_logger.Verbose("ScriptEngine", "EventQueueManager Adding localID: " + localID + ", FunctionName: " + FunctionName);
321 321
322 322
323 // Do we have any scripts in this object at all? If not, return 323 // Do we have any scripts in this object at all? If not, return
324 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false) 324 if (m_ScriptEngine.m_ScriptManager.Scripts.ContainsKey(localID) == false)
325 { 325 {
326 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID."); 326 //Console.WriteLine("Event \"" + FunctionName + "\" for localID: " + localID + ". No scripts found on this localID.");
327 return; 327 return;
328 } 328 }
329 329
330 Dictionary<LLUUID, IScript>.KeyCollection scriptKeys = 330 Dictionary<LLUUID, IScript>.KeyCollection scriptKeys =
331 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID); 331 m_ScriptEngine.m_ScriptManager.GetScriptKeys(localID);
332 332
333 foreach (LLUUID itemID in scriptKeys) 333 foreach (LLUUID itemID in scriptKeys)
334 { 334 {
335 // Add to each script in that object 335 // Add to each script in that object
336 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter? 336 // TODO: Some scripts may not subscribe to this event. Should we NOT add it? Does it matter?
337 AddToScriptQueue(localID, itemID, FunctionName, param); 337 AddToScriptQueue(localID, itemID, FunctionName, param);
338 } 338 }
339 } 339 }
340 340
341 /// <summary> 341 /// <summary>
342 /// Add event to event execution queue 342 /// Add event to event execution queue
343 /// </summary> 343 /// </summary>
344 /// <param name="localID"></param> 344 /// <param name="localID"></param>
345 /// <param name="itemID"></param> 345 /// <param name="itemID"></param>
346 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param> 346 /// <param name="FunctionName">Name of the function, will be state + "_event_" + FunctionName</param>
347 /// <param name="param">Array of parameters to match event mask</param> 347 /// <param name="param">Array of parameters to match event mask</param>
348 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param) 348 public void AddToScriptQueue(uint localID, LLUUID itemID, string FunctionName, params object[] param)
349 { 349 {
350 lock (queueLock) 350 lock (queueLock)
351 { 351 {
352 // Create a structure and add data 352 // Create a structure and add data
353 QueueItemStruct QIS = new QueueItemStruct(); 353 QueueItemStruct QIS = new QueueItemStruct();
354 QIS.localID = localID; 354 QIS.localID = localID;
355 QIS.itemID = itemID; 355 QIS.itemID = itemID;
356 QIS.functionName = FunctionName; 356 QIS.functionName = FunctionName;
357 QIS.param = param; 357 QIS.param = param;
358 358
359 // Add it to queue 359 // Add it to queue
360 eventQueue.Enqueue(QIS); 360 eventQueue.Enqueue(QIS);
361 } 361 }
362 } 362 }
363 } 363 }
364} \ No newline at end of file 364} \ No newline at end of file