Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Communication between scripts

Phil Wade
Registered User
Join date: 17 Oct 2006
Posts: 9
01-30-2007 13:40
I have the following problem

I have 2 scripts that must work together, the first script must perform some work then send a message to the second script so that it can do its bit, that works ok so far.

The problem that I have is that I need the first script to wait until the second script has finished before it resumes.

To complicate the matter the first script is recursive.

I give an outline of what I have at the moment below.

The real problem is the llSleep statment in th first script, what I really want is for the script to pause at this point until it receives a message from the second script to say the second script has done its bit.

Im new to LSL so I may be missing something obvious so please have patience with me.

-----------------------------------------------------------------------------------------------------
Script 1


my_function(param)
{
do
{
do something;

if(1st condition)
{
llLinkedMessage(do your bit); // Send message to second script
llSleep (??); // Give it time to finish
}

if(2nd condition)
{
do some more work:
my_function(param) // May need to call ourself
}

} while (3rd condition)
}


default
{

lots more code;
}

------------------------------------------------------------------------------------------
Script 2

my_other_function(param)
{
do some work;
}


default
{

link_message(param)
{
my_other_function(param)
}
}
Arachnid Baxter
Registered User
Join date: 8 Jan 2007
Posts: 44
01-30-2007 13:49
Have the first script return after sending the link message. Have the second script send a reply link message when it's finished, and the first one listen for link messages, and carry on executing when it receives the reply. You'll need to replace your recursion with iteration (always possible, but not always easy).
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
01-30-2007 14:02
I bet Newgate will post something about "states" soon. He's a rock on that. You could go into a state and add another linkmsg-event there. Check for a certain number (num) or command (str). Act on that and go into next state, aso. Help newgate!
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
Some one call?
01-30-2007 14:23
From: Woopsy Dazy
I bet Newgate will post something about "states" soon. He's a rock on that. You could go into a state and add another linkmsg-event there. Check for a certain number (num) or command (str). Act on that and go into next state, aso. Help newgate!


States would be one way of approaching it, but would depend on exactly what the code was trying to do as to wether or not it would be effective.

I'm more intrigued as to what you're sending from one script to another that requires recurssion.

You could use a cascade system, each script process its bit then passes it onto the next via linked message. You'd obviously have to include all the parameters, and you would probably end up with several scripts with near identical content just passing data between themselves until they finally spit out a result..
Phil Wade
Registered User
Join date: 17 Oct 2006
Posts: 9
More nfo
01-30-2007 15:38
Trying to walk a tree structure

entry point

pointer to the next entry on this level
pointer to first entry on next level
next level has the same pointers etc

recurssion is a nice solution because you just pass the the start point and call yourself

the problem is that when i get to the end of the tree i need to pass it to another script ( for memory reasons)

But i dont know how long the other script will take to finish

im sorry if this isnt making much sense to you im struggling to put it into words
Edison Swain
Registered User
Join date: 7 Dec 2006
Posts: 51
01-30-2007 16:22
I've used states like this to run a similar process. Again, like Newgate said, it does depend on what the rest of the script is doing - for example, it may limit or even halt some of the things that Script 1 is currently doing.

The way that I worked it was:

Script 1 is running in given state. When it needs to pass information to Script 2, it stores the information that it needs to pass in global variables, then jumps to a new state that simply passes the information to Script 2 and waits for a response. When it gets the response, it jumps to a new state again that gets it back into the swing of processing whatever it needs to process.

Here are some example scripts (forgive my ineptitude - I'm still new to scripting myself!)

This would be Script 1:
CODE

// values that will be passed from this script out to Script 2
string vOutVariable1;
string vOutVariable2;
string vOutVariable3;

// values that will be returned back from Script 2
string vReturnedVariable1;
string vReturnedVariable2;

state Running
{
touch_start(integer vNumber) // or whatever event handler you are using
{
// doing whatever it needs to do, then it gets to the point where it needs to pass processing over to Script 2

// assign the values that you need to pass over to Script 2 into global string variables (typecasting to strings where needed)
vOutVariable1 = // whatever
vOutVariable2 = // whatever
vOutVariable3 = // whatever

state WaitingForResponse;
}
}

state WaitingForResponse
{
state_entry()
{
// send the info to Script 2 - 'Command1' should be a string of your choosing that Script 2 will recognize to know it's time to start processing
llMessageLinked(LINK_THIS, 0, "Command1~" + vOutVariable1 + "~" + vOutVariable2 + "~" + vOutVariable3, NULL_KEY);
}

link_message(integer vSender, integer vNumber, string vString, key vID)
{
// now this state just sits and waits until it hears back from Script 2 - it will recognize the message by 'Command2'
list vParameters = llParseStringKeepNulls(vString, ["~"], []);

if (llList2String(vParameters, 0) == "Command2")
{
vReturnedVariable1= llList2String(vParameters, 1);
vReturnedVariable2= llList2String(vParameters, 2);

state ContinueRunning;
}
}
}

state ContinueRunning
{
// put whatever code you want in here to run after you get the info back from Script 2
}


And this would be Script 2:
CODE

// values that will be passed into this script from Script 1
string vInVariable1;
string vInVariable2;
string vInVariable3;

// values that will be returned from this script back to Script 1
string vReturningVariable1;
string vReturningVariable2;

state Idle
{
link_message(integer vSender, integer vNumber, string vString, key vID)
{
// this state just sits and waits until it gets a message from Script 1 - it verifies it is the correct message by checking to see if it includes 'Command1'
list vParameters = llParseStringKeepNulls(vString, ["~"], []);

if (llList2String(vParameters, 0) == "Command1")
{
// if we got the right 'Command1', then split the message back into it's individual variables
// this is where we'd typecast back to the native variable format ie, if we were passing integers or vectors
vInVariable1 = llList2String(vParameters, 1);
vInVariable2 = llList2String(vParameters, 2);
vInVariable3 = llList2String(vParameters, 3);

state Processing;
}
}
}

state Processing
{
state_entry()
{
// do whatever you need to do in Script 2 here - this can be as simple or as complex as you need it

// when you're ready, assign the variables that you'll need to pass back to Script 1
vReturningVariable1 = // whatever
vReturningVariable2 = // whatever

// send the info back to Script 1
llMessageLinked(LINK_THIS, 0, "Command2~" + vReturningVariable1 + "~" + vReturningVariable2, NULL_KEY);

// go back to sitting around and waiting until Script 2 is needed again
state Idle
}
}


A few caveats here:

- a setup like this does halt script 1 entirely, it's going to send the message to script 2 and then do nothing but wait for an answer, you may be able to modify this, depending on the regular flow of control in Script 1

- Command1 and Command2 should simply be unique strings that you can define to make things easily understood by you. A setup like this allows for multiple scripts (like Script 3 and Script 4) to work in similar ways as Script 2, just listening for different commands

- if you want to pass integers or keys back and forth, you can pass one of each as the integer or key parameters in the llMessageLinked call. But for multiple integers or keys, or for other data types like vectors or rotations, cast them to strings and concatenate them, then split them and cast them back in the other script

- in Script 1, depending on the flow of control for your script, you may not need to have a ContinueRunning state; jumping back into Running is fine if that's what works. Similarly, in Script 2, you may not even need a Processing state, as you may be able to accomplish something very simple directly in the event handler in the Idle state and pass the llMessageLinked back right from there. Or, if Script 2 is very complex, it can have multiple states itself before passing the information back

- always make sure that both Script 1 and Script 2 are designed so that one is going to be in a state that has a link_message event handler that will respond when the other needs to call it. Otherwise, it's very easy for one of the scripts to hang and freeze

- this example is probably not memory efficient in a number of ways, and can be improved upon; for example, using something like a bunch of standard 4 digit codes as your 'commands' would allow the use of llGetSubString(vString, 0, 3) in your 'if' statements, instead of creating the list first and using the list memory if you don't need to.

For my own purposes, I was building an application that got very large and needed to be broken into a number of scripts. I developed a series of commands that each one could then use to call the others, and hand off processing in the application. I even used a system like this to define an external 'function' that was rather large and needed to be called from multiple scripts. Instead of including the 'function' in each script individually (taking up space and requiring multiple sources to edit if I need to change it) I put the 'function' in a seperate script, and used link messages like these to pass 'parameters' into the 'function' and have it process what it needs to and then return a value.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
01-31-2007 00:25
From: Phil Wade
Trying to walk a tree structure

entry point

pointer to the next entry on this level
pointer to first entry on next level
next level has the same pointers etc

recurssion is a nice solution because you just pass the the start point and call yourself

the problem is that when i get to the end of the tree i need to pass it to another script ( for memory reasons)

But i dont know how long the other script will take to finish

im sorry if this isnt making much sense to you im struggling to put it into words


So each script handles a different branch of a bigger tree? or should that be a different tree of a forrest? :)

I wasnt questioning the use of recurssion, just why it needed to interact with a second script part way through. if possible you may want to see if you can make it such that the point at which you pass off to the second script is actually the end of this scripts functionality, unless of course it gets re-entered by the second script.

You're currently describing a straight forward semaphore / block and states will handle it quite nicely. Edison's code is along the same lines I would use although I prefer to use numeric command constants as numerical if's are simpler.
Adrian Zobel
Registered User
Join date: 4 Jan 2006
Posts: 49
01-31-2007 09:01
First of all, I think you shouldn't use recursion. Don't have the function call itself.

In an event-driven system like this, the more practical thing is to have the script send a link-message to itself. Well, actually, sometimes you send a linkmessage to yourself, and sometimes you send a linkmessage to the other script. In either case, you stop there... and nothing happens until you receive another linkmessage. If you're always waiting for a linkmessage to do anything, you don't need to use llSleep (or state change or anything else) to make yourself pause.