Targeting specific scripts with llMessageLinked
|
|
Basement Desade
Registered User
Join date: 14 Jul 2006
Posts: 91
|
06-29-2009 23:28
Is there an easy way to make only specific receiving scripts listen to link messages only from specific sending ones in a linkset, preferably one line per script? In one of my past threads, Void talked about filtering and using the script's name to check incoming messages. Well, I've been trying to figure out how to do this, but the wiki is as clear as mud to me on this subject. I wish they would say something like "To target a specific script with llMessageLinked, just do THIS," but, alas, they don't.  So, if anyone would care to share the exact syntax with me, I would certainly appreciate it.
|
|
Dora Gustafson
Registered User
Join date: 13 Mar 2007
Posts: 779
|
06-30-2009 00:23
From: Basement Desade Is there an easy way to make only specific receiving scripts listen to link messages only from specific sending ones in a linkset, preferably one line per script? In one of my past threads, Void talked about filtering and using the script's name to check incoming messages. Well, I've been trying to figure out how to do this, but the wiki is as clear as mud to me on this subject. I wish they would say something like "To target a specific script with llMessageLinked, just do THIS," but, alas, they don't.  So, if anyone would care to share the exact syntax with me, I would certainly appreciate it. You can not target a script by its name. What you have to work with are these 3 parameters: num, str and id. llMessageLinked(integer linknum, integer num, string str, key id); The sending script must set one of them to a value the receiving script will recognize. Only you can decide which parameter and what value it shall be. You must design your scripts accordingly. The linknum parameter can be used as well, but it addresses a prim (or more prims) rather than a script. Happy scripting 
_____________________
From Studio Dora
|
|
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
|
06-30-2009 00:24
In a given prim, there can only be one script (or one inventory item in general for that matter) with a particular name. So target a link message at a specific prim and include the name of the intended script in the link message's string or key parameters. The syntax is up to you, really. There's no "official" way to do it, just like there's no "official" syntax for chat commands.
When I've done this I usually just use the name of the intended script target as the key parameter, and encode all other transmitted data in the string parameter. When keeping track of possible recipients, you might want to key by the combination of prim link number and script name, since that is a unique key in the object.
|
|
Kaluura Boa
Polygon Project
Join date: 27 Mar 2007
Posts: 194
|
06-30-2009 00:47
Short answer: No. There is no way to let scripts filter *AUTOMATICALLY* incoming link messages. When a link message is sent, every script in the target prim(s) will hear the message. So, if you can't put each script alone in its prim...
Long answer: Yes. *PROGRAMMATICALLY*, you can filter whatever you want.
Whenever I work with link messages that must reach a specific script target, I use the integer parameter to indicate who sends and/or who must listen.
Imagine you give a UNIQUE number to each of your script with the following line at the beginning of each of them:
integer MyNumber = unique_value; // (Small positive number, plz!)
(Or else, you can extract the last letter of the script name and cast it to integer.)
When a script sends message, it does it this way:
llMessageLinked(LINK_SET, (MyNumber << 16) | Destination, some_string, some_key);
"Destination" is, of course, the number of the script which must listen.
Then, in every script which listen to link messages:
link_message(integer sender, integer num, string msg, key id) { if ((num & 0xFFFF) == MyNumber) { // Hey! Somebody is talking to ME. } }
Or else:
link_message(integer sender, integer num, string msg, key id) { if (((num >> 16) & 0xFFFF) == TheNumberOfTheScriptIListenTo) { // Hey! The script I listen to is talking } }
Depending on the situation, you can simply or "complexify" but there's nothing better, faster, simpler than using the integer parameter to do filtering. If needed, you pack all your message in the string parameter with llList2CSV([this, that, etc]) or else just (string)my_integer if you don't need more.
If you REALLY REALLY REALLY want to keep the integer for some other purpose than filtering, it's possible to use the key, but I prefer to avoid working with strings whenever possible.
Hope it helps,
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
06-30-2009 03:19
technical loophole:
you can force detection by only a single script by placing that script (and no others) in a separate child prim, then target it by sending the message to only that child prim.
please note this probably isn't the best way to do it, since any script that ends up in the same object may use broadcasting values which go to all prims, all children, or all others, and if your unfiltered script picks up one of these messages it could cause all sorts of un expected errors.
ETA: if the reason you are wanting an automatic way is because you are already using all the data types available for your message, the better solution is to prefix your filter phrase to the string field, and then either remove it or ignore it when you process the variables.
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Basement Desade
Registered User
Join date: 14 Jul 2006
Posts: 91
|
Still clear as mud
06-30-2009 03:26
I guess what I should do here, in order to understand, is to post some specifics. Let's say, for example, I link six prims. The three on the bottom are cubes, and they contain the following switch script: default { touch_start(integer total_number) { llMessageLinked(LINK_SET, 0, "on",""); ; state on; } } state on { touch_start(integer total_number) { llMessageLinked(LINK_SET, 0, "off",""); state default; } }
The three atop these are "lightbulb" spheres and contain the receiving script:
default { link_message(integer sender_num, integer num_detected, string str, key id) { if (str == "on") { llMessageLinked(LINK_SET, TRUE, "",""); llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE]); llSetPrimitiveParams([PRIM_POINT_LIGHT, TRUE, < 1, 1, 1>, 1.0, 10.0, 0.75]); llSetPrimitiveParams( [ PRIM_GLOW, ALL_SIDES, .3 ] ) ; } if (str == "off") { llMessageLinked(LINK_SET, FALSE, "",""); llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, FALSE]); llSetPrimitiveParams([PRIM_POINT_LIGHT, FALSE, < 1, 1, 1>, 1.0, 10.0, 0.75]); llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 0.0]); } } }
As they are, whenever I click on any of the cubes, all three of the spheres light up. How, specifically, would you go about making it so only the sphere atop the cube that is clicked lights up?
|
|
Talon Brown
Slacker Punk
Join date: 17 May 2006
Posts: 352
|
06-30-2009 04:17
1. Switch script: llMessageLinked(LINK_SET, 0, "on", llGetObjectDesc()); 2. Bulb script: At the start of link_message(), if (id != llGetObjectDesc()) return; 3. Set each cube and its associated sphere's description field to a unique string. 4. ??? 5. Profit!
That's how I did it anyway, although in my case the profit never really panned out, likely due to the lack of ??? Also, and this is off this specific topic, but you don't need to call llSetPrimitiveParams() 3 times like that. You can merge all those commands into a list and just call it once instead.
|
|
Qie Niangao
Coin-operated
Join date: 24 May 2006
Posts: 7,138
|
06-30-2009 04:49
A slight variant on Talon's approach is to use the prim names instead of descriptions (at least for the recipients) and have the sender at state_entry search the prims in the linkset for the link number with a matching llLinkName(). That way the sender can send to only that one prim, so all the scripts in all the other prims don't have to wake up and determine that the message isn't for them.
A much sleazier way to get that effect is to link the prims in an order such that a sender knows what link number whither to send based on its own llGetLinkNumber(). That's very fragile, however, and hence very Not Recommended.
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
06-30-2009 04:53
From: Basement Desade As they are, whenever I click on any of the cubes, all three of the spheres light up. How, specifically, would you go about making it so only the sphere atop the cube that is clicked lights up? 1. You can target the prim containing the script with the Link Message, by specifying that prim's link number as the destination. 2. You can target the script's ID by putting it in the unused "num" parameter. 3. Best solution: You can use llSetLinkPrimitiveParams() to set the prim parameters directly and get rid of three scripts.
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
06-30-2009 07:17
name you light prims "light 1", "light 2", etc and your switch prims "switch 1", switch 2", etc list gLstLights; list gLstSwitches;
default{ state_entry(){ string vStrName; integer vIntCounter = llGetNumberOfPrims(); while (vIntCounter){ vStrName = llGetLinkName( vIntCounter ); if (! llSubStringIndex( vStrName, "light" )){ gLstLights += [vStrName, vIntCounter]; } else if (! llSubStringIndex( vStrName, "switch" )){ gLstSwitches += [vStrName, FALSE]; } gLstLights = llListSort( gLstLights, 2, TRUE ); gLstSwitches = llListSort( gLstSwitches, 2, TRUE ); --vIntCounter; } if (vIntCounter = (gLstLights != gLstSwitches)){ llOwnerSay( "There are " + (string)(vIntCounter / 2) + " lights compared to switches. expect errors" ); } }
touch_start( integer vIntTotal ){ integer vIntTarget = llListFindList( gLstSwitches, (list)llGetLinkName( llDetectedLinkNumber( 0 ) ) ) + 1; if (vIntTarget){ integer vIntState = ! llList2Integer( gLstSwitches, vIntTarget ); gLstSwitches = llListReplaceList( gLstSwitches, (list)vIntState , vIntTarget, vIntTarget ); llSetLinkPrimitiveParams( llList2Integer( gLstLights, vIntTarget ), [PRIM_GLOW, ALL_SIDES, !vIntState, PRIM_FULLBRIGHT, ALL_SIDES, vIntState, PRIM_POINT_LIGHT, vIntState, < 1, 1, 1>, 1.0, 10.0, 0.75] ); } } }
should work, if you don't understand what a certain portion is doing, then ask and someone will explain it
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Basement Desade
Registered User
Join date: 14 Jul 2006
Posts: 91
|
Got it
06-30-2009 18:16
Thanks folks, but through a bit more research, and trial and error, I discovered I could just list, for example "integer linknum = 3;" at the top of the switch script, and then replace LINK_SET with "linknum" in the "llMessageLinked(LINK_SET, 0, "on",""  ;" line. The simple solution I was seeking. 
|
|
Innula Zenovka
Registered User
Join date: 20 Jun 2007
Posts: 1,825
|
06-30-2009 20:25
From: Basement Desade Thanks folks, but through a bit more research, and trial and error, I discovered I could just list, for example "integer linknum = 3;" at the top of the switch script, and then replace LINK_SET with "linknum" in the "llMessageLinked(LINK_SET, 0, "on",""  ;" line. The simple solution I was seeking.  The problem with that -- which certainly works -- is that it's so easy to break if (when) you have second thoughts about the build and this means changing the link order. In practice, I think you'll find it's far quicker and easier either to pass meaningful codes as part of the string argument (I sometimes call my scripts stuff like "1st Floor Light" and then say if(str==llGetScriptName()) in the link_message event) or, as Void's example does, use the prims' names/descriptions and do everything from one main script. Put it like this -- I like to keep things simple and intuitive for myself, which is why (having tried to do it once) I'd never try to target prims by their link number in a build of any size or complexity.
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
07-01-2009 05:21
It's quicker and easier and more efficient to get rid of the slave scripts when you can and use llSetLinkPrimitiveParams directly. Use the NAME of the prim as the target. You can start out with a routine like this: integer lightlink1; integer lightlink2; integer lightlink3;
find_links() { integer i; integer n = llGetNumberOfLinks();
for(i = 1; i < n; i++) { string link_name = llGetLinkName(i); if(link_name == "light 1") lightlink1 = i; else if(link_name == "light 2") lightlink2 = i; else if(link_name == "light 3") lightlink3 = i; } }
Run that routine from on_rez(), changed(), and state_entry(), and you can use llSetLinkPrimitiveParams() on lightlink1 or whatever without having to track the link numbers directly.
|
|
Innula Zenovka
Registered User
Join date: 20 Jun 2007
Posts: 1,825
|
07-01-2009 10:54
I agree about using llSetLinkWhatever() when you can -- I always do -- but there is a cost when you want to change more than one , but not all, of the prims in the linkset, Looping through a large linkset to check the name of each prim and (depending on the function) spending 0.2 seconds on each prim can take quite a while, and sometimes the effect just isn't what you want. I'm working on a building at the moment with about 150 prims in the linkset, and, while I could do something like, string TARGET_PRIM_NAME = "window";
changeAllTargetPrims(list primParams) { integer i; for (i = llGetNumberOfPrims(); i > 0; --i) { if (llGetLinkName(i) == TARGET_PRIM_NAME) { llSetLinkPrimitiveParams(i, primParams); } } }
to change the windows' opacity and/or vary their colour/texture, it would take a fair time to complete it, compared with sending a link message to LINK_SET and letting the scripts in the window prims all do their thing simulatenously.
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
07-01-2009 10:56
True, but the OP was only changing one light at a time.
|