Jump to content

Waiting for event handlers?


Dourden Blindside
 Share

You are about to reply to a thread that has been inactive for 961 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hello all,

In the below code I'm requesting Display Name.

Unfortunately i really can't figure out how to have displayName1 show a value. I understand that llOwnerSay("DisplayName1") happens before the handler is consumed, but how can i make my code wait until all the event calls are finished ?

I tried a do_while but that just broke my code into an infinite loop.

 

string displayName;
default
{
   state_entry()
   {
       llRequestDisplayName(llGetOwner());
       llOwnerSay("DisplayName1 "+ displayName);
   }
 
   dataserver(key queryid, string data) 
   {
     displayName = data;
     llOwnerSay("DisplayName2" + displayName );
   }
}

 

Thank you,

David

Link to comment
Share on other sites

Events are processed in their entirety when they are triggered, so in state_entry the llOwnerSay call is processed immediately after the display name is requested, without waiting for the result of the request.

The result of the display name request is placed in the script's event queue, and is processed when all the other events there, and the current event, have been dealt with. The requested data is only available in the dataserver event until it's saved to a global variable, when it becomes available to any subsequent events that might be triggered.

The llRequest* functions are, effectively, call-back functions. You make your request, and sometime in the future, once the relevant databases have been queried, the result is posted back to you, appearing in the dataserver event.

Link to comment
Share on other sites

14 minutes ago, KT Kingsley said:

The result of the display name request is placed in the script's event queue, and is processed when all the other events there, and the current event, have been dealt with. The requested data is only available in the dataserver event until it's saved to a global variable, when it becomes available to any subsequent events that might be triggered.

True, but how can i wait until the event is handled ? I can't continue my code without that data.

Link to comment
Share on other sites

http://wiki.secondlife.com/wiki/LlRequestDisplayName
Example:

key owner_key;
key owner_name_query;
string owner_display_name;
 
default
{
    state_entry()
    {
        owner_key = llGetOwner();
        owner_name_query = llRequestDisplayName(owner_key);
    }
    dataserver(key queryid, string data)
    {
        if ( owner_name_query == queryid )
        {
            owner_display_name = data;
            llSay(0, "The display name of the owner of this script : " + owner_display_name );
        }
    }
}

 

Link to comment
Share on other sites

Continue your code in the dataserver event once you've got your data. You wait for your data by waiting for the dataserver event. It'll fire automatically once the data is available.

string displayName;
default
{
   state_entry()
   {
       llRequestDisplayName(llGetOwner());
   }
 
   dataserver(key queryid, string data) 
   {
     displayName = data;
     llOwnerSay("DisplayName1 "+ displayName); 
     llOwnerSay("DisplayName2" + displayName );
   }
}

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Your best bet here is to remove the line in state_entry and then let the dataserver event announce the name.

 

If other parts of your script need to use displayName then all I can suggest is you set it to "" before the request for data and then elsewher in the cod check for an empty string and defeer action until it is no longer empty.

The dataserver can be as quick as a flash when doing things like reading notecards where the data is there in the region, but if the avatar in question is elsewhere it might take much longer for a return.

Edited by Profaitchikenz Haiku
  • Thanks 1
Link to comment
Share on other sites

A general thing to consider is that you need to structure your code to accommodate the fact that events, like KT explains, are going to be processed start-to-finish before any other event will get a chance to run. With that in mind, the notion of creating a busy while-loop won't go well because the event in which the loop is running will never release execution, and thus never allow any other events (like the dataserver) to begin.

Most of the time, scripts are going to be sitting idle, waiting for an event to trigger. So part of the process in LSL scripting is choosing the right events for the task - as well as where to place pertinent code.

If you need to wait on information from an asynchronous event (like dataserver) then one way to do so would be by placing the remainder of your code in the dataserver event. Alternatively, if you really want to do something like a busy loop, then using a timer event to periodically check the status of global variables (which could be updated by other events) would be a safer approach.

 

Edited by Fenix Eldritch
typo
  • Thanks 1
Link to comment
Share on other sites

Dataserver functions like llRequestDisplayName are a two-step process.

  1.  llRequestDisplayName is called, it fires off a request to the LL servers to get the display name for the resident ID you provided. It returns a UUID to identify the request.
  2. dataserver event is called, the ID parameter is the ID that was returned from the llRequestDisplayName function (This is so you can identify which request it is, in case you sent multiple requests), and the data parameter is obviously the data that you requested.

Keep in mind that scripts are "single threaded". That means it can only do one thing at a time.

 

It is possible to get dataserver events linearly, but you need two scripts and it's a bit more complicated.

  1. Script 1 sends a link message to Script 2, requesting that it make a dataserver request. Then sets the object description to "WAIT"
  2. Script 2 makes the request and once it has a result, it sets the object description to the result.
  3. Script 1 runs a loop waiting for the description to change from "WAIT".

This should only be used when absolutely necessary as it isn't very efficient. If you do use this sort of method, ensure that you have time limits on the loop to avoid your script freezing due to a failed request (Most fail silently, so the dataserver event is never raised).

Edited by Ariu Arai
  • Thanks 1
Link to comment
Share on other sites

On 10/27/2021 at 3:41 AM, Dourden Blindside said:

how can i make my code wait until all the event calls are finished ?

You can't. And you don't want to. And if you ever did, the event you're "waiting" for could no-longer happen! Don't "wait" for things in LSL. LSL is about "callbacks". "Gimme a call when you've got that done; I won't be waiting; I'll be busy doing other things."

On 10/27/2021 at 3:41 AM, Dourden Blindside said:

I tried a do_while but that just broke my code into an infinite loop.

Exactly! That's why "waiting" doesn't work.

(Well, you can wait in "timer", but then "timer" is stuck with whatever period you set for that wait, which may not be what other things need "timer" for. Best to save "timer" for things that actually do need to repeat at a fixed period indefinitely, such as a security orb scanning a house for intruders once per 2 seconds.)

Instead of "waiting", when I need events A, B, C, D to happen in that order, I put the code that triggers B in the event-handler for A, the code that triggers C in the event handler for B, and the code that triggers D in the event handler for C. That not only forces the events to happen in order A->B->C->D, but it minimizes delay time between them.

For example, say I want touching an object to launch a dialog box, but the dialog box needs data from a notecard. Then instead of having touch_end launch a dialog box directly, I'll do lin_num=0; queryid=llGetNotecardLine("card", lin_num); to get the first line of the notecard and trigger "dataserver". Then in dataserver, if we're not yet at end of file, I keep getting more notecard lines and appending them to a global list; if (EOF != next_line) {buttons += [next_line]; ++lin_num; queryid=llGetNotecardLine("card", lin_num);}  Then when we are at end-of-file, I launch the dialog box: if (EOF==next_line){llListen(-743, "", "", ""); llDialogBox(-743, "Styles", buttons);  Then when the user presses a button, that triggers a "listen" event which allows processing the choice the user made. In this case, events A->B->C->D are "someone touches object", "read data from notecard", "launch dialog box", and "press button". Event-handler-A triggers event B, event-handler-B triggers event C, and event C launches handler for event D :  touch_end -> data_server -> llDialogBox -> listen.

Basically, after the first few microseconds after an LSL script first starts, it spend all the rest of its time doing nothing and just waiting for events to occur. That's because you're sharing CPU time with every other user in that sim, so the language tries very hard to disallow you from hogging time. So after you've been doing LSL for a while, you'll get used to doing everything in event handlers and arranging events that need to happen in-order by having the event handlers trigger each other in the right order.

Edited by LoneWolfiNTj
fixed typos
Link to comment
Share on other sites

  • 2 weeks later...

Someone talked about using multiple scripts but another way would be to use states.   I find that states can be a good tool for initialization routines if they are critical for subsequent event handling down the line or any time I need to "pause" the main script and do some other tasks and don't want to offload to as separate script. 

Something like this.  it will effectively pause the main script while so it can wait for the right conditions.  You can use state_exit to set some global variable so if if called from deep in the script , state_entry and point to the right location to 'return' to.

 

string displayName = "UNSET";

default
{
	state_entry()
	{
		if (displayName == "UNSET")
		{
			state GDN;
		} else if (displayName = "Error Getting Name") {
			// do some stuff to handle that maybe recalling the state.
			;
		} else {
			llOwnerSay("owner display mame is " + displayName);
		}
	}
}

state GDN
{
	state_entry()
	{
		llSetTimerEvent(10.0)
		llRequestDisplayName(llGetOwnerKey());
	}
	
	dataserver( key queryid, string data)
	{
		displayName = data;
		state default;
	}
	
	timer()
	{
		displayName = "Error Getting Name";
		state default;
	}
	
	state_exit()
	{
		llSetTimerEvent(0.0);
	}
}

 

  • Like 1
Link to comment
Share on other sites

llOwnerSay("DisplayName1 "+ displayName) in state_entry wont give the display name because you haven't assigned a value to the displayName value yet. You can either assign a value with llGetDisplayName  before the ownersay message or wait for the dataserver event to trigger and return the data and then assign it and show it in an ownersay as you have. 

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 961 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...