aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/ScriptEngine/Common/Executor.cs16
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs17
-rw-r--r--OpenSim/Region/ScriptEngine/Common/IScript.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs22
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs40
-rw-r--r--OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs329
7 files changed, 180 insertions, 250 deletions
diff --git a/OpenSim/Region/ScriptEngine/Common/Executor.cs b/OpenSim/Region/ScriptEngine/Common/Executor.cs
index 56baa66..792004a 100644
--- a/OpenSim/Region/ScriptEngine/Common/Executor.cs
+++ b/OpenSim/Region/ScriptEngine/Common/Executor.cs
@@ -43,22 +43,22 @@ namespace OpenSim.Region.ScriptEngine.Common
43 } 43 }
44 44
45 45
46 protected override scriptEvents DoGetStateEventFlags() 46 protected override scriptEvents DoGetStateEventFlags(string state)
47 { 47 {
48 // Console.WriteLine("Get event flags for " + m_Script.State); 48 // Console.WriteLine("Get event flags for " + state);
49 49
50 // Check to see if we've already computed the flags for this state 50 // Check to see if we've already computed the flags for this state
51 scriptEvents eventFlags = scriptEvents.None; 51 scriptEvents eventFlags = scriptEvents.None;
52 if (m_stateEvents.ContainsKey(m_Script.State)) 52 if (m_stateEvents.ContainsKey(state))
53 { 53 {
54 m_stateEvents.TryGetValue(m_Script.State, out eventFlags); 54 m_stateEvents.TryGetValue(state, out eventFlags);
55 return eventFlags; 55 return eventFlags;
56 } 56 }
57 57
58 // Fill in the events for this state, cache the results in the map 58 // Fill in the events for this state, cache the results in the map
59 foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap) 59 foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap)
60 { 60 {
61 string evname = m_Script.State + "_event_" + kvp.Key; 61 string evname = state + "_event_" + kvp.Key;
62 Type type = m_Script.GetType(); 62 Type type = m_Script.GetType();
63 try 63 try
64 { 64 {
@@ -75,16 +75,16 @@ namespace OpenSim.Region.ScriptEngine.Common
75 } 75 }
76 76
77 // Save the flags we just computed and return the result 77 // Save the flags we just computed and return the result
78 m_stateEvents.Add(m_Script.State, eventFlags); 78 m_stateEvents.Add(state, eventFlags);
79 return (eventFlags); 79 return (eventFlags);
80 } 80 }
81 81
82 protected override void DoExecuteEvent(string FunctionName, object[] args) 82 protected override void DoExecuteEvent(string state, string FunctionName, object[] args)
83 { 83 {
84 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. 84 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
85 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead! 85 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
86 86
87 string EventName = m_Script.State + "_event_" + FunctionName; 87 string EventName = state + "_event_" + FunctionName;
88 88
89//#if DEBUG 89//#if DEBUG
90// Console.WriteLine("ScriptEngine: Script event function name: " + EventName); 90// Console.WriteLine("ScriptEngine: Script event function name: " + EventName);
diff --git a/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs b/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs
index 3b7e88e..eba88f3 100644
--- a/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ExecutorBase.cs
@@ -140,28 +140,23 @@ namespace OpenSim.Region.ScriptEngine.Common
140 /// </summary> 140 /// </summary>
141 /// <param name="FunctionName">Name of function to execute</param> 141 /// <param name="FunctionName">Name of function to execute</param>
142 /// <param name="args">Arguments to pass to function</param> 142 /// <param name="args">Arguments to pass to function</param>
143 public void ExecuteEvent(string FunctionName, object[] args) 143 public void ExecuteEvent(string state, string FunctionName, object[] args)
144 { 144 {
145 if (m_Running == false) 145 DoExecuteEvent(state, FunctionName, args);
146 {
147 // Script is inactive, do not execute!
148 return;
149 }
150 DoExecuteEvent(FunctionName, args);
151 } 146 }
152 147
153 protected abstract void DoExecuteEvent(string FunctionName, object[] args); 148 protected abstract void DoExecuteEvent(string state, string FunctionName, object[] args);
154 149
155 /// <summary> 150 /// <summary>
156 /// Compute the events handled by the current state of the script 151 /// Compute the events handled by the current state of the script
157 /// </summary> 152 /// </summary>
158 /// <returns>state mask</returns> 153 /// <returns>state mask</returns>
159 public scriptEvents GetStateEventFlags() 154 public scriptEvents GetStateEventFlags(string state)
160 { 155 {
161 return DoGetStateEventFlags(); 156 return DoGetStateEventFlags(state);
162 } 157 }
163 158
164 protected abstract scriptEvents DoGetStateEventFlags(); 159 protected abstract scriptEvents DoGetStateEventFlags(string state);
165 160
166 /// <summary> 161 /// <summary>
167 /// Stop script from running. Event execution will be ignored. 162 /// Stop script from running. Event execution will be ignored.
diff --git a/OpenSim/Region/ScriptEngine/Common/IScript.cs b/OpenSim/Region/ScriptEngine/Common/IScript.cs
index d38dc7b..edd8236 100644
--- a/OpenSim/Region/ScriptEngine/Common/IScript.cs
+++ b/OpenSim/Region/ScriptEngine/Common/IScript.cs
@@ -32,10 +32,7 @@ namespace OpenSim.Region.ScriptEngine.Common
32{ 32{
33 public interface IScript 33 public interface IScript
34 { 34 {
35 string State { get; set; }
36 int StartParam { get; set; }
37 ExecutorBase Exec { get; } 35 ExecutorBase Exec { get; }
38 string Source { get; set; }
39 void InitApi(string api, IScriptApi LSL_Functions); 36 void InitApi(string api, IScriptApi LSL_Functions);
40 } 37 }
41} 38}
diff --git a/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs b/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
index dc3ae05..1bcccf1 100644
--- a/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
+++ b/OpenSim/Region/ScriptEngine/Common/ScriptBaseClass.cs
@@ -74,12 +74,6 @@ namespace OpenSim.Region.ScriptEngine.Common
74 74
75 private string m_state = "default"; 75 private string m_state = "default";
76 76
77 public String State
78 {
79 get { return m_state; }
80 set { m_state = value; }
81 }
82
83 public void state(string newState) 77 public void state(string newState)
84 { 78 {
85 m_LSL_Functions.state(newState); 79 m_LSL_Functions.state(newState);
@@ -98,22 +92,6 @@ namespace OpenSim.Region.ScriptEngine.Common
98 92
99 public ILSL_Api m_LSL_Functions; 93 public ILSL_Api m_LSL_Functions;
100 public IOSSL_Api m_OSSL_Functions; 94 public IOSSL_Api m_OSSL_Functions;
101 private string _Source = String.Empty;
102 public string Source
103 {
104 get
105 {
106 return _Source;
107 }
108 set { _Source = value; }
109 }
110
111 private int m_StartParam = 0;
112 public int StartParam
113 {
114 get { return m_StartParam; }
115 set { m_StartParam = value; }
116 }
117 95
118 public ScriptBaseClass() 96 public ScriptBaseClass()
119 { 97 {
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
index 969a05e..e32c342 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/AppDomainManager.cs
@@ -188,7 +188,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
188 } 188 }
189 } 189 }
190 190
191 public IScript LoadScript(string FileName) 191 public IScript LoadScript(string FileName, out AppDomain ad)
192 { 192 {
193 // Find next available AppDomain to put it in 193 // Find next available AppDomain to put it in
194 AppDomainStructure FreeAppDomain = GetFreeAppDomain(); 194 AppDomainStructure FreeAppDomain = GetFreeAppDomain();
@@ -201,6 +201,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
201 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); 201 FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
202 //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt)); 202 //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
203 FreeAppDomain.ScriptsLoaded++; 203 FreeAppDomain.ScriptsLoaded++;
204 ad = FreeAppDomain.CurrentAppDomain;
204 205
205 return mbrt; 206 return mbrt;
206 } 207 }
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs
index 7ec71c2..6a3f388 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptEngine.cs
@@ -198,12 +198,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
198 if (localID == 0) 198 if (localID == 0)
199 return null; 199 return null;
200 200
201 IScript Script = m_ScriptManager.GetScript(localID, itemID); 201 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
202 202
203 if (Script == null) 203 if (id == null)
204 return null; 204 return null;
205 205
206 DetectParams[] det = m_ScriptManager.GetDetectParams(Script); 206 DetectParams[] det = m_ScriptManager.GetDetectParams(id);
207 207
208 if (number < 0 || number >= det.Length) 208 if (number < 0 || number >= det.Length)
209 return null; 209 return null;
@@ -223,12 +223,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
223 if (localID == 0) 223 if (localID == 0)
224 return; 224 return;
225 225
226 IScript Script = m_ScriptManager.GetScript(localID, itemID); 226 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
227 227
228 if (Script == null) 228 if (id == null)
229 return; 229 return;
230 230
231 string currentState = Script.State; 231 string currentState = id.State;
232 232
233 if (currentState != state) 233 if (currentState != state)
234 { 234 {
@@ -239,22 +239,29 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
239 } 239 }
240 catch (AppDomainUnloadedException) 240 catch (AppDomainUnloadedException)
241 { 241 {
242 Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance"); 242 Console.WriteLine("[SCRIPT]: state change called when "+
243 "script was unloaded. Nothing to worry about, "+
244 "but noting the occurance");
243 } 245 }
244 246
245 Script.State = state; 247 id.State = state;
246 248
247 try 249 try
248 { 250 {
249 int eventFlags = m_ScriptManager.GetStateEventFlags(localID, itemID); 251 int eventFlags = m_ScriptManager.GetStateEventFlags(localID,
252 itemID);
253
250 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID); 254 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
251 if (part != null) 255 if (part != null)
252 part.SetScriptEvents(itemID, eventFlags); 256 part.SetScriptEvents(itemID, eventFlags);
257
253 m_EventManager.state_entry(localID); 258 m_EventManager.state_entry(localID);
254 } 259 }
255 catch (AppDomainUnloadedException) 260 catch (AppDomainUnloadedException)
256 { 261 {
257 Console.WriteLine("[SCRIPT]: state change called when script was unloaded. Nothing to worry about, but noting the occurance"); 262 Console.WriteLine("[SCRIPT]: state change called when "+
263 "script was unloaded. Nothing to worry about, but "+
264 "noting the occurance");
258 } 265 }
259 } 266 }
260 } 267 }
@@ -265,11 +272,11 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
265 if (localID == 0) 272 if (localID == 0)
266 return false; 273 return false;
267 274
268 IScript script = m_ScriptManager.GetScript(localID, itemID); 275 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
269 if (script == null) 276 if (id == null)
270 return false; 277 return false;
271 278
272 return script.Exec.Running?true:false; 279 return id.Running;
273 } 280 }
274 281
275 public void SetScriptState(UUID itemID, bool state) 282 public void SetScriptState(UUID itemID, bool state)
@@ -278,11 +285,12 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
278 if (localID == 0) 285 if (localID == 0)
279 return; 286 return;
280 287
281 IScript script = m_ScriptManager.GetScript(localID, itemID); 288 InstanceData id = m_ScriptManager.GetScript(localID, itemID);
282 if (script == null) 289 if (id == null)
283 return; 290 return;
284 291
285 script.Exec.Running = state; 292 if (!id.Disabled)
293 id.Running = state;
286 } 294 }
287 295
288 public void ApiResetScript(UUID itemID) 296 public void ApiResetScript(UUID itemID)
diff --git a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
index 12a8fe4..99f61cd 100644
--- a/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
+++ b/OpenSim/Region/ScriptEngine/DotNetEngine/ScriptManager.cs
@@ -41,6 +41,17 @@ using System.Threading;
41 41
42namespace OpenSim.Region.ScriptEngine.DotNetEngine 42namespace OpenSim.Region.ScriptEngine.DotNetEngine
43{ 43{
44 public class InstanceData
45 {
46 public IScript Script;
47 public string State;
48 public bool Running;
49 public bool Disabled;
50 public string Source;
51 public int StartParam;
52 public AppDomain AppDomain;
53 }
54
44 public class ScriptManager 55 public class ScriptManager
45 { 56 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -49,13 +60,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
49 60
50 private Thread scriptLoadUnloadThread; 61 private Thread scriptLoadUnloadThread;
51 private static Thread staticScriptLoadUnloadThread; 62 private static Thread staticScriptLoadUnloadThread;
52 // private int scriptLoadUnloadThread_IdleSleepms;
53 private Queue<LUStruct> LUQueue = new Queue<LUStruct>(); 63 private Queue<LUStruct> LUQueue = new Queue<LUStruct>();
54 private static bool PrivateThread; 64 private static bool PrivateThread;
55 private int LoadUnloadMaxQueueSize; 65 private int LoadUnloadMaxQueueSize;
56 private Object scriptLock = new Object(); 66 private Object scriptLock = new Object();
57 private bool m_started = false; 67 private bool m_started = false;
58 private Dictionary<IScript, DetectParams[]> detparms = new Dictionary<IScript, DetectParams[]>(); 68 private Dictionary<InstanceData, DetectParams[]> detparms =
69 new Dictionary<InstanceData, DetectParams[]>();
59 70
60 // Load/Unload structure 71 // Load/Unload structure
61 private struct LUStruct 72 private struct LUStruct
@@ -75,15 +86,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
75 Unload = 2 86 Unload = 2
76 } 87 }
77 88
78 // Xantor 20080525: Keep a list of compiled scripts this session for reuse 89 public Dictionary<UUID, String> scriptList =
79 public Dictionary<UUID, String> scriptList = new Dictionary<UUID, string>(); 90 new Dictionary<UUID, string>();
80 91
81 // Object<string, Script<string, script>> 92 public Dictionary<uint, Dictionary<UUID, InstanceData>> Scripts =
82 // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory. 93 new Dictionary<uint, Dictionary<UUID, InstanceData>>();
83 // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
84 public Dictionary<uint, Dictionary<UUID, IScript>> Scripts =
85 new Dictionary<uint, Dictionary<UUID, IScript>>();
86 94
95 private Compiler.LSL.Compiler LSLCompiler;
87 96
88 public Scene World 97 public Scene World
89 { 98 {
@@ -91,7 +100,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
91 } 100 }
92 101
93 #endregion 102 #endregion
94 private Compiler.LSL.Compiler LSLCompiler;
95 103
96 public void Initialize() 104 public void Initialize()
97 { 105 {
@@ -99,21 +107,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
99 LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine); 107 LSLCompiler = new Compiler.LSL.Compiler(m_scriptEngine);
100 } 108 }
101 109
102 // KEEP TRACK OF SCRIPTS <int id, whatever script> 110 public void _StartScript(uint localID, UUID itemID, string Script,
103 //internal Dictionary<uint, Dictionary<UUID, LSL_BaseClass>> Scripts = new Dictionary<uint, Dictionary<UUID, LSL_BaseClass>>(); 111 int startParam, bool postOnRez)
104 // LOAD SCRIPT
105 // UNLOAD SCRIPT
106 // PROVIDE SCRIPT WITH ITS INTERFACE TO OpenSim
107
108
109 public void _StartScript(uint localID, UUID itemID, string Script, int startParam, bool postOnRez)
110 { 112 {
111 m_log.DebugFormat( 113 m_log.DebugFormat(
112 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}", 114 "[{0}]: ScriptManager StartScript: localID: {1}, itemID: {2}",
113 m_scriptEngine.ScriptEngineName, localID, itemID); 115 m_scriptEngine.ScriptEngineName, localID, itemID);
114 116
115 //IScriptHost root = host.GetRoot();
116
117 // We will initialize and start the script. 117 // We will initialize and start the script.
118 // It will be up to the script itself to hook up the correct events. 118 // It will be up to the script itself to hook up the correct events.
119 string CompiledScriptFile = String.Empty; 119 string CompiledScriptFile = String.Empty;
@@ -123,13 +123,13 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
123 if (null == m_host) 123 if (null == m_host)
124 { 124 {
125 m_log.ErrorFormat( 125 m_log.ErrorFormat(
126 "[{0}]: Could not find scene object part corresponding to localID {1} to start script", 126 "[{0}]: Could not find scene object part corresponding "+
127 "to localID {1} to start script",
127 m_scriptEngine.ScriptEngineName, localID); 128 m_scriptEngine.ScriptEngineName, localID);
128 129
129 return; 130 return;
130 } 131 }
131 132
132 // Xantor 20080525: I need assetID here to see if we already compiled this one previously
133 UUID assetID = UUID.Zero; 133 UUID assetID = UUID.Zero;
134 TaskInventoryItem taskInventoryItem = new TaskInventoryItem(); 134 TaskInventoryItem taskInventoryItem = new TaskInventoryItem();
135 if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem)) 135 if (m_host.TaskInventory.TryGetValue(itemID, out taskInventoryItem))
@@ -137,122 +137,135 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
137 137
138 try 138 try
139 { 139 {
140 // Xantor 20080525 see if we already compiled this script this session, stop incessant recompiling on
141 // scriptreset, spawning of objects with embedded scripts etc.
142
143 if (scriptList.TryGetValue(assetID, out CompiledScriptFile)) 140 if (scriptList.TryGetValue(assetID, out CompiledScriptFile))
144 { 141 {
145 m_log.InfoFormat("[SCRIPT]: Found existing compile of assetID {0}: {1}", assetID, CompiledScriptFile); 142 m_log.InfoFormat("[SCRIPT]: Found existing compile of "+
143 "assetID {0}: {1}", assetID, CompiledScriptFile);
146 } 144 }
147 else 145 else
148 { 146 {
149 // Compile (We assume LSL) 147 // Compile (We assume LSL)
150 CompiledScriptFile = LSLCompiler.PerformScriptCompile(Script); 148 CompiledScriptFile =
149 LSLCompiler.PerformScriptCompile(Script);
151 150
152 // Xantor 20080525 Save compiled scriptfile for later use 151 m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}",
153 m_log.InfoFormat("[SCRIPT]: Compiled assetID {0}: {1}", assetID, CompiledScriptFile); 152 assetID, CompiledScriptFile);
154 scriptList.Add(assetID, CompiledScriptFile); 153 scriptList.Add(assetID, CompiledScriptFile);
155 } 154 }
156 155
157//#if DEBUG 156 InstanceData id = new InstanceData();
158 //long before;
159 //before = GC.GetTotalMemory(true); // This force a garbage collect that freezes some windows plateforms
160//#endif
161 157
162 IScript CompiledScript; 158 IScript CompiledScript;
163 CompiledScript = m_scriptEngine.m_AppDomainManager.LoadScript(CompiledScriptFile); 159 CompiledScript =
164 160 m_scriptEngine.m_AppDomainManager.LoadScript(
165//#if DEBUG 161 CompiledScriptFile, out id.AppDomain);
166 //m_scriptEngine.Log.DebugFormat("[" + m_scriptEngine.ScriptEngineName + "]: Script " + itemID + " occupies {0} bytes", GC.GetTotalMemory(true) - before);
167//#endif
168 162
169 CompiledScript.Source = Script; 163 id.Script = CompiledScript;
170 CompiledScript.StartParam = startParam; 164 id.Source = Script;
165 id.StartParam = startParam;
166 id.State = "default";
167 id.Running = true;
168 id.Disabled = false;
171 169
172 // Add it to our script memstruct 170 // Add it to our script memstruct
173 m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, CompiledScript); 171 m_scriptEngine.m_ScriptManager.SetScript(localID, itemID, id);
174
175 // We need to give (untrusted) assembly a private instance of BuiltIns
176 // this private copy will contain Read-Only FullitemID so that it can bring that on to the server whenever needed.
177
178 172
179// OSSL_BuilIn_Commands LSLB = new OSSL_BuilIn_Commands(m_scriptEngine, m_host, localID, itemID);
180 LSL_Api LSL = new LSL_Api(); 173 LSL_Api LSL = new LSL_Api();
181 OSSL_Api OSSL = new OSSL_Api(); 174 OSSL_Api OSSL = new OSSL_Api();
182 175
183 LSL.Initialize(m_scriptEngine, m_host, localID, itemID); 176 LSL.Initialize(m_scriptEngine, m_host, localID, itemID);
184 OSSL.Initialize(m_scriptEngine, m_host, localID, itemID); 177 OSSL.Initialize(m_scriptEngine, m_host, localID, itemID);
185 178
186 // Start the script - giving it BuiltIns 179 // Start the script - giving it the APIs
187 CompiledScript.InitApi("LSL", LSL); 180 CompiledScript.InitApi("LSL", LSL);
188 CompiledScript.InitApi("OSSL", OSSL); 181 CompiledScript.InitApi("OSSL", OSSL);
189 182
190 // Fire the first start-event 183 // Fire the first start-event
191 int eventFlags = m_scriptEngine.m_ScriptManager.GetStateEventFlags(localID, itemID); 184 int eventFlags =
185 m_scriptEngine.m_ScriptManager.GetStateEventFlags(
186 localID, itemID);
187
192 m_host.SetScriptEvents(itemID, eventFlags); 188 m_host.SetScriptEvents(itemID, eventFlags);
193 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_entry", new DetectParams[0], new object[] { }); 189
190 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
191 localID, itemID, "state_entry", new DetectParams[0],
192 new object[] { });
193
194 if (postOnRez) 194 if (postOnRez)
195 { 195 {
196 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "on_rez", new DetectParams[0], new object[] { new LSL_Types.LSLInteger(startParam) }); 196 m_scriptEngine.m_EventQueueManager.AddToScriptQueue(
197 localID, itemID, "on_rez", new DetectParams[0],
198 new object[] { new LSL_Types.LSLInteger(startParam) });
197 } 199 }
198 } 200 }
199 catch (Exception e) // LEGIT: User Scripting 201 catch (Exception e) // LEGIT: User Scripting
200 { 202 {
201 //m_scriptEngine.Log.Error("[ScriptEngine]: Error compiling script: " + e.ToString());
202 try 203 try
203 { 204 {
204 // DISPLAY ERROR INWORLD 205 // DISPLAY ERROR INWORLD
205 string text = "Error compiling script:\r\n" + e.Message.ToString(); 206 string text = "Error compiling script:\r\n" +
206 if (text.Length > 1500) 207 e.Message.ToString();
207 text = text.Substring(0, 1499); // 0-1499 is 1500 characters 208 if (text.Length > 1100)
208 World.SimChat(Utils.StringToBytes(text), ChatTypeEnum.DebugChannel, 2147483647, 209 text = text.Substring(0, 1099);
209 m_host.AbsolutePosition, m_host.Name, m_host.UUID, false); 210
211 World.SimChat(Utils.StringToBytes(text),
212 ChatTypeEnum.DebugChannel, 2147483647,
213 m_host.AbsolutePosition, m_host.Name, m_host.UUID,
214 false);
210 } 215 }
211 catch (Exception e2) // LEGIT: User Scripting 216 catch (Exception e2) // LEGIT: User Scripting
212 { 217 {
213 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Error displaying error in-world: " + e2.ToString()); 218 m_scriptEngine.Log.Error("[" +
214 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " + 219 m_scriptEngine.ScriptEngineName +
215 "Errormessage: Error compiling script:\r\n" + e.Message.ToString()); 220 "]: Error displaying error in-world: " +
221 e2.ToString());
222 m_scriptEngine.Log.Error("[" +
223 m_scriptEngine.ScriptEngineName + "]: " +
224 "Errormessage: Error compiling script:\r\n" +
225 e2.Message.ToString());
216 } 226 }
217 } 227 }
218 } 228 }
219 229
220 public void _StopScript(uint localID, UUID itemID) 230 public void _StopScript(uint localID, UUID itemID)
221 { 231 {
222 IScript LSLBC = GetScript(localID, itemID); 232 InstanceData id = GetScript(localID, itemID);
223 if (LSLBC == null) 233 if (id == null)
224 return; 234 return;
225 235
226 // Stop long command on script 236 // Stop long command on script
227 AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID); 237 AsyncCommandManager.RemoveScript(m_scriptEngine, localID, itemID);
228 238
229 // TEMP: First serialize it
230 //GetSerializedScript(localID, itemID);
231
232 try 239 try
233 { 240 {
234 // Get AppDomain 241 // Get AppDomain
235 AppDomain ad = LSLBC.Exec.GetAppDomain();
236 // Tell script not to accept new requests 242 // Tell script not to accept new requests
237 m_scriptEngine.m_ScriptManager.GetScript(localID, itemID).Exec.StopScript(); 243 id.Running = false;
244 id.Disabled = true;
245 AppDomain ad = id.AppDomain;
246
238 // Remove from internal structure 247 // Remove from internal structure
239 m_scriptEngine.m_ScriptManager.RemoveScript(localID, itemID); 248 RemoveScript(localID, itemID);
249
240 // Tell AppDomain that we have stopped script 250 // Tell AppDomain that we have stopped script
241 m_scriptEngine.m_AppDomainManager.StopScript(ad); 251 m_scriptEngine.m_AppDomainManager.StopScript(ad);
242 } 252 }
243 catch (Exception e) // LEGIT: User Scripting 253 catch (Exception e) // LEGIT: User Scripting
244 { 254 {
245 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception stopping script localID: " + localID + " LLUID: " + itemID.ToString() + 255 m_scriptEngine.Log.Error("[" +
246 ": " + e.ToString()); 256 m_scriptEngine.ScriptEngineName +
257 "]: Exception stopping script localID: " +
258 localID + " LLUID: " + itemID.ToString() +
259 ": " + e.ToString());
247 } 260 }
248 } 261 }
249 262
250 public void ReadConfig() 263 public void ReadConfig()
251 { 264 {
252 // scriptLoadUnloadThread_IdleSleepms = m_scriptEngine.ScriptConfigSource.GetInt("ScriptLoadUnloadLoopms", 30);
253 // TODO: Requires sharing of all ScriptManagers to single thread 265 // TODO: Requires sharing of all ScriptManagers to single thread
254 PrivateThread = true; // m_scriptEngine.ScriptConfigSource.GetBoolean("PrivateScriptLoadUnloadThread", false); 266 PrivateThread = true;
255 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt("LoadUnloadMaxQueueSize", 100); 267 LoadUnloadMaxQueueSize = m_scriptEngine.ScriptConfigSource.GetInt(
268 "LoadUnloadMaxQueueSize", 100);
256 } 269 }
257 270
258 #region Object init/shutdown 271 #region Object init/shutdown
@@ -263,17 +276,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
263 { 276 {
264 m_scriptEngine = scriptEngine; 277 m_scriptEngine = scriptEngine;
265 } 278 }
279
266 public void Setup() 280 public void Setup()
267 { 281 {
268 ReadConfig(); 282 ReadConfig();
269 Initialize(); 283 Initialize();
270 } 284 }
285
271 public void Start() 286 public void Start()
272 { 287 {
273 m_started = true; 288 m_started = true;
274 289
275 290
276 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 291 AppDomain.CurrentDomain.AssemblyResolve +=
292 new ResolveEventHandler(CurrentDomain_AssemblyResolve);
277 293
278 // 294 //
279 // CREATE THREAD 295 // CREATE THREAD
@@ -289,43 +305,20 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
289 // Shared thread - make sure one exist, then assign it to the private 305 // Shared thread - make sure one exist, then assign it to the private
290 if (staticScriptLoadUnloadThread == null) 306 if (staticScriptLoadUnloadThread == null)
291 { 307 {
292 //staticScriptLoadUnloadThread = StartScriptLoadUnloadThread(); 308 //staticScriptLoadUnloadThread =
309 // StartScriptLoadUnloadThread();
293 } 310 }
294 scriptLoadUnloadThread = staticScriptLoadUnloadThread; 311 scriptLoadUnloadThread = staticScriptLoadUnloadThread;
295 } 312 }
296 } 313 }
297 314
298// TODO: unused
299// private static int privateThreadCount = 0;
300// private Thread StartScriptLoadUnloadThread()
301// {
302// Thread t = new Thread(ScriptLoadUnloadThreadLoop);
303// string name = "ScriptLoadUnloadThread:";
304// if (PrivateThread)
305// {
306// name += "Private:" + privateThreadCount;
307// privateThreadCount++;
308// }
309// else
310// {
311// name += "Shared";
312// }
313// t.Name = name;
314// t.IsBackground = true;
315// t.Priority = ThreadPriority.Normal;
316// t.Start();
317// OpenSim.Framework.ThreadTracker.Add(t);
318// return t;
319// }
320
321 ~ScriptManager() 315 ~ScriptManager()
322 { 316 {
323 // Abort load/unload thread 317 // Abort load/unload thread
324 try 318 try
325 { 319 {
326 //PleaseShutdown = true; 320 if (scriptLoadUnloadThread != null &&
327 //Thread.Sleep(100); 321 scriptLoadUnloadThread.IsAlive == true)
328 if (scriptLoadUnloadThread != null && scriptLoadUnloadThread.IsAlive == true)
329 { 322 {
330 scriptLoadUnloadThread.Abort(); 323 scriptLoadUnloadThread.Abort();
331 //scriptLoadUnloadThread.Join(); 324 //scriptLoadUnloadThread.Join();
@@ -340,28 +333,6 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
340 333
341 #region Load / Unload scripts (Thread loop) 334 #region Load / Unload scripts (Thread loop)
342 335
343// TODO: unused
344// private void ScriptLoadUnloadThreadLoop()
345// {
346// try
347// {
348// while (true)
349// {
350// if (LUQueue.Count == 0)
351// Thread.Sleep(scriptLoadUnloadThread_IdleSleepms);
352// //if (PleaseShutdown)
353// // return;
354// DoScriptLoadUnload();
355// }
356// }
357// catch (ThreadAbortException tae)
358// {
359// string a = tae.ToString();
360// a = String.Empty;
361// // Expected
362// }
363// }
364
365 public void DoScriptLoadUnload() 336 public void DoScriptLoadUnload()
366 { 337 {
367 if (!m_started) 338 if (!m_started)
@@ -371,7 +342,8 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
371 { 342 {
372 if (LUQueue.Count > 0) 343 if (LUQueue.Count > 0)
373 { 344 {
374m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngineName); 345 m_scriptEngine.Log.InfoFormat("[{0}]: Loading script",
346 m_scriptEngine.ScriptEngineName);
375 LUStruct item = LUQueue.Dequeue(); 347 LUStruct item = LUQueue.Dequeue();
376 348
377 if (item.Action == LUType.Unload) 349 if (item.Action == LUType.Unload)
@@ -381,7 +353,8 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
381 } 353 }
382 else if (item.Action == LUType.Load) 354 else if (item.Action == LUType.Load)
383 { 355 {
384 _StartScript(item.localID, item.itemID, item.script, item.startParam, item.postOnRez); 356 _StartScript(item.localID, item.itemID, item.script,
357 item.startParam, item.postOnRez);
385 } 358 }
386 } 359 }
387 } 360 }
@@ -391,20 +364,17 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
391 364
392 #region Helper functions 365 #region Helper functions
393 366
394 private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 367 private static Assembly CurrentDomain_AssemblyResolve(
368 object sender, ResolveEventArgs args)
395 { 369 {
396 //Console.WriteLine("ScriptManager.CurrentDomain_AssemblyResolve: " + args.Name); 370 return Assembly.GetExecutingAssembly().FullName == args.Name ?
397 return Assembly.GetExecutingAssembly().FullName == args.Name ? Assembly.GetExecutingAssembly() : null; 371 Assembly.GetExecutingAssembly() : null;
398 } 372 }
399 373
400 #endregion 374 #endregion
401 375
402
403
404 #region Start/Stop/Reset script 376 #region Start/Stop/Reset script
405 377
406 // private readonly Object startStopLock = new Object();
407
408 /// <summary> 378 /// <summary>
409 /// Fetches, loads and hooks up a script to an objects events 379 /// Fetches, loads and hooks up a script to an objects events
410 /// </summary> 380 /// </summary>
@@ -416,7 +386,13 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
416 { 386 {
417 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started) 387 if ((LUQueue.Count >= LoadUnloadMaxQueueSize) && m_started)
418 { 388 {
419 m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: ERROR: Load/unload queue item count is at " + LUQueue.Count + ". Config variable \"LoadUnloadMaxQueueSize\" is set to " + LoadUnloadMaxQueueSize + ", so ignoring new script."); 389 m_scriptEngine.Log.Error("[" +
390 m_scriptEngine.ScriptEngineName +
391 "]: ERROR: Load/unload queue item count is at " +
392 LUQueue.Count +
393 ". Config variable \"LoadUnloadMaxQueueSize\" "+
394 "is set to " + LoadUnloadMaxQueueSize +
395 ", so ignoring new script.");
420 return; 396 return;
421 } 397 }
422 398
@@ -428,7 +404,6 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Loading script", m_scriptEngine.ScriptEngi
428 ls.startParam = startParam; 404 ls.startParam = startParam;
429 ls.postOnRez = postOnRez; 405 ls.postOnRez = postOnRez;
430 LUQueue.Enqueue(ls); 406 LUQueue.Enqueue(ls);
431m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.ScriptEngineName);
432 } 407 }
433 } 408 }
434 409
@@ -451,10 +426,6 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
451 } 426 }
452 } 427 }
453 428
454 // Create a new instance of the compiler (reuse)
455 //private Compiler.LSL.Compiler LSLCompiler = new Compiler.LSL.Compiler();
456
457
458 #endregion 429 #endregion
459 430
460 #region Perform event execution in script 431 #region Perform event execution in script
@@ -466,33 +437,23 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
466 /// <param name="itemID">Script ID</param> 437 /// <param name="itemID">Script ID</param>
467 /// <param name="FunctionName">Name of function</param> 438 /// <param name="FunctionName">Name of function</param>
468 /// <param name="args">Arguments to pass to function</param> 439 /// <param name="args">Arguments to pass to function</param>
469 internal void ExecuteEvent(uint localID, UUID itemID, string FunctionName, DetectParams[] qParams, object[] args) 440 internal void ExecuteEvent(uint localID, UUID itemID,
441 string FunctionName, DetectParams[] qParams, object[] args)
470 { 442 {
471 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined 443 InstanceData id = GetScript(localID, itemID);
472 ///#if DEBUG 444 if (id == null)
473 /// Console.WriteLine("ScriptEngine: Inside ExecuteEvent for event " + FunctionName);
474 ///#endif
475 // Execute a function in the script
476 //m_scriptEngine.Log.Info("[" + ScriptEngineName + "]: Executing Function localID: " + localID + ", itemID: " + itemID + ", FunctionName: " + FunctionName);
477 //ScriptBaseInterface Script = (ScriptBaseInterface)GetScript(localID, itemID);
478 IScript Script = GetScript(localID, itemID);
479 if (Script == null)
480 {
481 return; 445 return;
482 } 446
483 //cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined 447 detparms[id] = qParams;
484 ///#if DEBUG 448 if (id.Running)
485 /// Console.WriteLine("ScriptEngine: Executing event: " + FunctionName); 449 id.Script.Exec.ExecuteEvent(id.State, FunctionName, args);
486 ///#endif 450 detparms.Remove(id);
487 // Must be done in correct AppDomain, so leaving it up to the script itself
488 detparms[Script] = qParams;
489 Script.Exec.ExecuteEvent(FunctionName, args);
490 detparms.Remove(Script);
491 } 451 }
492 452
493 public uint GetLocalID(UUID itemID) 453 public uint GetLocalID(UUID itemID)
494 { 454 {
495 foreach (KeyValuePair<uint, Dictionary<UUID, IScript> > k in Scripts) 455 foreach (KeyValuePair<uint, Dictionary<UUID, InstanceData> > k
456 in Scripts)
496 { 457 {
497 if (k.Value.ContainsKey(itemID)) 458 if (k.Value.ContainsKey(itemID))
498 return k.Key; 459 return k.Key;
@@ -502,15 +463,15 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
502 463
503 public int GetStateEventFlags(uint localID, UUID itemID) 464 public int GetStateEventFlags(uint localID, UUID itemID)
504 { 465 {
505 // Console.WriteLine("GetStateEventFlags for <" + localID + "," + itemID + ">");
506 try 466 try
507 { 467 {
508 IScript Script = GetScript(localID, itemID); 468 InstanceData id = GetScript(localID, itemID);
509 if (Script == null) 469 if (id == null)
510 { 470 {
511 return 0; 471 return 0;
512 } 472 }
513 ExecutorBase.scriptEvents evflags = Script.Exec.GetStateEventFlags(); 473 ExecutorBase.scriptEvents evflags =
474 id.Script.Exec.GetStateEventFlags(id.State);
514 return (int)evflags; 475 return (int)evflags;
515 } 476 }
516 catch (Exception) 477 catch (Exception)
@@ -530,50 +491,50 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
530 if (Scripts.ContainsKey(localID) == false) 491 if (Scripts.ContainsKey(localID) == false)
531 return new List<UUID>(); 492 return new List<UUID>();
532 493
533 Dictionary<UUID, IScript> Obj; 494 Dictionary<UUID, InstanceData> Obj;
534 Scripts.TryGetValue(localID, out Obj); 495 Scripts.TryGetValue(localID, out Obj);
535 496
536 return new List<UUID>(Obj.Keys); 497 return new List<UUID>(Obj.Keys);
537 } 498 }
538 499
539 public IScript GetScript(uint localID, UUID itemID) 500 public InstanceData GetScript(uint localID, UUID itemID)
540 { 501 {
541 lock (scriptLock) 502 lock (scriptLock)
542 { 503 {
543 IScript Script = null; 504 InstanceData id = null;
544 505
545 if (Scripts.ContainsKey(localID) == false) 506 if (Scripts.ContainsKey(localID) == false)
546 return null; 507 return null;
547 508
548 Dictionary<UUID, IScript> Obj; 509 Dictionary<UUID, InstanceData> Obj;
549 Scripts.TryGetValue(localID, out Obj); 510 Scripts.TryGetValue(localID, out Obj);
550 if (Obj.ContainsKey(itemID) == false) 511 if (Obj.ContainsKey(itemID) == false)
551 return null; 512 return null;
552 513
553 // Get script 514 // Get script
554 Obj.TryGetValue(itemID, out Script); 515 Obj.TryGetValue(itemID, out id);
555 return Script; 516 return id;
556 } 517 }
557 } 518 }
558 519
559 public void SetScript(uint localID, UUID itemID, IScript Script) 520 public void SetScript(uint localID, UUID itemID, InstanceData id)
560 { 521 {
561 lock (scriptLock) 522 lock (scriptLock)
562 { 523 {
563 // Create object if it doesn't exist 524 // Create object if it doesn't exist
564 if (Scripts.ContainsKey(localID) == false) 525 if (Scripts.ContainsKey(localID) == false)
565 { 526 {
566 Scripts.Add(localID, new Dictionary<UUID, IScript>()); 527 Scripts.Add(localID, new Dictionary<UUID, InstanceData>());
567 } 528 }
568 529
569 // Delete script if it exists 530 // Delete script if it exists
570 Dictionary<UUID, IScript> Obj; 531 Dictionary<UUID, InstanceData> Obj;
571 Scripts.TryGetValue(localID, out Obj); 532 Scripts.TryGetValue(localID, out Obj);
572 if (Obj.ContainsKey(itemID) == true) 533 if (Obj.ContainsKey(itemID) == true)
573 Obj.Remove(itemID); 534 Obj.Remove(itemID);
574 535
575 // Add to object 536 // Add to object
576 Obj.Add(itemID, Script); 537 Obj.Add(itemID, id);
577 } 538 }
578 } 539 }
579 540
@@ -587,7 +548,7 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
587 return; 548 return;
588 549
589 // Delete script if it exists 550 // Delete script if it exists
590 Dictionary<UUID, IScript> Obj; 551 Dictionary<UUID, InstanceData> Obj;
591 Scripts.TryGetValue(localID, out Obj); 552 Scripts.TryGetValue(localID, out Obj);
592 if (Obj.ContainsKey(itemID) == true) 553 if (Obj.ContainsKey(itemID) == true)
593 Obj.Remove(itemID); 554 Obj.Remove(itemID);
@@ -598,13 +559,13 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
598 559
599 public void ResetScript(uint localID, UUID itemID) 560 public void ResetScript(uint localID, UUID itemID)
600 { 561 {
601 IScript s = GetScript(localID, itemID); 562 InstanceData id = GetScript(localID, itemID);
602 string script = s.Source; 563 string script = id.Source;
603 StopScript(localID, itemID); 564 StopScript(localID, itemID);
604 SceneObjectPart part = World.GetSceneObjectPart(localID); 565 SceneObjectPart part = World.GetSceneObjectPart(localID);
605 part.GetInventoryItem(itemID).PermsMask = 0; 566 part.GetInventoryItem(itemID).PermsMask = 0;
606 part.GetInventoryItem(itemID).PermsGranter = UUID.Zero; 567 part.GetInventoryItem(itemID).PermsGranter = UUID.Zero;
607 StartScript(localID, itemID, script, s.StartParam, false); 568 StartScript(localID, itemID, script, id.StartParam, false);
608 } 569 }
609 570
610 571
@@ -629,20 +590,10 @@ m_scriptEngine.Log.InfoFormat("[{0}]: Queued script for load", m_scriptEngine.Sc
629 590
630 #endregion 591 #endregion
631 592
632 ///// <summary> 593 public DetectParams[] GetDetectParams(InstanceData id)
633 ///// If set to true then threads and stuff should try to make a graceful exit
634 ///// </summary>
635 //public bool PleaseShutdown
636 //{
637 // get { return _PleaseShutdown; }
638 // set { _PleaseShutdown = value; }
639 //}
640 //private bool _PleaseShutdown = false;
641
642 public DetectParams[] GetDetectParams(IScript script)
643 { 594 {
644 if (detparms.ContainsKey(script)) 595 if (detparms.ContainsKey(id))
645 return detparms[script]; 596 return detparms[id];
646 597
647 return null; 598 return null;
648 } 599 }