User:SuzannaLinn Resident/ScriptingClasses/Linkset Data
Linkset Data
Monday class
Linkset data
The linkset data is a permanent storage. It belongs to the object, not to the script.
The data stays there even if the script is reset or deleted. We can reset the script, modify and save the script, delete the script, and the data will stay there.
Ir's a list of pairs (key,value). In other programming languages, this is called a "dictionary".
Both key and value must be of type string, no matter what type the data really has.
We need to typecast to string when writing in the linkset data, and tytpecast back to the type of the data when reading.
It has a storage space of 128K. Scripts has a memory of 64K each.
Linkset Data stores the string in UTF-8, using 1 byte for the common characters. Script memory uses UTF-16, 2 bytes for each character.
Often the information in the Linkset Data information uses the double of space when copied to script memory.
Each object has its own linkset data. The object, not the prim. If an object has several prims linked, there is only one linkset data.
The data is accessible to all the scripts in all the prims of the object. We can write it in one script and read in another.
The advantages of the linkset data are:
- Permanent storage
- Bigger storage
- Shared for all the scripts in the object
Now if the script is reset we lose all the information. Or if we want to do some improvement in the script, we can't, because when saving the script is automatically reset.
And if we need to store many info the script will run out of memory.
Let's take a look at the functions that we will use with the linkset data.
To write we have llLinksetDataWrite( string name, string value ).
It stores "name" and "value". The "name" works as a key.
To get the information back we will use "name" as its key.
If later we write the same "name" with a different "value", the new "value" will be stored replacing the old one.
If "value" is an empty string, "name" is not written. Instead, if "name" already existed, it is deleted.
If we want to store only keys, like a list of avatar id's whom the script has given a notecard to avoid giving it again, we need to use a value, an white space for instance, " ".
To read there is llLinksetDataRead( string name ).
It returns de value associated with "name".
If "name" doesn't exist, it returns an empty string.
If we want to check if the key exists, we also use llLinksetDataRead() and check if the returned value is "".
We can see the linkset data as a list of string variables. The "name" is like the name of the variable and we assign a value to it, like doing "name=value".
llLinksetDataCountKeys( ) is used to know how much information we have stored.
It returns how many pairs (key, value) we have in the linkset data.
llLinksetDataReset() resets the linkset data.
It deletes everything that we have stored and leaves the linkset data empty. No way to recover it.
We need to be careful when using this function.
Reading the linkset data is slower than accesing the script memory.
If we have some data, not too big, that we use often in the script, is better to read it from the linkset data in the event state_entry and store it in variables.
Example: Quick notes
Please rezz the "Object 1 Quck Notes" that is in the Class Materials.
We are improving a script from the class Basics 3.
The idea is to store quick notes written in a channel, to be listed later.
The script listens to the owner in channel 7. In the previous version we stored the notes in a list, now we are going to store them in the linkset data.
Let's look at the script.
As keys we are using correlative numbers (typecasted to string), starting with 0, the values are the notes.
We have count, In line 2, to know the number of the next key. It's faster than using llLinksetDataCountKeys() each time.
In addNote(), lines 4-8, we write the note and increment the counter.
In sayNotes(), lines 10-16, we use "count" to loop on all the keys, and say the notes to the owner.
Let's go to state_entry, lines 20-24.
We get the total of keys. The first time, with the linkset data empty, it will be 0, Next times, after a reset of the script, we will recover the count.
And we start listening to the owner in channel 7 for the notes.
Going to listen, lines 26-38.
We need a way to delete the info, once we have listed and processed them. We do it typing RESET in uppercase.
If it is RESET we say the notes for the last time and delete them.
Otherwise we add the message to the notes.
In touch_start, lines 40-45,we say the notes to the owner.
And in changed, lines 47-53, in case of a new owner everything is reset. If we give the object, we don't want that the new owner see our notes.
More on Linkset Data
There is only one linkset data in each object, no matter how many linked prims it has.
And if we link two objects that both have a linkset data?
They are merged. If there are duplicate keys, one of them is lost. If they are too big, the (key,value) pairs that don't have space are lost.
And if we unlink a prim from a object that has a linkset data?
It is linked to the root prim. If we unlink a child prim, it will have an empty linkset data. If we unlink the root prim, the unlinked prim will have the linkset data, and the object will have an empty one.
Let's take a look to some more functions.
To delete a (key, value) pair we use llLinksetDataDelete( string name ).
If the "name" doesn't exist, it does nothing.
Using llLinksetDataDelete() is much more clear than using llLinksetDataWrite() with an empty string.
To get all the keys we have llLinksetDataListKeys( integer first, integer count ) .
It returns a list with the keys, starting at the index in "first" and returning a quantity of "count" keys (or less, if it arrives to the end of the linkset data).
Then we will loop in this list of key to get its values with llLinksetDataRead().
Why not returning all the keys at once? Because the linkset data storage is much bigger than the script memory, and sometimes we will not have enough free memoty in the script for it.
If we are sure that we have enough free memory we can get all the keys with llLinksetDataListKeys( 0, 0 ).
The data is automatically sorted alphabetically by the keys.
We will get the list of keys in alphabetical order, not in the order that we have written them.
llLinksetDataAvailable() returns the quanity of free bytes of storage in the linkset data.
When it is empty, there are 131072 bytes.
There is no limit in the length of key and values, other than the space available in the 128k.
We have to be careful to not write very long strings, because perhaps later we will not have enough free script memory to read them.
Example: List of Chatters
Please rezz the "Object 2 List of Chatters" that is in the Class Materials folder.
This is another script from the class Basics 3.
The idea is to count how many times each person has chatted in public, to be listed later.
We used two lists (for the chatter id's and the count of messages) to store the data.
Now we are using the linkset data. The key is the chatter id, and the value is the count of messages.
No global variables this time, which doesn't happen often.
In addListen(), lines 0-8, we add a new chatter or increase the count of messages if we already have the chatter.
We get the count in line 2, as always we get a string so we typecast it to integer.
If the chatter is not in the linkset data, llLinksetDataRead returns "", that becomes 0 when typecasted to integer.
If count is 0, we add the chatter with a starting count of 1.
If we already have the chatter, we increase the count.
We need the parentheses in
- (string)(count + 1)
with
- (string)count + 1 // WRONG !!!
it would typecast count to string, and try to add 1 to the string, throwing an error.
We could replace lines 3-7 with line 6 only. It does the same. We are detailing the process to show it more clear.
In sayChatters(), lines 10-22, we say all the chatters with their count of messages.
Now we don't have the keys from 0 to count. We have irregular values in the keys, which is the usual situation.
We get the list of keys in line 15 with llLinksetDataListKeys(0, 0).
We are reading all the keys together. We would get a script memory error with about 1,000 keys. But this is not expected to happen in this kind of script.
In other situations we would need to get the keys in chunks, of 500 keys, for instance:
- llLinksetDataListKeys(0, 500) // starting with key index 0, 500 keys
- llLinksetDataListKeys(500, 500) // starting with key index 500, 500 keys
etc, of course doing it in a for loop.
We loop on the keys, lines 18-21, to get each key in personId, and read the value with llLinksetDataRead.
getFullName(), lines 24-33, is the function that we used in the script in class Basics 3 to get the name.
It's a shortened version, you can compare it with the previous one.
The events are doing the same than in the script quick notes.
state_entry starts the listener, now listening to everyone in the public channel.
listen calls addListen() to add a new chatter or increase their count, or deletes the linkset data if the owner has said RESET.
touch_start list the chatters to the owner.
And changed resets everything in case of a new owner.
Answers to questions
Is it possible to have array of dictionaries in LSL?
- No, it's not possible in LSL, we will need to wait for Lua
What's the difference between an Object property and a Prim property?
- Object properties are shared by all the prims
- Prim properties are only for the prim, like the prim name, for instance
- Most of the properties are prim properties, color, size...
Storing in the linkset data, when the object is re rezzed it is lost?
- No, storing in the linkset data is never lost, this is one of its big advantages.
Can we store a set of individual notes and then read them all back as long as the object is rezzed?
- Yes, we can store lines of text, strings, each one with a different key, and we can read them at any moment, if the object is rezzed.
How do we know when it's reaching the storage limit?
- There is the function llLinksetDataAvailable() that returns the quantity of free bytes in the linkset data.
What kind of data is the linkset data usually used for?
- For all kind of data that comes in big quantities, there are plenty of uses, for instance:
- storing messages, info about people coming and going
- reading notecards and storing in linkset data
- statistics, visitor counters
- store user preferences
- Anything that we can store in a variable can be stored in the linkset data
Can we retrieve the list more than once, as the data accumulates?
- Yes, we can read the linkset data as many times as we want.
Is linkset data similar to global variables, with the difference that they stay alive after derezzing the object?
- All of them stay after derezzing, but globals variables disappear when resetting the script.
- Linkset data is even more global, because other scripts in the object have access to it.
- For instance, one script can read the config notecard and other scripts can get their configuration data without any message passing at all, its a way to exchange information among scripts.
Can we delete just one note ? Or all or nothing?
- Yes, we can delete only a note, a key in the linkset data.
If we take back the script into the inventory does it delete the data?
- If we remove the script from the object, the linkset data stays, if we add the script again to the object, we can list the notes.
Can we add other commands as well, like "RESET" in this script?
- Yes, we can listen for other commands and write a chain of if else if else if to check all the commands and do different actions.
Do we have in LSL something like 'case', or do we have to use many ifs?
- There is no "case" or "switch" command, only ifs.
If we're all using the same channel, will we confuse the script?
- No, because the script is only listening to the owner.
Do we have to reset our notes when we give it to someone else?
- lines 47-53 are only for the case that we have notes stored and we give the object to someone else, to delete the notes and avoid the others knowing our secrets, so when the object is transfereed to someone else, the linkset data is cleared.
What would happen if we choose channel 0 for channel notes?
- It would store as notes everything that the owner says in the public channel.
- The owner would make a record of everything that the owner has said in chat, but not other people because is only listening to the owner.
Would I have to write "/0" before saying the statements?
- No, no need to use /0, it's the channel by default when we say something.
What do we need to change if we don't want to listen to owner only?
- Replacing llGetOwner() with NULL_KEY in the function llListen(), everything said in local in its hearing distance would be recorded.
In the llinkset data, do the internal separators also count as chars?
- Only the strings that we store counts for the space, the internal separators doesn't count.
Has channel 0 a range?
- The range of listening is 20 meters from the center of the object where the script is.
Can we attach it to ourself as a HUD and sort of carry it with us?
- Yes, we can.
If an object is, let's say 20x20, does that change the range?
- No, it's always 20 meters from the center of the object.
Does (string)count just converts integers into strings?
- (string) converts any tipe of variable into a string, in this case an integer.
What count = llLinksetDataCountKeys(); does?
- This function returns the quantity of (key, value) pairs in the linkset data.
If we unlink the root prim will the linkset data still work?
- If we unlink the root prim, this unlinked prim will have the linkset data, the other prims will have it empty.
What are linked prims ?
- All the prims in the linkset/object, when an object have several prims, they are linked, so they are "linked prims".
- Sometimes excluding the root prim depending on the context.
Do you mean physical linking? for example having 2 cubes and linking them together?
- Yes, with the "link" option in the edit window.
Can we give 2 values the same key?
- No, the second value will replace the first.
Could anyone else have access to my Linkset Data? Maybe by a kind of ID/UUID, same as with notecards?
- No, no way, only scripts in the object can access the object's linkset data.
How much of the linkset data can we fit in our script?
- Our script is using parts of it's 64k for data, code, and everything else. Also if we're using the common latin alphabet our data will take up twice the space with UTF-16 in script memory that it takes with UTF-8 in linkset data. This means that the most data our script can process in a chunk will be something less then 25% of the space available to linkset data even with a tiny script.
Will people talking through objects, or with translators, be listened?
- Yes, everything that appears in the public chat is, the listener doesn't distinguish between objects and avatars except by matching names or keys.
Does the object have the same key as the owner?
- No, each object has a different uuid, to know the key of the owner there's the function llGetOwnerKey().
Are avatars and agents the same?
- Agent is the proper term for our presence in a sim. Avatar is the body we happen to be wearing at the time. But we often say Avatar when we really mean Agent.
Is it also 64k with Lua?
- Lua will have also 64k of script memory, but strings are stored in UTF-8, so much often they will take less space, also the compiled code is shorter.
Where is the linkset data stored? In what server?
- It is stored in the central server, all the time, and in the region server when the object is rezzed in the region.
A script can have access to only one linkset data?
- Yes, only the linkset data of the object where the script is.
Does the linkset data have its identifier?
- No, there is no uuid for the linkset data, it just goes with the object.
Why are we storing the uuids instead of the names?
- Here we are showing names, but storing data by UUID. Most often, we will want to use the UUID for data storage because it is guaranteed to be unique. The name could easily be anyones user name or display name, which, if we were storing by name, would cause conflation of data.