Don't click here unless you want to be banned.

LSL Wiki : LibraryWarpPos

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl411.us.archive.org
The corresponding forum thread for this can be found here.

For an alternate method that does not use llSetPrimitiveParams, but parallel calls to llSetPos (link messages to multiple llSetPos scripts); if you can understand it, try LibrarySenWarp instead.

WarpPos: a method by which the 10m limit on non-physical movement, which limits speed to about 50m/s, may be avoided.

llSetPrimitiveParams, it would seem, executes each rule in the list as it comes across it. This allows you to set up a list in the form of [PRIM_POSITION,pos,PRIM_POSITION,pos, ... ,PRIM_POSITION,pos] which, when run by the server, basically causes many llSetPos calls in a very short amount of time. As far as I can tell, this is done in one frame on the server-- so there are no intermediate steps in the journey.

It's completely public domain. Look at it, modify it, sell it in an item, whatever. But I'll be annoyed if you scam noobs into buying it.

I have added a hack which currently allows this to work in just two steps, regardless of destination. This seriously speeds up the function and allows you to cross large distances easily - Felixe Thorne -- Moved hack to current function since it was added to the original

warpPos( vector d ) //R&D by Keknehv Psaltery, ~05/25/2006
{
    integer iterations;
    vector curpos;
    if ( d.z < (llGround(d-llGetPos())+0.01)) 
        d.z = llGround(d-llGetPos())+0.01; //Avoid object getting stuck at destination
    if ( d.z > 4096 )      //Object doesn't get stuck on ceiling as of 1.18.5 (3), and with
        d.z = 4096;        //havok 4 the height limit is increasing to 1024m.

    //Hack added by Felixe Thorne
    curpos=llGetPos();
    llSetPrimitiveParams([PRIM_POSITION, <1.84e+19, 1.84e+19, 1.84e+19>, PRIM_POSITION, d]);
    if (llGetPos()==curpos) {
        //Looks like it's been fixed, resort to the old method..
        do //This will ensure the code still works.. albeit slowly.. if LL remove this trick (which they have done and reverted in the past..)
        {
            iterations++;
            integer s = (integer)(llVecMag(d-llGetPos())/10)+1; //The number of jumps necessary
            if ( s > 100 )  //Try and avoid stack/heap collisions with far away destinations
                s = 100;    //  1km should be plenty
            integer e = (integer)( llLog( s ) / llLog( 2 ) );   //Solve '2^n=s'        
            list rules = [ PRIM_POSITION, d ];  //The start for the rules list
            integer i;
            for ( i = 0 ; i < e ; ++i )     //Start expanding the list
                rules += rules;
                integer r = s - (integer)llPow( 2, e );
                if ( r > 0 )                    //Finish it up
                    rules += llList2List( rules, 0, r * 2 + 1 );
                llSetPrimitiveParams( rules );
                curpos=llGetPos();
                if (iterations>100) {
                    d=curpos; //We're going nowhere fast, so bug out of the loop
                }
        } while (llVecDist(curpos,d) > 0.2);
    }
}

A few observations:
Sim crossings are perilous for AVs. Depending on connection speed and whether or not you are connected to the sim (can see it on the mini-map), it may screw up your client. However, it seems like objects, by themselves, can cross great distances. I managed to send an object 4 sims away diagonally. Further testing would help us to understand these things.

The script limits the maximum distance to 1km, in order to prevent stack/heap collisions. Still, this is 100 times what llSetPos was limited to-- and you can, of course, modify it to allow larger distances, but beware. "A couple of hacks have been added which negate this restriction, so long as they continue to work."

The average time this function takes to execute is .2 seconds, which is barely noticeable at all, and can easily be attributed to general lag. A simple optimization for an object with a known destination might be to calculate the list beforehand, and then call llSetPrimitiveParams with that list.

BlindWanderer (Strife Onizuka) and a few other people took my code and smashed the list expansion, making it much faster and less memory intensive. Here's the modified code:
warpPos( vector destpos) 
{   //R&D by Keknehv Psaltery, 05/25/2006
    //with a little pokeing by Strife, and a bit more
    //some more munging by Talarus Luan
    //Final cleanup by Keknehv Psaltery

    //Add hack by Felixe Thorne 
    vector curpos;
    if ( destpos.z < (llGround(destpos-llGetPos())+0.01)) 
        destpos.z = llGround(destpos-llGetPos())+0.01; //Avoid object getting stuck at destination
    if ( destpos.z > 4096 )      //Object doesn't get stuck on ceiling as of 1.18.5 (3), and with
        destpos.z = 4096;        //havok 4 the height limit is increasing to 4096m.

    //Hack added by Felixe Thorne
    curpos=llGetPos();
    llSetPrimitiveParams([PRIM_POSITION, <1.84e+19, 1.84e+19, 1.84e+19>, PRIM_POSITION, destpos]);
    if (llGetPos()==curpos) {
        //Looks like it's been fixed, resort to the old method..
       // Compute the number of jumps necessary
       integer jumps = (integer)(llVecDist(destpos, llGetPos()) / 10.0) + 1;
       // Try and avoid stack/heap collisions, can be changed from 100 to 400 easily when compiled in Mono
       if (jumps > 400 )
           jumps = 400;    //  4km should be plenty
       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.
       //Changed by Eddy Ofarrel to tighten memory use some more
       llSetPrimitiveParams( (rules=[]) + rules + llList2List( rules, (count - jumps) << 1, count) );
       if ( llVecDist( llGetPos(), destpos ) > .001 ) //Failsafe
           while ( --jumps ) 
               llSetPos( destpos );
    }
}

TdubDowler (aka Riden Blaisdale) shrunk this even more (compile in mono or you could get stack heap errors):
warp(vector pos)
{
    list rules;
    integer num = llRound(llVecDist(llGetPos(),pos)/10)+1;
    integer x;
    for(x=0; x<num; ++x) rules=(rules=[])+rules+[PRIM_POSITION,pos];
    llSetPrimitiveParams(rules);
}

And shrinking the tiny version even more...
warp(vector pos)
{
    list rules;
    integer num = llCeil(llVecDist(llGetPos(),pos)/10);
    while(num--)rules=(rules=[])+rules+[PRIM_POSITION,pos];
    llSetPrimitiveParams(rules);
}
Well, that's all. Have fun!
Comments [Hide comments/form]
Can you post a summary of the thread here so those of us who can't see it know what this is for?
-- DolusNaumova (2006-05-26 14:56:01)
The exact same thing, just with possible discussion. Oh, and Ben Linden said they probably won't fix this.
-- KeknehvPsaltery (2006-05-26 15:01:20)
I see now. Thanks, Kek.
-- DolusNaumova (2006-05-27 10:29:39)
What does "llSetPrimitiveParams error running rule #3: non-integer rule."? I keep getting that as an error, although it's undeniable that it works well... :)
-- GwynethLlewelyn (2006-06-27 15:48:01)
Woops, that's probably because the optimized script is bugged. I'll put up the fixed version.
-- KeknehvPsaltery (2006-07-01 10:16:30)
Is it possible to use this in a loop to bypass the 1km limit?
-- DolusNaumova (2006-07-14 19:59:39)
Yes, here's a demonstration.

Posted in the Scripting Library by Khalek Trescothick/update by Iridescent Enzyme



This listens on channel 90 for stuff like "x,y,z*sim name", which will port the object to sim_name:<x, y, z>. Fixing it to take input as you like should be trivial, and is left as an excercise to the reader.

NB: This isn't a panacea - there are lots of conditions where we can't find a route to the destination. At some point in the future, I'll look at making this algorithm a recursive maze-solver, which should cover most cases, but for right now, I'd recommend just not using this script for huge distances, as that increases your chances of getting lost.

float delay = 4.0;
string destination_sim;
vector destination;
key sim_req;

warp_pos(vector d) {
    if (d.z > 768)
        d.z = 768;

    //The number of jumps necessary
    integer s = ((integer)(llVecDist(d, llGetPos()) / 10) + 1) << 1;
    //Try and avoid stack/heap collisions
    if (s > 200)
        s = 200;    //  1km should be plenty (but 2km is better, apparently)

    //Solve '2^n=s'
    integer e = (integer)(llLog(s) / 0.6931471805);
    integer i = e;
    list rules = [PRIM_POSITION, d];  //The start for the rules list
    if (i <= e) {
        do
            rules = (rules=[]) + rules + rules;//should tighten memory use.
        while ((i+=2) < e);     //Start expanding the list
    }
    llSetPrimitiveParams(rules + llDeleteSubList(rules, s - (1 << e), s));
}

vector ordinal_border(vector target) {
    vector ordinal = target - llGetRegionCorner();
    if (ordinal.y > 0)
        ordinal.y = 255;
    else if (ordinal.y < 0)
        ordinal.y = 0;

    if (ordinal.x > 0)
        ordinal.x = 255;
    else if (ordinal.x < 0)
        ordinal.x = 0;

    ordinal.z = 200;
    return ordinal;
}

vector plot_course(vector target) {
    vector pos = llGetPos();
    vector next_vertex = ordinal_border(target);
    vector norm = next_vertex - pos;

    vector first;
    vector second;
    vector try_long = <128, next_vertex.y, next_vertex.z>;
    vector try_lat = <next_vertex.x, 128, next_vertex.z>;
    if (llFabs(norm.x) > llFabs(norm.y)) {
        first = try_lat;
        second = try_long;
    } else {
        first = try_long;
        second = try_lat;
    }

    if (llEdgeOfWorld(pos, first) == FALSE)
        return first;
    else if (llEdgeOfWorld(pos, second) == FALSE)
        return second;
    else
        return <-1, -1, -1>;
}

debug_send_location() {
    llInstantMessage(llGetOwner(), "Now at: " + llGetRegionName() + ": " + (string)llGetPos());
}

default {
    state_entry() {
        llListen(90, "", "", "");
        llSitTarget(<0, 0, 0>, ZERO_ROTATION);
    }

    dataserver(key id, string data) {
        if (id == sim_req) {
            destination = (vector)data + destination;
            while (llGetRegionName() != destination_sim) {
                vector next_hop = plot_course(destination);
                if (next_hop.x == -1) {
                    llInstantMessage(llGetOwner(), "Pinpoint Error");
                    debug_send_location();
                    llDie();
                } else {
                    while (llVecDist(next_hop, llGetPos()) > 5)
                        warp_pos(next_hop);

                    if (next_hop.x == 0)
                        next_hop.x = -3;
                    else if (next_hop.x == 255)
                        next_hop.x = 258;
                    else if (next_hop.y == 0)
                        next_hop.y = -3;
                    else if (next_hop.y == 255)
                        next_hop.y = 258;

                    //Needed delay so you do not crash over sim borders!
                    llInstantMessage(llGetOwner(), "Crossing border in " + (string)delay +  " seconds.");
                    llSleep(delay);
                    debug_send_location();
                    llSetPos(next_hop);
                    llInstantMessage(llGetOwner(), "Border crossed.");
                    debug_send_location();
                }
            }
            destination -= llGetRegionCorner();
            while (llVecDist(destination, llGetPos()) > 5)
                warp_pos(destination);

            llInstantMessage(llGetOwner(), "At destination.");
            debug_send_location();
            llSay(0, "WAUUG!");
        }
    }

    listen(integer channel, string name, key id, string message) {
        list parts = llParseString2List(message, ["*"], []);
        list coords = llCSV2List(llList2String(parts, 0));
        destination_sim = llList2String(parts, 1);
        if(llGetSubString(destination_sim, 0, 0) == " ")
            destination_sim = llGetSubString(destination_sim, 1, -1);

        destination = <llList2Float(coords, 0), llList2Float(coords, 1), llList2Float(coords, 2)>;
        sim_req = llRequestSimulatorData(destination_sim, DATA_SIM_POS);
    }
}
-- KeknehvPsaltery (2006-07-14 21:10:28)
Very cool. Thanks for that, Kek; I was thinking about doing something like that myself but I don't have to anymore.

However, the llInstantMessage(llGetOwner(),...); should be replaced with llOwnerSay().
-- DolusNaumova (2006-07-15 07:40:15)
No, it shouldn't, because that function is meant to tell the location of an object several sims away, and llOwnerSay() only works when the owner is in the same sim.
-- KeknehvPsaltery (2006-07-15 09:26:02)
This is an awesome find, thanks for sharing the info!
-- ZhanZhao (2006-10-27 17:19:38)
Very Nice!
-- CometAero (2006-11-16 21:49:26)
Awesome, warpPos is broken again, and you assholes pulled the fix. Very helpful. I forgot that wiki's are about the suppression of knowledge, and making it as difficult to obtain information as possible. Egotistical bullshit like this is why I don't use this site.
-- c-66-56-94-64.hsd1.ga.comcast.net (2007-03-20 08:27:23)
I tried to use the script but I couldnt find a way to activate it... Can anyone help me?
-- pool-72-65-198-134.pitbpa.east.verizon.net (2007-06-14 09:22:09)
Attach a comment to this page: