Difference between revisions of "Dataserver API"

From Second Life Wiki
Jump to navigation Jump to search
(New page: {{LSL Header}} Dataserver Framework ---- Introduction: the most common problem i find is people asking about dataservers, reading from notecards to bypass variables within a notecard so...)
 
m (→‎Notecard: Replaced <source> with <syntaxhighlight>, using INI formatting)
 
(10 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}
{{RightToc}}
=Dataserver Framework=


Dataserver Framework
===Introduction===


----
A common problem in SL is reading and parsing notecards by script. One application for this is so a script can be distributed as no-mod but still be configurable.


Introduction:
The below framework demonstrates how to setup such an interface with very little work to retool.
the most common problem i find is people asking about dataservers, reading from notecards to bypass variables within a notecard so you can release your script as nomod.
so i setup a simple system that i use time and time again that can be reused in any project.
the class itself is state based meaning the default state reads the notecard and then starts another state when the notecard is read and ready to use i explain this further below.


Main Script:
The default state reads the notecard and when it is done it activates the configuration state.
<pre>
 
===Testimonial===
 
The most common problem I find is people asking about dataservers, reading from notecards to bypass variables within a notecard so you can release your script as nomod.
So I setup a simple system that I use time and time again that can be reused in any project.
The class itself is state based meaning the default state reads the notecard and then starts another state when the notecard is read and ready to use I explain this further below.
 
==Main Script==
<syntaxhighlight lang="lsl2">
string notecard_name = "configuration";  // name of notecard goes here
string notecard_name = "configuration";  // name of notecard goes here


key queryhandle;                  // to seperate Dataserver requests
// internals
integer DEBUG = FALSE;
integer line;
key queryhandle;                  // to separate Dataserver requests
key notecarduuid;


// UPDATES
init()
integer line ;
{
    queryhandle = llGetNotecardLine(notecard_name, line = 0);// request line
    notecarduuid = llGetInventoryKey(notecard_name);
}


// Config data loaded from notecard, with some sane defaults
// Config data loaded from notecard, with some sane defaults
Line 28: Line 42:
         // We want to reload channel notecard if it changed
         // We want to reload channel notecard if it changed
         if (change & CHANGED_INVENTORY)
         if (change & CHANGED_INVENTORY)
        {
            if(notecarduuid != llGetInventoryKey(notecard_name))
        llResetScript();
                init();
        }
       
     }
     }
     state_entry()
     state_entry()
     {
     {
         queryhandle = llGetNotecardLine(notecard_name, line);// request line
         init();
        line++ ;
     }
     }
      
      
     dataserver(key query_id, string data) {
     dataserver(key query_id, string data)
         if (query_id == queryhandle) {
    {
            // I've written this token parser so many times in so many languages...
         if (query_id == queryhandle)
             if (data != EOF) {   // not at the end of the notecard
        {
             if (data != EOF)
            {   // not at the end of the notecard
                 // yay!  Parsing time
                 // yay!  Parsing time
                 // first, is it a comment? or an empty line?
               
                 if (llGetSubString (data, 0, 0) != "#" && llStringLength (data) > 0)
                 // pesky whitespace
                data = llStringTrim(data, STRING_TRIM_HEAD);
 
                // is it a comment?
                 if (llGetSubString (data, 0, 0) != "#")
                 {
                 {
                     list parsed = llParseString2List (data, ["="], [""]) ;
                     integer s = llSubStringIndex(data, "=");
                     string token = llToLower (llStringTrim (llList2String (parsed, 0), STRING_TRIM)) ;
                    if(~s)//does it have an "=" in it?
                    if (token == "email_address")
                     {
                        email_address = llStringTrim (llList2String (parsed, 1), STRING_TRIM) ;
                        string token = llToLower(llStringTrim(llDeleteSubString(data, s, -1), STRING_TRIM));
                    if (token == "channel")
                        data = llStringTrim(llDeleteSubString(data, 0, s), STRING_TRIM);
                        channel = (integer)llStringTrim (llList2String (parsed, 1), STRING_TRIM) ;
 
                        //Insert your token parsers here.
                        if (token == "email_address")
                            email_address = data;
                        else if (token == "channel")
                            channel = (integer)data;
                    }
                 }
                 }


                 queryhandle = llGetNotecardLine(notecard_name, line);
                 queryhandle = llGetNotecardLine(notecard_name, ++line);
                 line++;
                 if(DEBUG) llOwnerSay("Notecard Data: " + data);
             } else {
             }
                 if (email_address == "")
            else
                    llOwnerSay ("NOTICE!  No email_address specified.  You will NOT receive purchase emails or status updates!") ;
            {
state configuration ;
                 if(DEBUG) llOwnerSay("Done Reading Notecard");
                state configuration ;
             }
             }
         }
         }
     }
     }
 
}
}


Line 70: Line 94:
{
{
   
   
            state_entry()
    state_entry()
            {
    {
            llListen(channel, "", "", "");
        llListen(channel, "", "", "");
            llShout(0, "Channel set to " + (string)channel);
        llShout(0, "Channel set to " + (string)channel);
            llShout(0, "Email set to " + (string)email_address);
        llShout(0, "Email set to " + (string)email_address);
            }   
    }   
}
}
</pre>
</syntaxhighlight>


NOECARD:
==Notecard==
<pre>
<syntaxhighlight lang="ini">
# This is the configuration file
# This is the configuration file
channel = 1000
channel = 1000
Line 86: Line 110:


# end
# end
</pre>
</syntaxhighlight>
Lines that start with "#" are comments.


USAGE: Ok lets explain how this works
==How It Works==
well the default state basailly reads all the lines for the notecard parces the lines into the notecard and we setup varables in the dataserver so we know if we want to overide a default value.


the dataserver consists over tokens for example <pre>if (token == "email_address")</pre> this means in the noecard there will be a value called email_address like our notecard above then followed by the read like <pre>email_address = llStringTrim (llList2String (parsed, 1), STRING_TRIM) ;</pre> as the notecard is string based there are ways to get this back into other values also very common usage within secondlife. being a string inside a notecard and you want the value as a float, vector, integer etc all you need todo is add (integer) after the command = for example <pre>menu_timer = (integer)llStringTrim (llList2String (parsed, 1), STRING_TRIM) ;</pre> this will convert the string into an integer.
The [[default]] [[state]] reads and parses all the lines in the notecard. As it reads the notecard it overwrites the default values with the values in the notecard. More specifically after each line has been validated and tokenized, the token is checked against supported tokens. If the token is supported the specific parser for the token is called, in the above example it is just a simple convert and copy.  


For technical support, requests, etc., use the Search under the Groups Tab and search for .::Prototype::.
For technical support, requests, etc., use the Search under the Groups Tab and search for Dazzle Software


if you have any problems getting this script to work either contect me inworld [https://wiki.secondlife.com/wiki/User:Revolution_Perenti Revolution Perenti]
If you have any problems getting this script to work either contact me in-world [https://wiki.secondlife.com/wiki/User:Revolution_Perenti Revolution Perenti]
or visit out Open Source Section at skidz partz we have many different versions of this system.
Or visit our free scripts at our LSL scripts [http://www.dazzlesoftware.org www.dazzlesoftware.org] Secondlife Open Source Section on Tutorials.
[http://slurl.com/secondlife/Snow%20Crash/128/128/23 Snow Crash]
Latest version always available on [https://marketplace.secondlife.com/p/Dazzle-Software-DataServer-API/374436 Marketplace] or [http://maps.secondlife.com/secondlife/Wyrd/230/83/97 Dazzle Software via Wyrd]


{{#vardefine:sort|Script Overide Functions}}{{LSLC|Library}}{{LSLC|Examples}}
{{LSLC|Library}}{{LSLC|Examples}}

Latest revision as of 16:55, 9 February 2023

Dataserver Framework

Introduction

A common problem in SL is reading and parsing notecards by script. One application for this is so a script can be distributed as no-mod but still be configurable.

The below framework demonstrates how to setup such an interface with very little work to retool.

The default state reads the notecard and when it is done it activates the configuration state.

Testimonial

The most common problem I find is people asking about dataservers, reading from notecards to bypass variables within a notecard so you can release your script as nomod. So I setup a simple system that I use time and time again that can be reused in any project. The class itself is state based meaning the default state reads the notecard and then starts another state when the notecard is read and ready to use I explain this further below.

Main Script

string notecard_name = "configuration";  // name of notecard goes here

// internals
integer DEBUG = FALSE;
integer line;
key queryhandle;                   // to separate Dataserver requests
key notecarduuid;

init()
{
    queryhandle = llGetNotecardLine(notecard_name, line = 0);// request line
    notecarduuid = llGetInventoryKey(notecard_name);
}

// Config data loaded from notecard, with some sane defaults
integer channel = 1000;
string email_address = "revolution.perenti@skidzpartz.com";
default
{
    changed(integer change)         
    {
        // We want to reload channel notecard if it changed
        if (change & CHANGED_INVENTORY)
            if(notecarduuid != llGetInventoryKey(notecard_name))
                init();
    }

    state_entry()
    {
        init();
    }
    
    dataserver(key query_id, string data)
    {
        if (query_id == queryhandle)
        {
            if (data != EOF)
            {   // not at the end of the notecard
                // yay!  Parsing time
                
                // pesky whitespace
                data = llStringTrim(data, STRING_TRIM_HEAD);

                // is it a comment?
                if (llGetSubString (data, 0, 0) != "#")
                {
                    integer s = llSubStringIndex(data, "=");
                    if(~s)//does it have an "=" in it?
                    {
                        string token = llToLower(llStringTrim(llDeleteSubString(data, s, -1), STRING_TRIM));
                        data = llStringTrim(llDeleteSubString(data, 0, s), STRING_TRIM);

                        //Insert your token parsers here.
                        if (token == "email_address")
                            email_address = data;
                        else if (token == "channel")
                            channel = (integer)data;
                    }
                }

                queryhandle = llGetNotecardLine(notecard_name, ++line);
                if(DEBUG) llOwnerSay("Notecard Data: " + data);
            }
            else
            {
                if(DEBUG) llOwnerSay("Done Reading Notecard");
                state configuration ;
            }
        }
    }
}

state configuration
{
 
    state_entry()
    {
        llListen(channel, "", "", "");
        llShout(0, "Channel set to " + (string)channel);
        llShout(0, "Email set to " + (string)email_address);
    }   
}

Notecard

# This is the configuration file
channel = 1000
email_address = phoenixcms@hotmail.co.uk

# end

Lines that start with "#" are comments.

How It Works

The default state reads and parses all the lines in the notecard. As it reads the notecard it overwrites the default values with the values in the notecard. More specifically after each line has been validated and tokenized, the token is checked against supported tokens. If the token is supported the specific parser for the token is called, in the above example it is just a simple convert and copy.

For technical support, requests, etc., use the Search under the Groups Tab and search for Dazzle Software

If you have any problems getting this script to work either contact me in-world Revolution Perenti Or visit our free scripts at our LSL scripts www.dazzlesoftware.org Secondlife Open Source Section on Tutorials. Latest version always available on Marketplace or Dazzle Software via Wyrd