Jump to content

Understanding dataserver event


mySky Phenomena
 Share

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

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

Recommended Posts

Hello,

I have searched for an answer to this question, but either don't understand the answer or am not finding what I'm looking for. I think the problem lies in my understanding of the way dataserver events (or events in general) work. Please let me know if my explanation is confusing.

(1) Is this how the dataserver event works?:

When I request a notecard line using llGetNotecardLine("My Notecard", 2), the dataserver event is triggered. Inside the dataserver block I can access whatever string is returned from line 2 in "My Notecard" and manipulate it (or whatever I'm trying to do).

(2) I have a script that needs to read some values in from specific lines in a notecard. For example, let's say I need to store the integers on lines 2 and 4 from "My Notecard" into two different variables called A and B. Is this true?:

Every time I call llGetNotecardLine(), the script is going to go into the same dataserver event, so inside the dataserver event block I have to have some way of figuring out which line I asked for to store it in the correct variable? Like this:

integer A;
integer B;
key queryA;
key queryB;

default
{
    
    state_entry()
    {
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
            return;
        }
        queryA = llGetNotecardLine("My Notecard", 2);
	queryB = llGetNotecardLine("My Notecard", 4);
    }

    dataserver(key query_id, string data)
    {
        if (query_id == queryA)
        {
            if (data == EOF)
                llSay(0,"Done reading notecard, read " + (string) notecardLine + " notecard lines.");
            else
            {
                A = (integer)data;
            }
        }
	if (query_id == queryB)
        {
            if (data == EOF)
                llSay(0,"Done reading notecard, read " + (string) notecardLine + " notecard lines.");
            else
            {
                B = (integer)data;
            }
        }
    }
}

Just FYI, I stole some of this code from an example I saw and added the parts I needed.

 

Thanks!

 

Link to comment
Share on other sites

Not quite.  The dataserver event is just like any other event.  It opens when it is called by a specific triggering message, in this case from your llGetNotecardLine statement.  If you want to call it a second time, you need another triggering message, as you have, but the logical place to send that message is from within the dataserver event itself, after you have executed the first action.

integer A;
integer B;
key queryA;
key queryB;

default
{
    
    state_entry()
    {
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
        }
        else
        {
            queryA = llGetNotecardLine("My Notecard", 2);
        }
    }

    dataserver(key query_id, string data)
    {
        if (query_id == queryA)  // The result of your call from state_entry
        {
            A = (integer)data;
            queryB = llGetNotecardLine("My Notecard", 4);  // NOW you ask it to read line 4
        }
	if (query_id == queryB)   // The result of your call from the first time through the dataserver event
        {
            B = (integer)data;
        }
    }
}

Note that you never need to ask  if (data == EOF) in your case because you are only reading a single,specific line each time.  You never have to test whether you have reached the last line.

Edited by Rolig Loon
Link to comment
Share on other sites

Ohhhhhh ok, that makes sense.

I actually have a bunch of info I need to grab from that notecard. Is there a more elegant way of doing that, or is the only way to setup the event the way you've done with queryA and queryB? Like if I had to fill A - F, would I need to just keep doing what you've done above, just for each variable?

Link to comment
Share on other sites

In that case, you are back to a standard "read everything until you get to the end" version:

integer iLine;
key MyQuery;
list lAllData;

default
{
    
    state_entry()
    {
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
        }
        else
        {
            MyQuery = llGetNotecardLine("My Notecard", iLine = 0);
        }
    }

    dataserver(key query_id, string data)
    {
        if (query_id == MyQuery)  // The result of your call from state_entry
        {
            if (data != EOF)
            {
                lAllData += [(integer)data];
                if (iLine < 5)  // If you haven't reached the sixth line, where F is ....
                {
                    MyQuery = llGetNotecardLine("My Notecard", ++iLine);  // NOW you ask it to read the next line
                }
            }              
        }	
    }
}

Once it's gone around that loop a few times, you'll have lAllData full of your variables, which you can unpack as A, B, C, D, E, F as you need them.

Of course, the easier way would be to simply put A, B, C, D, E, and F on a single line in your notecard and read the lot as a comma delimited string in one shot.  Then unpack it.  But I understand that this is really about learning how to read a notecard.

  • Thanks 1
Link to comment
Share on other sites

What's unspoken in all of this is that each event in a LSL script is a self-contained entity. You can't hop in and out of an event at will. Once you enter, script execution stays in the event until it reaches a logical exit. When execution passes to another event, it enters the new event at its top, not where you happened to be the last time you were there.  In your original example, you might get away with stacking up two or more calls to llGetNotecardLine in the state_entry event, but there's no guarantee that they would be executed in a predictable order (or properly). It's much safer to just execute one llGetNotecardLine call in state_entry and then make successive ones in the dataserver event itself, forcing execution to go around and around there until it is finished.

Link to comment
Share on other sites

What if I need to combine those two methods? Would this work?:

integer iLine;
key MyQuery;
key queryA;
key queryB;
list lAllData;
integer A;
integer B;
integer someNumber; //Whatever line on which the stuff I need ends

default
{
    
    state_entry()
    {
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
        }
        else
        {
            queryA = llGetNotecardLine("My Notecard", 2);
        }
    }

    dataserver(key query_id, string data)
    {
        if(query_id == queryA)
        {
        	A = (integer)data;
            queryB = llGetNotecardLine("My Notecard", 4);
        }
        else if(query_id == queryB)
        {
        	B = (integer)data;
            MyQuery = llGetNotecardLine("My Notecard", iLine = 0);
        }
        else if (query_id == MyQuery)  
        {
            if (data != EOF)
            {
                lAllData += [(integer)data];
                if (iLine < someNumber)  
                {
                    MyQuery = llGetNotecardLine("My Notecard", ++iLine);
                }
            }              
        }	
    }
}

 

Link to comment
Share on other sites

You can certainly mess with the logic to get your script to read as many cards and lines as you like, and in any order that you wish.  The way to find out whether a particular script works, of course, is to try it out and see.  The place where your logic is likely to get tricky is in counting lines. In what you are suggesting, for example, you will end up with data loading in A and in B, and the same data also loaded in the list lAllData (which will end up with A, B, C, D, E, and F).  If that's what you  are hoping for, that's great.

Incidentally, when I posted my version above, I included the test

if (iLine < 5)  // If you haven't reached the sixth line, where F is ....

which is not truly necessary, since the test for EOF will already take care of it handily if you only have six lines total on the card.  My thought was that you might be intending to do something quite like what you are suggesting now. If so, then the next thing to do would be to folllow that if (iLine < 5) block with another one that says

else

{

    //Read any remaining lines after the one with F in it, and do something entirely different with them

}

There is no single "perfect" way to write a script. If other scripters were chiming in here, they would each have their own ideas about what to do. In the end, the test of success is whether the method that you have chosen for yourself does what you wanted it to. The way to find out is to experiment until it does.

  • Like 2
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1663 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...