corrade-lsl-templates – Blame information for rev 42

Subversion Repositories:
Rev:
Rev Author Line No. Line
4 office 1 ///////////////////////////////////////////////////////////////////////////
29 office 2 // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 //
4 office 3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // This is an automatic teleporter, sitter and animator for the Corrade
6 // Second Life / OpenSim bot. You can find more details about the bot
7 // by following the URL: http://was.fm/secondlife/scripted_agents/corrade
8 //
9 // The sit script works together with a "configuration" notecard and an
10 // animation that must both be placed in the same primitive as this script.
11 // The purpose of this script is to demonstrate sitting with Corrade and
29 office 12 // you are free to use, change, and commercialize it under the CC BY 2.0
13 // license at: https://creativecommons.org/licenses/by/2.0
4 office 14 //
15 ///////////////////////////////////////////////////////////////////////////
16  
17 ///////////////////////////////////////////////////////////////////////////
29 office 18 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 19 ///////////////////////////////////////////////////////////////////////////
20 string wasKeyValueGet(string k, string data) {
21 if(llStringLength(data) == 0) return "";
22 if(llStringLength(k) == 0) return "";
23 list a = llParseString2List(data, ["&", "="], []);
24 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
25 if(i != -1) return llList2String(a, 2*i+1);
26 return "";
27 }
28  
29 ///////////////////////////////////////////////////////////////////////////
29 office 30 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 31 ///////////////////////////////////////////////////////////////////////////
32 string wasKeyValueEncode(list data) {
33 list k = llList2ListStrided(data, 0, -1, 2);
34 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
35 data = [];
36 do {
37 data += llList2String(k, 0) + "=" + llList2String(v, 0);
38 k = llDeleteSubList(k, 0, 0);
39 v = llDeleteSubList(v, 0, 0);
40 } while(llGetListLength(k) != 0);
41 return llDumpList2String(data, "&");
42 }
43  
44 ///////////////////////////////////////////////////////////////////////////
29 office 45 // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 46 ///////////////////////////////////////////////////////////////////////////
47 vector wasCirclePoint(float radius) {
48 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
49 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
50 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
51 return <x, y, 0>;
52 return wasCirclePoint(radius);
53 }
54  
55 ///////////////////////////////////////////////////////////////////////////
29 office 56 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 57 ///////////////////////////////////////////////////////////////////////////
58 // escapes a string in conformance with RFC1738
59 string wasURLEscape(string i) {
60 string o = "";
61 do {
62 string c = llGetSubString(i, 0, 0);
63 i = llDeleteSubString(i, 0, 0);
64 if(c == "") jump continue;
65 if(c == " ") {
66 o += "+";
67 jump continue;
68 }
69 if(c == "\n") {
70 o += "%0D" + llEscapeURL(c);
71 jump continue;
72 }
73 o += llEscapeURL(c);
74 @continue;
75 } while(i != "");
76 return o;
77 }
78  
79 // corrade data
80 string CORRADE = "";
81 string GROUP = "";
82 string PASSWORD = "";
83  
84 // for holding the callback URL
85 string callback = "";
86  
87 // for notecard reading
88 integer line = 0;
89  
90 // key-value data will be read into this list
91 list tuples = [];
92  
93 default {
94 state_entry() {
95 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
96 llOwnerSay("Sorry, could not find an inventory notecard.");
97 return;
98 }
99 // DEBUG
100 llOwnerSay("Reading configuration file...");
101 llGetNotecardLine("configuration", line);
102 }
103 dataserver(key id, string data) {
104 if(data == EOF) {
105 // invariant, length(tuples) % 2 == 0
106 if(llGetListLength(tuples) % 2 != 0) {
107 llOwnerSay("Error in configuration notecard.");
108 return;
109 }
110 CORRADE = llList2String(
111 tuples,
112 llListFindList(
113 tuples,
114 [
115 "corrade"
116 ]
117 )
118 +1);
119 if(CORRADE == "") {
120 llOwnerSay("Error in configuration notecard: corrade");
121 return;
122 }
123 GROUP = llList2String(
124 tuples,
125 llListFindList(
126 tuples,
127 [
128 "group"
129 ]
130 )
131 +1);
132 if(GROUP == "") {
133 llOwnerSay("Error in configuration notecard: group");
134 return;
135 }
136 PASSWORD = llList2String(
137 tuples,
138 llListFindList(
139 tuples,
140 [
141 "password"
142 ]
143 )
144 +1);
145 if(PASSWORD == "") {
146 llOwnerSay("Error in configuration notecard: password");
147 return;
148 }
149 // DEBUG
150 llOwnerSay("Read configuration file...");
151 state url;
152 }
153 if(data == "") jump continue;
154 integer i = llSubStringIndex(data, "#");
155 if(i != -1) data = llDeleteSubString(data, i, -1);
156 list o = llParseString2List(data, ["="], []);
157 // get rid of starting and ending quotes
158 string k = llDumpList2String(
159 llParseString2List(
160 llStringTrim(
161 llList2String(
162 o,
163  
164 ),
165 STRING_TRIM),
166 ["\""], []
167 ), "\"");
168 string v = llDumpList2String(
169 llParseString2List(
170 llStringTrim(
171 llList2String(
172 o,
173 1
174 ),
175 STRING_TRIM),
176 ["\""], []
177 ), "\"");
178 if(k == "" || v == "") jump continue;
179 tuples += k;
180 tuples += v;
181 @continue;
182 llGetNotecardLine("configuration", ++line);
183 }
184 on_rez(integer num) {
185 llResetScript();
186 }
187 changed(integer change) {
188 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
189 llResetScript();
190 }
191 }
192 }
193  
194 state url {
195 state_entry() {
196 // DEBUG
197 llOwnerSay("Requesting URL...");
198 llRequestURL();
199 }
200 http_request(key id, string method, string body) {
201 if(method != URL_REQUEST_GRANTED) return;
202 callback = body;
203 // DEBUG
204 llOwnerSay("Got URL...");
205 state detect;
206 }
207 on_rez(integer num) {
208 llResetScript();
209 }
210 changed(integer change) {
211 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
212 llResetScript();
213 }
214 }
215 }
216  
217 state detect {
218 state_entry() {
219 // DEBUG
220 llOwnerSay("Detecting if Corrade is online...");
221 llSetTimerEvent(5);
222 }
223 timer() {
224 llRequestAgentData((key)CORRADE, DATA_ONLINE);
225 }
226 dataserver(key id, string data) {
227 if(data != "1") {
228 // DEBUG
229 llOwnerSay("Corrade is not online, sleeping...");
230 llSetTimerEvent(30);
231 return;
232 }
233 llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 1);
234 }
235 no_sensor() {
236 // DEBUG
237 llOwnerSay("Teleporting Corrade...");
238 llInstantMessage((key)CORRADE,
239 wasKeyValueEncode(
240 [
241 "command", "teleport",
242 "group", wasURLEscape(GROUP),
243 "password", wasURLEscape(PASSWORD),
244 "entity", "region",
245 "region", wasURLEscape(llGetRegionName()),
246 "position", wasURLEscape(
247 (string)(
248 llGetPos() + wasCirclePoint(1)
249 )
250 ),
251 "callback", callback
252 ]
253 )
254 );
255 }
256 sensor(integer num) {
257 llSetTimerEvent(0);
258 state notify;
259 }
260 http_request(key id, string method, string body) {
261 llHTTPResponse(id, 200, "OK");
262 if(wasKeyValueGet("command", body) != "teleport" ||
263 wasKeyValueGet("success", body) != "True") {
264 // DEBUG
265 llOwnerSay("Teleport failed...");
266 return;
267 }
268 llSetTimerEvent(0);
269 state main;
270 }
271 on_rez(integer num) {
272 llResetScript();
273 }
274 changed(integer change) {
275 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
276 llResetScript();
277 }
278 }
279 }
280  
281 state notify {
282 state_entry() {
283 // DEBUG
284 llOwnerSay("Binding to the permission Corrade notification...");
285 llInstantMessage(
286 (key)CORRADE,
287 wasKeyValueEncode(
288 [
289 "command", "notify",
290 "group", wasURLEscape(GROUP),
291 "password", wasURLEscape(PASSWORD),
292 "action", "add",
293 "type", "permission",
294 "URL", wasURLEscape(callback),
295 "callback", wasURLEscape(callback)
296 ]
297 )
298 );
299 llSetTimerEvent(60);
300 }
301 http_request(key id, string method, string body) {
302 llHTTPResponse(id, 200, "OK");
303 if(wasKeyValueGet("command", body) != "notify" ||
304 wasKeyValueGet("success", body) != "True") {
305 // DEBUG
306 llOwnerSay("Failed to bind to the permission notification...");
307 state detect;
308 }
309 // DEBUG
310 llOwnerSay("Permission notification installed...");
311 llSetTimerEvent(0);
312 state main;
313 }
314 timer() {
315 llSetTimerEvent(0);
316 // DEBUG
317 llOwnerSay("Timeout binding to permission notification...");
318 state detect;
319 }
320 on_rez(integer num) {
321 llResetScript();
322 }
323 changed(integer change) {
324 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
325 llResetScript();
326 }
327 }
328 }
329  
330 state main {
331 state_entry() {
332 // DEBUG
333 llOwnerSay("Waiting...");
334 llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 1);
335 llSetTimerEvent(60);
336 }
337 sensor(integer num) {
338 // Corrade is already sitting. Do nothing.
339 if(llAvatarOnSitTarget() == (key)CORRADE) return;
340 // DEBUG
341 llOwnerSay("Sending sit command...");
342 llInstantMessage((key)CORRADE,
343 wasKeyValueEncode(
344 [
345 "command", "sit",
346 "group", wasURLEscape(GROUP),
347 "password", wasURLEscape(PASSWORD),
348 "item", wasURLEscape(
349 llGetKey()
350 ),
351 "range", 10
352 ]
353 )
354 );
355 llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 10);
356 }
357 no_sensor() {
358 llSensorRemove();
359 state detect;
360 }
361 http_request(key id, string method, string body) {
362 llHTTPResponse(id, 200, "OK");
363 if(wasKeyValueGet("type", body) != "permission" ||
364 wasKeyValueGet("permissions", body) != "TriggerAnimation") return;
365 // DEBUG
366 llOwnerSay("Corrade received the permission request to trigger an animation, replying...");
367 llInstantMessage((key)CORRADE,
368 wasKeyValueEncode(
369 [
370 "command", "replytoscriptpermissionrequest",
371 "group", wasURLEscape(GROUP),
372 "password", wasURLEscape(PASSWORD),
373 "action", "reply",
374 "item", wasURLEscape(wasKeyValueGet("item", body)),
375 "task", wasURLEscape(wasKeyValueGet("task", body)),
376 "permissions", "TriggerAnimation",
377 "region", wasURLEscape(wasKeyValueGet("region", body))
378 ]
379 )
380 );
381 }
382 timer() {
383 if(llAvatarOnSitTarget() == (key)CORRADE) return;
384 // DEBUG
385 llOwnerSay("Timeout during sit... Restarting...");
386 state detect;
387 }
388 on_rez(integer num) {
389 llResetScript();
390 }
391 changed(integer change) {
392 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
393 llResetScript();
394 }
395 }
396 }