Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Notecards

Alan Ajax
Registered User
Join date: 9 Aug 2006
Posts: 38
12-03-2006 19:29
Can someone please give me a code example of how to get config parameters from a notecard?

Thanks in advance
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
12-04-2006 04:22
Plenty of examples through out the forum.
The basic's are a dataserver event.

here is a relatively barebones example, ist based on Hank ramos's code I picked up when I first started in SL and I've used it ever since.

how you format your notecard is really down to you,
I use PARAMETER=VALUE pairs mainly for simplicity.

The chanegd event means that the system will automatically reset if the owner is changed or the inventory has been updated. I use this to allow the system to automatically detect when I have edited the notecard.


The timer event in the readConfig state helps prevent the script from locking up in the event of a dataserver event not happening for some reason.
CODE

// basic DataServer
//
string notecard = "Configuration";
integer lineCounter;
key dataRequestID;

integer Channel = 0;
float Volume = 0.0;
string Sound;

//
// helper functions
//
GetParameters(string str)
{
// parameters are stored as
// parameter=value

list ldata = llParseString2List(str, ["="], [""]);

string command = llList2String(ldata,0);
string value = llList2String(ldata,1);
integer intvalue = (integer)value;

//llOwnerSay("Read " + command + " : " + value);
if("Channel" == command)
{
Channel = intvalue;
}
else if("Volume" == command)
{
Volume = (float)value;
}
else if("Sound" == command)
{
Sound = value;
}
}

ChangedStatus(integer change)
{
// Test for a changed inventory
if (change & CHANGED_INVENTORY)
{
llResetScript();
}
else if (change & CHANGED_OWNER)
{
llResetScript();
}
}

// Used only for initialisation
default
{
state_entry()
{
state ReadConfig;
}


// Should never be rezzed in this state so reset
on_rez(integer num) { llResetScript(); }
// if something has been updated reset
changed(integer change) { ChangedStatus(change); }
}

// Main State
state Running
{
state_entry()
{
}

changed(integer change) { ChangedStatus(change); }
}

//--------------------------------------------------------------------------------
state ReadConfig
{
state_entry()
{
lineCounter = 0;
integer itemtype = llGetInventoryType(notecard);
if(INVENTORY_NOTECARD == itemtype)
{
dataRequestID = llGetNotecardLine(notecard, lineCounter);
llSetTimerEvent(10);
}
else
{
llOwnerSay("Error - configuration notecard missing, Using defaults only!");
state Running;
}

}

dataserver( key query_id, string data ) // read from the notecard
{
if(query_id == dataRequestID)
{
if (data != EOF)
{
if(llStringLength(data) > 3)
{
GetParameters(data);
}
lineCounter++;
dataRequestID = llGetNotecardLine( notecard, lineCounter );
}
else
{
llSetTimerEvent(0);
state Running;
}
}
}

timer()
{
llOwnerSay("ERROR - Dataserver time out! aborting");
llSetTimerEvent(0);
state Running;
}

// Should never be rezzed in this state so reset
on_rez(integer num) { llResetScript(); }
// if something has been updated reset
changed(integer change) { ChangedStatus(change); }
}

Alan Ajax
Registered User
Join date: 9 Aug 2006
Posts: 38
12-04-2006 06:42
Thanks! Exactly what I needed and more.
Zaphod Kotobide
zOMGWTFPME!
Join date: 19 Oct 2006
Posts: 2,087
Or...
12-16-2006 06:19
Another option that requires substantially less code, and does not have the delay implications of the dataserver() event, is to use llMessageLinked() .. pretty much straight out of the example scripts on the wiki.

Benefits: Much faster than notecard based settings, less code to clutter up your scripts

Risks: Because the "config" is indeed code, more chance that an inexperienced user might muck things up. Strong documentation is the order of the day.

Configuration Script looks like this:
CODE

// llMessageLinked based config
// Name/Value pairs - These are passed on to the main
// application script when requested
// Based on wiki example at
// http://www.lslwiki.com/lslwiki/wakka.php?wakka=ExampleArgumentMultiplexing

// Begin User Settings
integer sRange = 14;
float sArc = PI;
integer sRate = 2;
// End of User Settings.
// Do not change the following under penalty of loss of genetals

default
{
link_message(integer sender_num, integer num, string request, key id)
{
// Send back requested values
if (request == "send_params")
{
list params = ["params", sRange, sArc, sRate];
llMessageLinked(LINK_THIS, 0, llDumpList2String(params,"-=-"), NULL_KEY);
}
}
}


And the application script:
CODE

// Application script - adapt to call in parameters from
// config script as needed. touch_start is used here for
// example only, obviously there's a better trigger
// such as state_entry() inside your 'configure' state.
//
// Based on wiki example at
// http://www.lslwiki.com/lslwiki/wakka.php?wakka=ExampleArgumentMultiplexing

integer sRange;
float sArc;
integer sRate;

default
{
touch_start(integer total_number)
{
llMessageLinked(LINK_THIS, 0, "send_params", NULL_KEY);
}

link_message(integer sender_num, integer num, string message, key id)
{
list args = llParseStringKeepNulls( message, ["-=-"], [] );
string response = llList2String( args, 0);
if (response == "params")
{
sRange = (integer)llList2String( args, 1);
sArc = (float)llList2String( args, 2);
sRate = (integer)llList2String( args, 3);
}
}
}
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
12-16-2006 11:38
And the most obvious drawe back is that you need to edit it and recompile to update your object rather than just dropping in a new notecard.
Zaphod Kotobide
zOMGWTFPME!
Join date: 19 Oct 2006
Posts: 2,087
12-16-2006 12:47
Yup.. there's that too. Neither is necessarily ideal. Ideal would be the ability to directly convert strings to variables and functions.

I noticed you're checking string length on the incoming data and basically determining that it isn't a blank line by testing string length for >3 - Am I correct in assuming that there is actually no solid way to do this? No regex pattern matching?
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
12-16-2006 12:57
From: Zaphod Kotobide
Yup.. there's that too. Neither is necessarily ideal. Ideal would be the ability to directly convert strings to variables and functions.

I noticed you're checking string length on the incoming data and basically determining that it isn't a blank line by testing string length for >3 - Am I correct in assuming that there is actually no solid way to do this? No regex pattern matching?


None taht I am aware off, not that that means much!
Shippley Dittmann
Registered User
Join date: 30 Aug 2006
Posts: 13
reagarding the notecard configuration
06-28-2007 19:20
I am trying to learn the basic principals of the notecard configuration feature. I kind of get the idea from the script....

Can I see what an example Notecard text would be to change the settings for this script?

Something to do with playing a sound..??

Maybe a little explanation.

/shrug
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
06-29-2007 00:14
From: Shippley Dittmann
I am trying to learn the basic principals of the notecard configuration feature. I kind of get the idea from the script....

Can I see what an example Notecard text would be to change the settings for this script?

Something to do with playing a sound..??

Maybe a little explanation.

/shrug

The exact content of a notecard is completely up to you, all the datatserver does is return a line of text. I usually use key=value pairs for mosty things as its nice and simple.
i.e.

SOUND=mysoundfile

Script Fragment
CODE

dataserver(key queryid, string data)
{
//Check to make sure this is the request we are making.
//Remember that when data comes back from the dataserver,
//it goes to *all* scripts in your prim.
//So you have to make sure this is the data you want, and
//not data coming from some other script.
if (dataRequestID == queryid)
{
// llOwnerSay("received " + data);
llSetTimerEvent(0);
//If we haven't reached the end of the file
if (data != EOF)
{
// ; used as a comment line
if(llGetSubString(data, 0,0) != ";")
{
// Lines are in the form KEYWORD=value=extra
list ldata = llParseString2List(data,["="],[""]);
string command = llList2String(ldata,0);
string parameter1 = llList2String(ldata,1);
string parameter2 = llList2String(ldata,2);
// Process commands here
}
//Request next line
++lineCounter;
dataRequestID = llGetNotecardLine(notecardName, lineCounter);
llSetTimerEvent(10);
}
else
{
state RunMode;
}
}
}
_____________________
I'm back......
Domino Marama
Domino Designs
Join date: 22 Sep 2006
Posts: 1,126
06-29-2007 02:00
Here's an example of the way I do it. Obviously similar to the others but uses a notecard with "item name=item data" on each line. It also supports multiple data items per config item ("item name = item data, more data, even more data"

Comments can be included in the config by starting the line with # and it handles the most common cases of where people put unexpected spaces automatically.

In this example I've set it up for an optional _config notecard such as:

# System Channel is the main communications channel, it should be unique
System Channel = -55555
# Add a list of sims to use here
Sim List = Spinolds Flat, Mooz,URBIS
# set x y and z for the offset
Offset = 1.0, 10.0, 5.0
# another way to do lists
Nickname = Dom, Domino Marama
Nickname = DJ, Diamond Jubilee

CODE

integer systemChannel = -67894;
list simList = [ "Spinolds Flat" ];
list avatarNames;
list avatarNicknames;
vector offset;
integer tI;
list tL;
string tS;
key request;

default
{
state_entry()
{
if ( llGetInventoryType( "_config" ) == INVENTORY_NOTECARD )
{
request = llGetNotecardLine( "_config", tI = 0 );
}
else
{
state ready;
}
}


dataserver(key query, string data)
{
if ( request == query )
{
if ( data == EOF )
{
state ready;
}
else
{
if ( llGetSubString( data, 0 ,0 ) != "#" && llStringTrim(data, STRING_TRIM) != "")
{
tL = llParseString2List( data, ["= ", "=", " , ", ", ", " ,", ","],[] );
tS = llToLower( llStringTrim( llList2String( tL, 0 ), STRING_TRIM ));
// at this point tS contains lower case item name and tL[1,-1] contains data
if ( tS == "system channel" )
{
systemChannel = llList2Integer( tL, 1);
}
else if ( tS == "sim list" )
{
simList = llList2List( tL, 1, -1 );
}
else if ( tS == "offset" )
{
offset = < llList2Float( tL, 1 ), llList2Float( tL, 2 ), llList2Float( tL, 3 ) >;
}
else if ( tS == "nickname" )
{
// funky way of doing avatarNames += llList2List( tL,2,2 ); is to save memory
avatarNames = ( avatarNames = [] ) + avatarNames + llList2List( tL,2,2 );
avatarNicknames = ( avatarNicknames = [] ) + avatarNicknames + llList2List( tL,1,1 );
}
}
request = llGetNotecardLine( "_config", ++tI );
}
}
}
}

state ready
{
state_entry()
{
llOwnerSay( "good to go on channel " + (string)systemChannel + " for " + llDumpList2String( simList, ", " ) );
}
}