Jump to content

Saving information


Olivia Rizzo
 Share

You are about to reply to a thread that has been inactive for 1741 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I am thinking of writing a script that records who visits our parcel then we know who has been there. Possibly then the device could speak to them (in nearby) if they are not on a whitelist. But also we don't want it to repeatedly say the same thing as that would be annoying.

I got as far as getting the list and counting it using this:

list avatarsInRegion = llGetAgentList(AGENT_LIST_PARCEL, []);
integer numOfAvatars = llGetListLength(avatarsInRegion);

Now I have done that I hoped to go through the avatars and record them. But I have just discovered it is not possible to write to a notecard, only read.

Is there any SL way of recording information like this?

The only other way I can think is with an external web service / API but then that all gets a lot more complicated to set up.

Link to comment
Share on other sites

Without an external API, as far as I know, you can only keep residents in memory and do some pruning on a daily / weekly basis. Sure, you can try to keep data in (limited) invisible hover text, child prim names, slave scripts via linked messages, do kvp etc. but at the end, you'll make it even more complicated. Still, if you make your code small and robust (like, keeping only avatar keys on that list), you should have around ~30-40 KBs of free space to spare.

Can be useful:

 

Edited by panterapolnocy
  • Thanks 1
Link to comment
Share on other sites

You have few options.  If you have an Experience to work with, you can save information in KVP -- essentially dumping it into an LL server.  If not, you'll have to store your list in your own script, shove it off to another utility script, or send it to an off-world server.  If you'd like to save it in your own script or a helper script, you might want to look at  http://wiki.secondlife.com/wiki/User:Rolig_Loon/High-Capacity_Greeter-Counter .  That's a somewhat old script now, but it still works quite well and can save an amazing amount of information in compressed form before it hits a limit.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

9 minutes ago, Wulfie Reanimator said:

You can safely keep at least a couple hundred avatar keys in your script's memory.

During one of my tests, I've found that at least 600 keys will fit into a list, but it will cause a stack heap collision before it reached 650 IIRC.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

How long do you want to hold on to the data? If it's for a short period, you could do as Wulfie suggests and keep the list in the script's memory, clearing it out periodically or as it gets too close capacity. The LSL wiki contains several example scripts for what you describe, known as "greeters". Some of them even employ compression to store lots and lots of avatar keys at once. Rolig's high capacity greeter is a great example.

Another option would be to use the Key-Value-Pair database that comes with each Experience as a way to store data within Second Life. Though that requires some extra setup and it very likely overkill for the application of a humble greeter.

Edited by Fenix Eldritch
typos
  • Thanks 1
Link to comment
Share on other sites

Thanks everyone - super helpful and so quickly!

I won't go through and quote reply everyone but I have taken all that in. I think keeping them in the script memory is fine for our purposes.

I kind of forgot that even when we log out the scripts keep running. I assume region restarts would cause them to be reset though?

Maybe I will look into storing KVPs with an experience as an upgraded version once I get the basic thing running. And I will certainly look into greeters! I know this thing probably already exists but I want to write my own so I can learn better.

  • Like 1
Link to comment
Share on other sites

2 minutes ago, livb89 said:

I kind of forgot that even when we log out the scripts keep running. I assume region restarts would cause them to be reset though?

You would think that, but no. A region restart does not reset any script, unless it is specifically designed to do so.
Look into the changed() event if you want to write a script that resets upon region restart.


 

Edited by Fritigern Gothly
Improved my answer
  • Thanks 1
Link to comment
Share on other sites

4 minutes ago, livb89 said:

And I will certainly look into greeters! I know this thing probably already exists but I want to write my own so I can learn better.

By all means, use it as an example and tweak/rewrite to suite your specific needs. It's one of the best ways to lean. :)

  • Like 1
Link to comment
Share on other sites

7 minutes ago, Fritigern Gothly said:

During one of my tests, I've found that at least 600 keys will fit into a list, but it will cause a stack heap collision before it reached 650 IIRC.

Note that I said "safely." The absolute maximum amount of keys you can put into a list doesn't tell you what's practical. How big is the rest of the script? What else does it need to keep in memory? What kinds of operations does it need do on that list?

100 keys is about 9KB in Mono, which isn't very much. 100-300 keys is probably doable in most cases, but we need to know more before making any assumptions.

  • Like 1
Link to comment
Share on other sites

The script that I referenced uses compression techniques to jam a lot more unique partial keys into the script.  I don't recall how many I have been able to fit in it, but it was something like a couple of thousand.  And when it nears a limit, it starts deleting he oldest ones.  Even if you're writing your own script, it's worth looking to see how it works.

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

3 minutes ago, Wulfie Reanimator said:

What kinds of operations does it need do on that list?

I am thinking it will record which avatars are present (checking say every 60 seconds) then it will record when they were there and possibly how long for. So a list of keys and maybe a parallel list of timestamps.

The owner will be able to click to see the list. Basically a security system of sorts with a greeter built in. A more polite system than a security orb, kinda. Anyone on our whitelist gets a more welcoming message :)

Link to comment
Share on other sites

Try storing part of the UUID and an abbreviated timestamp as a single list element  ( time + "~" + UUID, maybe). Then periodically -- every few hours, every week, whatever ... -- delete list elements with the oldest timestamps.  Those will always be the ones at the start of the list.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

16 minutes ago, Wulfie Reanimator said:

The absolute maximum amount of keys you can put into a list doesn't tell you what's practical.

I never said it was practical, but I have noticed that many people are afraid to put more than just a handful of values in a list. My intention was only was to point out that a list can hold more keys than some people may think.

  • Like 2
Link to comment
Share on other sites

When the script is finished I'd do some profiling to see how many entries the script savely holds.

Once the script reaches that limit I add new entries at the beginning of the list and remove one entry from the end of the list.

The list will keep it's size then and I don't need a timestamp since the oldest entry is always at the end of the list.

So if I hold 250 entries I always have the newest 250 in the list. No need to think about a time for purging. Happens all automatic.

For higher capacity storage you should look into Rolig's script and if you need many many 1000 entries you can combine that with additional storage scripts but that's a point where the complexity reaches the level of external server usage.

  • Like 3
Link to comment
Share on other sites

4 hours ago, Rolig Loon said:

Try storing part of the UUID and an abbreviated timestamp as a single list element  ( time + "~" + UUID, maybe). Then periodically -- every few hours, every week, whatever ... -- delete list elements with the oldest timestamps.  Those will always be the ones at the start of the list.

It's a great idea, thanks. I will figure out some sort of string-based storage format like this, given that we can't make lists of complex objects like we can with arrays in javascript (I am a web designer in RL so know my way around that pretty well). 

Link to comment
Share on other sites

15 minutes ago, livb89 said:

It's a great idea, thanks. I will figure out some sort of string-based storage format like this, given that we can't make lists of complex objects like we can with arrays in javascript (I am a web designer in RL so know my way around that pretty well). 

You could think of a strided list as a multi-dimensional array.

I have no Java experience, but I used arrays in BASIC (yes, I am old 🙂 )

From the example at http://wiki.secondlife.com/wiki/Category:LSL_List#Strided_lists :

list demographics = ["John Adams", "male", "2007-06-22", 
                     "Shirley Bassey", "female", "2005-11-02", 
                     "Matt Damon", "male", "2008-05-19"];

(I added newlines for readability)

Alternatively, you could store each triplet as a single string, along these lines:

list demographics = ["John Adams|male|2007-06-22", 
                     "Shirley Bassey|female|2005-11-02", 
                     "Matt Damon|male|2008-05-19"];

and then split the lines with llGetSubString();

As for memory use, I did not test one method against the other, but it should not make a world of difference considering it's all strings.

 

 

Edited by Fritigern Gothly
Missed a word or two
Link to comment
Share on other sites

Since it was not mentioned, you can also use llSetLinkMedia() to store up to 27KB of data in 1KB blocks per legacy prim using the current, home and whitelist params.

Caveats:

  • URL schema enforcement exists for current and home params. ("https://" added at the beginning of data if "http://" or "https://" is not present)
  • When using the whitelist param, there is a 64 count limit if data is in CSV format. (attempting to exceed it yields a script error)
  • Reducing face count results in data loss on faces that no longer exist.

Benefits:

  • Synchronous access to data. (No leaving/entering script events)
  • Data survives taking into inventory and rerezzing.
  • Data survives shift-copying in-world.
  • Error control/reporting with r/w failure.

Detriments:

  • The presence of data yields media beacons.
  • Data is not secure.
Link to comment
Share on other sites

default
{
    touch_end(integer i)
    {
        if (llDetectedKey(0) == llGetOwner())
        {
            string data = llGetObjectDesc();
            integer link = llGetLinkNumber();
            integer face;
            if (i = llClearLinkMedia(link,face))
            {
                llOwnerSay("Media failed to be cleared on link " + (string)link + ", face " + (string)face + " due to error " + (string)i);
                return;
            }
            if (i = llSetLinkMedia(link,face,[PRIM_MEDIA_WHITELIST,data,PRIM_MEDIA_PERMS_INTERACT,0x0,PRIM_MEDIA_PERMS_CONTROL,0x0]))
            {
                llOwnerSay("Media failed to be set on link " + (string)link + ", face " + (string)face + " due to error " + (string)i);
                return;
            }
            llOwnerSay("Data set on link " + (string)link + ", face " + (string)face + ": '" + llList2String(llGetLinkMedia(link,face,[PRIM_MEDIA_WHITELIST]),0) + "'");
        }
    }
}

I included example usage of llClearLinkMedia() even though it may or may not be necessary for any specific application.

I used None for interact and controls perms so a media interface isn't generated when anyone hovers their mouse over the prim, but this doesn't prevent the stored data from leaking.

I used the whitelist param above. Remember to parse out the url schema if using the current url or home url param.

Also, another caveat is that touch won't work on a face with media, so if you want to use a touch script in the same prim, do so on a face that doesn't have media.

Edited by Lucia Nightfire
  • Like 2
Link to comment
Share on other sites

5 hours ago, Lucia Nightfire said:

Since it was not mentioned, you can also use llSetLinkMedia() to store up to 27KB of data in 1KB blocks per legacy prim using the current, home and whitelist params.

Caveats:

  • URL schema enforcement exists for current and home params. ("https://" added at the beginning of data if "http://" or "https://" is not present)
  • When using the whitelist param, there is a 64 count limit if data is in CSV format. (attempting to exceed it yields a script error)
  • Reducing face count results in data loss on faces that no longer exist.

So if I understand this correctly this is storage is *designed* store media URLs but here we are doing a sort of a hack where we are using those fields to store other data as a string? Basically taking advantage of the fact that LL allow up to 1KB for each field (about 1024 characters? allowing for 'https://')

Is that right?

Link to comment
Share on other sites

I don't consider using string literals to hold data outside of valid url format a hack.

LSL functions have always allowed literal type inputs.

The execution of incorrect formatted data should have error control/handling tied to it and it usually does with LSL or the viewer.

You can store data in many unconventional/unintended ways with other functions. As long as you don't plan on actually attempting to execute those functions you're still using literal type inputs.

A very basic example, an object's description field is commonly used to hold operation data with many applications instead of an actual "description".

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1741 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...