corrade-lsl-templates – Blame information for rev 29

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 a device that can be used to automatically batch-set the estate
6 // covenant for regions using the Corrade scripted agent. You can find out
7 // more about Corrade by following the URL:
8 // http://grimore.org/secondlife/scripted_agents/corrade
9 //
10 // The script works in conjunction with a "configuration" notecard, a
11 // "regions" notecard and a "covenant" notecard that must all be placed in
12 // the same primitive as this script.
13 //
14 // The purpose of this script is to demonstrate batch-setting the estate
15 // covenant with Corrade and you are free to use, change, and commercialize
29 office 16 // it under the CC BY 2.0
17 // license at: https://creativecommons.org/licenses/by/2.0
4 office 18 //
19 ///////////////////////////////////////////////////////////////////////////
20  
21 ///////////////////////////////////////////////////////////////////////////
29 office 22 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 23 ///////////////////////////////////////////////////////////////////////////
24 string wasProgress(integer percent, integer length, list symbols) {
25 percent /= (integer)((float)100.0/(length));
26 string p = llList2String(symbols,0);
27 integer itra = 0;
28 do {
29 if(itra>percent-1) p += llList2String(symbols,2);
30 else p += llList2String(symbols,1);
31 } while(++itra<length);
32 return p + llList2String(symbols,3);
33 }
34  
35 ///////////////////////////////////////////////////////////////////////////
29 office 36 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 37 ///////////////////////////////////////////////////////////////////////////
38 string wasKeyValueGet(string k, string data) {
39 if(llStringLength(data) == 0) return "";
40 if(llStringLength(k) == 0) return "";
41 list a = llParseString2List(data, ["&", "="], []);
42 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
43 if(i != -1) return llList2String(a, 2*i+1);
44 return "";
45 }
46  
47 ///////////////////////////////////////////////////////////////////////////
29 office 48 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 49 ///////////////////////////////////////////////////////////////////////////
50 string wasKeyValueEncode(list data) {
51 list k = llList2ListStrided(data, 0, -1, 2);
52 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
53 data = [];
54 do {
55 data += llList2String(k, 0) + "=" + llList2String(v, 0);
56 k = llDeleteSubList(k, 0, 0);
57 v = llDeleteSubList(v, 0, 0);
58 } while(llGetListLength(k) != 0);
59 return llDumpList2String(data, "&");
60 }
61  
62 ///////////////////////////////////////////////////////////////////////////
29 office 63 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 64 ///////////////////////////////////////////////////////////////////////////
65 // escapes a string in conformance with RFC1738
66 string wasURLEscape(string i) {
67 string o = "";
68 do {
69 string c = llGetSubString(i, 0, 0);
70 i = llDeleteSubString(i, 0, 0);
71 if(c == "") jump continue;
72 if(c == " ") {
73 o += "+";
74 jump continue;
75 }
76 if(c == "\n") {
77 o += "%0D" + llEscapeURL(c);
78 jump continue;
79 }
80 o += llEscapeURL(c);
81 @continue;
82 } while(i != "");
83 return o;
84 }
85  
86 ///////////////////////////////////////////////////////////////////////////
29 office 87 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 88 ///////////////////////////////////////////////////////////////////////////
89 string wasListToCSV(list l) {
90 list v = [];
91 do {
92 string a = llDumpList2String(
93 llParseStringKeepNulls(
94 llList2String(
95 l,
96  
97 ),
98 ["\""],
99 []
100 ),
101 "\"\""
102 );
103 if(llParseStringKeepNulls(a, [" ", ",", "\n"], []) != (list) a)
104 a = "\"" + a + "\"";
105 v += a;
106 l = llDeleteSubList(l, 0, 0);
107 } while(l != []);
108 return llDumpList2String(v, ",");
109 }
110  
111 ///////////////////////////////////////////////////////////////////////////
29 office 112 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 113 ///////////////////////////////////////////////////////////////////////////
114 list wasCSVToList(string csv) {
115 list l = [];
116 list s = [];
117 string m = "";
118 do {
119 string a = llGetSubString(csv, 0, 0);
120 csv = llDeleteSubString(csv, 0, 0);
121 if(a == ",") {
122 if(llList2String(s, -1) != "\"") {
123 l += m;
124 m = "";
125 jump continue;
126 }
127 m += a;
128 jump continue;
129 }
130 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
131 m += a;
132 csv = llDeleteSubString(csv, 0, 0);
133 jump continue;
134 }
135 if(a == "\"") {
136 if(llList2String(s, -1) != a) {
137 s += a;
138 jump continue;
139 }
140 s = llDeleteSubList(s, -1, -1);
141 jump continue;
142 }
143 m += a;
144 @continue;
145 } while(csv != "");
146 // invariant: length(s) = 0
147 return l + m;
148 }
149  
150 ///////////////////////////////////////////////////////////////////////////
29 office 151 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 152 ///////////////////////////////////////////////////////////////////////////
153 // unescapes a string in conformance with RFC1738
154 string wasURLUnescape(string i) {
155 return llUnescapeURL(
156 llDumpList2String(
157 llParseString2List(
158 llDumpList2String(
159 llParseString2List(
160 i,
161 ["+"],
162 []
163 ),
164 " "
165 ),
166 ["%0D%0A"],
167 []
168 ),
169 "\n"
170 )
171 );
172 }
173  
174 // corrade data
175 string CORRADE = "";
176 string GROUP = "";
177 string PASSWORD = "";
178  
179 // for holding the callback URL
180 string callback = "";
181  
182 // for notecard reading
183 integer line = 0;
184  
185 // key-value data will be read into this list
186 list tuples = [];
187 // regions will be stored here
188 list regions = [];
189 string region = "";
190 integer regionsChanged = 0;
191  
192 default {
193 state_entry() {
194 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
195 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
196 return;
197 }
198 if(llGetInventoryType("covenant") != INVENTORY_NOTECARD) {
199 llOwnerSay("Sorry, could not find a covenant inventory notecard.");
200 return;
201 }
202 // DEBUG
203 llOwnerSay("Reading configuration file...");
204 llGetNotecardLine("configuration", line);
205 }
206 dataserver(key id, string data) {
207 if(data == EOF) {
208 // invariant, length(tuples) % 2 == 0
209 if(llGetListLength(tuples) % 2 != 0) {
210 llOwnerSay("Error in configuration notecard.");
211 return;
212 }
213 CORRADE = llList2String(
214 tuples,
215 llListFindList(
216 tuples,
217 [
218 "corrade"
219 ]
220 )
221 +1);
222 if(CORRADE == "") {
223 llOwnerSay("Error in configuration notecard: corrade");
224 return;
225 }
226 GROUP = llList2String(
227 tuples,
228 llListFindList(
229 tuples,
230 [
231 "group"
232 ]
233 )
234 +1);
235 if(GROUP == "") {
236 llOwnerSay("Error in configuration notecard: group");
237 return;
238 }
239 PASSWORD = llList2String(
240 tuples,
241 llListFindList(
242 tuples,
243 [
244 "password"
245 ]
246 )
247 +1);
248 if(PASSWORD == "") {
249 llOwnerSay("Error in configuration notecard: password");
250 return;
251 }
252 // DEBUG
253 llOwnerSay("Read configuration notecard...");
254 state read_regions;
255 }
256 if(data == "") jump continue;
257 integer i = llSubStringIndex(data, "#");
258 if(i != -1) data = llDeleteSubString(data, i, -1);
259 list o = llParseString2List(data, ["="], []);
260 // get rid of starting and ending quotes
261 string k = llDumpList2String(
262 llParseString2List(
263 llStringTrim(
264 llList2String(
265 o,
266  
267 ),
268 STRING_TRIM),
269 ["\""], []
270 ), "\"");
271 string v = llDumpList2String(
272 llParseString2List(
273 llStringTrim(
274 llList2String(
275 o,
276 1
277 ),
278 STRING_TRIM),
279 ["\""], []
280 ), "\"");
281 if(k == "" || v == "") jump continue;
282 tuples += k;
283 tuples += v;
284 @continue;
285 llGetNotecardLine("configuration", ++line);
286 }
287 on_rez(integer num) {
288 llResetScript();
289 }
290 changed(integer change) {
291 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
292 llResetScript();
293 }
294 }
295 }
296  
297 state read_regions {
298 state_entry() {
299 if(llGetInventoryType("regions") != INVENTORY_NOTECARD) {
300 llOwnerSay("Sorry, could not find a regions inventory notecard.");
301 return;
302 }
303 // DEBUG
304 llOwnerSay("Reading regions notecard...");
305 line = 0;
306 llGetNotecardLine("regions", line);
307 }
308 dataserver(key id, string data) {
309 if(data == EOF) {
310 // DEBUG
311 llOwnerSay("Read regions notcard...");
312 state url;
313 }
314 if(data == "") jump continue;
315 regions += data;
316 @continue;
317 llGetNotecardLine("regions", ++line);
318 }
319 on_rez(integer num) {
320 llResetScript();
321 }
322 changed(integer change) {
323 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
324 llResetScript();
325 }
326 }
327 }
328  
329 state url {
330 state_entry() {
331 // DEBUG
332 llOwnerSay("Requesting URL...");
333 llRequestURL();
334 }
335 http_request(key id, string method, string body) {
336 if(method != URL_REQUEST_GRANTED) return;
337 callback = body;
338 // DEBUG
339 llOwnerSay("Got URL...");
340 state detect;
341 }
342 on_rez(integer num) {
343 llResetScript();
344 }
345 changed(integer change) {
346 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
347 llResetScript();
348 }
349 }
350 }
351  
352 state detect {
353 state_entry() {
354 // DEBUG
355 llOwnerSay("Detecting if Corrade is online...");
356 llSetTimerEvent(5);
357 }
358 timer() {
359 llRequestAgentData((key)CORRADE, DATA_ONLINE);
360 }
361 dataserver(key id, string data) {
362 if(data != "1") {
363 // DEBUG
364 llOwnerSay("Corrade is not online, sleeping...");
365 llSetTimerEvent(30);
366 return;
367 }
368 state teleport;
369 }
370 on_rez(integer num) {
371 llResetScript();
372 }
373 changed(integer change) {
374 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
375 llResetScript();
376 }
377 }
378 }
379  
380 state teleport {
381 state_entry() {
382 // Keep checking if Corrade disconnected.
383 llSetTimerEvent(5);
384 // Shuffle the regions and grab the next region.
385 region = llList2String(regions, 0);
386 regions = llDeleteSubList(regions, 0, 0);
387 regions += region;
388 // DEBUG
389 llOwnerSay("Teleporting to: " + region);
390 llInstantMessage(
391 (key)CORRADE,
392 wasKeyValueEncode(
393 [
394 "command", "teleport",
395 "group", wasURLEscape(GROUP),
396 "password", wasURLEscape(PASSWORD),
397 "region", wasURLEscape(region),
398 "entity", "region",
399 "fly", "True",
400 "position", <128,128,4096>,
401 "callback", wasURLEscape(callback)
402 ]
403 )
404 );
405 }
406 http_request(key id, string method, string body) {
407 llHTTPResponse(id, 200, "OK");
408 if(wasKeyValueGet("command", body) != "teleport" ||
409 wasKeyValueGet("success", body) != "True") {
410 // DEBUG
411 llOwnerSay("Failed to teleport to: " + region);
412 // Jump to trampoline for re-entry.
413 state teleport_trampoline;
414 }
415 // DEBUG
416 llOwnerSay("Teleported successfully to: " + region);
417 state get_covenant;
418 }
419 timer() {
420 llRequestAgentData((key)CORRADE, DATA_ONLINE);
421 }
422 dataserver(key id, string data) {
423 if(data != "1") {
424 // DEBUG
425 llOwnerSay("Corrade is not online, sleeping...");
426 state detect;
427 }
428 }
429 on_rez(integer num) {
430 llResetScript();
431 }
432 changed(integer change) {
433 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
434 llResetScript();
435 }
436 }
437 }
438  
439 state teleport_trampoline {
440 state_entry() {
441 // DEBUG
442 llOwnerSay("Sleeping...");
443 llSetTimerEvent(5);
444 }
445 timer() {
446 llSetTimerEvent(0);
447 state teleport;
448 }
449 on_rez(integer num) {
450 llResetScript();
451 }
452 changed(integer change) {
453 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
454 llResetScript();
455 }
456 }
457 }
458  
459 state get_covenant {
460 state_entry() {
461 // Keep checking if Corrade disconnected.
462 llSetTimerEvent(5);
463 // DEBUG
464 llOwnerSay("Getting covenant...");
465 llInstantMessage(
466 (key)CORRADE,
467 wasKeyValueEncode(
468 [
469 "command", "getestatecovenant",
470 "group", wasURLEscape(GROUP),
471 "password", wasURLEscape(PASSWORD),
472 "callback", wasURLEscape(callback)
473 ]
474 )
475 );
476 }
477 http_request(key id, string method, string body) {
478 llHTTPResponse(id, 200, "OK");
479 if(wasKeyValueGet("command", body) != "getestatecovenant" ||
480 wasKeyValueGet("success", body) != "True") {
481 // DEBUG
482 llOwnerSay("Failed to get covenant for region: " + region);
483 // Jump to trampoline for teleport.
484 state teleport_trampoline;
485 }
486 // DEBUG
487 llOwnerSay("Got covenant for region: " + region);
488 if(llList2Key(
489 wasCSVToList(
490 wasURLUnescape(
491 wasKeyValueGet(
492 "data",
493 body
494 )
495 )
496 ),
497  
498 ) == llGetInventoryKey("covenant")) {
499 // DEBUG
500 llOwnerSay("Covenant for region: \"" + region + "\" is set.");
501 ++regionsChanged;
502 llSetText(
503 "Corrade @ " + region + "\n" +
504 "Progress: " +
505 wasProgress(
506 100 * regionsChanged/llGetListLength(regions),
507 10,
508 [
509 "[", "█", "░", "]"
510 ]
511 ) + "[" + (string)regionsChanged + "/" + (string)llGetListLength(regions) + "]",
512 <0, 1, 1>,
513 1.0
514 );
515 state teleport_trampoline;
516 }
517 state set_covenant;
518 }
519 timer() {
520 llRequestAgentData((key)CORRADE, DATA_ONLINE);
521 }
522 dataserver(key id, string data) {
523 if(data != "1") {
524 // DEBUG
525 llOwnerSay("Corrade is not online, sleeping...");
526 state detect;
527 }
528 }
529 on_rez(integer num) {
530 llResetScript();
531 }
532 changed(integer change) {
533 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
534 llResetScript();
535 }
536 }
537 }
538  
539 state set_covenant {
540 state_entry() {
541 // Keep checking if Corrade disconnected.
542 llSetTimerEvent(5);
543 // DEBUG
544 llOwnerSay("Setting covenant...");
545 llInstantMessage(
546 (key)CORRADE,
547 wasKeyValueEncode(
548 [
549 "command", "setestatecovenant",
550 "group", wasURLEscape(GROUP),
551 "password", wasURLEscape(PASSWORD),
552 "item", llGetInventoryKey("covenant"),
553 "callback", wasURLEscape(callback)
554 ]
555 )
556 );
557 }
558 http_request(key id, string method, string body) {
559 llHTTPResponse(id, 200, "OK");
560 if(wasKeyValueGet("command", body) != "setestatecovenant" ||
561 wasKeyValueGet("success", body) != "True") {
562 // DEBUG
563 llOwnerSay("Failed to set covenant for region: " + region);
564 --regionsChanged;
565 // Jump to trampoline for teleport.
566 state teleport_trampoline;
567 }
568 // DEBUG
569 llOwnerSay("Set covenant for region: " + region);
570 state get_covenant;
571 }
572 timer() {
573 llRequestAgentData((key)CORRADE, DATA_ONLINE);
574 }
575 dataserver(key id, string data) {
576 if(data != "1") {
577 // DEBUG
578 llOwnerSay("Corrade is not online, sleeping...");
579 state detect;
580 }
581 }
582 on_rez(integer num) {
583 llResetScript();
584 }
585 changed(integer change) {
586 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
587 llResetScript();
588 }
589 }
590 }
591  
592