Difference between revisions of "User:Xaviar Czervik"
(Added code to user page, instead of links.) |
|||
Line 1: | Line 1: | ||
= About Me = | |||
Line 6: | Line 6: | ||
I'll be on the teen grid for another three years and counting... | I'll be on the teen grid for another three years and counting... | ||
= Some Code = | |||
== Object to Data v1.1 == | |||
(http://www.gnu.org/copyleft/fdl.html) in the spirit of which this script is GPL'd. Copyright (C) 2007 [[User:Xaviar Czervik|Xaviar Czervik]] | |||
(This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
I took the list serialize list code from someone, and it was posted on a wiki somewhere... (If this was you, please add your name so I can credit you). | |||
[[ | |||
I'm not one for writing documentation, so I apologize in advance for the confusion of the following. | |||
Here is a map of the objects: | |||
<pre> | |||
Object To Data | |||
| | |||
|---Object_Main (Script) | |||
|---Listen (Object) | |||
|---| | |||
|---|---Listen_Main(Script) | |||
|---HoloBox (Object) | |||
|---| | |||
|---|---Holo_Main (Script) | |||
|---|Data_Default (Note) | |||
</pre> | |||
Now that everything is set up, drag the last script into every PRIM. No objects can be linked. Then, click Save Program. The objects WILL DELETE THEM SELF, so be careful. Copy and paste the text into a note, exactly as it appers in the chat log. No need to remove any dates, or the object name. Simply paste it. | |||
Main_Main (Script) | |||
<pre> | |||
list data; | |||
key gSetupQueryId; | |||
integer gSetupNotecardLine = 0; | |||
string gSetupNotecardName = "Data_Default"; | |||
string lastData; | |||
readSettingsNotecard() { | |||
gSetupNotecardLine = 0; | |||
gSetupQueryId = llGetNotecardLine(gSetupNotecardName,gSetupNotecardLine); | |||
} | |||
default { | |||
state_entry() { | |||
llListen(-5, "", "", ""); | |||
llListen(-10, "", "", ""); | |||
llListen(1, "", "", ""); | |||
llListen(-1, "", llGetOwner(), ""); | |||
llPassTouches(0); | |||
} | |||
touch_start(integer total_number) { | |||
if (llDetectedKey(0) != llGetOwner()) | |||
return; | |||
llDialog(llGetOwner(), "What do you want to do?", ["Save Program", "Run Program"], -1); | |||
} | |||
listen(integer i, string s, key id, string m) { | |||
if (i == -5) | |||
llRezObject("Listen", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, (integer)m); | |||
if (i == -10) { | |||
data += m; | |||
llSetTimerEvent(3); | |||
} | |||
if (i == -1) { | |||
if (m == "Save Program") { | |||
llShout(-15, "Save Program"); | |||
} | |||
if (m == "Run Program") { | |||
readSettingsNotecard(); | |||
} | |||
} | |||
} | |||
timer() { | |||
llOwnerSay("Copy and paste the following into a note and call it 'Data_' and some descriptor."); | |||
llSetTimerEvent(0); | |||
integer i = 0; | |||
while (i < llGetListLength(data)) { | |||
llOwnerSay("\n" + llGetSubString(llList2String(data, i), 0, 250)); | |||
llOwnerSay("\n" + llGetSubString(llList2String(data, i), 251, -1)); | |||
i++; | |||
} | |||
} | |||
dataserver(key queryId, string data) { | |||
if(queryId == gSetupQueryId) { | |||
if(data != EOF) { | |||
gSetupNotecardLine += 1; | |||
gSetupQueryId = llGetNotecardLine(gSetupNotecardName,gSetupNotecardLine); | |||
if (llGetSubString(data, 0, 0) == "[") | |||
return; | |||
if (lastData == "") { | |||
lastData += data; | |||
} else { | |||
lastData += data; | |||
integer f = (integer)llFrand(10000) - 10000; | |||
llRezObject("HoloBox", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, f); | |||
list lis = llParseString2List(lastData, ["-=!!=-"], []); | |||
integer i = 0; | |||
while (i < llGetListLength(lis)) { | |||
llSay(f, llList2String(lis, i)); | |||
i++; | |||
} | |||
lastData = ""; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</pre> | |||
Listen_Main (Script) | |||
<pre> | |||
integer num = 0; | |||
list total = []; | |||
default { | |||
on_rez(integer i) { | |||
llListen(i, "", "", ""); | |||
} | |||
listen(integer i, string n, key id, string m) { | |||
if (llGetOwnerKey(id) == llGetOwner()) { | |||
num++; | |||
total += m; | |||
if (num == 10) { | |||
llShout(-10, llDumpList2String(total, "-=!!=-")); | |||
llDie(); | |||
} | |||
} | |||
} | |||
} | |||
</pre> | |||
Holo_Main (Script) | |||
<pre> | |||
string SERIALIZER_DELIMITER = "$!#"; | |||
integer num = 0; | |||
list unserializeList(string serialized_data) { | |||
// TODO: add some checking in-case we encounter a poorly formed serialization | |||
// consider using the same mem-packing list pushing technique used above | |||
// (want to run performace tests first) | |||
list result = []; | |||
list t; | |||
list l = llParseStringKeepNulls(serialized_data, [SERIALIZER_DELIMITER], []); | |||
string item; | |||
integer i = (l != []);//This is a hack, it gets list lenght. | |||
integer type = 0; | |||
do | |||
{ | |||
if((type = (integer)(item = llList2String(l, (i=~-i))))) | |||
{//Little error checking (also takes care of null strings). | |||
integer p = llSubStringIndex(item, ","); | |||
item = llDeleteSubString(item, 0, p); | |||
// How about those switch statements, Lindens??? | |||
if (TYPE_INTEGER == type) | |||
t = [(integer)item]; | |||
else if (TYPE_FLOAT == type) | |||
t = [(float)item]; | |||
else if (TYPE_STRING == type) | |||
t = [item]; | |||
else if (TYPE_KEY == type) | |||
t = [(key)item]; | |||
else | |||
{ | |||
if (TYPE_ROTATION ^ type)// if (TYPE_VECTOR == type) | |||
t = [(vector)("<" + item + ">")]; | |||
else// if (TYPE_ROTATION == type) | |||
t = [(rotation)("<" + item + ">")]; | |||
} | |||
//when dealing with very long lists it might be advantagous to use the commented out line instead. | |||
//result = [result = t] + result; | |||
result = t + result; | |||
} | |||
}while(i); | |||
return result; | |||
} | |||
default { | |||
on_rez(integer i) { | |||
llListen(i, "", "", ""); | |||
} | |||
listen(integer i, string n, key id, string m) { | |||
if (llGetOwnerKey(id) == llGetOwner()) { | |||
list l = unserializeList(m); | |||
num++; | |||
if (num == 1) { | |||
list l2 = [PRIM_TYPE] + l; | |||
llSetPrimitiveParams(l2); | |||
} | |||
if (num == 2) { | |||
llSetColor((vector)m, ALL_SIDES); | |||
} | |||
if (num == 3) { | |||
llSetRot((rotation)m); | |||
} | |||
if (num == 4) { | |||
llSetScale((vector)m); | |||
} | |||
if (num == 5) { | |||
llSetTexture(m, ALL_SIDES); | |||
} | |||
if (num == 6) { | |||
vector t = (vector)m; | |||
llScaleTexture(t.x, t.y, ALL_SIDES); | |||
} | |||
if (num == 7) { | |||
vector t = (vector)m; | |||
llOffsetTexture(t.x, t.y, ALL_SIDES); | |||
} | |||
if (num == 8) { | |||
llRotateTexture((integer)m, ALL_SIDES); | |||
} | |||
if (num == 9) { | |||
list l2 = [PRIM_BUMP_SHINY, ALL_SIDES] + l; | |||
llSetPrimitiveParams(l2); | |||
} | |||
if (num == 10) { | |||
while (llVecDist(llGetPos(), (vector)m) > .1) llSetPos((vector)m); | |||
llRemoveInventory(llGetScriptName()); | |||
} | |||
} | |||
} | |||
} | |||
</pre> | |||
Save Program (Script) | |||
<pre> | |||
string SERIALIZER_DELIMITER = "$!#"; | |||
string hexc="0123456789ABCDEF";//faster | |||
string Float2Hex(float input) | |||
{// Copyright Strife Onizuka, 2006-2007, LGPL, http://www.gnu.org/copyleft/lesser.html | |||
if((integer)input != input)//LL screwed up hex integers support in rotation & vector string typecasting | |||
{//this also keeps zero from hanging the zero stripper. | |||
float unsigned = llFabs(input);//logs don't work on negatives. | |||
integer exponent = llFloor(llLog(unsigned) / 0.69314718055994530941723212145818);//floor(log2(b)) + rounding error | |||
integer mantissa = (integer)((unsigned / (float)("0x1p"+(string)(exponent -= (exponent == 128)))) * 0x1000000);//shift up into integer range | |||
integer index = (integer)(llLog(mantissa & -mantissa) / 0.69314718055994530941723212145818);//index of first 'on' bit | |||
string str = "p" + (string)((exponent += index) - 24); | |||
mantissa = mantissa >> index; | |||
do | |||
str = llGetSubString(hexc,15&mantissa,15&mantissa) + str; | |||
while(mantissa = mantissa >> 4); | |||
if(input < 0) | |||
return "-0x" + str; | |||
return "0x" + str; | |||
}//integers pack well so anything that qualifies as an integer we dump as such, supports netative zero | |||
return llDeleteSubString((string)input,-7,-1);//trim off the float portion, return an integer | |||
} | |||
string serializeList(list l) { | |||
integer i = (l != []);//This is a hack, it gets list lenght. | |||
if(i) | |||
{ | |||
string serialized_data = ""; | |||
integer type = 0; | |||
string result; | |||
{@loop; | |||
// this custom loop is about as fast as a while loop. | |||
// we build the string backwords for memory reasons. | |||
// My kingdom for select statements.... | |||
if (TYPE_FLOAT == (type = llGetListEntryType(l, (i=~-i)))) | |||
// floats get extra love | |||
result = Float2Hex(llList2Float(l, i)); | |||
else if (TYPE_VECTOR == type) { | |||
vector v = llList2Vector(l, i); | |||
result = Float2Hex(v.x) + "," + Float2Hex(v.y) + "," + Float2Hex(v.z); | |||
} else if (TYPE_ROTATION == type) { | |||
rotation r = llList2Rot(l, i); | |||
result = Float2Hex(r.x) + "," + Float2Hex(r.y) + "," + Float2Hex(r.z) + "," + Float2Hex(r.s); | |||
} else //if ((TYPE_INTEGER == type) || (TYPE_STRING == type) || (TYPE_KEY == type)) | |||
result = llList2String(l, i);// integers, strings and keys required no voodoo | |||
if(i) | |||
{ | |||
//This came to me after reverse engeneering LSL bytecode, the realization that LSL memory management sucks. | |||
serialized_data = SERIALIZER_DELIMITER + (string)type + (serialized_data = result = ",") + result + serialized_data; | |||
jump loop; | |||
} | |||
} | |||
return (string)type + (serialized_data = result = ",") + result + serialized_data; | |||
} | |||
return ""; | |||
} | |||
Say(integer i, string m) { | |||
llSleep(.15); | |||
llShout(i, m); | |||
} | |||
default { | |||
state_entry() { | |||
llListen(-15, "", "", "Save Program"); | |||
} | |||
listen(integer i, string s, key id, string m) { | |||
integer f = (integer)llFrand(10000) + 1691507124; | |||
llShout(-5, (string)f); | |||
llSleep(1); | |||
list total; | |||
string tot; | |||
total = llGetPrimitiveParams([PRIM_TYPE]); | |||
tot = serializeList(total); | |||
Say(f, tot); | |||
Say(f, (string)llGetColor(ALL_SIDES)); | |||
Say(f, (string)llGetRot()); | |||
Say(f, (string)llGetScale()); | |||
Say(f, (string)llGetTexture(ALL_SIDES)); | |||
Say(f, (string)llGetTextureScale(ALL_SIDES)); | |||
Say(f, (string)llGetTextureOffset(ALL_SIDES)); | |||
Say(f, (string)llGetTextureRot(ALL_SIDES)); | |||
total = llGetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES]); | |||
total = [llList2Integer(total, 0), llList2Integer(total, 1)]; | |||
tot = serializeList(total); | |||
Say(f, tot); | |||
Say(f, (string)(llGetPos())); | |||
llSleep(1); | |||
llDie(); | |||
} | |||
} | |||
</pre> | |||
== Prefix Calculator == | |||
Created by [[User:Xaviar Czervik|Xaviar Czervik]]. Do whatever you wish with this function: Sell it (good luck), use it, or modify it. | |||
Evaluates an expression in prefix notation. I will give a few examples, and let you figure it out yourself. You have a brain: use it. | |||
+ 1 2 = 3 | |||
+ - 1 2 3 = 2 | |||
/ + 3 2 - +1 2 3 = 1.25 | |||
For more information visit http://en.wikipedia.org/wiki/Prefix_notation. | |||
Another prefix calculator script is the [[Chatbot]] sample. That script is much less simple, because it handles many more varieties of input, but that script exhibits essentially this same control flow. | |||
<pre> | |||
list stack; | |||
push(float i) { // Float To Integer - Not good to use for large values, but it works. Sue me... | |||
stack += (integer)(i*10000000); } | |||
float pop() { | |||
float i = peek(); | |||
stack = llList2List(stack, 0, -2); | |||
return i; | |||
} | |||
float peek() { // Float To Integer - Not good to use for large values, but it works. Sue me... | |||
return ((float)llList2Integer(stack, -1))/10000000;} | |||
default { | |||
state_entry() { | |||
llListen(0, "", llGetOwner(), ""); | |||
} | |||
listen(integer i, string n, key id, string m) { | |||
string data = m; | |||
list parsed = llParseString2List(data, [" "], []); | |||
integer i = llGetListLength(parsed); | |||
while (i--) { | |||
string data = llList2String(parsed, i); | |||
string check = (string)((float)data); | |||
while (llGetSubString(check, -1, -1) == "0") { | |||
check = llGetSubString(check, 0, -2); | |||
} | |||
if (llGetSubString(check, -1, -1) == ".") | |||
check = llGetSubString(check, 0, -2); | |||
if (check == data) { // Is it a number? | |||
push((float)data); | |||
} else { | |||
if (llStringLength(data) == 1) { | |||
float first = pop(); | |||
float second = pop(); | |||
if (data == "+") { | |||
push(first + second); | |||
} | |||
if (data == "-") { | |||
push(first - second); | |||
} | |||
if (data == "*") { | |||
push(first * second); | |||
} | |||
if (data == "/") { | |||
push((float)first / (float)second); | |||
} | |||
} else { | |||
float first = pop(); | |||
if (data == "sin") { | |||
push(llSin(first)); | |||
} | |||
if (data == "cos") { | |||
push(llCos(first)); | |||
} | |||
if (data == "tan") { | |||
push(llTan(first)); | |||
} | |||
if (data == "sqrt") { | |||
push(llSqrt(first)); | |||
} | |||
} | |||
} | |||
} | |||
llOwnerSay((string)pop()); | |||
} | |||
} | |||
</pre> | |||
== Efficiency Tester == | |||
Written by [[User:Xaviar Czervik|Xaviar Czervik]], Modified by [[User:Strife Onizuka|Strife Onizuka]]. | |||
This code will test the efficiency of what ever is in the while loop. | |||
I've used i += 1 because I found it to be faster on the [[LSL Script Efficiency]] page. | |||
Lots of people disagree with me that a += 1 is faster than ++a... If you don't like it, change it and then sue me :P. | |||
<pre> | |||
//IMPORTANT: Only perform tests in an empty region to reduce contamination and be sure to wearing no attachments. | |||
integer time() { | |||
string stamp = llGetTimestamp(); | |||
return (integer) llGetSubString(stamp, 11, 12) * 3600000 + | |||
(integer) llGetSubString(stamp, 14, 15) * 60000 + | |||
llRound((float)llGetSubString(stamp, 17, -2) * 1000000.0)/1000; | |||
//llInsertString(llDeleteSubString(stamp, 19, 19) + "000000", 23, ".") | |||
} | |||
default { | |||
state_entry() { | |||
//test variables | |||
float counter; | |||
//framework variables | |||
float i = 0; | |||
float j = 0; | |||
float max = 10000; | |||
float start = time(); | |||
do { | |||
//test | |||
counter += 1; | |||
}while (++i < max); | |||
float delta = time(); | |||
do ; while (++j < max); | |||
float end = time();//remove the time required by the framework | |||
float t = ((delta - start) - (end - delta))/max; | |||
llOwnerSay("The function in the loop took a total of " + (string)t + " milliseconds."); | |||
} | |||
} | |||
</pre> | |||
== Merge Sort == | |||
Created by [[User:Xaviar Czervik|Xaviar Czervik]]. Do whatever you wish with this function: Sell it (good luck), use it, or modify it. | |||
This code sorts a list through use of a Merge Sort. I have no idea why you would want to use it as it is more than 150 times slower than llListSort(), but it is a good demonstration of how a Merge Sort works. | |||
I realize I shouldn't be using iteration in a recursive method... Sue me. | |||
<pre> | |||
list sort(list l) { | |||
if (llGetListLength(l) > 1) { | |||
integer mid = llGetListLength(l)/2; | |||
list l2 = sort(llList2List(l, 0, mid-1)); | |||
list l3 = sort(llList2List(l, mid, -1)); | |||
return merge(l2, l3); | |||
} | |||
return l; | |||
} | |||
list merge(list l, list r) { | |||
integer lm = llGetListLength(l); | |||
integer rm = llGetListLength(r); | |||
integer lc; | |||
integer rc; | |||
list ret; | |||
while (lc < lm || rc < rm) { | |||
if (lc >= lm) { | |||
ret += llList2Integer(r, rc); | |||
rc++; | |||
} else if (rc >= rm) { | |||
ret += llList2Integer(l, lc); | |||
lc++; | |||
} else { | |||
if (llList2Integer(l, lc) <= llList2Integer(r, rc)) { | |||
ret += llList2Integer(l, lc); | |||
if (lc < lm) | |||
lc++; | |||
} else { | |||
ret += llList2Integer(r, rc); | |||
if (rc < rm) | |||
rc++; | |||
} | |||
} | |||
} | |||
return ret; | |||
} | |||
</pre> | |||
== String Compare == | |||
Created by [[User:Xaviar Czervik|Xaviar Czervik]]. Do whatever you wish with this function: Sell it (good luck), use it, or modify it. | |||
The following code returns 1, -1 or 0. The 1 and -1 are essentially random, however it will return the same value every time the script is executed. 0 Is returned when, and only when, the strings are exactly equal. Completely re-designed to use a few tricks I learned in the past months. Also much easier to read now. | |||
I have used this script for comparing the [[Key|Keys]] of two objects in a dynamic set of sensors, to decide which one should be the "Master" in the region to tell me information. I'm sure there can be more uses to this... | |||
<pre> | |||
integer compare(string s1, string s2) { | |||
if (s1 == s2) { | |||
return 0; | |||
} else if (llStringLength(s1) < llStringLength(s2)) { | |||
return 1; | |||
} else if (llStringLength(s1) > llStringLength(s2)) { | |||
return -1; | |||
} else { | |||
list l = [s1, s2]; | |||
l = llListSort(l, 0, 1); | |||
if (s1 == llList2String(l, 0)) | |||
return 1; | |||
return -1; | |||
} | |||
} | |||
</pre> | |||
== Pseudo-random Number Generator == | |||
Heres a Pseudo-random Number Generator - I just made it up off the top of my head - so it has no mathematical research behind it to prove it's random... I've tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me. | |||
I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done. | |||
I recently compared this with llFrand() and it is on average 5% faster. | |||
<pre> | |||
// IMPORTANT: Change the following number before using! | |||
integer seed = 0x61FA687C; | |||
integer rand() { | |||
seed = (integer)(seed * 0x71B5F252 + 0xD); | |||
return seed ^ 0x7FFFFFFF; | |||
} | |||
</pre> | |||
Example code to test the randomness (Is that a word?) of the generator. | |||
<pre> | |||
default { | |||
state_entry() { | |||
integer i = 0; | |||
integer min = 0x7FFFFFFF; | |||
integer max = -0x7FFFFFFF; | |||
integer total = 0; | |||
while (i < 100000000) { | |||
integer r = rand(); | |||
if (r < min) { | |||
min = r; | |||
} | |||
if (r > max) { | |||
max = r; | |||
} | |||
total += r; | |||
i++; | |||
} | |||
llOwnerSay("Min: " + (string)min); | |||
llOwnerSay("Max: " + (string)max); | |||
llOwnerSay("Average: " + (string)(total/100000000)); | |||
} | |||
} |
Revision as of 19:03, 24 September 2007
About Me
I don't like writing, as it wastes time, so the only thing you'll see from me is code. (Except when I need to explain, and then I will only explain half of it).
I'll be on the teen grid for another three years and counting...
Some Code
Object to Data v1.1
(http://www.gnu.org/copyleft/fdl.html) in the spirit of which this script is GPL'd. Copyright (C) 2007 Xaviar Czervik
(This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
I took the list serialize list code from someone, and it was posted on a wiki somewhere... (If this was you, please add your name so I can credit you).
I'm not one for writing documentation, so I apologize in advance for the confusion of the following.
Here is a map of the objects:
Object To Data | |---Object_Main (Script) |---Listen (Object) |---| |---|---Listen_Main(Script) |---HoloBox (Object) |---| |---|---Holo_Main (Script) |---|Data_Default (Note)
Now that everything is set up, drag the last script into every PRIM. No objects can be linked. Then, click Save Program. The objects WILL DELETE THEM SELF, so be careful. Copy and paste the text into a note, exactly as it appers in the chat log. No need to remove any dates, or the object name. Simply paste it.
Main_Main (Script)
list data; key gSetupQueryId; integer gSetupNotecardLine = 0; string gSetupNotecardName = "Data_Default"; string lastData; readSettingsNotecard() { gSetupNotecardLine = 0; gSetupQueryId = llGetNotecardLine(gSetupNotecardName,gSetupNotecardLine); } default { state_entry() { llListen(-5, "", "", ""); llListen(-10, "", "", ""); llListen(1, "", "", ""); llListen(-1, "", llGetOwner(), ""); llPassTouches(0); } touch_start(integer total_number) { if (llDetectedKey(0) != llGetOwner()) return; llDialog(llGetOwner(), "What do you want to do?", ["Save Program", "Run Program"], -1); } listen(integer i, string s, key id, string m) { if (i == -5) llRezObject("Listen", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, (integer)m); if (i == -10) { data += m; llSetTimerEvent(3); } if (i == -1) { if (m == "Save Program") { llShout(-15, "Save Program"); } if (m == "Run Program") { readSettingsNotecard(); } } } timer() { llOwnerSay("Copy and paste the following into a note and call it 'Data_' and some descriptor."); llSetTimerEvent(0); integer i = 0; while (i < llGetListLength(data)) { llOwnerSay("\n" + llGetSubString(llList2String(data, i), 0, 250)); llOwnerSay("\n" + llGetSubString(llList2String(data, i), 251, -1)); i++; } } dataserver(key queryId, string data) { if(queryId == gSetupQueryId) { if(data != EOF) { gSetupNotecardLine += 1; gSetupQueryId = llGetNotecardLine(gSetupNotecardName,gSetupNotecardLine); if (llGetSubString(data, 0, 0) == "[") return; if (lastData == "") { lastData += data; } else { lastData += data; integer f = (integer)llFrand(10000) - 10000; llRezObject("HoloBox", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, f); list lis = llParseString2List(lastData, ["-=!!=-"], []); integer i = 0; while (i < llGetListLength(lis)) { llSay(f, llList2String(lis, i)); i++; } lastData = ""; } } } } }
Listen_Main (Script)
integer num = 0; list total = []; default { on_rez(integer i) { llListen(i, "", "", ""); } listen(integer i, string n, key id, string m) { if (llGetOwnerKey(id) == llGetOwner()) { num++; total += m; if (num == 10) { llShout(-10, llDumpList2String(total, "-=!!=-")); llDie(); } } } }
Holo_Main (Script)
string SERIALIZER_DELIMITER = "$!#"; integer num = 0; list unserializeList(string serialized_data) { // TODO: add some checking in-case we encounter a poorly formed serialization // consider using the same mem-packing list pushing technique used above // (want to run performace tests first) list result = []; list t; list l = llParseStringKeepNulls(serialized_data, [SERIALIZER_DELIMITER], []); string item; integer i = (l != []);//This is a hack, it gets list lenght. integer type = 0; do { if((type = (integer)(item = llList2String(l, (i=~-i))))) {//Little error checking (also takes care of null strings). integer p = llSubStringIndex(item, ","); item = llDeleteSubString(item, 0, p); // How about those switch statements, Lindens??? if (TYPE_INTEGER == type) t = [(integer)item]; else if (TYPE_FLOAT == type) t = [(float)item]; else if (TYPE_STRING == type) t = [item]; else if (TYPE_KEY == type) t = [(key)item]; else { if (TYPE_ROTATION ^ type)// if (TYPE_VECTOR == type) t = [(vector)("<" + item + ">")]; else// if (TYPE_ROTATION == type) t = [(rotation)("<" + item + ">")]; } //when dealing with very long lists it might be advantagous to use the commented out line instead. //result = [result = t] + result; result = t + result; } }while(i); return result; } default { on_rez(integer i) { llListen(i, "", "", ""); } listen(integer i, string n, key id, string m) { if (llGetOwnerKey(id) == llGetOwner()) { list l = unserializeList(m); num++; if (num == 1) { list l2 = [PRIM_TYPE] + l; llSetPrimitiveParams(l2); } if (num == 2) { llSetColor((vector)m, ALL_SIDES); } if (num == 3) { llSetRot((rotation)m); } if (num == 4) { llSetScale((vector)m); } if (num == 5) { llSetTexture(m, ALL_SIDES); } if (num == 6) { vector t = (vector)m; llScaleTexture(t.x, t.y, ALL_SIDES); } if (num == 7) { vector t = (vector)m; llOffsetTexture(t.x, t.y, ALL_SIDES); } if (num == 8) { llRotateTexture((integer)m, ALL_SIDES); } if (num == 9) { list l2 = [PRIM_BUMP_SHINY, ALL_SIDES] + l; llSetPrimitiveParams(l2); } if (num == 10) { while (llVecDist(llGetPos(), (vector)m) > .1) llSetPos((vector)m); llRemoveInventory(llGetScriptName()); } } } }
Save Program (Script)
string SERIALIZER_DELIMITER = "$!#"; string hexc="0123456789ABCDEF";//faster string Float2Hex(float input) {// Copyright Strife Onizuka, 2006-2007, LGPL, http://www.gnu.org/copyleft/lesser.html if((integer)input != input)//LL screwed up hex integers support in rotation & vector string typecasting {//this also keeps zero from hanging the zero stripper. float unsigned = llFabs(input);//logs don't work on negatives. integer exponent = llFloor(llLog(unsigned) / 0.69314718055994530941723212145818);//floor(log2(b)) + rounding error integer mantissa = (integer)((unsigned / (float)("0x1p"+(string)(exponent -= (exponent == 128)))) * 0x1000000);//shift up into integer range integer index = (integer)(llLog(mantissa & -mantissa) / 0.69314718055994530941723212145818);//index of first 'on' bit string str = "p" + (string)((exponent += index) - 24); mantissa = mantissa >> index; do str = llGetSubString(hexc,15&mantissa,15&mantissa) + str; while(mantissa = mantissa >> 4); if(input < 0) return "-0x" + str; return "0x" + str; }//integers pack well so anything that qualifies as an integer we dump as such, supports netative zero return llDeleteSubString((string)input,-7,-1);//trim off the float portion, return an integer } string serializeList(list l) { integer i = (l != []);//This is a hack, it gets list lenght. if(i) { string serialized_data = ""; integer type = 0; string result; {@loop; // this custom loop is about as fast as a while loop. // we build the string backwords for memory reasons. // My kingdom for select statements.... if (TYPE_FLOAT == (type = llGetListEntryType(l, (i=~-i)))) // floats get extra love result = Float2Hex(llList2Float(l, i)); else if (TYPE_VECTOR == type) { vector v = llList2Vector(l, i); result = Float2Hex(v.x) + "," + Float2Hex(v.y) + "," + Float2Hex(v.z); } else if (TYPE_ROTATION == type) { rotation r = llList2Rot(l, i); result = Float2Hex(r.x) + "," + Float2Hex(r.y) + "," + Float2Hex(r.z) + "," + Float2Hex(r.s); } else //if ((TYPE_INTEGER == type) || (TYPE_STRING == type) || (TYPE_KEY == type)) result = llList2String(l, i);// integers, strings and keys required no voodoo if(i) { //This came to me after reverse engeneering LSL bytecode, the realization that LSL memory management sucks. serialized_data = SERIALIZER_DELIMITER + (string)type + (serialized_data = result = ",") + result + serialized_data; jump loop; } } return (string)type + (serialized_data = result = ",") + result + serialized_data; } return ""; } Say(integer i, string m) { llSleep(.15); llShout(i, m); } default { state_entry() { llListen(-15, "", "", "Save Program"); } listen(integer i, string s, key id, string m) { integer f = (integer)llFrand(10000) + 1691507124; llShout(-5, (string)f); llSleep(1); list total; string tot; total = llGetPrimitiveParams([PRIM_TYPE]); tot = serializeList(total); Say(f, tot); Say(f, (string)llGetColor(ALL_SIDES)); Say(f, (string)llGetRot()); Say(f, (string)llGetScale()); Say(f, (string)llGetTexture(ALL_SIDES)); Say(f, (string)llGetTextureScale(ALL_SIDES)); Say(f, (string)llGetTextureOffset(ALL_SIDES)); Say(f, (string)llGetTextureRot(ALL_SIDES)); total = llGetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES]); total = [llList2Integer(total, 0), llList2Integer(total, 1)]; tot = serializeList(total); Say(f, tot); Say(f, (string)(llGetPos())); llSleep(1); llDie(); } }
Prefix Calculator
Created by Xaviar Czervik. Do whatever you wish with this function: Sell it (good luck), use it, or modify it.
Evaluates an expression in prefix notation. I will give a few examples, and let you figure it out yourself. You have a brain: use it.
+ 1 2 = 3
+ - 1 2 3 = 2
/ + 3 2 - +1 2 3 = 1.25
For more information visit http://en.wikipedia.org/wiki/Prefix_notation.
Another prefix calculator script is the Chatbot sample. That script is much less simple, because it handles many more varieties of input, but that script exhibits essentially this same control flow.
list stack; push(float i) { // Float To Integer - Not good to use for large values, but it works. Sue me... stack += (integer)(i*10000000); } float pop() { float i = peek(); stack = llList2List(stack, 0, -2); return i; } float peek() { // Float To Integer - Not good to use for large values, but it works. Sue me... return ((float)llList2Integer(stack, -1))/10000000;} default { state_entry() { llListen(0, "", llGetOwner(), ""); } listen(integer i, string n, key id, string m) { string data = m; list parsed = llParseString2List(data, [" "], []); integer i = llGetListLength(parsed); while (i--) { string data = llList2String(parsed, i); string check = (string)((float)data); while (llGetSubString(check, -1, -1) == "0") { check = llGetSubString(check, 0, -2); } if (llGetSubString(check, -1, -1) == ".") check = llGetSubString(check, 0, -2); if (check == data) { // Is it a number? push((float)data); } else { if (llStringLength(data) == 1) { float first = pop(); float second = pop(); if (data == "+") { push(first + second); } if (data == "-") { push(first - second); } if (data == "*") { push(first * second); } if (data == "/") { push((float)first / (float)second); } } else { float first = pop(); if (data == "sin") { push(llSin(first)); } if (data == "cos") { push(llCos(first)); } if (data == "tan") { push(llTan(first)); } if (data == "sqrt") { push(llSqrt(first)); } } } } llOwnerSay((string)pop()); } }
Efficiency Tester
Written by Xaviar Czervik, Modified by Strife Onizuka.
This code will test the efficiency of what ever is in the while loop.
I've used i += 1 because I found it to be faster on the LSL Script Efficiency page.
Lots of people disagree with me that a += 1 is faster than ++a... If you don't like it, change it and then sue me :P.
//IMPORTANT: Only perform tests in an empty region to reduce contamination and be sure to wearing no attachments. integer time() { string stamp = llGetTimestamp(); return (integer) llGetSubString(stamp, 11, 12) * 3600000 + (integer) llGetSubString(stamp, 14, 15) * 60000 + llRound((float)llGetSubString(stamp, 17, -2) * 1000000.0)/1000; //llInsertString(llDeleteSubString(stamp, 19, 19) + "000000", 23, ".") } default { state_entry() { //test variables float counter; //framework variables float i = 0; float j = 0; float max = 10000; float start = time(); do { //test counter += 1; }while (++i < max); float delta = time(); do ; while (++j < max); float end = time();//remove the time required by the framework float t = ((delta - start) - (end - delta))/max; llOwnerSay("The function in the loop took a total of " + (string)t + " milliseconds."); } }
Merge Sort
Created by Xaviar Czervik. Do whatever you wish with this function: Sell it (good luck), use it, or modify it.
This code sorts a list through use of a Merge Sort. I have no idea why you would want to use it as it is more than 150 times slower than llListSort(), but it is a good demonstration of how a Merge Sort works.
I realize I shouldn't be using iteration in a recursive method... Sue me.
list sort(list l) { if (llGetListLength(l) > 1) { integer mid = llGetListLength(l)/2; list l2 = sort(llList2List(l, 0, mid-1)); list l3 = sort(llList2List(l, mid, -1)); return merge(l2, l3); } return l; } list merge(list l, list r) { integer lm = llGetListLength(l); integer rm = llGetListLength(r); integer lc; integer rc; list ret; while (lc < lm || rc < rm) { if (lc >= lm) { ret += llList2Integer(r, rc); rc++; } else if (rc >= rm) { ret += llList2Integer(l, lc); lc++; } else { if (llList2Integer(l, lc) <= llList2Integer(r, rc)) { ret += llList2Integer(l, lc); if (lc < lm) lc++; } else { ret += llList2Integer(r, rc); if (rc < rm) rc++; } } } return ret; }
String Compare
Created by Xaviar Czervik. Do whatever you wish with this function: Sell it (good luck), use it, or modify it.
The following code returns 1, -1 or 0. The 1 and -1 are essentially random, however it will return the same value every time the script is executed. 0 Is returned when, and only when, the strings are exactly equal. Completely re-designed to use a few tricks I learned in the past months. Also much easier to read now.
I have used this script for comparing the Keys of two objects in a dynamic set of sensors, to decide which one should be the "Master" in the region to tell me information. I'm sure there can be more uses to this...
integer compare(string s1, string s2) { if (s1 == s2) { return 0; } else if (llStringLength(s1) < llStringLength(s2)) { return 1; } else if (llStringLength(s1) > llStringLength(s2)) { return -1; } else { list l = [s1, s2]; l = llListSort(l, 0, 1); if (s1 == llList2String(l, 0)) return 1; return -1; } }
Pseudo-random Number Generator
Heres a Pseudo-random Number Generator - I just made it up off the top of my head - so it has no mathematical research behind it to prove it's random... I've tested it for a while and it looks random to me, about the same as llFrand(). But what ever. Sue me.
I use this for determining a random channel for two (or more) objects to talk on. This allows the scripts to talk without users being able to intercept the messages - and even if they do - then the channel will change in a minute or two - so no harm done.
I recently compared this with llFrand() and it is on average 5% faster.
// IMPORTANT: Change the following number before using! integer seed = 0x61FA687C; integer rand() { seed = (integer)(seed * 0x71B5F252 + 0xD); return seed ^ 0x7FFFFFFF; }
Example code to test the randomness (Is that a word?) of the generator.
default { state_entry() { integer i = 0; integer min = 0x7FFFFFFF; integer max = -0x7FFFFFFF; integer total = 0; while (i < 100000000) { integer r = rand(); if (r < min) { min = r; } if (r > max) { max = r; } total += r; i++; } llOwnerSay("Min: " + (string)min); llOwnerSay("Max: " + (string)max); llOwnerSay("Average: " + (string)(total/100000000)); } }