Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

making dialog getting data from memory scripts-- halp!

Chrysala Desideri
Scarlet Scriptrix
Join date: 4 Mar 2007
Posts: 65
02-09-2008 13:07
I am attempting to implement Very Keynes' memory script to hold notecard data (seperated values strings).

These strings are in 3 categories,first 2 characters of linkmessage key used to define categories.

i wish to retrieve the data and present a multipage menu, retrieving 1 page at a time. the menu will be "stacked" by category (the categories are access levels, first public, then group, then owner ) and the buttons numbered by making a count list of total buttons (listlength + 2ndlistlength etc..).

the description part of menu will be formed from part of the sCSV, and in the end the button chosen will index (some math i guess... if number > public count from total-public on next list) the right line to request.

however i'm going insane trying to get the info back for menu.. how to structure the linkmessage front end or whatever you call it. complete brain lockup. either that or i'm doing it wrong from the start.

here's my dataserver:

CODE

dataserver(key queryid, string data)
{




if (queryid == kCoord)
{
if(data != EOF)
{
if(data != "")
{

lCoord=llParseString2List(data,[";"],[""]);

access=llList2String(lCoord, 3);

if(access=="owner")
{
o_not_blank+=1;
llMessageLinked(LINK_THIS,0xfff1,data,"OL"+(string)not_blank);
iLinecount+=1;
kCoord = llGetNotecardLine(coord, iLinecount);
}

else if(access=="list"||access=="group")
{
g_not_blank+=1;
llMessageLinked(LINK_THIS,0xfff1,data,"GL"+(string)g_not_blank);
iLinecount+=1;
kCoord = llGetNotecardLine(coord, iLinecount);
}

else if(access!="owner" && access!="list" && access!="group")
{
not_blank+=1;
llMessageLinked(LINK_THIS,0xfff1,data,"PL"+(string)o_not_blank);
iLinecount+=1;
kCoord = llGetNotecardLine(coord, iLinecount);


}
}
else

{

kCoord = llGetNotecardLine(coord, iLinecount++);}

}
else
{

llSetText("",<1,1,1>,1);
llSleep(0.5);

}
return;

}
}




and the link_message i'm messing with (it's all wrong atm) - expects a linkmessage from script that detects on touch owner/samegroup/inlist/average joe... from that point on i'm lost.

CODE


link_message(integer sender_num, integer num, string str, key id)
{




if(str=="owner")
{
tot = not_blank+g_not_blank+o_not_blank;
integer n;
for(n=1;n<tot;n++)
{
lBaselist+=(string)n;

}
integer z;
for(z=1;z<not_blank;z++)
{
llMessageLinked(LINK_THIS,0xfff2,"","PL"+(string)z);
}
integer y;
for(y=1;y<g_not_blank;y++)
{
llMessageLinked(LINK_THIS,0xfff2,"","GL"+(string)y);
}
integer x;
for(x=1;x<o_not_blank;x++)
{
llMessageLinked(LINK_THIS,0xfff2,"","OL"+(string)x);
}
}
if(str=="lst")
{
tot = not_blank+g_not_blank;
integer n;
for(n=1;n<tot;n++)
{
lBaselist=(lBaselist=[])+lBaselist+(string)n;
}
integer y;
for(y=1;y<not_blank;y++)
{
llMessageLinked(LINK_THIS,0xfff2,"","PL"+(string)y);
}
integer x;
for(x=1;x<g_not_blank;x++)
{
llMessageLinked(LINK_THIS,0xfff2,"","GL"+(string)x);
}
}
if(str=="all")
{
tot = not_blank;
integer n;
for(n=1;n<tot;n++)
{
lBaselist=(lBaselist=[])+lBaselist+(string)n;
}
integer x;
for(x=1;x<not_blank;x++)
{
llMessageLinked(LINK_THIS,0xfff2,"","PL"+(string)x);
}
}



}




Halp?!
Haruki Watanabe
llSLCrash(void);
Join date: 28 Mar 2007
Posts: 434
02-09-2008 18:24
Can't really find something wrong - maybe it'd help, if you'd post the whole script... :)
Chrysala Desideri
Scarlet Scriptrix
Join date: 4 Mar 2007
Posts: 65
02-10-2008 06:28
Meybe what i've written so far isn't that 'off'... but what's missing is... what's missing!

basically i have written the dataserver, and monkeying around i have verified that the data is stored, the categories correct etc....

the problem is how to listen to the mem script's answer and get 1 page at a time to Void Singer's llDialog Paging... i'm not sure stuff is coming back in order (chat is useless for verifyig this, maybe i should try timestamping the linkmessage backfeed...)

but basically whats missing is what's missing!
Ollj Oh
Registered User
Join date: 28 Aug 2007
Posts: 522
02-10-2008 08:04
do you want a global list variable for dataserver's temporary storage?

Dataserver functions store data in it (if it is empty)
Other function calls read it (if it is not empty, and clear it if it was not empty)

a timer could check if the dataserver function changed the global variable (and empty it after processing data).
Chrysala Desideri
Scarlet Scriptrix
Join date: 4 Mar 2007
Posts: 65
02-10-2008 10:39
hi! and thanks for the replies...

no, i already have Very Keyne's memory scripts (VKF Datastore-- from library) holding global list couplets (data, index). What i want is to be able to retrieve 1 llDialog page at a time from a a very long list already stored.(working from Void Singer's absolute gem of dialog setup)

basically whatever order the entries are in on the notecard, they get seperated into 3 lists (index types). the dialog would then stack them type1 first, types 2 second, type 3 third.. and my idea was that having set integers of list length (the three not_blank variables) i could "count off" position in this created-on-the-fly list in the dialog.

i got the VKF datastore to store, am completely lost on the reconstruction bit.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
02-10-2008 12:02
it all depends on how you address the stored variables...

for instance if you limit the number of items stored per script, you could simply ask for a slice number (basically a starting index) which would then be grabbed by the storage scripts, which would decide if it has that slice, and return it.

ex.
each script holds 24 entry lines (could be singles could be pairs or more, doesn't matter)
script 0 (the unnumbered one) would hold 0-23
script 1 would hold 24-47,
etc

the scripts would know which slices they held by the internal formula of
script# * 24 to script# * 24 + 23

your master script would just request a set, starting at #, and the subs would see if they have it and then respond.

that's only good if you limit the entries per script. which is not good for dynamic sized data (where all entry sizes are not the same)

for that you need to tell each new storage script as you load it, what it's starting index is (or stor it in the master script). it can calc it's own ending index by list sizes.

you could also address all requests through the master script, then have it send the sub requests to the storage scripts. this is probably a better method since you can tell when you need to span more than one storage script, and queue the response back to the requesting end.

hopes some of that made sense.
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Chrysala Desideri
Scarlet Scriptrix
Join date: 4 Mar 2007
Posts: 65
02-10-2008 13:34
i *think* i get it....

as for identifying slices, they're being indexed with 2 chars for type, and i'm holding integers in the main script for each type's list length.

so the call woud basically add up the 3 integers, ("not_blank","g_not_blank" and "o_not_blank" in the case of the owner making the request) to see total length of menu.

the lldialog buttons then are numbered by list of numbers created on the fly from the total, and the requests for slices would request by index... PL1 - PL12, let's say, then GL1-GL4, then OL1-OL2 for buttons going from 1 to 18 in this case. thus, button 14 would call dataslice GL2.

now the list made from the "total buttons" variable should be enough to satisfy the page parsing from your dialog script, but i'm stuck at retrieving strings for the description (constructed as [string]button number+":"+first value in corresponding data slice).
my problem, i believe, is in not knowing how to handle the link_message return.

i want it to make the description list alone during menu time, preferably on the fly;
page-by-page, then send the whole slice as output once chosen...

hitting "more" goes to listen, i guess that's (also at menu start) where i have to make the request. it's parsing the return and sending up the next page that has me staring blankly at the screen and drooling. i think what the Question SHOULD be (goddess bless Douglas Adams!) is how will i get the link_message event to sort results and throw back the next page.. quandary #1 will it get slices in order naturally? and if so #2 how to structure event so it knows how much is coming to realise it has a page and toss it up?

i realise what i'm asking help with is practically a trade secret with those who make serious stuff, but thought i'd give it a shot. that it can be done i'm sure of, as i'm quite sure some products i've bought do exactly what i'm attempting.

anyway thank you so much for what you've given!
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
02-10-2008 14:10
Hi, Sorry I got in so late on the thread; I have been writing code and testing it on the beta grid most of today.

But what I was testing may be just what you need :)
This is the latest version of my DataStarage script, which I refer to as a “slice”.
The interface is now a lot less cryptic than the old one, and it handles several file types.
Variable length records, multiple fields per record and automatic or manual sorting.
I have also included a better description of the LinkMessages used to control it.
As such I hope, it will factor out some of the complexity for you.

CODE

// Indexed Sequential Access Method / Direct Access Storage Device
// data slice - A subscript of the ISAM/DASD componant of VK-Net
// Very Keynes - February 2008 tested in MONO and LSL2
// version 3.4 - 080210
//
//---------Technical Notes to aid in implementation---------------
//
// inter script communication:
//
// Commands are passed Via LinkMessages, parms are mapped as:
//
// link_message(integer tmp, integer num, string val, key arg)
// note: tmp may not be passed - used internally only.
// note: arg is further defined as - adr,ret,cmd,opt
// where: adr = script name being addressed
// ret = script name expecting the reply
// cmd = command to be processed
// opt = Optional parameter (not used in this module)
//
// Replys always appends the original arg to the reply arg
// so that the reciving scrip can understand the data returned
//
// Field content abbreviations:
// * - item is ignored
// [...] - item is optional
// rec# - record number (current record in reply)
// specifying rec# = 0 will address the column headers
// col# - column numbers starting at 1
// #recs - number of records
// #cols - number of columns
// mem - desired free space (free memory in reply)
//
// error format: num=err# val=* arg=ret,"err",arg
// error codes:
// num = -1 : not found
// num = -2 : incorrect number of fields passed
// num = -3 : slice is full
// num = -4 : invalid column number
// num = -5 : invalid record number
// if the command finished sucesfuly arg=ret,"ok ",arg
// is returned with num and val containing the data
//
// Command format in order of test/execution:
//
//System Commands
//
// Set and/or Return the current status of the slice:
// mem: num=[mem] val=* arg=adr,ret,"mem"
// reply num=mem val="#recs, #cols" arg=ret,status,arg
// note: if num >0 the low memory test will be adjusted to value of num
//
// Initialize the slice to type and define the column headers:
// new: num=type val="field names" arg=adr,ret,"new",
// reply num=mem val=adr arg=ret,status,arg
// note: supported file types (pass the numeric version in num)
// txt - 0 - Flatfile - single field per record no conversion
// dbx - 1 - Database file, unlimited fields per record CSV format
// idx - 2 - Index File, as above, with auto sort after each update
// note: Auto sort is by col#1 order is Ascending
//
// Sort the Table based on the 1st Field/Column:
// srt: num=[x] val=* arg=adr,ret,"srt",
// reply num=mem val=#recs, #cols arg=ret,status,arg
// note: if num != 0 sort Descending otherwise sort Ascending
// note: column headers are locked, rec#1 -> #recs are sorted
//
//data retrieval commands
//
// Find a record based on an Exact Match to the data supplied:
// fnd: num=col# val="search string" arg=adr,ret,"fnd",
// reply num=rec# val="Record Data" arg=ret,status,arg
// note: if col# > 0 only a match in that column is valid
// note: if col# = 0 a match in any column is valid
// note: error -1 returned if no match is found
// note: error -4 is returned if col# is not valid
//
// Return the current record in the Table:
// cur: num=* val=* arg=adr,ret,"cur",
// reply num=rec# val="Record Data" arg=ret,status,arg
//
// Return the first record in the Table:
// cur: num=* val=* arg=adr,ret,"fst",
// reply num=1 val="Record Data" arg=ret,status,arg
//
// Return the last record in the Table:
// cur: num=* val=* arg=adr,ret,"lst",
// reply num=rec# val="Record Data" arg=ret,status,arg
//
// Return the next record in the Table:
// nxt: num=* val=* arg=adr,ret,"nxt",
// reply num=rec# val="Record Data" arg=ret,status,arg
// note: error -5 is returned if rec# is not valid
//
// Return the previous record in the Table:
// prv: num=* val=* arg=adr,ret,"prv",
// reply num=rec# val="Record Data" arg=ret,status,arg
// note: error -5 is returned if rec# is not valid
//
// Return the record specified by rec#
// get: num=rec# val=* arg=adr,ret,"get",
// reply num=rec# val="Record Data" arg=ret,status,arg
// note: error -5 is returned if rec# is not valid
//
// Return a column of information specified by col#
// col: num=col# val=* arg=adr,ret,"col",
// reply num=col# val="Column Data" arg=ret,status,arg
// note: error -4 is returned if col# is not valid
//
//update commands
//
// Delete a record from the table:
// del: num=rec# val=* arg=adr,ret,"del",
// reply num=mem val=#recs, #cols arg=ret,status,arg
// note: column headers are locked, rec#0 cannot be deleted
// note: error -5 is returned if rec# is not valid
// note: mem is returned in the hope that this bug will be fixed in MONO
//
// Note: integrity test is performed for the following commands
// For dbx and idx types the number of data elements passed
// must match the number of fields defined else error -2
// is returned. txt files will accept any string value.
//
// Append a record to the end of the Table:
// add: num=* val="Record Data" arg=adr,ret,"add",
// reply num=rec# val=#recs, #cols arg=ret,status,arg
//
// Replace the record specified by rec#
// put: num=rec# val="Record Data" arg=adr,ret,"put",
// reply num=rec# val=#recs, #cols arg=ret,status,arg
// note: column headers are locked, so update rec#0 with care
//
//----------End of Documentation - Code starts here------------
//
//Default low memory test - adjust to suit your application
//for idx flies or if srt and col functions are requierd
//it should be set to 50% of space free on startup.
//i.e. 6500 for LSL2 and 30000 for MONO to be safe.
//note: mem may be adjusted at run time by the mem command.
integer mem = 6500;
//
// Do Not modify below this point, unless optimizing
// If you do optimize anything please drop a copy on me :)
//
//default type is idx - reset by new command
list data=["filename,adr"];integer sort = TRUE;integer stride = 2;

//working Variables
integer rec; //current record number
integer tot; //Total number of records in the table
string adr; //Slice Address
string cmd; //current command
list args; //[adr,ret,cmd,opt]
list lval; //val as list
float x;
//Functions
reply(integer num,string val,string msg){llMessageLinked(LINK_ROOT,num,val,llList2String(args,1)+","+msg);}

default
{
state_entry()
{
if(llGetStartParameter())llResetScript();//if spawned by redirect then reset
//determine name set by user or control/redirect pair and announce my presence
llMessageLinked(LINK_ROOT,llGetFreeMemory(),adr=llGetScriptName(),"all, created");
}

link_message(integer tmp, integer num, string val, key arg)
{
//decode the arg CSV format - adr,ret,cmd,opt
args=llCSV2List(arg);
if(llList2String(args,0)!=adr)return;//This command is not addressed to me so ignore it
cmd=llList2String(args,2);//extract cmd as it is used frequently

//Process cmd
//System Commands

// Set and/or Return the current status of the slice:
if("mem"==cmd)
{
if(0<num){mem=num;}
reply(llGetFreeMemory(),(string)tot+", "+(string)stride,"ok ,"+(string)arg);
return;
}

// Initialize the slice to type and define the column Headers:
if("new"==cmd)
{
if(0==num){data = [val]; stride=1; sort=FALSE;}
if(1==num){data = llCSV2List(val); stride=llGetListLength(data); sort=FALSE;}
if(2==num){data = llCSV2List(val); stride=llGetListLength(data); sort=TRUE;}
reply(stride,adr,"ok ,"+(string)arg);return;
}

// Sort the Table by the first Column:
if("srt"==cmd)
{
val=llList2CSV(llList2List(data,0,stride-1));
data = (data=[]) + llCSV2List(val) + llListSort(llDeleteSubList(data,0,stride-1),stride,!tmp);
reply(llGetFreeMemory(),(string)tot +", "+(string)stride,"ok ,"+(string)arg);return;
}

//data retrieval commands

// Find a record based on an Exact Match to the data supplied:
if("fnd"==cmd)
{
if(0 > num || stride < num)//invalid column number
{
reply(-4, "","err,"+(string)arg);
return;
}
x=llListFindList(data,[val]);
rec=(integer)x/stride;
x= 1+(stride*((x/stride)-rec));
tmp=(integer)x;
if(0!=rec)//Record was Found
{
if(0==num)//value was found and no column# was specified so return record
{
reply(rec,llList2CSV(llList2List(data,num=rec*stride,num+stride-1)),"ok ,"+(string)arg);
return;
}
else if(num==tmp)//column# matches so return record
{
reply(rec,llList2CSV(llList2List(data,num=rec*stride,num+stride-1)),"ok ,"+(string)arg);
return;
}
}
reply(-1,val,"err,"+(string)arg);//value not found in table
return;
}

// Return the current record in the Table:
if("cur"==cmd){num=rec;cmd="get";}

// Return the first record in the Table:
else if("fst"==cmd){num=1;cmd="get";}

// Return the last record in the Table:
else if("lst"==cmd){num=tot-1;cmd="get";}

// Return the next record in the Table:
else if("nxt"==cmd){num=rec+1;cmd="get";}

// Return the previous record in the Table:
else if("prv"==cmd){num=rec-1;cmd="get";}

// Return the record specified by rec#
if("get"==cmd)//get a record and return it
{
if(0 > num || tot < num){reply(-5, "","err,"+(string)arg);return;}
else if(1==stride){reply(rec=num,llList2String(data,num),"ok ,"+(string)arg);return;}//retain commas in txt files
else reply(rec=num,llList2CSV(llList2List(data,tmp=num*stride,tmp+stride-1)),"ok ,"+(string)arg);return;
}

// Return the column of information specified by col#
else if("col"==cmd)
{if(1 > num || stride < num){reply(-4, "","err,"+(string)arg);return;}
else {reply(num-1,llList2CSV(llList2ListStrided(llList2List(data, num-1, -1), 0, -1, stride)),"ok ,"+(string)arg);return;}
}
//update commands
// Delete a record from the table:
if("del"==cmd){if(1 > num || tot < num){reply(-5, "","err,"+(string)arg);return;}
data=(data=[])+llDeleteSubList(data,tmp=num*stride,tmp+stride-1);
reply(llGetFreeMemory(),(string)(--tot) +", "+(string)stride,"ok ,"+(string)arg);
jump internals;}//I hate jumps but had to skip to the internal processing

// decode the data string format - field1,field2,.....,fieldx
if(1==stride)lval=[val]; else lval=llCSV2List(val);
//test validity of data string
if(llGetListLength(lval)!=stride){reply(-2, "","err,"+(string)arg);return;}

// Append a record to the end of the existing Table:
else if("add"==cmd){cmd="put";num=tot+1;}//let put add the record to the table

// Replace the record specified by rec#
if("put"==cmd)//put (replace) a record in the table
{tot=(llGetListLength(data=(data=[])+llListReplaceList(data,lval,tmp=num*stride,tmp+stride-1))/stride)-1;
reply(rec=num,(string)tot+", "+(string)stride,"ok ,"+(string)arg);}

@internals;
//Internal Processing
//Auto Sort
if(sort){
val=llList2CSV(llList2List(data,0,stride-1));
data = (data=[]) + llCSV2List(val) + llListSort(llDeleteSubList(data,0,stride-1),stride,TRUE);}
tot=(llGetListLength(data)/stride-1);

//if mem is exceeded after executing commands send an Error to warn Caller:
if(llGetFreeMemory()<mem){reply(-3,"","err,"+(string)arg);}

//processing complete
return;
}
}


This is a sub component of a much larger system (still in development) but is usable as it is, without the controller script mentioned in the comments. The system will really come into it's own when MONO is released on the main Grid.
Chrysala Desideri
Scarlet Scriptrix
Join date: 4 Mar 2007
Posts: 65
02-11-2008 11:58
wow! looks fantastic....

but i think i've identified my particular problem (which doesn't get me that close to solving it).

what i need to set up would be a request for sets of memorised data... the parsing of the "columns" would be of great use, as except for the final call i do not need the entire string of the datum (sorry for misusing "slice" above! of course i meant the memorised string...) but rather the first CSV (not using commas, as i'm storing vectors, too,but you know what i mean)

i have a vague picture in my mind of how this would come out... my request for the menu page would be asking for, i guess a seperated string with the 1st SV of each of the the stored strings to be referenced on the page.

at this point it's getting embarrassing, as i know what i need to do but keep flaking out on explaining it and concretising in my mind what this request (and the linkmessage listen) would look like.

i'm thinking of requests like.. uh...

llMessageLinked(0,1,"menupage||PL1-PL11",[user key]);

getting an aswer like :

0,1,"Chateau Entrance||Piazza Gynoi||Mall-Casbah||DanceClub||Library||Temple||Villa Scarlatta||Palace||Garden||Torre Scarlatta||The Bagh",[userkey]

which wind up parsed and placed in llDialog description along with the button numbers made in lBaseList.

hmmm.... writing out the problem actually helps clear it up a bit. i need to parse the request to see the... mm beter if i phrase the request with all the things it needs, so when i get to "PL12+GL1+GL2+GL3+GL4+OL1+OL2" it sends the right stuff.....

ok rambling now but i think i may have understood something at this point. once more into the breach!

will be back sobbing and trembling later.

ciao!
Very Keynes
LSL is a Virus
Join date: 6 May 2006
Posts: 484
02-11-2008 15:51
It sounds like you are nearly there, and i agree, I have reams of paper that I scribble ideas down on, sometimes putting it in text rather than code really helps as do flow diagrams. Think laterally, rather than concentrating on your set idea of a protocol.

You can run several "slices", set one as flat file to store the vectors and never sort it so the record numbers are fixed. Then set one as DBX, or database, with the rest of the fields. The final slice is an index, which has 2 or more fields, one of them being the record numbers of the vectors. The index can be sorted and searched in any manner you wish and the record number then used to retrieve the menu information and the vector from the other 2 scripts.

Difficult to explain, and the next script in the set may simplify it.
How about we meet in world some time and I can tailor the scripts to fit your application and you can beta test my scripts for me in return? PM or IM me, I have IM to email set.