aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine
diff options
context:
space:
mode:
authorUbitUmarov2015-09-01 11:43:07 +0100
committerUbitUmarov2015-09-01 11:43:07 +0100
commitfb78b182520fc9bb0f971afd0322029c70278ea6 (patch)
treeb4e30d383938fdeef8c92d1d1c2f44bb61d329bd /OpenSim/Region/ScriptEngine/XEngine
parentlixo (diff)
parentMantis #7713: fixed bug introduced by 1st MOSES patch. (diff)
downloadopensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.zip
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.gz
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.bz2
opensim-SC-fb78b182520fc9bb0f971afd0322029c70278ea6.tar.xz
Merge remote-tracking branch 'os/master'
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs61
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/EventManager.cs442
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs126
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs129
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs195
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs152
-rwxr-xr-xOpenSim/Region/ScriptEngine/XEngine/XEngine.cs2464
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs69
9 files changed, 3674 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs
new file mode 100644
index 0000000..f4211c8
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Api/Runtime/XEngineScriptBase.cs
@@ -0,0 +1,61 @@
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.Runtime.Remoting;
30using System.Runtime.Remoting.Lifetime;
31using System.Security.Permissions;
32using System.Threading;
33using System.Reflection;
34using System.Collections;
35using System.Collections.Generic;
36using OpenSim.Region.ScriptEngine.Interfaces;
37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
39
40namespace OpenSim.Region.ScriptEngine.XEngine.ScriptBase
41{
42 public class XEngineScriptBase : ScriptBaseClass
43 {
44 /// <summary>
45 /// Used for script sleeps when we are using co-operative script termination.
46 /// </summary>
47 /// <remarks>null if co-operative script termination is not active</remarks>
48 WaitHandle m_coopSleepHandle;
49
50 public XEngineScriptBase(WaitHandle coopSleepHandle) : base()
51 {
52 m_coopSleepHandle = coopSleepHandle;
53 }
54
55 public void opensim_reserved_CheckForCoopTermination()
56 {
57 if (m_coopSleepHandle != null && m_coopSleepHandle.WaitOne(0))
58 throw new ScriptCoopStopException();
59 }
60 }
61} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
new file mode 100644
index 0000000..0ff2da3
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
@@ -0,0 +1,442 @@
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.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.ScriptEngine.Shared;
37using OpenSim.Region.ScriptEngine.Interfaces;
38using log4net;
39
40namespace OpenSim.Region.ScriptEngine.XEngine
41{
42 /// <summary>
43 /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
44 /// </summary>
45 public class EventManager
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private XEngine myScriptEngine;
50
51 public EventManager(XEngine _ScriptEngine)
52 {
53 myScriptEngine = _ScriptEngine;
54
55// m_log.Info("[XEngine] Hooking up to server events");
56 myScriptEngine.World.EventManager.OnAttach += attach;
57 myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
58 myScriptEngine.World.EventManager.OnObjectGrabbing += touch;
59 myScriptEngine.World.EventManager.OnObjectDeGrab += touch_end;
60 myScriptEngine.World.EventManager.OnScriptChangedEvent += changed;
61 myScriptEngine.World.EventManager.OnScriptAtTargetEvent += at_target;
62 myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
63 myScriptEngine.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target;
64 myScriptEngine.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target;
65 myScriptEngine.World.EventManager.OnScriptMovingStartEvent += moving_start;
66 myScriptEngine.World.EventManager.OnScriptMovingEndEvent += moving_end;
67 myScriptEngine.World.EventManager.OnScriptControlEvent += control;
68 myScriptEngine.World.EventManager.OnScriptColliderStart += collision_start;
69 myScriptEngine.World.EventManager.OnScriptColliding += collision;
70 myScriptEngine.World.EventManager.OnScriptCollidingEnd += collision_end;
71 myScriptEngine.World.EventManager.OnScriptLandColliderStart += land_collision_start;
72 myScriptEngine.World.EventManager.OnScriptLandColliding += land_collision;
73 myScriptEngine.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
74 IMoneyModule money = myScriptEngine.World.RequestModuleInterface<IMoneyModule>();
75 if (money != null)
76 {
77 money.OnObjectPaid+=HandleObjectPaid;
78 }
79 }
80
81 /// <summary>
82 /// When an object gets paid by an avatar and generates the paid event,
83 /// this will pipe it to the script engine
84 /// </summary>
85 /// <param name="objectID">Object ID that got paid</param>
86 /// <param name="agentID">Agent Id that did the paying</param>
87 /// <param name="amount">Amount paid</param>
88 private void HandleObjectPaid(UUID objectID, UUID agentID,
89 int amount)
90 {
91 // Since this is an event from a shared module, all scenes will
92 // get it. But only one has the object in question. The others
93 // just ignore it.
94 //
95 SceneObjectPart part =
96 myScriptEngine.World.GetSceneObjectPart(objectID);
97
98 if (part == null)
99 return;
100
101 if ((part.ScriptEvents & scriptEvents.money) == 0)
102 part = part.ParentGroup.RootPart;
103
104 m_log.Debug("Paid: " + objectID + " from " + agentID + ", amount " + amount);
105
106// part = part.ParentGroup.RootPart;
107 money(part.LocalId, agentID, amount);
108 }
109
110 /// <summary>
111 /// Handles piping the proper stuff to The script engine for touching
112 /// Including DetectedParams
113 /// </summary>
114 /// <param name="localID"></param>
115 /// <param name="originalID"></param>
116 /// <param name="offsetPos"></param>
117 /// <param name="remoteClient"></param>
118 /// <param name="surfaceArgs"></param>
119 public void touch_start(uint localID, uint originalID, Vector3 offsetPos,
120 IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
121 {
122 // Add to queue for all scripts in ObjectID object
123 DetectParams[] det = new DetectParams[1];
124 det[0] = new DetectParams();
125 det[0].Key = remoteClient.AgentId;
126 det[0].Populate(myScriptEngine.World);
127
128 if (originalID == 0)
129 {
130 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
131 if (part == null)
132 return;
133
134 det[0].LinkNum = part.LinkNum;
135 }
136 else
137 {
138 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
139 det[0].LinkNum = originalPart.LinkNum;
140 }
141
142 if (surfaceArgs != null)
143 {
144 det[0].SurfaceTouchArgs = surfaceArgs;
145 }
146
147 myScriptEngine.PostObjectEvent(localID, new EventParams(
148 "touch_start", new Object[] { new LSL_Types.LSLInteger(1) },
149 det));
150 }
151
152 public void touch(uint localID, uint originalID, Vector3 offsetPos,
153 IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
154 {
155 // Add to queue for all scripts in ObjectID object
156 DetectParams[] det = new DetectParams[1];
157 det[0] = new DetectParams();
158 det[0].Key = remoteClient.AgentId;
159 det[0].Populate(myScriptEngine.World);
160 det[0].OffsetPos = offsetPos;
161
162 if (originalID == 0)
163 {
164 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
165 if (part == null)
166 return;
167
168 det[0].LinkNum = part.LinkNum;
169 }
170 else
171 {
172 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
173 det[0].LinkNum = originalPart.LinkNum;
174 }
175 if (surfaceArgs != null)
176 {
177 det[0].SurfaceTouchArgs = surfaceArgs;
178 }
179
180 myScriptEngine.PostObjectEvent(localID, new EventParams(
181 "touch", new Object[] { new LSL_Types.LSLInteger(1) },
182 det));
183 }
184
185 public void touch_end(uint localID, uint originalID, IClientAPI remoteClient,
186 SurfaceTouchEventArgs surfaceArgs)
187 {
188 // Add to queue for all scripts in ObjectID object
189 DetectParams[] det = new DetectParams[1];
190 det[0] = new DetectParams();
191 det[0].Key = remoteClient.AgentId;
192 det[0].Populate(myScriptEngine.World);
193
194 if (originalID == 0)
195 {
196 SceneObjectPart part = myScriptEngine.World.GetSceneObjectPart(localID);
197 if (part == null)
198 return;
199
200 det[0].LinkNum = part.LinkNum;
201 }
202 else
203 {
204 SceneObjectPart originalPart = myScriptEngine.World.GetSceneObjectPart(originalID);
205 det[0].LinkNum = originalPart.LinkNum;
206 }
207
208 if (surfaceArgs != null)
209 {
210 det[0].SurfaceTouchArgs = surfaceArgs;
211 }
212
213 myScriptEngine.PostObjectEvent(localID, new EventParams(
214 "touch_end", new Object[] { new LSL_Types.LSLInteger(1) },
215 det));
216 }
217
218 public void changed(uint localID, uint change)
219 {
220 // Add to queue for all scripts in localID, Object pass change.
221 myScriptEngine.PostObjectEvent(localID, new EventParams(
222 "changed",new object[] { new LSL_Types.LSLInteger(change) },
223 new DetectParams[0]));
224 }
225
226 // state_entry: not processed here
227 // state_exit: not processed here
228
229 public void money(uint localID, UUID agentID, int amount)
230 {
231 myScriptEngine.PostObjectEvent(localID, new EventParams(
232 "money", new object[] {
233 new LSL_Types.LSLString(agentID.ToString()),
234 new LSL_Types.LSLInteger(amount) },
235 new DetectParams[0]));
236 }
237
238 public void collision_start(uint localID, ColliderArgs col)
239 {
240 // Add to queue for all scripts in ObjectID object
241 List<DetectParams> det = new List<DetectParams>();
242
243 foreach (DetectedObject detobj in col.Colliders)
244 {
245 DetectParams d = new DetectParams();
246 d.Key =detobj.keyUUID;
247 d.Populate(myScriptEngine.World);
248 det.Add(d);
249 }
250
251 if (det.Count > 0)
252 myScriptEngine.PostObjectEvent(localID, new EventParams(
253 "collision_start",
254 new Object[] { new LSL_Types.LSLInteger(det.Count) },
255 det.ToArray()));
256 }
257
258 public void collision(uint localID, ColliderArgs col)
259 {
260 // Add to queue for all scripts in ObjectID object
261 List<DetectParams> det = new List<DetectParams>();
262
263 foreach (DetectedObject detobj in col.Colliders)
264 {
265 DetectParams d = new DetectParams();
266 d.Key =detobj.keyUUID;
267 d.Populate(myScriptEngine.World);
268 det.Add(d);
269 }
270
271 if (det.Count > 0)
272 myScriptEngine.PostObjectEvent(localID, new EventParams(
273 "collision", new Object[] { new LSL_Types.LSLInteger(det.Count) },
274 det.ToArray()));
275 }
276
277 public void collision_end(uint localID, ColliderArgs col)
278 {
279 // Add to queue for all scripts in ObjectID object
280 List<DetectParams> det = new List<DetectParams>();
281
282 foreach (DetectedObject detobj in col.Colliders)
283 {
284 DetectParams d = new DetectParams();
285 d.Key =detobj.keyUUID;
286 d.Populate(myScriptEngine.World);
287 det.Add(d);
288 }
289
290 if (det.Count > 0)
291 myScriptEngine.PostObjectEvent(localID, new EventParams(
292 "collision_end",
293 new Object[] { new LSL_Types.LSLInteger(det.Count) },
294 det.ToArray()));
295 }
296
297 public void land_collision_start(uint localID, ColliderArgs col)
298 {
299 List<DetectParams> det = new List<DetectParams>();
300
301 foreach (DetectedObject detobj in col.Colliders)
302 {
303 DetectParams d = new DetectParams();
304 d.Position = detobj.posVector;
305 d.Populate(myScriptEngine.World);
306 det.Add(d);
307 myScriptEngine.PostObjectEvent(localID, new EventParams(
308 "land_collision_start",
309 new Object[] { new LSL_Types.Vector3(d.Position) },
310 det.ToArray()));
311 }
312
313 }
314
315 public void land_collision(uint localID, ColliderArgs col)
316 {
317 List<DetectParams> det = new List<DetectParams>();
318
319 foreach (DetectedObject detobj in col.Colliders)
320 {
321 DetectParams d = new DetectParams();
322 d.Position = detobj.posVector;
323 d.Populate(myScriptEngine.World);
324 det.Add(d);
325 myScriptEngine.PostObjectEvent(localID, new EventParams(
326 "land_collision",
327 new Object[] { new LSL_Types.Vector3(d.Position) },
328 det.ToArray()));
329 }
330 }
331
332 public void land_collision_end(uint localID, ColliderArgs col)
333 {
334 List<DetectParams> det = new List<DetectParams>();
335
336 foreach (DetectedObject detobj in col.Colliders)
337 {
338 DetectParams d = new DetectParams();
339 d.Position = detobj.posVector;
340 d.Populate(myScriptEngine.World);
341 det.Add(d);
342 myScriptEngine.PostObjectEvent(localID, new EventParams(
343 "land_collision_end",
344 new Object[] { new LSL_Types.Vector3(d.Position) },
345 det.ToArray()));
346 }
347 }
348
349 // timer: not handled here
350 // listen: not handled here
351
352 public void control(UUID itemID, UUID agentID, uint held, uint change)
353 {
354 myScriptEngine.PostScriptEvent(itemID, new EventParams(
355 "control",new object[] {
356 new LSL_Types.LSLString(agentID.ToString()),
357 new LSL_Types.LSLInteger(held),
358 new LSL_Types.LSLInteger(change)},
359 new DetectParams[0]));
360 }
361
362 public void email(uint localID, UUID itemID, string timeSent,
363 string address, string subject, string message, int numLeft)
364 {
365 myScriptEngine.PostObjectEvent(localID, new EventParams(
366 "email",new object[] {
367 new LSL_Types.LSLString(timeSent),
368 new LSL_Types.LSLString(address),
369 new LSL_Types.LSLString(subject),
370 new LSL_Types.LSLString(message),
371 new LSL_Types.LSLInteger(numLeft)},
372 new DetectParams[0]));
373 }
374
375 public void at_target(uint localID, uint handle, Vector3 targetpos,
376 Vector3 atpos)
377 {
378 myScriptEngine.PostObjectEvent(localID, new EventParams(
379 "at_target", new object[] {
380 new LSL_Types.LSLInteger(handle),
381 new LSL_Types.Vector3(targetpos),
382 new LSL_Types.Vector3(atpos) },
383 new DetectParams[0]));
384 }
385
386 public void not_at_target(uint localID)
387 {
388 myScriptEngine.PostObjectEvent(localID, new EventParams(
389 "not_at_target",new object[0],
390 new DetectParams[0]));
391 }
392
393 public void at_rot_target(uint localID, uint handle, Quaternion targetrot,
394 Quaternion atrot)
395 {
396 myScriptEngine.PostObjectEvent(localID, new EventParams(
397 "at_rot_target", new object[] {
398 new LSL_Types.LSLInteger(handle),
399 new LSL_Types.Quaternion(targetrot),
400 new LSL_Types.Quaternion(atrot) },
401 new DetectParams[0]));
402 }
403
404 public void not_at_rot_target(uint localID)
405 {
406 myScriptEngine.PostObjectEvent(localID, new EventParams(
407 "not_at_rot_target",new object[0],
408 new DetectParams[0]));
409 }
410
411 // run_time_permissions: not handled here
412
413 public void attach(uint localID, UUID itemID, UUID avatar)
414 {
415 myScriptEngine.PostObjectEvent(localID, new EventParams(
416 "attach",new object[] {
417 new LSL_Types.LSLString(avatar.ToString()) },
418 new DetectParams[0]));
419 }
420
421 // dataserver: not handled here
422 // link_message: not handled here
423
424 public void moving_start(uint localID)
425 {
426 myScriptEngine.PostObjectEvent(localID, new EventParams(
427 "moving_start",new object[0],
428 new DetectParams[0]));
429 }
430
431 public void moving_end(uint localID)
432 {
433 myScriptEngine.PostObjectEvent(localID, new EventParams(
434 "moving_end",new object[0],
435 new DetectParams[0]));
436 }
437
438 // object_rez: not handled here
439 // remote_data: not handled here
440 // http_response: not handled here
441 }
442}
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0094af6
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Region.ScriptEngine.XEngine")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim")]
14[assembly: AssemblyCopyright("OpenSimulator developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("1feed7de-3d45-4d3d-80e2-b57566284df5")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.8.2.*")]
34
35[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs
new file mode 100644
index 0000000..efb854d
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/ScriptEngineConsoleCommands.cs
@@ -0,0 +1,126 @@
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.Collections.Generic;
30using OpenSim.Framework;
31using OpenSim.Framework.Console;
32using OpenSim.Region.ScriptEngine.Interfaces;
33using OpenSim.Region.ScriptEngine.Shared.Api;
34using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
35
36namespace OpenSim.Region.ScriptEngine.XEngine
37{
38 public class ScriptEngineConsoleCommands
39 {
40 IScriptEngine m_engine;
41
42 public ScriptEngineConsoleCommands(IScriptEngine engine)
43 {
44 m_engine = engine;
45 }
46
47 public void RegisterCommands()
48 {
49 MainConsole.Instance.Commands.AddCommand(
50 "Scripts", false, "show script sensors", "show script sensors", "Show script sensors information",
51 HandleShowSensors);
52
53 MainConsole.Instance.Commands.AddCommand(
54 "Scripts", false, "show script timers", "show script timers", "Show script sensors information",
55 HandleShowTimers);
56 }
57
58 private bool IsSceneSelected()
59 {
60 return MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_engine.World;
61 }
62
63 private void HandleShowSensors(string module, string[] cmdparams)
64 {
65 if (!IsSceneSelected())
66 return;
67
68 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(m_engine);
69
70 if (sr == null)
71 {
72 MainConsole.Instance.Output("Plugin not yet initialized");
73 return;
74 }
75
76 List<SensorRepeat.SensorInfo> sensorInfo = sr.GetSensorInfo();
77
78 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
79 cdt.AddColumn("Part name", 40);
80 cdt.AddColumn("Script item ID", 36);
81 cdt.AddColumn("Type", 4);
82 cdt.AddColumn("Interval", 8);
83 cdt.AddColumn("Range", 8);
84 cdt.AddColumn("Arc", 8);
85
86 foreach (SensorRepeat.SensorInfo s in sensorInfo)
87 {
88 cdt.AddRow(s.host.Name, s.itemID, s.type, s.interval, s.range, s.arc);
89 }
90
91 MainConsole.Instance.Output(cdt.ToString());
92 MainConsole.Instance.OutputFormat("Total: {0}", sensorInfo.Count);
93 }
94
95 private void HandleShowTimers(string module, string[] cmdparams)
96 {
97 if (!IsSceneSelected())
98 return;
99
100 Timer timerPlugin = AsyncCommandManager.GetTimerPlugin(m_engine);
101
102 if (timerPlugin == null)
103 {
104 MainConsole.Instance.Output("Plugin not yet initialized");
105 return;
106 }
107
108 List<Timer.TimerInfo> timersInfo = timerPlugin.GetTimersInfo();
109
110 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
111 cdt.AddColumn("Part local ID", 13);
112 cdt.AddColumn("Script item ID", 36);
113 cdt.AddColumn("Interval", 10);
114 cdt.AddColumn("Next", 8);
115
116 foreach (Timer.TimerInfo t in timersInfo)
117 {
118 // Convert from 100 ns ticks back to seconds
119 cdt.AddRow(t.localID, t.itemID, (double)t.interval / 10000000, t.next);
120 }
121
122 MainConsole.Instance.Output(cdt.ToString());
123 MainConsole.Instance.OutputFormat("Total: {0}", timersInfo.Count);
124 }
125 }
126} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs
new file mode 100644
index 0000000..878e571
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineBasicTests.cs
@@ -0,0 +1,129 @@
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.Collections.Generic;
30using System.Threading;
31using Nini.Config;
32using NUnit.Framework;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules.Scripting.WorldComm;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Tests.Common;
39
40namespace OpenSim.Region.ScriptEngine.XEngine.Tests
41{
42 /// <summary>
43 /// Basic XEngine tests.
44 /// </summary>
45 [TestFixture]
46 public class XEngineBasicTests : OpenSimTestCase
47 {
48 private TestScene m_scene;
49 private XEngine m_xEngine;
50 private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
51 private OSChatMessage m_osChatMessageReceived;
52
53 [TestFixtureSetUp]
54 public void Init()
55 {
56 //AppDomain.CurrentDomain.SetData("APPBASE", Environment.CurrentDirectory + "/bin");
57// Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
58 m_xEngine = new XEngine();
59
60 IniConfigSource configSource = new IniConfigSource();
61
62 IConfig startupConfig = configSource.AddConfig("Startup");
63 startupConfig.Set("DefaultScriptEngine", "XEngine");
64
65 IConfig xEngineConfig = configSource.AddConfig("XEngine");
66 xEngineConfig.Set("Enabled", "true");
67 xEngineConfig.Set("StartDelay", "0");
68
69 // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
70 // to AssemblyResolver.OnAssemblyResolve fails.
71 xEngineConfig.Set("AppDomainLoading", "false");
72
73 m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource);
74 SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine);
75 m_scene.StartScripts();
76 }
77
78 /// <summary>
79 /// Test compilation and starting of a script.
80 /// </summary>
81 /// <remarks>
82 /// This is a less than ideal regression test since it involves an asynchronous operation (in this case,
83 /// compilation of the script).
84 /// </remarks>
85 [Test]
86 public void TestCompileAndStartScript()
87 {
88 TestHelpers.InMethod();
89 TestHelpers.EnableLogging();
90
91 UUID userId = TestHelpers.ParseTail(0x1);
92// UUID objectId = TestHelpers.ParseTail(0x100);
93// UUID itemId = TestHelpers.ParseTail(0x3);
94 string itemName = "TestStartScript() Item";
95
96 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, "TestStartScriptPart_", 0x100);
97 m_scene.AddNewSceneObject(so, true);
98
99 InventoryItemBase itemTemplate = new InventoryItemBase();
100// itemTemplate.ID = itemId;
101 itemTemplate.Name = itemName;
102 itemTemplate.Folder = so.UUID;
103 itemTemplate.InvType = (int)InventoryType.LSL;
104
105 m_scene.EventManager.OnChatFromWorld += OnChatFromWorld;
106
107 SceneObjectPart partWhereRezzed = m_scene.RezNewScript(userId, itemTemplate);
108
109 m_chatEvent.WaitOne(60000);
110
111 Assert.That(m_osChatMessageReceived, Is.Not.Null, "No chat message received in TestStartScript()");
112 Assert.That(m_osChatMessageReceived.Message, Is.EqualTo("Script running"));
113
114 bool running;
115 TaskInventoryItem scriptItem = partWhereRezzed.Inventory.GetInventoryItem(itemName);
116 Assert.That(
117 SceneObjectPartInventory.TryGetScriptInstanceRunning(m_scene, scriptItem, out running), Is.True);
118 Assert.That(running, Is.True);
119 }
120
121 private void OnChatFromWorld(object sender, OSChatMessage oscm)
122 {
123// Console.WriteLine("Got chat [{0}]", oscm.Message);
124
125 m_osChatMessageReceived = oscm;
126 m_chatEvent.Set();
127 }
128 }
129} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs
new file mode 100644
index 0000000..587695f
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineCrossingTests.cs
@@ -0,0 +1,195 @@
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.Threading;
30using Nini.Config;
31using NUnit.Framework;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Framework.EntityTransfer;
35using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Tests.Common;
39
40namespace OpenSim.Region.ScriptEngine.XEngine.Tests
41{
42 /// <summary>
43 /// XEngine tests connected with crossing scripts between regions.
44 /// </summary>
45 [TestFixture]
46 public class XEngineCrossingTests : OpenSimTestCase
47 {
48 [TestFixtureSetUp]
49 public void FixtureInit()
50 {
51 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
52 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
53 }
54
55 [TestFixtureTearDown]
56 public void TearDown()
57 {
58 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
59 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
60 // tests really shouldn't).
61 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
62 }
63
64 /// <summary>
65 /// Test script state preservation when a script crosses between regions on the same simulator.
66 /// </summary>
67 [Test]
68 public void TestScriptCrossOnSameSimulator()
69 {
70 TestHelpers.InMethod();
71// TestHelpers.EnableLogging();
72
73 UUID userId = TestHelpers.ParseTail(0x1);
74 int sceneObjectIdTail = 0x2;
75
76 EntityTransferModule etmA = new EntityTransferModule();
77 EntityTransferModule etmB = new EntityTransferModule();
78 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
79 XEngine xEngineA = new XEngine();
80 XEngine xEngineB = new XEngine();
81 xEngineA.DebugLevel = 1;
82 xEngineB.DebugLevel = 1;
83
84 IConfigSource configSource = new IniConfigSource();
85
86 IConfig startupConfig = configSource.AddConfig("Startup");
87 startupConfig.Set("DefaultScriptEngine", "XEngine");
88
89 IConfig xEngineConfig = configSource.AddConfig("XEngine");
90 xEngineConfig.Set("Enabled", "true");
91 xEngineConfig.Set("StartDelay", "0");
92
93 // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
94 // to AssemblyResolver.OnAssemblyResolve fails.
95 xEngineConfig.Set("AppDomainLoading", "false");
96
97 IConfig modulesConfig = configSource.AddConfig("Modules");
98 modulesConfig.Set("EntityTransferModule", etmA.Name);
99 modulesConfig.Set("SimulationServices", lscm.Name);
100
101 SceneHelpers sh = new SceneHelpers();
102 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000, configSource);
103 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999, configSource);
104
105 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, configSource, lscm);
106 SceneHelpers.SetupSceneModules(sceneA, configSource, etmA, xEngineA);
107 SceneHelpers.SetupSceneModules(sceneB, configSource, etmB, xEngineB);
108 sceneA.StartScripts();
109 sceneB.StartScripts();
110
111 SceneObjectGroup soSceneA = SceneHelpers.AddSceneObject(sceneA, 1, userId, "so1-", sceneObjectIdTail);
112 soSceneA.AbsolutePosition = new Vector3(128, 10, 20);
113
114 // CREATE SCRIPT TODO
115 InventoryItemBase scriptItemSceneA = new InventoryItemBase();
116 // itemTemplate.ID = itemId;
117 scriptItemSceneA.Name = "script1";
118 scriptItemSceneA.Folder = soSceneA.UUID;
119 scriptItemSceneA.InvType = (int)InventoryType.LSL;
120
121 AutoResetEvent chatEvent = new AutoResetEvent(false);
122 OSChatMessage messageReceived = null;
123 sceneA.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); };
124
125 sceneA.RezNewScript(userId, scriptItemSceneA,
126@"integer c = 0;
127
128default
129{
130 state_entry()
131 {
132 llSay(0, ""Script running"");
133 }
134
135 changed(integer change)
136 {
137 llSay(0, ""Changed"");
138 }
139
140 touch_start(integer n)
141 {
142 c = c + 1;
143 llSay(0, (string)c);
144 }
145}");
146
147 chatEvent.WaitOne(60000);
148
149 Assert.That(messageReceived, Is.Not.Null, "No chat message received.");
150 Assert.That(messageReceived.Message, Is.EqualTo("Script running"));
151
152 {
153 // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
154 DetectParams[] det = new DetectParams[1];
155 det[0] = new DetectParams();
156 det[0].Key = userId;
157 det[0].Populate(sceneA);
158
159 EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
160
161 xEngineA.PostObjectEvent(soSceneA.LocalId, ep);
162 chatEvent.WaitOne(60000);
163
164 Assert.That(messageReceived.Message, Is.EqualTo("1"));
165 }
166
167 sceneB.EventManager.OnChatFromWorld += (s, m) => { messageReceived = m; chatEvent.Set(); };
168
169 // Cross with a negative value
170 soSceneA.AbsolutePosition = new Vector3(128, -10, 20);
171
172 chatEvent.WaitOne(60000);
173 Assert.That(messageReceived.Message, Is.EqualTo("Changed"));
174
175 // TEST sending event to moved prim and output
176 {
177 SceneObjectGroup soSceneB = sceneB.GetSceneObjectGroup(soSceneA.Name);
178 TaskInventoryItem scriptItemSceneB = soSceneB.RootPart.Inventory.GetInventoryItem(scriptItemSceneA.Name);
179
180 // XXX: Should not be doing this so directly. Should call some variant of EventManager.touch() instead.
181 DetectParams[] det = new DetectParams[1];
182 det[0] = new DetectParams();
183 det[0].Key = userId;
184 det[0].Populate(sceneB);
185
186 EventParams ep = new EventParams("touch_start", new Object[] { new LSL_Types.LSLInteger(1) }, det);
187
188 xEngineB.PostObjectEvent(soSceneB.LocalId, ep);
189 chatEvent.WaitOne(60000);
190
191 Assert.That(messageReceived.Message, Is.EqualTo("2"));
192 }
193 }
194 }
195} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
new file mode 100644
index 0000000..2ef4058
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
@@ -0,0 +1,152 @@
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.Collections.Generic;
30using System.IO;
31using System.Linq;
32using System.Threading;
33using Nini.Config;
34using NUnit.Framework;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Region.CoreModules.Avatar.Attachments;
38using OpenSim.Region.CoreModules.Framework.InventoryAccess;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Region.ScriptEngine.XEngine;
41using OpenSim.Services.Interfaces;
42using OpenSim.Tests.Common;
43
44namespace OpenSim.Region.ScriptEngine.Tests
45{
46 [TestFixture]
47 public class XEnginePersistenceTests : OpenSimTestCase
48 {
49 private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
50
51 private void OnChatFromWorld(object sender, OSChatMessage oscm)
52 {
53 // Console.WriteLine("Got chat [{0}]", oscm.Message);
54
55 // m_osChatMessageReceived = oscm;
56 m_chatEvent.Set();
57 }
58
59 private void AddCommonConfig(IConfigSource config, List<object> modules)
60 {
61 config.AddConfig("Modules");
62 config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
63
64 AttachmentsModule attMod = new AttachmentsModule();
65 attMod.DebugLevel = 1;
66 modules.Add(attMod);
67 modules.Add(new BasicInventoryAccessModule());
68 }
69
70 private void AddScriptingConfig(IConfigSource config, XEngine.XEngine xEngine, List<object> modules)
71 {
72 IConfig startupConfig = config.AddConfig("Startup");
73 startupConfig.Set("DefaultScriptEngine", "XEngine");
74
75 IConfig xEngineConfig = config.AddConfig("XEngine");
76 xEngineConfig.Set("Enabled", "true");
77 xEngineConfig.Set("StartDelay", "0");
78
79 // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
80 // to AssemblyResolver.OnAssemblyResolve fails.
81 xEngineConfig.Set("AppDomainLoading", "false");
82
83 modules.Add(xEngine);
84 }
85
86 private Scene CreateScriptingEnabledTestScene(XEngine.XEngine xEngine)
87 {
88 IConfigSource config = new IniConfigSource();
89 List<object> modules = new List<object>();
90
91 AddCommonConfig(config, modules);
92 AddScriptingConfig(config, xEngine, modules);
93
94 Scene scene
95 = new SceneHelpers().SetupScene(
96 "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
97 SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
98
99 scene.StartScripts();
100
101 return scene;
102 }
103
104 [Test]
105 public void TestScriptedAttachmentPersistence()
106 {
107 TestHelpers.InMethod();
108// TestHelpers.EnableLogging();
109
110 XEngine.XEngine xEngine = new XEngine.XEngine();
111 Scene scene = CreateScriptingEnabledTestScene(xEngine);
112 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
113 ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
114
115 SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
116 TaskInventoryHelpers.AddScript(
117 scene.AssetService,
118 so.RootPart,
119 "scriptItem",
120 "default { attach(key id) { if (id != NULL_KEY) { llSay(0, \"Hello World\"); } } }");
121
122 InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
123
124 // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running.
125 // In the future, we need to be able to do this programatically more predicably.
126 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
127
128 SceneObjectGroup rezzedSo
129 = scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
130 TaskInventoryItem rezzedScriptItem = rezzedSo.RootPart.Inventory.GetInventoryItem("scriptItem");
131
132 // Wait for chat to signal rezzed script has been started.
133 m_chatEvent.WaitOne(60000);
134
135 // Force save
136 xEngine.DoBackup(new Object[] { 0 });
137
138// Console.WriteLine("ItemID {0}", rezzedScriptItem.ItemID);
139//
140// foreach (
141// string s in Directory.EnumerateFileSystemEntries(
142// string.Format("ScriptEngines/{0}", scene.RegionInfo.RegionID)))
143// Console.WriteLine(s);
144
145 Assert.IsFalse(
146 File.Exists(
147 string.Format("ScriptEngines/{0}/{1}.state", scene.RegionInfo.RegionID, rezzedScriptItem.ItemID)));
148
149 scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, rezzedSo);
150 }
151 }
152} \ No newline at end of file
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
new file mode 100755
index 0000000..78d4ee9
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -0,0 +1,2464 @@
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.Collections;
30using System.Collections.Generic;
31using System.Globalization;
32using System.IO;
33using System.Linq;
34using System.Reflection;
35using System.Security;
36using System.Security.Policy;
37using System.Text;
38using System.Threading;
39using System.Xml;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42using log4net;
43using Nini.Config;
44using Amib.Threading;
45using Mono.Addins;
46using OpenSim.Framework;
47using OpenSim.Framework.Console;
48using OpenSim.Region.Framework.Scenes;
49using OpenSim.Region.Framework.Interfaces;
50using OpenSim.Region.ScriptEngine.Interfaces;
51using OpenSim.Region.ScriptEngine.Shared;
52using OpenSim.Region.ScriptEngine.Shared.CodeTools;
53using OpenSim.Region.ScriptEngine.Shared.Instance;
54using OpenSim.Region.ScriptEngine.Shared.Api;
55using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
56using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
57using OpenSim.Region.ScriptEngine.XEngine.ScriptBase;
58using Timer = OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
59
60using ScriptCompileQueue = OpenSim.Framework.LocklessQueue<object[]>;
61
62namespace OpenSim.Region.ScriptEngine.XEngine
63{
64 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEngine")]
65 public class XEngine : INonSharedRegionModule, IScriptModule, IScriptEngine
66 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68
69 /// <summary>
70 /// Control the printing of certain debug messages.
71 /// </summary>
72 /// <remarks>
73 /// If DebugLevel >= 1, then we log every time that a script is started.
74 /// </remarks>
75 public int DebugLevel { get; set; }
76
77 /// <summary>
78 /// A parameter to allow us to notify the log if at least one script has a compilation that is not compatible
79 /// with ScriptStopStrategy.
80 /// </summary>
81 public bool HaveNotifiedLogOfScriptStopMistmatch { get; private set; }
82
83 private SmartThreadPool m_ThreadPool;
84 private int m_MaxScriptQueue;
85 private Scene m_Scene;
86 private IConfig m_ScriptConfig = null;
87 private IConfigSource m_ConfigSource = null;
88 private ICompiler m_Compiler;
89 private int m_MinThreads;
90 private int m_MaxThreads;
91
92 /// <summary>
93 /// Amount of time to delay before starting.
94 /// </summary>
95 private int m_StartDelay;
96
97 /// <summary>
98 /// Are we stopping scripts co-operatively by inserting checks in them at C# compile time (true) or aborting
99 /// their threads (false)?
100 /// </summary>
101 private bool m_coopTermination;
102
103 private int m_IdleTimeout;
104 private int m_StackSize;
105 private int m_SleepTime;
106 private int m_SaveTime;
107 private ThreadPriority m_Prio;
108 private bool m_Enabled = false;
109 private bool m_InitialStartup = true;
110 private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
111 private string m_ScriptErrorMessage;
112 private bool m_AppDomainLoading;
113 private Dictionary<UUID,ArrayList> m_ScriptErrors =
114 new Dictionary<UUID,ArrayList>();
115
116 // disable warning: need to keep a reference to XEngine.EventManager
117 // alive to avoid it being garbage collected
118#pragma warning disable 414
119 private EventManager m_EventManager;
120#pragma warning restore 414
121 private IXmlRpcRouter m_XmlRpcRouter;
122 private int m_EventLimit;
123 private bool m_KillTimedOutScripts;
124
125 /// <summary>
126 /// Number of milliseconds we will wait for a script event to complete on script stop before we forcibly abort
127 /// its thread.
128 /// </summary>
129 /// <remarks>
130 /// It appears that if a script thread is aborted whilst it is holding ReaderWriterLockSlim (possibly the write
131 /// lock) then the lock is not properly released. This causes mono 2.6, 2.10 and possibly
132 /// later to crash, sometimes with symptoms such as a leap to 100% script usage and a vm thead dump showing
133 /// all threads waiting on release of ReaderWriterLockSlim write thread which none of the threads listed
134 /// actually hold.
135 ///
136 /// Pausing for event completion reduces the risk of this happening. However, it may be that aborting threads
137 /// is not a mono issue per se but rather a risky activity in itself in an AppDomain that is not immediately
138 /// shutting down.
139 /// </remarks>
140 private int m_WaitForEventCompletionOnScriptStop = 1000;
141
142 private string m_ScriptEnginesPath = null;
143
144 private ExpiringCache<UUID, bool> m_runFlags = new ExpiringCache<UUID, bool>();
145
146 /// <summary>
147 /// Is the entire simulator in the process of shutting down?
148 /// </summary>
149 private bool m_SimulatorShuttingDown;
150
151 private static List<XEngine> m_ScriptEngines =
152 new List<XEngine>();
153
154 // Maps the local id to the script inventory items in it
155
156 private Dictionary<uint, List<UUID> > m_PrimObjects =
157 new Dictionary<uint, List<UUID> >();
158
159 // Maps the UUID above to the script instance
160
161 private Dictionary<UUID, IScriptInstance> m_Scripts =
162 new Dictionary<UUID, IScriptInstance>();
163
164 // Maps the asset ID to the assembly
165
166 private Dictionary<UUID, string> m_Assemblies =
167 new Dictionary<UUID, string>();
168
169 private Dictionary<string, int> m_AddingAssemblies =
170 new Dictionary<string, int>();
171
172 // This will list AppDomains by script asset
173
174 private Dictionary<UUID, AppDomain> m_AppDomains =
175 new Dictionary<UUID, AppDomain>();
176
177 // List the scripts running in each appdomain
178
179 private Dictionary<UUID, List<UUID> > m_DomainScripts =
180 new Dictionary<UUID, List<UUID> >();
181
182 private ScriptCompileQueue m_CompileQueue = new ScriptCompileQueue();
183 IWorkItemResult m_CurrentCompile = null;
184 private Dictionary<UUID, int> m_CompileDict = new Dictionary<UUID, int>();
185
186 private ScriptEngineConsoleCommands m_consoleCommands;
187
188 public string ScriptEngineName
189 {
190 get { return "XEngine"; }
191 }
192
193 public string ScriptClassName { get; private set; }
194
195 public string ScriptBaseClassName { get; private set; }
196
197 public ParameterInfo[] ScriptBaseClassParameters { get; private set; }
198
199 public string[] ScriptReferencedAssemblies { get; private set; }
200
201 public Scene World
202 {
203 get { return m_Scene; }
204 }
205
206 public static List<XEngine> ScriptEngines
207 {
208 get { return m_ScriptEngines; }
209 }
210
211 public IScriptModule ScriptModule
212 {
213 get { return this; }
214 }
215
216 // private struct RezScriptParms
217 // {
218 // uint LocalID;
219 // UUID ItemID;
220 // string Script;
221 // }
222
223 public IConfig Config
224 {
225 get { return m_ScriptConfig; }
226 }
227
228 public string ScriptEnginePath
229 {
230 get { return m_ScriptEnginesPath; }
231 }
232
233 public IConfigSource ConfigSource
234 {
235 get { return m_ConfigSource; }
236 }
237
238 /// <summary>
239 /// Event fired after the script engine has finished removing a script.
240 /// </summary>
241 public event ScriptRemoved OnScriptRemoved;
242
243 /// <summary>
244 /// Event fired after the script engine has finished removing a script from an object.
245 /// </summary>
246 public event ObjectRemoved OnObjectRemoved;
247
248 public void Initialise(IConfigSource configSource)
249 {
250 if (configSource.Configs["XEngine"] == null)
251 return;
252
253 m_ScriptConfig = configSource.Configs["XEngine"];
254 m_ConfigSource = configSource;
255
256 string rawScriptStopStrategy = m_ScriptConfig.GetString("ScriptStopStrategy", "co-op");
257
258 m_log.InfoFormat("[XEngine]: Script stop strategy is {0}", rawScriptStopStrategy);
259
260 if (rawScriptStopStrategy == "co-op")
261 {
262 m_coopTermination = true;
263 ScriptClassName = "XEngineScript";
264 ScriptBaseClassName = typeof(XEngineScriptBase).FullName;
265 ScriptBaseClassParameters = typeof(XEngineScriptBase).GetConstructor(new Type[] { typeof(WaitHandle) }).GetParameters();
266 ScriptReferencedAssemblies = new string[] { Path.GetFileName(typeof(XEngineScriptBase).Assembly.Location) };
267 }
268 else
269 {
270 ScriptClassName = "Script";
271 ScriptBaseClassName = typeof(ScriptBaseClass).FullName;
272 }
273
274// Console.WriteLine("ASSEMBLY NAME: {0}", ScriptReferencedAssemblies[0]);
275 }
276
277 public void AddRegion(Scene scene)
278 {
279 if (m_ScriptConfig == null)
280 return;
281
282 m_ScriptFailCount = 0;
283 m_ScriptErrorMessage = String.Empty;
284
285 m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true);
286
287 if (!m_Enabled)
288 return;
289
290 AppDomain.CurrentDomain.AssemblyResolve +=
291 OnAssemblyResolve;
292
293 m_Scene = scene;
294 m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName);
295
296 m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2);
297 m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100);
298 m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60);
299 string priority = m_ScriptConfig.GetString("Priority", "BelowNormal");
300 m_StartDelay = m_ScriptConfig.GetInt("StartDelay", 15000);
301 m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
302 m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
303 m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
304 m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true);
305
306 m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
307 m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
308 m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
309 m_WaitForEventCompletionOnScriptStop
310 = m_ScriptConfig.GetInt("WaitForEventCompletionOnScriptStop", m_WaitForEventCompletionOnScriptStop);
311
312 m_ScriptEnginesPath = m_ScriptConfig.GetString("ScriptEnginesPath", "ScriptEngines");
313
314 m_Prio = ThreadPriority.BelowNormal;
315 switch (priority)
316 {
317 case "Lowest":
318 m_Prio = ThreadPriority.Lowest;
319 break;
320 case "BelowNormal":
321 m_Prio = ThreadPriority.BelowNormal;
322 break;
323 case "Normal":
324 m_Prio = ThreadPriority.Normal;
325 break;
326 case "AboveNormal":
327 m_Prio = ThreadPriority.AboveNormal;
328 break;
329 case "Highest":
330 m_Prio = ThreadPriority.Highest;
331 break;
332 default:
333 m_log.ErrorFormat("[XEngine] Invalid thread priority: '{0}'. Assuming BelowNormal", priority);
334 break;
335 }
336
337 lock (m_ScriptEngines)
338 {
339 m_ScriptEngines.Add(this);
340 }
341
342 // Needs to be here so we can queue the scripts that need starting
343 //
344 m_Scene.EventManager.OnRezScript += OnRezScript;
345
346 // Complete basic setup of the thread pool
347 //
348 SetupEngine(m_MinThreads, m_MaxThreads, m_IdleTimeout, m_Prio,
349 m_MaxScriptQueue, m_StackSize);
350
351 m_Scene.StackModuleInterface<IScriptModule>(this);
352
353 m_XmlRpcRouter = m_Scene.RequestModuleInterface<IXmlRpcRouter>();
354 if (m_XmlRpcRouter != null)
355 {
356 OnScriptRemoved += m_XmlRpcRouter.ScriptRemoved;
357 OnObjectRemoved += m_XmlRpcRouter.ObjectRemoved;
358 }
359
360 m_consoleCommands = new ScriptEngineConsoleCommands(this);
361 m_consoleCommands.RegisterCommands();
362
363 MainConsole.Instance.Commands.AddCommand(
364 "Scripts", false, "xengine status", "xengine status", "Show status information",
365 "Show status information on the script engine.",
366 HandleShowStatus);
367
368 MainConsole.Instance.Commands.AddCommand(
369 "Scripts", false, "scripts show", "scripts show [<script-item-uuid>+]", "Show script information",
370 "Show information on all scripts known to the script engine.\n"
371 + "If one or more <script-item-uuid>s are given then only information on that script will be shown.",
372 HandleShowScripts);
373
374 MainConsole.Instance.Commands.AddCommand(
375 "Scripts", false, "show scripts", "show scripts [<script-item-uuid>+]", "Show script information",
376 "Synonym for scripts show command", HandleShowScripts);
377
378 MainConsole.Instance.Commands.AddCommand(
379 "Scripts", false, "scripts suspend", "scripts suspend [<script-item-uuid>+]", "Suspends all running scripts",
380 "Suspends all currently running scripts. This only suspends event delivery, it will not suspend a"
381 + " script that is currently processing an event.\n"
382 + "Suspended scripts will continue to accumulate events but won't process them.\n"
383 + "If one or more <script-item-uuid>s are given then only that script will be suspended. Otherwise, all suitable scripts are suspended.",
384 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleSuspendScript));
385
386 MainConsole.Instance.Commands.AddCommand(
387 "Scripts", false, "scripts resume", "scripts resume [<script-item-uuid>+]", "Resumes all suspended scripts",
388 "Resumes all currently suspended scripts.\n"
389 + "Resumed scripts will process all events accumulated whilst suspended.\n"
390 + "If one or more <script-item-uuid>s are given then only that script will be resumed. Otherwise, all suitable scripts are resumed.",
391 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleResumeScript));
392
393 MainConsole.Instance.Commands.AddCommand(
394 "Scripts", false, "scripts stop", "scripts stop [<script-item-uuid>+]", "Stops all running scripts",
395 "Stops all running scripts.\n"
396 + "If one or more <script-item-uuid>s are given then only that script will be stopped. Otherwise, all suitable scripts are stopped.",
397 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStopScript));
398
399 MainConsole.Instance.Commands.AddCommand(
400 "Scripts", false, "scripts start", "scripts start [<script-item-uuid>+]", "Starts all stopped scripts",
401 "Starts all stopped scripts.\n"
402 + "If one or more <script-item-uuid>s are given then only that script will be started. Otherwise, all suitable scripts are started.",
403 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
404
405 MainConsole.Instance.Commands.AddCommand(
406 "Debug", false, "debug scripts log", "debug scripts log <item-id> <log-level>", "Extra debug logging for a particular script.",
407 "Activates or deactivates extra debug logging for the given script.\n"
408 + "Level == 0, deactivate extra debug logging.\n"
409 + "Level >= 1, log state changes.\n"
410 + "Level >= 2, log event invocations.\n",
411 HandleDebugScriptLogCommand);
412
413 MainConsole.Instance.Commands.AddCommand(
414 "Debug", false, "debug xengine log", "debug xengine log [<level>]",
415 "Turn on detailed xengine debugging.",
416 "If level <= 0, then no extra logging is done.\n"
417 + "If level >= 1, then we log every time that a script is started.",
418 HandleDebugLevelCommand);
419 }
420
421 private void HandleDebugScriptLogCommand(string module, string[] args)
422 {
423 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
424 return;
425
426 if (args.Length != 5)
427 {
428 MainConsole.Instance.Output("Usage: debug script log <item-id> <log-level>");
429 return;
430 }
431
432 UUID itemId;
433
434 if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, args[3], out itemId))
435 return;
436
437 int newLevel;
438
439 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out newLevel))
440 return;
441
442 IScriptInstance si;
443
444 lock (m_Scripts)
445 {
446 // XXX: We can't give the user feedback on a bad item id because this may apply to a different script
447 // engine
448 if (!m_Scripts.TryGetValue(itemId, out si))
449 return;
450 }
451
452 si.DebugLevel = newLevel;
453 MainConsole.Instance.OutputFormat("Set debug level of {0} {1} to {2}", si.ScriptName, si.ItemID, newLevel);
454 }
455
456 /// <summary>
457 /// Change debug level
458 /// </summary>
459 /// <param name="module"></param>
460 /// <param name="args"></param>
461 private void HandleDebugLevelCommand(string module, string[] args)
462 {
463 if (args.Length >= 4)
464 {
465 int newDebug;
466 if (ConsoleUtil.TryParseConsoleNaturalInt(MainConsole.Instance, args[3], out newDebug))
467 {
468 DebugLevel = newDebug;
469 MainConsole.Instance.OutputFormat("Debug level set to {0} in XEngine for region {1}", newDebug, m_Scene.Name);
470 }
471 }
472 else if (args.Length == 3)
473 {
474 MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
475 }
476 else
477 {
478 MainConsole.Instance.Output("Usage: debug xengine log <level>");
479 }
480 }
481
482 /// <summary>
483 /// Parse the raw item id into a script instance from the command params if it's present.
484 /// </summary>
485 /// <param name="cmdparams"></param>
486 /// <param name="instance"></param>
487 /// <param name="comparer">Basis on which to sort output. Can be null if no sort needs to take place</param>
488 private void HandleScriptsAction(string[] cmdparams, Action<IScriptInstance> action)
489 {
490 HandleScriptsAction<object>(cmdparams, action, null);
491 }
492
493 /// <summary>
494 /// Parse the raw item id into a script instance from the command params if it's present.
495 /// </summary>
496 /// <param name="cmdparams"></param>
497 /// <param name="instance"></param>
498 /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param>
499 private void HandleScriptsAction<TKey>(
500 string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector)
501 {
502 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
503 return;
504
505 lock (m_Scripts)
506 {
507 string rawItemId;
508 UUID itemId = UUID.Zero;
509
510 if (cmdparams.Length == 2)
511 {
512 IEnumerable<IScriptInstance> scripts = m_Scripts.Values;
513
514 if (keySelector != null)
515 scripts = scripts.OrderBy<IScriptInstance, TKey>(keySelector);
516
517 foreach (IScriptInstance instance in scripts)
518 action(instance);
519
520 return;
521 }
522
523 for (int i = 2; i < cmdparams.Length; i++)
524 {
525 rawItemId = cmdparams[i];
526
527 if (!UUID.TryParse(rawItemId, out itemId))
528 {
529 MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid UUID", rawItemId);
530 continue;
531 }
532
533 if (itemId != UUID.Zero)
534 {
535 IScriptInstance instance = GetInstance(itemId);
536 if (instance == null)
537 {
538 // Commented out for now since this will cause false reports on simulators with more than
539 // one scene where the current command line set region is 'root' (which causes commands to
540 // go to both regions... (sigh)
541 // MainConsole.Instance.OutputFormat("Error - No item found with id {0}", itemId);
542 continue;
543 }
544 else
545 {
546 action(instance);
547 }
548 }
549 }
550 }
551 }
552
553 private void HandleShowStatus(string module, string[] cmdparams)
554 {
555 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
556 return;
557
558 MainConsole.Instance.Output(GetStatusReport());
559 }
560
561 public string GetStatusReport()
562 {
563 StringBuilder sb = new StringBuilder();
564 sb.AppendFormat("Status of XEngine instance for {0}\n", m_Scene.RegionInfo.RegionName);
565
566 long scriptsLoaded, eventsQueued = 0, eventsProcessed = 0;
567
568 lock (m_Scripts)
569 {
570 scriptsLoaded = m_Scripts.Count;
571
572 foreach (IScriptInstance si in m_Scripts.Values)
573 {
574 eventsQueued += si.EventsQueued;
575 eventsProcessed += si.EventsProcessed;
576 }
577 }
578
579 sb.AppendFormat("Scripts loaded : {0}\n", scriptsLoaded);
580 sb.AppendFormat("Scripts waiting for load : {0}\n", m_CompileQueue.Count);
581 sb.AppendFormat("Max threads : {0}\n", m_ThreadPool.MaxThreads);
582 sb.AppendFormat("Min threads : {0}\n", m_ThreadPool.MinThreads);
583 sb.AppendFormat("Allocated threads : {0}\n", m_ThreadPool.ActiveThreads);
584 sb.AppendFormat("In use threads : {0}\n", m_ThreadPool.InUseThreads);
585 sb.AppendFormat("Work items waiting : {0}\n", m_ThreadPool.WaitingCallbacks);
586// sb.AppendFormat("Assemblies loaded : {0}\n", m_Assemblies.Count);
587 sb.AppendFormat("Events queued : {0}\n", eventsQueued);
588 sb.AppendFormat("Events processed : {0}\n", eventsProcessed);
589
590 SensorRepeat sr = AsyncCommandManager.GetSensorRepeatPlugin(this);
591 sb.AppendFormat("Sensors : {0}\n", sr != null ? sr.SensorsCount : 0);
592
593 Dataserver ds = AsyncCommandManager.GetDataserverPlugin(this);
594 sb.AppendFormat("Dataserver requests : {0}\n", ds != null ? ds.DataserverRequestsCount : 0);
595
596 Timer t = AsyncCommandManager.GetTimerPlugin(this);
597 sb.AppendFormat("Timers : {0}\n", t != null ? t.TimersCount : 0);
598
599 Listener l = AsyncCommandManager.GetListenerPlugin(this);
600 sb.AppendFormat("Listeners : {0}\n", l != null ? l.ListenerCount : 0);
601
602 return sb.ToString();
603 }
604
605 public void HandleShowScripts(string module, string[] cmdparams)
606 {
607 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene))
608 return;
609
610 if (cmdparams.Length == 2)
611 {
612 lock (m_Scripts)
613 {
614 MainConsole.Instance.OutputFormat(
615 "Showing {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
616 }
617 }
618
619 HandleScriptsAction<long>(cmdparams, HandleShowScript, si => si.EventsProcessed);
620 }
621
622 private void HandleShowScript(IScriptInstance instance)
623 {
624 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
625 string status;
626
627 if (instance.ShuttingDown)
628 {
629 status = "shutting down";
630 }
631 else if (instance.Suspended)
632 {
633 status = "suspended";
634 }
635 else if (!instance.Running)
636 {
637 status = "stopped";
638 }
639 else
640 {
641 status = "running";
642 }
643
644 StringBuilder sb = new StringBuilder();
645
646 sb.AppendFormat("Script name : {0}\n", instance.ScriptName);
647 sb.AppendFormat("Status : {0}\n", status);
648 sb.AppendFormat("Queued events : {0}\n", instance.EventsQueued);
649 sb.AppendFormat("Processed events : {0}\n", instance.EventsProcessed);
650 sb.AppendFormat("Item UUID : {0}\n", instance.ItemID);
651 sb.AppendFormat("Asset UUID : {0}\n", instance.AssetID);
652 sb.AppendFormat("Containing part name: {0}\n", instance.PrimName);
653 sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID);
654 sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition);
655
656 MainConsole.Instance.Output(sb.ToString());
657 }
658
659 private void HandleSuspendScript(IScriptInstance instance)
660 {
661 if (!instance.Suspended)
662 {
663 instance.Suspend();
664
665 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
666 MainConsole.Instance.OutputFormat(
667 "Suspended {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
668 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
669 }
670 }
671
672 private void HandleResumeScript(IScriptInstance instance)
673 {
674 if (instance.Suspended)
675 {
676 instance.Resume();
677
678 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
679 MainConsole.Instance.OutputFormat(
680 "Resumed {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
681 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
682 }
683 }
684
685 private void HandleStartScript(IScriptInstance instance)
686 {
687 if (!instance.Running)
688 {
689 instance.Start();
690
691 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
692 MainConsole.Instance.OutputFormat(
693 "Started {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
694 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
695 }
696 }
697
698 private void HandleStopScript(IScriptInstance instance)
699 {
700 if (instance.Running)
701 {
702 instance.StayStopped = true; // the script was stopped explicitly
703
704 instance.Stop(0);
705
706 SceneObjectPart sop = m_Scene.GetSceneObjectPart(instance.ObjectID);
707 MainConsole.Instance.OutputFormat(
708 "Stopped {0}.{1}, item UUID {2}, prim UUID {3} @ {4}",
709 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, sop.AbsolutePosition);
710 }
711 }
712
713 public void RemoveRegion(Scene scene)
714 {
715 if (!m_Enabled)
716 return;
717
718 lock (m_Scripts)
719 {
720 m_log.InfoFormat(
721 "[XEngine]: Shutting down {0} scripts in {1}", m_Scripts.Count, m_Scene.RegionInfo.RegionName);
722
723 foreach (IScriptInstance instance in m_Scripts.Values)
724 {
725 // Force a final state save
726 //
727 try
728 {
729 if (instance.StatePersistedHere)
730 instance.SaveState();
731 }
732 catch (Exception e)
733 {
734 m_log.Error(
735 string.Format(
736 "[XEngine]: Failed final state save for script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
737 instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name)
738 , e);
739 }
740
741 // Clear the event queue and abort the instance thread
742 //
743 instance.Stop(0, true);
744
745 // Release events, timer, etc
746 //
747 instance.DestroyScriptInstance();
748
749 // Unload scripts and app domains.
750 // Must be done explicitly because they have infinite
751 // lifetime.
752 // However, don't bother to do this if the simulator is shutting
753 // down since it takes a long time with many scripts.
754 if (!m_SimulatorShuttingDown)
755 {
756 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
757 if (m_DomainScripts[instance.AppDomain].Count == 0)
758 {
759 m_DomainScripts.Remove(instance.AppDomain);
760 UnloadAppDomain(instance.AppDomain);
761 }
762 }
763 }
764
765 m_Scripts.Clear();
766 m_PrimObjects.Clear();
767 m_Assemblies.Clear();
768 m_DomainScripts.Clear();
769 }
770 lock (m_ScriptEngines)
771 {
772 m_ScriptEngines.Remove(this);
773 }
774 }
775
776 public void RegionLoaded(Scene scene)
777 {
778 if (!m_Enabled)
779 return;
780
781 m_EventManager = new EventManager(this);
782
783 m_Compiler = new Compiler(this);
784
785 m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
786 m_Scene.EventManager.OnScriptReset += OnScriptReset;
787 m_Scene.EventManager.OnStartScript += OnStartScript;
788 m_Scene.EventManager.OnStopScript += OnStopScript;
789 m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
790 m_Scene.EventManager.OnShutdown += OnShutdown;
791
792 // If region ready has been triggered, then the region had no scripts to compile and completed its other
793 // work.
794 m_Scene.EventManager.OnRegionReadyStatusChange += s => { if (s.Ready) m_InitialStartup = false; };
795
796 if (m_SleepTime > 0)
797 {
798 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
799 new Object[]{ m_SleepTime });
800 }
801
802 if (m_SaveTime > 0)
803 {
804 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
805 new Object[] { m_SaveTime });
806 }
807 }
808
809 public void StartProcessing()
810 {
811 m_ThreadPool.Start();
812 }
813
814 public void Close()
815 {
816 if (!m_Enabled)
817 return;
818
819 lock (m_ScriptEngines)
820 {
821 if (m_ScriptEngines.Contains(this))
822 m_ScriptEngines.Remove(this);
823 }
824 }
825
826 public object DoBackup(object o)
827 {
828 Object[] p = (Object[])o;
829 int saveTime = (int)p[0];
830
831 if (saveTime > 0)
832 System.Threading.Thread.Sleep(saveTime);
833
834// m_log.Debug("[XEngine] Backing up script states");
835
836 List<IScriptInstance> instances = new List<IScriptInstance>();
837
838 lock (m_Scripts)
839 {
840 foreach (IScriptInstance instance in m_Scripts.Values)
841 {
842 if (instance.StatePersistedHere)
843 {
844// m_log.DebugFormat(
845// "[XEngine]: Adding script {0}.{1}, item UUID {2}, prim UUID {3} in {4} for state persistence",
846// instance.PrimName, instance.ScriptName, instance.ItemID, instance.ObjectID, World.Name);
847
848 instances.Add(instance);
849 }
850 }
851 }
852
853 foreach (IScriptInstance i in instances)
854 {
855 try
856 {
857 i.SaveState();
858 }
859 catch (Exception e)
860 {
861 m_log.Error(
862 string.Format(
863 "[XEngine]: Failed to save state of script {0}.{1}, item UUID {2}, prim UUID {3} in {4}. Exception ",
864 i.PrimName, i.ScriptName, i.ItemID, i.ObjectID, World.Name)
865 , e);
866 }
867 }
868
869 if (saveTime > 0)
870 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
871 new Object[] { saveTime });
872
873 return 0;
874 }
875
876 public void SaveAllState()
877 {
878 DoBackup(new object[] { 0 });
879 }
880
881 public object DoMaintenance(object p)
882 {
883 object[] parms = (object[])p;
884 int sleepTime = (int)parms[0];
885
886 foreach (IScriptInstance inst in m_Scripts.Values)
887 {
888 if (inst.EventTime() > m_EventLimit)
889 {
890 inst.Stop(100);
891 if (!m_KillTimedOutScripts)
892 inst.Start();
893 }
894 }
895
896 System.Threading.Thread.Sleep(sleepTime);
897
898 m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
899 new Object[]{ sleepTime });
900
901 return 0;
902 }
903
904 public Type ReplaceableInterface
905 {
906 get { return null; }
907 }
908
909 public string Name
910 {
911 get { return "XEngine"; }
912 }
913
914 public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
915 {
916// m_log.DebugFormat(
917// "[XEngine]: OnRezScript event triggered for script {0}, startParam {1}, postOnRez {2}, engine {3}, stateSource {4}, script\n{5}",
918// itemID, startParam, postOnRez, engine, stateSource, script);
919
920 if (script.StartsWith("//MRM:"))
921 return;
922
923 List<IScriptModule> engines = new List<IScriptModule>(m_Scene.RequestModuleInterfaces<IScriptModule>());
924
925 List<string> names = new List<string>();
926 foreach (IScriptModule m in engines)
927 names.Add(m.ScriptEngineName);
928
929 int lineEnd = script.IndexOf('\n');
930
931 if (lineEnd > 1)
932 {
933 string firstline = script.Substring(0, lineEnd).Trim();
934
935 int colon = firstline.IndexOf(':');
936 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
937 {
938 string engineName = firstline.Substring(2, colon - 2);
939
940 if (names.Contains(engineName))
941 {
942 engine = engineName;
943 script = "//" + script.Substring(colon + 1);
944 }
945 else
946 {
947 if (engine == ScriptEngineName)
948 {
949 // If we are falling back on XEngine as the default engine, then only complain to the user
950 // if a script language has been explicitly set and it's one that we recognize or there are
951 // no non-whitespace characters after the colon.
952 //
953 // If the script is
954 // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message.
955 //
956 // If the colon ends the line then we'll risk the false positive as this is more likely
957 // to signal a real scriptengine line where the user wants to use the default compile language.
958 //
959 // This avoids the overwhelming number of false positives where we're in this code because
960 // there's a colon in a comment in the first line of a script for entirely
961 // unrelated reasons (e.g. vim settings).
962 //
963 // TODO: A better fix would be to deprecate simple : detection and look for some less likely
964 // string to begin the comment (like #! in unix shell scripts).
965 bool warnRunningInXEngine = false;
966 string restOfFirstLine = firstline.Substring(colon + 1);
967
968 // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs
969 if (restOfFirstLine.StartsWith("c#")
970 || restOfFirstLine.StartsWith("vb")
971 || restOfFirstLine.StartsWith("lsl")
972 || restOfFirstLine.Length == 0)
973 warnRunningInXEngine = true;
974
975 if (warnRunningInXEngine)
976 {
977 SceneObjectPart part =
978 m_Scene.GetSceneObjectPart(
979 localID);
980
981 TaskInventoryItem item =
982 part.Inventory.GetInventoryItem(itemID);
983
984 ScenePresence presence =
985 m_Scene.GetScenePresence(
986 item.OwnerID);
987
988 if (presence != null)
989 {
990 presence.ControllingClient.SendAgentAlertMessage(
991 "Selected engine unavailable. "+
992 "Running script on "+
993 ScriptEngineName,
994 false);
995 }
996 }
997 }
998 }
999 }
1000 }
1001
1002 if (engine != ScriptEngineName)
1003 return;
1004
1005 Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
1006
1007 if (stateSource == (int)StateSource.ScriptedRez)
1008 {
1009 lock (m_CompileDict)
1010 {
1011 m_CompileDict[itemID] = 0;
1012 }
1013
1014 DoOnRezScript(parms);
1015 }
1016 else
1017 {
1018 lock (m_CompileDict)
1019 m_CompileDict[itemID] = 0;
1020
1021 // This must occur after the m_CompileDict so that an existing compile thread cannot hit the check
1022 // in DoOnRezScript() before m_CompileDict has been updated.
1023 m_CompileQueue.Enqueue(parms);
1024
1025// m_log.DebugFormat("[XEngine]: Added script {0} to compile queue", itemID);
1026
1027 if (m_CurrentCompile == null)
1028 {
1029 // NOTE: Although we use a lockless queue, the lock here
1030 // is required. It ensures that there are never two
1031 // compile threads running, which, due to a race
1032 // conndition, might otherwise happen
1033 //
1034 lock (m_CompileQueue)
1035 {
1036 if (m_CurrentCompile == null)
1037 m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
1038 }
1039 }
1040 }
1041 }
1042
1043 public Object DoOnRezScriptQueue(Object dummy)
1044 {
1045 try
1046 {
1047 if (m_InitialStartup)
1048 {
1049 // This delay exists to stop mono problems where script compilation and startup would stop the sim
1050 // working properly for the session.
1051 System.Threading.Thread.Sleep(m_StartDelay);
1052
1053 m_log.InfoFormat("[XEngine]: Performing initial script startup on {0}", m_Scene.Name);
1054 }
1055
1056 object[] o;
1057
1058 int scriptsStarted = 0;
1059
1060 while (m_CompileQueue.Dequeue(out o))
1061 {
1062 try
1063 {
1064 if (DoOnRezScript(o))
1065 {
1066 scriptsStarted++;
1067
1068 if (m_InitialStartup)
1069 if (scriptsStarted % 50 == 0)
1070 m_log.InfoFormat(
1071 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.Name);
1072 }
1073 }
1074 catch (Exception e)
1075 {
1076 m_log.Error(
1077 string.Format(
1078 "[XEngine]: Failure in DoOnRezScriptQueue() for item {0} in {1}. Continuing. Exception ",
1079 o[1], m_Scene.Name),
1080 e);
1081 }
1082 }
1083
1084 if (m_InitialStartup)
1085 m_log.InfoFormat(
1086 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.Name);
1087
1088 }
1089 catch (Exception e)
1090 {
1091 m_log.Error(
1092 string.Format("[XEngine]: Failure in DoOnRezScriptQueue() in {0}. Exception ", m_Scene.Name), e);
1093 }
1094 finally
1095 {
1096 // FIXME: On failure we must trigger this even if the compile queue is not actually empty so that the
1097 // RegionReadyModule is not forever waiting. This event really needs a different name.
1098 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
1099 m_ScriptErrorMessage);
1100
1101 m_ScriptFailCount = 0;
1102 m_InitialStartup = false;
1103
1104 // NOTE: Despite having a lockless queue, this lock is required
1105 // to make sure there is never no compile thread while there
1106 // are still scripts to compile. This could otherwise happen
1107 // due to a race condition
1108 //
1109 lock (m_CompileQueue)
1110 {
1111 m_CurrentCompile = null;
1112
1113 // This is to avoid a situation where the m_CompileQueue while loop above could complete but
1114 // OnRezScript() place a new script on the queue and check m_CurrentCompile = null before we hit
1115 // this section.
1116 if (m_CompileQueue.Count > 0)
1117 m_CurrentCompile = m_ThreadPool.QueueWorkItem(DoOnRezScriptQueue, null);
1118 }
1119 }
1120
1121 return null;
1122 }
1123
1124 private bool DoOnRezScript(object[] parms)
1125 {
1126 Object[] p = parms;
1127 uint localID = (uint)p[0];
1128 UUID itemID = (UUID)p[1];
1129 string script =(string)p[2];
1130 int startParam = (int)p[3];
1131 bool postOnRez = (bool)p[4];
1132 StateSource stateSource = (StateSource)p[5];
1133
1134// m_log.DebugFormat("[XEngine]: DoOnRezScript called for script {0}", itemID);
1135
1136 lock (m_CompileDict)
1137 {
1138 if (!m_CompileDict.ContainsKey(itemID))
1139 return false;
1140 m_CompileDict.Remove(itemID);
1141 }
1142
1143 // Get the asset ID of the script, so we can check if we
1144 // already have it.
1145
1146 // We must look for the part outside the m_Scripts lock because GetSceneObjectPart later triggers the
1147 // m_parts lock on SOG. At the same time, a scene object that is being deleted will take the m_parts lock
1148 // and then later on try to take the m_scripts lock in this class when it calls OnRemoveScript()
1149 SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
1150 if (part == null)
1151 {
1152 m_log.ErrorFormat("[Script]: SceneObjectPart with localID {0} unavailable. Script NOT started.", localID);
1153 m_ScriptErrorMessage += "SceneObjectPart unavailable. Script NOT started.\n";
1154 m_ScriptFailCount++;
1155 return false;
1156 }
1157
1158 TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
1159 if (item == null)
1160 {
1161 m_ScriptErrorMessage += "Can't find script inventory item.\n";
1162 m_ScriptFailCount++;
1163 return false;
1164 }
1165
1166 if (DebugLevel > 0)
1167 m_log.DebugFormat(
1168 "[XEngine]: Loading script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1169 part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1170 part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1171
1172 UUID assetID = item.AssetID;
1173
1174 ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID);
1175
1176 string assemblyPath = "";
1177
1178 Culture.SetCurrentCulture();
1179
1180 Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
1181
1182 lock (m_ScriptErrors)
1183 {
1184 try
1185 {
1186 lock (m_AddingAssemblies)
1187 {
1188 m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assemblyPath, out linemap);
1189
1190// m_log.DebugFormat(
1191// "[XENGINE]: Found assembly path {0} onrez {1} in {2}",
1192// assemblyPath, item.ItemID, World.Name);
1193
1194 if (!m_AddingAssemblies.ContainsKey(assemblyPath)) {
1195 m_AddingAssemblies[assemblyPath] = 1;
1196 } else {
1197 m_AddingAssemblies[assemblyPath]++;
1198 }
1199 }
1200
1201 string[] warnings = m_Compiler.GetWarnings();
1202
1203 if (warnings != null && warnings.Length != 0)
1204 {
1205 foreach (string warning in warnings)
1206 {
1207 if (!m_ScriptErrors.ContainsKey(itemID))
1208 m_ScriptErrors[itemID] = new ArrayList();
1209
1210 m_ScriptErrors[itemID].Add(warning);
1211 // try
1212 // {
1213 // // DISPLAY WARNING INWORLD
1214 // string text = "Warning:\n" + warning;
1215 // if (text.Length > 1000)
1216 // text = text.Substring(0, 1000);
1217 // if (!ShowScriptSaveResponse(item.OwnerID,
1218 // assetID, text, true))
1219 // {
1220 // if (presence != null && (!postOnRez))
1221 // presence.ControllingClient.SendAgentAlertMessage("Script saved with warnings, check debug window!", false);
1222 //
1223 // World.SimChat(Utils.StringToBytes(text),
1224 // ChatTypeEnum.DebugChannel, 2147483647,
1225 // part.AbsolutePosition,
1226 // part.Name, part.UUID, false);
1227 // }
1228 // }
1229 // catch (Exception e2) // LEGIT: User Scripting
1230 // {
1231 // m_log.Error("[XEngine]: " +
1232 // "Error displaying warning in-world: " +
1233 // e2.ToString());
1234 // m_log.Error("[XEngine]: " +
1235 // "Warning:\r\n" +
1236 // warning);
1237 // }
1238 }
1239 }
1240 }
1241 catch (Exception e)
1242 {
1243// m_log.ErrorFormat(
1244// "[XEngine]: Exception when rezzing script with item ID {0}, {1}{2}",
1245// itemID, e.Message, e.StackTrace);
1246
1247 // try
1248 // {
1249 if (!m_ScriptErrors.ContainsKey(itemID))
1250 m_ScriptErrors[itemID] = new ArrayList();
1251 // DISPLAY ERROR INWORLD
1252 // m_ScriptErrorMessage += "Failed to compile script in object: '" + part.ParentGroup.RootPart.Name + "' Script name: '" + item.Name + "' Error message: " + e.Message.ToString();
1253 //
1254 m_ScriptFailCount++;
1255 m_ScriptErrors[itemID].Add(e.Message.ToString());
1256 // string text = "Error compiling script '" + item.Name + "':\n" + e.Message.ToString();
1257 // if (text.Length > 1000)
1258 // text = text.Substring(0, 1000);
1259 // if (!ShowScriptSaveResponse(item.OwnerID,
1260 // assetID, text, false))
1261 // {
1262 // if (presence != null && (!postOnRez))
1263 // presence.ControllingClient.SendAgentAlertMessage("Script saved with errors, check debug window!", false);
1264 // World.SimChat(Utils.StringToBytes(text),
1265 // ChatTypeEnum.DebugChannel, 2147483647,
1266 // part.AbsolutePosition,
1267 // part.Name, part.UUID, false);
1268 // }
1269 // }
1270 // catch (Exception e2) // LEGIT: User Scripting
1271 // {
1272 // m_log.Error("[XEngine]: "+
1273 // "Error displaying error in-world: " +
1274 // e2.ToString());
1275 // m_log.Error("[XEngine]: " +
1276 // "Errormessage: Error compiling script:\r\n" +
1277 // e.Message.ToString());
1278 // }
1279
1280 return false;
1281 }
1282 }
1283
1284 ScriptInstance instance = null;
1285 lock (m_Scripts)
1286 {
1287 // Create the object record
1288 if ((!m_Scripts.ContainsKey(itemID)) ||
1289 (m_Scripts[itemID].AssetID != assetID))
1290 {
1291 UUID appDomain = assetID;
1292
1293 if (part.ParentGroup.IsAttachment)
1294 appDomain = part.ParentGroup.RootPart.UUID;
1295
1296 if (!m_AppDomains.ContainsKey(appDomain))
1297 {
1298 try
1299 {
1300 AppDomainSetup appSetup = new AppDomainSetup();
1301 appSetup.PrivateBinPath = Path.Combine(
1302 m_ScriptEnginesPath,
1303 m_Scene.RegionInfo.RegionID.ToString());
1304
1305 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
1306 Evidence evidence = new Evidence(baseEvidence);
1307
1308 AppDomain sandbox;
1309 if (m_AppDomainLoading)
1310 {
1311 sandbox = AppDomain.CreateDomain(
1312 m_Scene.RegionInfo.RegionID.ToString(),
1313 evidence, appSetup);
1314 sandbox.AssemblyResolve +=
1315 new ResolveEventHandler(
1316 AssemblyResolver.OnAssemblyResolve);
1317 }
1318 else
1319 {
1320 sandbox = AppDomain.CurrentDomain;
1321 }
1322
1323 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
1324 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
1325 //PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
1326 //PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
1327 //CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
1328 //sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
1329 //sandbox.SetAppDomainPolicy(sandboxPolicy);
1330
1331 m_AppDomains[appDomain] = sandbox;
1332
1333 m_DomainScripts[appDomain] = new List<UUID>();
1334 }
1335 catch (Exception e)
1336 {
1337 m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
1338 m_ScriptErrorMessage += "Exception creating app domain:\n";
1339 m_ScriptFailCount++;
1340 lock (m_AddingAssemblies)
1341 {
1342 m_AddingAssemblies[assemblyPath]--;
1343 }
1344 return false;
1345 }
1346 }
1347 m_DomainScripts[appDomain].Add(itemID);
1348
1349 IScript scriptObj = null;
1350 EventWaitHandle coopSleepHandle;
1351 bool coopTerminationForThisScript;
1352
1353 // Set up assembly name to point to the appropriate scriptEngines directory
1354 AssemblyName assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyPath));
1355 assemblyName.CodeBase = Path.GetDirectoryName(assemblyPath);
1356
1357 if (m_coopTermination)
1358 {
1359 try
1360 {
1361 coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset);
1362
1363 scriptObj
1364 = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap(
1365 assemblyName.FullName,
1366 "SecondLife.XEngineScript",
1367 false,
1368 BindingFlags.Default,
1369 null,
1370 new object[] { coopSleepHandle },
1371 null,
1372 null);
1373
1374 coopTerminationForThisScript = true;
1375 }
1376 catch (TypeLoadException)
1377 {
1378 coopSleepHandle = null;
1379
1380 try
1381 {
1382 scriptObj
1383 = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap(
1384 assemblyName.FullName,
1385 "SecondLife.Script",
1386 false,
1387 BindingFlags.Default,
1388 null,
1389 null,
1390 null,
1391 null);
1392 }
1393 catch (Exception e2)
1394 {
1395 m_log.Error(
1396 string.Format(
1397 "[XENGINE]: Could not load previous SecondLife.Script from assembly {0} in {1}. Not starting. Exception ",
1398 assemblyName.FullName, World.Name),
1399 e2);
1400
1401 return false;
1402 }
1403
1404 coopTerminationForThisScript = false;
1405 }
1406 }
1407 else
1408 {
1409 try
1410 {
1411 scriptObj
1412 = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap(
1413 assemblyName.FullName,
1414 "SecondLife.Script",
1415 false,
1416 BindingFlags.Default,
1417 null,
1418 null,
1419 null,
1420 null);
1421
1422 coopSleepHandle = null;
1423 coopTerminationForThisScript = false;
1424 }
1425 catch (TypeLoadException)
1426 {
1427 coopSleepHandle = new XEngineEventWaitHandle(false, EventResetMode.AutoReset);
1428
1429 try
1430 {
1431 scriptObj
1432 = (IScript)m_AppDomains[appDomain].CreateInstanceAndUnwrap(
1433 assemblyName.FullName,
1434 "SecondLife.XEngineScript",
1435 false,
1436 BindingFlags.Default,
1437 null,
1438 new object[] { coopSleepHandle },
1439 null,
1440 null);
1441 }
1442 catch (Exception e2)
1443 {
1444 m_log.Error(
1445 string.Format(
1446 "[XENGINE]: Could not load previous SecondLife.XEngineScript from assembly {0} in {1}. Not starting. Exception ",
1447 assemblyName.FullName, World.Name),
1448 e2);
1449
1450 return false;
1451 }
1452
1453 coopTerminationForThisScript = true;
1454 }
1455 }
1456
1457 if (m_coopTermination != coopTerminationForThisScript && !HaveNotifiedLogOfScriptStopMistmatch)
1458 {
1459 // Notify the log that there is at least one script compile that doesn't match the
1460 // ScriptStopStrategy. Operator has to manually delete old DLLs - we can't do this on Windows
1461 // once the assembly has been loaded evne if the instantiation of a class was unsuccessful.
1462 m_log.WarnFormat(
1463 "[XEngine]: At least one existing compiled script DLL in {0} has {1} as ScriptStopStrategy whereas config setting is {2}."
1464 + "\nContinuing with script compiled strategy but to remove this message please set [XEngine] DeleteScriptsOnStartup = true for one simulator session to remove old script DLLs (script state will not be lost).",
1465 World.Name, coopTerminationForThisScript ? "co-op" : "abort", m_coopTermination ? "co-op" : "abort");
1466
1467 HaveNotifiedLogOfScriptStopMistmatch = true;
1468 }
1469
1470 instance = new ScriptInstance(this, part,
1471 item,
1472 startParam, postOnRez,
1473 m_MaxScriptQueue);
1474
1475 if (
1476 !instance.Load(
1477 scriptObj, coopSleepHandle, assemblyPath,
1478 Path.Combine(ScriptEnginePath, World.RegionInfo.RegionID.ToString()), stateSource, coopTerminationForThisScript))
1479 return false;
1480
1481// if (DebugLevel >= 1)
1482// m_log.DebugFormat(
1483// "[XEngine] Loaded script {0}.{1}, item UUID {2}, prim UUID {3} @ {4}.{5}",
1484// part.ParentGroup.RootPart.Name, item.Name, itemID, part.UUID,
1485// part.ParentGroup.RootPart.AbsolutePosition, part.ParentGroup.Scene.RegionInfo.RegionName);
1486
1487 if (presence != null)
1488 {
1489 ShowScriptSaveResponse(item.OwnerID,
1490 assetID, "Compile successful", true);
1491 }
1492
1493 instance.AppDomain = appDomain;
1494 instance.LineMap = linemap;
1495
1496 m_Scripts[itemID] = instance;
1497 }
1498 }
1499
1500 lock (m_PrimObjects)
1501 {
1502 if (!m_PrimObjects.ContainsKey(localID))
1503 m_PrimObjects[localID] = new List<UUID>();
1504
1505 if (!m_PrimObjects[localID].Contains(itemID))
1506 m_PrimObjects[localID].Add(itemID);
1507 }
1508
1509 if (!m_Assemblies.ContainsKey(assetID))
1510 m_Assemblies[assetID] = assemblyPath;
1511
1512 lock (m_AddingAssemblies)
1513 {
1514 m_AddingAssemblies[assemblyPath]--;
1515 }
1516
1517 if (instance != null)
1518 instance.Init();
1519
1520 bool runIt;
1521 if (m_runFlags.TryGetValue(itemID, out runIt))
1522 {
1523 if (!runIt)
1524 StopScript(itemID);
1525 m_runFlags.Remove(itemID);
1526 }
1527
1528 return true;
1529 }
1530
1531 public void OnRemoveScript(uint localID, UUID itemID)
1532 {
1533 // If it's not yet been compiled, make sure we don't try
1534 lock (m_CompileDict)
1535 {
1536 if (m_CompileDict.ContainsKey(itemID))
1537 m_CompileDict.Remove(itemID);
1538 }
1539
1540 IScriptInstance instance = null;
1541
1542 lock (m_Scripts)
1543 {
1544 // Do we even have it?
1545 if (!m_Scripts.ContainsKey(itemID))
1546 return;
1547
1548 instance = m_Scripts[itemID];
1549 m_Scripts.Remove(itemID);
1550 }
1551
1552 instance.Stop(m_WaitForEventCompletionOnScriptStop, true);
1553
1554 lock (m_PrimObjects)
1555 {
1556 // Remove the script from it's prim
1557 if (m_PrimObjects.ContainsKey(localID))
1558 {
1559 // Remove inventory item record
1560 if (m_PrimObjects[localID].Contains(itemID))
1561 m_PrimObjects[localID].Remove(itemID);
1562
1563 // If there are no more scripts, remove prim
1564 if (m_PrimObjects[localID].Count == 0)
1565 m_PrimObjects.Remove(localID);
1566 }
1567 }
1568
1569 if (instance.StatePersistedHere)
1570 instance.RemoveState();
1571
1572 instance.DestroyScriptInstance();
1573
1574 m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
1575 if (m_DomainScripts[instance.AppDomain].Count == 0)
1576 {
1577 m_DomainScripts.Remove(instance.AppDomain);
1578 UnloadAppDomain(instance.AppDomain);
1579 }
1580
1581 ObjectRemoved handlerObjectRemoved = OnObjectRemoved;
1582 if (handlerObjectRemoved != null)
1583 handlerObjectRemoved(instance.ObjectID);
1584
1585 ScriptRemoved handlerScriptRemoved = OnScriptRemoved;
1586 if (handlerScriptRemoved != null)
1587 handlerScriptRemoved(itemID);
1588 }
1589
1590 public void OnScriptReset(uint localID, UUID itemID)
1591 {
1592 ResetScript(itemID);
1593 }
1594
1595 public void OnStartScript(uint localID, UUID itemID)
1596 {
1597 StartScript(itemID);
1598 }
1599
1600 public void OnStopScript(uint localID, UUID itemID)
1601 {
1602 StopScript(itemID);
1603 }
1604
1605 private void CleanAssemblies()
1606 {
1607 List<UUID> assetIDList = new List<UUID>(m_Assemblies.Keys);
1608
1609 foreach (IScriptInstance i in m_Scripts.Values)
1610 {
1611 if (assetIDList.Contains(i.AssetID))
1612 assetIDList.Remove(i.AssetID);
1613 }
1614
1615 lock (m_AddingAssemblies)
1616 {
1617 foreach (UUID assetID in assetIDList)
1618 {
1619 // Do not remove assembly files if another instance of the script
1620 // is currently initialising
1621 if (!m_AddingAssemblies.ContainsKey(m_Assemblies[assetID])
1622 || m_AddingAssemblies[m_Assemblies[assetID]] == 0)
1623 {
1624// m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]);
1625 try
1626 {
1627 if (File.Exists(m_Assemblies[assetID]))
1628 File.Delete(m_Assemblies[assetID]);
1629
1630 if (File.Exists(m_Assemblies[assetID]+".text"))
1631 File.Delete(m_Assemblies[assetID]+".text");
1632
1633 if (File.Exists(m_Assemblies[assetID]+".mdb"))
1634 File.Delete(m_Assemblies[assetID]+".mdb");
1635
1636 if (File.Exists(m_Assemblies[assetID]+".map"))
1637 File.Delete(m_Assemblies[assetID]+".map");
1638 }
1639 catch (Exception)
1640 {
1641 }
1642 m_Assemblies.Remove(assetID);
1643 }
1644 }
1645 }
1646 }
1647
1648 private void UnloadAppDomain(UUID id)
1649 {
1650 if (m_AppDomains.ContainsKey(id))
1651 {
1652 AppDomain domain = m_AppDomains[id];
1653 m_AppDomains.Remove(id);
1654
1655 if (domain != AppDomain.CurrentDomain)
1656 AppDomain.Unload(domain);
1657 domain = null;
1658 // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
1659 }
1660 }
1661
1662 //
1663 // Start processing
1664 //
1665 private void SetupEngine(int minThreads, int maxThreads,
1666 int idleTimeout, ThreadPriority threadPriority,
1667 int maxScriptQueue, int stackSize)
1668 {
1669 m_MaxScriptQueue = maxScriptQueue;
1670
1671 STPStartInfo startInfo = new STPStartInfo();
1672 startInfo.ThreadPoolName = "XEngine";
1673 startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
1674 startInfo.MaxWorkerThreads = maxThreads;
1675 startInfo.MinWorkerThreads = minThreads;
1676 startInfo.ThreadPriority = threadPriority;;
1677 startInfo.MaxStackSize = stackSize;
1678 startInfo.StartSuspended = true;
1679
1680 m_ThreadPool = new SmartThreadPool(startInfo);
1681 }
1682
1683 //
1684 // Used by script instances to queue event handler jobs
1685 //
1686 public IScriptWorkItem QueueEventHandler(object parms)
1687 {
1688 return new XWorkItem(m_ThreadPool.QueueWorkItem(
1689 new WorkItemCallback(this.ProcessEventHandler),
1690 parms));
1691 }
1692
1693 /// <summary>
1694 /// Process a previously posted script event.
1695 /// </summary>
1696 /// <param name="parms"></param>
1697 /// <returns></returns>
1698 private object ProcessEventHandler(object parms)
1699 {
1700 Culture.SetCurrentCulture();
1701
1702 IScriptInstance instance = (ScriptInstance) parms;
1703
1704// m_log.DebugFormat("[XEngine]: Processing event for {0}", instance);
1705
1706 return instance.EventProcessor();
1707 }
1708
1709 /// <summary>
1710 /// Post event to an entire prim
1711 /// </summary>
1712 /// <param name="localID"></param>
1713 /// <param name="p"></param>
1714 /// <returns></returns>
1715 public bool PostObjectEvent(uint localID, EventParams p)
1716 {
1717 bool result = false;
1718 List<UUID> uuids = null;
1719
1720 lock (m_PrimObjects)
1721 {
1722 if (!m_PrimObjects.ContainsKey(localID))
1723 return false;
1724
1725 uuids = m_PrimObjects[localID];
1726
1727 foreach (UUID itemID in uuids)
1728 {
1729 IScriptInstance instance = null;
1730 try
1731 {
1732 if (m_Scripts.ContainsKey(itemID))
1733 instance = m_Scripts[itemID];
1734 }
1735 catch { /* ignore race conditions */ }
1736
1737 if (instance != null)
1738 {
1739 instance.PostEvent(p);
1740 result = true;
1741 }
1742 }
1743 }
1744
1745 return result;
1746 }
1747
1748 /// <summary>
1749 /// Post an event to a single script
1750 /// </summary>
1751 /// <param name="itemID"></param>
1752 /// <param name="p"></param>
1753 /// <returns></returns>
1754 public bool PostScriptEvent(UUID itemID, EventParams p)
1755 {
1756 if (m_Scripts.ContainsKey(itemID))
1757 {
1758 IScriptInstance instance = m_Scripts[itemID];
1759 if (instance != null)
1760 instance.PostEvent(p);
1761 return true;
1762 }
1763 return false;
1764 }
1765
1766 public bool PostScriptEvent(UUID itemID, string name, Object[] p)
1767 {
1768 Object[] lsl_p = new Object[p.Length];
1769 for (int i = 0; i < p.Length ; i++)
1770 {
1771 if (p[i] is int)
1772 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1773 else if (p[i] is string)
1774 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1775 else if (p[i] is Vector3)
1776 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1777 else if (p[i] is Quaternion)
1778 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1779 else if (p[i] is float)
1780 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1781 else
1782 lsl_p[i] = p[i];
1783 }
1784
1785 return PostScriptEvent(itemID, new EventParams(name, lsl_p, new DetectParams[0]));
1786 }
1787
1788 public bool PostObjectEvent(UUID itemID, string name, Object[] p)
1789 {
1790 SceneObjectPart part = m_Scene.GetSceneObjectPart(itemID);
1791 if (part == null)
1792 return false;
1793
1794 Object[] lsl_p = new Object[p.Length];
1795 for (int i = 0; i < p.Length ; i++)
1796 {
1797 if (p[i] is int)
1798 lsl_p[i] = new LSL_Types.LSLInteger((int)p[i]);
1799 else if (p[i] is string)
1800 lsl_p[i] = new LSL_Types.LSLString((string)p[i]);
1801 else if (p[i] is Vector3)
1802 lsl_p[i] = new LSL_Types.Vector3((Vector3)p[i]);
1803 else if (p[i] is Quaternion)
1804 lsl_p[i] = new LSL_Types.Quaternion((Quaternion)p[i]);
1805 else if (p[i] is float)
1806 lsl_p[i] = new LSL_Types.LSLFloat((float)p[i]);
1807 else
1808 lsl_p[i] = p[i];
1809 }
1810
1811 return PostObjectEvent(part.LocalId, new EventParams(name, lsl_p, new DetectParams[0]));
1812 }
1813
1814 public Assembly OnAssemblyResolve(object sender,
1815 ResolveEventArgs args)
1816 {
1817 if (!(sender is System.AppDomain))
1818 return null;
1819
1820 string[] pathList = new string[] {"bin", m_ScriptEnginesPath,
1821 Path.Combine(m_ScriptEnginesPath,
1822 m_Scene.RegionInfo.RegionID.ToString())};
1823
1824 string assemblyName = args.Name;
1825 if (assemblyName.IndexOf(",") != -1)
1826 assemblyName = args.Name.Substring(0, args.Name.IndexOf(","));
1827
1828 foreach (string s in pathList)
1829 {
1830 string path = Path.Combine(Directory.GetCurrentDirectory(),
1831 Path.Combine(s, assemblyName))+".dll";
1832
1833// Console.WriteLine("[XEngine]: Trying to resolve {0}", path);
1834
1835 if (File.Exists(path))
1836 return Assembly.LoadFrom(path);
1837 }
1838
1839 return null;
1840 }
1841
1842 private IScriptInstance GetInstance(UUID itemID)
1843 {
1844 IScriptInstance instance;
1845 lock (m_Scripts)
1846 {
1847 if (!m_Scripts.ContainsKey(itemID))
1848 return null;
1849 instance = m_Scripts[itemID];
1850 }
1851 return instance;
1852 }
1853
1854 public void SetScriptState(UUID itemID, bool running)
1855 {
1856 IScriptInstance instance = GetInstance(itemID);
1857 if (instance != null)
1858 {
1859 if (running)
1860 instance.Start();
1861 else
1862 instance.Stop(100);
1863 }
1864 }
1865
1866 public bool GetScriptState(UUID itemID)
1867 {
1868 IScriptInstance instance = GetInstance(itemID);
1869 return instance != null && instance.Running;
1870 }
1871
1872 public void ApiResetScript(UUID itemID)
1873 {
1874 IScriptInstance instance = GetInstance(itemID);
1875 if (instance != null)
1876 instance.ApiResetScript();
1877
1878 // Send the new number of threads that are in use by the thread
1879 // pool, I believe that by adding them to the locations where the
1880 // script is changing states that I will catch all changes to the
1881 // thread pool
1882 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
1883 }
1884
1885 public void ResetScript(UUID itemID)
1886 {
1887 IScriptInstance instance = GetInstance(itemID);
1888 if (instance != null)
1889 instance.ResetScript(m_WaitForEventCompletionOnScriptStop);
1890
1891 // Send the new number of threads that are in use by the thread
1892 // pool, I believe that by adding them to the locations where the
1893 // script is changing states that I will catch all changes to the
1894 // thread pool
1895 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
1896 }
1897
1898 public void StartScript(UUID itemID)
1899 {
1900 IScriptInstance instance = GetInstance(itemID);
1901 if (instance != null)
1902 instance.Start();
1903 else
1904 m_runFlags.AddOrUpdate(itemID, true, 240);
1905
1906 // Send the new number of threads that are in use by the thread
1907 // pool, I believe that by adding them to the locations where the
1908 // script is changing states that I will catch all changes to the
1909 // thread pool
1910 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
1911 }
1912
1913 public void StopScript(UUID itemID)
1914 {
1915 IScriptInstance instance = GetInstance(itemID);
1916
1917 if (instance != null)
1918 {
1919 lock (instance.EventQueue)
1920 instance.StayStopped = true; // the script was stopped explicitly
1921
1922 instance.Stop(m_WaitForEventCompletionOnScriptStop);
1923 }
1924 else
1925 {
1926// m_log.DebugFormat("[XENGINE]: Could not find script with ID {0} to stop in {1}", itemID, World.Name);
1927 m_runFlags.AddOrUpdate(itemID, false, 240);
1928 }
1929
1930 // Send the new number of threads that are in use by the thread
1931 // pool, I believe that by adding them to the locations where the
1932 // script is changing states that I will catch all changes to the
1933 // thread pool
1934 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
1935 }
1936
1937 public DetectParams GetDetectParams(UUID itemID, int idx)
1938 {
1939 IScriptInstance instance = GetInstance(itemID);
1940 return instance != null ? instance.GetDetectParams(idx) : null;
1941 }
1942
1943 public void SetMinEventDelay(UUID itemID, double delay)
1944 {
1945 IScriptInstance instance = GetInstance(itemID);
1946 if (instance != null)
1947 instance.MinEventDelay = delay;
1948 }
1949
1950 public UUID GetDetectID(UUID itemID, int idx)
1951 {
1952 IScriptInstance instance = GetInstance(itemID);
1953 return instance != null ? instance.GetDetectID(idx) : UUID.Zero;
1954 }
1955
1956 public void SetState(UUID itemID, string newState)
1957 {
1958 IScriptInstance instance = GetInstance(itemID);
1959 if (instance == null)
1960 return;
1961 instance.SetState(newState);
1962 }
1963
1964 public int GetStartParameter(UUID itemID)
1965 {
1966 IScriptInstance instance = GetInstance(itemID);
1967 return instance == null ? 0 : instance.StartParam;
1968 }
1969
1970 public void OnShutdown()
1971 {
1972 m_SimulatorShuttingDown = true;
1973
1974 List<IScriptInstance> instances = new List<IScriptInstance>();
1975
1976 lock (m_Scripts)
1977 {
1978 foreach (IScriptInstance instance in m_Scripts.Values)
1979 instances.Add(instance);
1980 }
1981
1982 foreach (IScriptInstance i in instances)
1983 {
1984 // Stop the script, even forcibly if needed. Then flag
1985 // it as shutting down and restore the previous run state
1986 // for serialization, so the scripts don't come back
1987 // dead after region restart
1988 //
1989 bool prevRunning = i.Running;
1990 i.Stop(50);
1991 i.ShuttingDown = true;
1992 i.Running = prevRunning;
1993 }
1994
1995 DoBackup(new Object[] {0});
1996 }
1997
1998 public IScriptApi GetApi(UUID itemID, string name)
1999 {
2000 IScriptInstance instance = GetInstance(itemID);
2001 return instance == null ? null : instance.GetApi(name);
2002 }
2003
2004 public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
2005 {
2006 IScriptInstance instance = GetInstance(itemID);
2007 if (instance == null)
2008 return;
2009 IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
2010 if (eq == null)
2011 {
2012 controllingClient.SendScriptRunningReply(objectID, itemID,
2013 GetScriptState(itemID));
2014 }
2015 else
2016 {
2017 eq.Enqueue(eq.ScriptRunningEvent(objectID, itemID, GetScriptState(itemID), true),
2018 controllingClient.AgentId);
2019 }
2020 }
2021
2022 public string GetXMLState(UUID itemID)
2023 {
2024// m_log.DebugFormat("[XEngine]: Getting XML state for script instance {0}", itemID);
2025
2026 IScriptInstance instance = GetInstance(itemID);
2027 if (instance == null)
2028 {
2029// m_log.DebugFormat("[XEngine]: Found no script instance for {0}, returning empty string", itemID);
2030 return "";
2031 }
2032
2033 string xml = instance.GetXMLState();
2034
2035 XmlDocument sdoc = new XmlDocument();
2036 bool loadedState = true;
2037 try
2038 {
2039 sdoc.LoadXml(xml);
2040 }
2041 catch (System.Xml.XmlException)
2042 {
2043 loadedState = false;
2044 }
2045
2046 XmlNodeList rootL = null;
2047 XmlNode rootNode = null;
2048 if (loadedState)
2049 {
2050 rootL = sdoc.GetElementsByTagName("ScriptState");
2051 rootNode = rootL[0];
2052 }
2053
2054 // Create <State UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">
2055 XmlDocument doc = new XmlDocument();
2056 XmlElement stateData = doc.CreateElement("", "State", "");
2057 XmlAttribute stateID = doc.CreateAttribute("", "UUID", "");
2058 stateID.Value = itemID.ToString();
2059 stateData.Attributes.Append(stateID);
2060 XmlAttribute assetID = doc.CreateAttribute("", "Asset", "");
2061 assetID.Value = instance.AssetID.ToString();
2062 stateData.Attributes.Append(assetID);
2063 XmlAttribute engineName = doc.CreateAttribute("", "Engine", "");
2064 engineName.Value = ScriptEngineName;
2065 stateData.Attributes.Append(engineName);
2066 doc.AppendChild(stateData);
2067
2068 XmlNode xmlstate = null;
2069
2070 // Add <ScriptState>...</ScriptState>
2071 if (loadedState)
2072 {
2073 xmlstate = doc.ImportNode(rootNode, true);
2074 }
2075 else
2076 {
2077 xmlstate = doc.CreateElement("", "ScriptState", "");
2078 }
2079
2080 stateData.AppendChild(xmlstate);
2081
2082 string assemName = instance.GetAssemblyName();
2083
2084 string fn = Path.GetFileName(assemName);
2085
2086 string assem = String.Empty;
2087
2088 if (File.Exists(assemName + ".text"))
2089 {
2090 FileInfo tfi = new FileInfo(assemName + ".text");
2091
2092 if (tfi != null)
2093 {
2094 Byte[] tdata = new Byte[tfi.Length];
2095
2096 try
2097 {
2098 using (FileStream tfs = File.Open(assemName + ".text",
2099 FileMode.Open, FileAccess.Read))
2100 {
2101 tfs.Read(tdata, 0, tdata.Length);
2102 }
2103
2104 assem = Encoding.ASCII.GetString(tdata);
2105 }
2106 catch (Exception e)
2107 {
2108 m_log.ErrorFormat(
2109 "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}",
2110 assemName, ".text", e.Message);
2111 }
2112 }
2113 }
2114 else
2115 {
2116 FileInfo fi = new FileInfo(assemName);
2117
2118 if (fi != null)
2119 {
2120 Byte[] data = new Byte[fi.Length];
2121
2122 try
2123 {
2124 using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read))
2125 {
2126 fs.Read(data, 0, data.Length);
2127 }
2128
2129 assem = System.Convert.ToBase64String(data);
2130 }
2131 catch (Exception e)
2132 {
2133 m_log.ErrorFormat(
2134 "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message);
2135 }
2136 }
2137 }
2138
2139 string map = String.Empty;
2140
2141 if (File.Exists(fn + ".map"))
2142 {
2143 using (FileStream mfs = File.Open(fn + ".map", FileMode.Open, FileAccess.Read))
2144 {
2145 using (StreamReader msr = new StreamReader(mfs))
2146 {
2147 map = msr.ReadToEnd();
2148 }
2149 }
2150 }
2151
2152 XmlElement assemblyData = doc.CreateElement("", "Assembly", "");
2153 XmlAttribute assemblyName = doc.CreateAttribute("", "Filename", "");
2154
2155 assemblyName.Value = fn;
2156 assemblyData.Attributes.Append(assemblyName);
2157
2158 assemblyData.InnerText = assem;
2159
2160 stateData.AppendChild(assemblyData);
2161
2162 XmlElement mapData = doc.CreateElement("", "LineMap", "");
2163 XmlAttribute mapName = doc.CreateAttribute("", "Filename", "");
2164
2165 mapName.Value = fn + ".map";
2166 mapData.Attributes.Append(mapName);
2167
2168 mapData.InnerText = map;
2169
2170 stateData.AppendChild(mapData);
2171
2172// m_log.DebugFormat("[XEngine]: Got XML state for {0}", itemID);
2173
2174 return doc.InnerXml;
2175 }
2176
2177 private bool ShowScriptSaveResponse(UUID ownerID, UUID assetID, string text, bool compiled)
2178 {
2179 return false;
2180 }
2181
2182 public bool SetXMLState(UUID itemID, string xml)
2183 {
2184// m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID);
2185
2186 if (xml == String.Empty)
2187 return false;
2188
2189 XmlDocument doc = new XmlDocument();
2190
2191 try
2192 {
2193 doc.LoadXml(xml);
2194 }
2195 catch (Exception)
2196 {
2197 m_log.Error("[XEngine]: Exception decoding XML data from region transfer");
2198 return false;
2199 }
2200
2201 XmlNodeList rootL = doc.GetElementsByTagName("State");
2202 if (rootL.Count < 1)
2203 return false;
2204
2205 XmlElement rootE = (XmlElement)rootL[0];
2206
2207 if (rootE.GetAttribute("Engine") != ScriptEngineName)
2208 return false;
2209
2210// On rez from inventory, that ID will have changed. It was only
2211// advisory anyway. So we don't check it anymore.
2212//
2213// if (rootE.GetAttribute("UUID") != itemID.ToString())
2214// return;
2215
2216 XmlNodeList stateL = rootE.GetElementsByTagName("ScriptState");
2217
2218 if (stateL.Count != 1)
2219 return false;
2220
2221 XmlElement stateE = (XmlElement)stateL[0];
2222
2223 if (World.m_trustBinaries)
2224 {
2225 XmlNodeList assemL = rootE.GetElementsByTagName("Assembly");
2226
2227 if (assemL.Count != 1)
2228 return false;
2229
2230 XmlElement assemE = (XmlElement)assemL[0];
2231
2232 string fn = assemE.GetAttribute("Filename");
2233 string base64 = assemE.InnerText;
2234
2235 string path = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2236 path = Path.Combine(path, fn);
2237
2238 if (!File.Exists(path))
2239 {
2240 Byte[] filedata = Convert.FromBase64String(base64);
2241
2242 try
2243 {
2244 using (FileStream fs = File.Create(path))
2245 {
2246// m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path);
2247
2248 fs.Write(filedata, 0, filedata.Length);
2249 }
2250 }
2251 catch (IOException ex)
2252 {
2253 // if there already exists a file at that location, it may be locked.
2254 m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message);
2255 }
2256
2257 string textpath = path + ".text";
2258 try
2259 {
2260 using (FileStream fs = File.Create(textpath))
2261 {
2262 using (StreamWriter sw = new StreamWriter(fs))
2263 {
2264// m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath);
2265
2266 sw.Write(base64);
2267 }
2268 }
2269 }
2270 catch (IOException ex)
2271 {
2272 // if there already exists a file at that location, it may be locked.
2273 m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message);
2274 }
2275 }
2276
2277 XmlNodeList mapL = rootE.GetElementsByTagName("LineMap");
2278 if (mapL.Count > 0)
2279 {
2280 XmlElement mapE = (XmlElement)mapL[0];
2281
2282 string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2283 mappath = Path.Combine(mappath, mapE.GetAttribute("Filename"));
2284
2285 try
2286 {
2287 using (FileStream mfs = File.Create(mappath))
2288 {
2289 using (StreamWriter msw = new StreamWriter(mfs))
2290 {
2291 // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath);
2292
2293 msw.Write(mapE.InnerText);
2294 }
2295 }
2296 }
2297 catch (IOException ex)
2298 {
2299 // if there already exists a file at that location, it may be locked.
2300 m_log.Error(
2301 string.Format("[XEngine]: Linemap file {0} could not be written. Exception ", mappath), ex);
2302 }
2303 }
2304 }
2305
2306 string statepath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2307 statepath = Path.Combine(statepath, itemID.ToString() + ".state");
2308
2309 try
2310 {
2311 using (FileStream sfs = File.Create(statepath))
2312 {
2313 using (StreamWriter ssw = new StreamWriter(sfs))
2314 {
2315// m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath);
2316
2317 ssw.Write(stateE.OuterXml);
2318 }
2319 }
2320 }
2321 catch (IOException ex)
2322 {
2323 // if there already exists a file at that location, it may be locked.
2324 m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message);
2325 }
2326
2327// m_log.DebugFormat(
2328// "[XEngine]: Wrote state for script item with ID {0} at {1} in {2}", itemID, statepath, m_Scene.Name);
2329
2330 return true;
2331 }
2332
2333 public ArrayList GetScriptErrors(UUID itemID)
2334 {
2335 System.Threading.Thread.Sleep(1000);
2336
2337 lock (m_ScriptErrors)
2338 {
2339 if (m_ScriptErrors.ContainsKey(itemID))
2340 {
2341 ArrayList ret = m_ScriptErrors[itemID];
2342 m_ScriptErrors.Remove(itemID);
2343 return ret;
2344 }
2345 return new ArrayList();
2346 }
2347 }
2348
2349 public Dictionary<uint, float> GetObjectScriptsExecutionTimes()
2350 {
2351 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
2352
2353 lock (m_Scripts)
2354 {
2355 foreach (IScriptInstance si in m_Scripts.Values)
2356 {
2357 if (!topScripts.ContainsKey(si.LocalID))
2358 topScripts[si.RootLocalID] = 0;
2359
2360 topScripts[si.RootLocalID] += GetExectionTime(si);
2361 }
2362 }
2363
2364 return topScripts;
2365 }
2366
2367 public float GetScriptExecutionTime(List<UUID> itemIDs)
2368 {
2369 if (itemIDs == null|| itemIDs.Count == 0)
2370 {
2371 return 0.0f;
2372 }
2373 float time = 0.0f;
2374 IScriptInstance si;
2375 // Calculate the time for all scripts that this engine is executing
2376 // Ignore any others
2377 foreach (UUID id in itemIDs)
2378 {
2379 si = GetInstance(id);
2380 if (si != null && si.Running)
2381 {
2382 time += GetExectionTime(si);
2383 }
2384 }
2385 return time;
2386 }
2387
2388 private float GetExectionTime(IScriptInstance si)
2389 {
2390 return (float)si.ExecutionTime.GetSumTime().TotalMilliseconds;
2391 }
2392
2393 public void SuspendScript(UUID itemID)
2394 {
2395// m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID);
2396
2397 IScriptInstance instance = GetInstance(itemID);
2398 if (instance != null)
2399 instance.Suspend();
2400// else
2401// m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2402
2403 // Send the new number of threads that are in use by the thread
2404 // pool, I believe that by adding them to the locations where the
2405 // script is changing states that I will catch all changes to the
2406 // thread pool
2407 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
2408 }
2409
2410 public void ResumeScript(UUID itemID)
2411 {
2412// m_log.DebugFormat("[XEngine]: Received request to resume script with ID {0}", itemID);
2413
2414 IScriptInstance instance = GetInstance(itemID);
2415 if (instance != null)
2416 instance.Resume();
2417// else
2418// m_log.DebugFormat("[XEngine]: Could not find script with ID {0} to resume", itemID);
2419
2420 // Send the new number of threads that are in use by the thread
2421 // pool, I believe that by adding them to the locations where the
2422 // script is changing states that I will catch all changes to the
2423 // thread pool
2424 m_Scene.setThreadCount(m_ThreadPool.InUseThreads);
2425 }
2426
2427 public bool HasScript(UUID itemID, out bool running)
2428 {
2429 running = true;
2430
2431 IScriptInstance instance = GetInstance(itemID);
2432 if (instance == null)
2433 return false;
2434
2435 running = instance.Running;
2436 return true;
2437 }
2438
2439 public void SleepScript(UUID itemID, int delay)
2440 {
2441 IScriptInstance instance = GetInstance(itemID);
2442 if (instance == null)
2443 return;
2444
2445 instance.ExecutionTimer.Stop();
2446 try
2447 {
2448 if (instance.CoopWaitHandle != null)
2449 {
2450 if (instance.CoopWaitHandle.WaitOne(delay))
2451 throw new ScriptCoopStopException();
2452 }
2453 else
2454 {
2455 Thread.Sleep(delay);
2456 }
2457 }
2458 finally
2459 {
2460 instance.ExecutionTimer.Start();
2461 }
2462 }
2463 }
2464}
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
new file mode 100644
index 0000000..9d9dee1
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs
@@ -0,0 +1,69 @@
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.IO;
30using System.Threading;
31using Amib.Threading;
32using OpenSim.Region.ScriptEngine.Interfaces;
33
34namespace OpenSim.Region.ScriptEngine.XEngine
35{
36 public class XWorkItem : IScriptWorkItem
37 {
38 private IWorkItemResult wr;
39
40 public IWorkItemResult WorkItem
41 {
42 get { return wr; }
43 }
44
45 public XWorkItem(IWorkItemResult w)
46 {
47 wr = w;
48 }
49
50 public bool Cancel()
51 {
52 return wr.Cancel();
53 }
54
55 public bool Abort()
56 {
57 return wr.Cancel(true);
58 }
59
60 public bool Wait(int t)
61 {
62 // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the
63 // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an
64 // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8
65 // (or very likely other versions of Mono at least up until 3.0.3).
66 return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false);
67 }
68 }
69}