XMRInstBackend.cs 28 KB

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