lsl-agent-scripts.tpl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. {{ define "lsl-agent-scripts" }}
  2. <p>These three scripts go inside a transparent box, worn by the agent's avatar.</p>
  3. <p>Copy the first code to a script called <code>register agent.lsl</code> and put it inside the transparent box. When the agent's avatar is rezzed, it will use this script to register with the engine, and be able to receive commands from it.</p>
  4. <pre><code class="language-javascript">// Handles agent registration with the external database
  5. // Send current configuration for agent class, subtype, and energy/money/happiness
  6. // On the first version it will only work in OpenSimulator and call osNPC functions
  7. string registrationURL = "http://{{.Host}}{{.ServerPort}}{{.URLPathPrefix}}/register-agent/";
  8. string externalURL; // this is what we'll get from SL to get incoming connections
  9. key registrationRequest; // used to track down the request for registration
  10. key httpRequestKey;
  11. string class = "peasant";
  12. string subtype = "publican";
  13. string home = ""; // place where NPC will return when energy exhausted
  14. float npcEnergy = 1.0; // start with max energy and happiness
  15. float npcMoney = 0.0; // but no money
  16. float npcHappiness = 1.0;
  17. integer LSLSignaturePIN = {{.LSLSignaturePIN}};
  18. init()
  19. {
  20. llSetObjectName("Bot Controller - " + llKey2Name(llGetOwner()));
  21. llSetText("Registering agent...", &lt;1.0,0.0,0.0&gt;, 1.0);
  22. llSay(0, "Registering agent...");
  23. // parse description field
  24. parseDescription();
  25. // make sure we release URLs before asking for a new one
  26. llReleaseURL(externalURL);
  27. externalURL = "";
  28. llRequestURL();
  29. }
  30. // parse description field, which contains the type of agent and the energy/money/happiness
  31. parseDescription()
  32. {
  33. list params = llParseString2List(llGetObjectDesc(), [";"], []);
  34. class = llList2String(params, 0);
  35. subtype = llList2String(params, 1);
  36. npcEnergy = llList2Float(params, 2);
  37. npcMoney = llList2Float(params, 3);
  38. npcHappiness = llList2Float(params, 4);
  39. home = llList2String(params, 5);
  40. updateSetText();
  41. }
  42. // save current parameters to object description and update floating text
  43. setDescription()
  44. {
  45. llSetObjectDesc(class + ";" + subtype + ";" +
  46. (string)npcEnergy + ";" +
  47. (string)npcMoney + ";" +
  48. (string)npcHappiness + ";" +
  49. home);
  50. updateSetText();
  51. }
  52. // update settext with energy, money, happiness
  53. updateSetText()
  54. {
  55. llSetText("Class: " + class +
  56. "\nSubType: " + subtype +
  57. "\nEnergy: " + (string)npcEnergy +
  58. "\nMoney: " + (string)npcMoney +
  59. "\nHappiness: " + (string)npcHappiness +
  60. "\nHome: " + home, &lt;npcEnergy,npcMoney,npcHappiness&gt;, 1.0);
  61. }
  62. default
  63. {
  64. state_entry()
  65. {
  66. parseDescription();
  67. llSetTimerEvent(3600.0); // this will hopefully force an update every hour
  68. }
  69. on_rez(integer what)
  70. {
  71. init();
  72. }
  73. attach(key avatar)
  74. {
  75. if (NULL_KEY != avatar)
  76. {
  77. init();
  78. }
  79. else
  80. {
  81. // NPC probably died. We cannot do anything about it, specially if it comes alive again with a different UUID.
  82. llSay(0, "Register Agent: Going awaaaaaaay...");
  83. }
  84. }
  85. touch_start(integer total_number)
  86. {
  87. // possibly this will allow to reconfigure the bot
  88. /*if (llDetectedKey(0) == llGetOwner() || llDetectedGroup(0) || )
  89. {*/
  90. updateSetText();
  91. init();
  92. /*}
  93. else
  94. {
  95. llSay(0, "Sorry " + llDetectedName(0) + ", you cannot reset this bot!");
  96. }*/
  97. }
  98. http_response(key request_id, integer status, list metadata, string body)
  99. {
  100. if (request_id == registrationRequest)
  101. {
  102. if (status == 200)
  103. {
  104. llSay(0, "Register Agent: [Registration request:] " + body);
  105. }
  106. else
  107. {
  108. llSetText("!!! BROKEN !!!", &lt;1.0,0.0,0.0&gt;, 1.0);
  109. llSay(0, "Register Agent: Error " +(string)status + ": " + body);
  110. llSetTimerEvent(3600.0); // try again later
  111. }
  112. }
  113. }
  114. http_request(key id, string method, string body)
  115. {
  116. if (method == URL_REQUEST_GRANTED)
  117. {
  118. externalURL = body;
  119. string myTimestamp = llGetTimestamp();
  120. registrationRequest = llHTTPRequest(registrationURL, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],
  121. "permURL=" + llEscapeURL(externalURL)
  122. + "&subtype=" + llEscapeURL(subtype)
  123. + "&class=" + llEscapeURL(class)
  124. + "&energy=" + llEscapeURL((string)npcEnergy)
  125. + "&money=" + llEscapeURL((string)npcMoney)
  126. + "&happiness=" + llEscapeURL((string)npcHappiness)
  127. + "&home=" + llEscapeURL(home)
  128. + "&amp;timestamp=" + myTimestamp
  129. + "&signature=" + llMD5String((string)llGetKey() + myTimestamp, LSLSignaturePIN));
  130. llSetTimerEvent(3600.0); // if the registration fails, try later
  131. }
  132. else if (method == URL_REQUEST_DENIED)
  133. {
  134. llSetText("!!! BROKEN !!!", &lt;1.0,0.0,0.0&gt;, 1.0);
  135. llSay(0, "Register Agent: Something went wrong, no url. Error was: '" + body + "'");
  136. llSetTimerEvent(3600.0); // try again later
  137. }
  138. else if (method == "POST" || method == "GET")
  139. {
  140. // incoming request for bot to do things
  141. //llSay(0, "Register Agent: [Request from server:] " + body);
  142. list params = llParseStringKeepNulls(llUnescapeURL(body), ["&", "="], []);
  143. string response; // what we return
  144. key NPC = llGetOwner();
  145. //if (osIsNpc(NPC))
  146. // llSay(0, "Register Agent: Sanity check: This is an NPC with key " + (string)NPC);
  147. //else
  148. // llSay(0, "Register Agent: Sanity check failed: Key " + (string)NPC + " is NOT an NPC");
  149. // llOwnerSay("List parsed: " + (string) params);
  150. string command = llList2String(params, 1);
  151. if (llList2String(params, 0) == "command")
  152. {
  153. if (command == "osNpcGetRot")
  154. {
  155. response = (string)osNpcGetRot(NPC);
  156. }
  157. else if (command == "osNpcSetRot")
  158. {
  159. osNpcSetRot(NPC, llList2Rot(params, 3));
  160. response = "Rotation set.";
  161. }
  162. else if (command == "osNpcGetPos")
  163. {
  164. response = (string)osNpcGetPos(NPC);
  165. }
  166. else if (command == "osNpcGetOwner")
  167. {
  168. response = (string)osNpcGetOwner(NPC);
  169. }
  170. else if (command == "osNpcMoveToTarget")
  171. {
  172. osNpcMoveToTarget(NPC, llList2Vector(params, 3), llList2Integer(params, 5));
  173. response = "Moving to target " + llList2String(params, 3);
  174. }
  175. else if (command == "osNpcStopMoveToTarget")
  176. {
  177. osNpcStopMoveToTarget(NPC);
  178. response = "Stopping.";
  179. }
  180. else if (command == "osNpcSit")
  181. {
  182. osNpcSit(NPC, llList2Key(params, 3), llList2Integer(params, 5));
  183. response = "Sitting on " +
  184. llKey2Name(llList2Key(params, 3))
  185. + " (" + llList2Key(params, 3) + ").";
  186. }
  187. else if (command == "osNpcStand")
  188. {
  189. osNpcStand(NPC);
  190. response = "Standing up.";
  191. }
  192. else if (command == "osNpcSay")
  193. {
  194. osNpcSay(NPC, llList2Integer(params, 3), llUnescapeURL(llList2String(params, 5)));
  195. response = "Saying \"" +
  196. llUnescapeURL(llList2String(params, 5)) + "\".";
  197. }
  198. else if (command == "osNpcShout")
  199. {
  200. osNpcShout(NPC, llList2Integer(params, 3), llUnescapeURL(llList2String(params, 5)));
  201. response = "Shouting \"" +
  202. llUnescapeURL(llList2String(params, 5)) + "\".";
  203. }
  204. else if (command == "osNpcWhisper")
  205. {
  206. osNpcWhisper(NPC, llList2Integer(params, 3), llUnescapeURL(llList2String(params, 5)));
  207. response = "Whispering \"" +
  208. llUnescapeURL(llList2String(params, 5)) + "\".";
  209. }
  210. else if (command == "osNpcPlayAnimation")
  211. {
  212. osNpcPlayAnimation(NPC, llList2String(params, 3));
  213. response = "Playing animation \"" +
  214. llList2String(params, 3) + "\".";
  215. }
  216. else if (command == "osNpcStopAnimation")
  217. {
  218. osNpcStopAnimation(NPC, llList2String(params, 3));
  219. response = "Stopping animation \"" +
  220. llList2String(params, 3) + "\".";
  221. }
  222. else if (command == "osNpcLoadAppearance")
  223. {
  224. osNpcLoadAppearance(NPC, llList2String(params, 3));
  225. response = "Loading appearance \"" +
  226. llList2String(params, 3) + "\".";
  227. }
  228. else if (command == "osNpcTouch")
  229. {
  230. osNpcTouch(NPC, llList2Key(params, 3), llList2Integer(params, 5));
  231. response = "Touching " + llKey2Name(llList2Key(params, 3))
  232. + " (" + llList2Key(params, 3) + ").";
  233. }
  234. else if (command == "getMoney")
  235. {
  236. response = (string)npcMoney;
  237. }
  238. else if (command == "getHappiness")
  239. {
  240. response = (string)npcHappiness;
  241. }
  242. else if (command == "getEnergy")
  243. {
  244. response = (string)npcEnergy;
  245. }
  246. else if (command == "getHome")
  247. {
  248. response = home;
  249. }
  250. else if (command == "getClass")
  251. {
  252. response = class;
  253. }
  254. else if (command == "getSubType")
  255. {
  256. response = subtype;
  257. }
  258. else if (command == "setMoney")
  259. {
  260. npcMoney = llList2Float(params, 3);
  261. response = "Setting Money to: " + (string)npcMoney;
  262. setDescription();
  263. }
  264. else if (command == "setHappiness")
  265. {
  266. npcHappiness = llList2Float(params, 3);
  267. response = "Setting Happiness to: " + (string)npcHappiness;
  268. setDescription();
  269. }
  270. else if (command == "setEnergy")
  271. {
  272. npcEnergy = llList2Float(params, 3);
  273. response = "Setting Energy to: " + (string)npcEnergy;
  274. setDescription();
  275. }
  276. else if (command == "setHome")
  277. {
  278. home = llList2String(params, 3);
  279. response = "Setting Home to: " + home;
  280. setDescription();
  281. }
  282. else if (command == "setClass")
  283. {
  284. class = llList2String(params, 3);
  285. response = "Setting Class to: " + class;
  286. setDescription();
  287. }
  288. else if (command == "setSubType")
  289. {
  290. subtype = llList2String(params, 3);
  291. response = "Setting SubType to: " + subtype;
  292. setDescription();
  293. }
  294. else if (command == "ping")
  295. {
  296. response = "pong";
  297. }
  298. else
  299. {
  300. response = "";
  301. llHTTPResponse(id, 405, "Register Agent: Unknown engine command " + command + ".");
  302. }
  303. }
  304. if (response)
  305. {
  306. //llSay(0, "Register Agent: Sending back response to " +
  307. // command + " '" +
  308. // response + "'...");
  309. llHTTPResponse(id, 200, response);
  310. }
  311. else
  312. {
  313. llSay(0, "Register Agent: ERROR: No response or no command found!'" + command + "' found.");
  314. llHTTPResponse(id, 404, "No response or no command '" + command + "' found.");
  315. }
  316. }
  317. else
  318. {
  319. llHTTPResponse(id, 405, "Method '" + method + "' unsupported.");
  320. }
  321. }
  322. changed(integer c)
  323. {
  324. // Region changed, get a new PermURL
  325. if (c & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT | CHANGED_OWNER ) )
  326. {
  327. init();
  328. }
  329. }
  330. timer()
  331. {
  332. llSetText("Register Agent: Timed out, trying again to\nregister agent...", &lt;1.0,0.0,0.0&gt;, 1.0);
  333. llSetTimerEvent(0.0);
  334. init();
  335. }
  336. }
  337. </code></pre>
  338. <p>This next script will use llCastRay to try to figure out objects around the agent at a narrow scope. llCastRay will be a bit more precise to tell the avatar if it's an object really in front of them.</p>
  339. <p>Copy it, name it <code>llCastRay detector script 3.1.lsl</code> and drop it inside the transparent box as with the script before.</p>
  340. <pre><code class="language-javascript">
  341. // Version 3.1 (for GoBot)
  342. // Just based on object rotation
  343. // Thanks to Lucinda Bulloch for a *working* llCastRay() demo script!
  344. // includes sending it to external webserver
  345. // to-do: see where the missing info comes from!
  346. string sensorURL = "http://{{.Host}}{{.ServerPort}}{{.URLPathPrefix}}/update-sensor/";
  347. key sensorRequest;
  348. particles(key uuid)
  349. {
  350. // laser beam
  351. llParticleSystem([
  352. PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE,
  353. PSYS_SRC_BURST_PART_COUNT,(integer) 4, // adjust for beam strength,
  354. PSYS_SRC_BURST_RATE,(float) .05,
  355. PSYS_PART_MAX_AGE,(float) 1.2, // was .6
  356. PSYS_SRC_BURST_SPEED_MIN,(float)1,
  357. PSYS_SRC_BURST_SPEED_MAX,(float) 7.0,
  358. PSYS_PART_START_SCALE,(vector) &lt;0,.1,0&gt;,
  359. PSYS_PART_END_SCALE,(vector) &lt;.04,.5,0&gt;,
  360. PSYS_PART_START_COLOR,(vector) &lt;1,0,0&gt;,
  361. PSYS_PART_END_COLOR,(vector) &lt;.2,0,0&gt;,
  362. PSYS_PART_START_ALPHA,(float)0.5,
  363. PSYS_PART_END_ALPHA,(float)0.00,
  364. PSYS_SRC_TARGET_KEY, uuid,
  365. PSYS_PART_FLAGS,
  366. PSYS_PART_EMISSIVE_MASK |
  367. PSYS_PART_FOLLOW_VELOCITY_MASK |
  368. PSYS_PART_FOLLOW_SRC_MASK |
  369. PSYS_PART_INTERP_SCALE_MASK |
  370. PSYS_PART_TARGET_LINEAR_MASK ]
  371. );
  372. }
  373. detection()
  374. {
  375. vector start = llGetPos();
  376. // vector end = start + &lt;10.0, 0.0, 0.0&gt;*llGetCameraRot();
  377. vector end = start + &lt;10.0, 0.0, 0.0&gt;*llGetRot();
  378. // rotation camRot = llGetCameraRot();
  379. // vector camPos = llGetCameraPos();
  380. // to-do: point slightly downwards
  381. /*
  382. rotation objectRot = llGetRootRotation() * llEuler2Rot(&lt;0.0, -45.0 * DEG_TO_RAD, 0.0&gt;);
  383. rotation castRot = llGetRootRotation() * llEuler2Rot(&lt;0.0, 45.0 * DEG_TO_RAD, 0.0&gt;);
  384. llSetRot(objectRot);
  385. llOwnerSay("Debug: Object rot: " + (string) objectRot
  386. + " Root rot: " + (string) llGetRootRotation());
  387. // + " Camera rot: "
  388. // + (string) camRot + " Camera pos: " + (string) camPos);
  389. */
  390. // llSetLinkPrimitiveParamsFast(2, [PRIM_ROT_LOCAL, objectRot]); // set prim to point slightly downwards
  391. list results = llCastRay(start, end, [
  392. RC_DATA_FLAGS, RC_GET_ROOT_KEY,
  393. RC_REJECT_TYPES, RC_REJECT_LAND,
  394. RC_MAX_HITS, 50,
  395. RC_DETECT_PHANTOM, TRUE
  396. ]);
  397. integer statusCode = llList2Integer(results, -1);
  398. if (statusCode == RCERR_SIM_PERF_LOW)
  399. {
  400. llSay(0, "Sim performance low, cannot use llRayCast()");
  401. }
  402. else if (statusCode == RCERR_CAST_TIME_EXCEEDED)
  403. {
  404. llSay(0, "Too many raycasts");
  405. }
  406. else if (statusCode == RCERR_UNKNOWN)
  407. {
  408. llSay(0, "Unknown raycast error");
  409. }
  410. else
  411. {
  412. //llOwnerSay("Current rotation: " + (string)llGetRot());
  413. //llOwnerSay("Current camera rotation: " + (string)llGetCameraRot());
  414. //llOwnerSay("Detected: " + llDumpList2String(results, "|"));
  415. integer hitNum;
  416. for (hitNum = 0; hitNum < statusCode; hitNum++)
  417. {
  418. key uuid = llList2Key(results, 2*hitNum);
  419. vector pos = llList2Vector(results, 2*hitNum+1);
  420. float dist = llVecDist(start, pos);
  421. string name;
  422. if (uuid == NULL_KEY)
  423. {
  424. // llOwnerSay("Land at " + (string)dist + "m");
  425. }
  426. else if (uuid == llGetOwner())
  427. {
  428. // llOwnerSay("Self-detected; ignoring");
  429. }
  430. else
  431. {
  432. name = llKey2Name(uuid);
  433. //llOwnerSay(name + "<" + (string) uuid + "> at " + (string)dist + "m");
  434. particles(uuid);
  435. // get a few more details
  436. list objectDetailsList = llGetObjectDetails(uuid, [ OBJECT_ROT, OBJECT_VELOCITY, OBJECT_CREATOR, OBJECT_PHANTOM, OBJECT_PRIM_EQUIVALENCE]);
  437. string type;
  438. // test if it is an avatar or an object
  439. if (llList2Key(objectDetailsList, 2) == NULL_KEY) // avatars have no creator!
  440. {
  441. type = "1";
  442. }
  443. else
  444. {
  445. type = "12"; // not entirely correct but ok; more checks are needed to figure out the exact type
  446. }
  447. // now get the bounding box too
  448. list boundingBox = llGetBoundingBox(uuid);
  449. // Sending remotely
  450. sensorRequest = llHTTPRequest(sensorURL +
  451. "?key=" + (string)uuid +
  452. "&name=" + name +
  453. "&pos=" + (string)pos +
  454. "&rot=" + llList2String(objectDetailsList, 0) +
  455. "&vel=" + llList2String(objectDetailsList, 1) +
  456. "&phantom=" + llList2String(objectDetailsList, 3) +
  457. "&prims=" + llList2String(objectDetailsList, 4) +
  458. "&bblo=" + llList2String(boundingBox, 0) +
  459. "&bbhi=" + llList2String(boundingBox, 1) +
  460. "&type=" + type +
  461. "&origin=castray" +
  462. "&amp;timestamp=" + llGetTimestamp(),
  463. [HTTP_METHOD, "GET"], "");
  464. }
  465. }
  466. }
  467. }
  468. default
  469. {
  470. state_entry()
  471. {
  472. // llRequestPermissions(llGetOwner(), PERMISSION_CONTROL_CAMERA|PERMISSION_TRACK_CAMERA);
  473. llClearCameraParams();
  474. llSetTimerEvent(5.0);
  475. }
  476. state_exit()
  477. {
  478. llParticleSystem([]);
  479. }
  480. on_rez(integer start_param)
  481. {
  482. llResetScript();
  483. }
  484. attach(key id)
  485. {
  486. if (id == llGetOwner())
  487. {
  488. // llRequestPermissions(id, PERMISSION_TAKE_CONTROLS|PERMISSION_TRACK_CAMERA);
  489. llResetScript();
  490. }
  491. else
  492. {
  493. llParticleSystem([]);
  494. // llReleaseControls();
  495. }
  496. }
  497. run_time_permissions(integer perm)
  498. {
  499. if (perm & PERMISSION_CONTROL_CAMERA)
  500. {
  501. llClearCameraParams();
  502. llSetTimerEvent(5.0);
  503. /* llSetCameraParams([
  504. CAMERA_ACTIVE, 1, // 1 is active, 0 is inactive
  505. CAMERA_BEHINDNESS_ANGLE, 0.0, // (0 to 180) degrees was 45
  506. CAMERA_BEHINDNESS_LAG, 0.0, // (0 to 3) seconds was 0.5
  507. CAMERA_DISTANCE, 0.5, // ( 0.5 to 10) meters was 8
  508. //CAMERA_FOCUS, &lt;0,0,5&gt;, // region relative position
  509. CAMERA_FOCUS_LAG, 0.0 , // (0 to 3) seconds was 0.05
  510. CAMERA_FOCUS_LOCKED, FALSE, // (TRUE or FALSE)
  511. CAMERA_FOCUS_THRESHOLD, 0.0, // (0 to 4) meters
  512. CAMERA_PITCH, 0.0, // (-45 to 80) degrees was 20
  513. //CAMERA_POSITION, &lt;0,0,0&gt;, // region relative position
  514. CAMERA_POSITION_LAG, 0.1, // (0 to 3) seconds
  515. CAMERA_POSITION_LOCKED, FALSE, // (TRUE or FALSE)
  516. CAMERA_POSITION_THRESHOLD, 0.0, // (0 to 4) meters
  517. CAMERA_FOCUS_OFFSET, &lt;1.0,0.0,1.0&gt; // &lt;-10,-10,-10&gt; to &lt;10,10,10&gt; meters was 3,0,2
  518. ]);
  519. */
  520. }
  521. }
  522. touch(integer who)
  523. {
  524. if (llDetectedKey(0) == llGetOwner())
  525. {
  526. llParticleSystem([]);
  527. detection();
  528. }
  529. }
  530. timer()
  531. {
  532. llParticleSystem([]);
  533. //llOwnerSay("Timer" + llGetTimestamp());
  534. detection();
  535. }
  536. http_response(key request_id, integer status, list metadata, string body)
  537. {
  538. if (request_id == sensorRequest)
  539. {
  540. if (status == 200)
  541. {
  542. // llOwnerSay(body);
  543. }
  544. else
  545. {
  546. llSay(0, "HTTP Error " + (string)status + ": " + body);
  547. }
  548. }
  549. }
  550. }
  551. </code></pre>
  552. <p>The last script uses regular sensors to gather even more data around itself. Sensors have a wider range than casting rays, but they basically retrieve objects irrespectively of their size, so we don't know if they are true obstacles or not.</p>
  553. <p>Copy the code below to a script called <code>Sensorama.lsl</code> and place it inside the transparent box as before.</p>
  554. <pre><code class="language-javascript">
  555. // Inside bot attachment
  556. // Senses data and sends it to remote host for processing
  557. string sensorURL = "http://{{.Host}}{{.ServerPort}}{{.URLPathPrefix}}/update-sensor/";
  558. key sensorRequest;
  559. default
  560. {
  561. state_entry()
  562. {
  563. llSay(0, "Attempting to sensorize...");
  564. llSensorRepeat("", NULL_KEY, AGENT|NPC|ACTIVE|PASSIVE|SCRIPTED, 10.0, PI/2, 5.0);
  565. }
  566. attach(key where)
  567. {
  568. if (where != NULL_KEY)
  569. {
  570. llResetScript();
  571. }
  572. }
  573. sensor(integer numDetected)
  574. {
  575. integer i;
  576. for (i = 0; i < numDetected; i++)
  577. {
  578. /*llOwnerSay("Detected " +
  579. llDetectedName(i) + " at " +
  580. (string)llDetectedPos(i) + " type: " +
  581. (string)llDetectedType(i));*/
  582. // get a few more details
  583. list objectDetailsList = llGetObjectDetails(llDetectedKey(i), [OBJECT_PHANTOM, OBJECT_PRIM_EQUIVALENCE]);
  584. // now get the bounding box too
  585. list boundingBox = llGetBoundingBox(llDetectedKey(i));
  586. // Sending remotely
  587. sensorRequest = llHTTPRequest(sensorURL +
  588. "?key=" + llDetectedKey(i) +
  589. "&name=" + llEscapeURL(llDetectedName(i)) +
  590. "&pos=" + (string)llDetectedPos(i) +
  591. "&rot=" + (string)llDetectedRot(i) +
  592. "&vel=" + (string)llDetectedVel(i) +
  593. "&phantom=" + llList2String(objectDetailsList, 0) +
  594. "&prims=" + llList2String(objectDetailsList, 1) +
  595. "&bblo=" + llList2String(boundingBox, 0) +
  596. "&bbhi=" + llList2String(boundingBox, 1) +
  597. "&origin=sensor" +
  598. "&type=" + llDetectedType(i) +
  599. "&amp;timestamp=" + llGetTimestamp(),
  600. [HTTP_METHOD, "GET"], "");
  601. }
  602. }
  603. http_response(key request_id, integer status, list metadata, string body)
  604. {
  605. if (request_id == sensorRequest)
  606. {
  607. if (status == 200)
  608. {
  609. // llOwnerSay(body);
  610. }
  611. else
  612. {
  613. llSay(0, "HTTP Error " + (string)status + ": " + body);
  614. }
  615. }
  616. }
  617. }
  618. </code></pre>
  619. {{ end }}