Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Inter script Communication Noobie Question

RichD Tomsen
Photographer / Builder
Join date: 18 Nov 2007
Posts: 24
06-11-2008 21:35
Been out of “Programming Mode” for a few years, but like riding a bike its coming back to me. I have been making a parcel media center script, and as is common I keep coming up with nice shinny new features for the script. Right now it works inside a single prime and has may functions similar to Freeview. So a little thought background

I have done my best to keep the code lean and light, using functions to handle repetitive operations. Keeping if/else statement small and efficient…. Etc….. But as in all complex scripts I have run head long into the memory wall… What I would like to to do is move some of these functions, particularly the ones that manipulate the prim itself, into a separate script that I can call from the main script. I know I can do a “say/listen” combination using specially set aside channels to talk to particular function scripts. And then parse the message into its component parts. Or I can use link messages, but these seem to talk to all of the scripts in a target prime, so I would have to have code to detect what script I’m actually talking to. This method seems inefficient.

Now my question. With the understanding that I have a single prim with multiple scripts. And one of these scripts is the master with a few slaves that need to be spoken to directly. What is the best way to handle this to operate most efficiently and with the least amount of induced lag?

Some code examples with a little explanation would be most helpful. I know how I would handle this in other programming languages, and a linked message seems to be intended for multi prim objects. There just doesn’t seem to be a way to call a specific script when they all reside in the same prim.
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
06-11-2008 22:37
well in the linked messages you can send more than just 1 thing at a time

llMessageLinked( integer linknum, integer num, string str, key id );

i often time just stick a integer in the second argument and on the other end look for that number, kinda like a chat channel

yea all the scripts will get the message but only the ones i want will function

ie

llMessageLinked(-4,1,"bob", NULL_KEY);

on the other end

link_message( integer sender_num, integer num, string str, key id )
{
if (num == 1) then llSay(str);
}

this of course isnt the only option, just the simplest

http://wiki.secondlife.com/wiki/Category:LSL_Link_Message
Johan Laurasia
Fully Rezzed
Join date: 31 Oct 2006
Posts: 1,394
06-11-2008 23:03
Also, it's important to mention link messages are the least laggy way to communicate between scripts, also...


llMessageLinked(-4,1,"bob", NULL_KEY);

is improper,


llMessageLinked(LINK_THIS,1,"bob", NULL_KEY);

is proper, it not only is easier to debug, it's not likely to break should LL ever decide to modify the constant.



http://www.secondscripter.com/
_____________________
My tutes
http://www.youtube.com/johanlaurasia
Shadow Subagja
Registered User
Join date: 29 Apr 2007
Posts: 354
06-12-2008 00:22
There is no baked in way to send a link message to a specific script. You can pretty easily cook up a channel type system between your scripts using the integer parameter in a link message, use the key value if you don't need it, or if you're passing a lot of data and are hard pressed you can always prefix your string message or key with a unique identifier and parse out the target name, command, arguments etc from there using a comma separated list and (llCSV2List is useful for this).

Basically you have to cook that part up and stay consistent for your scripts to inter-operate reliably.
RichD Tomsen
Photographer / Builder
Join date: 18 Nov 2007
Posts: 24
06-12-2008 09:26
Thanks all for your very helpful insight. I was leaning toward using linked messages as a solution but was wondering if someone had come up with a more interesting way to do it, or that I had missed a “call” function someplace.

I like the idea of using the second argument as a key to alert the script that it’s being talked to. It could also allow these script modules to have multi functions and to allow for return codes. The thing now is to work out the internal timing and routing of the main script… This is sure turning out to be much more of a project…. and I love it
Jesse Barnett
500,000 scoville units
Join date: 21 May 2006
Posts: 4,160
06-12-2008 09:49
From: Johan Laurasia
Also, it's important to mention link messages are the least laggy way to communicate between scripts, also...


llMessageLinked(-4,1,"bob", NULL_KEY);

is improper,


llMessageLinked(LINK_THIS,1,"bob", NULL_KEY);

is proper, it not only is easier to debug, it's not likely to break should LL ever decide to modify the constant.



http://www.secondscripter.com/

It isn't improper at all. LL isn't going to change the constants and break scripts.
_____________________
I (who is a she not a he) reserve the right to exercise selective comprehension of the OP's question at anytime.
From: someone
I am still around, just no longer here. See you across the aisle. Hope LL burns in hell for archiving this forum
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-12-2008 16:12
My use of link messages always follows a pretty well-defined pattern. I use the integer parameter as the command (and for any new script/protocol I generate a random integer in the range -2^-31 to 2^31-1 as the starting command number), and the string and key parameters as arguments to the command. Usually most parameters go into the string parameter in CSV format, and when appropriate I use the key parameter for a special purpose such as additional routing (which script the command is aimed at) or which resident initiated the action that the command is servicing.

For a few applications I have had need to route commands to specific scripts, and had multiple helper scripts to distribute the work load. When demand is high, it is even best to break all the helper scripts into multiple prims to guarantee that you don't run into the limit on maximum queued link messages (currently 64).

For example, if you need to send out 128 commands in a one second period, and each script has a one second delay servicing a command, you are going to lose messages (e.g. the first script picks up a command, services it, 127 messages fly by while it is delayed, 63 of which are dropped because the queue is filled, and one of those dropped is probably one that was aimed at the first script again). If instead you separate those scripts into groups between 8 different prims and send the link message only to the prim with the target script in it, you'll only be sending out 16 messages per second to each prim (and thus each script in that prim), and the scripts can easily keep up without the queue overflowing.

Here is an example of how to do this. This hasn't yet been compiled so it might need some minor syntax fixes, but it should give you the idea. Probably in a real application I would send messages to scripts in a round-robin fashion rather than randomly, but this works for an example script:

CODE

//// Main Script

// params not used
integer HELPER_QUERY_LINK = -741215098;
// key param is script name
integer HELPER_REGISTER_LINK = -741215099;
// string param is message
// key param is target helper script
integer EXAMPLE_COMMAND = -741215100;

float SETUP_TIME = 2.0;

string EXAMPLE_MESSAGE = "Hello Prim!";
float EXAMPLE_MESSAGE_DELAY = 0.1;

integer messaging = FALSE;
integer nextTargetHelper = 0;

// Each element has the form primNum:scriptName
list helperScripts = [];
integer nHelperScripts = 0;

queryHelperScripts()
{
llMessageLinked(LINK_SET, HELPER_QUERY_LINK, "", NULL_KEY);
}

registerHelperScript(integer primNum, string scriptName)
{
string entry = ((string)primNum)+","+scriptName;
if (llListFindList(helperScripts, [ entry ]) >= 0)
{
// Already registered
return;
}

helperScripts = (helperScripts=[])+helperScripts+[ entry ];
}

sendCommandToHelper(integer helperNum, integer cmd, string paramStr)
{
string entry = llList2String(helperScripts, helperNum);
integer commaPos = llSubStringIndex(entry, ",");
integer primNum = llGetSubString(entry, 0, commaPos-1);
string scriptName = llGetSubString(entry, commaPos+1, -1);

llMessageLinked(primNum, cmd, paramStr, (key)scriptName);
}


default
{
state_entry()
{
queryHelperScripts();
llSetTimerEvent(SETUP_TIME);
}

timer()
{
if (messaging)
{
// Send message to next helper script
sendCommandToHelper(nextTargetHelper, EXAMPLE_COMMAND, EXAMPLE_MESSAGE);
nextTargetHelper = (nextTargetHelper+1)%nHelperScripts;
} else
{
llOwnerSay("Master script ready. Starting message distribution.");
llSetTimerEvent(EXAMPLE_MESSAGE_DELAY);
}
}

link_message(integer senderPrim, integer cmd, string stringParam, key keyParam)
{
if (cmd == HELPER_REGISTER_LINK)
{
registerHelperScript(senderPrim, (string)keyParam);
}
}
}


CODE

//// Helper Script

// params not used
integer HELPER_QUERY_LINK = -741215098;
// key param is script name
integer HELPER_REGISTER_LINK = -741215099;
// string param is message
// key param is target helper script
integer EXAMPLE_COMMAND = -741215100;

float SETUP_TIME = 2.0;

sendHelperRegistration()
{
// Keep all helpers from responding all at once
llSleep(llFrand(0.5*SETUP_TIME));

llMessageLinked(LINK_SET, HELPER_REGISTER_LINK, "", llGetScriptName());
}


default
{
state_entry()
{
// On reset of all scripts, it is unknown whether a helper or the main script
// will be reset first. Therefore, send registration both when this script is
// reset AND when requested by the main script. Redundant registrations are
// detected by the main script anyway.
sendHelperRegistration();
}

link_message(integer senderPrim, integer cmd, string stringParam, key keyParam)
{
if (cmd == HELPER_QUERY_LINK)
{
sendHelperRegistration();
} else if (cmd == EXAMPLE_COMMAND)
{
if ((string)keyParam != llGetScriptName())
{
// This script isn't the target destination
return;
}

llOwnerSay(
"Helper '"+llGetScriptName()+
"' from prim "+llGetLinkNumber()+
" received message: "+stringParam);
}
}
}
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
06-12-2008 16:18
Interesting. For some reason the forums refuse to accept a preview or post with the following string (remove the space after the less-than character): < scriptName>

I assume it looks like a XML/(X)HTML tag to the forum software or something, and character escaping isn't working properly. This doesn't happen for other ones I have tried. For example, <primNum> works fine.