Multiple notecard loads, states, and 'dataserver'
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-20-2006 18:44
I tried live help, but my question was a bit too complicated to ask in that forum. (something I fully acknowledge). I am writing a script that will load data from 7 note cards. - One Main configuration file - Six data cards I want to load all 7 cards when the object is rez'd or when the owner resets the object. The reason for the pre-load is that I need the interaction of the object with the end user to be quick and loading each of the cards as they are called would cause a major delay between the option selection and the next dialog menu choice. Now, loading the Main configuration file is easy. I just call it up in the 'dataserver' process in the default state. The next 6 cards are giving me pause. I have thought of two possible ways to do this; neither one seems all that efficient and I am having problems figure out how to do them. Idea 1) I can create 6 states dedicated to loading the 6 cards. Once each state finishes, it calls the next state. Idea 2) I can can create a single 'preload' state and by changeing a global variable naming the card to load, I can call this state over and over again. Idea 1 is the quick and dirtyway to make it work, but I hate writing dedicated single-use functions in this manner. Idea 2 seems to be the most logical choice, I'm am not sure how to make it work. As best I can figure, I need to create two states to make this work. One state that does nothing but set the global notecardname variable and a second state that is called, loads the data, and then calls the 'loop state' to gett he notecardname variable incremented. There has to be a better, more efficient, less 'hackish' way of doing this.
Is there a way to call the 'dataserver' process within a single state multiple times without having to leave and re-enter the state? Any assistance in this matter would be *greatly* appreciated.
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|
|
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
|
05-20-2006 19:04
You could use a list of notecard names and one preload state to get the job done: list NOTECARDS = ["card1", "card2", "card3"];
integer curCard; integer curLine; key curReq;
list keys; list values;
default { state_entry() { state loadConfig; } }
state loadConfig { state_entry() { // Reinitilize relevant global variables: curCard = curLine = 0; // Get first line of first notecard in NOTECARDS list: curReq = llGetNotecardLine(llList2String(NOTECARDS, curCard), curLine); }
dataserver(key req, string data) { if (req != curReq) return; if (data != EOF) { // Read and parse the line in the current notecard: list parsed = llParseString2List(data, ["="], []); if (llGetListLength(parsed) == 2) { keys += llList2String(parsed, 0); values += llList2String(parsed, 1); }
// Get the next line in the current notecard: ++curLine; curReq = llGetNotecardLine(llList2String(NOTECARDS, curCard), curLine); } else { // We're done with this noteacard. ++curCard; if (curCard < llGetListLength(NOTECARDS)) { // We have more notecards to read: curLine = 0; curReq = llGetNotecardLine(llList2String(NOTECARDS, curCard), curLine); } else { // We're done with all notecards. state loaded; } } } }
state loaded { state_entry() { llOwnerSay("Notecard configuration loaded."); } }
Here I load three cards named "card1", "card2" and "card3". In each, Im assuming each line dictates a key-value pair. For example: color=blue food=cookie phrase=w00t
The keys (before the = sign) are loaded sequentially into the keys list, and the values (after the = sign) are loaded sequentially into the values list so that their indexes correspond. (index 0 in keys is "color", index 0 in values is "blue", etc) This lets you search the keys list using llListFindList, for the index to find the key's associated value in the values list. (llList2String(values, llListFindList(keys, ["food"])) obtains the value for the food key.) Edit for readers unfamiliar with non-LSL programming: Im referring to keys and values here in a hashtable's context; "keys" has nothing to do with LSL's key type or asset UUIDs (er, they do, for you database-aware people, but lets not get more confused here  ). In a dictionary, for example, keys are words and values are those words' definitions. Keys are simply pieces of known data you use to look up/search for associated unknown data. Hope this helps  ==Chris
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-20-2006 19:16
I'm storing all the data in the cards as pipe-delimited strings and then parsing them into separate lists as they load. This is done because the notecards are user editable and need to be stored in a easy-to-edit manner. Cool. Thanks. I'll hack that up and give it a shot. Now the big question.... WHY does that work? I guess more specifically, how does the dataserver process work? How does it know that the request handle has changed? Is it constantly polled and/or searching for data? Does this mean I need/should create a state for the main functions of my scripts that deos not include that process to cut down on server lag and load? Totally off-topic, when you are doing a dataserver load from a notecard, this is the best if statement ever created. if ( llGetSubString (data, 0, 0) != "#" && llStringLength (data) > 0 ) { // Is it a comment?I got it from the EVN Vendor system (GNU/OSS) and has my life a thousand times easier. It will ignore any line that starts with a blank space and/or a hash. In other words, it lets you have comments in your note cards so you can better describe how the data should look.
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|
|
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
|
05-20-2006 19:32
The dataserver is just like any other event. Lets say you called llSetPos in state_entry. If you declared a moving_start event, a new moving_start event will get pushed on the script's event queue. Once state_entry has completed, the next event in the queue will be run, and assuming no other events were queued before you called llSetPos, moving_start will then execute.
If you call llSetPos within moving_start, another moving_start event will be pushed onto the queue. After the current running moving_start event completes, the next moving_start event will run. (and so on and so forth, ad infinitum)
llGetNotecardLine and dataserver work in almost exactly the same way. If you call llGetNotecardLine within the dataserver event, another dataserver event will be pushed onto the event queue, and will be run after the current running dataserver event completes. This is why we use global variables to track our position within the current notecard and within the NOTECARDS list. Once dataserver tells us we've reached the end of our current notecard, we go to the next notecard in the NOTECARDS list and start from the top or, if there are no more notecards remaining in the NOTECARDS list, we switch to the loaded state.
I track the key returned from llGetNotecardLine just to make sure dataserver reqeuests are: A. Coming to the script from the asset server in order, and B. Not originating from another script within the same prim. (All scripts within the same prim receive a dataserver event regardless of which script called the llGetNotecardLine function.) ==Chris
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-21-2006 21:14
For those that are interested, this solution DOES work.
However, I've now run into memory limit issues, so unfortunately, I won't be able to use this.
Instead, I need to write a separate script for each card that is loaded and use Link messages to get the data loaded.
*sigh*
At least I'm learning the LSL language this way...
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|
|
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
|
05-22-2006 04:38
Androclese, don't give up yet! There may be a way to use strings instead of lists-- this is much, much more memory efficient.
Perhaps you can describe more fully the intent of the script and the data that you are parsing, and there might be a way to help you.
Also, if Live Help isn't knowledgeable enough, try the Scripting Mentors -- look in my signature for a link.
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-22-2006 07:18
I'm being purposely obtuse about the function of my application since, to the best of my research, nobody has done it yet; not like this anyway. I want to be the first to market. *grin*
Truth be told? My application is working a lot better when broken up into multiple scripts. It's actually flying now. The load time is 10x's as fast and the response is time is near instant with the dialog menu. I'm able to break the functions of the application up across each of the different scripts, call them to execute through a linked message, and balance my memory usage. As a pure exercise in function, I'm experimenting with putting the same functions into each of the scripts, and giving them each their own LinkMessage call. They will check the current memory usage of their script, report it back to the Primary script. The primary script then decides which script should execute the function based on memory usage. I may or may not have any practical use, but it's still fun to work on. The *only* issue I'm having is trying to sync up the different scripts to tell the master script when the application as a while is ready for use. My current train of thought is to send sync messages to the primary script, but I'm not sure how to collect and process the data since they 6 messages will be sent asynconyous. The best solution so far seems to be to put a timer event on the activation of the touch_start function, but that seems to be a bit hackish, especially if the server is lagging, the real start up time might be longer than the scripted timeout.
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|
|
Draco18s Majestic
Registered User
Join date: 19 Sep 2005
Posts: 2,744
|
05-22-2006 09:28
From: Androclese Antonelli The *only* issue I'm having is trying to sync up the different scripts to tell the master script when the application as a while is ready for use. My current train of thought is to send sync messages to the primary script, but I'm not sure how to collect and process the data since they 6 messages will be sent asynconyous.
If you mean finding out when all the sub-scripts have sent their data to the main script, try adding a boolean variable to each the link message checks (changing them from False to True) and afterwards (in the link message event, outside all the ifs) check to see that they are all True. (Bools can be hacked by using an integer. if(0) is false if(1) is true (so is if(2) and any other non-zero number), so your variables could be bool_message_1 = 0, bool_message_2 = 0, and bool_message_3 = 0 and check if(bool_message_1 && bool_message_2 && bool_message_3) and then send the main script to the next state.)
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-22-2006 10:43
From: Draco18s Majestic If you mean finding out when all the sub-scripts have sent their data to the main script, try adding a boolean variable to each the link message checks (changing them from False to True) and afterwards (in the link message event, outside all the ifs) check to see that they are all True. (Bools can be hacked by using an integer. if(0) is false if(1) is true (so is if(2) and any other non-zero number), so your variables could be bool_message_1 = 0, bool_message_2 = 0, and bool_message_3 = 0 and check if(bool_message_1 && bool_message_2 && bool_message_3) and then send the main script to the next state.) That part I got, but since the data comes in out of order, I'm not how to actually process it or how to control the "waiting" state while the sub scripts finish up. At current, this is my setup: Whether the object is newly rez'd or Reset, all the scripts drop into their default state. The Master script sends out a link message to the sub scripts to reset themselves. The sub-scripts needs this message because they are not coded to reset by themselves. The sub scripts process their data, loading the note cards and storing the information in their memory. (here is where I get stuck) Once each sub script finishes loading, it goes into a standby state, waiting for a link message so it knows to take action and use the data it is storing. The default action for this state is to send a Link Message out to the primary script, telling it has completed its task. This is based on your concept: The primary script, when it fires up, sets 6 variables to FALSE. As each sub script finishes, it sends its status to the primary script and the primary script records its status. Since I can pass both an integer and a string value through Link message, I can set both the status of the sub script TRUE/FALSE to determine if it has completed loading the datacars, I can also set the result of that load, SUCCESS, BLANK, or FAIL (in case the card is blank or not there). As each status comes in, the flag is set and the primary script then scans all the status flags and when it finds that 6 flags have been set, THEN it goes into the active state. This is just me brain-storming here. What do you think?
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|
|
Joannah Cramer
Registered User
Join date: 12 Apr 2006
Posts: 1,539
|
05-22-2006 10:46
From: Androclese Antonelli The *only* issue I'm having is trying to sync up the different scripts to tell the master script when the application as a while is ready for use. My current train of thought is to send sync messages to the primary script, but I'm not sure how to collect and process the data since they 6 messages will be sent asynconyous. Overly simplistic way to go about it, but... in the main script, during initialization: integer cards_loaded = 0 integer cards_total = 6 (sub-scripts send generic CARD_LOADED message when they are done) in main script in linked message event: if( Message == CARD_LOADED ) ++cards_loaded; if( cards_loaded == cards_total ) state up_and_running; ... this operates on presumption loading process for sub-scripts is triggered by the main script when it finds it suitable.
|
|
Androclese Antonelli
Org. B-Day: 05/11/04
Join date: 25 Apr 2006
Posts: 96
|
05-22-2006 13:14
From: Joannah Cramer Overly simplistic way to go about it, but... in the main script, during initialization: integer cards_loaded = 0 integer cards_total = 6 (sub-scripts send generic CARD_LOADED message when they are done) in main script in linked message event: if( Message == CARD_LOADED ) ++cards_loaded; if( cards_loaded == cards_total ) state up_and_running; ... this operates on presumption loading process for sub-scripts is triggered by the main script when it finds it suitable. That is almost exactly what I've got working now. I'm using the ability to send two messages through a linked message to also send the status of that process and the datacard load: - Through the integer value, I'm calling a process in the primary.
- Through the string value, I'm sending the state of the sub script. 0/1 aka FALSE/TRUE. Yes, in this case, FALSE is a valid value.
- Through the key value (just another string) I'm sending the result of the sub string's actions. Success, Failure, Empty.
This is cool, I'm finally (slowly) getting the hang of LSL.
_____________________
The Sculpted Garden Originally Born 5/11/2004 - New AV, Old Player. If you leave the game, don't delete your account, just make it 'free'. You'll lose your inventory like I did. *sniff*
|