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