aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs619
1 files changed, 619 insertions, 0 deletions
diff --git a/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs
new file mode 100644
index 0000000..833211f
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/YEngine/XMRInstBackend.cs
@@ -0,0 +1,619 @@
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.Yengine
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 // Say how long to sleep.
253 m_SleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(ms);
254
255 // Don't wake on any events.
256 m_SleepEventMask1 = 0;
257 m_SleepEventMask2 = 0;
258 }
259
260 // The compiler follows all calls to llSleep() with a call to CheckRun().
261 // So tell CheckRun() to suspend the microthread.
262 suspendOnCheckRunTemp = true;
263 }
264
265 /**
266 * Block script execution until an event is queued or a timeout is reached.
267 * @param timeout = maximum number of seconds to wait
268 * @param returnMask = if event is queued that matches these mask bits,
269 * the script is woken, that event is dequeued and
270 * returned to the caller. The event handler is not
271 * executed.
272 * @param backgroundMask = if any of these events are queued while waiting,
273 * execute their event handlers. When any such event
274 * handler exits, continue waiting for events or the
275 * timeout.
276 * @returns empty list: no event was queued that matched returnMask and the timeout was reached
277 * or a background event handler changed state (eg, via 'state' statement)
278 * else: list giving parameters of the event:
279 * [0] = event code (integer)
280 * [1..n] = call parameters to the event, if any
281 * Notes:
282 * 1) Scrips should use XMREVENTMASKn_<eventname> symbols for the mask arguments,
283 * where n is 1 or 2 for mask1 or mask2 arguments.
284 * The list[0] return argument can be decoded by using XMREVENTCODE_<eventname> symbols.
285 * 2) If all masks are zero, the call ends up acting like llSleep.
286 * 3) If an event is enabled in both returnMask and backgroundMask, the returnMask bit
287 * action takes precedence, ie, the event is returned. This allows a simple specification
288 * of -1 for both backgroundMask arguments to indicate that all events not listed in
289 * the returnMask argumetns should be handled in the background.
290 * 4) Any events not listed in either returnMask or backgroundMask arguments will be
291 * queued for later processing (subject to normal queue limits).
292 * 5) Background event handlers execute as calls from within xmrEventDequeue, they do
293 * not execute as separate threads. Thus any background event handlers must return
294 * before the call to xmrEventDequeue will return.
295 * 6) If a background event handler changes state (eg, via 'state' statement), the state
296 * is immediately changed and the script-level xmrEventDequeue call does not return.
297 * 7) For returned events, the detect parameters are overwritten by the returned event.
298 * For background events, the detect parameters are saved and restored.
299 * 8) Scripts must contain dummy event handler definitions for any event types that may
300 * be returned by xmrEventDequeue, to let the runtime know that the script is capable
301 * of processing that event type. Otherwise, the event may not be queued to the script.
302 */
303 private static LSL_List emptyList = new LSL_List(new object[0]);
304
305 public override LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
306 int backgroundMask1, int backgroundMask2)
307 {
308 DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
309 EventParams evt = null;
310 int callNo, evc2;
311 int evc1 = 0;
312 int mask1 = returnMask1 | backgroundMask1; // codes 00..31
313 int mask2 = returnMask2 | backgroundMask2; // codes 32..63
314 LinkedListNode<EventParams> lln = null;
315 object[] sv;
316 ScriptEventCode evc = ScriptEventCode.None;
317
318 callNo = -1;
319 try
320 {
321 if(callMode == CallMode_NORMAL)
322 goto findevent;
323
324 // Stack frame is being restored as saved via CheckRun...().
325 // Restore necessary values then jump to __call<n> label to resume processing.
326 sv = RestoreStackFrame("xmrEventDequeue", out callNo);
327 sleepUntil = DateTime.Parse((string)sv[0]);
328 returnMask1 = (int)sv[1];
329 returnMask2 = (int)sv[2];
330 mask1 = (int)sv[3];
331 mask2 = (int)sv[4];
332 switch(callNo)
333 {
334 case 0:
335 goto __call0;
336 case 1:
337 {
338 evc1 = (int)sv[5];
339 evc = (ScriptEventCode)(int)sv[6];
340 DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
341 object[] ehargs = (object[])sv[8];
342 evt = new EventParams(evc.ToString(), ehargs, detprms);
343 goto __call1;
344 }
345 }
346 throw new ScriptBadCallNoException(callNo);
347
348 // Find first event that matches either the return or background masks.
349 findevent:
350 Monitor.Enter(m_QueueLock);
351 for(lln = m_EventQueue.First; lln != null; lln = lln.Next)
352 {
353 evt = lln.Value;
354 evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
355 evc1 = (int)evc;
356 evc2 = evc1 - 32;
357 if((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
358 (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0)))
359 goto remfromq;
360 }
361
362 // Nothing found, sleep while one comes in.
363 m_SleepUntil = sleepUntil;
364 m_SleepEventMask1 = mask1;
365 m_SleepEventMask2 = mask2;
366 Monitor.Exit(m_QueueLock);
367 suspendOnCheckRunTemp = true;
368 callNo = 0;
369 __call0:
370 CheckRunQuick();
371 goto checktmo;
372
373 // Found one, remove it from queue.
374 remfromq:
375 m_EventQueue.Remove(lln);
376 if((uint)evc1 < (uint)m_EventCounts.Length)
377 m_EventCounts[evc1]--;
378
379 Monitor.Exit(m_QueueLock);
380 m_InstEHEvent++;
381
382 // See if returnable or background event.
383 if((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
384 (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0)))
385 {
386 // Returnable event, return its parameters in a list.
387 // Also set the detect parameters to what the event has.
388 int plen = evt.Params.Length;
389 object[] plist = new object[plen + 1];
390 plist[0] = (LSL_Integer)evc1;
391 for(int i = 0; i < plen;)
392 {
393 object ob = evt.Params[i];
394 if(ob is int)
395 ob = (LSL_Integer)(int)ob;
396 else if(ob is double)
397 ob = (LSL_Float)(double)ob;
398 else if(ob is string)
399 ob = (LSL_String)(string)ob;
400 plist[++i] = ob;
401 }
402 m_DetectParams = evt.DetectParams;
403 return new LSL_List(plist);
404 }
405
406 // It is a background event, simply call its event handler,
407 // then check event queue again.
408 callNo = 1;
409 __call1:
410 ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
411 if(seh == null)
412 goto checktmo;
413
414 DetectParams[] saveDetParams = this.m_DetectParams;
415 object[] saveEHArgs = this.ehArgs;
416 ScriptEventCode saveEventCode = this.eventCode;
417
418 this.m_DetectParams = evt.DetectParams;
419 this.ehArgs = evt.Params;
420 this.eventCode = evc;
421
422 try
423 {
424 seh(this);
425 }
426 finally
427 {
428 this.m_DetectParams = saveDetParams;
429 this.ehArgs = saveEHArgs;
430 this.eventCode = saveEventCode;
431 }
432
433 // Keep waiting until we find a returnable event or timeout.
434 checktmo:
435 if(DateTime.UtcNow < sleepUntil)
436 goto findevent;
437
438 // We timed out, return an empty list.
439 return emptyList;
440 }
441 finally
442 {
443 if(callMode != CallMode_NORMAL)
444 {
445 // Stack frame is being saved by CheckRun...().
446 // Save everything we need at the __call<n> labels so we can restore it
447 // when we need to.
448 sv = CaptureStackFrame("xmrEventDequeue", callNo, 9);
449 sv[0] = sleepUntil.ToString(); // needed at __call0,__call1
450 sv[1] = returnMask1; // needed at __call0,__call1
451 sv[2] = returnMask2; // needed at __call0,__call1
452 sv[3] = mask1; // needed at __call0,__call1
453 sv[4] = mask2; // needed at __call0,__call1
454 if(callNo == 1)
455 {
456 sv[5] = evc1; // needed at __call1
457 sv[6] = (int)evc; // needed at __call1
458 sv[7] = DetPrmsToObjArr(evt.DetectParams); // needed at __call1
459 sv[8] = evt.Params; // needed at __call1
460 }
461 }
462 }
463 }
464
465 /**
466 * @brief Enqueue an event
467 * @param ev = as returned by xmrEventDequeue saying which event type to queue
468 * and what argument list to pass to it. The llDetect...() parameters
469 * are as currently set for the script (use xmrEventLoadDets to set how
470 * you want them to be different).
471 */
472 public override void xmrEventEnqueue(LSL_List ev)
473 {
474 object[] data = ev.Data;
475 ScriptEventCode evc = (ScriptEventCode)ListInt(data[0]);
476
477 int nargs = data.Length - 1;
478 object[] args = new object[nargs];
479 Array.Copy(data, 1, args, 0, nargs);
480
481 PostEvent(new EventParams(evc.ToString(), args, m_DetectParams));
482 }
483
484 /**
485 * @brief Save current detect params into a list
486 * @returns a list containing current detect param values
487 */
488 private const int saveDPVer = 1;
489
490 public override LSL_List xmrEventSaveDets()
491 {
492 object[] obs = DetPrmsToObjArr(m_DetectParams);
493 return new LSL_List(obs);
494 }
495
496 private static object[] DetPrmsToObjArr(DetectParams[] dps)
497 {
498 int len = dps.Length;
499 object[] obs = new object[len * 16 + 1];
500 int j = 0;
501 obs[j++] = (LSL_Integer)saveDPVer;
502 for(int i = 0; i < len; i++)
503 {
504 DetectParams dp = dps[i];
505 obs[j++] = (LSL_String)dp.Key.ToString(); // UUID
506 obs[j++] = dp.OffsetPos; // vector
507 obs[j++] = (LSL_Integer)dp.LinkNum; // integer
508 obs[j++] = (LSL_String)dp.Group.ToString(); // UUID
509 obs[j++] = (LSL_String)dp.Name; // string
510 obs[j++] = (LSL_String)dp.Owner.ToString(); // UUID
511 obs[j++] = dp.Position; // vector
512 obs[j++] = dp.Rotation; // rotation
513 obs[j++] = (LSL_Integer)dp.Type; // integer
514 obs[j++] = dp.Velocity; // vector
515 obs[j++] = dp.TouchST; // vector
516 obs[j++] = dp.TouchNormal; // vector
517 obs[j++] = dp.TouchBinormal; // vector
518 obs[j++] = dp.TouchPos; // vector
519 obs[j++] = dp.TouchUV; // vector
520 obs[j++] = (LSL_Integer)dp.TouchFace; // integer
521 }
522 return obs;
523 }
524
525 /**
526 * @brief Load current detect params from a list
527 * @param dpList = as returned by xmrEventSaveDets()
528 */
529 public override void xmrEventLoadDets(LSL_List dpList)
530 {
531 m_DetectParams = ObjArrToDetPrms(dpList.Data);
532 }
533
534 private static DetectParams[] ObjArrToDetPrms(object[] objs)
535 {
536 int j = 0;
537 if((objs.Length % 16 != 1) || (ListInt(objs[j++]) != saveDPVer))
538 throw new Exception("invalid detect param format");
539
540 int len = objs.Length / 16;
541 DetectParams[] dps = new DetectParams[len];
542
543 for(int i = 0; i < len; i++)
544 {
545 DetectParams dp = new DetectParams();
546
547 dp.Key = new UUID(ListStr(objs[j++]));
548 dp.OffsetPos = (LSL_Vector)objs[j++];
549 dp.LinkNum = ListInt(objs[j++]);
550 dp.Group = new UUID(ListStr(objs[j++]));
551 dp.Name = ListStr(objs[j++]);
552 dp.Owner = new UUID(ListStr(objs[j++]));
553 dp.Position = (LSL_Vector)objs[j++];
554 dp.Rotation = (LSL_Rotation)objs[j++];
555 dp.Type = ListInt(objs[j++]);
556 dp.Velocity = (LSL_Vector)objs[j++];
557
558 SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs();
559
560 stea.STCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
561 stea.Normal = LSLVec2OMVec((LSL_Vector)objs[j++]);
562 stea.Binormal = LSLVec2OMVec((LSL_Vector)objs[j++]);
563 stea.Position = LSLVec2OMVec((LSL_Vector)objs[j++]);
564 stea.UVCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
565 stea.FaceIndex = ListInt(objs[j++]);
566
567 dp.SurfaceTouchArgs = stea;
568
569 dps[i] = dp;
570 }
571 return dps;
572 }
573
574 /**
575 * @brief The script is executing a 'state <newState>;' command.
576 * Tell outer layers to cancel any event triggers, like llListen(),
577 * then tell outer layers which events the new state has handlers for.
578 * We also clear the event queue as per http://wiki.secondlife.com/wiki/State
579 */
580 public override void StateChange()
581 {
582 // Cancel any llListen()s etc.
583 // But llSetTimerEvent() should persist.
584 object[] timers = m_XMRLSLApi.acm.TimerPlugin.GetSerializationData(m_ItemID);
585 AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
586 m_XMRLSLApi.acm.TimerPlugin.CreateFromData(m_LocalID, m_ItemID, UUID.Zero, timers);
587
588 // Tell whoever cares which event handlers the new state has.
589 m_Part.SetScriptEvents(m_ItemID, GetStateEventFlags(stateCode));
590
591 // Clear out any old events from the queue.
592 lock(m_QueueLock)
593 {
594 m_EventQueue.Clear();
595 for(int i = m_EventCounts.Length; --i >= 0;)
596 m_EventCounts[i] = 0;
597 }
598 }
599 }
600
601 /**
602 * @brief Thrown by things like llResetScript() to unconditionally
603 * unwind as script and reset it to the default state_entry
604 * handler. We don't want script-level try/catch to intercept
605 * these so scripts can't interfere with the behavior.
606 */
607 public class ScriptResetException: Exception, IXMRUncatchable
608 {
609 }
610
611 /**
612 * @brief Thrown by things like llDie() to unconditionally unwind as
613 * script. We don't want script-level try/catch to intercept
614 * these so scripts can't interfere with the behavior.
615 */
616 public class ScriptDieException: Exception, IXMRUncatchable
617 {
618 }
619}