One of the main problems with LSL scripting is that it doesn't have any state-persistency. An LSL script will not hold the state across sessions. That means if you are wearing an attachment and you have a script within that attachment which has some variables set to some user-defined value, once you log out and log-in back again, the variables won't hold the same values. Instead, the script will be re-initialized and the variables will have to be set again. This script will allow you to make your global variables persist across sessions by using some ingenuity dealing with prims and textures.

Usage Example

You are creating some attachment, for example, clothing which has some options the user can configure. However, if the user configures those options and you store the value of those options in a variable, once the user logs out, those global variables are reinitialised and they must set them again.

Setting Up

The script is placed in an invisible linked prim and listens for link messages. Depending on the format of the message it sets or retrieves a setting. It is not meant to hold a lot of data and it is limited by the length of a key. When a linked prim wants to store a string, it sends a link message to this invisible prim with the corresponding parameters. The invisible prim which contains this script, then converts the string to a key and sets the texture of one of its faces to the key to which the string was converted to. To retrieve the message, another link message is sent which retrieves the key off the corresponding face and converts it back to a string.


  • To store a message: llMessageLinked(<link number the memory script is in>, <face number>, <string to store>, “@push”);
  • To retrieve a message: llMessageLinked(<link number the memory script is in>, <face number>, <string to store>, “@pull”);

Intuitively, the invisible prim this script is in has any number of faces (in the syntax: <face number>) and thus allows you to store as many messages as there are faces on that particular prim. For example, if your invisible prim that this script is in is a simple 6-faced box, then you can store up to 6 messages: one for every face. In that case, if you would want to store a string on the memory location 3, the <face number> parameter above would be 3.

Case example

We create a simple flight assist device. We build two boxes, one for the flight script and one to hold this memory module and link them together. We want to allow the user to toggle the flight assist on and off but we would like to store that decision in a global variable and we want that variable to persist across sessions. In order to do so, when the flight assist script wants to store a string, for example flight_on in the memory module, it will send a link message to the memory module:

  llMessageLinked(2, 6, "flight_on", "@push");

this will make the memory module store the string flight_on in memory location 6. When the user logs out and logs in back again, the flight-assist must retrieve this setting from the memory module. It knows that it uses the 6th memory location (6th face). Thus, it asks the memory module for the string that was stored in memory location 6:

  llMessageLinked(2, 6, "flight_on", "@pull");

When the memory module receives the @pull request, it sends back a message to all linked prims containing the string that was stored in memory location 6. For example, a script could use this to set the global variable on state_entry():

integer flightOn = FALSE;
default {
  state_entry() {
    // The memory module has link number 2 and we want
    // to retrieve the contents of the memory location 6
    llMessageLinked(2, 6, "", "@pull");
  link_message(integer sender_num, integer num, string str, key id) {
    // The memory module sends a message to all
    // prims with the string parameter set to the
    // contents of the memory location that was 
    // queried with llMessageLinked() in state_entry()
    // and sets the value of a global variable.
    if(str == "flight_on") {
      flightOn = TRUE;

The following is the code of the memory module which must be in the invisible prim. It is not optimised and there is still room for improvement. One thing which should remain the same, or at most inlined, is the cSelect() function. It contains a lookup table of hex and ascii values which is declared locally instead of globally so that it will be declared on the fly without being constantly in memory.


//  Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3      //
//  Please see: for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
list cSelect(integer hex) {
	if(hex) return ["20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f","30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f","40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f","50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f","60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f","70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e"];
	return [" ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"]; 
string AsciiToKey(string str) {
    integer itra;
    string hexStr;
    for(itra=0; itra<llStringLength(str); itra++) {
        hexStr += llList2String(cSelect(1), llListFindList(cSelect(0), (list)llGetSubString(str, itra, itra)));
    while(itra<32) {
        hexStr += "0";
    return llGetSubString(hexStr,0,7) + "-" + llGetSubString(hexStr,8,11)+ "-" + llGetSubString(hexStr,12,15)+ "-" + llGetSubString(hexStr,16,19)+ "-" + llGetSubString(hexStr,20,31);
string KeyToAscii(key k) {
	integer itra;
	string strKey;
	for(itra=0; itra<llStringLength(k); itra++) {
		if(llGetSubString(k, itra, itra) != "-")
			strKey += llGetSubString(k, itra, itra);
	string pureKey;
	for(itra=0; itra<llStringLength(strKey); itra+=2) {
		if(llGetSubString(strKey, itra, itra+1) != "00")
			pureKey += llGetSubString(strKey, itra, itra+1);
	string asciiStr;
	for(itra=0; itra<llStringLength(pureKey); itra+=2) {
		asciiStr += llList2String(cSelect(0), llListFindList(cSelect(1), (list)llGetSubString(pureKey, itra, itra+1)));
	return asciiStr;
default {
    state_entry() {
 		llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX, 
                            PRIM_HOLE_DEFAULT,  // hole_shape
                            <.00, 1, .0>,   // cut
                            .0,                // hollow
                            <.0, .0, .0>,    // twist
                            <1, 1, .0>,    // top_size
                            <.0, .0, .0>,     // top_Shear
                            <.01, .01, .01>,  // size
                            <.0, .0, .0>,
    link_message(integer sender_num, integer num, string str, key id) {
    	if(num < 0 || num > 6 || llStringLength(str) > 16) return;
    	if(id == "@push") {
    		llSetTexture((key)AsciiToKey(str), num);
    		jump stored;
    	llMessageLinked(LINK_ALL_OTHERS, num, KeyToAscii(llGetTexture(num)), "@pull");

secondlife/persistent_storage/texture_memory.txt · Last modified: 2017/02/22 18:22 (external edit)

Access website using Tor

For the copyright, license, warranty and privacy terms for the usage of this website please see the license and privacy pages.