new apps
parent
5fb3ac714e
commit
2097267b9a
|
|
@ -0,0 +1,199 @@
|
||||||
|
/* =========================================================================
|
||||||
|
*
|
||||||
|
* Nanite Systems Advanced Research Encapsulation System
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025–2026 Nanite Systems Corporation
|
||||||
|
*
|
||||||
|
* =========================================================================
|
||||||
|
*
|
||||||
|
* Instructor Application
|
||||||
|
*
|
||||||
|
* This program is covered under the terms of the ARES Software Copyright
|
||||||
|
* License, Section 3 (ASCL-iii). It may be redistributed or used as the
|
||||||
|
* basis of commercial, closed-source products so long as steps are taken
|
||||||
|
* to ensure proper attribution as defined in the text of the license.
|
||||||
|
*
|
||||||
|
* To see the full text of the ASCL, type 'help license' on any standard
|
||||||
|
* ARES distribution, or visit http://nanite-systems.com/ASCL for the
|
||||||
|
* current version.
|
||||||
|
*
|
||||||
|
* DISCLAIMER
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS
|
||||||
|
* IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DAMAGES HOWEVER CAUSED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* =========================================================================
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ARES/a>
|
||||||
|
#include <ARES/api/interface.consts.h.lsl>
|
||||||
|
|
||||||
|
#define CLIENT_VERSION "1.0.0"
|
||||||
|
#define CLIENT_VERSION_TAGS "release"
|
||||||
|
|
||||||
|
#define DEFAULT_INTERVAL 30
|
||||||
|
#define DEFAULT_ANCHOR CLADDING_BACKDROP
|
||||||
|
|
||||||
|
integer enabled = FALSE;
|
||||||
|
integer interval = DEFAULT_INTERVAL;
|
||||||
|
string section = "instruction";
|
||||||
|
integer random = FALSE;
|
||||||
|
integer anchor = DEFAULT_ANCHOR;
|
||||||
|
integer offset = 0;
|
||||||
|
|
||||||
|
main(integer src, integer n, string m, key outs, key ins, key user) {
|
||||||
|
if(n == SIGNAL_INVOKE) {
|
||||||
|
list argv = split(m, " ");
|
||||||
|
integer argc = count(argv);
|
||||||
|
string msg = "";
|
||||||
|
string action = gets(argv, 1);
|
||||||
|
if(argc == 1 || action == "help") {
|
||||||
|
msg = "Usage: " + PROGRAM_NAME + " ...\n\n "
|
||||||
|
+ PROGRAM_NAME + " help: this message\n "
|
||||||
|
+ PROGRAM_NAME + " anchor <n>: set anchor prim (currently: " + (string)anchor + "); 0 for chat\n "
|
||||||
|
+ PROGRAM_NAME + " on|off|toggle: enable/disable/toggle instructor (currently: " + gets(["off", "on"], enabled) + ")\n "
|
||||||
|
+ PROGRAM_NAME + " interval <n>: set interval to <n> sec (currently: " + (string)interval + " sec)\n "
|
||||||
|
+ PROGRAM_NAME + " random|sequential: set random message selection on/off (currently: " + gets(["off", "on"], random) + ")\n "
|
||||||
|
+ PROGRAM_NAME + " from <section>: use LSD:<section> as input (currently: " + section + ")"
|
||||||
|
;
|
||||||
|
} else if(action == "anchor") {
|
||||||
|
setdbl("instructor", ["anchor"], (string)(anchor = (integer)gets(argv, 2)));
|
||||||
|
if(anchor < 0)
|
||||||
|
anchor = 0;
|
||||||
|
|
||||||
|
} else if(action == "on") {
|
||||||
|
setdbl("instructor", ["enabled"], (string)(enabled = TRUE));
|
||||||
|
set_timer("instruct", interval);
|
||||||
|
|
||||||
|
} else if(action == "off") {
|
||||||
|
setdbl("instructor", ["enabled"], (string)(enabled = FALSE));
|
||||||
|
set_timer("instruct", 0);
|
||||||
|
|
||||||
|
} else if(action == "toggle") {
|
||||||
|
setdbl("instructor", ["enabled"], (string)(enabled = !enabled));
|
||||||
|
if(enabled)
|
||||||
|
set_timer("instruct", interval);
|
||||||
|
else
|
||||||
|
set_timer("instruct", 0);
|
||||||
|
|
||||||
|
} else if(action == "interval") {
|
||||||
|
integer new_interval = (integer)gets(argv, 2);
|
||||||
|
if(new_interval >= 6) {
|
||||||
|
setdbl("instructor", ["interval"], (string)(interval = new_interval));
|
||||||
|
if(enabled)
|
||||||
|
set_timer("instruct", interval);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
msg = "Interval must be at least 6 sec. Use '@" + PROGRAM_NAME + " off' to disable instruction.";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(action == "random") {
|
||||||
|
setdbl("instructor", ["random"], (string)(random = TRUE));
|
||||||
|
|
||||||
|
} else if(action == "sequential") {
|
||||||
|
setdbl("instructor", ["random"], (string)(random = FALSE));
|
||||||
|
|
||||||
|
} else if(action == "from") {
|
||||||
|
string new_section = gets(argv, 2);
|
||||||
|
if(llOrd(llLinksetDataRead(new_section), 0) == 0x5b) { // '['
|
||||||
|
setdbl("instructor", ["section"], section = new_section);
|
||||||
|
} else {
|
||||||
|
msg = "Section '" + new_section + "' does not contain a JSON array.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg != "")
|
||||||
|
print(outs, user, msg);
|
||||||
|
} else if(n == SIGNAL_INIT) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
echo("[" + PROGRAM_NAME + "] init event");
|
||||||
|
#endif
|
||||||
|
enabled = (integer)getdbl("instructor", ["enabled"]);
|
||||||
|
random = (integer)getdbl("instructor", ["random"]);
|
||||||
|
interval = (integer)getdbl("instructor", ["interval"]);
|
||||||
|
string raw_anchor = getdbl("instructor", ["anchor"]);
|
||||||
|
if(raw_anchor == JSON_INVALID) {
|
||||||
|
setdbl("instructor", ["anchor"], (string)(anchor = DEFAULT_ANCHOR));
|
||||||
|
} else {
|
||||||
|
anchor = (integer)raw_anchor;
|
||||||
|
}
|
||||||
|
if(anchor < 0)
|
||||||
|
anchor = 0;
|
||||||
|
|
||||||
|
section = getdbl("instructor", ["section"]);
|
||||||
|
|
||||||
|
if(interval == 0)
|
||||||
|
setdbl("instructor", ["interval"], (string)(interval = DEFAULT_INTERVAL));
|
||||||
|
|
||||||
|
if(enabled)
|
||||||
|
set_timer("instruct", interval);
|
||||||
|
|
||||||
|
} else if(n == SIGNAL_TIMER) {
|
||||||
|
if(enabled) {
|
||||||
|
integer line_count = count(js2list(llLinksetDataRead(section)));
|
||||||
|
if(!line_count) {
|
||||||
|
echo("[" + PROGRAM_NAME + "] no usable data in " + section + "; please fix");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(random)
|
||||||
|
offset = (integer)llFrand(0x7fffffff) % line_count;
|
||||||
|
else
|
||||||
|
offset = (offset + 1) % line_count;
|
||||||
|
|
||||||
|
string message = getdbl(section, [offset]);
|
||||||
|
|
||||||
|
if(!anchor) {
|
||||||
|
echo(getdbl(section, [offset]));
|
||||||
|
} else {
|
||||||
|
vector color = getv(getp(2, [PRIM_COLOR, 1]), 0);
|
||||||
|
|
||||||
|
float fade = 0;
|
||||||
|
while(fade < 1.0) {
|
||||||
|
if(fade >= 0.9375)
|
||||||
|
fade = 1.0;
|
||||||
|
setp(anchor, [
|
||||||
|
PRIM_TEXT, message + "\n \n \n ", color, fade
|
||||||
|
]);
|
||||||
|
fade += 0.0625;
|
||||||
|
llSleep(0.022);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade = 1.0;
|
||||||
|
|
||||||
|
llSleep(interval * 0.5 - 2);
|
||||||
|
|
||||||
|
while(fade > 0.0) {
|
||||||
|
if(fade < 0.0625)
|
||||||
|
fade = 0.0;
|
||||||
|
setp(anchor, [
|
||||||
|
PRIM_TEXT, message + "\n \n \n ", color, fade
|
||||||
|
]);
|
||||||
|
fade -= 0.0625;
|
||||||
|
llSleep(0.022);
|
||||||
|
}
|
||||||
|
|
||||||
|
setp(anchor, [
|
||||||
|
PRIM_TEXT, "", ZV, 0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_timer("instruct", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(n == SIGNAL_UNKNOWN_SCRIPT) {
|
||||||
|
echo("[" + PROGRAM_NAME + "] failed to run '" + m + "' (kernel could not find the program specified)");
|
||||||
|
} else {
|
||||||
|
echo("[" + PROGRAM_NAME + "] unimplemented signal " + (string)n + ": " + m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <ARES/program>
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
|
||||||
|
/* =========================================================================
|
||||||
|
*
|
||||||
|
* Nanite Systems Advanced Research Encapsulation System
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025–2026 Nanite Systems Corporation
|
||||||
|
*
|
||||||
|
* =========================================================================
|
||||||
|
*
|
||||||
|
* Salvage Utility
|
||||||
|
*
|
||||||
|
* This program is covered under the terms of the ARES Software Copyright
|
||||||
|
* License, Section 3 (ASCL-iii). It may be redistributed or used as the
|
||||||
|
* basis of commercial, closed-source products so long as steps are taken
|
||||||
|
* to ensure proper attribution as defined in the text of the license.
|
||||||
|
*
|
||||||
|
* To see the full text of the ASCL, type 'help license' on any standard
|
||||||
|
* ARES distribution, or visit http://nanite-systems.com/ASCL for the
|
||||||
|
* current version.
|
||||||
|
*
|
||||||
|
* DISCLAIMER
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS
|
||||||
|
* IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||||
|
* DAMAGES HOWEVER CAUSED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* =========================================================================
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <ARES/a>
|
||||||
|
#define CLIENT_VERSION "1.0"
|
||||||
|
#define CLIENT_VERSION_TAGS "release"
|
||||||
|
|
||||||
|
main(integer src, integer n, string m, key outs, key ins, key user) {
|
||||||
|
if(n == SIGNAL_INVOKE) {
|
||||||
|
list argv = splitnulls(m, " ");
|
||||||
|
integer argc = count(argv);
|
||||||
|
string msg = "";
|
||||||
|
string action = gets(argv, 1);
|
||||||
|
if(argc == 1 || action == "help") {
|
||||||
|
msg = PROGRAM_NAME + " version " + CLIENT_VERSION + " (" + CLIENT_VERSION_TAGS + ")"
|
||||||
|
+ "\nUsage: " + PROGRAM_NAME + " <action> [<arguments>]"
|
||||||
|
+ "\nSupported actions:"
|
||||||
|
+ "\n help: this message"
|
||||||
|
+ "\n dbread <entry>: read from LSD storage"
|
||||||
|
+ "\n dbwrite <entry> <value>: write to LSD storage (self only)"
|
||||||
|
+ "\n dbdelete <entry>: delete from LSD storage (self only)"
|
||||||
|
+ "\n dbdrop <section>: delete a whole section from LSD storage (self only)"
|
||||||
|
+ "\n dblist: list all LSD entries"
|
||||||
|
+ "\n invdrop on|off: enable/disable inventory drop (self only)"
|
||||||
|
;
|
||||||
|
} else if(action == "dbread") {
|
||||||
|
string path = gets(argv, 2);
|
||||||
|
list ks = splitnulls(path, ".");
|
||||||
|
msg = getdbl(gets(ks, 0), delitem(ks, 0));
|
||||||
|
if(msg == "")
|
||||||
|
msg = "(empty)";
|
||||||
|
else if(msg == JSON_INVALID)
|
||||||
|
msg = "(undefined)";
|
||||||
|
|
||||||
|
} else if(action == "dbwrite") {
|
||||||
|
if(user != avatar) {
|
||||||
|
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
|
||||||
|
} else {
|
||||||
|
string path = gets(argv, 2);
|
||||||
|
list ks = splitnulls(path, ".");
|
||||||
|
string h = gets(ks, 0);
|
||||||
|
ks = delitem(ks, 0);
|
||||||
|
|
||||||
|
string old = getdbl(h, ks);
|
||||||
|
string new = concat(delrange(argv, 0, 2), " ");
|
||||||
|
|
||||||
|
string ksname = concat(ks, ".");
|
||||||
|
if(ksname == "")
|
||||||
|
ksname = "<root>";
|
||||||
|
|
||||||
|
tell(user, 0, "Writing database entry at (" + h + ", " + ksname + "):");
|
||||||
|
|
||||||
|
string test = llLinksetDataRead(h);
|
||||||
|
if(test != JSON_INVALID && setjs(test, ks, new) == JSON_INVALID) {
|
||||||
|
tell(user, 0, " !!! Cannot write database entry: result would be invalid JSON. Check for unbalanced {} and [] characters.");
|
||||||
|
} else {
|
||||||
|
setdbl(h, ks, new);
|
||||||
|
|
||||||
|
if(old == "")
|
||||||
|
old = "(empty)";
|
||||||
|
else if(old == JSON_INVALID)
|
||||||
|
old = "(undefined)";
|
||||||
|
|
||||||
|
tell(user, 0, " --- old value: " + old);
|
||||||
|
|
||||||
|
if(new == "")
|
||||||
|
new = "(empty)";
|
||||||
|
else if(new == JSON_INVALID)
|
||||||
|
new = "(undefined)";
|
||||||
|
|
||||||
|
tell(user, 0, " --- new value: " + new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(action == "dbdelete") {
|
||||||
|
if(user != avatar) {
|
||||||
|
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
|
||||||
|
} else {
|
||||||
|
string path = gets(argv, 2);
|
||||||
|
list ks = splitnulls(path, ".");
|
||||||
|
string h = gets(ks, 0);
|
||||||
|
ks = delitem(ks, 0);
|
||||||
|
|
||||||
|
string old = getdbl(h, ks);
|
||||||
|
string ksname = concat(ks, ".");
|
||||||
|
if(ksname == "")
|
||||||
|
ksname = "<root>";
|
||||||
|
|
||||||
|
if(old == JSON_INVALID) {
|
||||||
|
msg = "Cannot delete (" + h + ", " + ksname + "): it does not exist.";
|
||||||
|
} else {
|
||||||
|
tell(user, 0, "Deleting database entry at (" + h + ", " + ksname + "):");
|
||||||
|
|
||||||
|
string test = llLinksetDataRead(h);
|
||||||
|
if(test != JSON_INVALID && setjs(test, ks, JSON_DELETE) == JSON_INVALID) {
|
||||||
|
tell(user, 0, " !!! Cannot write database entry: result would be invalid JSON. Check for unbalanced {} and [] characters.");
|
||||||
|
} else {
|
||||||
|
setdbl(h, ks, JSON_DELETE);
|
||||||
|
|
||||||
|
if(old == "")
|
||||||
|
old = "(empty)";
|
||||||
|
|
||||||
|
tell(user, 0, " --- old value: " + old);
|
||||||
|
tell(user, 0, " --- deleted successfully.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(action == "dbdrop") {
|
||||||
|
if(user != avatar) {
|
||||||
|
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
|
||||||
|
} else {
|
||||||
|
string k = gets(argv, 2);
|
||||||
|
list candidates = llLinksetDataFindKeys(k, 0, 0);
|
||||||
|
if(contains(candidates, k) || gets(argv, 3) == "force") {
|
||||||
|
tell(user, 0, "Deleting key " + k);
|
||||||
|
tell(user, 0, "Contents were: " + llLinksetDataRead(k));
|
||||||
|
llLinksetDataDelete(k);
|
||||||
|
} else {
|
||||||
|
msg = "No key found: " + k + "\nIs it an accidental regex? If so, try: @" + PROGRAM_NAME + " dbdrop " + k + " force";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(action == "dblist") {
|
||||||
|
integer lsmax = llLinksetDataCountKeys();
|
||||||
|
integer li = 0;
|
||||||
|
while(li < lsmax) {
|
||||||
|
string k = gets(llLinksetDataListKeys(li, 1), 0);
|
||||||
|
tell(user, 0, " - " + k + " (" + (string)strlen(llLinksetDataRead(k)) + " bytes)");
|
||||||
|
++li;
|
||||||
|
llSleep(0.044);
|
||||||
|
}
|
||||||
|
tell(user, 0, (string)lsmax + " key(s), " + (string)llLinksetDataAvailable() + " byte(s) free");
|
||||||
|
|
||||||
|
} else if(action == "invdrop") {
|
||||||
|
if(user != avatar) {
|
||||||
|
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
|
||||||
|
} else {
|
||||||
|
integer new = index((["off", "on"]), gets(argv, 2));
|
||||||
|
if(new == 1) {
|
||||||
|
inventory_drop(TRUE);
|
||||||
|
msg = "Inventory drop enabled.";
|
||||||
|
} else if(new == 0) {
|
||||||
|
inventory_drop(FALSE);
|
||||||
|
msg = "Inventory drop disabled.";
|
||||||
|
} else {
|
||||||
|
msg = "Invalid option. Syntax must be: @" + PROGRAM_NAME + " invdrop on|off";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg = "Unknown action: " + action + ". For usage, see: @" + PROGRAM_NAME + " help";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msg != "")
|
||||||
|
tell(user, 0, msg);
|
||||||
|
} else if(n == SIGNAL_INIT) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
echo("[" + PROGRAM_NAME + "] init event");
|
||||||
|
#endif
|
||||||
|
} else if(n == SIGNAL_UNKNOWN_SCRIPT) {
|
||||||
|
echo("[" + PROGRAM_NAME + "] failed to run '" + m + "' (kernel could not find the program specified)");
|
||||||
|
} else {
|
||||||
|
echo("[" + PROGRAM_NAME + "] unimplemented signal " + (string)n + ": " + m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <ARES/program>
|
||||||
Loading…
Reference in New Issue