aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs703
1 files changed, 0 insertions, 703 deletions
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
deleted file mode 100644
index 6ac209e..0000000
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
+++ /dev/null
@@ -1,703 +0,0 @@
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 OpenSimulator 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.Reflection;
30using System.Globalization;
31using System.Runtime.Remoting;
32using System.Runtime.Remoting.Lifetime;
33using log4net;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.Interfaces;
38using OpenSim.Region.ScriptEngine.Shared;
39using OpenSim.Region.ScriptEngine.Shared.Api;
40using System.Collections.Generic;
41using System.IO;
42using System.Runtime.Serialization.Formatters.Binary;
43using System.Threading;
44using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
45using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
46using OpenSim.Region.ScriptEngine.Shared.CodeTools;
47
48namespace OpenSim.Region.ScriptEngine.DotNetEngine
49{
50 public class InstanceData
51 {
52 public IScript Script;
53 public string State;
54 public bool Running;
55 public bool Disabled;
56 public string Source;
57 public int StartParam;
58 public AppDomain AppDomain;
59 public Dictionary<string, IScriptApi> Apis;
60 public Dictionary<KeyValuePair<int,int>, KeyValuePair<int,int>>
61 LineMap;
62// public ISponsor ScriptSponsor;
63 }
64
65 public class ScriptManager
66 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 #region Declares
70
71 private Thread scriptLoadUnloadThread;
72 private static Thread staticScriptLoadUnloadThread = null;
73 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
74 private static bool PrivateThread;
75 private int LoadUnloadMaxQueueSize;
76 private Object scriptLock = new Object();
77 private bool m_started = false;
78 private Dictionary<InstanceData, DetectParams[]> detparms =
79 new Dictionary<InstanceData, DetectParams[]>();
80
81 // Load/Unload structure
82 private struct LUStruct
83 {
84 public uint localID;
85 public UUID itemID;
86 public string script;
87 public LUType Action;
88 public int startParam;
89 public bool postOnRez;
90 }
91
92 private enum LUType
93 {
94 Unknown = 0,
95 Load = 1,
96 Unload = 2
97 }
98
99 public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
100 new Dictionary<uint, Dictionary<UUID, InstanceData>>();
101
102 private Compiler LSLCompiler;
103
104 public Scene World
105 {
106 get { return m_scriptEngine.World; }
107 }
108
109 #endregion
110
111 public void Initialize()
112 {
113 // Create our compiler
114 LSLCompiler = new Compiler(m_scriptEngine);
115 }
116
117 public void _StartScript(uint localID, UUID itemID, string Script,
118 int startParam, bool postOnRez)
119 {
120 m_log.DebugFormat(
121 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}",
122 m_scriptEngine.ScriptEngineName, localID, itemID);
123
124 // We will initialize and start the script.
125 // It will be up to the script itself to hook up the correct events.
126 string CompiledScriptFile = String.Empty;
127
128 SceneObjectPart m_host = World.GetSceneObjectPart(localID);
129
130 if (null == m_host)
131 {
132 m_log.ErrorFormat(
133 "[{0}]: Could not find scene object part corresponding "+
134 "to localID {1} to start script",
135 m_scriptEngine.ScriptEngineName, localID);
136
137 return;
138 }
139
140 UUID assetID = UUID.Zero;
141 TaskInventoryItem taskInventoryItem = new TaskInventoryItem();
142 if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
143 assetID = taskInventoryItem.AssetID;
144
145 ScenePresence presence =
146 World.GetScenePresence(taskInventoryItem.OwnerID);
147
148 CultureInfo USCulture = new CultureInfo("en-US");
149 Thread.CurrentThread.CurrentCulture = USCulture;
150
151 try
152 {
153 // Compile (We assume LSL)
154 CompiledScriptFile =
155 (string)LSLCompiler.PerformScriptCompile(Script,
156 assetID.ToString(), taskInventoryItem.OwnerID);
157
158 if (presence != null && (!postOnRez))
159 presence.ControllingClient.SendAgentAlertMessage(
160 "Compile successful", false);
161
162 m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
163 assetID, CompiledScriptFile);
164
165 InstanceData id = new InstanceData();
166
167 IScript CompiledScript;
168 CompiledScript =
169 m_scriptEngine.m_AppDomainManager.LoadScript(
170 CompiledScriptFile, out id.AppDomain);
171 //Register the sponsor
172// ISponsor scriptSponsor = new ScriptSponsor();
173// ILease lease = (ILease)RemotingServices.GetLifetimeService(CompiledScript as MarshalByRefObject);
174// lease.Register(scriptSponsor);
175// id.ScriptSponsor = scriptSponsor;
176
177 id.LineMap = LSLCompiler.LineMap();
178 id.Script = CompiledScript;
179 id.Source = Script;
180 id.StartParam = startParam;
181 id.State = "default";
182 id.Running = true;
183 id.Disabled = false;
184
185 // Add it to our script memstruct
186 m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, id);
187
188 id.Apis = new Dictionary<string, IScriptApi>();
189
190 ApiManager am = new ApiManager();
191
192 foreach (string api in am.GetApis())
193 {
194 id.Apis[api] = am.CreateApi(api);
195 id.Apis[api].Initialize(m_scriptEngine, m_host,
196 localID, itemID);
197 }
198
199 foreach (KeyValuePair<string,IScriptApi> kv in id.Apis)
200 {
201 CompiledScript.InitApi(kv.Key, kv.Value);
202 }
203
204 // Fire the first start-event
205 int eventFlags =
206 m_scriptEngine.m_ScriptManager.GetStateEventFlags(
207 localID, itemID);
208
209 m_host.SetScriptEvents(itemID, eventFlags);
210
211 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
212 localID, itemID, "state_entry", new DetectParams[0],
213 new object[] { });
214
215 if (postOnRez)
216 {
217 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
218 localID, itemID, "on_rez", new DetectParams[0],
219 new object[] { new LSL_Types.LSLInteger(startParam) });
220 }
221
222 string[] warnings = LSLCompiler.GetWarnings();
223
224 if (warnings != null && warnings.Length != 0)
225 {
226 if (presence != null && (!postOnRez))
227 presence.ControllingClient.SendAgentAlertMessage(
228 "Script saved with warnings, check debug window!",
229 false);
230
231 foreach (string warning in warnings)
232 {
233 try
234 {
235 // DISPLAY WARNING INWORLD
236 string text = "Warning:\n" + warning;
237 if (text.Length > 1100)
238 text = text.Substring(0, 1099);
239
240 World.SimChat(Utils.StringToBytes(text),
241 ChatTypeEnum.DebugChannel, 2147483647,
242 m_host.AbsolutePosition, m_host.Name, m_host.UUID,
243 false);
244 }
245 catch (Exception e2) // LEGIT: User Scripting
246 {
247 m_log.Error("[" +
248 m_scriptEngine.ScriptEngineName +
249 "]: Error displaying warning in-world: " +
250 e2.ToString());
251 m_log.Error("[" +
252 m_scriptEngine.ScriptEngineName + "]: " +
253 "Warning:\r\n" +
254 warning);
255 }
256 }
257 }
258 }
259 catch (Exception e) // LEGIT: User Scripting
260 {
261 if (presence != null && (!postOnRez))
262 presence.ControllingClient.SendAgentAlertMessage(
263 "Script saved with errors, check debug window!",
264 false);
265 try
266 {
267 // DISPLAY ERROR INWORLD
268 string text = "Error compiling script:\n" +
269 e.Message.ToString();
270 if (text.Length > 1100)
271 text = text.Substring(0, 1099);
272
273 World.SimChat(Utils.StringToBytes(text),
274 ChatTypeEnum.DebugChannel, 2147483647,
275 m_host.AbsolutePosition, m_host.Name, m_host.UUID,
276 false);
277 }
278 catch (Exception e2) // LEGIT: User Scripting
279 {
280 m_log.Error("[" +
281 m_scriptEngine.ScriptEngineName +
282 "]: Error displaying error in-world: " +
283 e2.ToString());
284 m_log.Error("[" +
285 m_scriptEngine.ScriptEngineName + "]: " +
286 "Errormessage: Error compiling script:\r\n" +
287 e2.Message.ToString());
288 }
289 }
290 }
291
292 public void _StopScript(uint localID, UUID itemID)
293 {
294 InstanceData id = GetScript(localID, itemID);
295 if (id == null)
296 return;
297
298 m_log.DebugFormat("[{0}]: Unloading script",
299 m_scriptEngine.ScriptEngineName);
300
301 // Stop long command on script
302 AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID);
303
304 try
305 {
306 // Get AppDomain
307 // Tell script not to accept new requests
308 id.Running = false;
309 id.Disabled = true;
310 AppDomain ad = id.AppDomain;
311
312 // Remove from internal structure
313 RemoveScript(localID, itemID);
314
315 // Tell AppDomain that we have stopped script
316 m_scriptEngine.m_AppDomainManager.StopScript(ad);
317 }
318 catch (Exception e) // LEGIT: User Scripting
319 {
320 m_log.Error("[" +
321 m_scriptEngine.ScriptEngineName +
322 "]: Exception stopping script localID: " +
323 localID + " LLUID: " + itemID.ToString() +
324 ": " + e.ToString());
325 }
326 }
327
328 public void ReadConfig()
329 {
330 // TODO: Requires sharing of all ScriptManagers to single thread
331 PrivateThread = true;
332 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt(
333 "LoadUnloadMaxQueueSize", 100);
334 }
335
336 #region Object init/shutdown
337
338 public ScriptEngine m_scriptEngine;
339
340 public ScriptManager(ScriptEngine scriptEngine)
341 {
342 m_scriptEngine = scriptEngine;
343 }
344
345 public void Setup()
346 {
347 ReadConfig();
348 Initialize();
349 }
350
351 public void Start()
352 {
353 m_started = true;
354
355
356 AppDomain.CurrentDomain.AssemblyResolve +=
357 new ResolveEventHandler(CurrentDomain_AssemblyResolve);
358
359 //
360 // CREATE THREAD
361 // Private or shared
362 //
363 if (PrivateThread)
364 {
365 // Assign one thread per region
366 //scriptLoadUnloadThread = StartScriptLoadUnloadThread();
367 }
368 else
369 {
370 // Shared thread - make sure one exist, then assign it to the private
371 if (staticScriptLoadUnloadThread == null)
372 {
373 //staticScriptLoadUnloadThread =
374 // StartScriptLoadUnloadThread();
375 }
376 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
377 }
378 }
379
380 ~ScriptManager()
381 {
382 // Abort load/unload thread
383 try
384 {
385 if (scriptLoadUnloadThread != null &&
386 scriptLoadUnloadThread.IsAlive == true)
387 {
388 scriptLoadUnloadThread.Abort();
389 //scriptLoadUnloadThread.Join();
390 }
391 }
392 catch
393 {
394 }
395 }
396
397 #endregion
398
399 #region Load / Unload scripts (Thread loop)
400
401 public void DoScriptLoadUnload()
402 {
403 if (!m_started)
404 return;
405
406 lock (LUQueue)
407 {
408 if (LUQueue.Count > 0)
409 {
410 LUStruct item = LUQueue.Dequeue();
411
412 if (item.Action == LUType.Unload)
413 {
414 _StopScript(item.localID, item.itemID);
415 RemoveScript(item.localID, item.itemID);
416 }
417 else if (item.Action == LUType.Load)
418 {
419 m_log.DebugFormat("[{0}]: Loading script",
420 m_scriptEngine.ScriptEngineName);
421 _StartScript(item.localID, item.itemID, item.script,
422 item.startParam, item.postOnRez);
423 }
424 }
425 }
426 }
427
428 #endregion
429
430 #region Helper functions
431
432 private static Assembly CurrentDomain_AssemblyResolve(
433 object sender, ResolveEventArgs args)
434 {
435 return Assembly.GetExecutingAssembly().FullName == args.Name ?
436 Assembly.GetExecutingAssembly() : null;
437 }
438
439 #endregion
440
441 #region Start/Stop/Reset script
442
443 /// <summary>
444 /// Fetches, loads and hooks up a script to an objects events
445 /// </summary>
446 /// <param name="itemID"></param>
447 /// <param name="localID"></param>
448 public void StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
449 {
450 lock (LUQueue)
451 {
452 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
453 {
454 m_log.Error("[" +
455 m_scriptEngine.ScriptEngineName +
456 "]: ERROR: Load/unload queue item count is at " +
457 LUQueue.Count +
458 ". Config variable \"LoadUnloadMaxQueueSize\" "+
459 "is set to " + LoadUnloadMaxQueueSize +
460 ", so ignoring new script.");
461
462 return;
463 }
464
465 LUStruct ls = new LUStruct();
466 ls.localID = localID;
467 ls.itemID = itemID;
468 ls.script = Script;
469 ls.Action = LUType.Load;
470 ls.startParam = startParam;
471 ls.postOnRez = postOnRez;
472 LUQueue.Enqueue(ls);
473 }
474 }
475
476 /// <summary>
477 /// Disables and unloads a script
478 /// </summary>
479 /// <param name="localID"></param>
480 /// <param name="itemID"></param>
481 public void StopScript(uint localID, UUID itemID)
482 {
483 LUStruct ls = new LUStruct();
484 ls.localID = localID;
485 ls.itemID = itemID;
486 ls.Action = LUType.Unload;
487 ls.startParam = 0;
488 ls.postOnRez = false;
489 lock (LUQueue)
490 {
491 LUQueue.Enqueue(ls);
492 }
493 }
494
495 #endregion
496
497 #region Perform event execution in script
498
499 // Execute a LL-event-function in Script
500 internal void ExecuteEvent(uint localID, UUID itemID,
501 string FunctionName, DetectParams[] qParams, object[] args)
502 {
503 int ExeStage=0; // ;^) Ewe Loon, for debuging
504 InstanceData id=null;
505 try // ;^) Ewe Loon,fix
506 { // ;^) Ewe Loon,fix
507 ExeStage = 1; // ;^) Ewe Loon, for debuging
508 id = GetScript(localID, itemID);
509 if (id == null)
510 return;
511 ExeStage = 2; // ;^) Ewe Loon, for debuging
512 if (qParams.Length>0) // ;^) Ewe Loon,fix
513 detparms[id] = qParams;
514 ExeStage = 3; // ;^) Ewe Loon, for debuging
515 if (id.Running)
516 id.Script.ExecuteEvent(id.State, FunctionName, args);
517 ExeStage = 4; // ;^) Ewe Loon, for debuging
518 if (qParams.Length>0) // ;^) Ewe Loon,fix
519 detparms.Remove(id);
520 ExeStage = 5; // ;^) Ewe Loon, for debuging
521 }
522 catch (Exception e) // ;^) Ewe Loon, From here down tis fix
523 {
524 if ((ExeStage == 3)&&(qParams.Length>0))
525 detparms.Remove(id);
526 SceneObjectPart ob = m_scriptEngine.World.GetSceneObjectPart(localID);
527 m_log.InfoFormat("[Script Error] ,{0},{1},@{2},{3},{4},{5}", ob.Name , FunctionName, ExeStage, e.Message, qParams.Length, detparms.Count);
528 if (ExeStage != 2) throw e;
529 }
530 }
531
532 public uint GetLocalID(UUID itemID)
533 {
534 foreach (KeyValuePair<uint, Dictionary<UUID, InstanceData> > k
535 in Scripts)
536 {
537 if (k.Value.ContainsKey(itemID))
538 return k.Key;
539 }
540 return 0;
541 }
542
543 public int GetStateEventFlags(uint localID, UUID itemID)
544 {
545 try
546 {
547 InstanceData id = GetScript(localID, itemID);
548 if (id == null)
549 {
550 return 0;
551 }
552 int evflags = id.Script.GetStateEventFlags(id.State);
553
554 return (int)evflags;
555 }
556 catch (Exception)
557 {
558 }
559
560 return 0;
561 }
562
563 #endregion
564
565 #region Internal functions to keep track of script
566
567 public List<UUID> GetScriptKeys(uint localID)
568 {
569 if (Scripts.ContainsKey(localID) == false)
570 return new List<UUID>();
571
572 Dictionary<UUID, InstanceData> Obj;
573 Scripts.TryGetValue(localID, out Obj);
574
575 return new List<UUID>(Obj.Keys);
576 }
577
578 public InstanceData GetScript(uint localID, UUID itemID)
579 {
580 lock (scriptLock)
581 {
582 InstanceData id = null;
583
584 if (Scripts.ContainsKey(localID) == false)
585 return null;
586
587 Dictionary<UUID, InstanceData> Obj;
588 Scripts.TryGetValue(localID, out Obj);
589 if (Obj==null) return null;
590 if (Obj.ContainsKey(itemID) == false)
591 return null;
592
593 // Get script
594 Obj.TryGetValue(itemID, out id);
595 return id;
596 }
597 }
598
599 public void SetScript(uint localID, UUID itemID, InstanceData id)
600 {
601 lock (scriptLock)
602 {
603 // Create object if it doesn't exist
604 if (Scripts.ContainsKey(localID) == false)
605 {
606 Scripts.Add(localID, new Dictionary<UUID, InstanceData>());
607 }
608
609 // Delete script if it exists
610 Dictionary<UUID, InstanceData> Obj;
611 Scripts.TryGetValue(localID, out Obj);
612 if (Obj.ContainsKey(itemID) == true)
613 Obj.Remove(itemID);
614
615 // Add to object
616 Obj.Add(itemID, id);
617 }
618 }
619
620 public void RemoveScript(uint localID, UUID itemID)
621 {
622 if (localID == 0)
623 localID = GetLocalID(itemID);
624
625 // Don't have that object?
626 if (Scripts.ContainsKey(localID) == false)
627 return;
628
629 // Delete script if it exists
630 Dictionary<UUID, InstanceData> Obj;
631 Scripts.TryGetValue(localID, out Obj);
632 if (Obj.ContainsKey(itemID) == true)
633 Obj.Remove(itemID);
634 }
635
636 #endregion
637
638 public void ResetScript(uint localID, UUID itemID)
639 {
640 InstanceData id = GetScript(localID, itemID);
641 string script = id.Source;
642 StopScript(localID, itemID);
643 SceneObjectPart part = World.GetSceneObjectPart(localID);
644 part.Inventory.GetInventoryItem(itemID).PermsMask = 0;
645 part.Inventory.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
646 StartScript(localID, itemID, script, id.StartParam, false);
647 }
648
649 #region Script serialization/deserialization
650
651 public void GetSerializedScript(uint localID, UUID itemID)
652 {
653 // Serialize the script and return it
654 // Should not be a problem
655 FileStream fs = File.Create("SERIALIZED_SCRIPT_" + itemID);
656 BinaryFormatter b = new BinaryFormatter();
657 b.Serialize(fs, GetScript(localID, itemID));
658 fs.Close();
659 }
660
661 public void PutSerializedScript(uint localID, UUID itemID)
662 {
663 // Deserialize the script and inject it into an AppDomain
664
665 // How to inject into an AppDomain?
666 }
667
668 #endregion
669
670 public DetectParams[] GetDetectParams(InstanceData id)
671 {
672 if (detparms.ContainsKey(id))
673 return detparms[id];
674
675 return null;
676 }
677
678 public int GetStartParameter(UUID itemID)
679 {
680 uint localID = GetLocalID(itemID);
681 InstanceData id = GetScript(localID, itemID);
682
683 if (id == null)
684 return 0;
685
686 return id.StartParam;
687 }
688
689 public IScriptApi GetApi(UUID itemID, string name)
690 {
691 uint localID = GetLocalID(itemID);
692
693 InstanceData id = GetScript(localID, itemID);
694 if (id == null)
695 return null;
696
697 if (id.Apis.ContainsKey(name))
698 return id.Apis[name];
699
700 return null;
701 }
702 }
703}