XMRInstBackend.cs 28 KB

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