aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs1435
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 @@
1using System;
2using System.IO;
3using System.Threading;
4using System.Collections;
5using System.Collections.Generic;
6using System.Security.Policy;
7using System.Reflection;
8using System.Xml;
9using libsecondlife;
10using log4net;
11using Nini.Config;
12using Amib.Threading;
13using OpenSim.Framework;
14using OpenSim.Region.Environment;
15using OpenSim.Region.Environment.Scenes;
16using OpenSim.Region.Environment.Interfaces;
17using OpenSim.Region.ScriptEngine.XEngine.Script;
18
19namespace 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}