corrade-lsl-templates

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 37  →  ?path2? @ 38
/source/grid-follow/grid-follow.lsl
@@ -1,27 +1,16 @@
///////////////////////////////////////////////////////////////////////////
// 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 "";
}
@@ -102,7 +91,7 @@
string CORRADE = "";
string GROUP = "";
string PASSWORD = "";
string RANGE = "";
integer RANGE = 5;
 
// for holding the callback URL
string callback = "";
@@ -171,7 +160,7 @@
llOwnerSay("Error in configuration notecard: group");
return;
}
RANGE = llList2String(
RANGE = llList2Integer(
tuples,
llListFindList(
tuples,
@@ -180,7 +169,7 @@
]
)
+1);
if(RANGE == "") {
if(RANGE == 0) {
llOwnerSay("Error in configuration notecard: range");
return;
}
@@ -275,13 +264,15 @@
// 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,7 +325,10 @@
llResetScript();
}
}
state_exit() {
llSetTimerEvent(0);
}
}
state follow {
state_entry() {
@@ -348,11 +344,13 @@
// 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,
wasKeyValueEncode(
/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) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
// 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: CC BY 2.0 //
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list data) {
list k = llList2ListStrided(data, 0, -1, 2);
@@ -42,7 +32,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// 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;
@@ -52,7 +42,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// 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 = [];
@@ -77,7 +67,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// 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 = [];
@@ -116,7 +106,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// 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) {
@@ -140,7 +130,7 @@
}
 
///////////////////////////////////////////////////////////////////////////
// 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) {
@@ -167,6 +157,7 @@
string CORRADE = "";
string GROUP = "";
string PASSWORD = "";
float WAIT = 5;
 
// for holding the callback URL
string callback = "";
@@ -205,7 +196,8 @@
"corrade"
]
)
+1);
+1
);
if(CORRADE == "") {
llOwnerSay("Error in configuration notecard: corrade");
return;
@@ -218,7 +210,8 @@
"group"
]
)
+1);
+1
);
if(GROUP == "") {
llOwnerSay("Error in configuration notecard: group");
return;
@@ -231,11 +224,26 @@
"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;
@@ -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();
}
@@ -366,16 +424,29 @@
 
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,
wasKeyValueEncode(
@@ -385,6 +456,7 @@
"password", wasURLEscape(PASSWORD),
"entity", "region",
"region", wasURLEscape(region),
"position", wasURLEscape((string)<128, 128, 50>),
"callback", wasURLEscape(callback)
]
)
@@ -392,9 +464,13 @@
}
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: " +
wasURLUnescape(
wasKeyValueGet(
@@ -406,10 +482,31 @@
// Jump to trampoline for re-entry.
state teleport_trampoline;
}
// DEBUG
llOwnerSay("Teleported successfully to: " + region);
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("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();
}
@@ -440,7 +534,7 @@
state_entry() {
// DEBUG
llOwnerSay("Sleeping...");
llSetTimerEvent(30);
llSetTimerEvent(WAIT);
}
timer() {
state teleport;
@@ -462,7 +556,7 @@
state_entry() {
// DEBUG
llOwnerSay("Sleeping...");
llSetTimerEvent(10);
llSetTimerEvent(1);
}
timer() {
state stats;
@@ -484,8 +578,10 @@
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(
@@ -496,7 +592,7 @@
"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
// For a full list see: https://grimore.org/secondlife/scripted_agents/corrade/api/commands/getregiondata
"Stats.LastLag",
"Stats.Agents",
"Stats.Dilation",
@@ -514,6 +610,10 @@
}
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
@@ -627,4 +727,3 @@
llSetTimerEvent(0);
}
}