29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Globalization;
33 using System.Reflection;
34 using System.Runtime.Remoting;
35 using System.Runtime.Remoting.Lifetime;
36 using System.Security.Policy;
38 using System.Threading;
44 using OpenSim.Framework;
45 using OpenSim.Region.CoreModules;
46 using OpenSim.Region.Framework.Scenes;
47 using OpenSim.Region.Framework.Interfaces;
48 using OpenSim.Region.ScriptEngine.Shared;
49 using OpenSim.Region.ScriptEngine.Shared.Api;
50 using OpenSim.Region.ScriptEngine.Shared.Api.Runtime;
51 using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
52 using OpenSim.Region.ScriptEngine.Shared.CodeTools;
53 using OpenSim.Region.ScriptEngine.Interfaces;
55 using System.Diagnostics;
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 public bool StatePersistedHere {
get {
return m_AttachedAvatar == UUID.Zero; } }
75 private bool m_TimerQueued;
76 private DateTime m_EventStart;
77 private bool m_InEvent;
78 private string m_assemblyPath;
79 private string m_dataPath;
80 private string m_CurrentEvent = String.Empty;
81 private bool m_InSelfDelete;
82 private int m_MaxScriptQueue;
83 private bool m_SaveState;
84 private int m_ControlEventsInQueue;
85 private int m_LastControlLevel;
86 private bool m_CollisionInQueue;
87 private bool m_StateChangeInProgress;
90 private double m_minEventDelay;
92 private long m_eventDelayTicks;
93 private long m_nextEventTimeTicks;
94 private bool m_startOnInit =
true;
95 private UUID m_AttachedAvatar;
97 private bool m_postOnRez;
98 private bool m_startedFromSavedState;
99 private UUID m_CurrentStateHash;
100 private UUID m_RegionID;
102 public int DebugLevel {
get; set; }
104 public WaitHandle CoopWaitHandle {
get;
private set; }
105 public Stopwatch ExecutionTimer {
get;
private set; }
107 public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap {
get; set; }
109 private Dictionary<string,IScriptApi> m_Apis =
new Dictionary<string,IScriptApi>();
118 public double MinEventDelay
120 get {
return m_minEventDelay; }
124 m_minEventDelay = value;
126 m_minEventDelay = 0.0;
128 m_eventDelayTicks = (long)(m_minEventDelay * 10000000L);
129 m_nextEventTimeTicks = DateTime.Now.Ticks;
135 get {
return m_running; }
144 private bool m_running;
146 public bool Suspended
148 get {
return m_Suspended; }
155 bool wasSuspended = m_Suspended;
158 if (wasSuspended && !m_Suspended)
163 if (EventQueue.Count > 0 &&
Running && !ShuttingDown)
164 m_CurrentWorkItem = Engine.QueueEventHandler(
this);
170 private bool m_Suspended;
172 public bool ShuttingDown {
get; set; }
176 public bool StayStopped {
get; set; }
180 public UUID AppDomain {
get; set; }
184 public string PrimName {
get;
private set; }
186 public string ScriptName {
get;
private set; }
188 public UUID ItemID {
get;
private set; }
190 public UUID ObjectID {
get {
return Part.UUID; } }
192 public uint LocalID {
get {
return Part.LocalId; } }
194 public UUID RootObjectID {
get {
return Part.ParentGroup.UUID; } }
196 public uint RootLocalID {
get {
return Part.ParentGroup.LocalId; } }
198 public UUID AssetID {
get;
private set; }
200 public Queue EventQueue {
get;
private set; }
202 public long EventsQueued
207 return EventQueue.Count;
211 public long EventsProcessed {
get;
private set; }
213 public int StartParam {
get; set; }
217 public DateTime TimeStarted {
get;
private set; }
221 private static readonly
int MeasurementWindow = 30 * 1000;
223 private bool m_coopTermination;
225 private EventWaitHandle m_coopSleepHandle;
229 m_TimerQueued =
false;
230 m_StateChangeInProgress =
false;
236 int startParam,
bool postOnRez,
240 EventQueue =
new Queue(32);
241 ExecutionTimer =
new Stopwatch();
249 if (ScriptTask != null)
251 ScriptName = ScriptTask.Name;
252 ItemID = ScriptTask.ItemID;
253 AssetID = ScriptTask.AssetID;
256 PrimName = part.ParentGroup.Name;
257 StartParam = startParam;
258 m_MaxScriptQueue = maxScriptQueue;
259 m_postOnRez = postOnRez;
260 m_AttachedAvatar = part.ParentGroup.AttachedAvatar;
261 m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID;
263 m_SaveState = StatePersistedHere;
284 IScript script, EventWaitHandle coopSleepHandle,
string assemblyPath,
285 string dataPath,
StateSource stateSource,
bool coopTermination)
288 m_coopSleepHandle = coopSleepHandle;
289 m_assemblyPath = assemblyPath;
290 m_dataPath = dataPath;
291 m_stateSource = stateSource;
292 m_coopTermination = coopTermination;
294 if (m_coopTermination)
295 CoopWaitHandle = coopSleepHandle;
297 CoopWaitHandle = null;
301 foreach (
string api
in am.GetApis())
303 m_Apis[api] = am.CreateApi(api);
304 m_Apis[api].Initialize(Engine, Part, ScriptTask);
309 foreach (KeyValuePair<string,IScriptApi> kv
in m_Apis)
311 m_Script.InitApi(kv.Key, kv.Value);
316 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(
State));
321 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Error initializing script instance. Exception {6}{7}",
322 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, e.Message, e.StackTrace);
328 string savedState = Path.Combine(m_dataPath, ItemID.ToString() +
".state");
330 if (
File.Exists(savedState))
336 string xml = String.Empty;
340 FileInfo fi =
new FileInfo(savedState);
341 int size = (int)fi.Length;
344 using (FileStream fs = File.Open(savedState,
345 FileMode.Open, FileAccess.Read, FileShare.None))
347 Byte[] data =
new Byte[size];
348 fs.Read(data, 0, size);
350 xml = Encoding.UTF8.GetString(data);
352 ScriptSerializer.Deserialize(xml,
this);
354 AsyncCommandManager.CreateFromData(Engine,
355 LocalID, ItemID, ObjectID,
360 Part.SetScriptEvents(ItemID,
361 (int)m_Script.GetStateEventFlags(
State));
364 m_startOnInit =
false;
374 m_startedFromSavedState =
true;
378 if (!StatePersistedHere)
391 "[SCRIPT INSTANCE]: Not starting script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}. Unable to load script state file {6}. XML is {7}. Exception {8}{9}",
392 ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name, savedState, xml, e.Message, e.StackTrace);
410 if (m_startedFromSavedState)
464 private void ReleaseControls()
472 part.TaskInventory.LockItemsForRead(
true);
475 part.TaskInventory.LockItemsForRead(
false);
478 permsGranter = part.TaskInventory[ItemID].PermsGranter;
479 permsMask = part.TaskInventory[ItemID].PermsMask;
480 part.TaskInventory.LockItemsForRead(
false);
484 ScenePresence presence = Engine.World.GetScenePresence(permsGranter);
485 if (presence != null)
486 presence.UnRegisterControlEventsToScript(LocalID, ItemID);
494 AsyncCommandManager.RemoveScript(Engine, LocalID, ItemID);
499 string savedState = Path.Combine(m_dataPath, ItemID.ToString() +
".state");
507 File.Delete(savedState);
513 "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ",
514 savedState, ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name),
519 public void VarDump(Dictionary<string, object> vars)
537 TimeStarted = DateTime.Now;
543 if (EventQueue.Count > 0)
545 if (m_CurrentWorkItem == null)
546 m_CurrentWorkItem = Engine.QueueEventHandler(
this);
553 public bool Stop(
int timeout,
bool clearEventQueue =
false)
557 "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}",
558 ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks);
571 if (m_CurrentWorkItem == null)
578 if (m_CurrentWorkItem.Cancel())
580 m_CurrentWorkItem = null;
585 workItem = m_CurrentWorkItem;
592 if (!m_coopTermination)
595 if (workItem.Wait(timeout))
602 "[SCRIPT INSTANCE]: Co-operatively stopping script {0} {1} in {2} {3}",
603 ScriptName, ItemID, PrimName, ObjectID);
606 m_coopSleepHandle.Set();
610 if (workItem.Wait(Timeout.Infinite))
614 "[SCRIPT INSTANCE]: Co-operatively stopped script {0} {1} in {2} {3}",
615 ScriptName, ItemID, PrimName, ObjectID);
624 workItem = m_CurrentWorkItem;
627 if (workItem == null)
636 "[SCRIPT INSTANCE]: Aborting unstopped script {0} {1} in prim {2}, localID {3}, timeout was {4} ms",
637 ScriptName, ItemID, PrimName, LocalID, timeout);
644 m_CurrentWorkItem = null;
650 [DebuggerNonUserCode]
661 while (EventQueue.Count > 0)
664 if (tempv.
EventName ==
"timer") lastTimerEv = tempv;
676 if (lastTimerEv != null) EventQueue.Enqueue(lastTimerEv);
680 m_StateChangeInProgress =
true;
704 if (m_eventDelayTicks != 0)
706 if (DateTime.Now.Ticks < m_nextEventTimeTicks)
708 m_nextEventTimeTicks = DateTime.Now.Ticks + m_eventDelayTicks;
714 if (m_StateChangeInProgress && data.
EventName !=
"timer")
717 if (EventQueue.Count >= m_MaxScriptQueue)
724 m_TimerQueued =
true;
735 if (m_LastControlLevel == held && held == 0)
741 if (m_ControlEventsInQueue > 0)
743 if (m_LastControlLevel == held)
747 m_LastControlLevel = held;
748 m_ControlEventsInQueue++;
753 if (m_CollisionInQueue)
758 m_CollisionInQueue =
true;
761 EventQueue.Enqueue(data);
763 if (m_CurrentWorkItem == null)
765 m_CurrentWorkItem = Engine.QueueEventHandler(
this);
788 ExecutionTimer.Restart();
792 return EventProcessorInt();
796 ExecutionTimer.Stop();
797 ExecutionTime.AddSample(ExecutionTimer);
798 Part.ParentGroup.Scene.AddScriptExecutionTime(ExecutionTimer.ElapsedTicks);
803 private object EventProcessorInt()
812 if (EventQueue.Count > 0 && Running && !ShuttingDown)
814 m_CurrentWorkItem = Engine.QueueEventHandler(
this);
818 m_CurrentWorkItem = null;
824 m_TimerQueued =
false;
827 if (m_ControlEventsInQueue > 0)
828 m_ControlEventsInQueue--;
831 m_CollisionInQueue =
false;
836 "[SCRIPT INSTANCE]: Processing event {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
841 Part.ParentGroup.Name,
842 Part.ParentGroup.UUID,
843 Part.AbsolutePosition,
844 Part.ParentGroup.Scene.Name);
846 m_DetectParams = data.DetectParams;
850 State = data.Params[0].ToString();
854 "[SCRIPT INSTANCE]: Changing state to {0} for {1}/{2}({3})/{4}({5}) @ {6}/{7}",
859 Part.ParentGroup.Name,
860 Part.ParentGroup.UUID,
861 Part.AbsolutePosition,
862 Part.ParentGroup.Scene.Name);
863 AsyncCommandManager.StateChange(Engine,
867 m_StateChangeInProgress =
false;
869 Part.SetScriptEvents(ItemID, (int)m_Script.GetStateEventFlags(State));
873 if (Engine.World.PipeEventsForScript(LocalID) ||
874 data.EventName ==
"control")
882 m_CurrentEvent = data.EventName;
883 m_EventStart = DateTime.Now;
888 m_Script.ExecuteEvent(
State, data.EventName, data.Params);
893 m_CurrentEvent = String.Empty;
912 if ((!(e is TargetInvocationException)
916 && !(e is ThreadAbortException))
921 string text = FormatException(e);
923 if (text.Length > 1000)
924 text = text.Substring(0, 1000);
925 Engine.World.SimChat(Utils.StringToBytes(text),
927 Part.AbsolutePosition,
928 Part.Name, Part.UUID,
false);
931 m_log.Debug(string.Format(
932 "[SCRIPT INSTANCE]: Runtime error in script {0} (event {1}), part {2} {3} at {4} in {5} ",
937 Part.AbsolutePosition,
938 Part.ParentGroup.Scene.Name),
945 else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException))
947 m_InSelfDelete =
true;
948 Engine.World.DeleteSceneObject(Part.ParentGroup,
false);
950 else if ((e is TargetInvocationException) && (e.InnerException is ScriptDeleteException))
952 m_InSelfDelete =
true;
953 Part.Inventory.RemoveInventoryItem(ItemID);
955 else if ((e is TargetInvocationException) && (e.InnerException is ScriptCoopStopException))
959 "[SCRIPT INSTANCE]: Script {0}.{1} in event {2}, state {3} stopped co-operatively.",
960 PrimName, ScriptName, data.EventName,
State);
971 if (++EventsProcessed == 1000000)
972 EventsProcessed = 100000;
974 if ((EventsProcessed % 100000) == 0 && DebugLevel > 0)
976 m_log.DebugFormat(
"[SCRIPT INSTANCE]: Script \"{0}\" (Object \"{1}\" {2} @ {3}.{4}, Item ID {5}, Asset {6}) in event {7}: processed {8:n0} script events",
978 Part.ParentGroup.Name, Part.ParentGroup.UUID, Part.ParentGroup.AbsolutePosition, Part.ParentGroup.Scene.Name,
979 ScriptTask.ItemID, ScriptTask.AssetID, data.EventName, EventsProcessed);
982 if (EventQueue.Count > 0 && Running && !ShuttingDown)
984 m_CurrentWorkItem = Engine.QueueEventHandler(
this);
988 m_CurrentWorkItem = null;
992 m_DetectParams = null;
1002 return (DateTime.Now - m_EventStart).Seconds;
1007 if (m_Script == null)
1017 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
1018 part.Inventory.GetInventoryItem(ItemID).PermsGranter =
UUID.Zero;
1022 m_TimerQueued =
false;
1023 m_StateChangeInProgress =
false;
1026 m_Script.ResetVars();
1031 part.SetScriptEvents(ItemID,
1032 (int)m_Script.GetStateEventFlags(
State));
1036 m_SaveState = StatePersistedHere;
1042 [DebuggerNonUserCode]
1050 m_Script.ResetVars();
1052 part.Inventory.GetInventoryItem(ItemID).PermsMask = 0;
1053 part.Inventory.GetInventoryItem(ItemID).PermsGranter =
UUID.Zero;
1054 part.CollisionSound =
UUID.Zero;
1057 m_TimerQueued =
false;
1058 m_StateChangeInProgress =
false;
1060 m_Script.ResetVars();
1061 string oldState =
State;
1065 part.SetScriptEvents(ItemID,
1066 (int)m_Script.GetStateEventFlags(
State));
1068 if (m_CurrentEvent !=
"state_entry" || oldState !=
"default")
1070 m_SaveState = StatePersistedHere;
1079 if (m_Script != null)
1080 return m_Script.GetVars();
1082 return new Dictionary<string, object>();
1085 public void SetVars(Dictionary<string, object> vars)
1090 m_Script.SetVars(vars);
1095 if (m_DetectParams == null)
1097 if (idx < 0 || idx >= m_DetectParams.Length)
1100 return m_DetectParams[idx];
1105 if (m_DetectParams == null)
1107 if (idx < 0 || idx >= m_DetectParams.Length)
1110 return m_DetectParams[idx].Key;
1121 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
1142 string xml = ScriptSerializer.Serialize(
this);
1146 UUID hash = UUID.Parse(Utils.MD5String(xml));
1148 if (hash != m_CurrentStateHash)
1152 using (FileStream fs = File.Create(Path.Combine(m_dataPath, ItemID.ToString() +
".state")))
1154 Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml);
1155 fs.Write(buf, 0, buf.Length);
1166 m_CurrentStateHash = hash;
1169 StayStopped =
false;
1175 if (m_Apis.ContainsKey(name))
1179 return m_Apis[name];
1189 return String.Format(
"{0} {1} on {2}", ScriptName, ItemID, PrimName);
1192 string FormatException(Exception e)
1194 if (e.InnerException == null)
1195 return e.ToString();
1197 string message =
"Runtime error:\n" + e.InnerException.StackTrace;
1198 string[] lines = message.Split(
new char[] {
'\n'});
1200 foreach (
string line
in lines)
1202 if (line.Contains(
"SecondLife.Script"))
1204 int idx = line.IndexOf(
':');
1207 string val = line.Substring(idx+1);
1209 if (
int.TryParse(val, out lineNum))
1211 KeyValuePair<int, int> pos =
1212 Compiler.FindErrorPosition(
1213 lineNum, 0, LineMap);
1215 int scriptLine = pos.Key;
1216 int col = pos.Value;
1217 if (scriptLine == 0)
1221 message = string.Format(
"Runtime error:\n" +
1222 "({0}): {1}", scriptLine - 1,
1223 e.InnerException.Message);
1234 return e.ToString();
1239 return m_assemblyPath;
1256 PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
1258 return ScriptSerializer.Serialize(
this);
1261 public UUID RegionID
1263 get {
return m_RegionID; }
void SetVars(Dictionary< string, object > vars)
void SetState(string state)
Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
XEngineEventWaitHandle(bool initialState, EventResetMode mode)
void VarDump(Dictionary< string, object > vars)
static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID)
Remove a specific script (and all its pending commands)
IScriptApi GetApi(string name)
Dictionary< string, object > GetVars()
DetectParams[] DetectParams
DetectParams GetDetectParams(int idx)
Represents an item in a task inventory
A MetricsCollector for time spans.
override Object InitializeLifetimeService()
void PostEvent(EventParams data)
Post an event to this script instance.
bool Load(IScript script, EventWaitHandle coopSleepHandle, string assemblyPath, string dataPath, StateSource stateSource, bool coopTermination)
Load the script from an assembly into an AppDomain.
Used to signal when the script is stopping in co-operation with the script engine (instead of through...
An interface for a script API module to communicate with the engine it's running under ...
ScriptInstance(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item, int startParam, bool postOnRez, int maxScriptQueue)
TaskInventoryDictionary TaskInventory
const int PERMISSION_TAKE_CONTROLS
void ResetScript(int timeout)
Reset the script.
Xengine event wait handle.
void ApiResetScript()
Reset the script.
Interactive OpenSim region server
Interface for interaction with a particular script instance
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger LSLInteger
UUID GetDetectID(int idx)
object EventProcessor()
Process the next event queued for this script
bool Stop(int timeout, bool clearEventQueue=false)
Stop the script instance.
override string ToString()
Holds all the data required to execute a scripting event.
void DestroyScriptInstance()