Difference between revisions of "LlGetNotecardLine"

From Second Life Wiki
Jump to navigation Jump to search
m (Added link so server version changelog)
(24 intermediate revisions by 14 users not shown)
Line 1: Line 1:
{{LSL_Function/inventory|name|uuid=true|type=notecard}}{{LSL_Function
{{LSL_Function
|inject-2={{LSL_Function/negative_index|false|line}}{{LSL_Function/notecard|name|uuid=true}}
|func_id=217|func_sleep=0.1|func_energy=10.0
|func_id=217|func_sleep=0.1|func_energy=10.0
|sort=GetNotecardLine
|sort=GetNotecardLine
|func=llGetNotecardLine
|func=llGetNotecardLine
|return_type=key
|return_type=key
|return_subtype=handle
|p1_type=string|p1_name=name
|p1_type=string|p1_name=name
|p2_type=integer|p2_name=line|p2_desc=Line number of a notecard (the index starts at zero).
|p2_type=integer|p2_name=line|p2_desc=Line number in a notecard (the index starts at zero).
|func_desc=Requests the line '''line''' of the notecard '''name''' from the dataserver.
|func_desc=Requests the line {{LSLP|line}} of the notecard {{LSLP|name}} from the dataserver.
|return_text=that is the handle for a {{LSLG|dataserver}} event response.
|Return_text=for a [[dataserver]] event response.
|func_footnote=If '''line''' is past the end of the notecard {{LSLG|EOF}} is returned by the {{LSLG|dataserver}}.
|func_footnote=If {{LSLP|line}} is past the end of the notecard [[EOF]] is returned by the [[dataserver]].
|spec
|spec
|caveats=* If notecard contains embedded inventory items (such as textures and landmarks), EOF will be returned, regardless of the line requested.
|caveats=* If notecard contains embedded inventory items (such as textures and landmarks), [[EOF]] will be returned, regardless of the line requested.
*If the notecardline is longer then 255 characters/1024 Bytes it will be silently be cut down. Same like in llWhisper, llSay, llShout, and llRegionSay.
*If the requested line is longer than 1024 bytes the [[dataserver]] will return the first 1024 bytes of the line.
*If the notecard is empty, the dataserver will shout on the DEBUG_CHANNEL that the notecard does not exist. This is because until a notecard is saved for the first time, it does not exist as an asset only as an inventory placeholder ([[llGetInventoryKey]] will return [[NULL_KEY]]).
*The byte return for this function was increased from 255 bytes to 1024 bytes with server version [https://releasenotes.secondlife.com/simulator/2021-10-25.565008.html 2021-10-25.565008]
*The notecard read can be full perm, no-modify, or no-modify/no copy.
|constants
|constants
|examples=<pre>
|examples=
key kQuery;
<source lang="lsl2">
integer iLine = 0;
key notecardQueryId;
default {
string notecardName = "name of notecard as in object's contents";
   
    state_entry() {
        llSay(0, "Reading notecard...");
        kQuery = llGetNotecardLine("My Notecard", iLine);
    }


    dataserver(key query_id, string data) {
// script-wise, the first notecard line is line 0, the second line is line 1, etc.
integer notecardLine;


        if (query_id == kQuery) {
say(string inputString)
            // this is a line of our notecard
{
            if (data == EOF) {   
    llOwnerSay(inputString);
}


                llSay(0, "No more lines in notecard, read " + (string)iLine + " lines.");
default
 
{
            } else {
    state_entry()
 
    {
                // increment line count
        // Check the notecard exists, and has been saved
                llSay(0, "Line " + (string)iLine + ": " + data);
        if (llGetInventoryKey(notecardName) == NULL_KEY)
               
        {
                //request next line
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
                iLine++;
            return;
                kQuery = llGetNotecardLine("My Notecard", iLine);
        }
        // say("reading notecard named '" + notecardName + "'.");
        notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
    }


    dataserver(key query_id, string data)
    {
        if (query_id == notecardQueryId)
        {
            if (data == EOF)
                say("Done reading notecard, read " + (string) notecardLine + " notecard lines.");
            else
            {
                // bump line number for reporting purposes and in preparation for reading next line
                ++notecardLine;
                say( "Line: " + (string) notecardLine + " " + data);
                notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
             }
             }
         }
         }
     }
     }
}
}
</pre>
</source>
<pre>
|helpers=
<source lang="lsl2">
/////
/////
//  Generic Multi Notecard reader by Brangus Weir
//  Generic Multi Notecard reader by Brangus Weir
Line 59: Line 75:
list gThreeCard;  // All the lines from from the third card
list gThreeCard;  // All the lines from from the third card


string gsCardOneName = "One";  //Set thse to the name of the invetory iten.
string gsCardOneName = "One";  //Set these to the name of the invetory item.
string gsCardTwoName = "Two";
string gsCardTwoName = "Two";
string gsCardThreeName = "Three";
string gsCardThreeName = "Three";
Line 75: Line 91:
     if (_action == "") {
     if (_action == "") {
         loadNoteCard(gsCardOneName);
         loadNoteCard(gsCardOneName);
     } else if (_action = "finish") {
     } else if (_action == "finish") {
         // All cards have been read into the lists... now you can do any kind of string
         // All cards have been read into the lists... now you can do any kind of string
         // manipulations to get the data you need to set your script.
         // manipulations to get the data you need to set your script.
         // But here we will prove that the cards have been read with a loop
         // But here we will prove that the cards have been read with a loop


         integer end = llGetListLength(gOneCard);  //Always evaluate this once, don't do it
        g_lTempLines = []; // lets not forget to delete this global, or it will be dead weight.
 
         integer len = llGetListLength(gOneCard);  //Always evaluate this once, don't do it
                                                   //INSIDE the for loop like noob programers will.
                                                   //INSIDE the for loop like noob programers will.
                                                   //Reduce lag, THINK ABOUT MACHINE CYCLES!
                                                   //Reduce lag, THINK ABOUT MACHINE CYCLES!
         integer i;
         integer i = 0;
         for (i = 0; i< end; i++)
         for (; i< len; ++i)
             llSay(0, llList2String(gOneCard,i));
             llSay(0, llList2String(gOneCard,i));
         end = llGetListLength(gTwoCard);
 
         for (i = 0; i< end; i++)
         len = llGetListLength(gTwoCard);
         for (i = 0; i< len; ++i)
             llSay(0, llList2String(gTwoCard,i));
             llSay(0, llList2String(gTwoCard,i));
         end = llGetListLength(gThreeCard);
 
         for (i = 0; i< end; i++)
         len = llGetListLength(gThreeCard);
         for (i = 0; i< len; ++i)
             llSay(0, llList2String(gThreeCard,i));
             llSay(0, llList2String(gThreeCard,i));
     }                 
     }                 
Line 115: Line 135:
     } else if (_notecard == gsCardThreeName) {
     } else if (_notecard == gsCardThreeName) {
         gThreeCard = g_lTempLines;
         gThreeCard = g_lTempLines;
         initialize("finish");  // Finally pass exection to finish the initialization.   
         initialize("finish");  // Finally pass execution to finish the initialization.   
     }     
     }     
}
}
Line 126: Line 146:
      
      
     touch_start(integer _num_det){
     touch_start(integer _num_det){
         initialize("");    
         initialize("");
   
     }
     }
      
      
Line 135: Line 154:
             // this is a line of our notecard
             // this is a line of our notecard
             if (_data != EOF) {     
             if (_data != EOF) {     
                // increment line count
                 g_lTempLines += _data;
                 g_lTempLines += [_data];
                 //request a next line
                 //request a next line
                 g_iLine++;
                 ++g_iLine;   // increment line count
                 g_kQuery = llGetNotecardLine(g_sNoteCardName, g_iLine);
                 g_kQuery = llGetNotecardLine(g_sNoteCardName, g_iLine);
             } else {
             } else {
            //The notecard has been read  
                //The notecard has been read  
            //notify end of read
                //notify end of read
            notecardFinished(g_sNoteCardName);  
                notecardFinished(g_sNoteCardName);
                  
            }
        }
    }
}
</source>
 
<source lang="lsl2">
/////
//  Generic Multi Notecard reader by Randur Source
//  Given freely and published on wiki.secondlife.com
//
//  This script will read all note cards in sequence and dump the results into chat as an example.
//  It can be modified and extended to do other things to the data.
//
 
integer inventorycnt;
integer notecardlinecnt;
integer notecardlinenumber;
string notecardname;
key linenumberid;
key lineid;
 
getnextnotecardlinenumber()
{
    // first get the number of lines from the notecard
    inventorycnt++;
    if (inventorycnt < llGetInventoryNumber(INVENTORY_NOTECARD))
    {
        notecardname = llGetInventoryName(INVENTORY_NOTECARD,inventorycnt);
        linenumberid = llGetNumberOfNotecardLines(notecardname);
    }
    else
        llOwnerSay("Done.");
}
 
getnextnotecardline()
{
    // get the next line from the notecard or skip to the next notecard
    notecardlinecnt++;
    if (notecardlinecnt < notecardlinenumber)
        lineid = llGetNotecardLine(notecardname,notecardlinecnt);
    else
        getnextnotecardlinenumber();
}
 
default
{
    touch_start(integer total_number)
    {
        if (llDetectedKey(0) != llGetOwner()) return; // allow owner only
 
        inventorycnt = -1;
        getnextnotecardlinenumber();
    }
   
    dataserver(key queryid,string data)
    {
        if (queryid == linenumberid) // this was a line number lookup
        {
            linenumberid = NULL_KEY;
            notecardlinenumber = (integer)data;
            if (notecardlinenumber == 0)
                 getnextnotecardlinenumber();
            else
            {
                notecardlinecnt = -1;
                getnextnotecardline();
            }
        }
        else if (queryid == lineid) // this was a data line lookup
        {
            lineid = NULL_KEY;
 
            // Example of what to do with the data:
            // Test for valid avatar names, possibly multiple names on each line, separated by ,
            // and say them in chat to the owner
            list names = llParseString2List(data,[","],[]); // split lines on ,
            integer len = llGetListLength(names); // I wouldn't dare to put this inside the for loop
            integer cnt;
            for (cnt = 0; cnt < len; cnt++)
            {
                string name = llDumpList2String(llParseString2List(llList2String(names,cnt),[" "],[])," "); // remove extra spaces
                if (llGetListLength(llParseString2List(name,[" "],[])) == 2) // check for first + lastname
                    llOwnerSay(notecardname + ": " + name);
             }
             }
            getnextnotecardline();
         }
         }
     }
     }
}
}
</pre>
 
|helpers
</source>
|also_functions={{LSL DefineRow||[[llGetNumberOfNotecardLines]]|}}
|also_functions={{LSL DefineRow||[[llGetNumberOfNotecardLines]]|}}
|also_events={{LSL DefineRow||[[dataserver]]|}}
|also_events={{LSL DefineRow||[[dataserver]]|}}
|also_articles
|also_articles
|also_tests
|also_tests
|notes
|permission
|permission
|cat1=Notecard
|cat1=Notecard
Line 161: Line 263:
|cat3=
|cat3=
|cat4=
|cat4=
|history={{LSL Added|0.6.0|remote=http://secondlife.wikia.com/wiki/Version_0.6.0}}
}}
}}

Revision as of 04:52, 19 November 2021

Summary

Function: key llGetNotecardLine( string name, integer line );

Requests the line line of the notecard name from the dataserver.
Returns the handle (a key) for a dataserver event response.

• string name a notecard in the inventory of the prim this script is in or a UUID of a notecard
• integer line Line number in a notecard (the index starts at zero).

line does not support negative indexes. If line is past the end of the notecard EOF is returned by the dataserver.

Caveats

  • This function causes the script to sleep for 0.1 seconds.
  • If line is out of bounds the script continues to execute without an error message.
  • If name is missing from the prim's inventory and it is not a UUID or it is not a notecard then an error is shouted on DEBUG_CHANNEL.
  • If name is a UUID then there are no new asset permissions consequences for the object.
    • The resulting object develops no new usage restrictions that might have occurred if the asset had been placed in the prims inventory.
  • If name is a new empty notecard (never saved) then an error "Couldn't find notecard ~NAME~" (~NAME~ being the value of name) will be shouted on the DEBUG_CHANNEL. This is because until a notecard is saved for the first time, it does not exist as an asset only as an inventory placeholder.
  • If notecard contains embedded inventory items (such as textures and landmarks), EOF will be returned, regardless of the line requested.
  • If the requested line is longer than 1024 bytes the dataserver will return the first 1024 bytes of the line.
  • The byte return for this function was increased from 255 bytes to 1024 bytes with server version 2021-10-25.565008
  • The notecard read can be full perm, no-modify, or no-modify/no copy.
All Issues ~ Search JIRA for related Bugs

Examples

key notecardQueryId;
string notecardName = "name of notecard as in object's contents";

// script-wise, the first notecard line is line 0, the second line is line 1, etc.
integer notecardLine;

say(string inputString)
{
    llOwnerSay(inputString);
}

default
{
    state_entry()
    {
        // Check the notecard exists, and has been saved
        if (llGetInventoryKey(notecardName) == NULL_KEY)
        {
            llOwnerSay( "Notecard '" + notecardName + "' missing or unwritten");
            return;
        }
        // say("reading notecard named '" + notecardName + "'.");
        notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
    }

    dataserver(key query_id, string data)
    {
        if (query_id == notecardQueryId)
        {
            if (data == EOF)
                say("Done reading notecard, read " + (string) notecardLine + " notecard lines.");
            else
            {
                // bump line number for reporting purposes and in preparation for reading next line
                ++notecardLine;
                say( "Line: " + (string) notecardLine + " " + data);
                notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
            }
        }
    }
}

Useful Snippets

/////
//  Generic Multi Notecard reader by Brangus Weir
//  Given freely and published on wiki.secondlife.com
//
//  This script will read three note cards and store the results into three lists.
//  It can be modified and extended to as many (or few) cards as you'd like to read. 
//

list gOneCard;    // All the lines from from the first card
list gTwoCard;    // All the lines from from the second card
list gThreeCard;  // All the lines from from the third card

string gsCardOneName = "One";  //Set these to the name of the invetory item.
string gsCardTwoName = "Two";
string gsCardThreeName = "Three";

//Temporary variables for processing
string g_sNoteCardName; // Name of the card to be read.
list g_lTempLines;      // The resulting data pushed into a list
integer g_iLine;        // The line count for the card reader
key g_kQuery;           // The key of the card being read


initialize(string _action) {
    // Due to the execution order when using dataserver, this function sets the first card to 
    // be read, and the excetuion finishes when called again with the _action set to "finish".
    if (_action == "") {
        loadNoteCard(gsCardOneName);
    } else if (_action == "finish") {
        // All cards have been read into the lists... now you can do any kind of string
        // manipulations to get the data you need to set your script.
        // But here we will prove that the cards have been read with a loop

        g_lTempLines = []; // lets not forget to delete this global, or it will be dead weight.

        integer len = llGetListLength(gOneCard);  //Always evaluate this once, don't do it
                                                  //INSIDE the for loop like noob programers will.
                                                  //Reduce lag, THINK ABOUT MACHINE CYCLES!
        integer i = 0;
        for (; i< len; ++i)
            llSay(0, llList2String(gOneCard,i));

        len = llGetListLength(gTwoCard);
        for (i = 0; i< len; ++i)
            llSay(0, llList2String(gTwoCard,i));

        len = llGetListLength(gThreeCard);
        for (i = 0; i< len; ++i)
            llSay(0, llList2String(gThreeCard,i));
    }                
                              
}

loadNoteCard( string _notecard ) {
    g_lTempLines = []; //clear the temp lines
    g_sNoteCardName = _notecard;
    g_iLine = 0;
    g_kQuery = llGetNotecardLine(g_sNoteCardName, g_iLine);  
    
}

notecardFinished(string _notecard){
    // Called at the end of each notecard as it is read. The temp results are stored
    // and the next card is commanded to be read.
    if (_notecard == gsCardOneName) {
        gOneCard = g_lTempLines;
        loadNoteCard(gsCardTwoName);
    } else if (_notecard == gsCardTwoName) {
        gTwoCard = g_lTempLines;
        loadNoteCard(gsCardThreeName);
    } else if (_notecard == gsCardThreeName) {
        gThreeCard = g_lTempLines;
        initialize("finish");  // Finally pass execution to finish the initialization.   
    }    
}

default
{
    state_entry()
    {
    }
    
    touch_start(integer _num_det){
        initialize("");
    }
     
    dataserver(key _query_id, string _data) 
    {
        if (_query_id == g_kQuery) {
            // this is a line of our notecard
            if (_data != EOF) {    
                g_lTempLines += _data;
                //request a next line
                ++g_iLine;   // increment line count
                g_kQuery = llGetNotecardLine(g_sNoteCardName, g_iLine);
            } else {
                //The notecard has been read 
                //notify end of read
                notecardFinished(g_sNoteCardName);
            }
        }
    }
}
/////
//  Generic Multi Notecard reader by Randur Source
//  Given freely and published on wiki.secondlife.com
//
//  This script will read all note cards in sequence and dump the results into chat as an example.
//  It can be modified and extended to do other things to the data. 
//

integer inventorycnt;
integer notecardlinecnt;
integer notecardlinenumber;
string notecardname;
key linenumberid;
key lineid;

getnextnotecardlinenumber()
{
    // first get the number of lines from the notecard
    inventorycnt++;
    if (inventorycnt < llGetInventoryNumber(INVENTORY_NOTECARD))
    {
        notecardname = llGetInventoryName(INVENTORY_NOTECARD,inventorycnt);
        linenumberid = llGetNumberOfNotecardLines(notecardname);
    }
    else
        llOwnerSay("Done.");
}

getnextnotecardline()
{
     // get the next line from the notecard or skip to the next notecard
    notecardlinecnt++;
    if (notecardlinecnt < notecardlinenumber)
        lineid = llGetNotecardLine(notecardname,notecardlinecnt);
    else
        getnextnotecardlinenumber();
}

default
{
    touch_start(integer total_number)
    {
        if (llDetectedKey(0) != llGetOwner()) return; // allow owner only

        inventorycnt = -1;
        getnextnotecardlinenumber();
    }
    
    dataserver(key queryid,string data)
    {
        if (queryid == linenumberid) // this was a line number lookup
        {
            linenumberid = NULL_KEY;
            notecardlinenumber = (integer)data;
            if (notecardlinenumber == 0)
                getnextnotecardlinenumber();
            else
            {
                notecardlinecnt = -1;
                getnextnotecardline();
            }
        }
        else if (queryid == lineid) // this was a data line lookup
        {
            lineid = NULL_KEY;

            // Example of what to do with the data:
            // Test for valid avatar names, possibly multiple names on each line, separated by ,
            // and say them in chat to the owner
            list names = llParseString2List(data,[","],[]); // split lines on ,
            integer len = llGetListLength(names); // I wouldn't dare to put this inside the for loop
            integer cnt;
            for (cnt = 0; cnt < len; cnt++)
            {
                string name = llDumpList2String(llParseString2List(llList2String(names,cnt),[" "],[])," "); // remove extra spaces
                if (llGetListLength(llParseString2List(name,[" "],[])) == 2) // check for first + lastname
                    llOwnerSay(notecardname + ": " + name);
            }

            getnextnotecardline();
        }
    }
}

See Also

Events

•  dataserver

Functions

•  llGetNumberOfNotecardLines

Deep Notes

History

Search JIRA for related Issues

Footnotes

  1. ^ Early release notes were not very accurate or thorough, they sometimes included information about features added in previous releases or failed to include information about features added in that release.

Signature

function key llGetNotecardLine( string name, integer line );