corrade-lsl-templates

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 37  →  ?path2? @ 38
/source/grid-follow/grid-follow.lsl
@@ -1,30 +1,19 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// This is an automatic grid follower for the Corrade Second Life / OpenSim
// bot. You can find more details about the bot by following the URL:
// http://was.fm/secondlife/scripted_agents/corrade
//
// The follower script works together with a "configuration" notecard and
// that must be placed in the same primitive as this script.
// You are free to use, change, and commercialize it under the GNU/GPLv3
// license at: http://www.gnu.org/licenses/gpl.html
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, i+1);
list a = llParseStringKeepNulls(data, ["&", "="], []);
integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
if(i != -1) return llList2String(a, 2*i+1);
return "";
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
@@ -57,18 +46,18 @@
integer wasIsAvatarInSensorRange(key avatar) {
return llListFindList(
llGetAgentList(
AGENT_LIST_REGION,
AGENT_LIST_REGION,
[]
),
),
(list)((key)avatar)
) != -1 &&
) != -1 &&
llVecDist(
llGetPos(),
llGetPos(),
llList2Vector(
llGetObjectDetails(
avatar,
avatar,
[OBJECT_POS]
),
),
0
)
) <= 96;
@@ -102,7 +91,7 @@
string CORRADE = "";
string GROUP = "";
string PASSWORD = "";
string RANGE = "";
integer RANGE = 5;
 
// for holding the callback URL
string callback = "";
@@ -109,10 +98,10 @@
 
// for notecard reading
integer line = 0;
 
// key-value data will be read into this list
list tuples = [];
 
default {
state_entry() {
// set color for button
@@ -135,7 +124,7 @@
CORRADE = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"corrade"
]
@@ -148,7 +137,7 @@
GROUP = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"group"
]
@@ -161,7 +150,7 @@
PASSWORD = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"password"
]
@@ -171,16 +160,16 @@
llOwnerSay("Error in configuration notecard: group");
return;
}
RANGE = llList2String(
RANGE = llList2Integer(
tuples,
llListFindList(
tuples,
tuples,
[
"range"
]
)
+1);
if(RANGE == "") {
if(RANGE == 0) {
llOwnerSay("Error in configuration notecard: range");
return;
}
@@ -197,10 +186,10 @@
llParseString2List(
llStringTrim(
llList2String(
o,
o,
0
),
STRING_TRIM),
),
STRING_TRIM),
["\""], []
), "\"");
string v = llDumpList2String(
@@ -207,10 +196,10 @@
llParseString2List(
llStringTrim(
llList2String(
o,
o,
1
),
STRING_TRIM),
),
STRING_TRIM),
["\""], []
), "\"");
if(k == "" || v == "") jump continue;
@@ -228,7 +217,7 @@
}
}
}
 
state url {
state_entry() {
// DEBUG
@@ -269,19 +258,21 @@
}
}
}
 
state on {
state_entry() {
// set color for button
llSetColor(<0,1,0>, ALL_SIDES);
// if Corrade is in-range then just follow
if(wasIsAvatarInSensorRange(CORRADE)) state follow;
if(wasIsAvatarInSensorRange(CORRADE)) {
state follow;
}
// DEBUG
llOwnerSay("Detecting if Corrade is online...");
llSetTimerEvent(5);
}
timer() {
llRequestAgentData((key)CORRADE, DATA_ONLINE);
llRequestAgentData(CORRADE, DATA_ONLINE);
}
dataserver(key id, string data) {
if(data != "1") {
@@ -290,12 +281,12 @@
llSetTimerEvent(30);
return;
}
llSensorRepeat("", (key)CORRADE, AGENT, (integer)RANGE, TWO_PI, 5);
llSensorRepeat("", CORRADE, AGENT, RANGE, TWO_PI, 5);
}
no_sensor() {
// DEBUG
llOwnerSay("Teleporting Corrade...");
llInstantMessage((key)CORRADE,
llInstantMessage(CORRADE,
wasKeyValueEncode(
[
"command", "teleport",
@@ -310,19 +301,21 @@
);
}
sensor(integer num) {
llSetTimerEvent(0);
state follow;
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "teleport" ||
wasKeyValueGet("success", body) != "True") {
if(wasKeyValueGet("command", body) == "teleport") {
integer success = wasKeyValueGet("success", body) == "True";
if(success) {
// DEBUG
llOwnerSay("Teleport succeeded...");
state follow;
}
// DEBUG
llOwnerSay("Teleport failed...");
return;
}
llSetTimerEvent(0);
state follow;
}
on_rez(integer num) {
llResetScript();
@@ -332,8 +325,11 @@
llResetScript();
}
}
state_exit() {
llSetTimerEvent(0);
}
}
 
state follow {
state_entry() {
// DEBUG
@@ -348,13 +344,15 @@
// if Corrade is not online
if(data != "1") state on;
// Corrade is online, so attempt to dectect
llSensorRepeat("", CORRADE, AGENT, (integer)RANGE, TWO_PI, 1);
llSensorRepeat("", CORRADE, AGENT, RANGE, TWO_PI, 1);
}
no_sensor() {
// check if Corrade is in range, and if not, start detecting
if(!wasIsAvatarInSensorRange(CORRADE)) state on;
if(!wasIsAvatarInSensorRange(CORRADE)) {
state on;
}
// Corrade is in sensor range, so execute move.
llInstantMessage(CORRADE,
llInstantMessage(CORRADE,
wasKeyValueEncode(
[
"command", "walkto",
@@ -378,4 +376,4 @@
llResetScript();
}
}
}
}
/source/remote-region-scanning-device/remote-region-scanning-device.lsl
@@ -1,33 +1,23 @@
 
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 //
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// This is a device meant to scan regions and show metrics for the Corrade
// Second Life / OpenSim bot. You can find more details about the bot
// by following the URL: http://was.fm/secondlife/scripted_agents/corrade
//
// The script works in conjunction with a "configuration" notecard and a
// "regions" notecard that must both be placed in the same primitive.
// The purpose of this script is to demonstrate scanning with Corrade and
// you are free to use, change, and commercialize it under the CC BY 2.0
// license at: https://creativecommons.org/licenses/by/2.0
//
///////////////////////////////////////////////////////////////////////////
 
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, i+1);
list a = llParseStringKeepNulls(data, ["&", "="], []);
integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
if(i != -1) return llList2String(a, 2*i+1);
return "";
}
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list data) {
list k = llList2ListStrided(data, 0, -1, 2);
@@ -40,19 +30,19 @@
} while(llGetListLength(k) != 0);
return llDumpList2String(data, "&");
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
integer wasListCountExclude(list input, list exclude) {
if(llGetListLength(input) == 0) return 0;
if(llListFindList(exclude, (list)llList2String(input, 0)) == -1)
if(llListFindList(exclude, (list)llList2String(input, 0)) == -1)
return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasListToCSV(list l) {
list v = [];
@@ -60,10 +50,10 @@
string a = llDumpList2String(
llParseStringKeepNulls(
llList2String(
l,
l,
0
),
["\""],
),
["\""],
[]
),
"\"\""
@@ -75,9 +65,9 @@
} while(l != []);
return llDumpList2String(v, ",");
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
list wasCSVToList(string csv) {
list l = [];
@@ -114,9 +104,9 @@
// invariant: length(s) = 0
return l + m;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
// escapes a string in conformance with RFC1738
string wasURLEscape(string i) {
@@ -138,9 +128,9 @@
} while(i != "");
return o;
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
// unescapes a string in conformance with RFC1738
string wasURLUnescape(string i) {
@@ -149,28 +139,29 @@
llParseString2List(
llDumpList2String(
llParseString2List(
i,
["+"],
i,
["+"],
[]
),
),
" "
),
["%0D%0A"],
),
["%0D%0A"],
[]
),
),
"\n"
)
);
}
 
// corrade data
string CORRADE = "";
string GROUP = "";
string PASSWORD = "";
 
float WAIT = 5;
// for holding the callback URL
string callback = "";
 
// for notecard reading
integer line = 0;
@@ -179,7 +170,7 @@
// regions will be stored here
list regions = [];
string region = "";
 
default {
state_entry() {
if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
@@ -200,12 +191,13 @@
CORRADE = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"corrade"
]
)
+1);
+1
);
if(CORRADE == "") {
llOwnerSay("Error in configuration notecard: corrade");
return;
@@ -213,12 +205,13 @@
GROUP = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"group"
]
)
+1);
+1
);
if(GROUP == "") {
llOwnerSay("Error in configuration notecard: group");
return;
@@ -226,16 +219,31 @@
PASSWORD = llList2String(
tuples,
llListFindList(
tuples,
tuples,
[
"password"
]
)
+1);
+1
);
if(PASSWORD == "") {
llOwnerSay("Error in configuration notecard: password");
return;
}
WAIT = (float)llList2String(
tuples,
llListFindList(
tuples,
[
"wait"
]
)
+1
);
if(WAIT == 0) {
llOwnerSay("Error in configuration notecard: wait");
return;
}
// DEBUG
llOwnerSay("Read configuration notecard...");
state read;
@@ -249,10 +257,10 @@
llParseString2List(
llStringTrim(
llList2String(
o,
o,
0
),
STRING_TRIM),
),
STRING_TRIM),
["\""], []
), "\"");
string v = llDumpList2String(
@@ -259,10 +267,10 @@
llParseString2List(
llStringTrim(
llList2String(
o,
o,
1
),
STRING_TRIM),
),
STRING_TRIM),
["\""], []
), "\"");
if(k == "" || v == "") jump continue;
@@ -280,7 +288,7 @@
}
}
}
 
state read {
state_entry() {
if(llGetInventoryType("regions") != INVENTORY_NOTECARD) {
@@ -352,8 +360,58 @@
llSetTimerEvent(30);
return;
}
state notify;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
llResetScript();
}
}
}
state notify {
state_entry() {
// Timeout in 60s.
llSetTimerEvent(60);
// DEBUG
llOwnerSay("Binding to the CAPS notification...");
llInstantMessage(
(key)CORRADE,
wasKeyValueEncode(
[
"command", "notify",
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"action", "set",
"type", "CAPS",
"URL", wasURLEscape(callback),
"callback", wasURLEscape(callback)
]
)
);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "notify") return;
if(wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("Failed to bind to the CAPS notification...");
llResetScript();
}
// DEBUG
llOwnerSay("CAPS notification installed...");
state teleport;
}
timer() {
// DEBUG
llOwnerSay("Timeout binding to the CAPS notifications...");
llResetScript();
}
on_rez(integer num) {
llResetScript();
}
@@ -363,21 +421,34 @@
}
}
}
 
state teleport {
state_entry() {
// Timeout in one minute.
// Emergency timeout
llSetTimerEvent(60);
// Check that Corrade is online.
llSensorRepeat("", NULL_KEY, AGENT, 0.1, 0.1, 5);
// Shuffle the regions and grab the next region.
region = llList2String(regions, 0);
regions = llDeleteSubList(regions, 0, 0);
regions += region;
// The selected region is the current region so reshufle.
if(region == llGetRegionName()) {
// DEBUG
llOwnerSay("Already on current region " + region + ", trying the next region.");
region = llList2String(regions, 0);
regions = llDeleteSubList(regions, 0, 0);
regions += region;
}
// DEBUG
llOwnerSay("Teleporting to: " + region);
llInstantMessage(
(key)CORRADE,
(key)CORRADE,
wasKeyValueEncode(
[
"command", "teleport",
@@ -385,6 +456,7 @@
"password", wasURLEscape(PASSWORD),
"entity", "region",
"region", wasURLEscape(region),
"position", wasURLEscape((string)<128, 128, 50>),
"callback", wasURLEscape(callback)
]
)
@@ -392,13 +464,17 @@
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "teleport" ||
wasKeyValueGet("success", body) != "True") {
if(wasKeyValueGet("command", body) == "teleport") {
if(wasKeyValueGet("success", body) == "True") {
// DEBUG
llOwnerSay("Teleported successfully to: " + region + " and waiting for capabiltiies...");
return;
}
// DEBUG
llOwnerSay("Failed to teleport to " + region + " due to: " +
llOwnerSay("Failed to teleport to " + region + " due to: " +
wasURLUnescape(
wasKeyValueGet(
"error",
"error",
body
)
)
@@ -406,9 +482,30 @@
// Jump to trampoline for re-entry.
state teleport_trampoline;
}
if(wasKeyValueGet("notification", body) == "CAPS") {
string capsRegion = wasURLUnescape(
wasKeyValueGet(
"region",
body
)
);
string capsAction = wasURLUnescape(
wasKeyValueGet(
"action",
body
)
);
if(capsRegion == region && capsAction == "start") {
llOwnerSay("Capabiltiies for region " + region + " successfully connected.");
state stats_trampoline;
}
}
}
timer() {
// DEBUG
llOwnerSay("Teleported successfully to: " + region);
state stats_trampoline;
llOwnerSay("Timeout receiving capabilities, attempting emergency teleport...");
state teleport_trampoline;
}
no_sensor() {
llRequestAgentData((key)CORRADE, DATA_ONLINE);
@@ -420,9 +517,6 @@
state detect;
}
}
timer() {
state teleport_trampoline;
}
on_rez(integer num) {
llResetScript();
}
@@ -435,12 +529,12 @@
llSetTimerEvent(0);
}
}
 
state teleport_trampoline {
state_entry() {
// DEBUG
llOwnerSay("Sleeping...");
llSetTimerEvent(30);
llSetTimerEvent(WAIT);
}
timer() {
state teleport;
@@ -457,12 +551,12 @@
llSetTimerEvent(0);
}
}
 
state stats_trampoline {
state_entry() {
// DEBUG
llOwnerSay("Sleeping...");
llSetTimerEvent(10);
llSetTimerEvent(1);
}
timer() {
state stats;
@@ -479,17 +573,19 @@
llSetTimerEvent(0);
}
}
 
state stats {
state_entry() {
// Timeout in one minute.
llSetTimerEvent(60);
// Check that Corrade is online.
llSensorRepeat("", NULL_KEY, AGENT, 0.1, 0.1, 5);
// DEBUG
llOwnerSay("Fetching region statistics...");
llInstantMessage(
(key)CORRADE,
(key)CORRADE,
wasKeyValueEncode(
[
"command", "getregiondata",
@@ -496,8 +592,8 @@
"group", wasURLEscape(GROUP),
"password", wasURLEscape(PASSWORD),
"data", wasListToCSV([
// For a full list see: http://was.fm/secondlife/scripted_agents/corrade/application_programming_interface#get_region_data
"Stats.LastLag",
// For a full list see: https://grimore.org/secondlife/scripted_agents/corrade/api/commands/getregiondata
"Stats.LastLag",
"Stats.Agents",
"Stats.Dilation",
"Stats.FPS",
@@ -507,7 +603,7 @@
"Stats.PhysicsFPS",
"Stats.ScriptTime"
]),
"callback", wasURLEscape(callback)
"callback", wasURLEscape(callback)
]
)
);
@@ -514,13 +610,17 @@
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
// Ignore CAPS notification here.
if(wasKeyValueGet("notification", body) == "CAPS") {
return;
}
if(wasKeyValueGet("command", body) != "getregiondata" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("Failed to get stats for " + region + " due to: " +
llOwnerSay("Failed to get stats for " + region + " due to: " +
wasURLUnescape(
wasKeyValueGet(
"error",
"error",
body
)
)
@@ -534,7 +634,7 @@
list stat = wasCSVToList(
wasURLUnescape(
wasKeyValueGet(
"data",
"data",
body
)
)
@@ -542,61 +642,61 @@
llSetText("-:[ " + region + " ]:- \n" +
// Show the stats in the overhead text.
"Agents: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.Agents"
)+1
) + "\n" +
) + "\n" +
"LastLag: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.LastLag"
)+1
) + "\n" +
) + "\n" +
"Time Dilation: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.Dilation"
)+1
) + "\n" +
) + "\n" +
"FPS: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.FPS"
)+1
) + "\n" +
"Physics FPS: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.PhysicsFPS"
)+1
) + "\n" +
"Scripts: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.ActiveScripts"
)+1
) + "\n" +
"Script Time: " + llList2String(
stat,
stat,
llListFindList(
stat,
stat,
(list)"Stats.ScriptTime"
)+1
) + "\n" +
"Objects: " + llList2String(
stat,
stat,
llListFindList(
stat, (list)"Stats.Objects"
)+1
),
<1, 0, 0>,
),
<1, 0, 0>,
1.0
);
stat = [];
@@ -627,4 +727,3 @@
llSetTimerEvent(0);
}
}