User:Rolig Loon/UNDO PosRot

From Second Life Wiki
Jump to navigation Jump to search

NOTE (7/3/2010): This script will not function properly until server software 1.40.2 is rolled out again. Sorry

Features

Allows the user to undo position and rotation changes that have been made "manually" to prims in a linkset. Handy for recovering from accidental realignment of prims, and very handy if you want to use Edit to change positions and rotations of selected parts of a linkset temporarily and then restore them later to their original positions.

To use:

1. Name all prims. You have several options:

     a. Leave the SL default name "Object" on a prim.
     b. Make a prim's Name field blank (The script will name the prim "Child Prim x", where x is a unique number.)
     c. Give the prim a unique name of your own choosing.
     d. Give multiple prims the same unique name, so that they may be reset with a single command (see 3.b. below)

2. Place the script in the root prim of the linkset

     a. The script will automatically record each prim's current location and rotation in its Description field. DO NOT CHANGE THESE.
     b. If you add or remove prims in the linkset, the script will rewrite ALL current prim location/rotation information in ALL prims. (Except, see General Note 3, below.)
--- You may move or rotate any prims in the linkset, including the root prim, once the script is in place and has recorded prim information. ---

3. If you want to restore any prim to its last recorded position and rotation, type a command in chat channel 43 as follows:

     a. To restore a single prim, type "/43 undo prim_name" (without the quotes), where prim_name is the unique name of that prim
         NOTE: Restoring the root prim will force ALL prims to restore, because the root prim's rotation affects all later movements of child prims.
     b. To restore all prims with the same name, type "/43 undo all named prim_name", where prim_name is the unique name for those prims.
         NOTE: The ROOT prim cannot be moved with this command.
     c. To restore all prims in the linkset, type "/43 undo all".

General notes

1. When this script "undoes" a prim's position and rotation, it updates current information in that prim's Description field. Therefore, you cannot perform multiple "undo" commands on the same prim. (That is, it does not have a stack memory like Ctrl-Z does.)

2. Rotations of all child prims are calculated relative to the root prim's rotation, so moving the root prim will potentially misalign the entire linkset. For that reason, this script forces recalculation of all child prim orientations if you undo the orientation of the root prim.

3. Information stored in prim Description fields will not change if you take the object to Inventory and re-rez it, but it WILL be reset if you reset this script manually or if you give/sell the object containing it to another person or if you add or remove links. Note in particular, that the script will therefore reset if you or anyone sits on the object. You may change this default with the Sit_OK parameter. If you do that, DO NOT ADD OR REMOVE PRIMS WITHOUT FIRST SETTING Sit_OK TO FALSE AGAIN.

Script

<lsl>//UNDO_PosRot -- July 2010 -- Rolig Loon // // Allows user to undo position and rotation changes that have been made "manually" to prims in a linkset. // This script is free to Copy,Mod, or Transfer -- but PLEASE do not sell it. // // To use: // 1. Name all prims. You have several options: // a. Leave the SL default name "Object" on a prim. // b. Make a prim's Name field blank (The script will name the prim "Child Prim x", where x is a unique number.) // c. Give the prim a unique name of your own choosing. // d. Give multiple prims the same unique name, so that they may be reset with a single command (see 3.b. below) // 2. Place the script in the root prim of the linkset // a. The script will automatically record each prim's current location and rotation in its Description field. DO NOT CHANGE THESE. // b. If you add or remove prims in the linkset, the script will rewrite ALL current prim location/rotation information in ALL prims. // // --- You may move or rotate any prims in the linkset, including the root prim, once the script is in place and has recorded prim information. // // 3. If you want to restore any prim to its last recorded position and rotation, type a command in chat channel 43 as follows: // a. To restore a single prim, type "/43 undo prim_name" (without the quotes), where prim_name is the unique name of that prim // NOTE: Restoring the root prim will force ALL prims to restore, because the root prim's rotation affects all later movements of child prims. // b. To restore all prims with the same name, type "/43 undo all named prim_name", where prim_name is the unique name for those prims. // NOTE: The ROOT prim cannot be moved with this command. // c. To restore all prims in the linkset, type "/43 undo all". // // General notes: // 1. When this script "undoes" a prim's position and rotation, it updates current information in that prim's Description field. Therefore, you // cannot perform multiple "undo" commands on the same prim. (That is, it does not have a memory like Ctrl-Z does.) // 2. If you plan to undo several prims including the root prim, ALWAYS MOVE THE ROOT PRIM FIRST. // 3. Information stored in prim Description fields will not change if you take the object to Inventory and re-rez it, but it WILL be reset if // you reset this script manually or if you give/sell the object containing it to another person or if you add or remove links. Note in // particular, that the script will therefore reset if you or anyone sits on the object. You may change this default with the Sit_OK parameter. // If you do that, DO NOT ADD OR REMOVE PRIMS WITHOUT FIRST SETTING Sit_OK TO FALSE AGAIN.


integer Sit_OK = FALSE; //Change to TRUE to prevent this script from resetting if someone sits on the object vector OldPos; // Stored position of current prim rotation OldRot; // stored rotation of current prim list namelist; // stored prim names integer DChan = 43; // Command channel integer NoPrims; // Number of prims in this linkset integer Chan; // listen handler

OldSettings(integer k) //Read prim Decription fields to get stored positions and rotations {

   string Desc = llList2String(llGetLinkPrimitiveParams(k,[PRIM_DESC]),0);
   integer idx = llSubStringIndex(Desc,"?");
   OldPos = (vector)llGetSubString(Desc,0,idx-1);
   OldRot = (rotation)llGetSubString(Desc,idx+1,-1);

}

RewriteSettings() // Read current prim positions and rotations; record in prim Desc fields {

   namelist = [];
   integer k;
   for (k=1;k<=NoPrims;++k)
   {
       list childPR = llGetLinkPrimitiveParams( k, [PRIM_POSITION, PRIM_ROTATION, PRIM_NAME]); 
       vector global_pos = llList2Vector( childPR, 0);
       rotation global_rot = llList2Rot( childPR, 1);
       namelist += llList2String(childPR,2);
       llSetLinkPrimitiveParamsFast(k, [PRIM_DESC, (string)global_pos + "?" + (string)global_rot]);
   }

}

default {

   state_entry()
   {
       Chan = llListen(DChan,"",llGetOwner(),"");
       NoPrims = llGetNumberOfPrims();
       if (NoPrims == 1)
       {
           llOwnerSay("Sorry.  This script is for use in linksets. To reset individual prims, use Ctrl-Z instead.");
           llListenRemove(Chan);
       }
       integer k;
       for (k=2;k<=NoPrims;++k)  //Name any unnamed prims (Does not affect prims named "Object" or ones named by the user)
       {
           if (llGetLinkName(k) == "")
           {
               llSetLinkPrimitiveParamsFast(k,[PRIM_NAME, "Child Prim " + (string)k]);
           }
       }
       RewriteSettings();
   }
   

listen (integer channel, string name, key id, string msg)

   {
       string Go = llGetSubString(llStringTrim(msg,STRING_TRIM),0,3);
       if(llToUpper(Go) == "UNDO")
       {
           integer k;
           string ThisPrim = llStringTrim(llGetSubString(msg,5,-1),STRING_TRIM);
           integer idx = llListFindList(namelist,[ThisPrim]);
           if (~idx)
           {
               OldSettings(idx+1);
               if (idx != 0)
               {
                   rotation rootrot = llGetRot();
                   vector new_pos = (OldPos - llGetPos())/rootrot;
                   rotation new_rot = OldRot/rootrot/ rootrot;
                   llSetLinkPrimitiveParamsFast( idx+1, [PRIM_POSITION, new_pos, PRIM_ROTATION, new_rot, PRIM_DESC, (string)new_pos + "?" + (string)new_rot]);
               }
           }
           else if (llToUpper(ThisPrim) ==  "ALL" || idx == 0) //If you are resetting the root prim, you must reset all prims.
           {
               OldSettings(1);
               llSetLinkPrimitiveParamsFast(1,[PRIM_POSITION, OldPos*OldRot, PRIM_ROTATION, OldRot]); //Reset root prim first
               for (k=2;k<=NoPrims;++k) // Don't mess with the root prim!
               {
                   OldSettings(k);
                   rotation rootrot = llGetRot();
                   vector new_pos = (OldPos - llGetPos())/rootrot; 
                   rotation new_rot = OldRot/rootrot/ rootrot;
                   llSetLinkPrimitiveParamsFast( k, [PRIM_POSITION, new_pos, PRIM_ROTATION, new_rot]); 
               }
               RewriteSettings(); //Store new positions and rotations in prim Descriptions
           }
           else if (llToUpper(llGetSubString(ThisPrim,0,9)) == "ALL NAMED ")
           {
               string Prim_Name = llGetSubString(ThisPrim, 10,-1);
               for (k=2;k<=NoPrims;++k)
               {
                   if (Prim_Name == llGetLinkName(k)) //Undo ONLY specified links
                   {
                       OldSettings(k);
                       rotation rootrot = llGetRot();
                       vector new_pos = (OldPos - llGetPos())/rootrot; 
                       rotation new_rot = OldRot/rootrot/ rootrot;
                       llSetLinkPrimitiveParamsFast( k, [PRIM_POSITION, new_pos, PRIM_ROTATION, new_rot, PRIM_DESC, (string)new_pos + "?" + (string)new_rot]);
                   }
               }
           }
       }
   }
   
   changed (integer change) 
   {
       if (change & CHANGED_LINK && Sit_OK == FALSE)
       {
           llResetScript();
       }
       else if (change & CHANGED_OWNER)
       {
           llResetScript();
       }
   }

}</lsl>