state event help needed
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-05-2006 23:08
Hi coders Having problem to understand event handling in LSL-scripting. Sometimes when you just need a value, you have to wait for an event to return it. Waiting for an event means I'm jumping out of the spot in the code I'm currently in. Maybe the code below will explain what I mean. Must be an easier way of accomplishing this, or? Please enlighten me! P.s. Maybe it's possible to get creator name some other way but this is just an example of catching an event-state-value. string gCreatorName; default { state_entry() { llOwnerSay("state default entry"); if (gCreatorName == "") { state getcreatorname; } llOwnerSay("I was created by " + gCreatorName); llOwnerSay("Creator key is " + (string)llGetCreator()); } } state getcreatorname { state_entry() { llOwnerSay("state creator entry"); llRequestAgentData(llGetCreator(), DATA_NAME); } dataserver(key queryid, string data) { gCreatorName = data; state default; } }
Gives the following result: [22:53] Object: state default entry [22:53] Object: state creator entry [22:53] Object: state default entry [22:53] Object: I was created by Woopsy Dazy [22:53] Object: Creator key is ************** What puzzles me is that I have to restart default state. Can't I just "exit state" and continue where I was in default state?
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
12-05-2006 23:19
no, its almost like 2 different scripts in one file, that happen to share globals
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
12-05-2006 23:22
default { state_entry() { key creator = llGetCreator(); llOwnerSay("I was created by " + llKey2Name(creator)); llOwnerSay("Creator key is " + (string)creator); } }
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-05-2006 23:25
From: Osgeld Barmy no, its almost like 2 different scripts in one file, that happen to share globals Just to make sure. Your "no" means my code is basically the correct way of doing it?
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
12-05-2006 23:27
depends on what your doing, if you want totally independant states of operation yes, ie startup, running, and shutdown, in this case no, it seems like more of a headache than its really worth
see above, i changed it
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-05-2006 23:32
From: Osgeld Barmy default { state_entry() { llOwnerSay("I was created by " + llKey2Name(llGetCreator()); llOwnerSay("Creator key is " + (string)llGetCreator()); } }
Ok, that's a way but if I wanna do like this: touch_start() { llOwnerSay("First thing is: " + llsomecommand()); llOwnerSay("Second thing is:" + llsomethingthatreturnsvalueinastate()); llOwnerSay("Third thing is: " + llsomecommand()); }
I want to make sure 2nd statement is ready before running the 3rd. [EDIT] Ops you changed your code so I'm quoting wrong. Btw, llkey2name doesnt work when another avatar runs the code
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
12-05-2006 23:39
lsl is designed to do things in order, if it never finishes 1, it wont goto 2 ect
doesnt always mean you will get the intended result, but unless you dump ALOT of data into the script @ once its really stable about doing things in exact order
if you have 3 things ie
owner say "stuff" dataserver stuff(); owner say "stuff"
it will output "stuff" "stuff" before moving onto the next event (in this case dataserver)
so if you expect "stuff" data "stuff" you have to weave the 2 toghether like
touch start
llsay something dataserver call
dataserver event
deal with data llsay something else
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-06-2006 01:22
Thx! So to make sure things run in order (statements have dependencies) I will have to use states? I can't understand why some values are retrieved by an event and some not. Why can't I just do a function that handles the event and give me a value back? Is states the only way? So if I wanna pick dataserver (name, born, online, payment status) I would have to code 4 states!? Something is wrong here. What is it that I don't understand? Seems like every answer creates 5 new questions, sorry 
|
|
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
|
12-06-2006 03:19
From: Woopsy Dazy Thx! So to make sure things run in order (statements have dependencies) I will have to use states? I can't understand why some values are retrieved by an event and some not. Why can't I just do a function that handles the event and give me a value back? Is states the only way? Its the nature of distributed systems Think of it this way, the script/prim does need to know who owns it, but has absolutley no need to know about its their online status, birthdate or any other such information for normal running. So some data is held locally by the prim/script and can obviously be obtained locally using function calls such as llGetCreator, llGetOwner.. Other items, such as details of the owners, are held on the server and you have to access them by posting a dataserver request. From: Woopsy Dazy So if I wanna pick dataserver (name, born, online, payment status) I would have to code 4 states!? Something is wrong here. What is it that I don't understand? Seems like every answer creates 5 new questions, sorry  Not necessarily, you can handle all dataserver events in one state by firing off the new one when you receive the answer to the previous, or even concurrently if you know what you are doing.
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-06-2006 05:24
Thx Newgate, your explanations makes sense. I tried to compile some code to understand in what way I should retrieve all 5 dataserver-events and here's what I came up with. Haven't compiled and tested live cause I have no access atm. Ths code is supposed to return values of the five datatypes into a list named gCreatorList. Looks messy and I have no clue if it works: list gDataList = [DATA_ONLINE, DATA_NAME, DATA_BORN, DATA_RATING, DATA_PAYINFO]; integer gListLength = 0; integer gDataCount = 0; list gCreatorList = []; key gCreatorKey; default { state_entry() { gCreatorKey = llGetCreator(); glistlength = llGetListLength(gDataList); llRequestAgentData(gCreatorKey, llList2String(gDataList, gDataCount)); } dataserver(key queryid, string data) { gCreatorList = (gCreatorList=[]) + gCreatorList + data; gDataCount += 1; if (gDataCount < gListLength) { llRequestAgentData(gCreatorKey, llList2String(gDataList, gDataCount)); } } }
God I miss my old Visual Basic. Arrays, functions, easier syntax. Well, well, I'll get used to this, but it will take some time. 
|
|
Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
|
12-06-2006 05:25
What do you think about this (untested): string gCreatorName; default { state_entry() { gCreatorName = ""; integer wait = 0; integer timeout = whatYouWant; llRequestAgentData(llGetCreator(), DATA_NAME); while ((gCreatorName == "") && (wait < timeout)) { llSleep(0.1); wait++; } // Got it or failed }
dataserver(key queryid, string data) { gCreatorName = data; } }
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-06-2006 05:47
From: Jeff Kelley What do you think about this (untested): string gCreatorName; default { state_entry() { gCreatorName = ""; integer wait = 0; integer timeout = whatYouWant; llRequestAgentData(llGetCreator(), DATA_NAME); while ((gCreatorName == "") && (wait < timeout)) { llSleep(0.1); wait++; } // Got it or failed } dataserver(key queryid, string data) { gCreatorName = data; } }
Nice ty! If that works it's great  Think I tried something similar some time ago but then the dataserver-event never triggered, because the script was busy with the loop. I guess your llSleep is necessary for that reason?
|
|
Nynthan Folsom
Registered User
Join date: 29 Aug 2006
Posts: 70
|
12-06-2006 05:56
From: lslwiki Dataserver answers aren't necessarily coming in the order they were requested in. So, if there are multiple pending requests, always use the queryid key to determine which answer is being received. If only one request is processed at a time, and only one script is in the prim that uses the dataserver event, this problem doesn't arise. Therefore: list requestCodes; list requests; list replies; integer replyCount;
default { state_entry() { // A list of data items requestCodes = [DATA_PAYINFO, DATA_RATING, DATA_BORN, DATA_NAME, DATA_ONLINE]; // The owner of this script key ownerKey = llGetOwner(); // Counter integer i; i = llGetListLength(requestCodes); // Initialize the reply count so that we know how many replies have been received replyCount = 0; // Assemble 2 lists while(i--) { // This holds the request Ids requests += [llRequestAgentData(ownerKey, llList2Integer(requestCodes, i)]; // This holds placeholders for the replies replies += ""; } // Free the list of data items requestCodes = []; } dataserver(key reqId, string data) { integer i; // To store the index of the request key // Look for the reqId in the list, if found it should return a positive index if((i = llListFindList(requests, reqId)) != -1) { // Replace the corresponding item in the replies list llListReplaceList(replies, [data], i, i); // Inc the count of replies replyCount++; } // If we've received the same number of replies as requests, we should be done if(replyCount == llGetListLength(requests)) { // Free the requests list requests = []; // Jump to the next state state nextState; } } }
state nextState { state_entry() { // All data requested has now been returned } }
|
|
Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
|
12-06-2006 06:10
From: Woopsy Dazy I guess your llSleep is necessary for that reason? llSleep is here to make synchronous an asynchronous data request. That's you were asking for : having instructions in a sequential order, which makes the code much more readable. Since we want wait, it makes sense to sleep and release processor resource. If it will work or not depends on the way events are scheduled. We need to know if they are really asynchronous, like in real-time systems, or queued until a state is completed.
|
|
Woopsy Dazy
Registered User
Join date: 12 Nov 2006
Posts: 173
|
12-06-2006 06:46
Thanks A LOT everyone! Things have become a lot more clearer to me. And great to have some code to play around with. Awesome commented example there Nythan! Can't wait to try this out. My brain cell is gonna overload 
|
|
Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
|
12-06-2006 08:22
From: Jeff Kelley If it will work or not depends on the way events are scheduled. We need to know if they are really asynchronous, like in real-time systems, or queued until a state is completed. Unfotunately, LSL is no real-time language. An event handler can't execute while another thread is running. That means that we'll never get the dataverver handler executed until we've done with the current handler.
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
12-06-2006 11:19
yep lsl must finish everything in an event before moving on to the next event
|
|
Jeff Kelley
Registered User
Join date: 8 Nov 2006
Posts: 223
|
12-06-2006 14:46
From: Osgeld Barmy yep lsl must finish everything in an event before moving on to the next event So it should not be called an "event" but a "sub-state".
|