Saturday, November 27, 2010

Truly Warped

Edit: This method is obsolete with the release of llSetRegionPos(). I'm leaving the post as is, since there are still some interesting techniques demonstrated here.

Ever run into that extremely frustrating 10m cap on moving a prim to another position? Just another example of the Lindens trying to ruin our good time. Fortunately, thanks to Keknehv Psaltery and a few other talented scripters, we have this lovely little function-in-a-can commonly known as WarpPos. WarpPos uses a little oversight in the llSetPrimitiveParams implementation to possibly the greatest effect in the history of workarounds. In a nutshell, llSetPrimitiveParams executes a list of changes to the parameters of a prim in immediate succession. It is typically used for morphing the shape and size of prims, among other things, in a single function; without it we would have to call several functions in a row to achieve a similar effect. However, our boy Keknehv came up with the brilliant idea to stuff this list with many different calls to the same parameter...to change the position of a prim (imagine said prim puttering along 10m at a time in a straight line to the destination). While this could have been achieved with multiple calls to llSetPos, the script delay of 0.1 seconds makes this trip a great deal slower...with llSetPrimitiveParams, it happens in a single movement; so fast you can't even tell there are any movements beyond the first. Because of this fabulous bit of coding, many of the teleporters, weaponry, and all the things that need to move a great distance FAST are made extremely possible. So without any further delay, here is WarpPos!

warpPos( vector destpos,rotation destrot)
{
    //calculate the number of jumps
    integer jumps = (integer)(llVecDist(destpos, llGetPos()) / 10.0) + 1;
    //distance cap, can't go more than 4110 in a single warp
    if (jumps > 411)
        jumps = 411;
    list rules = [ PRIM_POSITION, destpos ];  //The start for the rules list
    integer count = 1;
    while ( ( count = count << 1 ) < jumps)
        rules = (rules=[]) + rules + rules;   //should tighten memory use.
   //putter along to the destination with the constructed rules list
    llSetLinkPrimitiveParamsFast(LINK_THIS, rules + llList2List( rules, (count - jumps) << 1, count) );
    if ( llVecDist( llGetPos(), destpos ) > .001 ) //Failsafe
        while ( --jumps )
        //when within less than 10m of the destination, do one final jump
            llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POSITION,destpos,PRIM_ROTATION,destrot]);
}

I'm not going to go into extensive detail on how this works, but I will attempt a general outline. Basically the script first calculates the distance the prim's current position and its destination. Then, diving by 10 (the maximum distance in meters for a single jump) will give the number of jumps required to reach the destination. Next comes a bit of a safety cap (which CAN be removed should you require some REALLY long warping) that limits the maximum distance of the warp to 4110 meters (or 411 10m jumps, modeled after the 4096m ceiling on active scripts). Personally, I don't care for this cap, and remove it on my own scripts when necessary; it doesn't actually prevent the prim from going above the 4096m altitude anyways. Then we have a bit of complicated data-pushing that builds the step-by-step list of position changes necessary to reach the desired coordinate, followed by the execution of said list. Finally, once we are close enough to reach the final destination with a single jump, we do so...and voila! Faster than you can say 'ludicrous speed' we have closed the gap on a potentially enormous amount of distance with relative ease. Take that, Lindens (although, to their credit, they decided to support this 'bug' rather than 'fix' it)! One more thing worth pointing out is that, if implemented properly, scripts with WarpPos can easily traverse to coordinates in other sims, even hopping across several at a time. However, sitting on a prim that is doing this is -not- advised, you will probably crash (without avatars on them though, prims can change sims with ease). This amazing piece of code is available on the wiki, albeit with different commenting and some minor differences (I updated all parameter-changing functions to use llSetLinkPrimitiveParamsFast, as well as adding in a bit to allow for controlling the orientation the prim arrives at as well). I hope you enjoyed this article, and that you use this knowledge to do some heavy-duty warping in the future :)

                                                                                                                                      ~Arkane

No comments:

Post a Comment