diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Instance')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | 660 | ||||
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs | 461 |
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Threading; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Security.Policy; | ||
34 | using System.Reflection; | ||
35 | using System.Globalization; | ||
36 | using System.Xml; | ||
37 | using libsecondlife; | ||
38 | using log4net; | ||
39 | using Nini.Config; | ||
40 | using Amib.Threading; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Region.Environment; | ||
43 | using OpenSim.Region.Environment.Scenes; | ||
44 | using OpenSim.Region.Environment.Interfaces; | ||
45 | using OpenSim.Region.ScriptEngine.Shared; | ||
46 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
47 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
48 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; | ||
49 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
50 | |||
51 | namespace 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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Threading; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Security.Policy; | ||
34 | using System.Reflection; | ||
35 | using System.Globalization; | ||
36 | using System.Xml; | ||
37 | using libsecondlife; | ||
38 | using log4net; | ||
39 | using Nini.Config; | ||
40 | using Amib.Threading; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Region.Environment; | ||
43 | using OpenSim.Region.Environment.Scenes; | ||
44 | using OpenSim.Region.Environment.Interfaces; | ||
45 | using OpenSim.Region.ScriptEngine.Shared; | ||
46 | using OpenSim.Region.ScriptEngine.Shared.Api; | ||
47 | using OpenSim.Region.ScriptEngine.Shared.ScriptBase; | ||
48 | using OpenSim.Region.ScriptEngine.Shared.CodeTools; | ||
49 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
50 | |||
51 | namespace 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 | } | ||