Don't click here unless you want to be banned.

LSL Wiki : LibrarySelfUpgradingScript

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl427.us.archive.org

Self Upgrading Script


In some of my projects, I've had a number of prims that each needed the same script. When changes needed to be made to the script, however, it became rather annoying to go through every object, remove the existing script, and copy in the new one.

One way to remedy the problem is with a "manager" object and scripts to manage the numerous prims that must be keep up-to-date, but personally I wasn't thrilled with that solution, especially when I was in the habit of regularly linking and unlinking all the prims. Instead, I wanted a solution where I could drop the new script from inventory onto each of the required prims and have them upgrade themselves (by removing the old version).

So here is the solution I wrote. This code is added to the script to be kept upgraded; it runs as soon as it is dropped on the target prim.

upgrade() {
    // Simple upgrade script; remove all other scripts with the same name as
    // myself.  ASSUMPTION: No spaces in the name (ie, the only space will be
    // between the core name and the auto-generated "version" number).
    
    // get my name
    string me   = llGetScriptName();  // full name of this script
    list parts  = llParseString2List(me, [" "], []);
    string name = llList2String(parts, 0);   // name without any trailing number
    
    // search all scripts in inventory for those starting with the same name
    integer n = llGetInventoryNumber(INVENTORY_SCRIPT);
    while (n-- > 0) {        
        string item = llGetInventoryName(INVENTORY_SCRIPT, n);
        if (item != me && 0 == llSubStringIndex(item, name)) {
            // remove scripts with same name (except myself, of course)
            llRemoveInventory(item);
        }
    }
}

default {
    state_entry() {
        upgrade();
        // rest of your script's startup code
    }
}

It isn't entirely robust, but (with a few minor restrictions on script naming) it serves my purpose. And it is relatively small, so I don't have any serious worries of it getting in the way of memory limits. This may not be a solution for everyone, but you might find it useful with a few tweaks of your own.

-= Update from Jippen Faddoul=-
This one isn't quite as flexable, but it assumes (usually correctly) that you are not starting off with several copies of the same script in the prim, but just 1 copy of the script to be updated.
Its a bit cleaner to put in your code, and will use less memory, since it doesn't need to deal with lists at all.
upgrade() {
    //Get the name of the script
    string self = llGetScriptName();
    // Find out if the script ends in " 1"
    // This rarely happens unless the script was copied in. ~.^
    integer find = llSubStringIndex(self," 1");
    // IF, and only if we find that this ends in " 1", start the update code.
    if(find != -1) { llRemoveInventory(llDeleteSubString(self,find,-1)); }
}

default {
    state_entry() {
        upgrade();
        // The actual script starts here.
    }
}


-= Update from Cron Stardust=-
I found that the upgrade capabilities of these two cool scripts was sadly limited to requiring no spaces in the name, and/or only removing the un-numbered edition allowing only one upgrade before going back to requiring manual work. So I decided to mess with it myself: Self Upgrading Script Enhanced

Cron

Comments [Hide comments/form]
Excellent tool, big thanks! I didn't find Jippen's version to work, not sure why (probably my mistake, but I copied it verbatim).

A couple notes:

Names with spaces work great, if the part after the space is a version number. That way, if I have "myScript v1" installed and drag in "myScript v2", it replaces V1, and makes it easier for me to quickly see what version is installed in an object, and keep versions organized in my inventory.

In your scripts, avoid use of llResetScript() or "state default" on inventory change. If you do, on dropping in the upgrade, both scripts start and either one might win.

If you use "changed" event in any states, you might want to delay before doing any processing because the old script will start running that code before it gets deleted. If the code has no external behavior, no worries. But if it does, e.g., says something, most likely you'll see the text before the old script gets deleted, leading to confusing behavior. (I use a new state and go to that state on change. The new state just starts a 1 sec timer, on timer it goes to the intended next state.)

These tips will help avoid interaction between the auto-update behavior and your object's behavior.
-- LearjeffInnis (2006-12-08 08:41:25)
Attach a comment to this page: