aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs')
-rw-r--r--OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs421
1 files changed, 0 insertions, 421 deletions
diff --git a/OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs
deleted file mode 100644
index 439fb7d..0000000
--- a/OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs
+++ /dev/null
@@ -1,421 +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/* Original code: Tedd Hansen */
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using System.Runtime.Serialization.Formatters.Binary;
34using System.Threading;
35using libsecondlife;
36using OpenSim.Framework;
37using OpenSim.Grid.ScriptEngine.DotNetEngine.Compiler;
38using OpenSim.Grid.ScriptEngine.DotNetEngine.Compiler.LSL;
39using OpenSim.Region.Environment.Scenes;
40
41namespace OpenSim.Grid.ScriptEngine.DotNetEngine
42{
43 /// <summary>
44 /// Loads scripts
45 /// Compiles them if necessary
46 /// Execute functions for EventQueueManager (Sends them to script on other AppDomain for execution)
47 /// </summary>
48 [Serializable]
49 public class ScriptManager
50 {
51 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
52
53 #region Declares
54
55 private Thread scriptLoadUnloadThread;
56 private int scriptLoadUnloadThread_IdleSleepms = 100;
57 private Queue<LoadStruct> loadQueue = new Queue<LoadStruct>();
58 private Queue<UnloadStruct> unloadQueue = new Queue<UnloadStruct>();
59
60 private struct LoadStruct
61 {
62 public uint localID;
63 public LLUUID itemID;
64 public string script;
65 }
66
67 private struct UnloadStruct
68 {
69 public uint localID;
70 public LLUUID itemID;
71 }
72
73 // Object<string, Script<string, script>>
74 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
75 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
76 internal Dictionary<uint, Dictionary<LLUUID, LSL_BaseClass>> Scripts =
77 new Dictionary<uint, Dictionary<LLUUID, LSL_BaseClass>>();
78
79 public Scene World
80 {
81 get { return m_scriptEngine.World; }
82 }
83
84 #endregion
85
86 #region Object init/shutdown
87
88 private ScriptEngine m_scriptEngine;
89
90 public ScriptManager(ScriptEngine scriptEngine)
91 {
92 m_scriptEngine = scriptEngine;
93 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
94 scriptLoadUnloadThread = new Thread(ScriptLoadUnloadThreadLoop);
95 scriptLoadUnloadThread.Name = "ScriptLoadUnloadThread";
96 scriptLoadUnloadThread.IsBackground = true;
97 scriptLoadUnloadThread.Priority = ThreadPriority.BelowNormal;
98 scriptLoadUnloadThread.Start();
99 }
100
101 ~ScriptManager()
102 {
103 // Abort load/unload thread
104 try
105 {
106 if (scriptLoadUnloadThread != null)
107 {
108 if (scriptLoadUnloadThread.IsAlive == true)
109 {
110 scriptLoadUnloadThread.Abort();
111 scriptLoadUnloadThread.Join();
112 }
113 }
114 }
115 catch
116 {
117 }
118 }
119
120 #endregion
121
122 #region Load / Unload scripts (Thread loop)
123
124 private void ScriptLoadUnloadThreadLoop()
125 {
126 try
127 {
128 while (true)
129 {
130 if (loadQueue.Count == 0 && unloadQueue.Count == 0)
131 Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
132
133 if (loadQueue.Count > 0)
134 {
135 LoadStruct item = loadQueue.Dequeue();
136 _StartScript(item.localID, item.itemID, item.script);
137 }
138
139 if (unloadQueue.Count > 0)
140 {
141 UnloadStruct item = unloadQueue.Dequeue();
142 _StopScript(item.localID, item.itemID);
143 }
144 }
145 }
146 catch (ThreadAbortException tae)
147 {
148 string a = tae.ToString();
149 a = "";
150 // Expected
151 }
152 }
153
154 #endregion
155
156 #region Helper functions
157
158 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
159 {
160 //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name);
161 return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null;
162 }
163
164 #endregion
165
166 #region Internal functions to keep track of script
167
168 internal Dictionary<LLUUID, LSL_BaseClass>.KeyCollection GetScriptKeys(uint localID)
169 {
170 if (Scripts.ContainsKey(localID) == false)
171 return null;
172
173 Dictionary<LLUUID, LSL_BaseClass> Obj;
174 Scripts.TryGetValue(localID, out Obj);
175
176 return Obj.Keys;
177 }
178
179 internal LSL_BaseClass GetScript(uint localID, LLUUID itemID)
180 {
181 if (Scripts.ContainsKey(localID) == false)
182 return null;
183
184 Dictionary<LLUUID, LSL_BaseClass> Obj;
185 Scripts.TryGetValue(localID, out Obj);
186 if (Obj.ContainsKey(itemID) == false)
187 return null;
188
189 // Get script
190 LSL_BaseClass Script;
191 Obj.TryGetValue(itemID, out Script);
192
193 return Script;
194 }
195
196 internal void SetScript(uint localID, LLUUID itemID, LSL_BaseClass Script)
197 {
198 // Create object if it doesn't exist
199 if (Scripts.ContainsKey(localID) == false)
200 {
201 Scripts.Add(localID, new Dictionary<LLUUID, LSL_BaseClass>());
202 }
203
204 // Delete script if it exists
205 Dictionary<LLUUID, LSL_BaseClass> Obj;
206 Scripts.TryGetValue(localID, out Obj);
207 if (Obj.ContainsKey(itemID) == true)
208 Obj.Remove(itemID);
209
210 // Add to object
211 Obj.Add(itemID, Script);
212 }
213
214 internal void RemoveScript(uint localID, LLUUID itemID)
215 {
216 // Don't have that object?
217 if (Scripts.ContainsKey(localID) == false)
218 return;
219
220 // Delete script if it exists
221 Dictionary<LLUUID, LSL_BaseClass> Obj;
222 Scripts.TryGetValue(localID, out Obj);
223 if (Obj.ContainsKey(itemID) == true)
224 Obj.Remove(itemID);
225 }
226
227 #endregion
228
229 #region Start/Stop/Reset script
230
231 /// <summary>
232 /// Fetches, loads and hooks up a script to an objects events
233 /// </summary>
234 /// <param name="itemID"></param>
235 /// <param name="localID"></param>
236 public void StartScript(uint localID, LLUUID itemID, string Script)
237 {
238 LoadStruct ls = new LoadStruct();
239 ls.localID = localID;
240 ls.itemID = itemID;
241 ls.script = Script;
242 loadQueue.Enqueue(ls);
243 }
244
245 /// <summary>
246 /// Disables and unloads a script
247 /// </summary>
248 /// <param name="localID"></param>
249 /// <param name="itemID"></param>
250 public void StopScript(uint localID, LLUUID itemID)
251 {
252 UnloadStruct ls = new UnloadStruct();
253 ls.localID = localID;
254 ls.itemID = itemID;
255 unloadQueue.Enqueue(ls);
256 }
257
258 public void ResetScript(uint localID, LLUUID itemID)
259 {
260 string script = GetScript(localID, itemID).SourceCode;
261 StopScript(localID, itemID);
262 StartScript(localID, itemID, script);
263 }
264
265 private void _StartScript(uint localID, LLUUID itemID, string Script)
266 {
267 //IScriptHost root = host.GetRoot();
268 Console.WriteLine("ScriptManager StartScript: localID: " + localID + ", itemID: " + itemID);
269
270 // We will initialize and start the script.
271 // It will be up to the script itself to hook up the correct events.
272 string ScriptSource = "";
273
274 SceneObjectPart m_host = World.GetSceneObjectPart(localID);
275
276 try
277 {
278 // Create a new instance of the compiler (currently we don't want reuse)
279 Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
280 // Compile (We assume LSL)
281 ScriptSource = LSLCompiler.CompileFromLSLText(Script);
282 //Console.WriteLine("Compilation of " + FileName + " done");
283 // * Insert yield into code
284 ScriptSource = ProcessYield(ScriptSource);
285
286
287#if DEBUG
288 long before;
289 before = GC.GetTotalMemory(true);
290#endif
291
292 LSL_BaseClass CompiledScript;
293 CompiledScript = m_scriptEngine.m_AppDomainManager.LoadScript(ScriptSource);
294
295#if DEBUG
296 Console.WriteLine("Script " + itemID + " occupies {0} bytes", GC.GetTotalMemory(true) - before);
297#endif
298
299 CompiledScript.SourceCode = ScriptSource;
300 // Add it to our script memstruct
301 SetScript(localID, itemID, CompiledScript);
302
303 // We need to give (untrusted) assembly a private instance of BuiltIns
304 // this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed.
305
306
307 LSL_BuiltIn_Commands LSLB = new LSL_BuiltIn_Commands(m_scriptEngine, m_host, localID, itemID);
308
309 // Start the script - giving it BuiltIns
310 CompiledScript.Start(LSLB);
311
312 // Fire the first start-event
313 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_entry", new object[] {});
314 }
315 catch (Exception e)
316 {
317 //m_scriptEngine.m_log.Error("[ScriptEngine]: Error compiling script: " + e.ToString());
318 try
319 {
320 // DISPLAY ERROR INWORLD
321 string text = "Error compiling script:\r\n" + e.Message.ToString();
322 if (text.Length > 1500)
323 text = text.Substring(0, 1500);
324 World.SimChat(Helpers.StringToField(text), ChatTypeEnum.Say, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID);
325 }
326 catch (Exception e2)
327 {
328 m_scriptEngine.m_log.Error("[ScriptEngine]: Error displaying error in-world: " + e2.ToString());
329 }
330 }
331 }
332
333 private void _StopScript(uint localID, LLUUID itemID)
334 {
335 // Stop script
336 Console.WriteLine("Stop script localID: " + localID + " LLUID: " + itemID.ToString());
337
338
339 // Stop long command on script
340 m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID);
341
342 LSL_BaseClass LSLBC = GetScript(localID, itemID);
343 if (LSLBC == null)
344 return;
345
346 // TEMP: First serialize it
347 //GetSerializedScript(localID, itemID);
348
349
350 try
351 {
352 // Get AppDomain
353 AppDomain ad = LSLBC.Exec.GetAppDomain();
354 // Tell script not to accept new requests
355 GetScript(localID, itemID).Exec.StopScript();
356 // Remove from internal structure
357 RemoveScript(localID, itemID);
358 // Tell AppDomain that we have stopped script
359 m_scriptEngine.m_AppDomainManager.StopScript(ad);
360 }
361 catch (Exception e)
362 {
363 Console.WriteLine("Exception stopping script localID: " + localID + " LLUID: " + itemID.ToString() +
364 ": " + e.ToString());
365 }
366 }
367
368 private string ProcessYield(string FileName)
369 {
370 // TODO: Create a new assembly and copy old but insert Yield Code
371 //return TempDotNetMicroThreadingCodeInjector.TestFix(FileName);
372 return FileName;
373 }
374
375 #endregion
376
377 #region Perform event execution in script
378
379 /// <summary>
380 /// Execute a LL-event-function in Script
381 /// </summary>
382 /// <param name="localID">Object the script is located in</param>
383 /// <param name="itemID">Script ID</param>
384 /// <param name="FunctionName">Name of function</param>
385 /// <param name="args">Arguments to pass to function</param>
386 internal void ExecuteEvent(uint localID, LLUUID itemID, string FunctionName, object[] args)
387 {
388 // Execute a function in the script
389 //m_scriptEngine.m_log.Info("[ScriptEngine]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
390 LSL_BaseClass Script = m_scriptEngine.m_ScriptManager.GetScript(localID, itemID);
391 if (Script == null)
392 return;
393
394 // Must be done in correct AppDomain, so leaving it up to the script itself
395 Script.Exec.ExecuteEvent(FunctionName, args);
396 }
397
398 #endregion
399
400 #region Script serialization/deserialization
401
402 public void GetSerializedScript(uint localID, LLUUID itemID)
403 {
404 // Serialize the script and return it
405 // Should not be a problem
406 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
407 BinaryFormatter b = new BinaryFormatter();
408 b.Serialize(fs, GetScript(localID, itemID));
409 fs.Close();
410 }
411
412 public void PutSerializedScript(uint localID, LLUUID itemID)
413 {
414 // Deserialize the script and inject it into an AppDomain
415
416 // How to inject into an AppDomain?
417 }
418
419 #endregion
420 }
421}