Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

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.

CODE


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
CODE

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
CODE

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:

CODE

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:

CODE

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):

CODE


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):

CODE


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:
CODE
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".