aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
diff options
context:
space:
mode:
authorTeravus Ovares2008-05-30 12:27:06 +0000
committerTeravus Ovares2008-05-30 12:27:06 +0000
commit1a47ff8094ee414a47aebd310826906d89428a09 (patch)
tree0e90b3a33f43ff8617a077bb57b86d6b28e63e71 /OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
parent* Fixed a dangling event hook that I added. (diff)
downloadopensim-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.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}