Jump to content

Update my radar that uses Sensor to use llGetAgentList


Recommended Posts

 I need to update my radar listed second below that uses sensor to use llGetAgentList listed first below so that it will work for the entire region. It works with Primsave so it needs to keep the same output. What's the best way to do that?

llGetAgentList

//https://wiki.secondlife.com/wiki/LlGetAgentList
//  Orders new list based on distance
//  and returns names and distances on touch

default
{
    touch_start(integer num_detected)
    {
        list keys = llGetAgentList(AGENT_LIST_REGION, []);
        integer numberOfKeys = llGetListLength(keys);

        vector currentPos = llGetPos();
        list newkeys;
        key thisAvKey;

        integer i;
        for (i = 0; i < numberOfKeys; ++i) {
            thisAvKey = llList2Key(keys,i);
            newkeys += [llRound(llVecDist(currentPos,
                            llList2Vector(llGetObjectDetails(thisAvKey, [OBJECT_POS]), 0))),
                        thisAvKey];
        }
 
        newkeys = llListSort(newkeys, 2, FALSE);     //  sort strided list by descending distance

        for (i = 0; i < (numberOfKeys * 2); i += 2) {
            //llOwnerSay(llGetDisplayName(llList2Key(newkeys, i+1))
            
            llSay(0,llGetDisplayName(llList2Key(newkeys, i+1))
                +" ["+ (string) llList2Integer(newkeys, i) + "m]");
        }
    }
}

 

Radar
///////////////////// User variables: ///////////////////////////////

// If the scan-distance is a sphere, this cuts off the bottom & top.
float ceiling = 90 ; // how high above the rezz-prim do we stop detecting
float floor = -90 ; // how low below the rezz-prim do we stop detecting, use negative
integer height_adjusted = 1 ; // Set to 1 to activate, 0 to de-activate to reduce lag

integer set_name = 0 ; // This sets the name of for what avi came first in the scan, as
                           // hover text over the rezzer.

integer rezzer_coms__C = -940369920 ; // The channel that is used for all
  // rezzers in the sim, to communicate & give commands.

// Below here nothing needs to be changed for proper operation  //
//////////////////////////////////////////////////////////////////

integer periodic_clean = 0 ; //a boolean that will be set when the next sensor is to do a simple clean

vector prim_z ; // the height of the rezzer at rezz-time (not on script reset)

integer to_rez_prims = 0 ; // How many prims will this rezzer rezz ?

integer message_given  = FALSE ; // prevents error message to be repeated

float scan_distance = 3 ; // distance to the avatar
integer rezzed = 0 ; // keep track of whether objects where rezzed already
integer position ; // counts down a number of Position commands after rezz,
   // because it turns out sometimes objects are rezzed, but do not position.
   // In all cases thusfar, one Position command did it.
   // Never did a Clean command not derezz everything

integer avDistance;
vector rPos;
integer i;

// A function that returns the amount of free prims on the land.
integer check_free ( integer verbose )
{
    integer max ; //maximum prims allowed
    integer here ; // prims that are rezzed, total count
    max = llGetParcelMaxPrims ( llGetPos ( ) , TRUE ) ;
    here = llGetParcelPrimCount ( llGetPos ( ) , PARCEL_COUNT_TOTAL , TRUE ) ;
    if ( verbose )
    {
        llWhisper ( 0 , "free prim space: "
            //  + " rezzed: " + ( string ) here
              + " free: " + ( string ) ( max - here ) ) ;
    }
    return max - here ; // how many still allowed
}

// rezzes the stuff
rezz ( )
{
    if ( 3 != rezzed ) // unrezzed
    {
        if ( to_rez_prims < check_free ( 0 ) )
        { // there  are enough prims free

 ///////////// Set name on rezzer:
            if ( set_name )
            {
                string avin ; // the one who entered (first)
                avin = llDetectedName ( 0 ) ; // find avi to give message
                llSetText ( avin , < 1 , 0 , 1 > , .4 ) ; // For the Fairy Inn, determines who owns the house
            }
 //////////// ^

            rezzed = 3 ; // keep track of rezzed status
        //llSay ( 0 , "Optional rezz message" ) ;
        // <--> here we rezz stuff
        // check if the primspace is there:
        // HERE WE ARE DOING THE REZZ COMMAND:
            llMessageLinked ( LINK_THIS , 0 , // unused
                                        "Build" , // copy over the received message
                                        "" ) ; // copy over, but it is unused
            position = 16 ;
                // We say on the coms what we do.
            llRegionSay ( rezzer_coms__C , "rezzing"
                      + ":" + ( string ) to_rez_prims ) ;
        }
        else // not enough free prims, give message once
        {
            key avi ; // the one who entered (first)
            avi = llDetectedKey ( 0 ) ; // find avi to give message
            if ( FALSE == message_given )
            {
                llRegionSayTo ( avi , 0 , "Not enough free prim space" ) ;
                    message_given = TRUE ; // remember to prevent spam
            }
        }
    }
        // We have to give the position order repeatedly, lag issues etc.
    if ( position ) // run down the positioning calls
    {
        if ( 0 == ( position % 5 ) ) // on ever count to 5, 3 times
        {
            llMessageLinked ( LINK_THIS , 0 , // unused
                                    "Position" , // copy over the received message
                                    "" ) ; // copy over, but it is unused
        }
        position -- ;
    }
}

de_rezz ( )
{
    message_given = FALSE ; // reset
    if ( rezzed )
    {
        //llSay ( derezz_channel , "derezz" ) ;
       // <--> here we derezz stuff
       llMessageLinked ( LINK_THIS , 0 , // unused
                              "Clean" , // copy over the received message
                            "" ) ; // copy over, but it is unused
       if ( 3 == rezzed )
       {
            //llSay ( 0 , "Optional de-rezz-message" ) ;
            llRegionSay ( rezzer_coms__C , "deleting"
                          + ":" + ( string ) to_rez_prims ) ;
        }
        rezzed -- ; // keep track of rezzed status
    }
    else if ( periodic_clean )
    {
               // <--> here we derezz stuff
       llMessageLinked ( LINK_THIS , 0 , // unused
                              "Clean" , // copy over the received message
                            "" ) ; // copy over, but it is unused
        periodic_clean = 0 ; // Done it, prevent re-execution on next sensor
    }
     ///////////// Set name on rezzer:
            llSetText ( "" , < 1 , 0 , 1 > , 1 ) ; // clear
    ///////////// ^
}

/* utility function from public library */
string left(string src, string divider)
{
    integer index = llSubStringIndex( src, divider );
    if(~index)
        return llDeleteSubString( src, index, -1);
    return src;
}

string right(string src, string divider)
{
    integer index = llSubStringIndex( src, divider );
    if(~index)
        return llDeleteSubString( src, 0, index + llStringLength(divider) - 1);
    return src;
}

default
{

    on_rez ( integer in )
    {
        llResetScript ( ) ;
    }

    state_entry ( )
    {
        scan_distance = ( float ) (
                 left ( llGetObjectDesc ( ) , "#" ) ) ; // object description field sets scan-distance.
        to_rez_prims = ( integer ) (
                 right ( llGetObjectDesc ( ) , "#" ) ) ; // object description field sets scan-distance.
        llSay ( 0 , "Scan distance (objdesc): " + ( string ) scan_distance
           + " meter. This rezzer rezzes: "
           + ( string ) to_rez_prims + " LI/prims" ) ;
        llSensorRepeat( "", NULL_KEY , AGENT , scan_distance , PI , 2.0 ); // the number is the range to search 96 = max

        // It turns out that sometimes by lag there are still objects that remain
        // rezzed despite the sensor system, probably because the object-rezzing is so
        // slow/lagged that they are rezzed after that the cleaning already has passed.
        // Therefore here is a periodic check & clean system, on a slower time tick to
        // reduce adding lag. Since nothing should be rezzed, or after one succesful clean
        // nothing remains rezzed, the clean command given will not be qued to other
        // scripts, because they are no longer there. Hence it should not be causing a
        // lot of lag anyway.
      // uncomment to use:
      //  llOwnerSay ( "Rezzer script initiation delay (30-60 seconds)..." ) ;
      //  llSleep ( 30 + ( integer ) llFrand ( 30 ) ) ; // This causes the timer to start at random,
        // so that not all these rezzers will do their periodic clean at the same second.
        // They could otherwise be close to each other, when they are rezzed out by the Crown.
        // Incidentally this also makes the Crown rezzing a little more comfortable, because
        // some large distance rezzers will start rezzing themselves automatically, if people
        // are even merely at ground level where the Crown is.
        llSetTimerEvent ( 60 ) ; // This seems to be fairly reasonable.
        llOwnerSay ( "Operational ..." ) ;
    }

    timer( )
    {
        // We are going to set a boolean, that will be used by the next sensor-sweep to do a
        // one time simple additional cleaning command, regardless of what is thought to be rezzed
        // by this script. It is not worth the additional trouble to create a check toward rezzed
        // objects
        periodic_clean = 1 ; // Next no-sensor will do a simple additional clean.
    }

    // The key code of the sencor and no-sencor events is written as a function,
    // because the no-sencor event is executed both by itself, and the sencor
    // event which is turned into a no-sencor event if the avi is detected in
    // the exclusion zones
    sensor ( integer number )
    {

        if ( height_adjusted )  // going to reject the scan find if out of high/low bounds
                                // This is meant to reduce lag, as it is often executed
        {
            // Compare z-axis (vertical), if the avi is outside the range,
            // the whole sensor should not have activated and hence all code
            // is skipped.
            vector location_avi = llDetectedPos ( 0 ) ;  // Where is the avi
            // Detected in range, now detract the top/bottom ends.
            prim_z = llGetPos ( ) ; // where is the rezzer

            if ( ( ( floor   + prim_z.z ) < location_avi.z ) &&  // avi above floor
                 ( ( ceiling + prim_z.z ) > location_avi.z ) ) // avi below ceiling
            {// inside of sensor-range
                rezz ( ) ; // This is de-facto the sencor event
            }
            else
            {
                de_rezz ( ) ; // turn the sencor in the no_sencor event
            }
        }
        else // We don't care about the height limits, and so it is always a good sensor find.
        {
            rezz ( ) ;
        }
    }

    // sensor does not detect owner if it's attached
    no_sensor()
    {
        de_rezz ( ) ; // remove it
    }
}

Link to comment
Share on other sites

If there's not already a timer() event handler, one might simply replace the call to llSensorRepeat with a llSetTimerEvent with the same interval, and then move the logic in the existing sensor() and no_sensor() events into a new timer() event, stepping through the list returned by llGetAgentList() the way the sensor events stepped through llDetected* agents.

Here the existing timer() event is pretty simple and apparently driven by a global counter on the same interval, so could probably stay there with a little tweaking, but…

… problem is, I can't figure out how this existing code steps through the agents detected by the sensor. The llDetected* function calls only use the zero-th detection (so the one sensed agent nearest the sensor), so… I guess I'm stumped. Are we sure this sensor code is actually doing the thing that instead would be done with llGetAgentList ? If we really only care about the nearest agent, I guess we could step through that list hunting for it by llVecDist between each agent's OBJECT_POS and the scripted object's position, but is that really what this script is trying to do?

(I have no idea what Primsave is, but it sorta doesn't matter until I understand how the sensor results work.)

Link to comment
Share on other sites

The radar keeps the build rezzed while an avatar is in range. It doesn't report any specific names. So, that is also what I was trying to figure out. Does it need some logic like no agents found, or check each agent found for in range or not and does llGetAgentList work that way. Primsave tells your rezzer to keep a build rezzed while avatars are in range, and derez when no avatars are in range. You put the range and number of prims in the object description like this 45#112 and the ceiling and floor in the script.

Link to comment
Share on other sites

Ah okay so it really is only conditional on the presence of one avatar in range. Unfortunately, as the wiki says of llGetAgentList, "There is no guaranteed understandable order or randomness to the list returned" so the timer()  logic will need to loop through that list, terminating when it finds one in range, and if it exhausts the list without finding any, de_rezz as in the current no_sensor() event. And if it does find one in range, that corresponds to whatever is done in the current sensor() event.

The periodic_clean variable is currently set by the timer() event which triggers the next de_rezz to send an extra "Clean" message. What might work instead is a global timestamp of when the last such cleaning happened, and let de_rezz check if llGetTime() has gone longer than that 60-second periodic cleaning interval, and if so, send the extra message and update the global timestamp.

Edited by Qie Niangao
Link to comment
Share on other sites

Posted (edited)

Thanks, that clears up that issue! The wiki has an example of sorting the list

 

//  Orders new list based on distance
//  and returns names and distances on touch

default
{
    touch_start(integer num_detected)
    {
        list keys = llGetAgentList(AGENT_LIST_REGION, []);
        integer numberOfKeys = llGetListLength(keys);

        vector currentPos = llGetPos();
        list newkeys;
        key thisAvKey;

        integer i;
        for (i = 0; i < numberOfKeys; ++i) {
            thisAvKey = llList2Key(keys,i);
            newkeys += [llRound(llVecDist(currentPos,
                            llList2Vector(llGetObjectDetails(thisAvKey, [OBJECT_POS]), 0))),
                        thisAvKey];
        }
  
        newkeys = llListSort(newkeys, 2, FALSE);     //  sort strided list by descending distance

        for (i = 0; i < (numberOfKeys * 2); i += 2) {
            llOwnerSay(llGetDisplayName(llList2Key(newkeys, i+1))
                +" ["+ (string) llList2Integer(newkeys, i) + "m]");
        }
    }
}
Edited by Petey Carver
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...