It’s often useful to have somewhere to store settings for an SL gadget, and a common way of doing this is in a notecard kept in the contents of the main prim.

The script listed below shows a way of reading the contents of a notecard (there is, unfortunately, no way of writing a notecard – you have to do this manually).

You can jump straight to the listing if you want, but I thought this would be a suitable opportunity to address a problem with LSL scripting (or at least one of the problems), namely…

Why Does It Have To Be So Convoluted?

Let’s take the subject of this blog as an example. To read a notecard you have to find the notecard, send a message to the server, set up an event to wait for a reply from the server, and then repeat this for every line that you want to read.

Why can’t you just do something like this?

    line = llGetNotecardLine("notecard", linenumber);

As it happens, there is a very good reason for this, and it isn’t just that the developers at Linden Lab are determined to make life difficult for you!

To understand, imagine that you could do something like the above line. What would happen? Remember that everything in SecondLife, including your notecard, is stored on the server. To get the line from the notecard, SecondLife has to go to the server, find the notecard, extract the requested line, and send it back. If the server is under heavy load, this could take some time (familiar, yes?).

What happens to your script during all this? Well, it is still waiting for the response to come back from the server. In other words, as soon as it hits this line, the script will stop and wait…and wait…and…

You get the picture. Compare this with the actual system. Your script sends a data request to the server, and then carries on. When the server returns the data, the data event is triggered in your script, which meanwhile has been happily going on with any other stuff that it needed to do.

This kind of pattern – send a request, return the data via an event – is very common to multi-tasking environments, and SecondLife is no exception. Without this seemingly convoluted system, your scripts would be much less responsive, and far more susceptible to the effects of lag.

The Script

// Variables
key qryNotecard;
string notecard_name = "Settings";
integer notecard_line = 0;// Routines

init()
{
    // Make sure we actually have a notecard matching
    // the name. If we do, process it.
    if (llGetInventoryType(notecard_name) == INVENTORY_NOTECARD)
    {
        readNotecard();
        return;
    }
}

readNotecard()
{
    llOwnerSay("Reading settings. Please wait.");
    // Send a request for the first line (line 0). Any subsequent
    // lines will be requested when the dataserver event is
    // triggered.
    notecard_line = 0;
    qryNotecard = llGetNotecardLine(notecard_name, notecard_line) ;
}

checkLine(string line)
{
    // Ignore empty lines and comment lines.
    if(("" != line) && (llGetSubString(line, 0, 1) != "//"))
    {
        // Extract the line details. Assume that valid
        // settings are in the format 'name=value', like
        // a Windows .INI file. Ignore any which are not.
        list Details = llParseString2List(line, ["="], []);
        string keyname = llList2String(Details, 0);
        string contents = llList2String(Details, 1);
        // If we have a valid line, process the contents.
        if (("" != keyname) && ("" != contents))
        {
            // For this demo, we just display the details.
            llOwnerSay(keyname);
            llOwnerSay(contents);
        }
    }
    // Get the next line.
    notecard_line = notecard_line + 1;
    qryNotecard = llGetNotecardLine(notecard_name, notecard_line) ;
}

// Events
default
{
    state_entry()
    {
        init();
    }
    on_rez( integer r )
    {
        init();
    }
    dataserver(key query, string data)
    {
        // Check whether this is a response to our notecard
        // query.
        if (query == qryNotecard)
        {
            if (data != EOF)
            {
                // Handle the returned notecard line.
                checkLine(data) ;
                return;
            }
            else
            {
                llOwnerSay("Finished reading settings.");
            }
        }
    }
}