aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs644
1 files changed, 644 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs
new file mode 100644
index 0000000..acf1e66
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRInstBackend.cs
@@ -0,0 +1,644 @@
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 System.Reflection;
31using System.Collections;
32using System.Collections.Generic;
33using System.Runtime.Remoting.Lifetime;
34using System.Security.Policy;
35using System.IO;
36using System.Xml;
37using System.Text;
38using OpenMetaverse;
39using OpenSim.Framework;
40using OpenSim.Region.ScriptEngine.Interfaces;
41using OpenSim.Region.ScriptEngine.Shared;
42using OpenSim.Region.ScriptEngine.Shared.Api;
43using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
44using OpenSim.Region.ScriptEngine.XMREngine;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.Framework.Scenes.Scripting;
47using OpenSim.Region.Framework.Interfaces;
48using log4net;
49
50using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
51using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
52using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
53using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
54using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
55using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
56using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
57
58namespace OpenSim.Region.ScriptEngine.XMREngine
59{
60 /****************************************************\
61 * This file contains routines called by scripts. *
62 \****************************************************/
63
64 public class XMRLSL_Api : LSL_Api
65 {
66 public AsyncCommandManager acm;
67 private XMRInstance inst;
68
69 public void InitXMRLSLApi(XMRInstance i)
70 {
71 acm = AsyncCommands;
72 inst = i;
73 }
74
75 protected override void ScriptSleep(int ms)
76 {
77 inst.Sleep(ms);
78 }
79
80 public override void llSleep(double sec)
81 {
82 inst.Sleep((int)(sec * 1000.0));
83 }
84
85 public override void llDie()
86 {
87 inst.Die();
88 }
89
90 /**
91 * @brief Seat avatar on prim.
92 * @param owner = true: owner of prim script is running in
93 * false: avatar that has given ANIMATION permission on the prim
94 * @returns 0: successful
95 * -1: no permission to animate
96 * -2: no av granted perms
97 * -3: av not in region
98 */
99 public int xmrSeatAvatar (bool owner)
100 {
101 // Get avatar to be seated and make sure they have given us ANIMATION permission
102
103 UUID avuuid;
104 if (owner) {
105 avuuid = inst.m_Part.OwnerID;
106 } else {
107 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
108 return -1;
109 }
110 avuuid = m_item.PermsGranter;
111 }
112 if (avuuid == UUID.Zero) {
113 return -2;
114 }
115
116 ScenePresence presence = World.GetScenePresence (avuuid);
117 if (presence == null) {
118 return -3;
119 }
120
121 // remoteClient = not used by ScenePresence.HandleAgentRequestSit()
122 // agentID = not used by ScenePresence.HandleAgentRequestSit()
123 // targetID = UUID of prim to sit on
124 // offset = offset of sitting position
125
126 presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
127 return 0;
128 }
129
130 /**
131 * @brief llTeleportAgent() is broken in that if you pass it a landmark,
132 * it still subjects the position to spawn points, as it always
133 * calls RequestTeleportLocation() with TeleportFlags.ViaLocation.
134 * See llTeleportAgent() and CheckAndAdjustTelehub().
135 *
136 * @param agent = what agent to teleport
137 * @param landmark = inventory name or UUID of a landmark object
138 * @param lookat = looking direction after teleport
139 */
140 public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
141 {
142 // find out about agent to be teleported
143 UUID agentId;
144 if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
145
146 ScenePresence presence = World.GetScenePresence (agentId);
147 if (presence == null) throw new ApplicationException ("agent not present in scene");
148 if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
149 if (presence.IsGod) throw new ApplicationException ("agent is a god");
150
151 // prim must be owned by land owner or prim must be attached to agent
152 if (m_host.ParentGroup.AttachmentPoint == 0) {
153 if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
154 throw new ApplicationException ("prim not owned by land's owner");
155 }
156 } else {
157 if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
158 }
159
160 // find landmark in inventory or by UUID
161 UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
162 if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
163
164 // read it in and make sure it is a landmark
165 AssetBase lma = World.AssetService.Get (assetID.ToString ());
166 if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
167
168 // parse the record
169 AssetLandmark lm = new AssetLandmark (lma);
170
171 // the regionhandle (based on region's world X,Y) might be out of date
172 // re-read the handle so we can pass it to RequestTeleportLocation()
173 var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
174 if (region == null) throw new ApplicationException ("no such region");
175
176 // finally ready to teleport
177 World.RequestTeleportLocation (presence.ControllingClient,
178 region.RegionHandle,
179 lm.Position,
180 lookat,
181 (uint)TeleportFlags.ViaLandmark);
182 }
183
184 /**
185 * @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL.
186 * Code modelled after llSetParcelMusicURL().
187 * @param newurl = new URL to set (or "" to leave it alone)
188 * @returns previous URL string
189 */
190 public string xmrSetParcelMusicURLGroup (string newurl)
191 {
192 string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
193 if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
194
195 IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
196 if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
197
198 GroupRecord grouprec = igm.GetGroupRecord (groupname);
199 if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
200
201 GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
202 if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
203
204 ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
205 if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
206 string oldurl = land.GetMusicUrl ();
207 if (oldurl == null) oldurl = "";
208 if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
209 return oldurl;
210 }
211 }
212
213 public partial class XMRInstance
214 {
215 /**
216 * @brief The script is calling llReset().
217 * We throw an exception to unwind the script out to its main
218 * causing all the finally's to execute and it will also set
219 * eventCode = None to indicate event handler has completed.
220 */
221 public void ApiReset()
222 {
223 ClearQueueExceptLinkMessages();
224 throw new ScriptResetException();
225 }
226
227 /**
228 * @brief The script is calling one of the llDetected...(int number)
229 * functions. Return corresponding DetectParams pointer.
230 */
231 public DetectParams GetDetectParams(int number)
232 {
233 DetectParams dp = null;
234 if ((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length)) {
235 dp = m_DetectParams[number];
236 }
237 return dp;
238 }
239
240 /**
241 * @brief Script is calling llDie, so flag the run loop to delete script
242 * once we are off the microthread stack, and throw an exception
243 * to unwind the stack asap.
244 */
245 public void Die()
246 {
247 // llDie doesn't work in attachments!
248 if (m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
249 return;
250
251 throw new ScriptDieException();
252 }
253
254 /**
255 * @brief Called by script to sleep for the given number of milliseconds.
256 */
257 public void Sleep(int ms)
258 {
259 lock (m_QueueLock) {
260
261 /*
262 * Say how long to sleep.
263 */
264 m_SleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(ms);
265
266 /*
267 * Don't wake on any events.
268 */
269 m_SleepEventMask1 = 0;
270 m_SleepEventMask2 = 0;
271 }
272
273 /*
274 * The compiler follows all calls to llSleep() with a call to CheckRun().
275 * So tell CheckRun() to suspend the microthread.
276 */
277 suspendOnCheckRunTemp = true;
278 }
279
280 /**
281 * Block script execution until an event is queued or a timeout is reached.
282 * @param timeout = maximum number of seconds to wait
283 * @param returnMask = if event is queued that matches these mask bits,
284 * the script is woken, that event is dequeued and
285 * returned to the caller. The event handler is not
286 * executed.
287 * @param backgroundMask = if any of these events are queued while waiting,
288 * execute their event handlers. When any such event
289 * handler exits, continue waiting for events or the
290 * timeout.
291 * @returns empty list: no event was queued that matched returnMask and the timeout was reached
292 * or a background event handler changed state (eg, via 'state' statement)
293 * else: list giving parameters of the event:
294 * [0] = event code (integer)
295 * [1..n] = call parameters to the event, if any
296 * Notes:
297 * 1) Scrips should use XMREVENTMASKn_<eventname> symbols for the mask arguments,
298 * where n is 1 or 2 for mask1 or mask2 arguments.
299 * The list[0] return argument can be decoded by using XMREVENTCODE_<eventname> symbols.
300 * 2) If all masks are zero, the call ends up acting like llSleep.
301 * 3) If an event is enabled in both returnMask and backgroundMask, the returnMask bit
302 * action takes precedence, ie, the event is returned. This allows a simple specification
303 * of -1 for both backgroundMask arguments to indicate that all events not listed in
304 * the returnMask argumetns should be handled in the background.
305 * 4) Any events not listed in either returnMask or backgroundMask arguments will be
306 * queued for later processing (subject to normal queue limits).
307 * 5) Background event handlers execute as calls from within xmrEventDequeue, they do
308 * not execute as separate threads. Thus any background event handlers must return
309 * before the call to xmrEventDequeue will return.
310 * 6) If a background event handler changes state (eg, via 'state' statement), the state
311 * is immediately changed and the script-level xmrEventDequeue call does not return.
312 * 7) For returned events, the detect parameters are overwritten by the returned event.
313 * For background events, the detect parameters are saved and restored.
314 * 8) Scripts must contain dummy event handler definitions for any event types that may
315 * be returned by xmrEventDequeue, to let the runtime know that the script is capable
316 * of processing that event type. Otherwise, the event may not be queued to the script.
317 */
318 private static LSL_List emptyList = new LSL_List (new object[0]);
319
320 public override LSL_List xmrEventDequeue (double timeout, int returnMask1, int returnMask2,
321 int backgroundMask1, int backgroundMask2)
322 {
323 DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds (timeout * 1000.0);
324 EventParams evt = null;
325 int callNo, evc2;
326 int evc1 = 0;
327 int mask1 = returnMask1 | backgroundMask1; // codes 00..31
328 int mask2 = returnMask2 | backgroundMask2; // codes 32..63
329 LinkedListNode<EventParams> lln = null;
330 object[] sv;
331 ScriptEventCode evc = ScriptEventCode.None;
332
333 callNo = -1;
334 try {
335 if (callMode == CallMode_NORMAL) goto findevent;
336
337 /*
338 * Stack frame is being restored as saved via CheckRun...().
339 * Restore necessary values then jump to __call<n> label to resume processing.
340 */
341 sv = RestoreStackFrame ("xmrEventDequeue", out callNo);
342 sleepUntil = DateTime.Parse ((string)sv[0]);
343 returnMask1 = (int)sv[1];
344 returnMask2 = (int)sv[2];
345 mask1 = (int)sv[3];
346 mask2 = (int)sv[4];
347 switch (callNo) {
348 case 0: goto __call0;
349 case 1: {
350 evc1 = (int)sv[5];
351 evc = (ScriptEventCode)(int)sv[6];
352 DetectParams[] detprms = ObjArrToDetPrms ((object[])sv[7]);
353 object[] ehargs = (object[])sv[8];
354 evt = new EventParams (evc.ToString (), ehargs, detprms);
355 goto __call1;
356 }
357 }
358 throw new ScriptBadCallNoException (callNo);
359
360 /*
361 * Find first event that matches either the return or background masks.
362 */
363 findevent:
364 Monitor.Enter (m_QueueLock);
365 for (lln = m_EventQueue.First; lln != null; lln = lln.Next) {
366 evt = lln.Value;
367 evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), evt.EventName);
368 evc1 = (int)evc;
369 evc2 = evc1 - 32;
370 if ((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
371 (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0))) goto remfromq;
372 }
373
374 /*
375 * Nothing found, sleep while one comes in.
376 */
377 m_SleepUntil = sleepUntil;
378 m_SleepEventMask1 = mask1;
379 m_SleepEventMask2 = mask2;
380 Monitor.Exit (m_QueueLock);
381 suspendOnCheckRunTemp = true;
382 callNo = 0;
383 __call0:
384 CheckRunQuick ();
385 goto checktmo;
386
387 /*
388 * Found one, remove it from queue.
389 */
390 remfromq:
391 m_EventQueue.Remove (lln);
392 if ((uint)evc1 < (uint)m_EventCounts.Length) {
393 m_EventCounts[evc1] --;
394 }
395 Monitor.Exit (m_QueueLock);
396 m_InstEHEvent ++;
397
398 /*
399 * See if returnable or background event.
400 */
401 if ((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
402 (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0))) {
403
404 /*
405 * Returnable event, return its parameters in a list.
406 * Also set the detect parameters to what the event has.
407 */
408 int plen = evt.Params.Length;
409 object[] plist = new object[plen+1];
410 plist[0] = (LSL_Integer)evc1;
411 for (int i = 0; i < plen;) {
412 object ob = evt.Params[i];
413 if (ob is int) ob = (LSL_Integer)(int)ob;
414 else if (ob is double) ob = (LSL_Float)(double)ob;
415 else if (ob is string) ob = (LSL_String)(string)ob;
416 plist[++i] = ob;
417 }
418 m_DetectParams = evt.DetectParams;
419 return new LSL_List (plist);
420 }
421
422 /*
423 * It is a background event, simply call its event handler,
424 * then check event queue again.
425 */
426 callNo = 1;
427 __call1:
428 ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc1];
429 if (seh == null) goto checktmo;
430
431 DetectParams[] saveDetParams = this.m_DetectParams;
432 object[] saveEHArgs = this.ehArgs;
433 ScriptEventCode saveEventCode = this.eventCode;
434
435 this.m_DetectParams = evt.DetectParams;
436 this.ehArgs = evt.Params;
437 this.eventCode = evc;
438
439 try {
440 seh (this);
441 } finally {
442 this.m_DetectParams = saveDetParams;
443 this.ehArgs = saveEHArgs;
444 this.eventCode = saveEventCode;
445 }
446
447 /*
448 * Keep waiting until we find a returnable event or timeout.
449 */
450 checktmo:
451 if (DateTime.UtcNow < sleepUntil) goto findevent;
452
453 /*
454 * We timed out, return an empty list.
455 */
456 return emptyList;
457 } finally {
458 if (callMode != CallMode_NORMAL) {
459
460 /*
461 * Stack frame is being saved by CheckRun...().
462 * Save everything we need at the __call<n> labels so we can restore it
463 * when we need to.
464 */
465 sv = CaptureStackFrame ("xmrEventDequeue", callNo, 9);
466 sv[0] = sleepUntil.ToString (); // needed at __call0,__call1
467 sv[1] = returnMask1; // needed at __call0,__call1
468 sv[2] = returnMask2; // needed at __call0,__call1
469 sv[3] = mask1; // needed at __call0,__call1
470 sv[4] = mask2; // needed at __call0,__call1
471 if (callNo == 1) {
472 sv[5] = evc1; // needed at __call1
473 sv[6] = (int)evc; // needed at __call1
474 sv[7] = DetPrmsToObjArr (evt.DetectParams); // needed at __call1
475 sv[8] = evt.Params; // needed at __call1
476 }
477 }
478 }
479 }
480
481 /**
482 * @brief Enqueue an event
483 * @param ev = as returned by xmrEventDequeue saying which event type to queue
484 * and what argument list to pass to it. The llDetect...() parameters
485 * are as currently set for the script (use xmrEventLoadDets to set how
486 * you want them to be different).
487 */
488 public override void xmrEventEnqueue (LSL_List ev)
489 {
490 object[] data = ev.Data;
491 ScriptEventCode evc = (ScriptEventCode)ListInt (data[0]);
492
493 int nargs = data.Length - 1;
494 object[] args = new object[nargs];
495 Array.Copy (data, 1, args, 0, nargs);
496
497 PostEvent (new EventParams (evc.ToString (), args, m_DetectParams));
498 }
499
500 /**
501 * @brief Save current detect params into a list
502 * @returns a list containing current detect param values
503 */
504 private const int saveDPVer = 1;
505
506 public override LSL_List xmrEventSaveDets ()
507 {
508 object[] obs = DetPrmsToObjArr (m_DetectParams);
509 return new LSL_List (obs);
510 }
511
512 private static object[] DetPrmsToObjArr (DetectParams[] dps)
513 {
514 int len = dps.Length;
515 object[] obs = new object[len*16+1];
516 int j = 0;
517 obs[j++] = (LSL_Integer)saveDPVer;
518 for (int i = 0; i < len; i ++) {
519 DetectParams dp = dps[i];
520 obs[j++] = (LSL_String)dp.Key.ToString(); // UUID
521 obs[j++] = dp.OffsetPos; // vector
522 obs[j++] = (LSL_Integer)dp.LinkNum; // integer
523 obs[j++] = (LSL_String)dp.Group.ToString(); // UUID
524 obs[j++] = (LSL_String)dp.Name; // string
525 obs[j++] = (LSL_String)dp.Owner.ToString(); // UUID
526 obs[j++] = dp.Position; // vector
527 obs[j++] = dp.Rotation; // rotation
528 obs[j++] = (LSL_Integer)dp.Type; // integer
529 obs[j++] = dp.Velocity; // vector
530 obs[j++] = dp.TouchST; // vector
531 obs[j++] = dp.TouchNormal; // vector
532 obs[j++] = dp.TouchBinormal; // vector
533 obs[j++] = dp.TouchPos; // vector
534 obs[j++] = dp.TouchUV; // vector
535 obs[j++] = (LSL_Integer)dp.TouchFace; // integer
536 }
537 return obs;
538 }
539
540
541 /**
542 * @brief Load current detect params from a list
543 * @param dpList = as returned by xmrEventSaveDets()
544 */
545 public override void xmrEventLoadDets (LSL_List dpList)
546 {
547 m_DetectParams = ObjArrToDetPrms (dpList.Data);
548 }
549
550 private static DetectParams[] ObjArrToDetPrms (object[] objs)
551 {
552 int j = 0;
553 if ((objs.Length % 16 != 1) || (ListInt (objs[j++]) != saveDPVer)) {
554 throw new Exception ("invalid detect param format");
555 }
556
557 int len = objs.Length / 16;
558 DetectParams[] dps = new DetectParams[len];
559
560 for (int i = 0; i < len; i ++) {
561 DetectParams dp = new DetectParams ();
562
563 dp.Key = new UUID (ListStr (objs[j++]));
564 dp.OffsetPos = (LSL_Vector)objs[j++];
565 dp.LinkNum = ListInt (objs[j++]);
566 dp.Group = new UUID (ListStr (objs[j++]));
567 dp.Name = ListStr (objs[j++]);
568 dp.Owner = new UUID (ListStr (objs[j++]));
569 dp.Position = (LSL_Vector)objs[j++];
570 dp.Rotation = (LSL_Rotation)objs[j++];
571 dp.Type = ListInt (objs[j++]);
572 dp.Velocity = (LSL_Vector)objs[j++];
573
574 SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs ();
575
576 stea.STCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]);
577 stea.Normal = LSLVec2OMVec ((LSL_Vector)objs[j++]);
578 stea.Binormal = LSLVec2OMVec ((LSL_Vector)objs[j++]);
579 stea.Position = LSLVec2OMVec ((LSL_Vector)objs[j++]);
580 stea.UVCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]);
581 stea.FaceIndex = ListInt (objs[j++]);
582
583 dp.SurfaceTouchArgs = stea;
584
585 dps[i] = dp;
586 }
587
588 return dps;
589 }
590
591 /**
592 * @brief The script is executing a 'state <newState>;' command.
593 * Tell outer layers to cancel any event triggers, like llListen(),
594 * then tell outer layers which events the new state has handlers for.
595 * We also clear the event queue as per http://wiki.secondlife.com/wiki/State
596 */
597 public override void StateChange()
598 {
599 /*
600 * Cancel any llListen()s etc.
601 * But llSetTimerEvent() should persist.
602 */
603 object[] timers = m_XMRLSLApi.acm.TimerPlugin.GetSerializationData(m_ItemID);
604 AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
605 m_XMRLSLApi.acm.TimerPlugin.CreateFromData(m_LocalID, m_ItemID, UUID.Zero, timers);
606
607 /*
608 * Tell whoever cares which event handlers the new state has.
609 */
610 m_Part.SetScriptEvents(m_ItemID, GetStateEventFlags(stateCode));
611
612 /*
613 * Clear out any old events from the queue.
614 */
615 lock (m_QueueLock) {
616 m_EventQueue.Clear();
617 for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0;
618 }
619 }
620
621 /**
622 * @brief Script is calling xmrStackLeft().
623 */
624 public override int xmrStackLeft ()
625 {
626 return microthread.StackLeft ();
627 }
628 }
629
630 /**
631 * @brief Thrown by things like llResetScript() to unconditionally
632 * unwind as script and reset it to the default state_entry
633 * handler. We don't want script-level try/catch to intercept
634 * these so scripts can't interfere with the behavior.
635 */
636 public class ScriptResetException : Exception, IXMRUncatchable { }
637
638 /**
639 * @brief Thrown by things like llDie() to unconditionally unwind as
640 * script. We don't want script-level try/catch to intercept
641 * these so scripts can't interfere with the behavior.
642 */
643 public class ScriptDieException : Exception, IXMRUncatchable { }
644}