User:Becky Pippen/New LSL Functions

From Second Life Wiki
Jump to: navigation, search

New LSL Functions

These memory-saving LSL functions are now available in server version 1.38::

<lsl> list llGetLinkPrimitiveParams(integer linknumber, list params)

     llSetLinkPrimitiveParamsFast(integer link, list params)

     llLinkParticleSystem(integer link, list rules)

     llSetLinkTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate)

</lsl>

We will also get PRIM_TEXT for getting and setting hover text with llSetLinkPrimitiveParams(). The parameter list will be:

<lsl> PRIM_TEXT, string msg, vector color, float alpha </lsl>

The deal with resizer scripts

Some content creators prefer to distribute their objects no-mod, yet still allow customers to resize or retexture the linkset. Scripts can do that in a no-mod linkset, but the obvious solution using llSetLinkPrimitiveParams() doesn't work well because of the 0.2-second delay built into the function. To work around the delay, we have had to put a script in every child prim that can respond immediately to a message from the root prim. When these functions become available, we will be able to do this kind of thing with a single script.

Fixing existing scripts

To fix such a script, locate the call to llMessageLinked() in the master script where it sends the link message to the individual prims. It might look something vaguely like this:

<lsl>llMessageLinked(LINK_whatever, command_resize, (string)newSize, NULL_KEY);</lsl>

Replace that with a loop that applies whatever changes you need to each prim using llSetLinkPrimitiveParamsFast(). The prims have link numbers from 1 through llGetNumberOfPrims(), so you can make an efficient loop as shown here; just add any additional processing you need for each prim inside the loop:

<lsl> applyChildParams(list ruleSet)

{
    integer linkNum;
    for (linkNum = llGetNumberOfPrims(); linkNum >= 1; --linkNum) {
        llSetLinkPrimitiveParamsFast(linkNum, ruleSet);
    }
} </lsl>

For example, to use this function to set the color and alpha of all the prims, build the parameter list and pass it to applyChildParams() like this:

<lsl>applyChildParams([PRIM_COLOR, ALL_SIDES, <0.9, 0.8, 0.2>, 1.0]);</lsl>

However, when you only need to apply a constant rule set like this to every prim in the linkset, then the loop above can be simplified to a single statement;

<lsl>llSetLinkPrimitiveParamsFast(LINK_SET, ruleSet);</lsl>

Or use LINK_ALL_OTHERS or LINK_ALL_CHILDREN instead of LINK_SET as appropriate.

For another example, you can make a resizer script apply relative instead of absolute size changes by using the new function llGetLinkPrimitiveParams(). The script can read each child's current size, then apply a resize factor and use llSetLinkPrimitiveParamsFast() to set a new size. This can help make it easy for the script to do the right thing even if reset and all its variables get reinitialized. The following function will resize all the prims (including the root itself) by a factor:

<lsl> rescaleLinksetByFactor(float factor)

{
    integer linkNum;
    for (linkNum = llGetNumberOfPrims(); linkNum >= 1; --linkNum) {
        list params = llGetLinkPrimitiveParams(linkNum, [PRIM_SIZE]);
        llSetLinkPrimitiveParamsFast(linkNum,
            [PRIM_SIZE, factor * llList2Vector(params, 0)]);
    }
} </lsl>

But what if the function above encounters a prim that, after resized, would have a dimension outside the legal range of 0.01m to 10.0m? That could have unfortunate consequences, so here is a function that resizes all the prims by a specified factor but only if all the resulting dimensions in all the prims will all be in the legal range of 0.01m to 10.0m. If any dimension in any prim would go out of those bounds, the function will return FALSE without resizing anything. This example also includes repositioning the child prims within the linkset. Change or add whatever additional parameters are needed for your particular application.

<lsl> // This is not a complete resizer solution; it's just a demo of

// how to call the new LSL functions.

// Set the minimum and maximum size allowed for any prim in the linkset:
//
float minPrimSize = 0.01;
float maxPrimSize = 10.0;

// Resize all the prims in the linkset. For example, to resize all
// the prims to 1% smaller, call this function with factor=0.99
// Returns TRUE if successful, or FALSE if resizing would have
// set a prim size out of bounds.
//
integer resizeLinksetWithBounds(float factor)
{
    // Test to see if it's safe to change all the prim sizes:

    integer linkNum;
    for (linkNum = llGetNumberOfPrims(); linkNum >= 1; --linkNum) {
        list params = llGetLinkPrimitiveParams(linkNum, [PRIM_SIZE]);
        vector sz = factor * llList2Vector(params, 0);
        if (sz.x < minPrimSize || sz.x > maxPrimSize ||
            sz.y < minPrimSize || sz.y > maxPrimSize ||
            sz.z < minPrimSize || sz.z > maxPrimSize) {
                return FALSE;
        }
    }

    // We've determined that we can safely change all the sizes, so
    // let's do so now.

    for (linkNum = llGetNumberOfPrims(); linkNum >= 1; --linkNum) {
        list oldParams = llGetLinkPrimitiveParams(linkNum, [PRIM_SIZE, PRIM_POSITION]);

        list newParams = [ PRIM_SIZE, factor * llList2Vector(oldParams, 0) ];
        if (linkNum > 1) {
            vector linkPos = (vector)llList2String(oldParams, 1);
            vector localPos = (linkPos - llGetRootPosition()) / llGetRootRotation();
            newParams += [ PRIM_POSITION, factor * localPos ];
        }

        llSetLinkPrimitiveParamsFast(linkNum, newParams);
    }

    return TRUE;
} </lsl>

Here's a silly example of how it's used:

<lsl> // Example of how to call resizeLinksetWithBounds()

//
default
{
    touch_start(integer num)
    {
        float factor = llPow(llFrand(2.0), 2.0); // random factor for demo
        if (resizeLinksetWithBounds(factor)) {
            llOwnerSay("Resized successfully by factor = " + (string)factor);
        } else {
            llOwnerSay("Oops, can't resize by factor " + (string)factor);
        }
    }
} </lsl>

(Acknowledgements: Thanks to Keith Reinard for testing and improving the example above.)

Also see Maestro Linden's newly posted linkset resizer.

Resizer challenges

A complete resizer solution is outside the scope of this article, but might need to consider such things as:

  • You might need a way to reset all the prims to a known size, position, and orientation in case a resize loop breaks before successfully resizing all the prims.
  • The example above might give unexpected results if executed while the object is in motion. For example, there is no way to guarantee that the functions llGetLinkPrimitiveParams() and llGetRootPosition() will be evaluated during the same simulator frame, so the local offset of a child prim could be computed incorrectly as the difference of the root position in one frame and the child position in another frame.
  • Roundoff errors could accumulate if proportional scaling is done many times. (See the Discussion page.)
  • It's easy to scale a linkset so that prims get moved beyond their linkability limits, and no easy way for a script to test for this in advance. For more information, see the discussions at SVC-5328 and SVC-5166.

Long range plans

The new LSL features described above are expected to appear in server version 1.38. Babbage Linden also mentioned a few additional LSL features he would like to implement sometime after 1.38, but with no guarantees if or when:

<lsl> PRIM_NAME, PRIM_DESC // for llGet/SetPrimitiveParams()

llAvatarOnLinkSitTarget()
llLinkSitTarget() </lsl>

Also see