corrade-lsl-templates – Diff between revs 24 and 29

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 24 Rev 29
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // 4 //
5 // A module using AI-SIML that allows group members to talk to Corrade. 5 // A module using AI-SIML that allows group members to talk to Corrade.
6 // 6 //
7 /////////////////////////////////////////////////////////////////////////// 7 ///////////////////////////////////////////////////////////////////////////
8   8  
9 /////////////////////////////////////////////////////////////////////////// 9 ///////////////////////////////////////////////////////////////////////////
10 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 10 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
11 /////////////////////////////////////////////////////////////////////////// 11 ///////////////////////////////////////////////////////////////////////////
12 string wasKeyValueGet(string k, string data) { 12 string wasKeyValueGet(string k, string data) {
13 if(llStringLength(data) == 0) return ""; 13 if(llStringLength(data) == 0) return "";
14 if(llStringLength(k) == 0) return ""; 14 if(llStringLength(k) == 0) return "";
15 list a = llParseString2List(data, ["&", "="], []); 15 list a = llParseString2List(data, ["&", "="], []);
16 integer i = llListFindList(a, [ k ]); 16 integer i = llListFindList(a, [ k ]);
17 if(i != -1) return llList2String(a, i+1); 17 if(i != -1) return llList2String(a, i+1);
18 return ""; 18 return "";
19 } 19 }
20 20
21 /////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////
22 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 22 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
23 /////////////////////////////////////////////////////////////////////////// 23 ///////////////////////////////////////////////////////////////////////////
24 string wasKeyValueEncode(list data) { 24 string wasKeyValueEncode(list data) {
25 list k = llList2ListStrided(data, 0, -1, 2); 25 list k = llList2ListStrided(data, 0, -1, 2);
26 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 26 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
27 data = []; 27 data = [];
28 do { 28 do {
29 data += llList2String(k, 0) + "=" + llList2String(v, 0); 29 data += llList2String(k, 0) + "=" + llList2String(v, 0);
30 k = llDeleteSubList(k, 0, 0); 30 k = llDeleteSubList(k, 0, 0);
31 v = llDeleteSubList(v, 0, 0); 31 v = llDeleteSubList(v, 0, 0);
32 } while(llGetListLength(k) != 0); 32 } while(llGetListLength(k) != 0);
33 return llDumpList2String(data, "&"); 33 return llDumpList2String(data, "&");
34 } 34 }
35   35  
36 /////////////////////////////////////////////////////////////////////////// 36 ///////////////////////////////////////////////////////////////////////////
37 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // 37 // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 //
38 /////////////////////////////////////////////////////////////////////////// 38 ///////////////////////////////////////////////////////////////////////////
39 // http://was.fm/secondlife/wanderer 39 // http://was.fm/secondlife/wanderer
40 vector wasCirclePoint(float radius) { 40 vector wasCirclePoint(float radius) {
41 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 41 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
42 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 42 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
43 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) 43 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
44 return <x, y, 0>; 44 return <x, y, 0>;
45 return wasCirclePoint(radius); 45 return wasCirclePoint(radius);
46 } 46 }
47   47  
48 /////////////////////////////////////////////////////////////////////////// 48 ///////////////////////////////////////////////////////////////////////////
49 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 49 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
50 /////////////////////////////////////////////////////////////////////////// 50 ///////////////////////////////////////////////////////////////////////////
51 // escapes a string in conformance with RFC1738 51 // escapes a string in conformance with RFC1738
52 string wasURLEscape(string i) { 52 string wasURLEscape(string i) {
53 string o = ""; 53 string o = "";
54 do { 54 do {
55 string c = llGetSubString(i, 0, 0); 55 string c = llGetSubString(i, 0, 0);
56 i = llDeleteSubString(i, 0, 0); 56 i = llDeleteSubString(i, 0, 0);
57 if(c == "") jump continue; 57 if(c == "") jump continue;
58 if(c == " ") { 58 if(c == " ") {
59 o += "+"; 59 o += "+";
60 jump continue; 60 jump continue;
61 } 61 }
62 if(c == "\n") { 62 if(c == "\n") {
63 o += "%0D" + llEscapeURL(c); 63 o += "%0D" + llEscapeURL(c);
64 jump continue; 64 jump continue;
65 } 65 }
66 o += llEscapeURL(c); 66 o += llEscapeURL(c);
67 @continue; 67 @continue;
68 } while(i != ""); 68 } while(i != "");
69 return o; 69 return o;
70 } 70 }
71   71  
72 /////////////////////////////////////////////////////////////////////////// 72 ///////////////////////////////////////////////////////////////////////////
73 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 73 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
74 /////////////////////////////////////////////////////////////////////////// 74 ///////////////////////////////////////////////////////////////////////////
75 list wasCSVToList(string csv) { 75 list wasCSVToList(string csv) {
76 list l = []; 76 list l = [];
77 list s = []; 77 list s = [];
78 string m = ""; 78 string m = "";
79 do { 79 do {
80 string a = llGetSubString(csv, 0, 0); 80 string a = llGetSubString(csv, 0, 0);
81 csv = llDeleteSubString(csv, 0, 0); 81 csv = llDeleteSubString(csv, 0, 0);
82 if(a == ",") { 82 if(a == ",") {
83 if(llList2String(s, -1) != "\"") { 83 if(llList2String(s, -1) != "\"") {
84 l += m; 84 l += m;
85 m = ""; 85 m = "";
86 jump continue; 86 jump continue;
87 } 87 }
88 m += a; 88 m += a;
89 jump continue; 89 jump continue;
90 } 90 }
91 if(a == "\"" && llGetSubString(csv, 0, 0) == a) { 91 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
92 m += a; 92 m += a;
93 csv = llDeleteSubString(csv, 0, 0); 93 csv = llDeleteSubString(csv, 0, 0);
94 jump continue; 94 jump continue;
95 } 95 }
96 if(a == "\"") { 96 if(a == "\"") {
97 if(llList2String(s, -1) != a) { 97 if(llList2String(s, -1) != a) {
98 s += a; 98 s += a;
99 jump continue; 99 jump continue;
100 } 100 }
101 s = llDeleteSubList(s, -1, -1); 101 s = llDeleteSubList(s, -1, -1);
102 jump continue; 102 jump continue;
103 } 103 }
104 m += a; 104 m += a;
105 @continue; 105 @continue;
106 } while(csv != ""); 106 } while(csv != "");
107 // postcondition: length(s) = 0 107 // postcondition: length(s) = 0
108 return l + m; 108 return l + m;
109 } 109 }
110   110  
111 /////////////////////////////////////////////////////////////////////////// 111 ///////////////////////////////////////////////////////////////////////////
112 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 112 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
113 /////////////////////////////////////////////////////////////////////////// 113 ///////////////////////////////////////////////////////////////////////////
114 string wasListToCSV(list l) { 114 string wasListToCSV(list l) {
115 list v = []; 115 list v = [];
116 do { 116 do {
117 string a = llDumpList2String( 117 string a = llDumpList2String(
118 llParseStringKeepNulls( 118 llParseStringKeepNulls(
119 llList2String( 119 llList2String(
120 l, 120 l,
121 0 121 0
122 ), 122 ),
123 ["\""], 123 ["\""],
124 [] 124 []
125 ), 125 ),
126 "\"\"" 126 "\"\""
127 ); 127 );
128 if(llParseStringKeepNulls( 128 if(llParseStringKeepNulls(
129 a, 129 a,
130 [" ", ",", "\n", "\""], [] 130 [" ", ",", "\n", "\""], []
131 ) != 131 ) !=
132 (list) a 132 (list) a
133 ) a = "\"" + a + "\""; 133 ) a = "\"" + a + "\"";
134 v += a; 134 v += a;
135 l = llDeleteSubList(l, 0, 0); 135 l = llDeleteSubList(l, 0, 0);
136 } while(l != []); 136 } while(l != []);
137 return llDumpList2String(v, ","); 137 return llDumpList2String(v, ",");
138 } 138 }
139   139  
140 /////////////////////////////////////////////////////////////////////////// 140 ///////////////////////////////////////////////////////////////////////////
141 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 141 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
142 /////////////////////////////////////////////////////////////////////////// 142 ///////////////////////////////////////////////////////////////////////////
143 // unescapes a string in conformance with RFC1738 143 // unescapes a string in conformance with RFC1738
144 string wasURLUnescape(string i) { 144 string wasURLUnescape(string i) {
145 return llUnescapeURL( 145 return llUnescapeURL(
146 llDumpList2String( 146 llDumpList2String(
147 llParseString2List( 147 llParseString2List(
148 llDumpList2String( 148 llDumpList2String(
149 llParseString2List( 149 llParseString2List(
150 i, 150 i,
151 ["+"], 151 ["+"],
152 [] 152 []
153 ), 153 ),
154 " " 154 " "
155 ), 155 ),
156 ["%0D%0A"], 156 ["%0D%0A"],
157 [] 157 []
158 ), 158 ),
159 "\n" 159 "\n"
160 ) 160 )
161 ); 161 );
162 } 162 }
163   163  
164 /////////////////////////////////////////////////////////////////////////// 164 ///////////////////////////////////////////////////////////////////////////
165 // Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // 165 // Copyright (C) 2017 Wizardry and Steamworks - License: CC BY 2.0 //
166 /////////////////////////////////////////////////////////////////////////// 166 ///////////////////////////////////////////////////////////////////////////
167 list wasSetIntersect(list a, list b) { 167 list wasSetIntersect(list a, list b) {
168 if(llGetListLength(a) == 0) return []; 168 if(llGetListLength(a) == 0) return [];
169 string i = llList2String(a, 0); 169 string i = llList2String(a, 0);
170 a = llDeleteSubList(a, 0, 0); 170 a = llDeleteSubList(a, 0, 0);
171 if(llListFindList(b, (list)i) == -1) 171 if(llListFindList(b, (list)i) == -1)
172 return wasSetIntersect(a, b); 172 return wasSetIntersect(a, b);
173 return i + wasSetIntersect(a, b); 173 return i + wasSetIntersect(a, b);
174 } 174 }
175   175  
176 // configuration data 176 // configuration data
177 string configuration = ""; 177 string configuration = "";
178 // callback URL 178 // callback URL
179 string URL = ""; 179 string URL = "";
180 // store message over state. 180 // store message over state.
181 string data = ""; 181 string data = "";
182 string jump_table = ""; 182 string jump_table = "";
183 string messageHash = ""; 183 string messageHash = "";
184   184  
185 default { 185 default {
186 state_entry() { 186 state_entry() {
187 llOwnerSay("[AI] Starting..."); 187 llOwnerSay("[AI] Starting...");
188 llSetTimerEvent(10); 188 llSetTimerEvent(10);
189 } 189 }
190 link_message(integer sender, integer num, string message, key id) { 190 link_message(integer sender, integer num, string message, key id) {
191 if(id != "configuration") return; 191 if(id != "configuration") return;
192 llOwnerSay("[AI] Got configuration..."); 192 llOwnerSay("[AI] Got configuration...");
193 configuration = message; 193 configuration = message;
194 194
195 // Subscribe to MQTT messages. 195 // Subscribe to MQTT messages.
196 jump_table = "subscribe"; 196 jump_table = "subscribe";
197 state url; 197 state url;
198 } 198 }
199 timer() { 199 timer() {
200 llOwnerSay("[AI] Requesting configuration..."); 200 llOwnerSay("[AI] Requesting configuration...");
201 llMessageLinked(LINK_THIS, 0, "configuration", NULL_KEY); 201 llMessageLinked(LINK_THIS, 0, "configuration", NULL_KEY);
202 } 202 }
203 on_rez(integer num) { 203 on_rez(integer num) {
204 llResetScript(); 204 llResetScript();
205 } 205 }
206 changed(integer change) { 206 changed(integer change) {
207 if((change & CHANGED_INVENTORY) || 207 if((change & CHANGED_INVENTORY) ||
208 (change & CHANGED_REGION_START) || 208 (change & CHANGED_REGION_START) ||
209 (change & CHANGED_OWNER)) { 209 (change & CHANGED_OWNER)) {
210 llResetScript(); 210 llResetScript();
211 } 211 }
212 } 212 }
213 state_exit() { 213 state_exit() {
214 llSetTimerEvent(0); 214 llSetTimerEvent(0);
215 } 215 }
216 } 216 }
217   217  
218 state url { 218 state url {
219 state_entry() { 219 state_entry() {
220 // DEBUG 220 // DEBUG
221 llOwnerSay("[AI] Requesting URL..."); 221 llOwnerSay("[AI] Requesting URL...");
222 llRequestURL(); 222 llRequestURL();
223 } 223 }
224 http_request(key id, string method, string body) { 224 http_request(key id, string method, string body) {
225 if(method != URL_REQUEST_GRANTED) return; 225 if(method != URL_REQUEST_GRANTED) return;
226 URL = body; 226 URL = body;
227 227
228 // DEBUG 228 // DEBUG
229 llOwnerSay("[AI] Got URL..."); 229 llOwnerSay("[AI] Got URL...");
230 230
231 if(jump_table == "subscribe") 231 if(jump_table == "subscribe")
232 state subscribe; 232 state subscribe;
233 if(jump_table == "publish") 233 if(jump_table == "publish")
234 state publish; 234 state publish;
235 } 235 }
236 on_rez(integer num) { 236 on_rez(integer num) {
237 llResetScript(); 237 llResetScript();
238 } 238 }
239 changed(integer change) { 239 changed(integer change) {
240 if((change & CHANGED_INVENTORY) || 240 if((change & CHANGED_INVENTORY) ||
241 (change & CHANGED_REGION_START) || 241 (change & CHANGED_REGION_START) ||
242 (change & CHANGED_OWNER)) { 242 (change & CHANGED_OWNER)) {
243 llResetScript(); 243 llResetScript();
244 } 244 }
245 } 245 }
246 } 246 }
247   247  
248 state subscribe { 248 state subscribe {
249 state_entry() { 249 state_entry() {
250 // DEBUG 250 // DEBUG
251 llOwnerSay("[AI] Subscribing to Corrade AI..."); 251 llOwnerSay("[AI] Subscribing to Corrade AI...");
252 llInstantMessage( 252 llInstantMessage(
253 wasKeyValueGet( 253 wasKeyValueGet(
254 "corrade", 254 "corrade",
255 configuration 255 configuration
256 ), 256 ),
257 wasKeyValueEncode( 257 wasKeyValueEncode(
258 [ 258 [
259 "command", "MQTT", 259 "command", "MQTT",
260 "group", wasURLEscape( 260 "group", wasURLEscape(
261 wasKeyValueGet( 261 wasKeyValueGet(
262 "group", 262 "group",
263 configuration 263 configuration
264 ) 264 )
265 ), 265 ),
266 "password", wasURLEscape( 266 "password", wasURLEscape(
267 wasKeyValueGet( 267 wasKeyValueGet(
268 "password", 268 "password",
269 configuration 269 configuration
270 ) 270 )
271 ), 271 ),
272 // Subscribe to Corrade AI 272 // Subscribe to Corrade AI
273 "action", "subscribe", 273 "action", "subscribe",
274 "id", wasURLEscape( 274 "id", wasURLEscape(
275 wasKeyValueGet( 275 wasKeyValueGet(
276 "ai subscription", 276 "ai subscription",
277 configuration 277 configuration
278 ) 278 )
279 ), 279 ),
280 // Corrade AI listening host. 280 // Corrade AI listening host.
281 "host", wasURLEscape( 281 "host", wasURLEscape(
282 wasKeyValueGet( 282 wasKeyValueGet(
283 "ai host", 283 "ai host",
284 configuration 284 configuration
285 ) 285 )
286 ), 286 ),
287 // Corrade AI listening port. 287 // Corrade AI listening port.
288 "port", wasURLEscape( 288 "port", wasURLEscape(
289 wasKeyValueGet( 289 wasKeyValueGet(
290 "ai port", 290 "ai port",
291 configuration 291 configuration
292 ) 292 )
293 ), 293 ),
294 // Corrade AI credentials. 294 // Corrade AI credentials.
295 "username", wasURLEscape( 295 "username", wasURLEscape(
296 wasKeyValueGet( 296 wasKeyValueGet(
297 "ai username", 297 "ai username",
298 configuration 298 configuration
299 ) 299 )
300 ), 300 ),
301 "secret", wasURLEscape( 301 "secret", wasURLEscape(
302 wasKeyValueGet( 302 wasKeyValueGet(
303 "ai secret", 303 "ai secret",
304 configuration 304 configuration
305 ) 305 )
306 ), 306 ),
307 // Use the SIML module of Corrade AI. 307 // Use the SIML module of Corrade AI.
308 "topic", "SIML", 308 "topic", "SIML",
309 // Send the result of the MQTT command to this URL. 309 // Send the result of the MQTT command to this URL.
310 "callback", wasURLEscape(URL) 310 "callback", wasURLEscape(URL)
311 ] 311 ]
312 ) 312 )
313 ); 313 );
314 } 314 }
315 315
316 http_request(key id, string method, string body) { 316 http_request(key id, string method, string body) {
317 llHTTPResponse(id, 200, "OK"); 317 llHTTPResponse(id, 200, "OK");
318 llReleaseURL(URL); 318 llReleaseURL(URL);
319 if(wasKeyValueGet("command", body) != "MQTT" || 319 if(wasKeyValueGet("command", body) != "MQTT" ||
320 wasKeyValueGet("success", body) != "True") { 320 wasKeyValueGet("success", body) != "True") {
321 // DEBUG 321 // DEBUG
322 llOwnerSay("[AI] Unable to subscribe to MQTT topic: " + 322 llOwnerSay("[AI] Unable to subscribe to MQTT topic: " +
323 wasURLUnescape( 323 wasURLUnescape(
324 wasKeyValueGet("error", body) 324 wasKeyValueGet("error", body)
325 ) 325 )
326 ); 326 );
327 llResetScript(); 327 llResetScript();
328 } 328 }
329 329
330 state listen_group; 330 state listen_group;
331 } 331 }
332 on_rez(integer num) { 332 on_rez(integer num) {
333 llResetScript(); 333 llResetScript();
334 } 334 }
335 changed(integer change) { 335 changed(integer change) {
336 if((change & CHANGED_INVENTORY) || 336 if((change & CHANGED_INVENTORY) ||
337 (change & CHANGED_REGION_START) || 337 (change & CHANGED_REGION_START) ||
338 (change & CHANGED_OWNER)) { 338 (change & CHANGED_OWNER)) {
339 llResetScript(); 339 llResetScript();
340 } 340 }
341 } 341 }
342 state_exit() { 342 state_exit() {
343 llSetTimerEvent(0); 343 llSetTimerEvent(0);
344 } 344 }
345 } 345 }
346   346  
347 state listen_group { 347 state listen_group {
348 state_entry() { 348 state_entry() {
349 // DEBUG 349 // DEBUG
350 llOwnerSay("[AI] Waiting for group messages..."); 350 llOwnerSay("[AI] Waiting for group messages...");
351 } 351 }
352 link_message(integer sender, integer num, string message, key id) { 352 link_message(integer sender, integer num, string message, key id) {
353 // We only care about notifications now. 353 // We only care about notifications now.
354 if(id != "notification") 354 if(id != "notification")
355 return; 355 return;
356 356
357 // Listen to group message notifications. 357 // Listen to group message notifications.
358 if(wasKeyValueGet("type", message) != "group") 358 if(wasKeyValueGet("type", message) != "group")
359 return; 359 return;
360 360
361 // Get the sent message. 361 // Get the sent message.
362 data = wasURLUnescape( 362 data = wasURLUnescape(
363 wasKeyValueGet( 363 wasKeyValueGet(
364 "message", 364 "message",
365 message 365 message
366 ) 366 )
367 ); 367 );
368 368
369 // Check if this is an eggdrop command. 369 // Check if this is an eggdrop command.
370 if(llGetSubString(data, 0, 0) != 370 if(llGetSubString(data, 0, 0) !=
371 wasKeyValueGet("command", configuration)) 371 wasKeyValueGet("command", configuration))
372 return; 372 return;
373 373
374 // Check if the command matches the current module. 374 // Check if the command matches the current module.
375 list command = llParseString2List(data, [" "], []); 375 list command = llParseString2List(data, [" "], []);
376 if(llList2String(command, 0) != 376 if(llList2String(command, 0) !=
377 wasKeyValueGet("command", configuration) + 377 wasKeyValueGet("command", configuration) +
378 wasKeyValueGet("nickname", configuration)) 378 wasKeyValueGet("nickname", configuration))
379 return; 379 return;
380 380
381 // Remove command. 381 // Remove command.
382 command = llDeleteSubList(command, 0, 0); 382 command = llDeleteSubList(command, 0, 0);
383 383
384 // Dump the rest of the message. 384 // Dump the rest of the message.
385 data = llDumpList2String(command, " "); 385 data = llDumpList2String(command, " ");
386   386  
387 // Get an URL. 387 // Get an URL.
388 jump_table = "publish"; 388 jump_table = "publish";
389 state url; 389 state url;
390 } 390 }
391 on_rez(integer num) { 391 on_rez(integer num) {
392 llResetScript(); 392 llResetScript();
393 } 393 }
394 changed(integer change) { 394 changed(integer change) {
395 if((change & CHANGED_INVENTORY) || 395 if((change & CHANGED_INVENTORY) ||
396 (change & CHANGED_REGION_START) || 396 (change & CHANGED_REGION_START) ||
397 (change & CHANGED_OWNER)) { 397 (change & CHANGED_OWNER)) {
398 llResetScript(); 398 llResetScript();
399 } 399 }
400 } 400 }
401 } 401 }
402   402  
403 state publish { 403 state publish {
404 state_entry() { 404 state_entry() {
405 // DEBUG 405 // DEBUG
406 llOwnerSay("[AI] Sending to AI for processing..."); 406 llOwnerSay("[AI] Sending to AI for processing...");
407 407
408 messageHash = llSHA1String(data); 408 messageHash = llSHA1String(data);
409 409
410 llInstantMessage( 410 llInstantMessage(
411 wasKeyValueGet( 411 wasKeyValueGet(
412 "corrade", 412 "corrade",
413 configuration 413 configuration
414 ), 414 ),
415 wasKeyValueEncode( 415 wasKeyValueEncode(
416 [ 416 [
417 "command", "MQTT", 417 "command", "MQTT",
418 "group", wasURLEscape( 418 "group", wasURLEscape(
419 wasKeyValueGet( 419 wasKeyValueGet(
420 "group", 420 "group",
421 configuration 421 configuration
422 ) 422 )
423 ), 423 ),
424 "password", wasURLEscape( 424 "password", wasURLEscape(
425 wasKeyValueGet( 425 wasKeyValueGet(
426 "password", 426 "password",
427 configuration 427 configuration
428 ) 428 )
429 ), 429 ),
430 "action", "publish", 430 "action", "publish",
431 // Corrade AI listening host. 431 // Corrade AI listening host.
432 "host", wasURLEscape( 432 "host", wasURLEscape(
433 wasKeyValueGet( 433 wasKeyValueGet(
434 "ai host", 434 "ai host",
435 configuration 435 configuration
436 ) 436 )
437 ), 437 ),
438 // Corrade AI listening port. 438 // Corrade AI listening port.
439 "port", wasURLEscape( 439 "port", wasURLEscape(
440 wasKeyValueGet( 440 wasKeyValueGet(
441 "ai port", 441 "ai port",
442 configuration 442 configuration
443 ) 443 )
444 ), 444 ),
445 // Corrade AI credentials. 445 // Corrade AI credentials.
446 "username", wasURLEscape( 446 "username", wasURLEscape(
447 wasKeyValueGet( 447 wasKeyValueGet(
448 "ai username", 448 "ai username",
449 configuration 449 configuration
450 ) 450 )
451 ), 451 ),
452 "secret", wasURLEscape( 452 "secret", wasURLEscape(
453 wasKeyValueGet( 453 wasKeyValueGet(
454 "ai secret", 454 "ai secret",
455 configuration 455 configuration
456 ) 456 )
457 ), 457 ),
458 // Use the SIML module of Corrade AI. 458 // Use the SIML module of Corrade AI.
459 "topic", "SIML", 459 "topic", "SIML",
460 "payload", wasURLEscape( 460 "payload", wasURLEscape(
461 wasKeyValueEncode( 461 wasKeyValueEncode(
462 [ 462 [
463 // The hash is an identifier that will allow responses from Corrade AI 463 // The hash is an identifier that will allow responses from Corrade AI
464 // for various messages to be distinguished. It can be any identifier 464 // for various messages to be distinguished. It can be any identifier
465 // but a handy way of generating an identifier is to hash the message. 465 // but a handy way of generating an identifier is to hash the message.
466 "Hash", messageHash, 466 "Hash", messageHash,
467 // Note the double escaping! 467 // Note the double escaping!
468 "Message", wasURLEscape(data) 468 "Message", wasURLEscape(data)
469 ] 469 ]
470 ) 470 )
471 ), 471 ),
472 "callback", wasURLEscape(URL) 472 "callback", wasURLEscape(URL)
473 ] 473 ]
474 ) 474 )
475 ); 475 );
476 llSetTimerEvent(60); 476 llSetTimerEvent(60);
477 } 477 }
478 http_request(key id, string method, string body) { 478 http_request(key id, string method, string body) {
479 llHTTPResponse(id, 200, "OK"); 479 llHTTPResponse(id, 200, "OK");
480 llReleaseURL(URL); 480 llReleaseURL(URL);
481 if(wasKeyValueGet("command", body) != "MQTT" || 481 if(wasKeyValueGet("command", body) != "MQTT" ||
482 wasKeyValueGet("success", body) != "True") { 482 wasKeyValueGet("success", body) != "True") {
483 // DEBUG 483 // DEBUG
484 llOwnerSay("[AI] Unable to publish message: " + 484 llOwnerSay("[AI] Unable to publish message: " +
485 wasURLUnescape( 485 wasURLUnescape(
486 wasKeyValueGet("data", body) 486 wasKeyValueGet("data", body)
487 ) 487 )
488 ); 488 );
489 state listen_group; 489 state listen_group;
490 } 490 }
491 491
492 // DEBUG 492 // DEBUG
493 llOwnerSay("[AI] Message published successfully..."); 493 llOwnerSay("[AI] Message published successfully...");
494 } 494 }
495 link_message(integer sender, integer num, string message, key id) { 495 link_message(integer sender, integer num, string message, key id) {
496 // We only care about notifications now. 496 // We only care about notifications now.
497 if(id != "notification") 497 if(id != "notification")
498 return; 498 return;
499 499
500 // Listen to MQTT messages. 500 // Listen to MQTT messages.
501 if(wasKeyValueGet("type", message) != "MQTT") 501 if(wasKeyValueGet("type", message) != "MQTT")
502 return; 502 return;
503 503
504 // Get the sent message. 504 // Get the sent message.
505 data = wasURLUnescape( 505 data = wasURLUnescape(
506 wasKeyValueGet( 506 wasKeyValueGet(
507 "payload", 507 "payload",
508 message 508 message
509 ) 509 )
510 ); 510 );
511 511
512 string hash = wasURLUnescape( 512 string hash = wasURLUnescape(
513 wasKeyValueGet( 513 wasKeyValueGet(
514 "Hash", 514 "Hash",
515 data 515 data
516 ) 516 )
517 ); 517 );
518 518
519 string serverMessage = wasURLUnescape( 519 string serverMessage = wasURLUnescape(
520 wasKeyValueGet( 520 wasKeyValueGet(
521 "ServerMessage", 521 "ServerMessage",
522 data 522 data
523 ) 523 )
524 ); 524 );
525 525
526 // Skip generated messages that are not for the published message. 526 // Skip generated messages that are not for the published message.
527 if(hash != messageHash || 527 if(hash != messageHash ||
528 serverMessage != "True") 528 serverMessage != "True")
529 return; 529 return;
530 530
531 data = wasURLUnescape( 531 data = wasURLUnescape(
532 wasKeyValueGet( 532 wasKeyValueGet(
533 "Message", 533 "Message",
534 data 534 data
535 ) 535 )
536 ); 536 );
537 537
538 state tell; 538 state tell;
539 } 539 }
540 timer() { 540 timer() {
541 llReleaseURL(URL); 541 llReleaseURL(URL);
542 state listen_group; 542 state listen_group;
543 } 543 }
544 on_rez(integer num) { 544 on_rez(integer num) {
545 llResetScript(); 545 llResetScript();
546 } 546 }
547 changed(integer change) { 547 changed(integer change) {
548 if((change & CHANGED_INVENTORY) || 548 if((change & CHANGED_INVENTORY) ||
549 (change & CHANGED_REGION_START) || 549 (change & CHANGED_REGION_START) ||
550 (change & CHANGED_OWNER)) { 550 (change & CHANGED_OWNER)) {
551 llResetScript(); 551 llResetScript();
552 } 552 }
553 } 553 }
554 state_exit() { 554 state_exit() {
555 llSetTimerEvent(0); 555 llSetTimerEvent(0);
556 } 556 }
557 } 557 }
558   558  
559 state tell { 559 state tell {
560 state_entry() { 560 state_entry() {
561 // DEBUG 561 // DEBUG
562 llOwnerSay("[AI] Sending to group."); 562 llOwnerSay("[AI] Sending to group.");
563 llInstantMessage( 563 llInstantMessage(
564 wasKeyValueGet( 564 wasKeyValueGet(
565 "corrade", 565 "corrade",
566 configuration 566 configuration
567 ), 567 ),
568 wasKeyValueEncode( 568 wasKeyValueEncode(
569 [ 569 [
570 "command", "tell", 570 "command", "tell",
571 "group", wasURLEscape( 571 "group", wasURLEscape(
572 wasKeyValueGet( 572 wasKeyValueGet(
573 "group", 573 "group",
574 configuration 574 configuration
575 ) 575 )
576 ), 576 ),
577 "password", wasURLEscape( 577 "password", wasURLEscape(
578 wasKeyValueGet( 578 wasKeyValueGet(
579 "password", 579 "password",
580 configuration 580 configuration
581 ) 581 )
582 ), 582 ),
583 "entity", "group", 583 "entity", "group",
584 "message", wasURLEscape(data) 584 "message", wasURLEscape(data)
585 ] 585 ]
586 ) 586 )
587 ); 587 );
588 state listen_group; 588 state listen_group;
589 } 589 }
590 } 590 }
591   591