Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Problems with listen

Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-29-2006 04:38
I apologise in advance for this query, because I suspect the answer is probably obvious, but unfortunately I'm a crap scripter.

I have a script which listens for a message put out by another script.

The form of the script is that there is a state_entry() followed by a listen. Within the listen there is a while loop. The 'while' checks a message received by the listen. If the message is negative the flow drops out of the while and continues to cycle through the listen. If the message is positive, the flow loops around various instructions until the message changes to negative, then it drops out of the while and continues to cycle through the listen.

The problem is, that once the while receives a positive message, it no longer seems to listen, and the while loop carries on indefinitely.

Does anybody have any idea how I can set up this loop so that it continues to listen within the loop?

Hope that is not too obtuse.
_____________________
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
08-29-2006 05:18
Without seeing the code it will be hard to figure out what's going wrong here. Right now it almost sounds as if you're saying you're using a while to loop a listen? The listen section will be executed anytime the script receives anything fitting the channel, etc of what you told it to listen to in the state_entry().

This is a basic sample of the code I'm thinking you'd need..

CODE
default
{
state_entry()
{
llListen(99,"",llGetOwner(),"");
}
listen(integer chan, string name, key id, string msg)
{
if (msg == "do it")
{
statethatdoesstuff();
}
else if (msg == "stop it")
{
statethatstopsthatstuff();
}
}
}
Baron Hauptmann
Just Designs / Scripter
Join date: 29 Oct 2005
Posts: 358
08-29-2006 06:10
From your description, without seeing the code, I can only guess at what you are doing. But if I understand you right, I think that you misunderstand how the listen event works.

Basically, any time something is said which matches the criteria from the llListen function call, the listen() event is started. And it continues until the functions in that event are completed, then it handles the next listen event that it receives. So if it hears something, then gets put in a loop, it will never act on something else.

Instead of using a "while" loop, you should either set a global variable or call a timer or something like that to handle what you want to remain under a certain condition until a new listen changes it. The only reason you would want to use a "while" loop in a listen is if something IN THE WHILE LOOP will cause it to exit the loop, like incrementing a variable. Nothing from outside the loop, like a listen, a touch, or a link message, will be handled until the loop is FINISHED. So saying something new will NEVER cause the while loop in a listen event to quit.

If you have more questions about it, please post any relative segment of your code . . . perhaps someone can help you figure out a better way of handling things.

Baron H.
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
08-29-2006 06:20
From: Selador Cellardoor
Does anybody have any idea how I can set up this loop so that it continues to listen within the loop?

Basically, you can't do it without tailoring flow of your application around multiple events.

Specifically, once an event is triggered your code is expected to deal fully with it (by leaving the event scope through return call or by reaching end of relevant code block) ... and only then it's supplied with any possible event(s) which happened meanwhile or later.

So if you have something like (pseudocode)

listen( message ) {

while( message == "do it" ) { // do it; }
}

... it'll keep looping forever if you rely on another listen() even being triggered meanwhile, with a message which would cause to abandon the loop. Because receiving another message never happens.

you could probably deal with it through something like (more pseudocode):
CODE

default {

state_entry() { llListen( ... ); }

listen( string Message ) {

if( Message == "do it" ) { llSetTimerEvent( 1.0 ); }
else if( Message == "stop" ) { llSetTimerEvent( 0.0 ); }
}

timer() {
// do the single instance of content of your while( condition == TRUE ) block here
}

it's far from ideal obviously and without more detail of program in question hard to say if of any use... but you can hopefully develop it into something more useful, in worst case ^^;;
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-29-2006 09:05
From: Tiarnalalon Sismondi
Without seeing the code it will be hard to figure out what's going wrong here. Right now it almost sounds as if you're saying you're using a while to loop a listen? The listen section will be executed anytime the script receives anything fitting the channel, etc of what you told it to listen to in the state_entry().

This is a basic sample of the code I'm thinking you'd need..

CODE
default
{
state_entry()
{
llListen(99,"",llGetOwner(),"");
}
listen(integer chan, string name, key id, string msg)
{
if (msg == "do it")
{
statethatdoesstuff();
}
else if (msg == "stop it")
{
statethatstopsthatstuff();
}
}
}


Unfortunately, what happens with this is that having executed the if (do it) statement once, it then seems to go quiescent, waiting for another listen. What it should do is continue to loop around the code inside what is an if statement in your example.
_____________________
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-29-2006 09:07
From: Joannah Cramer
Basically, you can't do it without tailoring flow of your application around multiple events.

Specifically, once an event is triggered your code is expected to deal fully with it (by leaving the event scope through return call or by reaching end of relevant code block) ... and only then it's supplied with any possible event(s) which happened meanwhile or later.

So if you have something like (pseudocode)

listen( message ) {

while( message == "do it" ) { // do it; }
}

... it'll keep looping forever if you rely on another listen() even being triggered meanwhile, with a message which would cause to abandon the loop. Because receiving another message never happens.

you could probably deal with it through something like (more pseudocode):
CODE

default {

state_entry() { llListen( ... ); }

listen( string Message ) {

if( Message == "do it" ) { llSetTimerEvent( 1.0 ); }
else if( Message == "stop" ) { llSetTimerEvent( 0.0 ); }
}

timer() {
// do the single instance of content of your while( condition == TRUE ) block here
}

it's far from ideal obviously and without more detail of program in question hard to say if of any use... but you can hopefully develop it into something more useful, in worst case ^^;;


Ok, thanks. I will go away and experiment with this. :)
_____________________
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-29-2006 14:37
From: Joannah Cramer
Basically, you can't do it without tailoring flow of your application around multiple events.

Specifically, once an event is triggered your code is expected to deal fully with it (by leaving the event scope through return call or by reaching end of relevant code block) ... and only then it's supplied with any possible event(s) which happened meanwhile or later.

So if you have something like (pseudocode)

listen( message ) {

while( message == "do it" ) { // do it; }
}

... it'll keep looping forever if you rely on another listen() even being triggered meanwhile, with a message which would cause to abandon the loop. Because receiving another message never happens.

you could probably deal with it through something like (more pseudocode):
CODE

default {

state_entry() { llListen( ... ); }

listen( string Message ) {

if( Message == "do it" ) { llSetTimerEvent( 1.0 ); }
else if( Message == "stop" ) { llSetTimerEvent( 0.0 ); }
}

timer() {
// do the single instance of content of your while( condition == TRUE ) block here
}

it's far from ideal obviously and without more detail of program in question hard to say if of any use... but you can hopefully develop it into something more useful, in worst case ^^;;


Ok, I have tried this, and it *almost* works. :) The difficulty I have is that each time through the 'do it' sequence is controlled by random events, so the time taken for the sequence can be highly variable. I just don't know how to get round the problem.
_____________________
Adriana Caligari
Registered User
Join date: 21 Apr 2005
Posts: 458
08-29-2006 14:55
how about this

CODE

integer DOIT = FALSE;

default
{
state_entry()
{
state ready;
}
}
state ready
{
state_entry()
{
listen( 0,"","","" ) ;
if ( DOIT )
{
// do stuff
}
else
{
// do other stuff
}
state ready;
}
listen( integer ch, string nm, key id, string mess )
{
if ( mess == "do it" )
{
DOIT = TRUE;
}
else
{
DOIT = FALSE;
}
}
}


Or did i entirely miss the point ?
_____________________
Maker of quality Gadgets
Caligari Designs Store
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
08-30-2006 04:26
From: Selador Cellardoor
Ok, I have tried this, and it *almost* works. :) The difficulty I have is that each time through the 'do it' sequence is controlled by random events, so the time taken for the sequence can be highly variable. I just don't know how to get round the problem.

Will need some underhanded tweaking, then -.^
CODE

default {

state_entry() { llListen(...); }

listen( string Message ) {

if( Message == "do it" ) { llSetTimerEvent( 0.1 ); }
else if( Message == "stop" ) { llSetTimerEvent( 0.0 ); }
}

timer() {

llSetTimerEvent( 0.0 );
// do the single instance of content of your while( condition == TRUE ) block here
llSetTimerEvent( 0.1 );
}
}

... this is entirely untested and i dunno if timer frequency in timer() event will be fast enough to prevent multiple instances from triggering... but the gist is, relevant message fires the timer() (effectively) once, the timer is then stopped for period of time needed to carry out the loop, then resumed with delay long enough for any possible listen() that occured meanwhile to get through... the actual times may need some adjustments, there. o.O;

edit: i think Adriana's way should work too, though it seems the "state ready" should be "state default" in the last line of state_entry() of ready state..? ^^;;
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-30-2006 13:27
From: Adriana Caligari
how about this

CODE

integer DOIT = FALSE;

default
{
state_entry()
{
state ready;
}
}
state ready
{
state_entry()
{
listen( 0,"","","" ) ;
if ( DOIT )
{
// do stuff
}
else
{
// do other stuff
}
state ready;
}
listen( integer ch, string nm, key id, string mess )
{
if ( mess == "do it" )
{
DOIT = TRUE;
}
else
{
DOIT = FALSE;
}
}
}




Ok - what I have found with this (having made the change that Joannah suggested - changing the state ready to state default at the end of the main loop) is that if I keep the state default at the end of the main loop, as it is here, the script loops repeatedly round the main loop and never hears the change to the message. If I put the state default at the end of the listen, the script runs correctly once, with the message set at DOIT=FALSE, and if I then input the 'do it' message, it runs correctly through the main loop - but only once, and then waits for input again. What it should do it to run repeatedly through the main loop until it hears the change of message.
_____________________
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
08-30-2006 13:29
From: Joannah Cramer


edit: i think Adriana's way should work too, though it seems the "state ready" should be "state default" in the last line of state_entry() of ready state..? ^^;;


Ok - I am trying to get Adriana's method to work first, because I don't want to completely recast the script again, but if I can't get it to work I will try the method you suggested. Many thanks. :)
_____________________
Adriana Caligari
Registered User
Join date: 21 Apr 2005
Posts: 458
08-30-2006 14:09
It looks like Joannah's solution is the best - just modified mine to that shown below and it works in the way I think you wanted.

It would appear in my original solution that the llListen setup stuff is queued - and hence getting erased before it is set up by the state change.

You live and learn.

CODE

integer DOIT = FALSE;

default
{
state_entry()
{
llListen( 0,"","","" );
llSetTimerEvent( 0.1 );
}
listen( integer ch, string nm, key id, string mess )
{
if ( mess == "do it" )
{
DOIT = TRUE;
}
else
{
DOIT = FALSE;
}
}
timer()
{
llSetTimerEvent( 0 );
if ( DOIT )
{
// do something
}
else
{
// dont do something
}
llSetTimerEvent( 0.1 );
}
}
_____________________
Maker of quality Gadgets
Caligari Designs Store
Selador Cellardoor
Registered User
Join date: 16 Nov 2003
Posts: 3,082
09-01-2006 16:41
It works!

Thanks very much Adriana and Johanna. I would never have figured it out on my own. :)
_____________________