aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Instance
diff options
context:
space:
mode:
authorMelanie Thielker2008-08-27 22:38:36 +0000
committerMelanie Thielker2008-08-27 22:38:36 +0000
commit6e3367d68ca6e0e632078dc02f52b03bd034afce (patch)
tree787b31ac8ce1d29b40869aafa1bebd476e86979a /OpenSim/Region/ScriptEngine/Shared/Instance
parentRefactor Executor into the script app domain and IScript. This changes (diff)
downloadopensim-SC-6e3367d68ca6e0e632078dc02f52b03bd034afce.zip
opensim-SC-6e3367d68ca6e0e632078dc02f52b03bd034afce.tar.gz
opensim-SC-6e3367d68ca6e0e632078dc02f52b03bd034afce.tar.bz2
opensim-SC-6e3367d68ca6e0e632078dc02f52b03bd034afce.tar.xz
Refactor XScriptInstance to IScriptInstance and move into Shared/. Now
engines that want to use the XEngine's instance handling and state persistence can do so. IScriptInstance is optional, but it does require the SmartThreadPool if it is used.
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Instance')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs660
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs461
2 files changed, 1121 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
new file mode 100644
index 0000000..30c0274
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -0,0 +1,660 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Threading;
31using System.Collections;
32using System.Collections.Generic;
33using System.Security.Policy;
34using System.Reflection;
35using System.Globalization;
36using System.Xml;
37using libsecondlife;
38using log4net;
39using Nini.Config;
40using Amib.Threading;
41using OpenSim.Framework;
42using OpenSim.Region.Environment;
43using OpenSim.Region.Environment.Scenes;
44using OpenSim.Region.Environment.Interfaces;
45using OpenSim.Region.ScriptEngine.Shared;
46using OpenSim.Region.ScriptEngine.Shared.Api;
47using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
48using OpenSim.Region.ScriptEngine.Shared.CodeTools;
49using OpenSim.Region.ScriptEngine.Interfaces;
50
51namespace OpenSim.Region.ScriptEngine.Shared.Instance
52{
53 public class ScriptInstance : IScriptInstance
54 {
55 private IScriptEngine m_Engine;
56 private IWorkItemResult m_CurrentResult=null;
57 private Queue m_EventQueue = new Queue(32);
58 private bool m_RunEvents = false;
59 private LLUUID m_ItemID;
60 private uint m_LocalID;
61 private LLUUID m_ObjectID;
62 private LLUUID m_AssetID;
63 private IScript m_Script;
64 private LLUUID m_AppDomain;
65 private DetectParams[] m_DetectParams;
66 private bool m_TimerQueued;
67 private DateTime m_EventStart;
68 private bool m_InEvent;
69 private string m_PrimName;
70 private string m_ScriptName;
71 private string m_Assembly;
72 private int m_StartParam = 0;
73 private string m_CurrentEvent = String.Empty;
74 private bool m_InSelfDelete = false;
75
76 private Dictionary<string,IScriptApi> m_Apis = new Dictionary<string,IScriptApi>();
77
78 // Script state
79 private string m_State="default";
80
81 public Object[] PluginData = new Object[0];
82
83 public bool Running
84 {
85 get { return m_RunEvents; }
86 set { m_RunEvents = value; }
87 }
88
89 public string State
90 {
91 get { return m_State; }
92 set { m_State = value; }
93 }
94
95 public IScriptEngine Engine
96 {
97 get { return m_Engine; }
98 }
99
100 public LLUUID AppDomain
101 {
102 get { return m_AppDomain; }
103 set { m_AppDomain = value; }
104 }
105
106 public string PrimName
107 {
108 get { return m_PrimName; }
109 }
110
111 public string ScriptName
112 {
113 get { return m_ScriptName; }
114 }
115
116 public LLUUID ItemID
117 {
118 get { return m_ItemID; }
119 }
120
121 public LLUUID ObjectID
122 {
123 get { return m_ObjectID; }
124 }
125
126 public uint LocalID
127 {
128 get { return m_LocalID; }
129 }
130
131 public LLUUID AssetID
132 {
133 get { return m_AssetID; }
134 }
135
136 public Queue EventQueue
137 {
138 get { return m_EventQueue; }
139 }
140
141 public void ClearQueue()
142 {
143 m_TimerQueued = false;
144 m_EventQueue.Clear();
145 }
146
147 public int StartParam
148 {
149 get { return m_StartParam; }
150 set { m_StartParam = value; }
151 }
152
153 public ScriptInstance(IScriptEngine engine, uint localID,
154 LLUUID objectID, LLUUID itemID, LLUUID assetID, string assembly,
155 AppDomain dom, string primName, string scriptName,
156 int startParam, bool postOnRez, StateSource stateSource)
157 {
158 m_Engine = engine;
159
160 m_LocalID = localID;
161 m_ObjectID = objectID;
162 m_ItemID = itemID;
163 m_AssetID = assetID;
164 m_PrimName = primName;
165 m_ScriptName = scriptName;
166 m_Assembly = assembly;
167 m_StartParam = startParam;
168
169 ApiManager am = new ApiManager();
170
171 SceneObjectPart part=engine.World.GetSceneObjectPart(localID);
172 if (part == null)
173 {
174 engine.Log.Error("[Script] SceneObjectPart unavailable. Script NOT started.");
175 return;
176 }
177
178 foreach (string api in am.GetApis())
179 {
180 m_Apis[api] = am.CreateApi(api);
181 m_Apis[api].Initialize(engine, part, localID, itemID);
182 }
183
184 try
185 {
186 m_Script = (IScript)dom.CreateInstanceAndUnwrap(
187 Path.GetFileNameWithoutExtension(assembly),
188 "SecondLife.Script");
189 }
190 catch (Exception e)
191 {
192 m_Engine.Log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly);
193 }
194
195 try
196 {
197 foreach (KeyValuePair<string,IScriptApi> kv in m_Apis)
198 {
199 m_Script.InitApi(kv.Key, kv.Value);
200 }
201
202// m_Engine.Log.Debug("[Script] Script instance created");
203
204 part.SetScriptEvents(m_ItemID,
205 (int)m_Script.GetStateEventFlags(State));
206 }
207 catch (Exception e)
208 {
209 m_Engine.Log.Error("[Script] Error loading script instance\n"+e.ToString());
210 return;
211 }
212
213 string savedState = Path.Combine(Path.GetDirectoryName(assembly),
214 m_ItemID.ToString() + ".state");
215 if (File.Exists(savedState))
216 {
217 string xml = String.Empty;
218
219 try
220 {
221 FileInfo fi = new FileInfo(savedState);
222 int size=(int)fi.Length;
223 if (size < 512000)
224 {
225 using (FileStream fs = File.Open(savedState,
226 FileMode.Open, FileAccess.Read, FileShare.None))
227 {
228 System.Text.ASCIIEncoding enc =
229 new System.Text.ASCIIEncoding();
230
231 Byte[] data = new Byte[size];
232 fs.Read(data, 0, size);
233
234 xml = enc.GetString(data);
235
236 ScriptSerializer.Deserialize(xml, this);
237
238 AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands;
239 async.CreateFromData(
240 m_LocalID, m_ItemID, m_ObjectID,
241 PluginData);
242
243 m_Engine.Log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", m_PrimName, m_ScriptName);
244
245 if (m_RunEvents)
246 {
247 m_RunEvents = false;
248 Start();
249 if (postOnRez)
250 PostEvent(new EventParams("on_rez",
251 new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0]));
252 }
253
254 // we get new rez events on sim restart, too
255 // but if there is state, then we fire the change
256 // event
257 if (stateSource == StateSource.NewRez)
258 {
259// m_Engine.Log.Debug("[Script] Posted changed(CHANGED_REGION_RESTART) to script");
260 PostEvent(new EventParams("changed",
261 new Object[] {new LSL_Types.LSLInteger(256)}, new DetectParams[0]));
262 }
263 }
264 }
265 else
266 {
267 m_Engine.Log.Error("[Script] Unable to load script state: Memory limit exceeded");
268 Start();
269 PostEvent(new EventParams("state_entry",
270 new Object[0], new DetectParams[0]));
271 if (postOnRez)
272 PostEvent(new EventParams("on_rez",
273 new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0]));
274
275 }
276 }
277 catch (Exception e)
278 {
279 m_Engine.Log.ErrorFormat("[Script] Unable to load script state from xml: {0}\n"+e.ToString(), xml);
280 Start();
281 PostEvent(new EventParams("state_entry",
282 new Object[0], new DetectParams[0]));
283 if (postOnRez)
284 PostEvent(new EventParams("on_rez",
285 new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0]));
286 }
287 }
288 else
289 {
290// m_Engine.Log.ErrorFormat("[Script] Unable to load script state, file not found");
291 Start();
292 PostEvent(new EventParams("state_entry",
293 new Object[0], new DetectParams[0]));
294
295 if (postOnRez)
296 PostEvent(new EventParams("on_rez",
297 new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0]));
298 }
299 }
300
301 public void RemoveState()
302 {
303 string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly),
304 m_ItemID.ToString() + ".state");
305
306 try
307 {
308 File.Delete(savedState);
309 }
310 catch(Exception)
311 {
312 }
313 }
314
315 public void VarDump(Dictionary<string, object> vars)
316 {
317 Console.WriteLine("Variable dump for script {0}", m_ItemID.ToString());
318 foreach (KeyValuePair<string, object> v in vars)
319 {
320 Console.WriteLine("Variable: {0} = '{1}'", v. Key,
321 v.Value.ToString());
322 }
323 }
324
325 public void Start()
326 {
327 lock (m_EventQueue)
328 {
329 if (Running)
330 return;
331
332 m_RunEvents = true;
333
334 if (m_EventQueue.Count > 0)
335 {
336 if (m_CurrentResult == null)
337 m_CurrentResult = m_Engine.QueueEventHandler(this);
338 else
339 m_Engine.Log.Error("[Script] Tried to start a script that was already queued");
340 }
341 }
342 }
343
344 public bool Stop(int timeout)
345 {
346 IWorkItemResult result;
347
348 lock (m_EventQueue)
349 {
350 if (!Running)
351 return true;
352
353 if (m_CurrentResult == null)
354 {
355 m_RunEvents = false;
356 return true;
357 }
358
359 if (m_CurrentResult.Cancel())
360 {
361 m_CurrentResult = null;
362 m_RunEvents = false;
363 return true;
364 }
365
366 result = m_CurrentResult;
367 m_RunEvents = false;
368 }
369
370 if (SmartThreadPool.WaitAll(new IWorkItemResult[] {result}, new TimeSpan((long)timeout * 100000), false))
371 {
372 return true;
373 }
374
375 lock (m_EventQueue)
376 {
377 result = m_CurrentResult;
378 }
379
380 if (result == null)
381 return true;
382
383 if (!m_InSelfDelete)
384 result.Abort();
385
386 lock (m_EventQueue)
387 {
388 m_CurrentResult = null;
389 }
390
391 return true;
392 }
393
394 public void SetState(string state)
395 {
396 PostEvent(new EventParams("state_exit", new Object[0],
397 new DetectParams[0]));
398 PostEvent(new EventParams("state", new Object[] { state },
399 new DetectParams[0]));
400 PostEvent(new EventParams("state_entry", new Object[0],
401 new DetectParams[0]));
402 }
403
404 public void PostEvent(EventParams data)
405 {
406// m_Engine.Log.DebugFormat("[Script] Posted event {2} in state {3} to {0}.{1}",
407// m_PrimName, m_ScriptName, data.EventName, m_State);
408
409 if (!Running)
410 return;
411
412 lock (m_EventQueue)
413 {
414 if (m_EventQueue.Count >= m_Engine.MaxScriptQueue)
415 return;
416
417 m_EventQueue.Enqueue(data);
418 if (data.EventName == "timer")
419 {
420 if (m_TimerQueued)
421 return;
422 m_TimerQueued = true;
423 }
424
425 if (!m_RunEvents)
426 return;
427
428 if (m_CurrentResult == null)
429 {
430 m_CurrentResult = m_Engine.QueueEventHandler(this);
431 }
432 }
433 }
434
435 public object EventProcessor()
436 {
437 EventParams data = null;
438
439 lock (m_EventQueue)
440 {
441 data = (EventParams) m_EventQueue.Dequeue();
442 if (data == null) // Shouldn't happen
443 {
444 m_CurrentResult = null;
445 return 0;
446 }
447 if (data.EventName == "timer")
448 m_TimerQueued = false;
449 }
450
451 m_DetectParams = data.DetectParams;
452
453 if (data.EventName == "state") // Hardcoded state change
454 {
455// m_Engine.Log.DebugFormat("[Script] Script {0}.{1} state set to {2}",
456// m_PrimName, m_ScriptName, data.Params[0].ToString());
457 m_State=data.Params[0].ToString();
458 AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands;
459 async.RemoveScript(
460 m_LocalID, m_ItemID);
461
462 SceneObjectPart part = m_Engine.World.GetSceneObjectPart(
463 m_LocalID);
464 if (part != null)
465 {
466 part.SetScriptEvents(m_ItemID,
467 (int)m_Script.GetStateEventFlags(State));
468 }
469 }
470 else
471 {
472 SceneObjectPart part = m_Engine.World.GetSceneObjectPart(
473 m_LocalID);
474// m_Engine.Log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}",
475// m_PrimName, m_ScriptName, data.EventName, m_State);
476
477 try
478 {
479 m_CurrentEvent = data.EventName;
480 m_EventStart = DateTime.Now;
481 m_InEvent = true;
482
483 m_Script.ExecuteEvent(State, data.EventName, data.Params);
484
485 m_InEvent = false;
486 m_CurrentEvent = String.Empty;
487 }
488 catch (Exception e)
489 {
490 m_InEvent = false;
491 m_CurrentEvent = String.Empty;
492
493 if (!(e is TargetInvocationException) || (!(e.InnerException is EventAbortException) && (!(e.InnerException is SelfDeleteException))))
494 {
495 if (e is System.Threading.ThreadAbortException)
496 {
497 lock (m_EventQueue)
498 {
499 if ((m_EventQueue.Count > 0) && m_RunEvents)
500 {
501 m_CurrentResult=m_Engine.QueueEventHandler(this);
502 }
503 else
504 {
505 m_CurrentResult = null;
506 }
507 }
508
509 m_DetectParams = null;
510
511 return 0;
512 }
513
514 try
515 {
516 // DISPLAY ERROR INWORLD
517 string text = "Runtime error:\n" + e.ToString();
518 if (text.Length > 1400)
519 text = text.Substring(0, 1400);
520 m_Engine.World.SimChat(Helpers.StringToField(text),
521 ChatTypeEnum.DebugChannel, 2147483647,
522 part.AbsolutePosition,
523 part.Name, part.UUID, false);
524 }
525 catch (Exception e2) // LEGIT: User Scripting
526 {
527 m_Engine.Log.Error("[Script]: "+
528 "Error displaying error in-world: " +
529 e2.ToString());
530 m_Engine.Log.Error("[Script]: " +
531 "Errormessage: Error compiling script:\r\n" +
532 e.ToString());
533 }
534 }
535 else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException))
536 {
537 m_InSelfDelete = true;
538 if (part != null && part.ParentGroup != null)
539 m_Engine.World.DeleteSceneObject(part.ParentGroup);
540 }
541 }
542 }
543
544 lock (m_EventQueue)
545 {
546 if ((m_EventQueue.Count > 0) && m_RunEvents)
547 {
548 m_CurrentResult = m_Engine.QueueEventHandler(this);
549 }
550 else
551 {
552 m_CurrentResult = null;
553 }
554 }
555
556 m_DetectParams = null;
557
558 return 0;
559 }
560
561 public int EventTime()
562 {
563 if (!m_InEvent)
564 return 0;
565
566 return (DateTime.Now - m_EventStart).Seconds;
567 }
568
569 public void ResetScript()
570 {
571 bool running = Running;
572
573 RemoveState();
574
575 Stop(0);
576 SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID);
577 part.GetInventoryItem(m_ItemID).PermsMask = 0;
578 part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero;
579 AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands;
580 async.RemoveScript(m_LocalID, m_ItemID);
581 m_EventQueue.Clear();
582 m_Script.ResetVars();
583 m_State = "default";
584 if (running)
585 Start();
586 PostEvent(new EventParams("state_entry",
587 new Object[0], new DetectParams[0]));
588 }
589
590 public void ApiResetScript()
591 {
592 // bool running = Running;
593
594 RemoveState();
595
596 m_Script.ResetVars();
597 SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID);
598 part.GetInventoryItem(m_ItemID).PermsMask = 0;
599 part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero;
600 AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands;
601 async.RemoveScript(m_LocalID, m_ItemID);
602 if (m_CurrentEvent != "state_entry")
603 {
604 PostEvent(new EventParams("state_entry",
605 new Object[0], new DetectParams[0]));
606 }
607 }
608
609 public Dictionary<string, object> GetVars()
610 {
611 return m_Script.GetVars();
612 }
613
614 public void SetVars(Dictionary<string, object> vars)
615 {
616 m_Script.SetVars(vars);
617 }
618
619 public DetectParams GetDetectParams(int idx)
620 {
621 if (idx < 0 || idx >= m_DetectParams.Length)
622 return null;
623
624 return m_DetectParams[idx];
625 }
626
627 public LLUUID GetDetectID(int idx)
628 {
629 if (idx < 0 || idx >= m_DetectParams.Length)
630 return LLUUID.Zero;
631
632 return m_DetectParams[idx].Key;
633 }
634
635 public void SaveState(string assembly)
636 {
637 AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands;
638 PluginData = async.GetSerializationData(m_ItemID);
639
640 string xml = ScriptSerializer.Serialize(this);
641
642 try
643 {
644 FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"));
645 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
646 Byte[] buf = enc.GetBytes(xml);
647 fs.Write(buf, 0, buf.Length);
648 fs.Close();
649 }
650 catch(Exception e)
651 {
652 Console.WriteLine("Unable to save xml\n"+e.ToString());
653 }
654 if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")))
655 {
656 throw new Exception("Completed persistence save, but no file was created");
657 }
658 }
659 }
660}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs
new file mode 100644
index 0000000..ba003c5
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs
@@ -0,0 +1,461 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Threading;
31using System.Collections;
32using System.Collections.Generic;
33using System.Security.Policy;
34using System.Reflection;
35using System.Globalization;
36using System.Xml;
37using libsecondlife;
38using log4net;
39using Nini.Config;
40using Amib.Threading;
41using OpenSim.Framework;
42using OpenSim.Region.Environment;
43using OpenSim.Region.Environment.Scenes;
44using OpenSim.Region.Environment.Interfaces;
45using OpenSim.Region.ScriptEngine.Shared;
46using OpenSim.Region.ScriptEngine.Shared.Api;
47using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
48using OpenSim.Region.ScriptEngine.Shared.CodeTools;
49using OpenSim.Region.ScriptEngine.Interfaces;
50
51namespace OpenSim.Region.ScriptEngine.Shared.Instance
52{
53 public class ScriptSerializer
54 {
55 public static string Serialize(ScriptInstance instance)
56 {
57 bool running = instance.Running;
58
59 if (running)
60 instance.Stop(50);
61
62 XmlDocument xmldoc = new XmlDocument();
63
64 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
65 "", "");
66 xmldoc.AppendChild(xmlnode);
67
68 XmlElement rootElement = xmldoc.CreateElement("", "ScriptState",
69 "");
70 xmldoc.AppendChild(rootElement);
71
72 XmlElement state = xmldoc.CreateElement("", "State", "");
73 state.AppendChild(xmldoc.CreateTextNode(instance.State));
74
75 rootElement.AppendChild(state);
76
77 XmlElement run = xmldoc.CreateElement("", "Running", "");
78 run.AppendChild(xmldoc.CreateTextNode(
79 running.ToString()));
80
81 rootElement.AppendChild(run);
82
83 Dictionary<string, Object> vars = instance.GetVars();
84
85 XmlElement variables = xmldoc.CreateElement("", "Variables", "");
86
87 foreach (KeyValuePair<string, Object> var in vars)
88 WriteTypedValue(xmldoc, variables, "Variable", var.Key,
89 var.Value);
90
91 rootElement.AppendChild(variables);
92
93 XmlElement queue = xmldoc.CreateElement("", "Queue", "");
94
95 int count = instance.EventQueue.Count;
96
97 while (count > 0)
98 {
99 EventParams ep = (EventParams)instance.EventQueue.Dequeue();
100 instance.EventQueue.Enqueue(ep);
101 count--;
102
103 XmlElement item = xmldoc.CreateElement("", "Item", "");
104 XmlAttribute itemEvent = xmldoc.CreateAttribute("", "event",
105 "");
106 itemEvent.Value = ep.EventName;
107 item.Attributes.Append(itemEvent);
108
109 XmlElement parms = xmldoc.CreateElement("", "Params", "");
110
111 foreach (Object o in ep.Params)
112 WriteTypedValue(xmldoc, parms, "Param", String.Empty, o);
113
114 item.AppendChild(parms);
115
116 XmlElement detect = xmldoc.CreateElement("", "Detected", "");
117
118 foreach (DetectParams det in ep.DetectParams)
119 {
120 XmlElement objectElem = xmldoc.CreateElement("", "Object",
121 "");
122 XmlAttribute pos = xmldoc.CreateAttribute("", "pos", "");
123 pos.Value = det.OffsetPos.ToString();
124 objectElem.Attributes.Append(pos);
125
126 XmlAttribute d_linkNum = xmldoc.CreateAttribute("",
127 "linkNum", "");
128 d_linkNum.Value = det.LinkNum.ToString();
129 objectElem.Attributes.Append(d_linkNum);
130
131 XmlAttribute d_group = xmldoc.CreateAttribute("",
132 "group", "");
133 d_group.Value = det.Group.ToString();
134 objectElem.Attributes.Append(d_group);
135
136 XmlAttribute d_name = xmldoc.CreateAttribute("",
137 "name", "");
138 d_name.Value = det.Name.ToString();
139 objectElem.Attributes.Append(d_name);
140
141 XmlAttribute d_owner = xmldoc.CreateAttribute("",
142 "owner", "");
143 d_owner.Value = det.Owner.ToString();
144 objectElem.Attributes.Append(d_owner);
145
146 XmlAttribute d_position = xmldoc.CreateAttribute("",
147 "position", "");
148 d_position.Value = det.Position.ToString();
149 objectElem.Attributes.Append(d_position);
150
151 XmlAttribute d_rotation = xmldoc.CreateAttribute("",
152 "rotation", "");
153 d_rotation.Value = det.Rotation.ToString();
154 objectElem.Attributes.Append(d_rotation);
155
156 XmlAttribute d_type = xmldoc.CreateAttribute("",
157 "type", "");
158 d_type.Value = det.Type.ToString();
159 objectElem.Attributes.Append(d_type);
160
161 XmlAttribute d_velocity = xmldoc.CreateAttribute("",
162 "velocity", "");
163 d_velocity.Value = det.Velocity.ToString();
164 objectElem.Attributes.Append(d_velocity);
165
166 objectElem.AppendChild(
167 xmldoc.CreateTextNode(det.Key.ToString()));
168
169 detect.AppendChild(objectElem);
170 }
171
172 item.AppendChild(detect);
173
174 queue.AppendChild(item);
175 }
176
177 rootElement.AppendChild(queue);
178
179 XmlNode plugins = xmldoc.CreateElement("", "Plugins", "");
180 DumpList(xmldoc, plugins,
181 new LSL_Types.list(instance.PluginData));
182
183 rootElement.AppendChild(plugins);
184
185 if (running)
186 instance.Start();
187
188 return xmldoc.InnerXml;
189 }
190
191 public static void Deserialize(string xml, ScriptInstance instance)
192 {
193 XmlDocument doc = new XmlDocument();
194
195 Dictionary<string, object> vars = instance.GetVars();
196
197 instance.PluginData = new Object[0];
198
199 doc.LoadXml(xml);
200
201 XmlNodeList rootL = doc.GetElementsByTagName("ScriptState");
202 if (rootL.Count != 1)
203 {
204 return;
205 }
206 XmlNode rootNode = rootL[0];
207
208 if (rootNode != null)
209 {
210 object varValue;
211 XmlNodeList partL = rootNode.ChildNodes;
212
213 foreach (XmlNode part in partL)
214 {
215 switch (part.Name)
216 {
217 case "State":
218 instance.State=part.InnerText;
219 break;
220 case "Running":
221 instance.Running=bool.Parse(part.InnerText);
222 break;
223 case "Variables":
224 XmlNodeList varL = part.ChildNodes;
225 foreach (XmlNode var in varL)
226 {
227 string varName;
228 varValue=ReadTypedValue(var, out varName);
229
230 if (vars.ContainsKey(varName))
231 vars[varName] = varValue;
232 }
233 instance.SetVars(vars);
234 break;
235 case "Queue":
236 XmlNodeList itemL = part.ChildNodes;
237 foreach (XmlNode item in itemL)
238 {
239 List<Object> parms = new List<Object>();
240 List<DetectParams> detected =
241 new List<DetectParams>();
242
243 string eventName =
244 item.Attributes.GetNamedItem("event").Value;
245 XmlNodeList eventL = item.ChildNodes;
246 foreach (XmlNode evt in eventL)
247 {
248 switch (evt.Name)
249 {
250 case "Params":
251 XmlNodeList prms = evt.ChildNodes;
252 foreach (XmlNode pm in prms)
253 parms.Add(ReadTypedValue(pm));
254
255 break;
256 case "Detected":
257 XmlNodeList detL = evt.ChildNodes;
258 foreach (XmlNode det in detL)
259 {
260 string vect =
261 det.Attributes.GetNamedItem(
262 "pos").Value;
263 LSL_Types.Vector3 v =
264 new LSL_Types.Vector3(vect);
265
266 int d_linkNum=0;
267 LLUUID d_group = LLUUID.Zero;
268 string d_name = String.Empty;
269 LLUUID d_owner = LLUUID.Zero;
270 LSL_Types.Vector3 d_position =
271 new LSL_Types.Vector3();
272 LSL_Types.Quaternion d_rotation =
273 new LSL_Types.Quaternion();
274 int d_type = 0;
275 LSL_Types.Vector3 d_velocity =
276 new LSL_Types.Vector3();
277
278 try
279 {
280 string tmp;
281
282 tmp = det.Attributes.GetNamedItem(
283 "linkNum").Value;
284 int.TryParse(tmp, out d_linkNum);
285
286 tmp = det.Attributes.GetNamedItem(
287 "group").Value;
288 LLUUID.TryParse(tmp, out d_group);
289
290 d_name = det.Attributes.GetNamedItem(
291 "name").Value;
292
293 tmp = det.Attributes.GetNamedItem(
294 "owner").Value;
295 LLUUID.TryParse(tmp, out d_owner);
296
297 tmp = det.Attributes.GetNamedItem(
298 "position").Value;
299 d_position =
300 new LSL_Types.Vector3(tmp);
301
302 tmp = det.Attributes.GetNamedItem(
303 "rotation").Value;
304 d_rotation =
305 new LSL_Types.Quaternion(tmp);
306
307 tmp = det.Attributes.GetNamedItem(
308 "type").Value;
309 int.TryParse(tmp, out d_type);
310
311 tmp = det.Attributes.GetNamedItem(
312 "velocity").Value;
313 d_velocity =
314 new LSL_Types.Vector3(tmp);
315
316 }
317 catch (Exception) // Old version XML
318 {
319 }
320
321 LLUUID uuid = new LLUUID();
322 LLUUID.TryParse(det.InnerText,
323 out uuid);
324
325 DetectParams d = new DetectParams();
326 d.Key = uuid;
327 d.OffsetPos = v;
328 d.LinkNum = d_linkNum;
329 d.Group = d_group;
330 d.Name = d_name;
331 d.Owner = d_owner;
332 d.Position = d_position;
333 d.Rotation = d_rotation;
334 d.Type = d_type;
335 d.Velocity = d_velocity;
336
337 detected.Add(d);
338 }
339 break;
340 }
341 }
342 EventParams ep = new EventParams(
343 eventName, parms.ToArray(),
344 detected.ToArray());
345 instance.EventQueue.Enqueue(ep);
346 }
347 break;
348 case "Plugins":
349 instance.PluginData = ReadList(part).Data;
350 break;
351 }
352 }
353 }
354 }
355
356 private static void DumpList(XmlDocument doc, XmlNode parent,
357 LSL_Types.list l)
358 {
359 foreach (Object o in l.Data)
360 WriteTypedValue(doc, parent, "ListItem", "", o);
361 }
362
363 private static LSL_Types.list ReadList(XmlNode parent)
364 {
365 List<Object> olist = new List<Object>();
366
367 XmlNodeList itemL = parent.ChildNodes;
368 foreach (XmlNode item in itemL)
369 olist.Add(ReadTypedValue(item));
370
371 return new LSL_Types.list(olist.ToArray());
372 }
373
374 private static void WriteTypedValue(XmlDocument doc, XmlNode parent,
375 string tag, string name, object value)
376 {
377 Type t=value.GetType();
378 XmlAttribute typ = doc.CreateAttribute("", "type", "");
379 XmlNode n = doc.CreateElement("", tag, "");
380
381 if (value is LSL_Types.list)
382 {
383 typ.Value = "list";
384 n.Attributes.Append(typ);
385
386 DumpList(doc, n, (LSL_Types.list) value);
387
388 if (name != String.Empty)
389 {
390 XmlAttribute nam = doc.CreateAttribute("", "name", "");
391 nam.Value = name;
392 n.Attributes.Append(nam);
393 }
394
395 parent.AppendChild(n);
396 return;
397 }
398
399 n.AppendChild(doc.CreateTextNode(value.ToString()));
400
401 typ.Value = t.ToString();
402 n.Attributes.Append(typ);
403 if (name != String.Empty)
404 {
405 XmlAttribute nam = doc.CreateAttribute("", "name", "");
406 nam.Value = name;
407 n.Attributes.Append(nam);
408 }
409
410 parent.AppendChild(n);
411 }
412
413 private static object ReadTypedValue(XmlNode tag, out string name)
414 {
415 name = tag.Attributes.GetNamedItem("name").Value;
416
417 return ReadTypedValue(tag);
418 }
419
420 private static object ReadTypedValue(XmlNode tag)
421 {
422 Object varValue;
423 string assembly;
424
425 string itemType = tag.Attributes.GetNamedItem("type").Value;
426
427 if (itemType == "list")
428 return ReadList(tag);
429
430 if (itemType == "libsecondlife.LLUUID")
431 {
432 LLUUID val = new LLUUID();
433 LLUUID.TryParse(tag.InnerText, out val);
434
435 return val;
436 }
437
438 Type itemT = Type.GetType(itemType);
439 if (itemT == null)
440 {
441 Object[] args =
442 new Object[] { tag.InnerText };
443
444 assembly = itemType+", OpenSim.Region.ScriptEngine.Shared";
445 itemT = Type.GetType(assembly);
446 if (itemT == null)
447 return null;
448
449 varValue = Activator.CreateInstance(itemT, args);
450
451 if (varValue == null)
452 return null;
453 }
454 else
455 {
456 varValue = Convert.ChangeType(tag.InnerText, itemT);
457 }
458 return varValue;
459 }
460 }
461}