XMRInstBackend.cs 29 KB

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