June 28, 2012

Rezzing prims with varying properties

If an object rezzes prims with varying properties (shape, size, color, texture, etc), it can rez a generic scripted prim and then send that prim a message containing a list of values to be given to llSetPrimitiveParams().

The prim to be rezzed would contain this script
 

integer rezzerChannel = -873648273;
integer settingsChannel = -873648274;
default
{
state_entry() { 

     llSetStatus( STATUS_DIE_AT_EDGE, TRUE );
     llListen( settingsChannel, "", NULL_KEY, "" );
}

on_rez( integer rezCode ) {
     if ( rezCode == 0 ) {
         llResetScript();
     } else {
         llSay(rezzerChannel , "primRezzed|"+(string)rezCode);
     }
}

listen ( integer channel, string fromName, key fromKey, string msg ) {
    list a = llParseStringKeepNulls( msg, ["|"], [] );
    if ( llList2String(a,0) == "primSettings" ) {
        if ( llList2String(a,-1) == "END" ) {
            integer n = (integer)llList2String(a,1);
            if ( n > 0 ) {
                list params = decodeTypeList( llList2List( a,2,n+1) );
                llSetPrimitiveParams( params );
            }
        } else {
            llSay(DEBUG_CHANNEL, "*** truncated message");
        }
        llRemoveInventory( llGetScriptName() );
    }
}
}

 
Notes on the rezzed prim script:

  • STATUS_DIE_AT_EDGE keeps errant prims out of your Lost and Found folder.
  • In on_rez(), the special handling of a rezCode of zero allows you to manually rez the prim. The rezzer should give a non-zero rezCode to each object it rezzes.
  • For non-zero rezCodes, the script sends a message back to the rezzer. The rezzer responds with the desired settings.
  • llSay() is sufficient because the prim must have been rezzed within 10 meters of the rezzer.
________________
A rezzer script that creates a green horizontal polygon could be written as follows:

integer rezzerChannel = -873648273;
integer settingsChannel = -873648274;

integer polyCount = 8;

default
{
state_entry() {
    llListen( rezzerChannel , "", NULL_KEY, "" );
}

touch_start( integer nTouch ) {
     
    string name = llGetInventoryName(INVENTORY_OBJECT,0);
    integer k; for ( k=0; k < polyCount; k++ ) {
        llRezObject( name, llGetPos(), ZERO_VECTOR,
                        ZERO_ROTATION, 100 + k);
    }
}

listen ( integer channel, string fromName, key fromKey, string msg ) {
    list a = llParseStringKeepNulls( msg, ["|"], [] );
    if ( llList2String(a,0) == "primRezzed" ) {
         integer index = (integer)llList2String(a,1);
       
        float height = 5;
        float radius = 15; 
        float width = 0.2;
        float length = 2 * radius * llTan( PI / polyCount );

        float angle = index * TWO_PI / polyCount;
        rotation cRot = llEuler2Rot( < PI_BY_TWO, 0,0> )
                * llEuler2Rot( <0, 0, angle > );

        vector cPos = llGetPos() + < 0,0 ,height> 
                         + < radius,0 ,0>* cRot;

        // [ PRIM_TYPE, PRIM_TYPE_CYLINDER, integer hole_shape,
        // vector cut, float hollow, vector twist,
        // vector top_size, vector top_shear ]
        list settingsList = [
            PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0,1,0>, 0.0,
                <0,0,0>, <1,1,0>, <0,0,0>,
            PRIM_COLOR, ALL_SIDES, <0,1,0>, 1.0,
            PRIM_SIZE, < width, width, length >,
            PRIM_ROTATION, cRot, 
            PRIM_POSITION, cPos, PRIM_POSITION, cPos, 
            PRIM_POSITION, cPos ];
        settingsList = encodeTypeList( settingsList );

        llRegionSayTo( fromKey, settingsChannel, llDumpList2String(
            [ "primSettings", llGetListLength(settingsList) ]
            + settingsList
            + ["END"], "|" ));
    }
}
}
 
Notes on rezzer script:

  • It does not matter where llRezObject() places the prims since the subsequent message will specify the position.
  • Do not send prim settings in the object_rez() event. The prim may have rezzed, yet it may not have registered its listen event with the region.
  • SET_POSITION is limited to a 10 meter movement, so use several as needed. Given the height and radius used in this script, three was more than sufficient.
  • There is a limit to the number of messages that may be queued to the rezzer. If you will be rezzing more than 30 prims, use a timer to rez them in bursts of 20. Keep track of the number of rezzed prims and the number of messages received. Only rez bursts when the difference is less than 10.
 ________________

General notes:
  • The functions encodeTypeList() and decodeTypeList are described in the post "Interobject Communications: lists
  • If the call to llRemoveInventory() is removed from the rezzed prim script, then the rezzer could later change the settings of specific rezzed prims.  In this situation, the rezzed prim script should accept a "primScriptRemove" message.
 
  • Region managers frown on high performance rezzers. You might consider throttling the rezzing by putting a brief llSleep() after llRezObject(), which has an intrinsic delay of only 0.1 second.
  • As a clean-up courtesy to the region server, the rezzed prim script might call llSetTimerEvent()  when the rezCode is non-zero.  The timer event handler would call llDie().
[end]