Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Object listens only to parent?

Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
09-24-2005 13:58
I'm creating on object rezzer, and I'm trying to script a solution where the rezzer deletes all the objects it has rezzed by shouting a delete command on an obscure channel.

The problem occurs, of course, when another of the same rezzer is used nearby to delete it's own objects - obviously, all of them will delete, not just the ones created by that rezzer.

I'm wondering if there is a simple, elegant way to solve this - a way to either pass the key from the rezzer to its children, and have them only listen to the object that created them, or a way to make the object speak through the owner (which I'm fairly sure is impossible), or some other way to filter the command so that the rezzer will only delete its own objects.
Jillian Callahan
Rotary-winged Neko Girl
Join date: 24 Jun 2004
Posts: 3,766
09-24-2005 14:05
Well - one way is to have the rezzer choose a random channel to use when it rezzes - then pass that chanel to the children through the rez parameter.
_____________________
Aliasi Stonebender
Return of Catbread
Join date: 30 Jan 2005
Posts: 1,858
09-24-2005 14:10
From: Luc Aubret
I'm creating on object rezzer, and I'm trying to script a solution where the rezzer deletes all the objects it has rezzed by shouting a delete command on an obscure channel.

The problem occurs, of course, when another of the same rezzer is used nearby to delete it's own objects - obviously, all of them will delete, not just the ones created by that rezzer.

I'm wondering if there is a simple, elegant way to solve this - a way to either pass the key from the rezzer to its children, and have them only listen to the object that created them, or a way to make the object speak through the owner (which I'm fairly sure is impossible), or some other way to filter the command so that the rezzer will only delete its own objects.


an easy way might be to have the parent choose a random chat channel and pass it along to the rezzed objects through the start parameter.
_____________________
Red Mary says, softly, “How a man grows aggressive when his enemy displays propriety. He thinks: I will use this good behavior to enforce my advantage over her. Is it any wonder people hold good behavior in such disregard?”
Anything Surplus Home to the "Nuke the Crap Out of..." series of games and other stuff
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
09-24-2005 23:26
From: Aliasi Stonebender
an easy way might be to have the parent choose a random chat channel and pass it along to the rezzed objects through the start parameter.


That sounds perfect, except that I've not a clue how to choose a random number, or pass it along to the objects, LOL. Does anyone have a postable example of this being done?
Judah Jimador
Registered User
Join date: 13 Mar 2005
Posts: 230
09-25-2005 00:27
Hi, Luc,

I think they're suggesting something like this (code fragments only):


In the master object:
CODE


integer my_channel;

//
// Pick your group's channel
//
default {
state_entry() {
float some_huge_channel_number = 50000.0 + llFrand( 1000000.0 );
my_channel = (integer)some_huge_channel_number;
}
}
.
.
.
//
// Then, when you rez the object...the last argument in this function
// is passed into that object's on_rez event.
//
llRezObject( "LittleBuddy", llGetPos(), ZERO_VECTOR, ZERO_ROTATION, my_channel );

.
.
.

//
// Finally, when you're ready for your group to die..
//

llShout( my_channel, "..die" );



Your rezzed objects would have code that looked something like this:

CODE


default {

on_rez( integer rez_arg ) {
llListen( rez_arg, "", "", "..die" );
}

listen( integer channel, string name, key id, string msg ) {
llDie();
}

}



(That looks about right to me, but it's untested.)

--jj
Cadroe Murphy
Assistant to Mr. Shatner
Join date: 31 Jul 2003
Posts: 689
09-25-2005 08:49
I wanted to offer an idea in case you deal with the same situation I have. I have build tools which need to send commands to individual prims out of a set once they've been rezzed. For that reason I pass each prim a unique index through the rez param, so that each prim can filter out commands to itself. (There's a special ID for the whole set so I can send a command to every prim). Since the rez param is already being used for something, here is what I do. The prims listen on a default channel when they are rezzed. The rezzer immeditely generates a random channel and broadcasts it over the default channel to the prims. From then on communication between the rezzer and prims is over this new random channel. In theory the default channel is only used for a tiny slice of time, and after that the rezzed prims ignore the default channel, so the risk of collision with another rezzer is negligible.

I've put a little time into making generic scripts for rezzing and managing sets of prims, and I'm just going to stick the current code here. It's not finished, but maybe it will illustrate what I'm saying. The BlockManager script is designed to be used by other scripts through link messages. The Block script would be placed in the prim to be rezzed by the BlockManager.

CODE

//BlockManager script
//By Cadroe Murphy - 9-09-05
string gBlockName = "SmartBlock"; //name of block object in inventory
integer cInitBlockChannel = 4148744; //initial channel for communicating with blocks
integer gBlockChannel = cInitBlockChannel;
integer gNumBlocks = 0;

integer ALL_ID = 9999;
integer CREATE_SET = 6000;
integer FREEZE_SET = 6001;
integer DELETE_SET = 6002;
integer SEND_CMD = 6010;

integer ERR_OUT_OF_BOUNDS = 7000;

//Generate a new set of blocks and establish a comm channel with them
CreateSet()
{
//Freeze an existing set if it exists
if (gBlockChannel != cInitBlockChannel)
llShout(gBlockChannel, (string)ALL_ID + "_freeze");
//Reset channel
gBlockChannel = cInitBlockChannel;

vector pos = llGetPos();
integer i;
//Rez the blocks above this object in a stack
//The param for each rezzed object is its id (i.e. its index, from 0 to gNumBlocks)
for (i = 0; i < gNumBlocks; i++)
{
llRezObject(gBlockName, <pos.x, pos.y, pos.z + 1 + (i * .1)>,
<0.0, 0.0, 0.0>, <0, 0, 0, 0.0>, i);
}
//Generate a random channel to communicate on and send to blocks
integer newChannel = llRound(llFrand(999999)) + 100;
llShout(gBlockChannel, (string)ALL_ID + "_channel_" + (string)newChannel);
gBlockChannel = newChannel;
llOwnerSay("Created new set.");
}

//Tell any existing set of blocks to freeze which deletes the scripts inside them
FreezeSet()
{
llShout(gBlockChannel, (string)ALL_ID + "_freeze");
gBlockChannel = cInitBlockChannel;
llOwnerSay("Froze set.");
}

//Tell any existing set of blocks to delete themselves
//Obviously won't work if they've already been frozen
DeleteSet()
{
llShout(gBlockChannel, (string)ALL_ID + "_delete");
gBlockChannel = cInitBlockChannel;
llOwnerSay("Deleted set.");
}

//Send command to blocks - check for out of bounds
SendCommand(integer inSender, string inCmd, integer inIndex)
{
if (inIndex != ALL_ID && inIndex > gNumBlocks - 1)
{
//out of bounds, send error message
llMessageLinked(inSender, ERR_OUT_OF_BOUNDS, inCmd, (string)inIndex);
return;
}
llShout(gBlockChannel, (string)inIndex + "_" + inCmd);
}

default
{
state_entry()
{

}

link_message(integer sender_num, integer num, string str, key id)
{
if (num == CREATE_SET)
{
CreateSet();
}
else if (num == FREEZE_SET)
{
FreezeSet();
}
else if (num == DELETE_SET)
{
DeleteSet();
}
else if (num == SEND_CMD)
{
string ids = (string)id;
integer idx = (integer)ids;
SendCommand(sender_num, str, idx);
}
}

}



CODE

//Block script - Cadroe Murphy - for use by BlockManager
integer cInitBlockChannel = 4148744; //initial channel for communicating with manager
integer gChannel; //the channel specified for this ste of blocks
integer gCommHandle; //the handle of the open listen channel
integer gIndex = -1; //this block's index in set

integer ALL_ID = 9999;

HandlePrimCommand(list inCmdLine)
{
string tempStr;
vector tempVec;
rotation tempRot;
float tempFloatX;
float tempFloatY;
integer tempInt;
string cmd;

cmd = llList2String(inCmdLine, 1);
cmd = llToLower(cmd);

if (cmd == "pos")
{
tempStr = llList2String(inCmdLine,2);
tempVec = (vector)tempStr;
while (llGetPos() != tempVec)
llSetPos(tempVec);
return;
}
if (cmd == "rot")
{
tempStr = llList2String(inCmdLine,2);
tempRot = (rotation)tempStr;
llSetRot(tempRot);
return;
}
if (cmd == "posrot")
{
tempStr = llList2String(inCmdLine,2);
tempVec = (vector)tempStr;
tempStr = llList2String(inCmdLine,3);
tempRot = (rotation)tempStr;
llSetRot(tempRot);
while (llGetPos() != tempVec)
llSetPos(tempVec);
return;
}
if (cmd == "lookat")
{
tempStr = llList2String(inCmdLine,2);
tempVec = (vector)tempStr;
llLookAt(tempVec, 1, 1);
return;
}
if (cmd == "topsize")
{
tempFloatX = llList2Float(inCmdLine, 2);
tempFloatY = llList2Float(inCmdLine, 3);
llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX,
PRIM_HOLE_DEFAULT, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>,
<tempFloatX, tempFloatY, 0.0>,
<0.0, 0.0, 0.0>]);
return;
}
if (cmd == "color")
{
tempStr = llList2String(inCmdLine,2);
tempVec = (vector)tempStr;
tempInt = llList2Integer(inCmdLine, 3);
llSetColor(tempVec, tempInt);
return;
}
if (cmd == "texture")
{
tempStr = llList2String(inCmdLine,2);
tempInt = llList2Integer(inCmdLine, 3);
llSetTexture(tempStr, tempInt);
return;
}
if (cmd == "name")
{
llSetObjectName(llList2String(inCmdLine,2));
return;
}
}

default
{
on_rez(integer start_param)
{
gIndex = start_param;
gCommHandle = llListen(cInitBlockChannel,"" ,"","");
}

listen(integer chan, string name, key id, string text)
{
list cmdLine;
integer index;
string cmd;

cmdLine = llParseString2List(text, ["_"], []);
index = llList2Integer(cmdLine, 0);
if (index != gIndex && index != ALL_ID)
//not addressed to us, ignore
return;

cmd = llList2String(cmdLine, 1);
cmd = llToLower(cmd);
if (cmd == "channel")
{
integer newChannel = llList2Integer(cmdLine, 2);
llListenRemove(gCommHandle);
gCommHandle = llListen(newChannel, "", "", "");
}
else if (cmd == "delete")
{
llDie();
}
else if (cmd == "freeze")
{
llRemoveInventory(llGetScriptName());
return;
}
else
{
HandlePrimCommand(cmdLine);
}

}
}

_____________________
ShapeGen 1.12 and Cadroe Lathe 1.32 now available through
SLExchange.
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
09-25-2005 15:26
From: Cadroe Murphy
The prims listen on a default channel when they are rezzed. The rezzer immeditely generates a random channel and broadcasts it over the default channel to the prims. From then on communication between the rezzer and prims is over this new random channel. In theory the default channel is only used for a tiny slice of time, and after that the rezzed prims ignore the default channel, so the risk of collision with another rezzer is negligible.


Cadroe, your shapeblocks are excellent... but they have MAJOR collisions. Try and run two of them at the same time anywhere near each other, and your prims will get very confused.
Cadroe Murphy
Assistant to Mr. Shatner
Join date: 31 Jul 2003
Posts: 689
09-25-2005 15:36
From: Keknehv Psaltery
Cadroe, your shapeblocks are excellent... but they have MAJOR collisions. Try and run two of them at the same time anywhere near each other, and your prims will get very confused.


Oops, I'll look into it. If you think of a specific example I'd appreciate the feedback. No one's ever mentioned this to me, and I don't believe I've used two near each other myself since whatever initial trial I did. Splitting the block management out into these seperate scripts would be a good time for me to track down the problem. It does seem OK in theory... :) The first thing to confirm would be that the blocks are switching channels. If so, then if nothing else it should be possible to avoid collisions by giving seperate instances of the tools their own default channels (matching globals in the rezzer and rezee). But like I said, I'll look into it.
_____________________
ShapeGen 1.12 and Cadroe Lathe 1.32 now available through
SLExchange.
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
09-25-2005 17:31
Just try and rez two large spheres within 50m of each other simultaneously. You'll see it rather quickly.

Regardless of that minor flaw, Shapeblocks are truly brilliant. Thanks for making them free.
Cadroe Murphy
Assistant to Mr. Shatner
Join date: 31 Jul 2003
Posts: 689
09-25-2005 17:45
Aha, two spheres is actually a good clue. And thanks for the kind words, Keknehv, I'm glad people get use out of them.
_____________________
ShapeGen 1.12 and Cadroe Lathe 1.32 now available through
SLExchange.
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
09-26-2005 07:28
Thanks for all the great suggestions, guys.

I had a "wait a sec..." moment a few minutes back.

Instead of messing with random numbers, couldn't I just have the rezzing object assign its own key in the rezzed object's start param? Then the llListen in the on_rez event could automatically be assigned just to listen to the rezzing parent.

It sounds far too simple to work. Is it?
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
09-26-2005 07:52
From: Luc Aubret
It sounds far too simple to work. Is it?
I'm afriad so. :(
While keys are really just numbers (which we usually deal with pretty formatted in hex), they are really, really big numbers. They need 128 bits to represent, while integers only have 32 bits.
BTW - Does anyone know if there is an established format for keys? It would be kinda cool if we could guarantee that a specific set of 32 or less bits would be unique within a sim, for example.
Azrael Baphomet
Registered User
Join date: 13 Sep 2005
Posts: 93
09-26-2005 08:25
From: Luc Aubret
I'm creating on object rezzer, and I'm trying to script a solution where the rezzer deletes all the objects it has rezzed by shouting a delete command on an obscure channel.

The problem occurs, of course, when another of the same rezzer is used nearby to delete it's own objects - obviously, all of them will delete, not just the ones created by that rezzer.

I'm wondering if there is a simple, elegant way to solve this - a way to either pass the key from the rezzer to its children, and have them only listen to the object that created them, or a way to make the object speak through the owner (which I'm fairly sure is impossible), or some other way to filter the command so that the rezzer will only delete its own objects.



I used a similar approach to the others listed here, but I used a smaller number of channels by passing each object a string-based designator on one channel. Commands to die are prefaced with this designator and broadcast on another channel. Only objects whose designators match the current die command execute the llDie command.
Zodiakos Absolute
With a a dash of lemon.
Join date: 6 Jun 2005
Posts: 282
09-26-2005 12:32
I guess you could technically still use the object key, if you really wanted to, and were willing to use more steps to do it. You could use the random channel as previously stated, then just send the rezzing object's key on that channel, delete the listen on the rezzed object, then create a new listen that will only listen to objects with that key. I don't know what the point would be, and I don't think it would necessarily be more efficient than just listening on a random channel. :D
Luc Aubret
Oreo-eater
Join date: 14 Sep 2005
Posts: 86
09-26-2005 13:08
I agree that passing the object key along through a random chat channel would be an unnecessary redundancy. I've put my solution together by simply passing a random channel through the llRezObject start param. Thanks, guys.
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
09-26-2005 13:21
if you want to go the extra step, remember that object_rez passes the key of the rezzed object as its only parameter. you could use this to llEmail the key to the rezzed object (incurring a 20s penalty for each object), or you could add it to a list, and whenever the rezzer hears a "hello?" from another object, it only responds with "yes - here's my key - listen to me" if the key is in the list, etc etc.