User:Tano Toll/LSL Tips and tricks

From Second Life Wiki
Jump to navigation Jump to search

Some common, or less common, LSL tips, tricks and `hacks` i'd like to share.


Hack 1 : Use lists for typecasting to save bytes

Problem example:

string s = "Amount: "+(string)amount+"L$ by avatar "+name+" with key "+(string)id;

Hacked solution:

string s = (string)["Amount: ", amount, "L$ by avatar ",name," with key ", id];

Explanation: Typecasting a list to string will auto-typecast all elements in the list (without spacers). If you need spacers, you could use llDumpList2String(list, seperator)

Example usage:

llOwnerSay ((string)["Free memory: ",llGetFreeMemory()]);

Justification: Only 1 typecast and a list declaration is needed, which saves bytes when you'd have to do many typecasts. Also, it makes your code more readable.


Hack 2: Abuse sensor event to emulate a 2nd timer.

In need of a second and independant timer? Of course you can just multiplex your timer. But, if your script not uses llSensor() or llSensorRepeat() for anything else, you can abuse this as a second timer. Preferably do not use this for timers with a low interval as there is some overhead.

How: 1. Set up an llSensorEvent() with an impossible combination

    llSensorRepeat ("noname", "invalidkey", AGENT|ACTIVE, 0.0, 0.0, 30.0);

2. Use the no_sensor() event as alternate timer

    no_sensor() {
        llOwnerSay ("Timer 2");
    }

Hack 3: Create a better PRNG

The pseudo random number generator available to LSL scripts is far from perfect. A better -albeit slower- way of generating pseudo random numbers is to use llMD5String().

string seed="initvalue";
integer rnd() {    
    seed = llMD5String ("Some constant" + seed, 0); //feed seed to itself. You can add more entropy if you like
    return (integer)("0x"+llGetSubString(seed, 0, 6); //will return a positive integer 28-bits wide
    //or:
    //return (integer)("0x"+llGetSubString(seed, 0, 7); //will return a signed integer 32-bits wide
}

imperfect usage example:

seed="example";
integer A = rnd() % 100; //A = 0..99

Hack 4: Use notecards without notecards

Not as much a hack, yet an unknown feature by many. You want to use a configuration or data notecard, but not include a notecard in your product? Totally possible:

 1. Create a notecard in your inventory and fill in the data
 2. Copy the UUID key of this notecard and paste it in your script as notecard name
 3. Your script can read the notecard as normal (as if it was a notecard in the object).

Catch: If you change the contents of the notecard, the key will change!


Hack 5: Variable parameters

Yet again, just an overlooked feature. Suppose you have a function, and you want it to accept various types as parameter. Much like 'overloaded' functions in typed languages, or typeless functions.

Answer: just use a list! Example

print (list data) {
    llSay (0, llList2String(data,0));
}
print ([0]); //prints '0'
print ([1.0]); //prints '1.00000000'
print (["I have a cow"]); //prints 'I have a cow'

Of course your function has to be type aware (or type-ignorant).


Hack 6: Formatting floats

a short way to imperfectly print floats. May be adequate for many cases.


//format float to string
//by Tano Toll 2015 - public domain

//note that this will work for most but not any values. still it serves my needs.
//fails very large numbers (> +- maxint) and for very small negative values of zero.
//so -0.9 will be mistranslated. so will 1e20


//fixed precision (1 decimal after seperator):
string formatFloat (float value) {
    return llGetSubString((string) value, 0, llStringLength((string) ((integer) value))+1); //1 bit precision
}

//arbitrary precision (N decimals after decimal seperator)
string formatFloat2 (float value, integer precision) {    
    return llGetSubString((string) value, 0, llStringLength((string) ((integer) value))+precision); //1 bit precision
}


//example:
default
{
    state_entry()
    {
        llSay(0, (string) [formatFloat(PI)," ", formatFloat(-PI), " ", formatFloat2(-PI, 6), " ", formatFloat (-0.01), " ", 
            formatFloat (-0.999999999999), " ", formatFloat (1e8), " ",formatFloat (1e9), " ",formatFloat (1e10), " ", 
            formatFloat (-2e8), " ", formatFloat (-2e9), " ", formatFloat (-2e10), " ", formatFloat (-2e30), " ", formatFloat (1e-30)] );
    }

}

--Tano Toll (talk) 04:47, 5 February 2016 (PST)