LlGetNotecardLineSync
Looking for the current API? Open the llGetNotecardLineSync reference →
Wiki description
Gets the
line of the notecard name from the region's notecard cache immediately without raising a dataserver event.Function notes
Returns EOF if
line is past the end of the notecard.Specification
This function returns a string containing the requested line from a notecard in prim inventory, without the need for an asynchronous dataserver event, if the notecard is cached/known in its entirety by the simulator. This speeds up acessing notecard lines tremendously, and allows for near instantaneous random access.
If the notecard does not exist it returns the constant NAK and will shout a message to the debug channel. If the notecard has not been previously cached on the simulator it will return the NAK constant.
Notecards are cached into a fixed-size buffer, with the oldest (least-recently read) notecard getting removed first. It is not safe to assume a notecard has been previously cached. Data for a previously cached notecard may be dropped from the cache at any time, especially on a busy server.
Caveats
- 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 (not characters), llGetNotecardLineSync will only return the first 1024 bytes of the line.
- To check that the returned line has not been truncated, use the example snippet on llStringToBase64 to check the number of bytes returned by llGetNotecardLineSync. If the string is exactly 1024 bytes, it may have been truncated.
- Do not use llStringLength for this, because strings in LSL support multi-byte characters (UTF-8 for LSL-2, UTF-16 for Mono).
- To check that the returned line has not been truncated, use the example snippet on llStringToBase64 to check the number of bytes returned by llGetNotecardLineSync. If the string is exactly 1024 bytes, it may have been truncated.
- A dataserver event does not get raised. Therefore, other scripts in the linkset are unaware of the processed notecard lines.
- Since this function does not idle the script while waiting for a dataserver event, garbage collection will not run while loading an entire notecard by calling llGetNotecardLineSync in a loop. For large notecards, you can quickly run out of free memory, even if you overwrite each line as you read it.
- This does not occur with llGetNotecardLine, which runs garbage collection while waiting for the dataserver event.
- This can be mitigated using timers (any length will do), but not llSleep, which also blocks garbage collection.
Examples
string NOTECARD_NAME = "notecard";
key READ_KEY = NULL_KEY;
default
{
touch_start(integer total_number)
{
READ_KEY = llGetNumberOfNotecardLines(NOTECARD_NAME);
}
dataserver(key request, string data)
{
if (request == READ_KEY)
{
integer count = (integer)data;
integer index;
for (index = 0; index < (count+1); ++index)
{
string line = llGetNotecardLineSync(NOTECARD_NAME, index);
if (line == NAK)
{
llOwnerSay("---NAK---");
}
else if (line == EOF)
{
llOwnerSay("---EOF---");
}
else
{
llOwnerSay(line);
}
}
}
}
}Following example to call a normal dataserver notecard read using llGetNotecardLine if llGetNotecardlineSync fails with a NAK. Keep in mind to clear any lists you are reading data into when using the following example to keep from corrupting the integrity of the list data.
// llGetNotecardLineSync example with fall back to the old dataserver read
// if llGetNotecardLineSync fails with a NAK.
string NOTECARD_NAME = "notecard";
key READ_KEY = NULL_KEY;
key noteCard_qry;
integer noteCard_line;
default
{
state_entry()
{
// read the notecards number of lines to the
// simulators cache memory
READ_KEY = llGetNumberOfNotecardLines(NOTECARD_NAME);
}
dataserver(key request, string data)
{
// read notecards using the new llGetNotecardLineSync function
// from simulator cache.
if (request == READ_KEY)
{
integer count = (integer)data;
integer index;
for (index = 0; index < (count+1); ++index)
{
string line = llGetNotecardLineSync(NOTECARD_NAME, index);
if (line == NAK)
{
// Got a notecard NAK meaning llGetNotecardLineSync had and error.
// falling back to the old dataserver event to read notecards.
llOwnerSay("---NAK---");
noteCard_qry = llGetNotecardLine(NOTECARD_NAME, noteCard_line);
return; // return is needed to break the for/next loop once the NAK is encountered.
}
else if (line == EOF)
{
// End of notecard.
llOwnerSay("---EOF---");
}
else
{
// do work here.
llOwnerSay(line);
}
}
}
// old system takes over if a NAK is encountered.
if(request == noteCard_qry)
{
if(data == EOF)
{
// End of notecard encountered.
llOwnerSay("EOF encountered");
}
else
{
// process normal notecard line, then read the next line
// of the notecard.
llOwnerSay(data);
noteCard_qry = llGetNotecardLine(NOTECARD_NAME, ++noteCard_line);
}
}
}
}Here is a more compact implementation that returns to using llGetNotecardLineSync whenever possible:
string file_name;
integer file_line_number;
key file_request;
default {
state_entry() {
file_name = llGetInventoryName(INVENTORY_NOTECARD, 0); // get the name of the first notecard in the object's inventory
}
touch_start(integer n) {
// start reading text when the object is touched (you'll probably want to move these lines to another place depending on your needs):
file_line_number = 0;
file_request = llGetNotecardLine(file_name, file_line_number);
}
dataserver(key id, string message) {
if (id == file_request) {
while (message != EOF && message != NAK) {
llOwnerSay(message); // do useful things with the text here
message = llGetNotecardLineSync(file_name, ++file_line_number);
}
if (message == NAK)
file_request = llGetNotecardLine(file_name, file_line_number);
if (message == EOF)
llOwnerSay("End of file.");
}
}
}See also: functions
Shared wiki helpers
The original page also injects shared parameter notes, caveats or issue information through these helpers. Their conditional MediaWiki logic is not reproduced here; inspect the preserved helper source for additional material.
Template:LSL Function/negative index
Original shared helper source (conditional wiki logic is not evaluated)
{{LSL Injection Test}}<noinclude>
Format:
<nowiki>{{LSL Function/negative index|boolean|p1|p2|p3}}</nowiki><br/>
Exclude p1, p2, or p3 if not used.
{{#vardefine:also_articles|{{LSL DefineRow||Test}}}}
{{#vardefine:ni_mode|true}}
{{#vardefine:ni_nc|}}
{{#vardefine:ni_p1|number}}
{{#vardefine:ni_p2|p2}}
<!--{{#vardefine:ni_p3|p3}}-->
</noinclude>{{#if:
{{#vardefine:ni_c|{{#if:{{{2|{{#var:ni_p1}}}}}|{{#if:{{{3|{{#var:ni_p2}}}}}|{{#if:{{{4|{{#var:ni_p3}}}}}|3|2}}|1}}|0}}}}
{{#vardefine:t|{{#ifeq:{{{1|{{#var:ni_mode}}}}}|true|{{#switch:{{#var:ni_c}}|3|2=LSL_Function/negative_index/range|1=LSL_Function/negative_index/single}}}}}}
{{{{#var:t}}|{{{2|{{#var:ni_p1}}}}}|{{{3|{{#var:ni_p2}}}}}|{{{4|{{#var:ni_p3}}}}}|noExclude={{{noExclude|}}}}}
{{#if:{{{noSpec|}}}||
{{#vardefine:spec|{{#var:spec}}
{{#if:{{#var:t}}|
{{{!}} {{Prettytable|style=float:left;}}
{{!}}-{{Hl2}}
! Index
! Positive
! Negative
{{!}}-
{{!}} First
{{!}} <code>0</code>
{{!}} <code>-{{{length|length}}}</code>
{{!}}-
{{!}} Last
{{!}} <code>{{{length|length}}} - 1</code>
{{!}} <code>-1</code>
{{!}}}
=== Indexes ===
<div style="display:table;"><div style="display:block;">
*Positive indexes count from the beginning, the first item being indexed as <code>0</code>, the last as <code>({{{length|length}}} - 1)</code>.
</div></div>
<div style="display:table;"><div style="display:block;">
*Negative indexes count from the far end, the first item being indexed as <code>-{{{length|length}}}</code>, the last as <code>-1</code>.
</div></div>
}}
}}
}}
{{#vardefine:also_articles|{{#var:also_articles}}
{{#if:{{#var:t}}|{{LSL_DefineRow||{{LSLGC|Negative_Index{{#var:lang}}|Negative Index}}|}}}}}}
{{#vardefine:header_footnote|{{#var:header_footnote}}{{PBR}}
{{#vardefineecho:ni_ps|{{#switch:{{#var:ni_c}}
|0=This function
|1={{LSLP|{{{2}}}}}
|2={{LSLP|{{{2}}}}} & {{LSLP|{{{3}}}}}
|3={{LSLP|{{{2}}}}}, {{LSLP|{{{3}}}}} & {{LSLP|{{{4}}}}}
}}}} {{#if:{{#var:t}}| support{{#ifexpr:{{#var:ni_c}}>1||s}}| ''do{{#ifexpr:{{#var:ni_c}}>1||es}} not'' support }} {{LSLGC|Negative_Index{{#var:lang}}|negative indexes}}.{{PBR}}
}}
{{#vardefine:footer|{{#var:footer}}
{{#if:{{#var:t}}|{{#ifeq:{{NAMESPACE}}|Template||{{#if:{{#var:self}}{{{self|}}}{{#pos:{{#var:moded}}|r}}{{#pos:{{#var:moded}}|u}}||{{LSLC|Negative Index{{#var:lang}}}}}}}}|
{{#if:{{#var:self}}{{{self|}}}{{#pos:{{#var:moded}}|r}}{{#pos:{{#var:moded}}|u}}||{{LSLC|Positive_Index_Only{{#var:lang}}}}}}
}}}}
{{#vardefine:caveats|{{#var:caveats}}
{{#if:{{{nc|{{#var:ni_nc}}}}}||
* If {{#switch:{{#var:ni_c}}
|3=either {{LSLP|{{{2}}}}}, {{LSLP|{{{3}}}}} or {{LSLP|{{{4}}}}} are
|2=either {{LSLP|{{{2}}}}} or {{LSLP|{{{3}}}}} are
|1={{LSLP|{{{2}}}}} is}} out of bounds {{#if:{{{oob-return|}}}|this function returns {{{oob-return|}}} and}} the script continues to execute without an error message.
{{#if:{{#var:t}}|{{#ifexpr:{{#var:ni_c}}>1|{{#if:{{{noExclude|}}}|* {{LSLP|{{{2}}}}} & {{LSLP|{{{3}}}}} will not form an [[#exclusion_range|exclusion range]] when {{LSLP|{{{2}}}}} is past {{LSLP|{{{3}}}}} (Approximately: {{LSLP|{{{2}}}}} > {{LSLP|{{{3}}}}}), instead it will act as if {{LSLP|{{{2}}}}} was zero & {{LSLP|{{{3}}}}} was -1.|* {{LSLP|{{{2}}}}} & {{LSLP|{{{3}}}}} will form an [[#exclusion_range|exclusion range]] when {{LSLP|{{{2}}}}} is past {{LSLP|{{{3}}}}} (Approximately: {{LSLP|{{{2}}}}} > {{LSLP|{{{3}}}}}). }}}}}}
}}}}
}}<noinclude>
==Debugging==
{| {{Prettytable}}
|-{{Hl2}}
! #var
! value
|-
{{VarPair|header_footnote}}
|-
{{VarPair|spec}}
|-
{{VarPair|caveats}}
|-
{{VarPair|notes}}
|-
{{VarPair|constants_nb}}
|-
{{VarPairTable|also_articles}}
|-
{{VarPair|footer}}
|}
</noinclude>Template:LSL Function/notecard
Original shared helper source (conditional wiki logic is not evaluated)
{{LSL Injection Test}}{{LSL_Function/inventory|{{{1|name}}}|uuid={{{uuid|}}}|type=notecard}}{{#if:
{{#vardefine:caveats|{{#var:caveats}}
* If {{LSLP|{{{1|name}}}}} is a new empty notecard (never saved) then an error "Couldn't find notecard ~NAME~" (~NAME~ being the value of {{LSLP|{{{1|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 the notecard is {{LSLGC|Permissions/Asset|full-perms}} you can check for this with [[llGetInventoryKey]] which will return [[NULL_KEY]] in this case. However if notecard is not {{LSLGC|Permissions/Asset|full-perms}}, there is no way to avoid the error message.
}}
}}<noinclude>
{{Box|Caveats|2={{#var:caveats}}}}
</noinclude>Original wiki source
Some wiki templates and tables need their original context. View this article on the Second Life Wiki. Technical wording and examples are retained from the source; historical guidance may differ from current behavior.