Read once? OK. Read many times? No way.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 09:07
Here are the guts of a script that has been bugging me for the past couple of days. Basically, it's a heart of a data storage system that lets a user put information in a stack of notecards and then browse through them sequentially later. Once it reads a card, it gives the user the option of reading the next card and so on, until it reaches the last one. At that point, it is supposed to go back and let the user browse the set again, starting with the first card. It does that, but on the second and successive passes through it can't seem to read all lines on a card. It reads a random number of lines on any card (not the same number each time) and ignores the rest. Here's the stripped-down script ...... list Choice = []; list URLs = []; integer listener; integer MENU_CHANNEL = 1000; key user; string gName; key gQueryID; integer gLine; integer Lines; integer cardNo = 0;
ResetLists() { Choice = []; URLs = []; Lines = 0; }
default { state_entry() { if (llGetInventoryNumber(INVENTORY_NOTECARD) < 1) { llOwnerSay("There's no notecard in this device."); } else { gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } } on_rez(integer num) { llResetScript(); }
dataserver(key query_id, string data) { if (query_id == gQueryID) { if(data != EOF) { if ( llGetSubString(data, 0, 0) != "#" && llStringTrim(data, STRING_TRIM) != "" ) { Choice += llStringTrim(llGetSubString(data,0,llSubStringIndex(data,"|")-1),STRING_TRIM); URLs += llStringTrim(llGetSubString(data,llSubStringIndex(data,"|")+1,-1),STRING_TRIM); ++Lines; } ++gLine; gQueryID = llGetNotecardLine(gName, gLine); } } } touch_start(integer total_number) { listener = llListen(1000,"","",""); llOwnerSay("There are "+ (string)llGetListLength(Choice)+ " items in the Choice list."); llDialog(llGetOwner(),"Click this button",["New Card?"],1000); }
listen(integer channel, string name, key id, string message) { if (message == "New Card?") { ++ cardNo; llOwnerSay("# of notecards = "+ (string)llGetInventoryNumber(INVENTORY_NOTECARD) + " cardNo = " + (string)cardNo); if(llGetInventoryNumber(INVENTORY_NOTECARD) > cardNo) { ResetLists(); gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } else { llOwnerSay("You have sampled all notecards in inventory. Returning to card #1."); ResetLists(); cardNo = 0; gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } } } }
I've tested it with a set of two cards. One has 21 lines; the other has 17. Here are results of a few passes ... [8:07] Object: There are 21 items in the Choice list. [8:07] Object: # of notecards = 2 cardNo = 1 [8:07] Object: There are 17 items in the Choice list. [8:07] Object: # of notecards = 2 cardNo = 2 [8:07] Object: You have sampled all notecards in inventory. Returning to card #1. [8:07] Object: There are 6 items in the Choice list. [8:07] Object: # of notecards = 2 cardNo = 1 [8:07] Object: There are 3 items in the Choice list. [8:07] Object: # of notecards = 2 cardNo = 2 [8:07] Object: You have sampled all notecards in inventory. Returning to card #1. [8:07] Object: There are 6 items in the Choice list. [8:07] Object: # of notecards = 2 cardNo = 1 [8:07] Object: There are 4 items in the Choice list. [8:08] Object: # of notecards = 2 cardNo = 2 [8:08] Object: You have sampled all notecards in inventory. Returning to card #1. [8:08] Object: There are 5 items in the Choice list. [8:08] Object: # of notecards = 2 cardNo = 1 [8:08] Object: There are 6 items in the Choice list. [8:08] Object: # of notecards = 2 cardNo = 2 [8:08] Object: You have sampled all notecards in inventory. Returning to card #1. Can anyone help me see the error of my ways?
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Cerise Sorbet
Registered User
Join date: 8 Jun 2008
Posts: 254
|
01-31-2010 09:49
Hi Rollig, how soon do you touch to see the line numbers? llGetNotecardLine is very slow with 0.1 second delay. It is good to have a lock variable set at the first line, unlock when EOF happens. Then the touch event can so go away I am not ready yet!
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 10:01
 That's it, Cerise. I'm just not patient enough. At your suggestion, I tried waiting 10 seconds before clicking the dialog button. It works every blessed time. Thank you. Because other people are likely to be at least as impatient as I am, I'll go back and throw a timer into the system to slow down the compulsive button pushers.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Ron Khondji
Entirely unlike.
Join date: 6 Jan 2007
Posts: 224
|
01-31-2010 10:09
You could use states instead of a timer. One state to read the notecards and another with the touch and dialog stuff.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 10:10
That's true. I tend to avoid switching states usually, but this might be a good place to do that. I'll play with it.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Cid Jacobs
Theoretical Meteorologist
Join date: 18 Jul 2004
Posts: 4,304
|
01-31-2010 10:38
I would use llGetAndResetTime().
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 11:54
From: Cid Jacobs I would use llGetAndResetTime(). I wouldn't have thought of that. It doesn't leap out and look like an obvious way to handle this problem. Tell me more.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Twisted Pharaoh
if ("hello") {"hey hey";}
Join date: 24 Mar 2007
Posts: 315
|
01-31-2010 11:59
I was thinking about something along that line: list Choice = []; list URLs = []; integer listener; integer MENU_CHANNEL = 1000; key user; string gName; key gQueryID; integer gLine; integer Lines; integer cardNo = 0; integer Reading = FALSE ; ResetLists() { Choice = []; URLs = []; Lines = 0; }
default { state_entry() { if (Reading) { Reading = FALSE ; } else { if (llGetInventoryNumber(INVENTORY_NOTECARD) < 1) { llOwnerSay("There's no notecard in this device."); } else { gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); state reading ; } } }
touch_start(integer total_number) { listener = llListen(1000,"","",""); llOwnerSay("There are "+ (string)llGetListLength(Choice)+ " items in the Choice list."); llDialog(llGetOwner(),"Click this button",["New Card?"],1000); }
listen(integer channel, string name, key id, string message) { if (message == "New Card?") { ++ cardNo; llOwnerSay("# of notecards = "+ (string)llGetInventoryNumber(INVENTORY_NOTECARD) + " cardNo = " + (string)cardNo); if(llGetInventoryNumber(INVENTORY_NOTECARD) == cardNo) { llOwnerSay("You have sampled all notecards in inventory. Returning to card #1."); cardNo = 0; } ResetLists(); gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); state reading ; } } }
state reading { on_rez(integer num) { llResetScript(); } state_entry() { Reading = TRUE ; gQueryID = llGetNotecardLine(gName,gLine); } dataserver(key query_id, string data) { if (query_id == gQueryID) { if(data != EOF) { if ( llGetSubString(data, 0, 0) != "#" && llStringTrim(data, STRING_TRIM) != "" ) { Choice += llStringTrim(llGetSubString(data,0,llSubStringIndex(data,"|")-1),STRING_TRIM); URLs += llStringTrim(llGetSubString(data,llSubStringIndex(data,"|")+1,-1),STRING_TRIM); ++Lines; } ++gLine; gQueryID = llGetNotecardLine(gName, gLine); } else state default ; } } }
You can do almost the same without states but that would be confusing because you would have to prevent the user to touch the object or select menu.
|
Twisted Pharaoh
if ("hello") {"hey hey";}
Join date: 24 Mar 2007
Posts: 315
|
01-31-2010 12:13
From: Rolig Loon I wouldn't have thought of that. It doesn't leap out and look like an obvious way to handle this problem. Tell me more. That would let you measure the time between two touch events I think.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 12:21
From: Twisted Pharaoh That would let you measure the time between two touch events I think. Yes, I can see that. Like the timer approach, though, it seems a bit ad hoc. Following Ron's suggestion instead, I have rebuilt the script along much the same lines as you just did, using states. I can't test it until I can get in world again this evening, but I think this is the way to go. Thanks. 
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|
Pale Spectre
Registered User
Join date: 2 Sep 2005
Posts: 586
|
01-31-2010 12:32
If you want to avoid states the 'locking' method suggested by Cerise is also fool-proof... list Choice = []; list URLs = []; integer listener; integer MENU_CHANNEL = 1000; key user; string gName; key gQueryID; integer gLine; integer Lines; integer cardNo = 0; string status;
ResetLists() { Choice = []; URLs = []; Lines = 0; }
default { state_entry() { if (llGetInventoryNumber(INVENTORY_NOTECARD) < 1) { llOwnerSay("There's no notecard in this device."); } else { llOwnerSay("Please be patient while the choices load..." ; status = "LOADING"; gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } } on_rez(integer num) { llResetScript(); }
dataserver(key query_id, string data) { if (query_id == gQueryID) { if(data != EOF) { if ( llGetSubString(data, 0, 0) != "#" && llStringTrim(data, STRING_TRIM) != "" ) { Choice += llStringTrim(llGetSubString(data,0,llSubStringIndex(data,"|")-1),STRING_TRIM); URLs += llStringTrim(llGetSubString(data,llSubStringIndex(data,"|")+1,-1),STRING_TRIM); ++Lines; } ++gLine; gQueryID = llGetNotecardLine(gName, gLine); } else ( status = "READY"; llOwnerSay("...finished loading the choicess." ; llOwnerSay("You are now ready to begin. " ; } } } touch_start(integer total_number) { if (status == "LOADING" llOwnerSay("Sorry, the choices are still loading... I'll tell you when it's ready. " ; else { listener = llListen(1000,"","",""); llOwnerSay("There are "+ (string)llGetListLength(Choice)+ " items in the Choice list."); llDialog(llGetOwner(),"Click this button",["New Card?"],1000); } }
listen(integer channel, string name, key id, string message) { if (message == "New Card?") { ++ cardNo; llOwnerSay("# of notecards = "+ (string)llGetInventoryNumber(INVENTORY_NOTECARD) + " cardNo = " + (string)cardNo); if(llGetInventoryNumber(INVENTORY_NOTECARD) > cardNo) { ResetLists(); gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } else { llOwnerSay("You have sampled all notecards in inventory. Returning to card #1."); ResetLists(); cardNo = 0; gLine = 0; gName = llGetInventoryName(INVENTORY_NOTECARD,cardNo); gQueryID = llGetNotecardLine(gName,gLine); } } } }
|
Cid Jacobs
Theoretical Meteorologist
Join date: 18 Jul 2004
Posts: 4,304
|
01-31-2010 20:05
if(llGetTime() < x) { no go} else {llResetTime(); go}
|
Twisted Pharaoh
if ("hello") {"hey hey";}
Join date: 24 Mar 2007
Posts: 315
|
01-31-2010 20:09
From: Pale Spectre If you want to avoid states the 'locking' method suggested by Cerise is also fool-proof... That works but you need to lock the listen handler as well "just in case" the user stacks the menus open.
|
Cerise Sorbet
Registered User
Join date: 8 Jun 2008
Posts: 254
|
01-31-2010 20:39
dataserver is a separate process. It is good most times but it can hang up. A timer is good to look for a dataserver stall, a notecard failure is not usual but it can happen. A timer is not best for input wait, EOF is the right condition to watch.
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
01-31-2010 20:47
Well, I learn something every day. Until now I hadn't realized how much inherent delay there can be in a dataserver event. I tried two or three methods, just for the heck of it, and ended up splitting the script into two states along the lines that Twisted suggested. The full version of the script now works very nicely, so I thank you all.
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|