diff options
author | Teravus Ovares | 2008-05-30 12:27:06 +0000 |
---|---|---|
committer | Teravus Ovares | 2008-05-30 12:27:06 +0000 |
commit | 1a47ff8094ee414a47aebd310826906d89428a09 (patch) | |
tree | 0e90b3a33f43ff8617a077bb57b86d6b28e63e71 /OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |
parent | * Fixed a dangling event hook that I added. (diff) | |
download | opensim-SC_OLD-1a47ff8094ee414a47aebd310826906d89428a09.zip opensim-SC_OLD-1a47ff8094ee414a47aebd310826906d89428a09.tar.gz opensim-SC_OLD-1a47ff8094ee414a47aebd310826906d89428a09.tar.bz2 opensim-SC_OLD-1a47ff8094ee414a47aebd310826906d89428a09.tar.xz |
* This is Melanie's XEngine script engine. I've not tested this real well, however, it's confirmed to compile and OpenSimulator to run successfully without this script engine active.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 1435 |
1 files changed, 1435 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs new file mode 100644 index 0000000..3ca03b2 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -0,0 +1,1435 @@ | |||
1 | using System; | ||
2 | using System.IO; | ||
3 | using System.Threading; | ||
4 | using System.Collections; | ||
5 | using System.Collections.Generic; | ||
6 | using System.Security.Policy; | ||
7 | using System.Reflection; | ||
8 | using System.Xml; | ||
9 | using libsecondlife; | ||
10 | using log4net; | ||
11 | using Nini.Config; | ||
12 | using Amib.Threading; | ||
13 | using OpenSim.Framework; | ||
14 | using OpenSim.Region.Environment; | ||
15 | using OpenSim.Region.Environment.Scenes; | ||
16 | using OpenSim.Region.Environment.Interfaces; | ||
17 | using OpenSim.Region.ScriptEngine.XEngine.Script; | ||
18 | |||
19 | namespace OpenSim.Region.ScriptEngine.XEngine | ||
20 | { | ||
21 | public class XEngine : IRegionModule | ||
22 | { | ||
23 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
24 | |||
25 | private SmartThreadPool m_ThreadPool; | ||
26 | private int m_MaxScriptQueue; | ||
27 | private Scene m_Scene; | ||
28 | private IConfig m_ScriptConfig; | ||
29 | private Compiler m_Compiler; | ||
30 | private EventManager m_EventManager; | ||
31 | private int m_EventLimit; | ||
32 | private bool m_KillTimedOutScripts; | ||
33 | |||
34 | private static List<XEngine> m_ScriptEngines = | ||
35 | new List<XEngine>(); | ||
36 | public AsyncCommandManager m_ASYNCLSLCommandManager; | ||
37 | |||
38 | // Maps the local id to the script inventory items in it | ||
39 | |||
40 | private Dictionary<uint, List<LLUUID> > m_PrimObjects = | ||
41 | new Dictionary<uint, List<LLUUID> >(); | ||
42 | |||
43 | // Maps the LLUUID above to the script instance | ||
44 | |||
45 | private Dictionary<LLUUID, XScriptInstance> m_Scripts = | ||
46 | new Dictionary<LLUUID, XScriptInstance>(); | ||
47 | |||
48 | // Maps the asset ID to the assembly | ||
49 | |||
50 | private Dictionary<LLUUID, string> m_Assemblies = | ||
51 | new Dictionary<LLUUID, string>(); | ||
52 | |||
53 | // This will list AppDomains by script asset | ||
54 | |||
55 | private Dictionary<LLUUID, AppDomain> m_AppDomains = | ||
56 | new Dictionary<LLUUID, AppDomain>(); | ||
57 | |||
58 | // List the scripts running in each appdomain | ||
59 | |||
60 | private Dictionary<LLUUID, List<LLUUID> > m_DomainScripts = | ||
61 | new Dictionary<LLUUID, List<LLUUID> >(); | ||
62 | |||
63 | public string ScriptEngineName | ||
64 | { | ||
65 | get { return "XEngine"; } | ||
66 | } | ||
67 | |||
68 | public Scene World | ||
69 | { | ||
70 | get { return m_Scene; } | ||
71 | } | ||
72 | |||
73 | public ILog Log | ||
74 | { | ||
75 | get { return m_log; } | ||
76 | } | ||
77 | |||
78 | public static List<XEngine> ScriptEngines | ||
79 | { | ||
80 | get { return m_ScriptEngines; } | ||
81 | } | ||
82 | |||
83 | private struct RezScriptParms | ||
84 | { | ||
85 | uint LocalID; | ||
86 | LLUUID ItemID; | ||
87 | string Script; | ||
88 | } | ||
89 | |||
90 | public IConfig ScriptConfigSource | ||
91 | { | ||
92 | get { return m_ScriptConfig; } | ||
93 | } | ||
94 | |||
95 | // | ||
96 | // IRegionModule functions | ||
97 | // | ||
98 | public void Initialise(Scene scene, IConfigSource configSource) | ||
99 | { | ||
100 | AppDomain.CurrentDomain.AssemblyResolve += | ||
101 | OnAssemblyResolve; | ||
102 | |||
103 | m_log.InfoFormat("[XEngine] Initializing scripts in region {0}", | ||
104 | scene.RegionInfo.RegionName); | ||
105 | m_Scene=scene; | ||
106 | |||
107 | m_ScriptConfig = configSource.Configs["XEngine"]; | ||
108 | |||
109 | if(m_ScriptConfig == null) | ||
110 | { | ||
111 | m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled"); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | int minThreads = m_ScriptConfig.GetInt("MinThreads", 2); | ||
116 | int maxThreads = m_ScriptConfig.GetInt("MaxThreads", 2); | ||
117 | int idleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60); | ||
118 | string priority = m_ScriptConfig.GetString("Priority", "BelowNormal"); | ||
119 | int maxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); | ||
120 | int stackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); | ||
121 | int sleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", | ||
122 | 10)*1000; | ||
123 | m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30); | ||
124 | m_KillTimedOutScripts = m_ScriptConfig.GetBoolean( | ||
125 | "KillTimedOutScripts", false); | ||
126 | int saveTime = m_ScriptConfig.GetInt("SaveInterval", 300)*1000; | ||
127 | |||
128 | ThreadPriority prio = ThreadPriority.BelowNormal; | ||
129 | switch(priority) | ||
130 | { | ||
131 | case "Lowest": | ||
132 | prio=ThreadPriority.Lowest; | ||
133 | break; | ||
134 | case "BelowNormal": | ||
135 | prio=ThreadPriority.BelowNormal; | ||
136 | break; | ||
137 | case "Normal": | ||
138 | prio=ThreadPriority.Normal; | ||
139 | break; | ||
140 | case "AboveNormal": | ||
141 | prio=ThreadPriority.AboveNormal; | ||
142 | break; | ||
143 | case "Highest": | ||
144 | prio=ThreadPriority.Highest; | ||
145 | break; | ||
146 | default: | ||
147 | m_log.ErrorFormat("[XEngine] Invalid thread priority: '"+ | ||
148 | priority+"'. Assuming BelowNormal"); | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | lock(m_ScriptEngines) | ||
153 | { | ||
154 | m_ScriptEngines.Add(this); | ||
155 | } | ||
156 | |||
157 | m_EventManager = new EventManager(this); | ||
158 | m_ASYNCLSLCommandManager = new AsyncCommandManager(this); | ||
159 | |||
160 | StartEngine(minThreads, maxThreads, idleTimeout, prio, | ||
161 | maxScriptQueue, stackSize); | ||
162 | |||
163 | m_Compiler = new Compiler(this); | ||
164 | |||
165 | m_Scene.EventManager.OnRezScript += OnRezScript; | ||
166 | m_Scene.EventManager.OnRemoveScript += OnRemoveScript; | ||
167 | m_Scene.EventManager.OnScriptReset += OnScriptReset; | ||
168 | |||
169 | if(sleepTime > 0) | ||
170 | { | ||
171 | m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
172 | this.DoMaintenance), new Object[] | ||
173 | { sleepTime }); | ||
174 | } | ||
175 | |||
176 | if(saveTime > 0) | ||
177 | { | ||
178 | m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
179 | this.DoBackup), new Object[] { saveTime }); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | public void PostInitialise() | ||
184 | { | ||
185 | m_ThreadPool.Start(); | ||
186 | } | ||
187 | |||
188 | public void Close() | ||
189 | { | ||
190 | lock(m_ScriptEngines) | ||
191 | { | ||
192 | if(m_ScriptEngines.Contains(this)) | ||
193 | m_ScriptEngines.Remove(this); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | public object DoBackup(object o) | ||
198 | { | ||
199 | Object[] p = (Object[])o; | ||
200 | int saveTime = (int)p[0]; | ||
201 | |||
202 | System.Threading.Thread.Sleep(saveTime); | ||
203 | |||
204 | // m_log.Debug("[XEngine] Backing up script states"); | ||
205 | |||
206 | List<XScriptInstance> instances = new List<XScriptInstance>(); | ||
207 | |||
208 | lock(m_Scripts) | ||
209 | { | ||
210 | foreach (XScriptInstance instance in m_Scripts.Values) | ||
211 | instances.Add(instance); | ||
212 | } | ||
213 | |||
214 | foreach (XScriptInstance i in instances) | ||
215 | { | ||
216 | string assembly = String.Empty; | ||
217 | |||
218 | lock(m_Scripts) | ||
219 | { | ||
220 | if(!m_Assemblies.ContainsKey(i.AssetID)) | ||
221 | continue; | ||
222 | assembly = m_Assemblies[i.AssetID]; | ||
223 | } | ||
224 | |||
225 | i.SaveState(assembly); | ||
226 | } | ||
227 | |||
228 | instances.Clear(); | ||
229 | |||
230 | m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
231 | this.DoBackup), new Object[] { saveTime }); | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | public object DoMaintenance(object p) | ||
237 | { | ||
238 | object[] parms = (object[])p; | ||
239 | int sleepTime = (int)parms[0]; | ||
240 | |||
241 | foreach (XScriptInstance inst in m_Scripts.Values) | ||
242 | { | ||
243 | if(inst.EventTime() > m_EventLimit) | ||
244 | { | ||
245 | inst.Stop(100); | ||
246 | if(!m_KillTimedOutScripts) | ||
247 | inst.Start(); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | System.Threading.Thread.Sleep(sleepTime); | ||
252 | |||
253 | m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
254 | this.DoMaintenance), new Object[] | ||
255 | { sleepTime }); | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | public string Name | ||
261 | { | ||
262 | get { return "XEngine"; } | ||
263 | } | ||
264 | |||
265 | public bool IsSharedModule | ||
266 | { | ||
267 | get { return false; } | ||
268 | } | ||
269 | |||
270 | // | ||
271 | // XEngine functions | ||
272 | // | ||
273 | public int MaxScriptQueue | ||
274 | { | ||
275 | get { return m_MaxScriptQueue; } | ||
276 | } | ||
277 | |||
278 | // | ||
279 | // Hooks | ||
280 | // | ||
281 | public void OnRezScript(uint localID, LLUUID itemID, string script) | ||
282 | { | ||
283 | m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
284 | this.DoOnRezScript), new Object[] | ||
285 | { localID, itemID, script}); | ||
286 | } | ||
287 | |||
288 | private object DoOnRezScript(object parm) | ||
289 | { | ||
290 | Object[] p = (Object[])parm; | ||
291 | uint localID = (uint)p[0]; | ||
292 | LLUUID itemID = (LLUUID)p[1]; | ||
293 | string script =(string)p[2]; | ||
294 | |||
295 | // Get the asset ID of the script, so we can check if we | ||
296 | // already have it. | ||
297 | |||
298 | SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); | ||
299 | if(part == null) | ||
300 | return false; | ||
301 | |||
302 | TaskInventoryItem item = part.GetInventoryItem(itemID); | ||
303 | if(item == null) | ||
304 | return false; | ||
305 | |||
306 | LLUUID assetID=item.AssetID; | ||
307 | |||
308 | // m_log.DebugFormat("[XEngine] Compiling script {0} ({1})", | ||
309 | // item.Name, itemID.ToString()); | ||
310 | |||
311 | string assembly=""; | ||
312 | try | ||
313 | { | ||
314 | assembly=m_Compiler.PerformScriptCompile(script, | ||
315 | assetID.ToString()); | ||
316 | m_log.DebugFormat("[XEngine] Loaded script {0}.{1}", | ||
317 | part.ParentGroup.RootPart.Name, item.Name); | ||
318 | } | ||
319 | catch (Exception e) | ||
320 | { | ||
321 | try | ||
322 | { | ||
323 | // DISPLAY ERROR INWORLD | ||
324 | string text = "Error compiling script:\r\n" + e.Message.ToString(); | ||
325 | if (text.Length > 1400) | ||
326 | text = text.Substring(0, 1400); | ||
327 | World.SimChat(Helpers.StringToField(text), | ||
328 | ChatTypeEnum.DebugChannel, 2147483647, | ||
329 | part.AbsolutePosition, | ||
330 | part.Name, part.UUID, false); | ||
331 | } | ||
332 | catch (Exception e2) // LEGIT: User Scripting | ||
333 | { | ||
334 | m_log.Error("[XEngine]: "+ | ||
335 | "Error displaying error in-world: " + | ||
336 | e2.ToString()); | ||
337 | m_log.Error("[XEngine]: " + | ||
338 | "Errormessage: Error compiling script:\r\n" + | ||
339 | e.Message.ToString()); | ||
340 | } | ||
341 | |||
342 | return false; | ||
343 | } | ||
344 | |||
345 | lock(m_Scripts) | ||
346 | { | ||
347 | // Create the object record | ||
348 | |||
349 | if(!m_PrimObjects.ContainsKey(localID)) | ||
350 | m_PrimObjects[localID] = new List<LLUUID>(); | ||
351 | |||
352 | if(!m_PrimObjects[localID].Contains(itemID)) | ||
353 | m_PrimObjects[localID].Add(itemID); | ||
354 | |||
355 | if(!m_Assemblies.ContainsKey(assetID)) | ||
356 | m_Assemblies[assetID] = assembly; | ||
357 | |||
358 | if((!m_Scripts.ContainsKey(itemID)) || | ||
359 | (m_Scripts[itemID].AssetID != assetID)) | ||
360 | { | ||
361 | LLUUID appDomain=assetID; | ||
362 | |||
363 | if(part.ParentGroup.RootPart.m_IsAttachment) | ||
364 | appDomain=part.ParentGroup.RootPart.UUID; | ||
365 | |||
366 | if(!m_AppDomains.ContainsKey(appDomain)) | ||
367 | { | ||
368 | try | ||
369 | { | ||
370 | AppDomainSetup appSetup = new AppDomainSetup(); | ||
371 | // appSetup.ApplicationBase = Path.Combine( | ||
372 | // "ScriptEngines", | ||
373 | // m_Scene.RegionInfo.RegionID.ToString()); | ||
374 | |||
375 | Evidence baseEvidence = | ||
376 | AppDomain.CurrentDomain.Evidence; | ||
377 | Evidence evidence = new Evidence(baseEvidence); | ||
378 | |||
379 | m_AppDomains[appDomain] = | ||
380 | AppDomain.CreateDomain( | ||
381 | m_Scene.RegionInfo.RegionID.ToString(), | ||
382 | evidence, appSetup); | ||
383 | |||
384 | m_AppDomains[appDomain].AssemblyResolve += | ||
385 | new ResolveEventHandler( | ||
386 | AssemblyResolver.OnAssemblyResolve); | ||
387 | m_DomainScripts[appDomain] = new List<LLUUID>(); | ||
388 | } | ||
389 | catch (Exception e) | ||
390 | { | ||
391 | m_log.Error("[XEngine] Exception creating app domain:\n"+e.ToString()); | ||
392 | return false; | ||
393 | } | ||
394 | } | ||
395 | m_DomainScripts[appDomain].Add(itemID); | ||
396 | |||
397 | |||
398 | XScriptInstance instance = new XScriptInstance(this,localID, | ||
399 | part.UUID, itemID, assetID, assembly, | ||
400 | m_AppDomains[appDomain]); | ||
401 | |||
402 | instance.AppDomain = appDomain; | ||
403 | |||
404 | m_Scripts[itemID] = instance; | ||
405 | } | ||
406 | } | ||
407 | return true; | ||
408 | } | ||
409 | |||
410 | public void OnRemoveScript(uint localID, LLUUID itemID) | ||
411 | { | ||
412 | lock(m_Scripts) | ||
413 | { | ||
414 | // Do we even have it? | ||
415 | if(!m_Scripts.ContainsKey(itemID)) | ||
416 | return; | ||
417 | |||
418 | m_ASYNCLSLCommandManager.RemoveScript(localID, itemID); | ||
419 | |||
420 | XScriptInstance instance=m_Scripts[itemID]; | ||
421 | m_Scripts.Remove(itemID); | ||
422 | |||
423 | instance.ClearQueue(); | ||
424 | instance.Stop(0); | ||
425 | |||
426 | SceneObjectPart part = | ||
427 | m_Scene.GetSceneObjectPart(localID); | ||
428 | |||
429 | if(part != null) | ||
430 | part.RemoveScriptEvents(itemID); | ||
431 | |||
432 | // Remove the script from it's prim | ||
433 | if(m_PrimObjects.ContainsKey(localID)) | ||
434 | { | ||
435 | // Remove inventory item record | ||
436 | if(m_PrimObjects[localID].Contains(itemID)) | ||
437 | m_PrimObjects[localID].Remove(itemID); | ||
438 | |||
439 | // If there are no more scripts, remove prim | ||
440 | if(m_PrimObjects[localID].Count == 0) | ||
441 | { | ||
442 | m_PrimObjects.Remove(localID); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | m_DomainScripts[instance.AppDomain].Remove(instance.ItemID); | ||
447 | if(m_DomainScripts[instance.AppDomain].Count == 0) | ||
448 | { | ||
449 | m_DomainScripts.Remove(instance.AppDomain); | ||
450 | UnloadAppDomain(instance.AppDomain); | ||
451 | } | ||
452 | |||
453 | instance = null; | ||
454 | |||
455 | CleanAssemblies(); | ||
456 | } | ||
457 | } | ||
458 | |||
459 | public void OnScriptReset(uint localID, LLUUID itemID) | ||
460 | { | ||
461 | ResetScript(itemID); | ||
462 | } | ||
463 | |||
464 | private void CleanAssemblies() | ||
465 | { | ||
466 | List<LLUUID> assetIDList = new List<LLUUID>(m_Assemblies.Keys); | ||
467 | |||
468 | foreach (XScriptInstance i in m_Scripts.Values) | ||
469 | { | ||
470 | if(assetIDList.Contains(i.AssetID)) | ||
471 | assetIDList.Remove(i.AssetID); | ||
472 | } | ||
473 | |||
474 | foreach (LLUUID assetID in assetIDList) | ||
475 | { | ||
476 | // m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]); | ||
477 | try | ||
478 | { | ||
479 | if(File.Exists(m_Assemblies[assetID])) | ||
480 | File.Delete(m_Assemblies[assetID]); | ||
481 | if(File.Exists(m_Assemblies[assetID]+".state")) | ||
482 | File.Delete(m_Assemblies[assetID]+".state"); | ||
483 | if(File.Exists(m_Assemblies[assetID]+".mdb")) | ||
484 | File.Delete(m_Assemblies[assetID]+".mdb"); | ||
485 | } | ||
486 | catch (Exception e) | ||
487 | { | ||
488 | } | ||
489 | m_Assemblies.Remove(assetID); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | private void UnloadAppDomain(LLUUID id) | ||
494 | { | ||
495 | if(m_AppDomains.ContainsKey(id)) | ||
496 | { | ||
497 | AppDomain domain=m_AppDomains[id]; | ||
498 | m_AppDomains.Remove(id); | ||
499 | |||
500 | AppDomain.Unload(domain); | ||
501 | domain = null; | ||
502 | // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString()); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | // | ||
507 | // Start processing | ||
508 | // | ||
509 | private void StartEngine(int minThreads, int maxThreads, | ||
510 | int idleTimeout, ThreadPriority threadPriority, | ||
511 | int maxScriptQueue, int stackSize) | ||
512 | { | ||
513 | m_MaxScriptQueue=maxScriptQueue; | ||
514 | |||
515 | STPStartInfo startInfo = new STPStartInfo(); | ||
516 | startInfo.IdleTimeout = idleTimeout; | ||
517 | startInfo.MaxWorkerThreads = maxThreads; | ||
518 | startInfo.MinWorkerThreads = minThreads; | ||
519 | startInfo.ThreadPriority = threadPriority; | ||
520 | startInfo.StackSize = stackSize; | ||
521 | startInfo.StartSuspended = true; | ||
522 | |||
523 | m_ThreadPool = new SmartThreadPool(startInfo); | ||
524 | } | ||
525 | |||
526 | // | ||
527 | // Used by script instances to queue event handler jobs | ||
528 | // | ||
529 | public IWorkItemResult QueueEventHandler(object parms) | ||
530 | { | ||
531 | return m_ThreadPool.QueueWorkItem(new WorkItemCallback( | ||
532 | this.ProcessEventHandler), parms); | ||
533 | } | ||
534 | |||
535 | // | ||
536 | // The main script engine worker | ||
537 | // | ||
538 | private object ProcessEventHandler(object parms) | ||
539 | { | ||
540 | XScriptInstance instance=(XScriptInstance)parms; | ||
541 | |||
542 | return instance.EventProcessor(); | ||
543 | } | ||
544 | |||
545 | // | ||
546 | // Post event to an entire prim | ||
547 | // | ||
548 | public bool PostObjectEvent(uint localID, XEventParams p) | ||
549 | { | ||
550 | bool result = false; | ||
551 | |||
552 | if(!m_PrimObjects.ContainsKey(localID)) | ||
553 | return false; | ||
554 | |||
555 | foreach (LLUUID itemID in m_PrimObjects[localID]) | ||
556 | { | ||
557 | if(m_Scripts.ContainsKey(itemID)) | ||
558 | { | ||
559 | XScriptInstance instance = m_Scripts[itemID]; | ||
560 | if(instance != null) | ||
561 | { | ||
562 | instance.PostEvent(p); | ||
563 | result = true; | ||
564 | } | ||
565 | } | ||
566 | } | ||
567 | return result; | ||
568 | } | ||
569 | |||
570 | // | ||
571 | // Post an event to a single script | ||
572 | // | ||
573 | public bool PostScriptEvent(LLUUID itemID, XEventParams p) | ||
574 | { | ||
575 | if(m_Scripts.ContainsKey(itemID)) | ||
576 | { | ||
577 | XScriptInstance instance = m_Scripts[itemID]; | ||
578 | if(instance != null) | ||
579 | instance.PostEvent(p); | ||
580 | return true; | ||
581 | } | ||
582 | return false; | ||
583 | } | ||
584 | |||
585 | public Assembly OnAssemblyResolve(object sender, | ||
586 | ResolveEventArgs args) | ||
587 | { | ||
588 | if(!(sender is System.AppDomain)) | ||
589 | return null; | ||
590 | |||
591 | string[] pathList=new string[] {"bin", "ScriptEngines", | ||
592 | Path.Combine("ScriptEngines", | ||
593 | m_Scene.RegionInfo.RegionID.ToString())}; | ||
594 | |||
595 | string assemblyName = args.Name; | ||
596 | if(assemblyName.IndexOf(",") != -1) | ||
597 | assemblyName=args.Name.Substring(0, args.Name.IndexOf(",")); | ||
598 | |||
599 | foreach (string s in pathList) | ||
600 | { | ||
601 | string path=Path.Combine(Directory.GetCurrentDirectory(), | ||
602 | Path.Combine(s, assemblyName))+".dll"; | ||
603 | |||
604 | if(File.Exists(path)) | ||
605 | return Assembly.LoadFrom(path); | ||
606 | } | ||
607 | |||
608 | return null; | ||
609 | } | ||
610 | |||
611 | private XScriptInstance GetInstance(LLUUID itemID) | ||
612 | { | ||
613 | XScriptInstance instance; | ||
614 | lock(m_Scripts) | ||
615 | { | ||
616 | if(!m_Scripts.ContainsKey(itemID)) | ||
617 | return null; | ||
618 | instance = m_Scripts[itemID]; | ||
619 | } | ||
620 | return instance; | ||
621 | } | ||
622 | |||
623 | public void SetScriptState(LLUUID itemID, bool running) | ||
624 | { | ||
625 | XScriptInstance instance = GetInstance(itemID); | ||
626 | if(instance != null) | ||
627 | { | ||
628 | if(running) | ||
629 | instance.Start(); | ||
630 | else | ||
631 | instance.Stop(500); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | public bool GetScriptState(LLUUID itemID) | ||
636 | { | ||
637 | XScriptInstance instance = GetInstance(itemID); | ||
638 | if(instance != null) | ||
639 | return instance.Running; | ||
640 | return false; | ||
641 | } | ||
642 | |||
643 | public void ResetScript(LLUUID itemID) | ||
644 | { | ||
645 | XScriptInstance instance = GetInstance(itemID); | ||
646 | if(instance != null) | ||
647 | instance.ResetScript(); | ||
648 | } | ||
649 | |||
650 | public XDetectParams GetDetectParams(LLUUID itemID, int idx) | ||
651 | { | ||
652 | XScriptInstance instance = GetInstance(itemID); | ||
653 | if(instance != null) | ||
654 | return instance.GetDetectParams(idx); | ||
655 | return new XDetectParams(); | ||
656 | } | ||
657 | |||
658 | public LLUUID GetDetectID(LLUUID itemID, int idx) | ||
659 | { | ||
660 | XScriptInstance instance = GetInstance(itemID); | ||
661 | if(instance != null) | ||
662 | return instance.GetDetectID(idx); | ||
663 | return LLUUID.Zero; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | public struct XDetectParams | ||
668 | { | ||
669 | public LLUUID Key; | ||
670 | public LSL_Types.Vector3 OffsetPos; | ||
671 | } | ||
672 | |||
673 | public class XEventParams | ||
674 | { | ||
675 | public XEventParams(string eventName, Object[] eventParams, XDetectParams[] detectParams) | ||
676 | { | ||
677 | EventName=eventName; | ||
678 | Params=eventParams; | ||
679 | DetectParams=detectParams; | ||
680 | } | ||
681 | |||
682 | public string EventName; | ||
683 | public Object[] Params; | ||
684 | public XDetectParams[] DetectParams; | ||
685 | } | ||
686 | |||
687 | public class XScriptInstance | ||
688 | { | ||
689 | private XEngine m_Engine; | ||
690 | private IWorkItemResult m_CurrentResult=null; | ||
691 | private Queue m_EventQueue=new Queue(32); | ||
692 | private bool m_RunEvents=false; | ||
693 | private LLUUID m_ItemID; | ||
694 | private uint m_LocalID; | ||
695 | private LLUUID m_ObjectID; | ||
696 | private LLUUID m_AssetID; | ||
697 | private IScript m_Script; | ||
698 | private LSL_ScriptCommands m_LSLCommands; | ||
699 | private OSSL_ScriptCommands m_OSSLCommands; | ||
700 | private Executor m_Executor; | ||
701 | private LLUUID m_AppDomain; | ||
702 | private XDetectParams[] m_DetectParams; | ||
703 | private bool m_TimerQueued; | ||
704 | private DateTime m_EventStart; | ||
705 | private bool m_InEvent; | ||
706 | |||
707 | // Script state | ||
708 | private string m_State="default"; | ||
709 | |||
710 | public Object[] PluginData = new Object[0]; | ||
711 | |||
712 | public bool Running | ||
713 | { | ||
714 | get { return m_RunEvents; } | ||
715 | } | ||
716 | |||
717 | public string State | ||
718 | { | ||
719 | get { return m_State; } | ||
720 | set { m_State = value; } | ||
721 | } | ||
722 | |||
723 | public XEngine Engine | ||
724 | { | ||
725 | get { return m_Engine; } | ||
726 | } | ||
727 | |||
728 | public LLUUID AppDomain | ||
729 | { | ||
730 | get { return m_AppDomain; } | ||
731 | set { m_AppDomain = value; } | ||
732 | } | ||
733 | |||
734 | public LLUUID ItemID | ||
735 | { | ||
736 | get { return m_ItemID; } | ||
737 | } | ||
738 | |||
739 | public LLUUID ObjectID | ||
740 | { | ||
741 | get { return m_ObjectID; } | ||
742 | } | ||
743 | |||
744 | public uint LocalID | ||
745 | { | ||
746 | get { return m_LocalID; } | ||
747 | } | ||
748 | |||
749 | public LLUUID AssetID | ||
750 | { | ||
751 | get { return m_AssetID; } | ||
752 | } | ||
753 | |||
754 | public Queue EventQueue | ||
755 | { | ||
756 | get { return m_EventQueue; } | ||
757 | } | ||
758 | |||
759 | public void ClearQueue() | ||
760 | { | ||
761 | m_TimerQueued = false; | ||
762 | m_EventQueue.Clear(); | ||
763 | } | ||
764 | |||
765 | public XScriptInstance(XEngine engine, uint localID, LLUUID objectID, | ||
766 | LLUUID itemID, LLUUID assetID, string assembly, AppDomain dom) | ||
767 | { | ||
768 | m_Engine=engine; | ||
769 | |||
770 | m_LocalID = localID; | ||
771 | m_ObjectID = objectID; | ||
772 | m_ItemID = itemID; | ||
773 | m_AssetID = assetID; | ||
774 | |||
775 | SceneObjectPart part=engine.World.GetSceneObjectPart(localID); | ||
776 | if(part == null) | ||
777 | { | ||
778 | engine.Log.Error("[XEngine] SceneObjectPart unavailable. Script NOT started."); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | m_LSLCommands = new LSL_ScriptCommands(engine, this, part, localID, | ||
783 | itemID); | ||
784 | m_OSSLCommands = new OSSL_ScriptCommands(engine, this, part, | ||
785 | localID, itemID); | ||
786 | |||
787 | try | ||
788 | { | ||
789 | m_Script = (IScript)dom.CreateInstanceAndUnwrap( | ||
790 | Path.GetFileNameWithoutExtension(assembly), | ||
791 | "SecondLife.Script"); | ||
792 | } | ||
793 | catch (Exception e) | ||
794 | { | ||
795 | m_Engine.Log.ErrorFormat("[XEngine] Error loading assembly {0}\n"+e.ToString(), assembly); | ||
796 | } | ||
797 | |||
798 | try | ||
799 | { | ||
800 | m_Script.Start(m_LSLCommands, m_OSSLCommands); | ||
801 | |||
802 | m_Executor = new Executor(m_Script); | ||
803 | |||
804 | // m_Engine.Log.Debug("[XEngine] Script instance created"); | ||
805 | |||
806 | part.SetScriptEvents(m_ItemID, | ||
807 | (int)m_Executor.GetStateEventFlags()); | ||
808 | } | ||
809 | catch (Exception e) | ||
810 | { | ||
811 | m_Engine.Log.Error("Error loading script instance\n"+e.ToString()); | ||
812 | } | ||
813 | |||
814 | string savedState = assembly+".state"; | ||
815 | if(File.Exists(savedState)) | ||
816 | { | ||
817 | string xml = String.Empty; | ||
818 | |||
819 | try | ||
820 | { | ||
821 | FileInfo fi = new FileInfo(savedState); | ||
822 | int size=(int)fi.Length; | ||
823 | if(size < 130000) | ||
824 | { | ||
825 | using (FileStream fs = File.Open(savedState, | ||
826 | FileMode.Open, FileAccess.Read, FileShare.None)) | ||
827 | { | ||
828 | System.Text.ASCIIEncoding enc = | ||
829 | new System.Text.ASCIIEncoding(); | ||
830 | |||
831 | Byte[] data=new Byte[size]; | ||
832 | fs.Read(data, 0, size); | ||
833 | |||
834 | xml=enc.GetString(data); | ||
835 | |||
836 | ScriptSerializer.Deserialize(xml, this); | ||
837 | |||
838 | m_Engine.m_ASYNCLSLCommandManager.CreateFromData( | ||
839 | m_LocalID, m_ItemID, m_ObjectID, | ||
840 | PluginData); | ||
841 | } | ||
842 | } | ||
843 | else | ||
844 | { | ||
845 | m_Engine.Log.Error("Unable to load script state: Memory limit exceeded"); | ||
846 | PostEvent(new XEventParams("state_entry", | ||
847 | new Object[0], new XDetectParams[0])); | ||
848 | } | ||
849 | } | ||
850 | catch (Exception e) | ||
851 | { | ||
852 | m_Engine.Log.ErrorFormat("Unable to load script state from xml: {0}\n"+e.ToString(), xml); | ||
853 | PostEvent(new XEventParams("state_entry", | ||
854 | new Object[0], new XDetectParams[0])); | ||
855 | } | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | PostEvent(new XEventParams("state_entry", | ||
860 | new Object[0], new XDetectParams[0])); | ||
861 | } | ||
862 | Start(); | ||
863 | } | ||
864 | |||
865 | public void VarDump(Dictionary<string, object> vars) | ||
866 | { | ||
867 | Console.WriteLine("Variable dump for script {0}", m_ItemID.ToString()); | ||
868 | foreach (KeyValuePair<string, object> v in vars) | ||
869 | { | ||
870 | Console.WriteLine("Variable: {0} = '{1}'", v. Key, | ||
871 | v.Value.ToString()); | ||
872 | } | ||
873 | } | ||
874 | |||
875 | public void Start() | ||
876 | { | ||
877 | lock(m_EventQueue) | ||
878 | { | ||
879 | if(Running) | ||
880 | return; | ||
881 | |||
882 | m_RunEvents=true; | ||
883 | |||
884 | if(m_EventQueue.Count > 0) | ||
885 | { | ||
886 | if(m_CurrentResult == null) | ||
887 | m_CurrentResult=m_Engine.QueueEventHandler(this); | ||
888 | } | ||
889 | } | ||
890 | } | ||
891 | |||
892 | public bool Stop(int timeout) | ||
893 | { | ||
894 | IWorkItemResult result; | ||
895 | |||
896 | lock(m_EventQueue) | ||
897 | { | ||
898 | if(!Running) | ||
899 | return true; | ||
900 | |||
901 | if(m_CurrentResult == null) | ||
902 | { | ||
903 | m_RunEvents=false; | ||
904 | return true; | ||
905 | } | ||
906 | |||
907 | if(m_CurrentResult.Cancel()) | ||
908 | { | ||
909 | m_CurrentResult=null; | ||
910 | m_RunEvents=false; | ||
911 | return true; | ||
912 | } | ||
913 | |||
914 | result=m_CurrentResult; | ||
915 | m_RunEvents=false; | ||
916 | } | ||
917 | |||
918 | if(SmartThreadPool.WaitAll(new IWorkItemResult[] {result}, new TimeSpan((long)timeout*100000), false)) | ||
919 | { | ||
920 | return true; | ||
921 | } | ||
922 | |||
923 | lock(m_EventQueue) | ||
924 | { | ||
925 | if(m_CurrentResult != null) | ||
926 | m_CurrentResult.Abort(); | ||
927 | else | ||
928 | return true; | ||
929 | } | ||
930 | |||
931 | return true; | ||
932 | } | ||
933 | |||
934 | public void SetState(string state) | ||
935 | { | ||
936 | PostEvent(new XEventParams("state_exit", new Object[0], | ||
937 | new XDetectParams[0])); | ||
938 | PostEvent(new XEventParams("state", new Object[] { state }, | ||
939 | new XDetectParams[0])); | ||
940 | PostEvent(new XEventParams("state_entry", new Object[0], | ||
941 | new XDetectParams[0])); | ||
942 | } | ||
943 | |||
944 | public void PostEvent(XEventParams data) | ||
945 | { | ||
946 | lock(m_EventQueue) | ||
947 | { | ||
948 | if(m_EventQueue.Count >= m_Engine.MaxScriptQueue) | ||
949 | return; | ||
950 | |||
951 | m_EventQueue.Enqueue(data); | ||
952 | if(data.EventName == "timer") | ||
953 | { | ||
954 | if(m_TimerQueued) | ||
955 | return; | ||
956 | m_TimerQueued = true; | ||
957 | } | ||
958 | |||
959 | if(!m_RunEvents) | ||
960 | return; | ||
961 | |||
962 | if(m_CurrentResult == null) | ||
963 | { | ||
964 | m_CurrentResult=m_Engine.QueueEventHandler(this); | ||
965 | } | ||
966 | } | ||
967 | } | ||
968 | |||
969 | public object EventProcessor() | ||
970 | { | ||
971 | XEventParams data=null; | ||
972 | |||
973 | lock(m_EventQueue) | ||
974 | { | ||
975 | data=(XEventParams)m_EventQueue.Dequeue(); | ||
976 | if(data == null) // Shouldn't happen | ||
977 | { | ||
978 | m_CurrentResult=null; | ||
979 | return 0; | ||
980 | } | ||
981 | if(data.EventName == "timer") | ||
982 | m_TimerQueued = false; | ||
983 | } | ||
984 | |||
985 | m_DetectParams=data.DetectParams; | ||
986 | |||
987 | if(data.EventName == "state") // Hardcoded state change | ||
988 | { | ||
989 | m_State=data.Params[0].ToString(); | ||
990 | m_Engine.m_ASYNCLSLCommandManager.RemoveScript( | ||
991 | m_LocalID, m_ItemID); | ||
992 | |||
993 | SceneObjectPart part=m_Engine.World.GetSceneObjectPart( | ||
994 | m_LocalID); | ||
995 | if(part != null) | ||
996 | { | ||
997 | part.SetScriptEvents(m_ItemID, | ||
998 | (int)m_Executor.GetStateEventFlags()); | ||
999 | } | ||
1000 | } | ||
1001 | else | ||
1002 | { | ||
1003 | // m_Engine.Log.DebugFormat("[XEngine] Processed event {0}", data.EventName); | ||
1004 | SceneObjectPart part=m_Engine.World.GetSceneObjectPart( | ||
1005 | m_LocalID); | ||
1006 | try | ||
1007 | { | ||
1008 | m_EventStart = DateTime.Now; | ||
1009 | m_InEvent = true; | ||
1010 | m_Executor.ExecuteEvent(data.EventName, data.Params); | ||
1011 | m_InEvent = false; | ||
1012 | } | ||
1013 | catch (Exception e) | ||
1014 | { | ||
1015 | m_InEvent = false; | ||
1016 | if(e is System.Threading.ThreadAbortException) | ||
1017 | { | ||
1018 | lock(m_EventQueue) | ||
1019 | { | ||
1020 | if((m_EventQueue.Count > 0) && m_RunEvents) | ||
1021 | { | ||
1022 | m_CurrentResult=m_Engine.QueueEventHandler(this); | ||
1023 | } | ||
1024 | else | ||
1025 | { | ||
1026 | m_CurrentResult=null; | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | m_DetectParams=null; | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | try | ||
1036 | { | ||
1037 | // DISPLAY ERROR INWORLD | ||
1038 | string text = "Runtime error:\n" + e.ToString(); | ||
1039 | if (text.Length > 1400) | ||
1040 | text = text.Substring(0, 1400); | ||
1041 | m_Engine.World.SimChat(Helpers.StringToField(text), | ||
1042 | ChatTypeEnum.DebugChannel, 2147483647, | ||
1043 | part.AbsolutePosition, | ||
1044 | part.Name, part.UUID, false); | ||
1045 | } | ||
1046 | catch (Exception e2) // LEGIT: User Scripting | ||
1047 | { | ||
1048 | m_Engine.Log.Error("[XEngine]: "+ | ||
1049 | "Error displaying error in-world: " + | ||
1050 | e2.ToString()); | ||
1051 | m_Engine.Log.Error("[XEngine]: " + | ||
1052 | "Errormessage: Error compiling script:\r\n" + | ||
1053 | e.ToString()); | ||
1054 | } | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | lock(m_EventQueue) | ||
1059 | { | ||
1060 | if((m_EventQueue.Count > 0) && m_RunEvents) | ||
1061 | { | ||
1062 | m_CurrentResult=m_Engine.QueueEventHandler(this); | ||
1063 | } | ||
1064 | else | ||
1065 | { | ||
1066 | m_CurrentResult=null; | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | m_DetectParams=null; | ||
1071 | |||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | public int EventTime() | ||
1076 | { | ||
1077 | if(!m_InEvent) | ||
1078 | return 0; | ||
1079 | |||
1080 | return (DateTime.Now - m_EventStart).Seconds; | ||
1081 | } | ||
1082 | |||
1083 | public void ResetScript() | ||
1084 | { | ||
1085 | Stop(0); | ||
1086 | m_Engine.m_ASYNCLSLCommandManager.RemoveScript(m_LocalID, m_ItemID); | ||
1087 | m_EventQueue.Clear(); | ||
1088 | m_Script.ResetVars(); | ||
1089 | m_State = "default"; | ||
1090 | Start(); | ||
1091 | PostEvent(new XEventParams("state_entry", | ||
1092 | new Object[0], new XDetectParams[0])); | ||
1093 | } | ||
1094 | |||
1095 | public Dictionary<string, object> GetVars() | ||
1096 | { | ||
1097 | return m_Script.GetVars(); | ||
1098 | } | ||
1099 | |||
1100 | public void SetVars(Dictionary<string, object> vars) | ||
1101 | { | ||
1102 | m_Script.SetVars(vars); | ||
1103 | } | ||
1104 | |||
1105 | public XDetectParams GetDetectParams(int idx) | ||
1106 | { | ||
1107 | if(idx < 0 || idx >= m_DetectParams.Length) | ||
1108 | return new XDetectParams(); | ||
1109 | |||
1110 | return m_DetectParams[idx]; | ||
1111 | } | ||
1112 | |||
1113 | public LLUUID GetDetectID(int idx) | ||
1114 | { | ||
1115 | if(idx < 0 || idx >= m_DetectParams.Length) | ||
1116 | return LLUUID.Zero; | ||
1117 | |||
1118 | return m_DetectParams[idx].Key; | ||
1119 | } | ||
1120 | |||
1121 | public void SaveState(string assembly) | ||
1122 | { | ||
1123 | PluginData = | ||
1124 | m_Engine.m_ASYNCLSLCommandManager.GetSerializationData( | ||
1125 | m_ItemID); | ||
1126 | |||
1127 | string xml=ScriptSerializer.Serialize(this); | ||
1128 | |||
1129 | try | ||
1130 | { | ||
1131 | FileStream fs = File.Create(assembly+".state"); | ||
1132 | System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); | ||
1133 | Byte[] buf=enc.GetBytes(xml); | ||
1134 | fs.Write(buf, 0, buf.Length); | ||
1135 | fs.Close(); | ||
1136 | } | ||
1137 | catch(Exception) | ||
1138 | { | ||
1139 | return; | ||
1140 | } | ||
1141 | } | ||
1142 | } | ||
1143 | |||
1144 | public class ScriptSerializer | ||
1145 | { | ||
1146 | public static string Serialize(XScriptInstance instance) | ||
1147 | { | ||
1148 | instance.Stop(50); | ||
1149 | |||
1150 | XmlDocument xmldoc = new XmlDocument(); | ||
1151 | |||
1152 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
1153 | "", ""); | ||
1154 | xmldoc.AppendChild(xmlnode); | ||
1155 | |||
1156 | XmlElement rootElement = xmldoc.CreateElement("", "ScriptState", | ||
1157 | ""); | ||
1158 | xmldoc.AppendChild(rootElement); | ||
1159 | |||
1160 | XmlElement state = xmldoc.CreateElement("", "State", ""); | ||
1161 | state.AppendChild(xmldoc.CreateTextNode(instance.State)); | ||
1162 | |||
1163 | rootElement.AppendChild(state); | ||
1164 | |||
1165 | Dictionary<string, Object> vars = instance.GetVars(); | ||
1166 | |||
1167 | XmlElement variables = xmldoc.CreateElement("", "Variables", ""); | ||
1168 | |||
1169 | foreach (KeyValuePair<string, Object> var in vars) | ||
1170 | WriteTypedValue(xmldoc, variables, "Variable", var.Key, | ||
1171 | var.Value); | ||
1172 | |||
1173 | rootElement.AppendChild(variables); | ||
1174 | |||
1175 | XmlElement queue = xmldoc.CreateElement("", "Queue", ""); | ||
1176 | |||
1177 | int count = instance.EventQueue.Count; | ||
1178 | |||
1179 | while(count > 0) | ||
1180 | { | ||
1181 | XEventParams ep = (XEventParams)instance.EventQueue.Dequeue(); | ||
1182 | instance.EventQueue.Enqueue(ep); | ||
1183 | count--; | ||
1184 | |||
1185 | XmlElement item = xmldoc.CreateElement("", "Item", ""); | ||
1186 | XmlAttribute itemEvent = xmldoc.CreateAttribute("", "event", | ||
1187 | ""); | ||
1188 | itemEvent.Value=ep.EventName; | ||
1189 | item.Attributes.Append(itemEvent); | ||
1190 | |||
1191 | XmlElement parms = xmldoc.CreateElement("", "Params", ""); | ||
1192 | |||
1193 | foreach (Object o in ep.Params) | ||
1194 | WriteTypedValue(xmldoc, parms, "Param", String.Empty, o); | ||
1195 | |||
1196 | item.AppendChild(parms); | ||
1197 | |||
1198 | XmlElement detect = xmldoc.CreateElement("", "Detected", ""); | ||
1199 | |||
1200 | foreach (XDetectParams det in ep.DetectParams) | ||
1201 | { | ||
1202 | XmlElement objectElem = xmldoc.CreateElement("", "Object", | ||
1203 | ""); | ||
1204 | XmlAttribute pos = xmldoc.CreateAttribute("", "pos", ""); | ||
1205 | pos.Value=det.OffsetPos.ToString(); | ||
1206 | objectElem.Attributes.Append(pos); | ||
1207 | objectElem.AppendChild( | ||
1208 | xmldoc.CreateTextNode(det.Key.ToString())); | ||
1209 | |||
1210 | detect.AppendChild(objectElem); | ||
1211 | } | ||
1212 | |||
1213 | item.AppendChild(detect); | ||
1214 | |||
1215 | queue.AppendChild(item); | ||
1216 | } | ||
1217 | |||
1218 | rootElement.AppendChild(queue); | ||
1219 | |||
1220 | XmlNode plugins = xmldoc.CreateElement("", "Plugins", ""); | ||
1221 | if(instance.PluginData.Length > 0) | ||
1222 | DumpList(xmldoc, plugins, | ||
1223 | new LSL_Types.list(instance.PluginData)); | ||
1224 | |||
1225 | rootElement.AppendChild(plugins); | ||
1226 | |||
1227 | instance.Start(); | ||
1228 | |||
1229 | return xmldoc.InnerXml; | ||
1230 | } | ||
1231 | |||
1232 | public static void Deserialize(string xml, XScriptInstance instance) | ||
1233 | { | ||
1234 | XmlDocument doc = new XmlDocument(); | ||
1235 | |||
1236 | Dictionary<string, object> vars = instance.GetVars(); | ||
1237 | |||
1238 | instance.PluginData = new Object[0]; | ||
1239 | |||
1240 | doc.LoadXml(xml); | ||
1241 | |||
1242 | XmlNodeList rootL = doc.GetElementsByTagName("ScriptState"); | ||
1243 | if(rootL.Count != 1) | ||
1244 | { | ||
1245 | return; | ||
1246 | } | ||
1247 | XmlNode rootNode = rootL[0]; | ||
1248 | |||
1249 | if(rootNode != null) | ||
1250 | { | ||
1251 | object varValue; | ||
1252 | XmlNodeList partL = rootNode.ChildNodes; | ||
1253 | |||
1254 | foreach (XmlNode part in partL) | ||
1255 | { | ||
1256 | switch(part.Name) | ||
1257 | { | ||
1258 | case "State": | ||
1259 | instance.State=part.InnerText; | ||
1260 | break; | ||
1261 | case "Variables": | ||
1262 | XmlNodeList varL = part.ChildNodes; | ||
1263 | foreach (XmlNode var in varL) | ||
1264 | { | ||
1265 | string varName; | ||
1266 | varValue=ReadTypedValue(var, out varName); | ||
1267 | |||
1268 | if(vars.ContainsKey(varName)) | ||
1269 | vars[varName] = varValue; | ||
1270 | } | ||
1271 | instance.SetVars(vars); | ||
1272 | break; | ||
1273 | case "Queue": | ||
1274 | XmlNodeList itemL = part.ChildNodes; | ||
1275 | foreach (XmlNode item in itemL) | ||
1276 | { | ||
1277 | List<Object> parms = new List<Object>(); | ||
1278 | List<XDetectParams> detected = | ||
1279 | new List<XDetectParams>(); | ||
1280 | |||
1281 | string eventName = | ||
1282 | item.Attributes.GetNamedItem("event").Value; | ||
1283 | XmlNodeList eventL = item.ChildNodes; | ||
1284 | foreach (XmlNode evt in eventL) | ||
1285 | { | ||
1286 | switch(evt.Name) | ||
1287 | { | ||
1288 | case "Params": | ||
1289 | XmlNodeList prms = evt.ChildNodes; | ||
1290 | foreach (XmlNode pm in prms) | ||
1291 | parms.Add(ReadTypedValue(pm)); | ||
1292 | |||
1293 | break; | ||
1294 | case "Detected": | ||
1295 | XmlNodeList detL = evt.ChildNodes; | ||
1296 | foreach (XmlNode det in detL) | ||
1297 | { | ||
1298 | string vect = | ||
1299 | det.Attributes.GetNamedItem( | ||
1300 | "pos").Value; | ||
1301 | LSL_Types.Vector3 v = | ||
1302 | new LSL_Types.Vector3(vect); | ||
1303 | LLUUID uuid = new LLUUID(); | ||
1304 | LLUUID.TryParse(det.InnerText, | ||
1305 | out uuid); | ||
1306 | |||
1307 | XDetectParams d; | ||
1308 | d.Key = uuid; | ||
1309 | d.OffsetPos = v; | ||
1310 | |||
1311 | detected.Add(d); | ||
1312 | } | ||
1313 | break; | ||
1314 | } | ||
1315 | } | ||
1316 | XEventParams ep = new XEventParams( | ||
1317 | eventName, parms.ToArray(), | ||
1318 | detected.ToArray()); | ||
1319 | instance.EventQueue.Enqueue(ep); | ||
1320 | } | ||
1321 | break; | ||
1322 | case "Plugins": | ||
1323 | instance.PluginData = ReadList(part).Data; | ||
1324 | break; | ||
1325 | } | ||
1326 | } | ||
1327 | } | ||
1328 | } | ||
1329 | |||
1330 | private static void DumpList(XmlDocument doc, XmlNode parent, | ||
1331 | LSL_Types.list l) | ||
1332 | { | ||
1333 | foreach (Object o in l.Data) | ||
1334 | WriteTypedValue(doc, parent, "ListItem", "", o); | ||
1335 | } | ||
1336 | |||
1337 | private static LSL_Types.list ReadList(XmlNode parent) | ||
1338 | { | ||
1339 | List<Object> olist = new List<Object>(); | ||
1340 | |||
1341 | XmlNodeList itemL = parent.ChildNodes; | ||
1342 | foreach(XmlNode item in itemL) | ||
1343 | olist.Add(ReadTypedValue(item)); | ||
1344 | |||
1345 | return new LSL_Types.list(olist.ToArray()); | ||
1346 | } | ||
1347 | |||
1348 | private static void WriteTypedValue(XmlDocument doc, XmlNode parent, | ||
1349 | string tag, string name, object value) | ||
1350 | { | ||
1351 | Type t=value.GetType(); | ||
1352 | XmlAttribute typ = doc.CreateAttribute("", "type", ""); | ||
1353 | XmlNode n = doc.CreateElement("", tag, ""); | ||
1354 | |||
1355 | if(value is LSL_Types.list) | ||
1356 | { | ||
1357 | typ.Value = "list"; | ||
1358 | n.Attributes.Append(typ); | ||
1359 | |||
1360 | DumpList(doc, n, (LSL_Types.list) value); | ||
1361 | |||
1362 | if(name != String.Empty) | ||
1363 | { | ||
1364 | XmlAttribute nam = doc.CreateAttribute("", "name", ""); | ||
1365 | nam.Value = name; | ||
1366 | n.Attributes.Append(nam); | ||
1367 | } | ||
1368 | |||
1369 | parent.AppendChild(n); | ||
1370 | return; | ||
1371 | } | ||
1372 | |||
1373 | n.AppendChild(doc.CreateTextNode(value.ToString())); | ||
1374 | |||
1375 | typ.Value = t.ToString(); | ||
1376 | n.Attributes.Append(typ); | ||
1377 | if(name != String.Empty) | ||
1378 | { | ||
1379 | XmlAttribute nam = doc.CreateAttribute("", "name", ""); | ||
1380 | nam.Value = name; | ||
1381 | n.Attributes.Append(nam); | ||
1382 | } | ||
1383 | |||
1384 | parent.AppendChild(n); | ||
1385 | } | ||
1386 | |||
1387 | private static object ReadTypedValue(XmlNode tag, out string name) | ||
1388 | { | ||
1389 | name = tag.Attributes.GetNamedItem("name").Value; | ||
1390 | |||
1391 | return ReadTypedValue(tag); | ||
1392 | } | ||
1393 | |||
1394 | private static object ReadTypedValue(XmlNode tag) | ||
1395 | { | ||
1396 | Object varValue; | ||
1397 | string assembly; | ||
1398 | |||
1399 | string itemType = tag.Attributes.GetNamedItem("type").Value; | ||
1400 | |||
1401 | if(itemType == "list") | ||
1402 | return ReadList(tag); | ||
1403 | |||
1404 | if(itemType == "libsecondlife.LLUUID") | ||
1405 | { | ||
1406 | LLUUID val = new LLUUID(); | ||
1407 | LLUUID.TryParse(tag.InnerText, out val); | ||
1408 | |||
1409 | return val; | ||
1410 | } | ||
1411 | |||
1412 | Type itemT = Type.GetType(itemType); | ||
1413 | if(itemT == null) | ||
1414 | { | ||
1415 | Object[] args = | ||
1416 | new Object[] { tag.InnerText }; | ||
1417 | |||
1418 | assembly = itemType+", OpenSim.Region.ScriptEngine.XEngine.Script"; | ||
1419 | itemT = Type.GetType(assembly); | ||
1420 | if(itemT == null) | ||
1421 | return null; | ||
1422 | |||
1423 | varValue = Activator.CreateInstance(itemT, args); | ||
1424 | |||
1425 | if(varValue == null) | ||
1426 | return null; | ||
1427 | } | ||
1428 | else | ||
1429 | { | ||
1430 | varValue = Convert.ChangeType(tag.InnerText, itemT); | ||
1431 | } | ||
1432 | return varValue; | ||
1433 | } | ||
1434 | } | ||
1435 | } | ||