Jenna Felton
Resident-
Posts
38 -
Joined
-
Last visited
Reputation
11 GoodRecent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
That is the simplest approach. Both 'LSD containers' must have scripts installed with an access API between them. The API must implement access rules (who is allowed to read or write the store, which keys are read-only) and also specify formatting of the data. Especially when the access must be allowed between items of different owners and creators. But I'd rather wait with this until it is casted in marble that LL is not going to add an outside access to the LSD storage to the LSL. When this happens, the API with this access should be negotiated and added to SL wiki. But there is nothing that prevents anybody to invent this API for very own applications.
-
That is doable, have a free attachment slot then when collected some important data, attach a backup storage item, send the data to it, or when restoring data, read from it via chat commands and then detach after saving or reading the data. When using RLV it goes even automatically, otherwise needs user action, but then it is a little inconvenient. I hoped it would work automatically from the attachment itself, with any viewer and without an extra backup item. And without an experience because that is not something any resident can afford. There is an other Jira which was accepted, and maybe (probably not but nice to dream of ) was the reason to invent the LSD: A grid-wide KVP database to store data persistently. This can be an other solution if it is implemented.
-
Happy new year everyone Actually I wanted to discuss this in the next SL Server meeting but explaining the matter in few sentences would be difficult and easier to read here and maybe I will not come to asking there, so we can discuss here instead. It happens repeatedly (at least once every few weeks) that the viewer crashes and attachments are rolled back and some important data is lost. And it is not always data you can restore in few seconds. I was hoping LSD will persist crash rollbacks but apparently it was not designed for this but maybe we can use LSD to establish such a persistence. So I wanted ask few questions before I make a reasonable feature request if any. Question 1: Is it correct that attachment data is load from asset servers and then passed from sim to sim and stored back to the asset servers only when the attachment is detached or the owner logs out or crashed? Back in this thread it was claimed to be so, but not by a Linden, so I better ask to confirm. When it is not correct, the rest is maybe irrelevant. Actually it is naturally to do it this way: Attachments change their data permanently and it is wise to save the data when the attachments stop collecting it, i.e. on detach or on crash. However, I was thinking that detecting a crash works precise but because attachments seem to loose data to crashes sometimes, it seems that there are conditions preventing saving attachments on crash and LL can not fix them. Hence we can try the data loss prevention. First attempt: When the avatar is leaving a region, the region stores the attachment data to the asset servers when this data was changed while on the region. Not practicable because the relevant attachments change their state dozens of times on every region and we would overload the asset servers every time we leave a region. The system can not know which data is volatile and must not be saved and which has to be persistent. We need a way to tell the system which data must be kept persistent and which can be lost without problems. To do so, we could use the LSD storage: Attempt 2: When an attachment is leaving a region after the LSD store of the attachment was changed, the server stores the content of the LSD storage back to the asset servers. Whatever scripts want to keep persistent, they simply put on the LSD storage and when the attachment is attached, they load the actual data from there. As long scripts keep the important data in the LSD storage, crashes will not wipe them. Better but still not fully practicable yet: Some applications will use LSD storage to replace inter-script communication and those attachments will load the asset server needlessly like it was for the attempt 1, because the LSD storage will be changing permanently on every region. Hence the attempt 3: The 'persistent' keys: integer llLinksetDataWritePersistent(string name, string value); Creates or changes a persistent key. A key that was created this way is marked as persistent and can only be changed with this function; calling llLinksetDataWrite() for this key fails. A persistent key can be read normally with llLinksetDataRead(). Persistent keys are not protected. To have a key persistent and protected, we can write the data protected and use a secondary persistent key that changes every time the protected key does (like a revision number for persistent-protected data, but it can be even a boolean actually which flips.) Now, when leaving a region after a persistent key was changed on it, the server stores the entire LSD storage with this key back to the asset servers. Changing non-persistent keys will not mark the LSD storage as 'has to be stored'. This way scripts can change the LSD storage without loading the asset servers but once a persistent key was changed, the first leaving the region writes the data into asset servers. A bad crash looses only the data of the last region, not the progress of the entire day. Sometimes we can run into race conditions here: Leaving a region and changing the persistent key after arriving and before crashing. The leaving region detects crash as well and saves the LSD storage after the entering region already did, invalidating so the LSD content. To prevent this, the LSD storage would have a revision number. When attachment is rezzed, the revision number is reset to 0 on the asset server and rezzed link-set. Every time a persistent key changes, the revision number is increased. When a region server tries to store the LSD storage to the asset server, the data is only accepted when the revision number is newer than on the asset server. This avoids overwriting the stored LSD data with the older content. Now Question 2: Is it possible to write the LSD storage to asset server separate from the rest of the attachment? Can the structure of the attachment asset be organized in a way, that the LSD storage can be stored separately faster and more efficient than saving the entire attachment? When this is not the case than probably the whole attachment must be stored together with the LSD storage for persistence. Question 3: Is the suggested automatic LSD backup possible to tackle? When not, maybe it is more preferable to have a function that triggers the backup manually, e.g. after important data has changed: integer llLinksetDataStore(); The function would store the content of the LSD storage to the asset servers, or when the LSD storage can't be saved separately, then the whole linkset. The function may have a throttle per attachment and fail when called too frequent (be it more often than every 15 minutes) anywhere in the linkset.
-
I tried to keep the design of new functions close to the current ones, so that extending the system wont be too difficult. However I realized that scripts might want to close access to the LSD store even to scripts which owner has modify right to their linkset. Then the script would need to set a pin (not my idea actually but I can not find the post) llLinksetDataSetPublicAccessPin(integer pin); // when pin = FALSE, updating into LSD from outside is only open // when the linkset is modifyable, otherwise requires same pin. Edit: Actually the pin can be also a regular parameter for all public access functions that update the LSD store from outside. When the pin is not set to the LSD store, then access functions will use FALSE as pin and have success when the linkset is modifyable. Otherwise they use a pin number and have success when it is the correct one, regardless if the linkset is modify or not. This way no additional write, delete, reset functions are necessary.. And one more thing. Also not my idea, but I would also like to see the action parameter in the linkset_data event built of flags instead of being just a number. This way you can combine the actions WRITE, DELETE, RESET with additional parameters like PROTECTED (protected slot of LSD was updated), PUBLIC, CREATED (the key was created upon writing, and not just updated), etc. and so you can get a vast number of possible actions, and still be able to check them all easily.
-
This topic is still hot, so I thought maybe I add some more functions to the LSD family First, not fully replaceable but it would help scripts to prepare the LSD store without resetting the whole thing. And when reducing the event load like in the BUG-232792 is out of the table it will also reduce the count of generated link messages: integer llLinksetDataDeleteKeys(list keys, string password); The function takes a list of keys to delete and deletes those it can. The function will delete unprotected, protected keys and public keys (I come back on them later.) When it could delete at least one key, it will trigger only one linkset_data event, with the CSV of the deleted keys in the name parameter and the CSV of the keys if failed to delete in the value parameter. The return could be either the number of deleted keys or more generally one of three constants meaning for full success, partial success, full failure. When an unprotected key is to be deleted, the password parameter is ignored. A protected key is deleted if the password matches the one the key is protected with (and otherwise the deletion of this key fails.) Public keys are also protected with passwords, so they are handled the same as protected keys. Public keys Here the fun begins for all people who wait the access from outside the linkset: integer llLinksetDataWritePublic(string name, string value, string password); string llLinksetDataReadPublic(string name, string password); integer llLinksetDataDeletePublic(string name, string password); These functions create, update, read and delete public keys in the LSD store attached to the linkset the script runs in. I.e. 'from inside' the linkset the keys behave quite similar to protected keys. But these keys are also available for the public access: integer llLinksetDataWriteInto(key target, string name, string value, string password); string llLinksetDataReadFrom(key target, string name, string password); integer llLinksetDataDeleteFrom(key target, string name, string password); integer llLinksetDataResetInto(key target); list llLinksetDataListKeysFrom(key target, integer first, integer count); list llLinksetDataFindKeysFrom(key target, string regex, integer first, integer count); list llGetObjectDetails(key target, [OBJECT_DATA_AVAILABLE, OBJECT_KEYS_COUNT]); The functions take the key of an object and operate on the LSD store attached to the root prim of it. The naming is not important and using llGetObjectDetails also not copyrighted However, the functions operate only on the public keys in that LSD store. Especially the resetting only wipes out the public keys and leaves the protected and unprotected keys untouched, so the scripts inside the target not loose any data. Listing keys and the number of them also ignores protected and unprotected keys. Only DATA_AVAILABLE returns the free space, because the script can not know which of it will be used for comming public keys. Writing access 'from outside' is only available when the script has modify permission to the target linkset (in the next post I introduced a pin which lifts this restriction.) The functions trigger appropriate linkset_data events to be handled by the scripts running within the target linkset. The accessing script will not need any event (I think return value is sufficient.) Read access from outside will have the same restrictions llGetObjectDetails function has. Finally, issuing llLinksetDataWriteInto creates a key in the LSD store, when it was not there yet, and this key can be read 'from inside' the linkset via the llLinksetDataReadPublic function as if it was created via llLinksetDataWritePublic. This way scripts can provide data for free or secure access from other objects on the same region without using chat messages. We can use scripted and unscripted objects to create environments or experiences by providing required data in the LSD stores of these objects, in a way the object creators were not aware of. Even automatically, e.g. via scene rezzers.
-
I think the feature as it is will cover a wide range of applications. Now when it is released we will be able to write the applications and then when we get idea for applications which the LSD store in this definition can not or can hardly support, feature requests for enchanting it will follow. For example I can imagine a function that would wipe out a bunch of keys, protected with the same password. This way a plugin script which is leaving the build would not remove each key separately and overflow the event queue. This can be added after the release. Maybe I am wrong but I think the project is in a phase when it would only accept the last minute changes such that without them the LSD store definition would break future applications. But maybe I just wish it life before Christmas
-
When you not want that your neighbor eats your yogurt from the commonly used fridge, do not let them live with you. But when they move out and left back their pudding, you want to be able to clean the fridge despite there are yogurts and pudding with other's people names on them. Something like that Means do not install scripts that call llLinksetDataReset despite being plugins but the main script must be able to clean the database this way after the plugin scripts left protected keys after de-installation.
-
I think most of what was asked here can be done by using a script in the linkset and using it as an API: Chat messages for access the store from outside and link messages to access from within the link set (when the keys are protected). The script would respect the access level of the keys and allow or block the operation request. Only when we want to avoid extra script in every linkset using a LSD store, or the overhead of messages between scripts when the scripts could read and write to the store directly, then we need the inter-object access, access levels and pins. I think by now all of the applications using LSD store will have a script in them and so the current definition is sufficient. But I have a strong feeling requests about opening access from the viewer UI or from other objects will remain and follow and with it the access pins and levels. Because this will save the extra scripts and messages and allow interesting use cases. And because of that, I want throw something else into the round, but related. When the LSD store is only under control of one installed script, then this script can define the names of the keys fully as it wants. But when we want to give access to different scripts, made by different creators, or to let viewer access the store, than we need to invent a simple semantics. This way you can also link LSD stores and the keys will mostly not interfere. I suggest to build key names from hierarchical prefixes. connected by a dot. The first (main) prefix will identify the instance that (mainly) uses the key. For example I made a HUD and I'd like it to remember the position on screen, for every HUD slot. The script is the 'core' script, so I call the keys "core.pos.ltop", "core.pos.center", and so on. A plugin script for this HUD that is meant to style my attachments would use the main prefix "style" and the keywords would be e.g. "style.color.theme" or alike. When I want to allow others to write plugin scripts for my HUD, I'd have to define a system that allows the creators to name the keys so that they not clash. The simplest and safest way might be to use their avatar key or login name as main prefix. I would then define such system in the user manual for my HUD or give it with the dev kit I release. However, I'd also suggest to reserve the names of each TPV from the TPV list as prefix to avoid. And the prefix "viewer" as a common prefix to use by all viewers. The keys with them as main prefix will be used by the viewer when the viewer would get the direct or indirect access one day. When by then there will be objects on the market using the prefixes, then the viewer could have damaged the objects. As for viewer access applications. For example the viewer could store the last region and last position under keys "viewer.last.region", "viewer.last.position". Then not only firestorm will be able to rez the object at the position it was picked up and even then when the object was picked up with an other viewer or by someone else (when the keys remain stored.) Also, every TPV could then store the own information into the LSD store of a linkset under their own main prefix.
-
I was actually expecting that when the server finds some data of an object it can not handle, this data remains attached to the object and is passed over to the next region because it probably can handle the data. This way when LL deploys e.g. a server that for some reason forgot how to handle materials, walking into this region, while wearing a super expensive super rare gacha suit full of materials will not loose the materials, you can safely visit the region. But would the server drop the unknown properties, your suit is done. Loosing the unknown object properties brings extra pressure on LL to not deploy servers to Agni before all bugs that may destroy worn asset are fixed. Actually such bugs should not deployed to Agni anyways but they can happen. Passing over unknown object properties, like the LSD store, would reduce the danger of these bugs.
-
I've tested out my 'crash plan', all points passed. I tried some of the forced errors (Disconnection, llError, Bad Memory, Driver Crash) gave up testing all because same result. Crashing as soon as possible after adding keys to the LSD store or after teleport did not lose the content of the store or the new keywords. However, I could not force a crash which would lose changes to the script itself, and thus can not say if the LSD store will be more persistent than the linkset and scripts in there. But I have big hopes about this.
-
Thank you Rider, having protected keys is cool, but I'd like to have a way to get access to protected keys to some degree without having a password. Because there are applications extensible via plugins, be it scripts installed into the application or (never seen but possible) linked to core prim. The core script and the plugin script can be by different creators. Now the core script may want to maintain some keywords while plugin scripts would have only read access to them unless the developer or the core script made the write or deletion password known to the plugin script. I would suggest to create protected key like this: llLinksetDataCreateProtected(string name, string pass, integer level); while level defines if the key is read protected, write protected, delete protected. Write protection inherits read protection (read protected key needs password to be changed) Delete protection inherits read and write protection. Write protected keys can be read without password but not changed Delete protected keys can be read and changed without password but not deleted. Edit Better to separate creation of the key and actual writing because this will avoid to change the protection level every time you change the content. After the key is created it can be changed via llLinksetDataWriteProtected as defined.
-
I have created a test script which allows to reset the LSD, store and read keys of it, and it remembers the number of keys it has stored. My Test Plan which I'd like to see to pass at every point is this: Reset LSD store, add 2 keys, list them - the script must know there are 2 keys in store and the store must have them (pass) Add 2 keys, detach, reattach the HUD - the script must know there are 4 keys in store and the store must have them (pass) Add 2 keys, teleport out, teleport Back - the script must know there are 6 keys in store and the store must have them (pass) Add 2 keys, Crash the viewer, Relog - the script may think there are 6 keys in the store but the store must have 8 keys Add 2 more keys, Crash the viewer after 1 minute, Relog - the script may think there are 8 keys in the store but the store must have 10 keys Add 2 more keys, Crash the viewer after teleport out, teleport in, Relog - the script may think there are 10 keys in store but the store must have 12 keys Add 2 more keys, Crash the viewer after 15 min, Relog - the script may think there are 12 keys in store but the store must have all 14 keys I not know yet which viewer error I take for crashing it, maybe I try more than one, but by now the test failed already on TP into region that not supports LSD and teleport back (as reported in this JIRA, there you can also find the script and the test build). Why all the fuss. Sometimes my viewer crashes or internet disconnects. When I have bad internet sometimes, it can happen within 5 minutes online time and few of my friends have it quite often like this. When this happens, servers fail to write the state of the link set into asset servers, resulting in the loss of data and this data can be very important. And it is hard for the server to know which data is important on the particular link set and which is not. For example I bought a dress and use texture HUD to style it. I crash after styling, the texture is lost, but after log in i use the HUD again and all is back and propper. No big deal to loose this texture to a crash. Now imagine the creator of the dress invented a revolutionary system where the textures are applied in their store after I paid for them. I paid 1000L$, the dress got all styled, I tp home, crash, log in at infohub and all textures are gone. I may pay an other 1000L$ now. With Linkset Data we've got an excellent tool to explain the server which part of the linkset is important and has to be saved as soon as possible while the rest is of lower priority and must not survive any crashes. The texture receiver in my dress stores the textures into the LSD and then checks in on_rez() event if the stored data are newer than it knows and if so, it reads and reapplies it. Crashes are no more that bad any more. At the last user meetings i was told that the Linkset Data was meant to be persistent but I am not sure if my question was understood or the answer was that the LS Data was meant to survive script crashes and resets but not the linkset' crashes. When this level of persistency was not planned originally, I think to fill a feature request to ask for it. Edit The version in Jira not remembers the number of keys (represents the linkset state not covered by the LSD system), so when interested, please use this script in an 3 prim HUD: integer rows = 0; resetRows() { rows = 0; llLinksetDataReset(); listRows(); } listRows() { llOwnerSay("Num Rows (in script): "+(string)rows); integer size = llLinksetDataCountKeys(); list keys = llLinksetDataListKeys(0, -1); string text = "Num Keys (in store): "+(string)size; integer i; for (i = 0 ; i < size ; i++) { string name = llList2String(keys, i); text += "\n\t"+name+" -> "+llLinksetDataRead(name); } llOwnerSay(text); } addRow() { string name = (string)(llLinksetDataCountKeys() +1); string value = llGetTimestamp(); integer add = llLinksetDataWrite(name, value); rows = llLinksetDataCountKeys(); llOwnerSay("add row ("+name+" -> "+value+"): "+(string)add); } default { state_entry() { llSetLinkPrimitiveParams(1, [PRIM_TEXT, "add", <1,1,1>, 1]); llSetLinkPrimitiveParams(2, [PRIM_TEXT, "list", <1,1,1>, 1]); llSetLinkPrimitiveParams(3, [PRIM_TEXT, "reset", <1,1,1>, 1]); } on_rez(integer start_param) { listRows(); } touch_start(integer num) { num = llDetectedLinkNumber(0); if (num == 3) resetRows(); else if (num == 2) listRows(); else addRow(); } } Edit 2 Lucia answered in the Jira and named an other region that supports the system. Teleports between these regions retained the LSD data. So the point 3 is pass. Will continue with the test tomorrow.
-
I quite like this suggestion. Maybe the LSD would be attached not to the root link but to every prim in linkset? 64kB would be the alotment per object (linkset) and not per prim. To access the LSD a script would first open the LSD via the function integer llLinksetDataOpen(integer link, integer writemode, string password); The function would allow opening the LSD in any prim in the linkset, while using LINK_THIS would allow access to the LSD of the same prim, when really needs and allow to link the prims without the scripts damage the LSD from an other prim after linking. Delinking a prim would take the attached LSD with the prim, as well. The return value (LSD index) would address the LSD the script has opened (0 = FALSE means the script provided wrong password and can not use data functions). When you want to have access to LSD from multiple prims at same time, e.g. to add values from different stores, then this LSD index need to be provided in the data accessing functions. It would be also good to have the way to lock the LSD from changing by different scripts. For example when a script opened the LSD in write mode, no other script can do this and is delayed until the LSD is closed via llLinksetDataClose(integer index); As alternative, instead of using the number, returned by llLinksetDataOpen, the data function and llLinksetDataClose would accept the link number as reference of the LSD, since no link can have two LSD attached. Edit I not realized yesterday, letting scripts lock multiple LSD stores can lead to a circular lock where two or more scripts try to lock the same 2 or more stores in different order and lock out themselves. To avoid this, the scripts should be able only to lock different stores in the order of the LSD-associated link numbers. Or not delay when a script tries to open a locked store but receive an error response so the script can lift the lock on an other store and try again in a random while. Or we drop hard-locking completely (because it should ensure that two scripts not change the same store at same time destroying the data), but instead use the soft-locking in the manner of the Experience Tools: integer llLinksetDataUpdate(integer store, string name, string value, integer checked, string original_value); This will not prevent two scripts damage the same LSD store but they can detect if a store is in use and with some discipline on the scripter's end refrain from overwriting.
-
I could not test it yet (was just lucky to find in the BUG-232751 that this feature is live in Mauve in Aditi) but in that Jira is said Is it important to sort the keys in these functions? Because when I am just interested in the list of the keys without needs for order, the sorting is an overhead. When sorting not used internally, maybe it is better to drop it and when you need the keys sorted, you just wrap the output in llListSort? Edit: Ok, after I know the parameters, sorting is indeed needed. The functions return keys out of a certain range and for this you need a proper order to make the output deterministic.
-
Project Bento Feedback Thread
Jenna Felton replied to Linden Lab's topic in Building and Texturing Forum
Cathy Foil wrote: Those making and selling animations will want to clearly label their animations as "Rotations Only", "Rotations and Translations" or "Translations Only"... I think that is a good suggestion. But I think also mesh head creators will have to classify their mesh by what sort of expressions the mesh will accept. Because the customer buying the mesh head will rarely understand why the particular expression will not work with the mesh, but they can learn that some expressions will go and some not. They must not even understand what a rotation and what a translation is, but when they know this mesh fails on expressions using translation than they know which expressions the customer can look at and which are not worth of spending time for looking at the demos for them. Also, when the mesh head or fullbody uses the expression override (be it the suggestion of polysail or LL implements the feature request for it) this must be explained too, since that is a big plus in having predefined best looking expressions (since made by the mesh creator themselves) and probably simple to use new expressions made by third party. However, there will be a load of new information falling on the head of the to the mesh wearer and I think they have to be prepared for it. So I think there must be an explaining post somewhere targeting the customers and explaining that there is a slides vs. expressions problem, that some expressions can not work on some meshes, what an expression override is (if there will be a ready to use solution) and probably a simple to understand video about what translations and rotations are, how they affect the mesh and why some mesh can not accept translations in expressions. A bold request, sorry, but I myself am not good enough to make an easy to understand explaination and having deep understanding of the topics technically. Cathy Foil wrote: I probably am not explaining my self well enough. The program that is setup to use your web cam watches your face for expression and when it recognizes an expression say like when you smile it recognizes that you are smiling and sends a signal to the viewer you are logged in with to play a pre-recorded smile animation. So it wouldn't matter how big your smile was in real life it simply play the animation named "Smile". This can be done by expression overrider (assumed it is available.) The web cam program will just start recognized expressions and they will run overriding animations. Needs a service that sends signals from the clinent computer to the LL server running the agent. Can be done by LL or probably the web service which the expression hud worn by the avatar offers and client web cam program is registered into.