Object to Data v1.4

From Second Life Wiki
Jump to navigation Jump to search

(http://www.gnu.org/copyleft/fdl.html) in the spirit of which this script is GPL'd. Copyright (C) 2007 Xaviar Czervik

(This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.


I took the list serialize list code from someone, and it was posted on a wiki somewhere... (If this was you, please add your name so I can credit you).

I'm not one for writing documentation, so I apologize in advance for the confusion of the following.


Here is a map of the objects:

ObjectMakerFromNotecard
|
|---Setup (Notecard)
|---Main (Script)
|---Replicated (Object)
|---|
|---|---Main (Script)


ObjectDataSaver
|
|---Main (Script)
|---ListenToReplicate(Object)
|---|
|---|---Main (Script)


The following code goes in an object called Replicated. It is needed for the ObjectMakerFromNotecard.


string SERIALIZER_DELIMITER = "$!#"; integer num = 0;

list unserializeList(string serialized_data) {

   // TODO: add some checking in-case we encounter a poorly formed serialization
   //       consider using the same mem-packing list pushing technique used above
   //       (want to run performace tests first)
   list result = [];
   list t;
   list l = llParseStringKeepNulls(serialized_data, [SERIALIZER_DELIMITER], []);
   string item;
   integer i = (l != []);//This is a hack, it gets list lenght.
   integer type = 0;
   do
   {
       if((type = (integer)(item = llList2String(l, (i=~-i)))))
       {//Little error checking (also takes care of null strings).
           integer p = llSubStringIndex(item, ",");
           item = llDeleteSubString(item, 0, p);
           // How about those switch statements, Lindens???
           if (TYPE_INTEGER == type)
               t = [(integer)item];
           else if (TYPE_FLOAT == type)
               t = [(float)item];
           else if (TYPE_STRING == type)
               t = [item];
           else if (TYPE_KEY == type)
               t = [(key)item];
           else
           {
               if (TYPE_ROTATION ^ type)// if (TYPE_VECTOR == type)
                   t = [(vector)("<" + item + ">")];
               else// if (TYPE_ROTATION == type)
                   t = [(rotation)("<" + item + ">")];
           }
           //when dealing with very long lists it might be advantagous to use the commented out line instead.
           //result = [result = t] + result;
           result = t + result;
       }
   }while(i);
   return result;

}

default {

   on_rez(integer i) {
       llListen(i, "", "", "");
   }
   listen(integer i, string n, key id, string m) {
       if (llGetOwnerKey(id) == llGetOwner()) {
           list l = unserializeList(m);
           num++;
           if (num == 1) {
               list l2 = [PRIM_TYPE] + l;
               llSetPrimitiveParams(l2);
           }
           if (num == 2) {
               llSetColor((vector)m, ALL_SIDES);
           }
           if (num == 3) {
               llSetRot((rotation)m);
           }
           if (num == 4) {
               llSetScale((vector)m);
           }
           if (num == 5) {
               llSetTexture(m, ALL_SIDES);
           }
           if (num == 6) {
               vector t = (vector)m;
               llScaleTexture(t.x, t.y, ALL_SIDES);
           }
           if (num == 7) {
               vector t = (vector)m;
               llOffsetTexture(t.x, t.y, ALL_SIDES);
           }
           if (num == 8) {
               llRotateTexture((integer)m, ALL_SIDES);
           }
           if (num == 9) {
               list l2 = [PRIM_BUMP_SHINY, ALL_SIDES] + l;
               llSetPrimitiveParams(l2);
           }
           if (num == 10) {
               while (llVecDist(llGetPos(), (vector)m) > .1) llSetPos((vector)m);
               llRemoveInventory(llGetScriptName());
           }
           
           
           
       }
   }

}


The following object is called ObjectMakerFromNotecard. It has the following script and a note called Setup. (The data for setup will be given later).

key gSetupQueryId; integer gSetupNotecardLine; string gSetupNotecardName = "Setup";


readSettingsNotecard() {

  gSetupNotecardLine = 0;
  gSetupQueryId = llGetNotecardLine(gSetupNotecardName,gSetupNotecardLine); 

}


default {

   state_entry() {
        readSettingsNotecard();
   }
   dataserver(key queryId, string data) {
       if(queryId == gSetupQueryId)  {
           if(data != EOF) {
               integer f = (integer)llFrand(10000) - 10000;
               llRezObject("Replicated", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, f);
               list lis = llParseString2List(data, ["-=!!=-"], []);
               integer i = 0;
               while (i < llGetListLength(lis)) {
                   llSay(f, llList2String(lis, i));
                   i++;
               }
               gSetupQueryId = llGetNotecardLine(gSetupNotecardName,++gSetupNotecardLine); 
           } else {
               state running;   
           }
       }
   }        
   changed(integer change) {
       if (change&CHANGED_INVENTORY)
           llResetScript();
   }

}

state running {

   changed(integer change) {
       if (change&CHANGED_INVENTORY)
           llResetScript();
   }

}


The following object is called ListenToReplicate. Place it in ObjectDataSaver.

integer num = 0; list total = [];

default {

   on_rez(integer i) {
       llListen(i, "", "", "");
   }
   listen(integer i, string n, key id, string m) {
       if (llGetOwnerKey(id) == llGetOwner()) {
           num++;
           total += m;
           if (num == 10) {
               llShout(-10, llDumpList2String(total, "-=!!=-"));
               llDie();
           }
           
           
       }
   }

}


The following code is for the ObjectDataSaver. It will also have and object called ListenToReplicate.

list data;

default {

   state_entry() {
       llListen(-5, "", "", "");
       llListen(-10, "", "", "");
       llListen(1, "", "", "");
   }
   listen(integer i, string n, key id, string m) {
       if (i == -5)
           llRezObject("ListenToReplicate", llGetPos() + <0,0,2>, <0,0,0>, <0,0,0,0>, (integer)m);
       if (i == -10)
           data += m;
       if (i == 1) {
           integer i = 0;
           while (i < llGetListLength(data)) {
               llOwnerSay("\n" + llList2String(data, i));
               i++;
           }
       }
   }

}


After you created the tree, drag the ObjectDataSaver down. Then place the following script in every prim of the object you want to save. Lastly, type any message on ch 1 and it will tell you the data. Then copy and paste it into a note called Setup and place it in the ObjectMakerFromNotecard. (WARNING: EACH PRIM IS DELETED ONCE THE SCRIPT RUNS!!)


string SERIALIZER_DELIMITER = "$!#";

string hexc="0123456789ABCDEF";//faster

string Float2Hex(float a) {// Copyright Strife Onizuka, 2006, LGPL, http://www.gnu.org/copyleft/lesser.html

   if(a)
   {
       float b = llFabs(a);
       integer c = llFloor(llLog(b) / 0.69314718055994530941723212145818);//floor(log2(b))
       if(c > 127) c = 127;//catch fatal rounding error in exponent.
       integer d = (integer)((b / llPow(2.0,c)) * 0x1000000);//shift up into integer range
       string f = "p";
       while(!(d & 0xf))
       {//strip extra zeros off before converting or they break "p"
           d = d >> 4;
           c+=4;
       }
       do
           f = llGetSubString(hexc, 0xf & d, 0xf & d) + f;
       while(d = d >> 4);
       if(a < 0)
           return "-0x" + f + (string)(c - 24);
       return "0x" + f + (string)(c - 24);
   }
   return "0";//zero would hang the zero stripper.

}

string serializeList(list l) {

   integer i = (l != []);//This is a hack, it gets list lenght.
   if(i)
   {
       string serialized_data = "";
       integer type = 0;
       string result;
       {@loop;
           // this custom loop is about as fast as a while loop.
           // we build the string backwords for memory reasons.
           // My kingdom for select statements....
           if (TYPE_FLOAT == (type = llGetListEntryType(l, (i=~-i))))
               // floats get extra love
               result = Float2Hex(llList2Float(l, i));
           else if (TYPE_VECTOR == type) {
               vector v = llList2Vector(l, i);
               result = Float2Hex(v.x) + "," + Float2Hex(v.y) + "," + Float2Hex(v.z);
           } else  if (TYPE_ROTATION == type) {
               rotation r = llList2Rot(l, i);
               result = Float2Hex(r.x) + "," + Float2Hex(r.y) + "," + Float2Hex(r.z) + "," + Float2Hex(r.s);
           } else //if ((TYPE_INTEGER == type) || (TYPE_STRING ==  type) || (TYPE_KEY == type))
               result = llList2String(l, i);// integers, strings and keys required no voodoo
           if(i)
           {
               //This came to me after reverse engeneering LSL bytecode, the realization that LSL memory management sucks.
               serialized_data = SERIALIZER_DELIMITER + (string)type + (serialized_data = result = ",") + result + serialized_data;
               jump loop;
           }
       }
       return (string)type + (serialized_data = result = ",") + result + serialized_data;
   }
   return "";

}

Say(integer i, string m) {

   llSleep(.15);
   llShout(i, m);

}

default {

   state_entry() {
       integer f = (integer)llFrand(10000) + 1691507124;
       llShout(-5, (string)f);
       llSleep(1);
       list total;
       string tot;
       total = llGetPrimitiveParams([PRIM_TYPE]);
       tot = serializeList(total);
       Say(f, tot);
       Say(f, (string)llGetColor(ALL_SIDES));
       Say(f, (string)llGetRot());
       Say(f, (string)llGetScale());
       Say(f, (string)llGetTexture(ALL_SIDES));
       Say(f, (string)llGetTextureScale(ALL_SIDES));
       Say(f, (string)llGetTextureOffset(ALL_SIDES));
       Say(f, (string)llGetTextureRot(ALL_SIDES));
       total = llGetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES]);
       total = [llList2Integer(total, 0), llList2Integer(total, 1)];
       tot = serializeList(total);
       Say(f, tot);
       Say(f, (string)(llGetPos()));
       llSleep(1);
       llDie();
   }

}