CameraSynch2
CameraSynch2 v1.0.0
Synchronization of multiple avatar cameras.
This script initially needs to be dropped individually into numerous linked prims.
However because the script adds a PIN, after its been added once the owner can issue the "update" command to automatically propogate any changes made to the root script into the child prims/scripts.
TO USE:
1] Rez a bunch of prims, one for each bum you want to sit on them.
2] Link them together.
3] Drop a copy of this script in each prim.
4] Sit one person on the controller seat, and some persons on the other seats.
5] Read the spam when you sit down.
<lsl> // // BELOG Hax // AEST 20071221 0452 [SLT: 20071220 1152] // https://wiki.secondlife.com/wiki/CameraSynch2 // // VERSION: // v1.0.0 revised and wikified from my previous: 'CameraSynch v0.3.1' // Not really well tested, but seems good. // Timer frequency could do with some moderation... Possibly with dynamic adjustment. // // CREDITS: // Meyermagic Salome and Nomad Padar for // http://wiki.secondlife.com/wiki/Camera_Sync // I drew some inspiration from theirs some time after I wrote the first iteration of this script. // I don't think I actually derived anything from it... // but theirs was the original..and Nomad is awesome. //========================================================================= // ---LICENCE START--- // http://creativecommons.org/licenses/by-sa/3.0/ // ie: Attribution licence: // Give me credit by leaving it in the script I created. // Supply my original script with your modified version. // Refer to the wiki URL from which you copied this script. // https://wiki.secondlife.com/wiki/CameraSynch2 // ---LICENCE END--- //=========================================================================
// SHARED CONFIGURATION integer gPayloadPIN = 89876847; //---------------------------------- // CONFIGURATION float gFrequency = 0.02; integer gChan = 0; //---------------------------------- // CORE CODE - controller string gCamController = NULL_KEY; vector gOldCamPos; rotation gOldCamRot; string gOldDesc; integer gTog; // CORE CODE - spectator //-------------------------------------- f_camDefault() { llSetCameraParams([
CAMERA_ACTIVE, FALSE, //1 is active, 0 is inactive CAMERA_BEHINDNESS_ANGLE, 10.0, //(0 to 180) degrees CAMERA_BEHINDNESS_LAG, 0.0, //(0 to 3) seconds CAMERA_DISTANCE, 3.0, //(0.5 to 10) meters CAMERA_FOCUS_LAG, 0.1 , //(0 to 3) seconds CAMERA_FOCUS_LOCKED, FALSE, //(TRUE or FALSE) CAMERA_FOCUS_THRESHOLD, 1.0, //(0 to 4) meters CAMERA_PITCH, 0.0, //(-45 to 80) degrees CAMERA_POSITION_LAG, 0.1, //(0 to 3) seconds CAMERA_POSITION_LOCKED, FALSE, //(TRUE or FALSE) CAMERA_POSITION_THRESHOLD, 1.0, //(0 to 4) meters CAMERA_FOCUS_OFFSET, ZERO_VECTOR //<-10,-10,-10> to <10,10,10> meters ]);
} //---------------------------------- default { on_rez(integer start_param)
{ llResetScript(); } state_entry() { if (gPayloadPIN) llSetRemoteScriptAccessPin(gPayloadPIN); llSitTarget(<0.2, 0.0, 0.5>, <0.0, 0.0, 0.0, 1.0>); integer link = llGetLinkNumber(); if (link>1) { string name = "Spectator#"+(string)(link-1); llSetObjectName(name); llSetColor(<0.0, 1.0, 1.0>, ALL_SIDES); llSetText(name, <1.0, 1.0, 1.0>, 1.0); state repeater; } llSetColor(<1.0, 1.0, 0.0>, ALL_SIDES); llSetObjectName(llGetScriptName()); llSetText("CONTROLLER", <1.0, 1.0, 1.0>,1.0); if (gPayloadPIN) llListen(gChan, "", llGetOwner(), "update"); } listen(integer channel, string name, key id, string message) { integer cc; integer c = cc = llGetNumberOfPrims(); llOwnerSay("WAIT: Propogating scripts..."); while(c>1) { llSetText("Updating: "+(string)(cc-c+1)+"/"+(string)(cc-1) , <1.0, 1.0, 1.0>, 1.0); llRemoteLoadScriptPin(llGetLinkKey(c--), llGetScriptName(), gPayloadPIN, TRUE, 1); } llSetText("CONTROLLER", <1.0, 1.0, 1.0>, 1.0); llOwnerSay("OK: Script propogation completed."); } changed(integer change) { if (change & CHANGED_LINK) { gCamController = llAvatarOnSitTarget(); if (gCamController != NULL_KEY) { llRequestPermissions(gCamController , PERMISSION_TRACK_CAMERA|PERMISSION_TAKE_CONTROLS ); } else { llSetTimerEvent(0.0); llSetObjectDesc(gOldDesc); llResetScript(); } } } run_time_permissions(integer perm) { if(perm & PERMISSION_TAKE_CONTROLS) { llTakeControls(0| CONTROL_LBUTTON,TRUE, TRUE); //work anywhere llInstantMessage(llGetPermissionsKey(), "\nThis device allows the spectator cameras to be controlled by YOU." +"\nUseful Tips:" +"\n1] Ensure you are NOT in mouselook." +"\n2] Spectators cameras track yours with a short delay, and do not move quite as smoothly " +"as yours does, so go slowly and avoid any sudden or disconcerting movements." +"\nREMEMBER: If your drawdistance is greater than a spectators, their camera may be left " +"behind at some point. So if you hear people say 'did we stop moving?' you should move " +"your camera closer to where you are all sitting." ); llSetTimerEvent(gFrequency); } else //never llUnSit(gCamController); } timer() { vector camPos = llGetCameraPos(); rotation camRot = llGetCameraRot(); if (llVecDist(camPos, gOldCamPos) > 0.001 || llAngleBetween(camRot, gOldCamRot) >= 0.0008) { gTog = !gTog; gOldCamPos = camPos; gOldCamRot = camRot; llSetText("RELAYING..",<0.0, (float)gTog, 1.0-gTog>,1.0); llSetObjectDesc((string)camPos+"#"+(string)camRot); } }
} //========================================================================= state repeater { on_rez(integer start_param)
{ llResetScript(); } state_entry() { llSetTimerEvent(0.0); } changed(integer change) { if (change & CHANGED_LINK) { if (llGetLinkNumber() == 0) llResetScript(); key av = llAvatarOnSitTarget(); if (av != NULL_KEY && llGetPermissionsKey() == NULL_KEY) { llRequestPermissions(av, PERMISSION_CONTROL_CAMERA); } } } run_time_permissions(integer perms) { if (perms & PERMISSION_CONTROL_CAMERA) { llInstantMessage(llGetPermissionsKey(), "This device allows the spectator cameras to be centrally controlled." +"\nPlease : " +"\n1] Ensure you are NOT in mouselook." +"\n2] Reset your camera by pushing the escape button 3 or 4 times." +"\nNOTE: If the controller avatar's drawdistance is greater than yours, " +"you may experience being 'left behind' at some point. Either increase " +"your draw distance, or reset your camera again (hit escape a few times) " +"after a short while and hopefully the controllers camera is closer and " +"tracking will resume.\nObviously it helps to let the controller know if " +"they are too far away, but perhaps your drawdistance could also be higher." +"\n[ctrl-P.... graphics tab...'custom' checkbox... 'drawdistance' slider... increase it a bit]" ); llSetTimerEvent(gFrequency); } } timer() { if (llGetPermissionsKey()) { string desc = llList2String(llGetObjectDetails(llGetLinkKey(LINK_ROOT), [OBJECT_DESC]),0); integer index = llSubStringIndex(desc, "#"); vector pos = (vector)llGetSubString(desc, 0, index-1); if (pos == ZERO_VECTOR) { f_camDefault(); return; } rotation rot = (rotation)llGetSubString(desc, index+1, -1); llSetCameraParams([ CAMERA_ACTIVE, 1 //1 is active, 0 is inactive ,CAMERA_BEHINDNESS_ANGLE, 0.0 //(0 to 180) degrees
// ,CAMERA_BEHINDNESS_LAG, 0.05 //(0 to 3) seconds
,CAMERA_DISTANCE, 0.0 //(0.5 to 10) meters ,CAMERA_FOCUS, pos + llRot2Fwd(rot) //Region-relative ,CAMERA_FOCUS_LAG, 0.05 //(0 to 3) seconds ,CAMERA_FOCUS_LOCKED, TRUE //(TRUE or FALSE) ,CAMERA_FOCUS_THRESHOLD, 0.0 //(0 to 4) meters ,CAMERA_POSITION, pos //Region-relative position ,CAMERA_POSITION_LAG, 0.05 //(0 to 3) seconds ,CAMERA_POSITION_LOCKED, TRUE //(TRUE or FALSE) ,CAMERA_POSITION_THRESHOLD, 0.0 //(0 to 4) meters ,CAMERA_FOCUS_OFFSET, ZERO_VECTOR //<-10,-10,-10> to <10,10,10> meters ]); } else { llSetTimerEvent(0.0); } }
} //=========================================================================
</lsl>