diff options
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 | } | ||