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

LSL Wiki : OBJS

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl338.us.archive.org
I am studying a way for serializing objects in sl. NOTE: This is still a preliminary draft: I'm heavily working on it to have it properly designed/programmed. Any suggestions are welcome :)

Current version has still some major problems, including:

* Too slow: each prim needs at least 10 seconds to be rezzed (probably due to BTLT serialization :(
* Position is not maintained (some major bug to solve)

Probably will simplify using standard listdump without BTLT.



Using llGetPrimitiveParams and putting information in a convenient format that can be reread by a rezzer. This is essential for moving objects from SL to opensim whenever they will implement llRezObject and llSetPrimitiveParams :) [Possibly we will lose the textures, so protocol should be robust enough to be able to produce a subset of the parameters to be really tight and simple to use].

OBJS protocol consists of a serialization of object properties convenient enough to be produced on a chat output so people can easily cut/paste from the history and put result into a notecard. This means that protocol tolerates the presence of extra beginning characters such as [HH:MM] Object: at the head.

I want to be as "standard" as possible and reusing work from other people here in this wiki, as well as being decently compatible with standard lsl Functions.

So here is the protocol:
// Packing lines longer than 255 bytes (limit in reading notecard) in multiple lines:
// You look for  +OBJS or @OBJS so to be sure to have data of this protocol. + means the line will continue, @ means the line is finishing
..(prefix).......+OBJS......(data)...................+ 
..(prefix).......@OBJS.....(data)...................@
// (data) when repacked will contain a BTLT strong typed list of arguments composed by the following entries:
[-1, name // first pair is the name
[-2, desc // second pair is the description
...rest of the list // is in llSetPrimitiveParams format so to be easily fed to it to easily reconstruct the object 
// MUST START with the position of the object to be rezzed for easily understanding where to rez it in reference to others
//We use BTLT to preserve the float vectors so to avoid drifting. Also it is quite tight
//Also we will try to use optimizations to be able not to specify all single faces when they refer to the same properties [NOTDONE]


Protocol consists in 3 pieces:
* "OBJS Serializer" to be put in a prim chatting main parameters, then people can cut and paste them and put in a notecard,
* "OBJS Rezzer" will read the notecard (pack it), rez a prim and linkMessage to it the serialization. A subset of the properties are handled (name, description, position, size, type, textures, colors).
* "OBJS Prim" will interpret the (packed)

The idea is that positions will be rebuilt on the top of the rezzer object (plus a displacement of 2 meters) and all the other objects will be rebuilt with reference to the first object.


Here an example (Note that the protocol will tolerate the prefixes from the chat window, like HH:MM and object name. Moreover it will support the splitting of lines longer than 240 chars using a continuation character as suffix. (Warning, while the Serializer should be OK, I'm still heavily working on the rezzer and the prim part)

[3:06]  Ishtar Temple: OBJS|?!@#$|/////w!Ishtar Temple|/////g!BlueVertigo Heron|AAAABg#2QwUJ4QQlurQgQxrve|AAAABw#SQSPwQQFHrg|AAAAC$G2uvQmcwOvEelQvzUEywvzUEyg|AAAAEQ|@5748decc-f629-461c-9a36-a35a221fe21f#2PkzMzQPZmZmg#EPwAB?|AAAAEg|#SP4P4P4?P4|AAAA+
[3:06]  Ishtar Temple: OBJSFg||AAAAAQ|AAAAEQ|AAAAAQ@3f530516-8709-d211-b8e9-4c609f88625d#2PkzMzQPZmZmg#EPwAB?|AAAAEg|AAAAAQ#SP4P4P4?P4|AAAAFg|AAAAAQ|AAAAAQ|AAAAEQ|AAAAAg@3f530516-8709-d211-b8e9-4c609f88625d#2PkzMzQPZmZmg#EPwAB?|AAAAEg|AAAAAg#SP4P4+
[3:06]  Ishtar Temple: OBJSP4?|AAAAFg|AAAAAg|AAAAAQ|AAAAEQ|AAAAAw@3f530516-8709-d211-b8e9-4c609f88625d#2PkzMzQPZmZmg#EPwAB?|AAAAEg|AAAAAw#SP4P4P4?P4|AAAAFg|AAAAAw|AAAAAQ|AAAAEQ|AAAAB@5748decc-f629-461c-9a36-a35a221fe21f#2PkzMzQPZmZmg#EPwAB?|AAAAEg+
[3:06]  Ishtar Temple: OBJS|AAAAB#SP4P4P4?|AAAAFg|AAAAB|AAAAAQ|AAAAEQ|AAAABQ@5748decc-f629-461c-9a36-a35a221fe21f#2PkzMzQPZmZmg#EPwAB?|AAAAEg|AAAABQ#SP4P4P4?P4|AAAAFg|AAAABQ|AAAAAQ|AAAACQ||#QP4?#A#SP4P4#A@



Script producing the serialization sequence (Note: I gave up using the standard serialization function from Strife Onizuka becase it was too slow and not working with textures because of a bug in sl :(
Instead I developed a personal version which emits ONLY one llGetPrimitiveParams, and works on the output to make it compatible with a llSetPrimitiveParams.

//
// December 2007
// OBJS serializer
// This script will simply say its properties on public chat allowing to pick them and use in a
// V1.0 Follows specs found on 



//BTLT is part of the Combined Library.
//BTLT Version 0.1 beta

//===================================================//
//                 Combined Library                  //
//             "Nov  5 2007", "04:00:34"             //
//  Copyright (C) 2004-2007, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//{

rotation stiufr(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //--XXXXYYYYZZZZSSSS
    integer     raw = llBase64ToInteger(llGetSubString("AAA" + in + "AAA", 0, 5)) >> 2;
    integer     offset = 1;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, len + 2, 1)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 6))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

vector stiufv(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //-XXXXYYYYZZZZ
    integer     raw = llBase64ToInteger(llGetSubString("AAAA" + in + "AA", 0, 5)) >> 2;
    integer     offset = 0;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, -~len, 0)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

string vfuist(vector in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      buf = fuist(in.y);
    integer     len = llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) + llStringLength(buf)) << 2), 4, 4) + (buf =
                                                                                               fuist(in.x)) + buf + fuist(in.z);
}    //-XXXXYYYYZZZZ

string rfuist(rotation in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      z = fuist(in.z);
    string      buf = fuist(in.y);
    integer     len = (llStringLength(z) << 3) | llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) | llStringLength(buf)) << 2), 3, 4) + (buf =
                                                                                               fuist(in.x)) + buf + z +
        fuist(in.s);
}    //--XXXXYYYYZZZZSSSS

string ist(integer b)            //Mono Safe, LSO Safe, Double Unsafe
{
    string      src = llIntegerToBase64(b);
    integer     c = 6;
    do;
    while ("A" == llGetSubString(src, c = ~-c, c));
    return llDeleteSubString(src, -~c, 0x8000);
}

string fuist(float input)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //float union to base64ed integer
    if (input) {    //is it non zero?
        integer     sign = (input < 0) << 31;    //the sign, but later this variable is reused to store the shift
        integer     exp;
        if ((input = llFabs(input)) < 2.3509887016445750159374730744445e-38)    //Denormalized range check & last stirde of normalized range
            sign = sign | (integer) (input / 1.4012984643248170709237295832899e-45);    //the math overlaps; saves cpu time.
        else
            sign = (0x7FFFFF & (integer) (input * (0x1000000 >> sign))) | (((exp + 126 + (sign = ((integer) input - (3 <= (input /= (float) ("0x1p" + (string) (exp -= ((exp = llFloor(llLog(input) / 0.69314718055994530941723212145818)) == 128)))))))) << 23) | sign);    //extremes will error towards extremes. this yuch corrects it.
        return ist(sign);
    }    //for grins, detect the sign on zero. it's not pretty but it works. the previous requires alot of unwinding to understand it.
    if ((string) input == (string) (0.0))
        return "";
    return "g";
}

float stiuf(string input)
{    //base64ed integer union to float
    integer     buf = llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5));
    return ((float) ("0x1p" + (string) ((buf | !buf) - 150))) * ((!!(buf = (0xff & (buf >> 23))) << 23) | ((buf & 0x7fffff))) *
        (1 | (buf >> 31));
}    //will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warented.

list BTLTParse(string input)
{
    list        partial;
    if (llStringLength(input) > 6) {
        string      seperators = llGetSubString(input, (0), 6);
        integer     pos =
            ([] !=
             (partial =
              llList2List(input +
                          llParseStringKeepNulls(llDeleteSubString(input, (0), 5),[],
                                                 [input =
                                                  llGetSubString(seperators, (0), (0)), llGetSubString(seperators, 1, 1),
                                                  llGetSubString(seperators, 2, 2), llGetSubString(seperators, 3, 3),
                                                  llGetSubString(seperators, 4, 4), llGetSubString(seperators, 5, 5)]),
                          (llSubStringIndex(seperators, llGetSubString(seperators, 6, 6)) < 6) << 1, -1)));
        integer     type = (0);
        integer     sub_pos = (0);
        do {
            list        current = (list) (input = llList2String(partial, sub_pos = -~pos));    //TYPE_STRING || TYPE_INVALID (though we don't care about invalid)
            if (!(type = llSubStringIndex(seperators, llList2String(partial, pos))))    //TYPE_INTEGER
                current = (list) (llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5)));
            else if (type == 1)    //TYPE_FLOAT
                current = (list) (stiuf(input));
            else if (type == 3)    //TYPE_KEY
                current = (list) ((key) (input));
            else if (type == 4)    //TYPE_VECTOR
                current = (list) (stiufv(input));
            else if (type == 5)    //TYPE_ROTATION
                current = (list) (stiufr(input));
            partial = llListReplaceList(partial, current, pos, sub_pos);
        } while ((pos = -~sub_pos) & 0x80000000);
    }
    return partial;
}

string BTLTDump(list input, string seperators)
{    //This function is dangerous
    seperators += "|/?!@#$%^&*()_=:;~`'<>{}[],.\n\" qQxXzZ\\";
    string      cumulator = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + (string) (input);
    integer     counter = (0);
    do
        if (~llSubStringIndex(cumulator, llGetSubString(seperators, counter, counter)))
            seperators = llDeleteSubString(seperators, counter, counter);
        else
            counter = -~counter;
    while (counter < 6);
    seperators = llGetSubString(seperators, (0), 5);

    string      buffer = cumulator = "";

    if ((counter = (input !=[]))) {
        do {
            integer     type = ~-llGetListEntryType(input, counter = ~-counter);

            if (type == 4)    //TYPE_VECTOR - 1
                buffer = vfuist(llList2Vector(input, counter));
            else
             if (type == 5)    //TYPE_ROTATION - 1
                buffer = rfuist(llList2Rot(input, counter));
            else
             if (type == 1)    //TYPE_FLOAT - 1
                buffer = fuist(llList2Float(input, counter));
            else
             if (!type)    //TYPE_INTEGER - 1
            {
                buffer = ist(llList2Integer(input, counter));
            } else

                buffer = llList2String(input, counter);

            cumulator = (cumulator = llGetSubString(seperators, type, type)) + buffer + cumulator;
        } while (counter);
    }
    return seperators + cumulator;
}
//} Combined Library

list GetAllParams()
{
    list lAsk=[ PRIM_POSITION, PRIM_SIZE,  PRIM_ROTATION ];
    // NEXT LIST will contain
    // number of pos returned by the call
    // number of parameters (right after) to be pushed
    list lIns=[ 1,1,PRIM_POSITION,1,1,PRIM_SIZE,1,1,PRIM_ROTATION];
    integer side=llGetNumberOfSides();
    integer i;
    for(i=0;i<side;i++)
    {
        lAsk+= [PRIM_TEXTURE, i, PRIM_COLOR, i, PRIM_TEXGEN, i];
        lIns+= [4,2,PRIM_TEXTURE,i,2,2,PRIM_COLOR,i,1,2,PRIM_TEXGEN,i];
    }
    lAsk+= [ PRIM_TYPE ];
    lIns+= [ -1,1,PRIM_TYPE]; // we cannot know the length of this :(
    lAsk=llGetPrimitiveParams(lAsk);
    list lOut=[];
    
    integer iAsk=0; integer iIns=0; integer iRetValues=0; integer iInsValues;
    list lRetValues; list lInsValues;
    while(iRetValues!=-1)
    {
        iRetValues=llList2Integer(lIns,iIns++);
        iInsValues=llList2Integer(lIns,iIns++);
                    
        if(iRetValues>=0)
        {
            lInsValues=llList2List(lIns  ,iIns,iIns+iInsValues-1);
            iIns+=iInsValues;
            
            lRetValues=llList2List(lAsk   ,iAsk,iAsk+iRetValues-1);
            iAsk+=iRetValues;
        }
        else
        {
            lInsValues=llList2List(lIns  ,iIns, iIns+iInsValues-1);
            lRetValues=llList2List(lAsk   ,iAsk,-1);

        }

        lOut+=lInsValues + lRetValues;
    }
    lAsk=[]; lIns=[];
    return lOut;
    
}
//Contributed by Salahzar Stenvaag

Show(string x)
{
    integer WRAP=220; // to have short lines
    integer len=llStringLength(x)+1+llStringLength(llGetObjectName());
    while(len>WRAP)
    {
        //llSay(0,"finallen: "+(string)finallen);
        llSay(0,"OBJS"+llGetSubString(x,0,WRAP-1)+"+");
        x=llGetSubString(x,WRAP,-1);
        len-=WRAP;
            
    }
    llSay(0,"OBJS"+x+"@");

}

default
{
    state_entry()
    {
        llSay(0, "OBJS Serializer V1.0");
    }

    touch_start(integer total_number)
    {
        list lst=[-1,llGetObjectName(),-2,llGetObjectDesc() ] + GetAllParams();
        Show(BTLTDump(lst,""));
        //Show(llList2CSV(GetAllParams()));
    }
}

OBJS Prim: script interpreting the BTLT sequence from linked rezzer
//
// December 2007
// OBJS Prim
// This script will simply interpret OBJS command received on LINK channel (BTLT syntax)
// Will implement extra commands -1: Name, -2: description
//

debug(string type,string str)
{
    //llOwnerSay("::"+str);
}

//BTLT is part of the Combined Library.
//BTLT Version 0.1 beta

//===================================================//
//                 Combined Library                  //
//             "Nov  5 2007", "04:00:34"             //
//  Copyright (C) 2004-2007, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//{

rotation stiufr(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //--XXXXYYYYZZZZSSSS
    integer     raw = llBase64ToInteger(llGetSubString("AAA" + in + "AAA", 0, 5)) >> 2;
    integer     offset = 1;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, len + 2, 1)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 6))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

vector stiufv(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //-XXXXYYYYZZZZ
    integer     raw = llBase64ToInteger(llGetSubString("AAAA" + in + "AA", 0, 5)) >> 2;
    integer     offset = 0;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, -~len, 0)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

string vfuist(vector in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      buf = fuist(in.y);
    integer     len = llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) + llStringLength(buf)) << 2), 4, 4) + (buf =
                                                                                               fuist(in.x)) + buf + fuist(in.z);
}    //-XXXXYYYYZZZZ

string rfuist(rotation in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      z = fuist(in.z);
    string      buf = fuist(in.y);
    integer     len = (llStringLength(z) << 3) | llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) | llStringLength(buf)) << 2), 3, 4) + (buf =
                                                                                               fuist(in.x)) + buf + z +
        fuist(in.s);
}    //--XXXXYYYYZZZZSSSS

string ist(integer b)            //Mono Safe, LSO Safe, Double Unsafe
{
    string      src = llIntegerToBase64(b);
    integer     c = 6;
    do;
    while ("A" == llGetSubString(src, c = ~-c, c));
    return llDeleteSubString(src, -~c, 0x8000);
}

string fuist(float input)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //float union to base64ed integer
    if (input) {    //is it non zero?
        integer     sign = (input < 0) << 31;    //the sign, but later this variable is reused to store the shift
        integer     exp;
        if ((input = llFabs(input)) < 2.3509887016445750159374730744445e-38)    //Denormalized range check & last stirde of normalized range
            sign = sign | (integer) (input / 1.4012984643248170709237295832899e-45);    //the math overlaps; saves cpu time.
        else
            sign = (0x7FFFFF & (integer) (input * (0x1000000 >> sign))) | (((exp + 126 + (sign = ((integer) input - (3 <= (input /= (float) ("0x1p" + (string) (exp -= ((exp = llFloor(llLog(input) / 0.69314718055994530941723212145818)) == 128)))))))) << 23) | sign);    //extremes will error towards extremes. this yuch corrects it.
        return ist(sign);
    }    //for grins, detect the sign on zero. it's not pretty but it works. the previous requires alot of unwinding to understand it.
    if ((string) input == (string) (0.0))
        return "";
    return "g";
}

float stiuf(string input)
{    //base64ed integer union to float
    integer     buf = llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5));
    return ((float) ("0x1p" + (string) ((buf | !buf) - 150))) * ((!!(buf = (0xff & (buf >> 23))) << 23) | ((buf & 0x7fffff))) *
        (1 | (buf >> 31));
}    //will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warented.

list BTLTParse(string input)
{
    list        partial;
    if (llStringLength(input) > 6) {
        string      seperators = llGetSubString(input, (0), 6);
        integer     pos =
            ([] !=
             (partial =
              llList2List(input +
                          llParseStringKeepNulls(llDeleteSubString(input, (0), 5),[],
                                                 [input =
                                                  llGetSubString(seperators, (0), (0)), llGetSubString(seperators, 1, 1),
                                                  llGetSubString(seperators, 2, 2), llGetSubString(seperators, 3, 3),
                                                  llGetSubString(seperators, 4, 4), llGetSubString(seperators, 5, 5)]),
                          (llSubStringIndex(seperators, llGetSubString(seperators, 6, 6)) < 6) << 1, -1)));
        integer     type = (0);
        integer     sub_pos = (0);
        do {
            list        current = (list) (input = llList2String(partial, sub_pos = -~pos));    //TYPE_STRING || TYPE_INVALID (though we don't care about invalid)
            if (!(type = llSubStringIndex(seperators, llList2String(partial, pos))))    //TYPE_INTEGER
                current = (list) (llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5)));
            else if (type == 1)    //TYPE_FLOAT
                current = (list) (stiuf(input));
            else if (type == 3)    //TYPE_KEY
                current = (list) ((key) (input));
            else if (type == 4)    //TYPE_VECTOR
                current = (list) (stiufv(input));
            else if (type == 5)    //TYPE_ROTATION
                current = (list) (stiufr(input));
            partial = llListReplaceList(partial, current, pos, sub_pos);
        } while ((pos = -~sub_pos) & 0x80000000);
    }
    return partial;
}

string BTLTDump(list input, string seperators)
{    //This function is dangerous
    seperators += "|/?!@#$%^&*()_=:;~`'<>{}[],.\n\" qQxXzZ\\";
    string      cumulator = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + (string) (input);
    integer     counter = (0);
    do
        if (~llSubStringIndex(cumulator, llGetSubString(seperators, counter, counter)))
            seperators = llDeleteSubString(seperators, counter, counter);
        else
            counter = -~counter;
    while (counter < 6);
    seperators = llGetSubString(seperators, (0), 5);

    string      buffer = cumulator = "";

    if ((counter = (input !=[]))) {
        do {
            integer     type = ~-llGetListEntryType(input, counter = ~-counter);

            if (type == 4)    //TYPE_VECTOR - 1
                buffer = vfuist(llList2Vector(input, counter));
            else
             if (type == 5)    //TYPE_ROTATION - 1
                buffer = rfuist(llList2Rot(input, counter));
            else
             if (type == 1)    //TYPE_FLOAT - 1
                buffer = fuist(llList2Float(input, counter));
            else
             if (!type)    //TYPE_INTEGER - 1
            {
                buffer = ist(llList2Integer(input, counter));
            } else

                buffer = llList2String(input, counter);

            cumulator = (cumulator = llGetSubString(seperators, type, type)) + buffer + cumulator;
        } while (counter);
    }
    return seperators + cumulator;
}

//} Combined Library




default
{
     
    state_entry()
    {
        llListen(0,"","",NULL_KEY);
    }
    
    link_message(integer sendernum, integer num, string message, key id)
    {

        debug("MSG","Message: "+message);
        llResetTime();
        list lOBJS=BTLTParse(message);
        //interpret(message);
        debug("MSG","Converted: "+llList2CSV(lOBJS));
        // interpret and strip -1 and -2 (first positions only!!!)
        if(llList2Integer(lOBJS,0)==-1) 
        {
            llSetObjectName(llList2String(lOBJS,1));
            lOBJS=llDeleteSubList(lOBJS, 0, 1);
        }
        if(llList2Integer(lOBJS,0)==-2)
        {
            llSetObjectDesc(llList2String(lOBJS,1));
            lOBJS=llDeleteSubList(lOBJS, 0, 1);
        }
        // what's next is simply the setPrimitiveParams
        
        llSetPrimitiveParams(lOBJS);
        llOwnerSay("Done. (Used: "+(string)llGetAndResetTime()+" secs");
        
    }
        
    

}

Script rezzing the object and communicating to it the proper commands (also repacks the split lines from the notecard)
//
// December 2007
// OBJS rezzer
// This script will rez an object reading the BTLT serialization build by the serializer

string sNOTECARD="SCENE";
integer iDEBUG=0;
vector vSTARTINGPOINT;
string sCONTINUATION="";
integer iREZOBJ=TRUE;

list lOBJS;
string sOBJS;

integer iFIRST=1;
vector vFIRSTOBJECT;
string sPRIMNAME="OBJS Prim";
vector vPOS;


//BTLT is part of the Combined Library.
//BTLT Version 0.1 beta

//===================================================//
//                 Combined Library                  //
//             "Nov  5 2007", "04:00:34"             //
//  Copyright (C) 2004-2007, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//{

rotation stiufr(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //--XXXXYYYYZZZZSSSS
    integer     raw = llBase64ToInteger(llGetSubString("AAA" + in + "AAA", 0, 5)) >> 2;
    integer     offset = 1;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, len + 2, 1)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 6))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

vector stiufv(string in)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //-XXXXYYYYZZZZ
    integer     raw = llBase64ToInteger(llGetSubString("AAAA" + in + "AA", 0, 5)) >> 2;
    integer     offset = 0;
    integer     len = raw & 7;
    return <stiuf(llDeleteSubString(in, -~len, 0)),
        stiuf(llDeleteSubString(in, (len = (7 & (raw >> 3))) - ~(offset += len), offset)),
        stiuf(llDeleteSubString(in, 0, offset + len)) >;
}

string vfuist(vector in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      buf = fuist(in.y);
    integer     len = llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) + llStringLength(buf)) << 2), 4, 4) + (buf =
                                                                                               fuist(in.x)) + buf + fuist(in.z);
}    //-XXXXYYYYZZZZ

string rfuist(rotation in)        //Mono Unsafe, LSO Safe, Double Unsafe
{
    string      z = fuist(in.z);
    string      buf = fuist(in.y);
    integer     len = (llStringLength(z) << 3) | llStringLength(buf);
    return llGetSubString(llIntegerToBase64(((len << 3) | llStringLength(buf)) << 2), 3, 4) + (buf =
                                                                                               fuist(in.x)) + buf + z +
        fuist(in.s);
}    //--XXXXYYYYZZZZSSSS

string ist(integer b)            //Mono Safe, LSO Safe, Double Unsafe
{
    string      src = llIntegerToBase64(b);
    integer     c = 6;
    do;
    while ("A" == llGetSubString(src, c = ~-c, c));
    return llDeleteSubString(src, -~c, 0x8000);
}

string fuist(float input)        //Mono Unsafe, LSO Safe, Double Unsafe
{    //float union to base64ed integer
    if (input) {    //is it non zero?
        integer     sign = (input < 0) << 31;    //the sign, but later this variable is reused to store the shift
        integer     exp;
        if ((input = llFabs(input)) < 2.3509887016445750159374730744445e-38)    //Denormalized range check & last stirde of normalized range
            sign = sign | (integer) (input / 1.4012984643248170709237295832899e-45);    //the math overlaps; saves cpu time.
        else
            sign = (0x7FFFFF & (integer) (input * (0x1000000 >> sign))) | (((exp + 126 + (sign = ((integer) input - (3 <= (input /= (float) ("0x1p" + (string) (exp -= ((exp = llFloor(llLog(input) / 0.69314718055994530941723212145818)) == 128)))))))) << 23) | sign);    //extremes will error towards extremes. this yuch corrects it.
        return ist(sign);
    }    //for grins, detect the sign on zero. it's not pretty but it works. the previous requires alot of unwinding to understand it.
    if ((string) input == (string) (0.0))
        return "";
    return "g";
}

float stiuf(string input)
{    //base64ed integer union to float
    integer     buf = llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5));
    return ((float) ("0x1p" + (string) ((buf | !buf) - 150))) * ((!!(buf = (0xff & (buf >> 23))) << 23) | ((buf & 0x7fffff))) *
        (1 | (buf >> 31));
}    //will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warented.

list BTLTParse(string input)
{
    list        partial;
    if (llStringLength(input) > 6) {
        string      seperators = llGetSubString(input, (0), 6);
        integer     pos =
            ([] !=
             (partial =
              llList2List(input +
                          llParseStringKeepNulls(llDeleteSubString(input, (0), 5),[],
                                                 [input =
                                                  llGetSubString(seperators, (0), (0)), llGetSubString(seperators, 1, 1),
                                                  llGetSubString(seperators, 2, 2), llGetSubString(seperators, 3, 3),
                                                  llGetSubString(seperators, 4, 4), llGetSubString(seperators, 5, 5)]),
                          (llSubStringIndex(seperators, llGetSubString(seperators, 6, 6)) < 6) << 1, -1)));
        integer     type = (0);
        integer     sub_pos = (0);
        do {
            list        current = (list) (input = llList2String(partial, sub_pos = -~pos));    //TYPE_STRING || TYPE_INVALID (though we don't care about invalid)
            if (!(type = llSubStringIndex(seperators, llList2String(partial, pos))))    //TYPE_INTEGER
                current = (list) (llBase64ToInteger(llGetSubString(input + "AAAAAA", 0, 5)));
            else if (type == 1)    //TYPE_FLOAT
                current = (list) (stiuf(input));
            else if (type == 3)    //TYPE_KEY
                current = (list) ((key) (input));
            else if (type == 4)    //TYPE_VECTOR
                current = (list) (stiufv(input));
            else if (type == 5)    //TYPE_ROTATION
                current = (list) (stiufr(input));
            partial = llListReplaceList(partial, current, pos, sub_pos);
        } while ((pos = -~sub_pos) & 0x80000000);
    }
    return partial;
}

string BTLTDump(list input, string seperators)
{    //This function is dangerous
    seperators += "|/?!@#$%^&*()_=:;~`'<>{}[],.\n\" qQxXzZ\\";
    string      cumulator = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + (string) (input);
    integer     counter = (0);
    do
        if (~llSubStringIndex(cumulator, llGetSubString(seperators, counter, counter)))
            seperators = llDeleteSubString(seperators, counter, counter);
        else
            counter = -~counter;
    while (counter < 6);
    seperators = llGetSubString(seperators, (0), 5);

    string      buffer = cumulator = "";

    if ((counter = (input !=[]))) {
        do {
            integer     type = ~-llGetListEntryType(input, counter = ~-counter);

            if (type == 4)    //TYPE_VECTOR - 1
                buffer = vfuist(llList2Vector(input, counter));
            else
             if (type == 5)    //TYPE_ROTATION - 1
                buffer = rfuist(llList2Rot(input, counter));
            else
             if (type == 1)    //TYPE_FLOAT - 1
                buffer = fuist(llList2Float(input, counter));
            else
             if (!type)    //TYPE_INTEGER - 1
            {
                buffer = ist(llList2Integer(input, counter));
            } else

                buffer = llList2String(input, counter);

            cumulator = (cumulator = llGetSubString(seperators, type, type)) + buffer + cumulator;
        } while (counter);
    }
    return seperators + cumulator;
}



debug(string module,string str)
{
    if(iDEBUG==TRUE) llOwnerSay("DEBUG("+llGetScriptName()+"): ["+module+"] "+str);
}


integer iNOTECARDLINE=0;

readnext()
{
    iNOTECARDLINE++;
    llGetNotecardLine(sNOTECARD, iNOTECARDLINE);
}
readscene()
{
    // read notecard
    iNOTECARDLINE=0;
    llGetNotecardLine(sNOTECARD,iNOTECARDLINE);
    //debug("llGetNotecardLine returned: "+(string)k);
}


// Rezzing an object (called when encountered "F" part of notecard reading
// will continue on object_rez event
rezz()
{
    debug("REZZ","Trying to rez the object");
    
    // vPOS decides where to rez the object 
    // if object will be more than 10m far then must rez it at starting point
    // also will try to keep notice of coordinates of FIRSTOBJECT to have all
    // subsequent object be rezzed relative to it
    vPOS=vSTARTINGPOINT; // start from starting point
    vector vOriginalPos=(vector)llList2String(lOBJS,5); // 5th element is the position!!!
    if(iFIRST==TRUE)
    {
        iFIRST=FALSE;
        vFIRSTOBJECT=vOriginalPos;
    }
    else
    {
        vPOS=vOriginalPos-vFIRSTOBJECT+vSTARTINGPOINT;        
    }
    vector vRezPos=vPOS;
    if(llVecDist(vPOS,llGetPos()) > 10) vRezPos=vSTARTINGPOINT;
    debug("REZZ"," Final pos at "+(string)vPOS+" initial rez at "+(string)vRezPos);
    
    // update list and string representation
    //lOBJS=llListReplaceList(lOBJS,[ vPOS ],5,5);
    //sOBJS=BTLTDump(lOBJS,"");
    

    if(iREZOBJ==TRUE) llRezObject(sPRIMNAME,vRezPos,<0,0,0>,ZERO_ROTATION,0);
    else
    {
        // for debug purposes
        // talk only to this prim with current serialization
        llMessageLinked(2,0,sOBJS,"");
        
        // makes elaboration progress on next line
        readnext();
    }
    // calmly wait until the object get rezzed (object_rez)
    return;
}

    


integer already=0;

default
{
    state_entry()
    {
        string scriptname=llGetScriptName();
        list pieces=llParseString2List(scriptname,[" ","-","."],[]);
        string lastpiece=llList2String(pieces,-1);
        if(llSubStringIndex(llToUpper(scriptname),"DEBUG")>=0) iDEBUG=TRUE;
        //debug("INIT"," freeMemory: "+(string)llGetFreeMemory());
        
        vSTARTINGPOINT=llGetPos();
        vSTARTINGPOINT.z+=2; // starts 2 m above me
        if(iREZOBJ==TRUE) llRequestPermissions(llGetOwner(),PERMISSION_CHANGE_LINKS);
        
    }
    // Wait until the object is rezzed
    object_rez(key id)
    {
        // create link with this object so to be able to talk with it very easily without
        // llSay and listening. Create link is slow
        debug("OBJECT_REZ","Linking and setting parameters");
        llCreateLink(id,TRUE);
        
        // talk only to this prim with current serialization
        llMessageLinked(2,0,sOBJS,"");
        
        // clean out memory
        sOBJS=""; lOBJS=[]; 
        
        // makes elaboration progress on next line
        readnext();
        
        
    }
    

    touch_start(integer total_number)
    {
        // now reading scene
        if(iREZOBJ && already)
        {
            llSay(0,"Cannot rerez. Unlink delete, reset if you really want to");
            return;
        }
        already=1;
        sCONTINUATION="";
        readscene();
        //llRezObject("Camaleont Prim",llGetPos()+<0,0,2>,ZERO_VECTOR,ZERO_ROTATION,1000);
        //llSay(0,"Created prim just over me");
    }
        // notecard reader 
    dataserver(key id, string sMessage)
    {
        //debug("dataserver received data: "+data);
        string sMethod="DATASERVER";
        if (sMessage != EOF)
        {
            debug(sMethod,"Reading scene line #"+(string)iNOTECARDLINE);
            if(llGetSubString(sMessage,0,0)!="#") // ignore comments
            {
                // try to decode one string. Eliminate starting :
                integer iFound=llSubStringIndex(sMessage,"OBJS");
                if(iFound<0)
                {
                    llSay(0,"Invalid OBJS line at line#"+(string)iNOTECARDLINE);
                    return;
                }
                
                
                debug(sMethod,"read message "+(string)llStringLength(sMessage)+":"+sMessage);
                //
                
                // handle continuation character
                string last=llGetSubString(sMessage,-1,-1);
                if(last=="+")
                {
                    debug(sMethod,"Found continuation, caching it..");
                    sCONTINUATION+=llGetSubString(sMessage,iFound+4,-2);
                    readnext();
                    return;

                }
                if(last!="@")
                {
                    llSay(0,"Invalid OBJS line (missing @) at line#"+(string)iNOTECARDLINE);
                    return;
                }
                

                // we are at last continuation or no continuation at all
                sOBJS=sCONTINUATION+llGetSubString(sMessage,iFound+4,-2);
                sMessage="";
                debug(sMethod,"Found final line: "+sOBJS);
                sCONTINUATION="";

                lOBJS=BTLTParse(sOBJS); 
                rezz();
                return; // when rezzing, notecard reading will be deferred

                    
            }
            
            // go to next line
            readnext();
            
            //debug("tried to read line "+(string)notecardline+" key "+(string)k);
            return;
        }  
        else
        {
            llSay(0,"Finished rezzing the scene unlinking me (the root)");
            if(iREZOBJ==TRUE) llBreakLink(LINK_ROOT);
            // remove the joker from the linkset
            //llSleep(5); // wait some seconds before unlinking root
            
        }
        
    }    
    
}
There is no comment on this page. [Display comments/form]