Object rez: Difference between revisions

From Second Life Wiki
Jump to navigation Jump to search
Gwyneth Llewelyn (talk | contribs)
m Replaced <source> with <syntaxhighlight>
Wulfie Reanimator (talk | contribs)
mNo edit summary
 
(3 intermediate revisions by the same user not shown)
Line 8: Line 8:
* Triggers in all running scripts with an [[object_rez]] event, AND in the same '''prim''' as the script calling [[llRezObject]] or [[llRezAtRoot]].
* Triggers in all running scripts with an [[object_rez]] event, AND in the same '''prim''' as the script calling [[llRezObject]] or [[llRezAtRoot]].
** Does NOT trigger in linked prims.
** Does NOT trigger in linked prims.
* A message sent to the rezzed object may arrive before the object has opened a channel and is ready to receive it unless you provide for a communication handshake between the rezzer and the new object.
* A message sent to the rezzed object may arrive before the object has had a chance to opened a listen channel and is ready to receive [[listen]] events unless you provide for a communication handshake between the rezzer and the new object.
** Objects that have opened a listen channel before being rezzed (for example in [[state_entry]]) will be able to receive messages as soon as object_rez is triggered.
|examples=
|examples=
Script in the parent object "Rezzer.lsl"
==== Rez with handshake communication ====
The rezzer script will create a new object ("rezzee") and wait for a message from it before sending inventory items to the new object. Once all inventory items have been sent, the rezzer will send a message to the new object, letting it know the process is finished.
<syntaxhighlight lang="lsl2">
<syntaxhighlight lang="lsl2">
////////////////////////
// The rezzer and rezzee must use the same communication channel.
// Rezzer script.
integer COM_CHANNEL = -17974594;
// Rez' an object from inventory, establishes a communication channel and
string REZZEE_NAME = "Rezzee";
//  gives the rezzed object inventory.
 
integer COM_CHANNEL=-17974594; // chat channel used to coordinate between rezzer and rezzee
string REZZEE_NAME="Rezzee";


// These are expected messages between rezzer and rezzee.
string CMD_REZZEE_READY = "REZZEE_READY";
string CMD_REZZEE_READY = "REZZEE_READY";
string CMD_REZZER_DONE = "REZZER_DONE";
string CMD_REZZER_DONE = "REZZER_DONE";


key rezzee_key;
key rezzee_key;


default  
default
{
{
//...
touch_start(integer num_detected)
touch_start(integer count)
{
{
state configure_child;
// A separate state is used to disable touch-events and remove listens.
// This prevents multiple objects from being rezzed until the previous one
// has finished receiving everything it needs.
state rez_new_object;
}
}
//...
}
}


// rez and configure a child
state rez_new_object
state configure_child
{
{
state_entry()
state_entry()
{
{
// where to rez
// Listen for messages on the shared channel, from objects with the correct name.
vector position = llGetPos() + <0.0, 0.0, 1.0>;
llListen(COM_CHANNEL, REZZEE_NAME, "", "");
// establish rezzer's listen on the command channel
 
llListen( COM_CHANNEL, "", "", "" );
// Rez the object with the shared channel as the rez-parameter.
// rez the object from inventory.  Note that we are passing the  
vector position = llGetPos() + <0, 0, 1>;
// communication channel as the rez parameter.
llRezObject(REZZEE_NAME, position, ZERO_VECTOR, ZERO_ROTATION, COM_CHANNEL);
llRezObject(REZZEE_NAME, position, ZERO_VECTOR, ZERO_ROTATION, COM_CHANNEL);
}
}


object_rez(key id)
object_rez(key id)
{ // the object has been rezzed in world. It may not have successfully
{
// established its communication yet or done anything that it needs to
// The object has rezzed in-world. It may not have called llListen yet,
// in order to be ready for config. Don't do anything till we get the signal
// so we'll save its UUID and wait for a message from it.
rezzee_key = id;
rezzee_key = id;
}
}
 
listen(integer channel, string name, key id, string message)
listen(integer channel, string name, key id, string message)
{
{
if (message == CMD_REZZEE_READY)
// Check that the 'ready' message was sent by the object we rezzed last.
{ // the rezzee has told us that they are ready to be configured.  We can
if (message == CMD_REZZEE_READY && id == rezzee_key)
// we can sanity check id == rezzee_id, but in this trivial case that is
{
// not necessary.
// Send inventory to the new object.
integer count = llGetInventoryNumber(INVENTORY_NOTECARD);
integer i = llGetInventoryNumber(INVENTORY_NOTECARD);
// give all note cards in our inventory to the rezzee (we could do scripts or objects here too)
while (i--)
while(count)
{
{
string name = llGetInventoryName(INVENTORY_NOTECARD, --count);
string name = llGetInventoryName(INVENTORY_NOTECARD, i);
llGiveInventory(id, name);
llGiveInventory(id, name);
}
}
// And now tell the rezzee that we have finished giving it everything.
 
// Let the new object know it's ready, and return to original state.
llRegionSayTo(id, COM_CHANNEL, CMD_REZZER_DONE);
llRegionSayTo(id, COM_CHANNEL, CMD_REZZER_DONE);
// And we can leave configure child mode.
state default;
state default;
}
}
Line 77: Line 74:
}
}
</syntaxhighlight>
</syntaxhighlight>
Script in the child object "Rezzee.lsl"
The script in the new object ("rezzee") will let the rezzer know when it's prepared to receive communications.
<syntaxhighlight lang="lsl2">
<syntaxhighlight lang="lsl2">
// Rezzee
// These are expected messages between rezzer and rezzee.
 
integer com_channel = 0;
key parent_key = NULL_KEY;
 
string CMD_REZZEE_READY = "REZZEE_READY";
string CMD_REZZEE_READY = "REZZEE_READY";
string CMD_REZZER_DONE = "REZZER_DONE";
string CMD_REZZER_DONE = "REZZER_DONE";


default  
// These will be determined after this object is created by another object.
integer com_channel;
key rezzer_key;
 
default
{
{
//...
on_rez(integer start_param)
on_rez(integer start_param)
{
{
// A separate state is used to prevent other functionality from happening
// while this object waits for its rezzer to finish sending everything it needs.
com_channel = start_param;
com_channel = start_param;
state configure;
state wait_for_configuration;
}
}
//...
}
}


state configure
state wait_for_configuration
{
{
state_entry()
state_entry()
{
{
// Get the key of the object that rezzed us
// Get the key of the object which rezzed this object.
list details = llGetObjectDetails( llGetKey(), [ OBJECT_REZZER_KEY ] );
list details = llGetObjectDetails(llGetKey(), [OBJECT_REZZER_KEY]);
parent_key = llList2Key(details, 0);
rezzer_key = llList2Key(details, 0);
 
// establish our command channel and only listen to the object that rezzed us
// Listen for messages on the shared channel, from only the rezzer.
llListen(com_channel, "", parent_key, "");
llListen(com_channel, "", rezzer_key, "");
// Our rezzer will be giving us inventory.
 
llAllowInventoryDrop(TRUE);
// Prepare to receive inventory, then tell the rezzer we're ready.
// finally tell our rezzer that we are ready
llAllowInventoryDrop(TRUE);
llRegionSayTo( parent_key, com_channel, CMD_REZZEE_READY );
llRegionSayTo(rezzer_key, com_channel, CMD_REZZEE_READY);
}
}
 
listen( integer channel, string name, key id, string message )
listen( integer channel, string name, key id, string message )
{ // in a more complex example you could check that the id and channel
{
// match but for this example we can take it on faith.
// Check that the 'done' message was sent by the rezzer.
if (message == CMD_REZZER_DONE)
if (message == CMD_REZZER_DONE && id == rezzer_key)
{ // the parent has told this script that it is done we can go back to  
{
// our normal state.
// Return to the original state to continue normal functionality.
state default;
state default;
}
}
}
}
 
state_exit()
state_exit()
{ // turn off inventory drop.
{
llAllowInventoryDrop(FALSE);
// Turn off inventory drop. Changing state will also remove listens.
// We don't need to clean up the listen since that will be done automatically
llAllowInventoryDrop(FALSE);
// when we leave this state.
}
}
}
</syntaxhighlight>
==== Rez and communicate without handshake ====
If the new object has already opened a listen channel before being rezzed, a handshake is not necessary because the object_rez event will not trigger until the object is fully initialized.
 
This is how a script in the new object can pre-open a listen channel:
<syntaxhighlight lang="lsl2">
// The rezzer and rezzee must use the same communication channel.
integer COM_CHANNEL = -17974594;
 
default
{
    // This event is triggered when the script starts
    // and doesn't trigger again when this object is rezzed,
    // which means the listener will be open as soon as a new copy is rezzed.
    state_entry()
    {
        llListen(COM_CHANNEL, "", "", "");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        // Get the key of the object which rezzed this object.
        list details = llGetObjectDetails(llGetKey(), [OBJECT_REZZER_KEY]);
        key rezzer_key = llList2Key(details, 0);
 
        if (id == rezzer_key)
        {
            // The message could be anything useful, such as
            // position data, sound/texture/avatar UUID, etc.
            llOwnerSay("I heard: " + message);
        }
    }
}
</syntaxhighlight>
And this is how it would simplify the rezzer script:
<syntaxhighlight lang="lsl2">
// The rezzer and rezzee must use the same communication channel.
integer COM_CHANNEL = -17974594;
string REZZEE_NAME = "Rezzee";
 
default
{
    touch_start(integer num_detected)
    {
        // Rez the object. The shared channel isn't included
        // because the new object is already listening to it.
        vector position = llGetPos() + <0, 0, 1>;
        llRezObject(REZZEE_NAME, position, ZERO_VECTOR, ZERO_ROTATION, 0);
    }
 
    object_rez(key id)
    {
        // The object has rezzed in-world.
        // We can message it directly because we know it's listening.
        llRegionSayTo(id, COM_CHANNEL, "Are you there?");
    }
}
}
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 16:08, 27 January 2024

Description

Event: object_rez( key id ){ ; }

Triggered when the object rezzes an object.

• key id UUID of object rezzed.

Caveats

  • Triggers in all running scripts with an object_rez event, AND in the same prim as the script calling llRezObject or llRezAtRoot.
    • Does NOT trigger in linked prims.
  • A message sent to the rezzed object may arrive before the object has had a chance to opened a listen channel and is ready to receive listen events unless you provide for a communication handshake between the rezzer and the new object.
    • Objects that have opened a listen channel before being rezzed (for example in state_entry) will be able to receive messages as soon as object_rez is triggered.


Examples

Rez with handshake communication

The rezzer script will create a new object ("rezzee") and wait for a message from it before sending inventory items to the new object. Once all inventory items have been sent, the rezzer will send a message to the new object, letting it know the process is finished. <syntaxhighlight lang="lsl2"> // The rezzer and rezzee must use the same communication channel. integer COM_CHANNEL = -17974594; string REZZEE_NAME = "Rezzee";

// These are expected messages between rezzer and rezzee. string CMD_REZZEE_READY = "REZZEE_READY"; string CMD_REZZER_DONE = "REZZER_DONE";

key rezzee_key;

default { touch_start(integer num_detected) { // A separate state is used to disable touch-events and remove listens. // This prevents multiple objects from being rezzed until the previous one // has finished receiving everything it needs. state rez_new_object; } }

state rez_new_object { state_entry() { // Listen for messages on the shared channel, from objects with the correct name. llListen(COM_CHANNEL, REZZEE_NAME, "", "");

// Rez the object with the shared channel as the rez-parameter. vector position = llGetPos() + <0, 0, 1>; llRezObject(REZZEE_NAME, position, ZERO_VECTOR, ZERO_ROTATION, COM_CHANNEL); }

object_rez(key id) { // The object has rezzed in-world. It may not have called llListen yet, // so we'll save its UUID and wait for a message from it. rezzee_key = id; }

listen(integer channel, string name, key id, string message) { // Check that the 'ready' message was sent by the object we rezzed last. if (message == CMD_REZZEE_READY && id == rezzee_key) { // Send inventory to the new object. integer i = llGetInventoryNumber(INVENTORY_NOTECARD); while (i--) { string name = llGetInventoryName(INVENTORY_NOTECARD, i); llGiveInventory(id, name); }

// Let the new object know it's ready, and return to original state. llRegionSayTo(id, COM_CHANNEL, CMD_REZZER_DONE); state default; } } } </syntaxhighlight> The script in the new object ("rezzee") will let the rezzer know when it's prepared to receive communications. <syntaxhighlight lang="lsl2"> // These are expected messages between rezzer and rezzee. string CMD_REZZEE_READY = "REZZEE_READY"; string CMD_REZZER_DONE = "REZZER_DONE";

// These will be determined after this object is created by another object. integer com_channel; key rezzer_key;

default { on_rez(integer start_param) { // A separate state is used to prevent other functionality from happening // while this object waits for its rezzer to finish sending everything it needs. com_channel = start_param; state wait_for_configuration; } }

state wait_for_configuration { state_entry() { // Get the key of the object which rezzed this object. list details = llGetObjectDetails(llGetKey(), [OBJECT_REZZER_KEY]); rezzer_key = llList2Key(details, 0);

// Listen for messages on the shared channel, from only the rezzer. llListen(com_channel, "", rezzer_key, "");

// Prepare to receive inventory, then tell the rezzer we're ready. llAllowInventoryDrop(TRUE); llRegionSayTo(rezzer_key, com_channel, CMD_REZZEE_READY); }

listen( integer channel, string name, key id, string message ) { // Check that the 'done' message was sent by the rezzer. if (message == CMD_REZZER_DONE && id == rezzer_key) { // Return to the original state to continue normal functionality. state default; } }

state_exit() { // Turn off inventory drop. Changing state will also remove listens. llAllowInventoryDrop(FALSE); } } </syntaxhighlight>

Rez and communicate without handshake

If the new object has already opened a listen channel before being rezzed, a handshake is not necessary because the object_rez event will not trigger until the object is fully initialized.

This is how a script in the new object can pre-open a listen channel: <syntaxhighlight lang="lsl2"> // The rezzer and rezzee must use the same communication channel. integer COM_CHANNEL = -17974594;

default {

   // This event is triggered when the script starts
   // and doesn't trigger again when this object is rezzed,
   // which means the listener will be open as soon as a new copy is rezzed.
   state_entry()
   {
       llListen(COM_CHANNEL, "", "", "");
   }
   listen(integer channel, string name, key id, string message)
   {
       // Get the key of the object which rezzed this object.
       list details = llGetObjectDetails(llGetKey(), [OBJECT_REZZER_KEY]);
       key rezzer_key = llList2Key(details, 0);
       if (id == rezzer_key)
       {
           // The message could be anything useful, such as
           // position data, sound/texture/avatar UUID, etc.
           llOwnerSay("I heard: " + message);
       }
   }

} </syntaxhighlight> And this is how it would simplify the rezzer script: <syntaxhighlight lang="lsl2"> // The rezzer and rezzee must use the same communication channel. integer COM_CHANNEL = -17974594; string REZZEE_NAME = "Rezzee";

default {

   touch_start(integer num_detected)
   {
       // Rez the object. The shared channel isn't included
       // because the new object is already listening to it.
       vector position = llGetPos() + <0, 0, 1>;
       llRezObject(REZZEE_NAME, position, ZERO_VECTOR, ZERO_ROTATION, 0);
   }
   object_rez(key id)
   {
       // The object has rezzed in-world.
       // We can message it directly because we know it's listening.
       llRegionSayTo(id, COM_CHANNEL, "Are you there?");
   }

} </syntaxhighlight>

See Also

Events

•  on_rez Triggered when the object the script is in is rezzed

Functions

•  llRezObject Used to rez an object at the center of mass
•  llRezAtRoot Used to rez an object at the root

Deep Notes

Issues

All Issues

~ Search JIRA for related Issues
   object_rez() erroneously triggers on full parcel
   Possible Mono bug with object_rez

Signature

event void object_rez( key id );