diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs b/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs deleted file mode 100644 index 987a0a0..0000000 --- a/OpenSim/Region/ScriptEngine/Common/ScriptEngineBase/ScriptManager.cs +++ /dev/null | |||
@@ -1,510 +0,0 @@ | |||
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 OpenSim 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.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Runtime.Serialization.Formatters.Binary; | ||
33 | using System.Threading; | ||
34 | using OpenMetaverse; | ||
35 | using OpenSim.Region.Environment.Scenes; | ||
36 | using OpenSim.Region.ScriptEngine.Shared; | ||
37 | |||
38 | namespace OpenSim.Region.ScriptEngine.Common.ScriptEngineBase | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Loads scripts | ||
42 | /// Compiles them if necessary | ||
43 | /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution) | ||
44 | /// </summary> | ||
45 | /// | ||
46 | |||
47 | // This class is as close as you get to the script without being inside script class. It handles all the dirty work for other classes. | ||
48 | // * Keeps track of running scripts | ||
49 | // * Compiles script if necessary (through "Compiler") | ||
50 | // * Loads script (through "AppDomainManager" called from for example "EventQueueManager") | ||
51 | // * Executes functions inside script (called from for example "EventQueueManager" class) | ||
52 | // * Unloads script (through "AppDomainManager" called from for example "EventQueueManager") | ||
53 | // * Dedicated load/unload thread, and queues loading/unloading. | ||
54 | // This so that scripts starting or stopping will not slow down other theads or whole system. | ||
55 | // | ||
56 | [Serializable] | ||
57 | public abstract class ScriptManager : iScriptEngineFunctionModule | ||
58 | { | ||
59 | #region Declares | ||
60 | |||
61 | private Thread scriptLoadUnloadThread; | ||
62 | private static Thread staticScriptLoadUnloadThread; | ||
63 | // private int scriptLoadUnloadThread_IdleSleepms; | ||
64 | private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); | ||
65 | private static bool PrivateThread; | ||
66 | private int LoadUnloadMaxQueueSize; | ||
67 | private Object scriptLock = new Object(); | ||
68 | private bool m_started = false; | ||
69 | private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>(); | ||
70 | |||
71 | // Load/Unload structure | ||
72 | private struct LUStruct | ||
73 | { | ||
74 | public uint localID; | ||
75 | public UUID itemID; | ||
76 | public string script; | ||
77 | public LUType Action; | ||
78 | public int startParam; | ||
79 | public bool postOnRez; | ||
80 | } | ||
81 | |||
82 | private enum LUType | ||
83 | { | ||
84 | Unknown = 0, | ||
85 | Load = 1, | ||
86 | Unload = 2 | ||
87 | } | ||
88 | |||
89 | // Xantor 20080525: Keep a list of compiled scripts this session for reuse | ||
90 | public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>(); | ||
91 | |||
92 | // Object<string, Script<string, script>> | ||
93 | // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. | ||
94 | // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead! | ||
95 | public Dictionary<uint, Dictionary<UUID, IScript>> Scripts = | ||
96 | new Dictionary<uint, Dictionary<UUID, IScript>>(); | ||
97 | |||
98 | |||
99 | public Scene World | ||
100 | { | ||
101 | get { return m_scriptEngine.World; } | ||
102 | } | ||
103 | |||
104 | #endregion | ||
105 | |||
106 | public void ReadConfig() | ||
107 | { | ||
108 | // scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30); | ||
109 | // TODO: Requires sharing of all ScriptManagers to single thread | ||
110 | PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false); | ||
111 | LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100); | ||
112 | } | ||
113 | |||
114 | #region Object init/shutdown | ||
115 | |||
116 | public ScriptEngine m_scriptEngine; | ||
117 | |||
118 | public ScriptManager(ScriptEngine scriptEngine) | ||
119 | { | ||
120 | m_scriptEngine = scriptEngine; | ||
121 | } | ||
122 | public abstract void Initialize(); | ||
123 | public void Setup() | ||
124 | { | ||
125 | ReadConfig(); | ||
126 | Initialize(); | ||
127 | } | ||
128 | public void Start() | ||
129 | { | ||
130 | m_started = true; | ||
131 | |||
132 | |||
133 | AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); | ||
134 | |||
135 | // | ||
136 | // CREATE THREAD | ||
137 | // Private or shared | ||
138 | // | ||
139 | if (PrivateThread) | ||
140 | { | ||
141 | // Assign one thread per region | ||
142 | //scriptLoadUnloadThread = StartScriptLoadUnloadThread(); | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | // Shared thread - make sure one exist, then assign it to the private | ||
147 | if (staticScriptLoadUnloadThread == null) | ||
148 | { | ||
149 | //staticScriptLoadUnloadThread = StartScriptLoadUnloadThread(); | ||
150 | } | ||
151 | scriptLoadUnloadThread = staticScriptLoadUnloadThread; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | // TODO: unused | ||
156 | // private static int privateThreadCount = 0; | ||
157 | // private Thread StartScriptLoadUnloadThread() | ||
158 | // { | ||
159 | // Thread t = new Thread(ScriptLoadUnloadThreadLoop); | ||
160 | // string name = "ScriptLoadUnloadThread:"; | ||
161 | // if (PrivateThread) | ||
162 | // { | ||
163 | // name += "Private:" + privateThreadCount; | ||
164 | // privateThreadCount++; | ||
165 | // } | ||
166 | // else | ||
167 | // { | ||
168 | // name += "Shared"; | ||
169 | // } | ||
170 | // t.Name = name; | ||
171 | // t.IsBackground = true; | ||
172 | // t.Priority = ThreadPriority.Normal; | ||
173 | // t.Start(); | ||
174 | // OpenSim.Framework.ThreadTracker.Add(t); | ||
175 | // return t; | ||
176 | // } | ||
177 | |||
178 | ~ScriptManager() | ||
179 | { | ||
180 | // Abort load/unload thread | ||
181 | try | ||
182 | { | ||
183 | //PleaseShutdown = true; | ||
184 | //Thread.Sleep(100); | ||
185 | if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true) | ||
186 | { | ||
187 | scriptLoadUnloadThread.Abort(); | ||
188 | //scriptLoadUnloadThread.Join(); | ||
189 | } | ||
190 | } | ||
191 | catch | ||
192 | { | ||
193 | } | ||
194 | } | ||
195 | |||
196 | #endregion | ||
197 | |||
198 | #region Load / Unload scripts (Thread loop) | ||
199 | |||
200 | // TODO: unused | ||
201 | // private void ScriptLoadUnloadThreadLoop() | ||
202 | // { | ||
203 | // try | ||
204 | // { | ||
205 | // while (true) | ||
206 | // { | ||
207 | // if (LUQueue.Count == 0) | ||
208 | // Thread.Sleep(scriptLoadUnloadThread_IdleSleepms); | ||
209 | // //if (PleaseShutdown) | ||
210 | // // return; | ||
211 | // DoScriptLoadUnload(); | ||
212 | // } | ||
213 | // } | ||
214 | // catch (ThreadAbortException tae) | ||
215 | // { | ||
216 | // string a = tae.ToString(); | ||
217 | // a = String.Empty; | ||
218 | // // Expected | ||
219 | // } | ||
220 | // } | ||
221 | |||
222 | public void DoScriptLoadUnload() | ||
223 | { | ||
224 | if (!m_started) | ||
225 | return; | ||
226 | |||
227 | lock (LUQueue) | ||
228 | { | ||
229 | if (LUQueue.Count > 0) | ||
230 | { | ||
231 | m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName); | ||
232 | LUStruct item = LUQueue.Dequeue(); | ||
233 | |||
234 | if (item.Action == LUType.Unload) | ||
235 | { | ||
236 | _StopScript(item.localID, item.itemID); | ||
237 | RemoveScript(item.localID, item.itemID); | ||
238 | } | ||
239 | else if (item.Action == LUType.Load) | ||
240 | { | ||
241 | _StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | #endregion | ||
248 | |||
249 | #region Helper functions | ||
250 | |||
251 | private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) | ||
252 | { | ||
253 | //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name); | ||
254 | return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null; | ||
255 | } | ||
256 | |||
257 | #endregion | ||
258 | |||
259 | |||
260 | |||
261 | #region Start/Stop/Reset script | ||
262 | |||
263 | // private readonly Object startStopLock = new Object(); | ||
264 | |||
265 | /// <summary> | ||
266 | /// Fetches, loads and hooks up a script to an objects events | ||
267 | /// </summary> | ||
268 | /// <param name="itemID"></param> | ||
269 | /// <param name="localID"></param> | ||
270 | public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez) | ||
271 | { | ||
272 | lock (LUQueue) | ||
273 | { | ||
274 | if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started) | ||
275 | { | ||
276 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script."); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | LUStruct ls = new LUStruct(); | ||
281 | ls.localID = localID; | ||
282 | ls.itemID = itemID; | ||
283 | ls.script = Script; | ||
284 | ls.Action = LUType.Load; | ||
285 | ls.startParam = startParam; | ||
286 | ls.postOnRez = postOnRez; | ||
287 | LUQueue.Enqueue(ls); | ||
288 | m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /// <summary> | ||
293 | /// Disables and unloads a script | ||
294 | /// </summary> | ||
295 | /// <param name="localID"></param> | ||
296 | /// <param name="itemID"></param> | ||
297 | public void StopScript(uint localID, UUID itemID) | ||
298 | { | ||
299 | LUStruct ls = new LUStruct(); | ||
300 | ls.localID = localID; | ||
301 | ls.itemID = itemID; | ||
302 | ls.Action = LUType.Unload; | ||
303 | ls.startParam = 0; | ||
304 | ls.postOnRez = false; | ||
305 | lock (LUQueue) | ||
306 | { | ||
307 | LUQueue.Enqueue(ls); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | // Create a new instance of the compiler (reuse) | ||
312 | //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler(); | ||
313 | |||
314 | public abstract void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez); | ||
315 | public abstract void _StopScript(uint localID, UUID itemID); | ||
316 | |||
317 | |||
318 | #endregion | ||
319 | |||
320 | #region Perform event execution in script | ||
321 | |||
322 | /// <summary> | ||
323 | /// Execute a LL-event-function in Script | ||
324 | /// </summary> | ||
325 | /// <param name="localID">Object the script is located in</param> | ||
326 | /// <param name="itemID">Script ID</param> | ||
327 | /// <param name="FunctionName">Name of function</param> | ||
328 | /// <param name="args">Arguments to pass to function</param> | ||
329 | internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args) | ||
330 | { | ||
331 | //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined | ||
332 | ///#if DEBUG | ||
333 | /// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName); | ||
334 | ///#endif | ||
335 | // Execute a function in the script | ||
336 | //m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName); | ||
337 | //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID); | ||
338 | IScript Script = GetScript(localID, itemID); | ||
339 | if (Script == null) | ||
340 | { | ||
341 | return; | ||
342 | } | ||
343 | //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined | ||
344 | ///#if DEBUG | ||
345 | /// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName); | ||
346 | ///#endif | ||
347 | // Must be done in correct AppDomain, so leaving it up to the script itself | ||
348 | detparms[Script] = qParams; | ||
349 | Script.Exec.ExecuteEvent(FunctionName, args); | ||
350 | detparms.Remove(Script); | ||
351 | } | ||
352 | |||
353 | public uint GetLocalID(UUID itemID) | ||
354 | { | ||
355 | foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts) | ||
356 | { | ||
357 | if (k.Value.ContainsKey(itemID)) | ||
358 | return k.Key; | ||
359 | } | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | public int GetStateEventFlags(uint localID, UUID itemID) | ||
364 | { | ||
365 | // Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">"); | ||
366 | try | ||
367 | { | ||
368 | IScript Script = GetScript(localID, itemID); | ||
369 | if (Script == null) | ||
370 | { | ||
371 | return 0; | ||
372 | } | ||
373 | ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags(); | ||
374 | return (int)evflags; | ||
375 | } | ||
376 | catch (Exception) | ||
377 | { | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | |||
384 | #endregion | ||
385 | |||
386 | #region Internal functions to keep track of script | ||
387 | |||
388 | public List<UUID> GetScriptKeys(uint localID) | ||
389 | { | ||
390 | if (Scripts.ContainsKey(localID) == false) | ||
391 | return new List<UUID>(); | ||
392 | |||
393 | Dictionary<UUID, IScript> Obj; | ||
394 | Scripts.TryGetValue(localID, out Obj); | ||
395 | |||
396 | return new List<UUID>(Obj.Keys); | ||
397 | } | ||
398 | |||
399 | public IScript GetScript(uint localID, UUID itemID) | ||
400 | { | ||
401 | lock (scriptLock) | ||
402 | { | ||
403 | IScript Script = null; | ||
404 | |||
405 | if (Scripts.ContainsKey(localID) == false) | ||
406 | return null; | ||
407 | |||
408 | Dictionary<UUID, IScript> Obj; | ||
409 | Scripts.TryGetValue(localID, out Obj); | ||
410 | if (Obj.ContainsKey(itemID) == false) | ||
411 | return null; | ||
412 | |||
413 | // Get script | ||
414 | Obj.TryGetValue(itemID, out Script); | ||
415 | return Script; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | public void SetScript(uint localID, UUID itemID, IScript Script) | ||
420 | { | ||
421 | lock (scriptLock) | ||
422 | { | ||
423 | // Create object if it doesn't exist | ||
424 | if (Scripts.ContainsKey(localID) == false) | ||
425 | { | ||
426 | Scripts.Add(localID, new Dictionary<UUID, IScript>()); | ||
427 | } | ||
428 | |||
429 | // Delete script if it exists | ||
430 | Dictionary<UUID, IScript> Obj; | ||
431 | Scripts.TryGetValue(localID, out Obj); | ||
432 | if (Obj.ContainsKey(itemID) == true) | ||
433 | Obj.Remove(itemID); | ||
434 | |||
435 | // Add to object | ||
436 | Obj.Add(itemID, Script); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | public void RemoveScript(uint localID, UUID itemID) | ||
441 | { | ||
442 | if (localID == 0) | ||
443 | localID = GetLocalID(itemID); | ||
444 | |||
445 | // Don't have that object? | ||
446 | if (Scripts.ContainsKey(localID) == false) | ||
447 | return; | ||
448 | |||
449 | // Delete script if it exists | ||
450 | Dictionary<UUID, IScript> Obj; | ||
451 | Scripts.TryGetValue(localID, out Obj); | ||
452 | if (Obj.ContainsKey(itemID) == true) | ||
453 | Obj.Remove(itemID); | ||
454 | } | ||
455 | |||
456 | #endregion | ||
457 | |||
458 | |||
459 | public void ResetScript(uint localID, UUID itemID) | ||
460 | { | ||
461 | IScript s = GetScript(localID, itemID); | ||
462 | string script = s.Source; | ||
463 | StopScript(localID, itemID); | ||
464 | SceneObjectPart part = World.GetSceneObjectPart(localID); | ||
465 | part.GetInventoryItem(itemID).PermsMask = 0; | ||
466 | part.GetInventoryItem(itemID).PermsGranter = UUID.Zero; | ||
467 | StartScript(localID, itemID, script, s.StartParam, false); | ||
468 | } | ||
469 | |||
470 | |||
471 | #region Script serialization/deserialization | ||
472 | |||
473 | public void GetSerializedScript(uint localID, UUID itemID) | ||
474 | { | ||
475 | // Serialize the script and return it | ||
476 | // Should not be a problem | ||
477 | FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID); | ||
478 | BinaryFormatter b = new BinaryFormatter(); | ||
479 | b.Serialize(fs, GetScript(localID, itemID)); | ||
480 | fs.Close(); | ||
481 | } | ||
482 | |||
483 | public void PutSerializedScript(uint localID, UUID itemID) | ||
484 | { | ||
485 | // Deserialize the script and inject it into an AppDomain | ||
486 | |||
487 | // How to inject into an AppDomain? | ||
488 | } | ||
489 | |||
490 | #endregion | ||
491 | |||
492 | ///// <summary> | ||
493 | ///// If set to true then threads and stuff should try to make a graceful exit | ||
494 | ///// </summary> | ||
495 | //public bool PleaseShutdown | ||
496 | //{ | ||
497 | // get { return _PleaseShutdown; } | ||
498 | // set { _PleaseShutdown = value; } | ||
499 | //} | ||
500 | //private bool _PleaseShutdown = false; | ||
501 | |||
502 | public DetectParams[] GetDetectParams(IScript script) | ||
503 | { | ||
504 | if (detparms.ContainsKey(script)) | ||
505 | return detparms[script]; | ||
506 | |||
507 | return null; | ||
508 | } | ||
509 | } | ||
510 | } | ||