diff options
author | Tedd Hansen | 2008-09-17 16:46:23 +0000 |
---|---|---|
committer | Tedd Hansen | 2008-09-17 16:46:23 +0000 |
commit | e94d6f12eeb3bd84a752fc401847b4c25d39cdac (patch) | |
tree | a4d4f1d91df2f2dd2d6fc715c7b8e9bb241f5784 /OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs | |
parent | * SSL Documentation update from Lexa (diff) | |
download | opensim-SC_OLD-e94d6f12eeb3bd84a752fc401847b4c25d39cdac.zip opensim-SC_OLD-e94d6f12eeb3bd84a752fc401847b4c25d39cdac.tar.gz opensim-SC_OLD-e94d6f12eeb3bd84a752fc401847b4c25d39cdac.tar.bz2 opensim-SC_OLD-e94d6f12eeb3bd84a752fc401847b4c25d39cdac.tar.xz |
More ScriptEngine cleanup
Diffstat (limited to 'OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs')
-rw-r--r-- | OpenSim/Grid/ScriptEngine/DotNetEngine/ScriptManager.cs | 421 |
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 */ | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Runtime.Serialization.Formatters.Binary; | ||
34 | using System.Threading; | ||
35 | using libsecondlife; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Grid.ScriptEngine.DotNetEngine.Compiler; | ||
38 | using OpenSim.Grid.ScriptEngine.DotNetEngine.Compiler.LSL; | ||
39 | using OpenSim.Region.Environment.Scenes; | ||
40 | |||
41 | namespace 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 | } | ||