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 script demonstrates the built-in local chat AIML talking feature of
6 // the Corrade Second Life / OpenSim bot. For more documentation on Corrade
7 // follow the URL: http://grimore.org/secondlife/scripted_agents/corrade
8 //
9 // The script works in combination with a "configuration" notecard that
10 // must be placed in the same primitive as this script. The purpose of this
11 // script is to demonstrate answering messages with Corrade's built-in AI
12 // and you are free to use, change, and commercialize it under the terms
29 office 13 // of the CC BY 2.0 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) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 46 ///////////////////////////////////////////////////////////////////////////
47 // escapes a string in conformance with RFC1738
48 string wasURLEscape(string i) {
49 string o = "";
50 do {
51 string c = llGetSubString(i, 0, 0);
52 i = llDeleteSubString(i, 0, 0);
53 if(c == "") jump continue;
54 if(c == " ") {
55 o += "+";
56 jump continue;
57 }
58 if(c == "\n") {
59 o += "%0D" + llEscapeURL(c);
60 jump continue;
61 }
62 o += llEscapeURL(c);
63 @continue;
64 } while(i != "");
65 return o;
66 }
67  
68 ///////////////////////////////////////////////////////////////////////////
29 office 69 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
4 office 70 ///////////////////////////////////////////////////////////////////////////
71 // unescapes a string in conformance with RFC1738
72 string wasURLUnescape(string i) {
73 return llUnescapeURL(
74 llDumpList2String(
75 llParseString2List(
76 llDumpList2String(
77 llParseString2List(
78 i,
79 ["+"],
80 []
81 ),
82 " "
83 ),
84 ["%0D%0A"],
85 []
86 ),
87 "\n"
88 )
89 );
90 }
91  
92 // corrade data
93 key CORRADE = NULL_KEY;
94 string GROUP = "";
95 string PASSWORD = "";
96  
97 // instance variables
98 string firstname = "";
99 string lastname = "";
100 string message = "";
101  
102 // for holding the callback URL
103 string callback = "";
104  
105 // for notecard reading
106 integer line = 0;
107  
108 // key-value data will be read into this list
109 list tuples = [];
110  
111 default {
112 state_entry() {
113 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
114 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
115 return;
116 }
117 // DEBUG
118 llOwnerSay("Reading configuration file...");
119 llGetNotecardLine("configuration", line);
120 }
121 dataserver(key id, string data) {
122 if(data == EOF) {
123 // invariant, length(tuples) % 2 == 0
124 if(llGetListLength(tuples) % 2 != 0) {
125 llOwnerSay("Error in configuration notecard.");
126 return;
127 }
128 CORRADE = llList2Key(
129 tuples,
130 llListFindList(
131 tuples,
132 [
133 "corrade"
134 ]
135 )
136 +1);
137 if(CORRADE == NULL_KEY) {
138 llOwnerSay("Error in configuration notecard: corrade");
139 return;
140 }
141 GROUP = llList2String(
142 tuples,
143 llListFindList(
144 tuples,
145 [
146 "group"
147 ]
148 )
149 +1);
150 if(GROUP == "") {
151 llOwnerSay("Error in configuration notecard: group");
152 return;
153 }
154 PASSWORD = llList2String(
155 tuples,
156 llListFindList(
157 tuples,
158 [
159 "password"
160 ]
161 )
162 +1);
163 if(PASSWORD == "") {
164 llOwnerSay("Error in configuration notecard: password");
165 return;
166 }
167 // DEBUG
168 llOwnerSay("Read configuration notecard...");
169 state url;
170 }
171 if(data == "") jump continue;
172 integer i = llSubStringIndex(data, "#");
173 if(i != -1) data = llDeleteSubString(data, i, -1);
174 list o = llParseString2List(data, ["="], []);
175 // get rid of starting and ending quotes
176 string k = llDumpList2String(
177 llParseString2List(
178 llStringTrim(
179 llList2String(
180 o,
181  
182 ),
183 STRING_TRIM),
184 ["\""], []
185 ), "\"");
186 string v = llDumpList2String(
187 llParseString2List(
188 llStringTrim(
189 llList2String(
190 o,
191 1
192 ),
193 STRING_TRIM),
194 ["\""], []
195 ), "\"");
196 if(k == "" || v == "") jump continue;
197 tuples += k;
198 tuples += v;
199 @continue;
200 llGetNotecardLine("configuration", ++line);
201 }
202 on_rez(integer num) {
203 llResetScript();
204 }
205 changed(integer change) {
206 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
207 llResetScript();
208 }
209 }
210 }
211  
212 state url {
213 state_entry() {
214 // DEBUG
215 llOwnerSay("Requesting URL...");
216 llRequestURL();
217 }
218 http_request(key id, string method, string body) {
219 if(method != URL_REQUEST_GRANTED) return;
220 callback = body;
221 // DEBUG
222 llOwnerSay("Got URL...");
223 state detect;
224 }
225 on_rez(integer num) {
226 llResetScript();
227 }
228 changed(integer change) {
229 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
230 llResetScript();
231 }
232 }
233 }
234  
235 state detect {
236 state_entry() {
237 // DEBUG
238 llOwnerSay("Detecting if Corrade is online...");
239 llSetTimerEvent(5);
240 }
241 timer() {
242 llRequestAgentData((key)CORRADE, DATA_ONLINE);
243 }
244 dataserver(key id, string data) {
245 if(data != "1") {
246 // DEBUG
247 llOwnerSay("Corrade is not online, sleeping...");
248 llSetTimerEvent(30);
249 return;
250 }
251 state notify;
252 }
253 on_rez(integer num) {
254 llResetScript();
255 }
256 changed(integer change) {
257 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
258 llResetScript();
259 }
260 }
261 }
262  
263 state notify {
264 state_entry() {
265 // DEBUG
266 llOwnerSay("Binding to the local message notification...");
267 llInstantMessage(
268 (key)CORRADE,
269 wasKeyValueEncode(
270 [
271 "command", "notify",
272 "group", wasURLEscape(GROUP),
273 "password", wasURLEscape(PASSWORD),
274 "action", "set",
275 "type", "local",
276 "URL", wasURLEscape(callback),
277 "callback", wasURLEscape(callback)
278 ]
279 )
280 );
281 }
282 http_request(key id, string method, string body) {
283 llHTTPResponse(id, 200, "OK");
284 if(wasKeyValueGet("command", body) != "notify" ||
285 wasKeyValueGet("success", body) != "True") {
286 // DEBUG
287 llOwnerSay("Failed to bind to the local chat notification...");
288 state detect;
289 }
290 // DEBUG
291 llOwnerSay("Local chat notification installed...");
292 state chat;
293 }
294 on_rez(integer num) {
295 llResetScript();
296 }
297 changed(integer change) {
298 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
299 llResetScript();
300 }
301 }
302 }
303  
304 state chat {
305 state_entry() {
306 // DEBUG
307 llOwnerSay("Waiting for local chat message...");
308 llSetTimerEvent(5);
309 }
310 timer() {
311 llRequestAgentData((key)CORRADE, DATA_ONLINE);
312 }
313 dataserver(key id, string data) {
314 if(data == "1") return;
315 // DEBUG
316 llOwnerSay("Corrade is not online, sleeping...");
317 // Switch to detect loop and wait there for Corrade to come online.
318 state detect;
319 }
320 http_request(key id, string method, string body) {
321 llHTTPResponse(id, 200, "OK");
322 firstname = wasURLUnescape(wasKeyValueGet("firstname", body));
323 lastname = wasURLUnescape(wasKeyValueGet("lastname", body));
324 // DEBUG
325 message = wasKeyValueGet("message", body);
326 if(message != "") {
327 llOwnerSay("Got local chat from: " + firstname + " " + lastname);
328 state process;
329 }
330 }
331 on_rez(integer num) {
332 llResetScript();
333 }
334 changed(integer change) {
335 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
336 llResetScript();
337 }
338 }
339 }
340  
341 state process {
342 state_entry() {
343 // DEBUG
344 llOwnerSay("Sending message to Corrade's AI facility...");
345 llInstantMessage(CORRADE,
346 wasKeyValueEncode(
347 [
348 "command", "ai",
349 "group", wasURLEscape(GROUP),
350 "password", wasURLEscape(PASSWORD),
351 "action", "process",
352 "message", wasURLEscape(message),
353 "callback", wasURLEscape(callback)
354 ]
355 )
356 );
357 llSetTimerEvent(5);
358 }
359 timer() {
360 llRequestAgentData((key)CORRADE, DATA_ONLINE);
361 }
362 dataserver(key id, string data) {
363 if(data == "1") return;
364 // DEBUG
365 llOwnerSay("Corrade is not online, sleeping...");
366 // Switch to detect loop and wait there for Corrade to come online.
367 state detect;
368 }
369 http_request(key id, string method, string body) {
370 llHTTPResponse(id, 200, "OK");
371 // DEBUG
372 llOwnerSay("Sending answer to: " + firstname + " " + lastname);
373 llInstantMessage(CORRADE,
374 wasKeyValueEncode(
375 [
376 "command", "tell",
377 "group", wasURLEscape(GROUP),
378 "password", wasURLEscape(PASSWORD),
379 "entity", "local",
380 "message", wasKeyValueGet("data", body)
381 ]
382 )
383 );
384 state chat;
385 }
386 on_rez(integer num) {
387 llResetScript();
388 }
389 changed(integer change) {
390 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
391 llResetScript();
392 }
393 }
394 }