123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Threading;
- using System.Collections.Generic;
- using OpenMetaverse;
- using OpenSim.Framework;
- using OpenSim.Region.ScriptEngine.Shared;
- using OpenSim.Region.ScriptEngine.Shared.Api;
- using log4net;
- using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
- using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
- using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
- using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
- using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
- using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
- using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
- namespace OpenSim.Region.ScriptEngine.Yengine
- {
- /****************************************************\
- * This file contains routines called by scripts. *
- \****************************************************/
- public class XMRLSL_Api: LSL_Api
- {
- public AsyncCommandManager acm;
- private XMRInstance inst;
- public void InitXMRLSLApi(XMRInstance i)
- {
- acm = AsyncCommands;
- inst = i;
- }
- protected override void ScriptSleep(int ms)
- {
- ms = (int)(ms * m_ScriptDelayFactor);
- if (ms < 10)
- return;
- inst.Sleep(ms);
- }
- public override void llSleep(double sec)
- {
- inst.Sleep((int)(sec * 1000.0));
- }
- public override void llDie()
- {
- inst.Die();
- }
- /**
- * @brief Seat avatar on prim.
- * @param owner = true: owner of prim script is running in
- * false: avatar that has given ANIMATION permission on the prim
- * @returns 0: successful
- * -1: no permission to animate
- * -2: no av granted perms
- * -3: av not in region
- */
- /* engines should not have own API
- public int xmrSeatAvatar (bool owner)
- {
- // Get avatar to be seated and make sure they have given us ANIMATION permission
- UUID avuuid;
- if (owner) {
- avuuid = inst.m_Part.OwnerID;
- } else {
- if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
- return -1;
- }
- avuuid = m_item.PermsGranter;
- }
- if (avuuid == UUID.Zero) {
- return -2;
- }
- ScenePresence presence = World.GetScenePresence (avuuid);
- if (presence == null) {
- return -3;
- }
- // remoteClient = not used by ScenePresence.HandleAgentRequestSit()
- // agentID = not used by ScenePresence.HandleAgentRequestSit()
- // targetID = UUID of prim to sit on
- // offset = offset of sitting position
- presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
- return 0;
- }
- */
- /**
- * @brief llTeleportAgent() is broken in that if you pass it a landmark,
- * it still subjects the position to spawn points, as it always
- * calls RequestTeleportLocation() with TeleportFlags.ViaLocation.
- * See llTeleportAgent() and CheckAndAdjustTelehub().
- *
- * @param agent = what agent to teleport
- * @param landmark = inventory name or UUID of a landmark object
- * @param lookat = looking direction after teleport
- */
- /* engines should not have own API
- public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
- {
- // find out about agent to be teleported
- UUID agentId;
- if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
- ScenePresence presence = World.GetScenePresence (agentId);
- if (presence == null) throw new ApplicationException ("agent not present in scene");
- if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
- if (presence.IsGod) throw new ApplicationException ("agent is a god");
- // prim must be owned by land owner or prim must be attached to agent
- if (m_host.ParentGroup.AttachmentPoint == 0) {
- if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
- throw new ApplicationException ("prim not owned by land's owner");
- }
- } else {
- if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
- }
- // find landmark in inventory or by UUID
- UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
- if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
- // read it in and make sure it is a landmark
- AssetBase lma = World.AssetService.Get (assetID.ToString ());
- if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
- // parse the record
- AssetLandmark lm = new AssetLandmark (lma);
- // the regionhandle (based on region's world X,Y) might be out of date
- // re-read the handle so we can pass it to RequestTeleportLocation()
- var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
- if (region == null) throw new ApplicationException ("no such region");
- // finally ready to teleport
- World.RequestTeleportLocation (presence.ControllingClient,
- region.RegionHandle,
- lm.Position,
- lookat,
- (uint)TeleportFlags.ViaLandmark);
- }
- */
- /**
- * @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL.
- * Code modelled after llSetParcelMusicURL().
- * @param newurl = new URL to set (or "" to leave it alone)
- * @returns previous URL string
- */
- /* engines should not have own API
- public string xmrSetParcelMusicURLGroup (string newurl)
- {
- string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
- if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
- IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
- if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
- GroupRecord grouprec = igm.GetGroupRecord (groupname);
- if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
- GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
- if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
- ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
- if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
- string oldurl = land.GetMusicUrl ();
- if (oldurl == null) oldurl = "";
- if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
- return oldurl;
- }
- */
- }
- public partial class XMRInstance
- {
- /**
- * @brief The script is calling llReset().
- * We throw an exception to unwind the script out to its main
- * causing all the finally's to execute and it will also set
- * eventCode = None to indicate event handler has completed.
- */
- public void ApiReset()
- {
- // do not do llResetScript on entry
- if(eventCode == ScriptEventCode.state_entry && stateCode == 0)
- return;
- ClearQueueExceptLinkMessages();
- throw new ScriptResetException();
- }
- /**
- * @brief The script is calling one of the llDetected...(int number)
- * functions. Return corresponding DetectParams pointer.
- */
- public DetectParams GetDetectParams(int number)
- {
- DetectParams dp = null;
- if((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length))
- dp = m_DetectParams[number];
- return dp;
- }
- /**
- * @brief Script is calling llDie, so flag the run loop to delete script
- * once we are off the microthread stack, and throw an exception
- * to unwind the stack asap.
- */
- public void Die()
- {
- // llDie doesn't work in attachments!
- if(m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
- return;
- throw new ScriptDieException();
- }
- /**
- * @brief Called by script to sleep for the given number of milliseconds.
- */
- public void Sleep(int ms)
- {
- lock(m_QueueLock)
- {
- // Say how long to sleep.
- m_SleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(ms);
- // Don't wake on any events.
- m_SleepEventMask1 = 0;
- m_SleepEventMask2 = 0;
- }
- // The compiler follows all calls to llSleep() with a call to CheckRun().
- // So tell CheckRun() to suspend the microthread.
- suspendOnCheckRunTemp = true;
- }
- /**
- * Block script execution until an event is queued or a timeout is reached.
- * @param timeout = maximum number of seconds to wait
- * @param returnMask = if event is queued that matches these mask bits,
- * the script is woken, that event is dequeued and
- * returned to the caller. The event handler is not
- * executed.
- * @param backgroundMask = if any of these events are queued while waiting,
- * execute their event handlers. When any such event
- * handler exits, continue waiting for events or the
- * timeout.
- * @returns empty list: no event was queued that matched returnMask and the timeout was reached
- * or a background event handler changed state (eg, via 'state' statement)
- * else: list giving parameters of the event:
- * [0] = event code (integer)
- * [1..n] = call parameters to the event, if any
- * Notes:
- * 1) Scrips should use XMREVENTMASKn_<eventname> symbols for the mask arguments,
- * where n is 1 or 2 for mask1 or mask2 arguments.
- * The list[0] return argument can be decoded by using XMREVENTCODE_<eventname> symbols.
- * 2) If all masks are zero, the call ends up acting like llSleep.
- * 3) If an event is enabled in both returnMask and backgroundMask, the returnMask bit
- * action takes precedence, ie, the event is returned. This allows a simple specification
- * of -1 for both backgroundMask arguments to indicate that all events not listed in
- * the returnMask argumetns should be handled in the background.
- * 4) Any events not listed in either returnMask or backgroundMask arguments will be
- * queued for later processing (subject to normal queue limits).
- * 5) Background event handlers execute as calls from within xmrEventDequeue, they do
- * not execute as separate threads. Thus any background event handlers must return
- * before the call to xmrEventDequeue will return.
- * 6) If a background event handler changes state (eg, via 'state' statement), the state
- * is immediately changed and the script-level xmrEventDequeue call does not return.
- * 7) For returned events, the detect parameters are overwritten by the returned event.
- * For background events, the detect parameters are saved and restored.
- * 8) Scripts must contain dummy event handler definitions for any event types that may
- * be returned by xmrEventDequeue, to let the runtime know that the script is capable
- * of processing that event type. Otherwise, the event may not be queued to the script.
- */
- private static LSL_List emptyList = new LSL_List(new object[0]);
- public override LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
- int backgroundMask1, int backgroundMask2)
- {
- DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
- EventParams evt = null;
- int callNo, evc2;
- int evc1 = 0;
- int mask1 = returnMask1 | backgroundMask1; // codes 00..31
- int mask2 = returnMask2 | backgroundMask2; // codes 32..63
- LinkedListNode<EventParams> lln = null;
- object[] sv;
- ScriptEventCode evc = ScriptEventCode.None;
- callNo = -1;
- try
- {
- if(callMode == CallMode_NORMAL)
- goto findevent;
- // Stack frame is being restored as saved via CheckRun...().
- // Restore necessary values then jump to __call<n> label to resume processing.
- sv = RestoreStackFrame("xmrEventDequeue", out callNo);
- sleepUntil = DateTime.Parse((string)sv[0]);
- returnMask1 = (int)sv[1];
- returnMask2 = (int)sv[2];
- mask1 = (int)sv[3];
- mask2 = (int)sv[4];
- switch(callNo)
- {
- case 0:
- goto __call0;
- case 1:
- {
- evc1 = (int)sv[5];
- evc = (ScriptEventCode)(int)sv[6];
- DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
- object[] ehargs = (object[])sv[8];
- evt = new EventParams(evc.ToString(), ehargs, detprms);
- goto __call1;
- }
- }
- throw new ScriptBadCallNoException(callNo);
- // Find first event that matches either the return or background masks.
- findevent:
- Monitor.Enter(m_QueueLock);
- for(lln = m_EventQueue.First; lln != null; lln = lln.Next)
- {
- evt = lln.Value;
- evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
- evc1 = (int)evc;
- evc2 = evc1 - 32;
- if((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
- (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0)))
- goto remfromq;
- }
- // Nothing found, sleep while one comes in.
- m_SleepUntil = sleepUntil;
- m_SleepEventMask1 = mask1;
- m_SleepEventMask2 = mask2;
- Monitor.Exit(m_QueueLock);
- suspendOnCheckRunTemp = true;
- callNo = 0;
- __call0:
- CheckRunQuick();
- goto checktmo;
- // Found one, remove it from queue.
- remfromq:
- m_EventQueue.Remove(lln);
- if((uint)evc1 < (uint)m_EventCounts.Length)
- m_EventCounts[evc1]--;
- Monitor.Exit(m_QueueLock);
- m_InstEHEvent++;
- // See if returnable or background event.
- if((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
- (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0)))
- {
- // Returnable event, return its parameters in a list.
- // Also set the detect parameters to what the event has.
- int plen = evt.Params.Length;
- object[] plist = new object[plen + 1];
- plist[0] = (LSL_Integer)evc1;
- for(int i = 0; i < plen;)
- {
- object ob = evt.Params[i];
- if(ob is int)
- ob = (LSL_Integer)(int)ob;
- else if(ob is double)
- ob = (LSL_Float)(double)ob;
- else if(ob is string)
- ob = (LSL_String)(string)ob;
- plist[++i] = ob;
- }
- m_DetectParams = evt.DetectParams;
- return new LSL_List(plist);
- }
- // It is a background event, simply call its event handler,
- // then check event queue again.
- callNo = 1;
- __call1:
- ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
- if(seh == null)
- goto checktmo;
- DetectParams[] saveDetParams = this.m_DetectParams;
- object[] saveEHArgs = this.ehArgs;
- ScriptEventCode saveEventCode = this.eventCode;
- this.m_DetectParams = evt.DetectParams;
- this.ehArgs = evt.Params;
- this.eventCode = evc;
- try
- {
- seh(this);
- }
- finally
- {
- this.m_DetectParams = saveDetParams;
- this.ehArgs = saveEHArgs;
- this.eventCode = saveEventCode;
- }
- // Keep waiting until we find a returnable event or timeout.
- checktmo:
- if(DateTime.UtcNow < sleepUntil)
- goto findevent;
- // We timed out, return an empty list.
- return emptyList;
- }
- finally
- {
- if(callMode != CallMode_NORMAL)
- {
- // Stack frame is being saved by CheckRun...().
- // Save everything we need at the __call<n> labels so we can restore it
- // when we need to.
- sv = CaptureStackFrame("xmrEventDequeue", callNo, 9);
- sv[0] = sleepUntil.ToString(); // needed at __call0,__call1
- sv[1] = returnMask1; // needed at __call0,__call1
- sv[2] = returnMask2; // needed at __call0,__call1
- sv[3] = mask1; // needed at __call0,__call1
- sv[4] = mask2; // needed at __call0,__call1
- if(callNo == 1)
- {
- sv[5] = evc1; // needed at __call1
- sv[6] = (int)evc; // needed at __call1
- sv[7] = DetPrmsToObjArr(evt.DetectParams); // needed at __call1
- sv[8] = evt.Params; // needed at __call1
- }
- }
- }
- }
- /**
- * @brief Enqueue an event
- * @param ev = as returned by xmrEventDequeue saying which event type to queue
- * and what argument list to pass to it. The llDetect...() parameters
- * are as currently set for the script (use xmrEventLoadDets to set how
- * you want them to be different).
- */
- public override void xmrEventEnqueue(LSL_List ev)
- {
- object[] data = ev.Data;
- ScriptEventCode evc = (ScriptEventCode)ListInt(data[0]);
- int nargs = data.Length - 1;
- object[] args = new object[nargs];
- Array.Copy(data, 1, args, 0, nargs);
- PostEvent(new EventParams(evc.ToString(), args, m_DetectParams));
- }
- /**
- * @brief Save current detect params into a list
- * @returns a list containing current detect param values
- */
- private const int saveDPVer = 1;
- public override LSL_List xmrEventSaveDets()
- {
- object[] obs = DetPrmsToObjArr(m_DetectParams);
- return new LSL_List(obs);
- }
- private static object[] DetPrmsToObjArr(DetectParams[] dps)
- {
- int len = dps.Length;
- object[] obs = new object[len * 16 + 1];
- int j = 0;
- obs[j++] = (LSL_Integer)saveDPVer;
- for(int i = 0; i < len; i++)
- {
- DetectParams dp = dps[i];
- obs[j++] = (LSL_String)dp.Key.ToString(); // UUID
- obs[j++] = dp.OffsetPos; // vector
- obs[j++] = (LSL_Integer)dp.LinkNum; // integer
- obs[j++] = (LSL_String)dp.Group.ToString(); // UUID
- obs[j++] = (LSL_String)dp.Name; // string
- obs[j++] = (LSL_String)dp.Owner.ToString(); // UUID
- obs[j++] = dp.Position; // vector
- obs[j++] = dp.Rotation; // rotation
- obs[j++] = (LSL_Integer)dp.Type; // integer
- obs[j++] = dp.Velocity; // vector
- obs[j++] = dp.TouchST; // vector
- obs[j++] = dp.TouchNormal; // vector
- obs[j++] = dp.TouchBinormal; // vector
- obs[j++] = dp.TouchPos; // vector
- obs[j++] = dp.TouchUV; // vector
- obs[j++] = (LSL_Integer)dp.TouchFace; // integer
- }
- return obs;
- }
- /**
- * @brief Load current detect params from a list
- * @param dpList = as returned by xmrEventSaveDets()
- */
- public override void xmrEventLoadDets(LSL_List dpList)
- {
- m_DetectParams = ObjArrToDetPrms(dpList.Data);
- }
- private static DetectParams[] ObjArrToDetPrms(object[] objs)
- {
- int j = 0;
- if((objs.Length % 16 != 1) || (ListInt(objs[j++]) != saveDPVer))
- throw new Exception("invalid detect param format");
- int len = objs.Length / 16;
- DetectParams[] dps = new DetectParams[len];
- for(int i = 0; i < len; i++)
- {
- DetectParams dp = new DetectParams();
- dp.Key = new UUID(ListStr(objs[j++]));
- dp.OffsetPos = (LSL_Vector)objs[j++];
- dp.LinkNum = ListInt(objs[j++]);
- dp.Group = new UUID(ListStr(objs[j++]));
- dp.Name = ListStr(objs[j++]);
- dp.Owner = new UUID(ListStr(objs[j++]));
- dp.Position = (LSL_Vector)objs[j++];
- dp.Rotation = (LSL_Rotation)objs[j++];
- dp.Type = ListInt(objs[j++]);
- dp.Velocity = (LSL_Vector)objs[j++];
- SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs();
- stea.STCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
- stea.Normal = LSLVec2OMVec((LSL_Vector)objs[j++]);
- stea.Binormal = LSLVec2OMVec((LSL_Vector)objs[j++]);
- stea.Position = LSLVec2OMVec((LSL_Vector)objs[j++]);
- stea.UVCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
- stea.FaceIndex = ListInt(objs[j++]);
- dp.SurfaceTouchArgs = stea;
- dps[i] = dp;
- }
- return dps;
- }
- /**
- * @brief The script is executing a 'state <newState>;' command.
- * Tell outer layers to cancel any event triggers, like llListen(),
- * then tell outer layers which events the new state has handlers for.
- * We also clear the event queue as per http://wiki.secondlife.com/wiki/State
- */
- public override void StateChange()
- {
- // Cancel any llListen()s etc.
- // But llSetTimerEvent() should persist.
- object[] timers = m_XMRLSLApi.acm.TimerPlugin.GetSerializationData(m_ItemID);
- AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
- m_XMRLSLApi.acm.TimerPlugin.CreateFromData(m_LocalID, m_ItemID, UUID.Zero, timers);
- // Tell whoever cares which event handlers the new state has.
- m_Part.SetScriptEvents(m_ItemID, GetStateEventFlags(stateCode));
- // Clear out any old events from the queue.
- lock(m_QueueLock)
- {
- m_EventQueue.Clear();
- for(int i = m_EventCounts.Length; --i >= 0;)
- m_EventCounts[i] = 0;
- }
- }
- }
- /**
- * @brief Thrown by things like llResetScript() to unconditionally
- * unwind as script and reset it to the default state_entry
- * handler. We don't want script-level try/catch to intercept
- * these so scripts can't interfere with the behavior.
- */
- public class ScriptResetException: Exception, IXMRUncatchable
- {
- }
- /**
- * @brief Thrown by things like llDie() to unconditionally unwind as
- * script. We don't want script-level try/catch to intercept
- * these so scripts can't interfere with the behavior.
- */
- public class ScriptDieException: Exception, IXMRUncatchable
- {
- }
- }
|