vtp.lsl 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. // :CATEGORY:Prim Animator
  2. // :NAME:Archipelis scripts for prim animator
  3. // :AUTHOR:Ferd Frederix
  4. // :CREATED:2013-09-06
  5. // :EDITED:2013-09-18 15:38:48
  6. // :ID:52
  7. // :NUM:75
  8. // :REV:1
  9. // :WORLD:Second Life
  10. // :DESCRIPTION:
  11. // Prim storage renumber animation recorder
  12. // - Not a fully debugged useful script.
  13. // It tries to make each prim have a number that matches the prim animator numbers so you can add more prims.
  14. // :CODE:
  15. // Prim Animator DB
  16. // 06/20/2011
  17. // Author Ferd Frederix
  18. // Use with one or more copies of the script 'Store 0..Store 1.. Store N'
  19. // Copyright 2011 Fred Beckhusen aka Ferd Frederix
  20. //
  21. // Licensed under the GNU Version3 license at http://www.gnu.org/copyleft/gpl.html
  22. // This program and the STORE scipts it uses must be left Copy/Transfer/MOD
  23. // Any items that use these scripts may have more restrictive permissions.
  24. // for help and how to use, see "http://meteverse.mitsi.com/secondlife/Posts/Prim-Animator-DB
  25. // Prim position root script
  26. // Put this script in the root prim.
  27. // touch the prim to start recording
  28. // Record - store a new set of child prim positions
  29. // Clear RAM - wipe out all recording in the prim. Leaves the database intact
  30. // Pause - insert a 0.1 second pause
  31. // Erase - Erases the Server data
  32. // Load - Loads the data from the Server
  33. // Publisgh - Saves the data to the database
  34. // Recordings - Lists all recordings ( up to 16)
  35. // Name - name a new recording
  36. // Play All Plays back all recordings with a 1 second Pause.
  37. // Publish - Saves to database
  38. // Help - Get Web Help
  39. // More - TBD
  40. // configurable things
  41. string MyName ; // The creator of the animation
  42. string MyItemName; // a Name just for this unique item and any copies
  43. integer debug = TRUE; // if set to TRUE, debug info appears
  44. // Code follows - no need to edit below this line.
  45. // remote db reading
  46. key kHttpRequestID;
  47. integer countLoaded = 0; // how many nanims have been loaded via HTTP
  48. integer iPlayChannel = 1; // the playback channel, this is the channel you use in LinkMessages
  49. integer countchannel= 2001; // how many have been saved
  50. integer iDialogChannel ; // dialog boxes
  51. integer iPrimCount ; // total number of prims
  52. integer iWantNameFlag; // flag indicating we are waiting for a name to be chatted
  53. integer imax; // total records in store
  54. integer runtime = 0; // set to 1 after Recording and publishing.
  55. // animation store
  56. string sCurrentAnimationName; // The name of the animation we are playing
  57. string sPriorAniName; // the prior animation name so we can spot differences as we read them in
  58. list lLastPrimList; // storage of the last prim position we learned
  59. integer iLastSTRIDE = 4; // size of the last prim list
  60. integer iListenerHandle; // temp iListenerHandle when we are waiting for them to give us a name
  61. list lUserAnimNames; // animations read from the notecard added to the Menu display
  62. // Commands
  63. integer Clear = 99; // erase local db
  64. integer Erase = 100; // erase Server DB command
  65. integer Add = 101; // add a coordinate
  66. integer Publish = 102; // save to db
  67. integer Name = 103; // send Name to db
  68. integer thisName = 104; // send thisName to db
  69. integer Play = 105; // play channel to make an animation run
  70. list NameNum; // 2 stride list of real vs virtual numbers of prims
  71. Debug( string msg)
  72. {
  73. if (debug) llOwnerSay(msg);
  74. }
  75. integer getVirtual(integer real)
  76. {
  77. llOwnerSay("Seeking " + (string) real);
  78. integer i;
  79. integer num = llGetListLength(NameNum);
  80. for (i = 0 ; i < num; i += 2)
  81. {
  82. llOwnerSay("Examine " + (string) i);
  83. if (llList2Integer(NameNum,i) == real)
  84. {
  85. llOwnerSay("Located " + (string) real);
  86. return (real);
  87. }
  88. }
  89. integer new = i/2 +1;
  90. llOwnerSay("Returning " + (string) new);
  91. return new;
  92. }
  93. Renumber()
  94. {
  95. integer realPrimNum ;
  96. for ( realPrimNum = 2; realPrimNum < iPrimCount; realPrimNum++)
  97. {
  98. list name = llGetLinkPrimitiveParams(realPrimNum,[PRIM_DESC] );
  99. integer num = (integer) llList2String(name,0);
  100. if (num == realPrimNum)
  101. {
  102. NameNum += num;
  103. NameNum += num;
  104. }
  105. else
  106. {
  107. integer newNum = getVirtual(realPrimNum); // get the next unused prim Number
  108. string newname = generate_index(newNum); // make 2 digits
  109. llSetLinkPrimitiveParamsFast(realPrimNum,[ PRIM_DESC,newname ]); // save it
  110. NameNum += (integer) newname; // save it in the Real to Virtual List
  111. NameNum += num;
  112. }
  113. }
  114. llOwnerSay(llDumpList2String(NameNum,","));
  115. }
  116. // get a 2-digit string fiven a number
  117. string generate_index(integer i)
  118. {
  119. if (i < 10)
  120. return "0" + (string)i;
  121. return (string)i;
  122. }
  123. // clear any old listeners and make a new on to control lag
  124. NewListen()
  125. {
  126. iDialogChannel = (integer) (llFrand(400) + 300);
  127. llListenRemove(iListenerHandle);
  128. iListenerHandle = llListen(iDialogChannel,"","","");
  129. }
  130. // prompt the user for an animation name. Uses text box or chat
  131. AskForName()
  132. {
  133. iWantNameFlag = TRUE;
  134. llSetTimerEvent(60);
  135. NewListen();
  136. llOwnerSay("Enter the name in the text box or type the new animation name on channel /" + (string) iDialogChannel );
  137. llTextBox(llGetOwner(),"Type the new animation name",iDialogChannel);
  138. }
  139. Get(string data)
  140. {
  141. Debug("Data was " + data);
  142. list lLine = (llParseString2List(data, ["|"], []));
  143. string sAniName = llList2String(lLine,0);
  144. string sNum = (string) Getline(lLine,1);
  145. float fNum = (float) sNum;
  146. vector vPos = (vector) Getline(lLine,2); // global for calcChild()
  147. rotation rRot = (rotation) Getline(lLine,3); // global for calcChild()
  148. vector vprimSize = (vector) Getline(lLine,4);
  149. countLoaded++;
  150. // the first record is always the root prim size
  151. if (fNum == 0)
  152. {
  153. FetchNext();
  154. return;
  155. }
  156. if (sAniName != sPriorAniName)
  157. {
  158. sPriorAniName = sAniName;
  159. sCurrentAnimationName = sAniName;
  160. if (llListFindList(lUserAnimNames,[sAniName]) == -1)
  161. {
  162. Debug("Loading animation " + sAniName);
  163. lUserAnimNames += sAniName;
  164. }
  165. }
  166. // Debug("Loading Prim #" + (string) fNum);
  167. if(fNum != 1) // skip root prim
  168. {
  169. sCurrentAnimationName = sAniName;
  170. llMessageLinked(LINK_THIS,Add,sAniName
  171. +"|"
  172. + (string) fNum
  173. +"|"
  174. + (string) vPos
  175. + "|"
  176. + (string) rRot
  177. + "|"
  178. + (string) vprimSize,"");
  179. llSetText("Initialising... \n" + (string) (countLoaded) , <1,1,1>, 1.0);
  180. }
  181. llSleep(1); // http throttle avoidance
  182. FetchNext();
  183. }
  184. // in case of hand editing, we wupe out extra stuff at end
  185. string Getline(list Input, integer line)
  186. {
  187. return llStringTrim(llList2String(Input, line),STRING_TRIM);
  188. }
  189. Record()
  190. {
  191. if (llStringLength(sCurrentAnimationName) > 0)
  192. {
  193. integer ifoundmovement = 0; // will be set if any child moved
  194. integer iPrimCounter ; // skip past the root prim
  195. for (iPrimCounter =2; iPrimCounter <= iPrimCount ; iPrimCounter++ )
  196. {
  197. list my_list = llGetLinkPrimitiveParams(iPrimCounter,[PRIM_POSITION,PRIM_ROTATION, PRIM_SIZE ]);
  198. // position is always in region coordinates, even if the prim is a child or the root prim of an attachment.
  199. // rot is always the global rotation, even if the prim is a child or the root prim of an attachment.
  200. // get current prim pos, rot and size
  201. vector vrealPrimPos = llList2Vector (my_list,0) - llGetPos(); // position subtract Global Pos
  202. vrealPrimPos /= llGetRot();
  203. rotation rrealPrimRot = llList2Rot (my_list,1) / llGetRot(); // rotation subtract Global Rot
  204. vector vrealPrimSize = llList2Vector (my_list,2); // size
  205. // compare it to the last one we had, stride of list is a 4, and it is already sorted
  206. integer iindex = (iPrimCounter - 2) * iLastSTRIDE; // zeroth position is fPrimCounter - start, or 2
  207. // get the last thing we remembered about this prim
  208. integer iprimNum = llList2Integer (lLastPrimList, iindex); // must be 0,1,2, in order
  209. vector vlastPrimPos = llList2Vector (lLastPrimList, iindex+1);
  210. rotation rlastPrimRot = llList2Rot (lLastPrimList, iindex+2);
  211. vector vlastPrimSize = llList2Vector (lLastPrimList, iindex+3);
  212. // if anything changed on this prim, we must record it.
  213. if (vlastPrimPos != vrealPrimPos ||
  214. rlastPrimRot != rrealPrimRot ||
  215. vlastPrimSize!= vrealPrimSize
  216. )
  217. {
  218. ifoundmovement++;
  219. //Save them in the master list of all animations
  220. llMessageLinked(LINK_THIS,Add,sCurrentAnimationName+ "|"
  221. + (string) iPrimCounter
  222. + "|"
  223. + (string) vrealPrimPos
  224. + "|"
  225. + (string) rrealPrimRot
  226. + "|"
  227. + (string) vrealPrimSize,"");
  228. imax = llGetListLength(lLastPrimList);
  229. // save the changes in the last prim list so we can keep our lists smaller
  230. lLastPrimList = llListReplaceList(lLastPrimList,[vrealPrimPos],iPrimCounter+1,iPrimCounter+1);
  231. lLastPrimList = llListReplaceList(lLastPrimList,[rrealPrimRot],iPrimCounter+2,iPrimCounter+2);
  232. lLastPrimList = llListReplaceList(lLastPrimList,[vrealPrimSize],iPrimCounter+3,iPrimCounter+3);
  233. //Debug("Saved in history at prim # " + (string) (iPrimCounter));
  234. llSleep(0.1);
  235. } // if
  236. else
  237. {
  238. Debug("Same @" + (string) iPrimCounter);
  239. }
  240. } // for
  241. //Debug("history:" + llDumpList2String(lLastPrimList,":"));
  242. //Debug("master:" + llDumpList2String(lAniStore," "));
  243. if (!ifoundmovement)
  244. {
  245. llOwnerSay("You must move at least one child prim.");
  246. }
  247. }
  248. else
  249. {
  250. AskForName();
  251. }
  252. }
  253. // on reset, record the base position in history so we can see changes
  254. ClearRAM()
  255. {
  256. iPrimCount = llGetNumberOfPrims(); // how many we are recording
  257. Debug("Prim Count = " + (string) iPrimCount);
  258. sCurrentAnimationName = ""; // no name in use
  259. lLastPrimList = []; // wipe last animations list
  260. integer iPrimCounter ;
  261. integer primCounter = 0;
  262. for (iPrimCounter=2; iPrimCounter <= iPrimCount ; iPrimCounter++ ) // skip 1, which is the root prim
  263. {
  264. list my_list = llGetLinkPrimitiveParams(iPrimCounter,[PRIM_POSITION, PRIM_ROTATION, PRIM_SIZE ]);
  265. // save the local pos and rot, since llGetLinkPrimitiveParams returns global pos and rot
  266. vector primpos = llList2Vector (my_list,0) - llGetPos();
  267. primpos /= llGetRot();
  268. rotation primrot = llList2Rot (my_list,1) / llGetRot();
  269. vector primsize = llList2Vector (my_list,2) ;
  270. lLastPrimList += iPrimCounter;
  271. lLastPrimList += primpos;
  272. lLastPrimList += primrot;
  273. lLastPrimList += primsize;
  274. primCounter++;
  275. }
  276. llOwnerSay("RAM is cleared - Initial Settings saved for " + (string) primCounter + " child prims");
  277. }
  278. rotation calcChildRot(rotation rdeltaRot)
  279. {
  280. if (llGetAttached())
  281. return rdeltaRot/llGetLocalRot();
  282. else
  283. return rdeltaRot/llGetRootRotation();
  284. }
  285. MakeMenu()
  286. {
  287. if (runtime)
  288. {
  289. MakeMenu2();
  290. return;
  291. }
  292. list amenu = ["Record","Clear RAM","Pause"] +
  293. ["Erase","Load","Publish"] +
  294. ["Recordings","Name","Play All"] +
  295. ["Help","More", "Finish"];
  296. string menuText = "Available Memory: " + (string) llGetFreeMemory() +
  297. "\n\n" +
  298. "Recordings: Select a named animation\n" +
  299. "Name: Set the animation name\n" +
  300. "Play All: Play all animations\n" +
  301. "Clear RAM: Erase SL memory\n"+
  302. "Erase: Delete Server Data\n" +
  303. "Load: Get from Server\n" +
  304. "Publish: Save to Server\n" +
  305. "Record: Record a snapshot of prim positions\n" +
  306. "Pause: Insert 0.1 second pause\n" +
  307. "Finish: End all programming\n" +
  308. "Help: Help";
  309. NewListen();
  310. llDialog(llGetOwner(), menuText,amenu,iDialogChannel);
  311. }
  312. MakeMenu2()
  313. {
  314. string menuText ;
  315. list menu2 = lUserAnimNames;
  316. menu2 = llDeleteSubList(menu2,11,999); // 12 max
  317. if (runtime)
  318. menu2 += "Unlock";
  319. if (llGetListLength(lUserAnimNames) == 0)
  320. {
  321. menu2 += ["Back"] ;
  322. menuText = " There are no animation names to display\n\n" +
  323. "Back:- Go back to programming menu";
  324. }
  325. else
  326. menuText = "Pick an animation to play.";
  327. NewListen();
  328. llDialog(llGetOwner(), menuText,menu2,iDialogChannel);
  329. }
  330. FetchNext()
  331. {
  332. string url = "http://www.outworldz.com/cgi/animate.plx?Type=Load&Count=" + (string) countLoaded + "&Name=" + llEscapeURL(MyName) + "&Password=" + llEscapeURL(MyItemName);
  333. Debug(url);
  334. kHttpRequestID = llHTTPRequest(url, [], "");
  335. }
  336. default
  337. {
  338. state_entry()
  339. {
  340. MyName = llGetOwner(); // assign the owner if we get reset
  341. MyItemName = llGetObjectDesc(); // and get the name of the Object
  342. llOwnerSay("Animation name from the description is " + MyItemName);
  343. if (MyItemName == "(No Description)" || llStringLength(MyItemName) == 0)
  344. {
  345. MyItemName = "Archipelis_" + (string) (llCeil(llFrand(200000) + 5000000)); // pick a large random number for a name
  346. llOwnerSay("Animations will be saved as '" + MyItemName + "'");
  347. llSetObjectDesc(MyItemName);
  348. }
  349. llMessageLinked(LINK_THIS,Name,MyName,"");
  350. llMessageLinked(LINK_THIS,thisName,MyItemName,"");
  351. if (runtime)
  352. {
  353. ClearRAM();
  354. FetchNext(); // start with first line in DB
  355. }
  356. else
  357. {
  358. ClearRAM();
  359. }
  360. Renumber();
  361. }
  362. http_response(key queryid, integer status, list metadata, string data)
  363. {
  364. if (queryid == kHttpRequestID )
  365. {
  366. if (status == 200) // HTTP success status
  367. {
  368. if (data == "nothing to do")
  369. {
  370. llOwnerSay("Initialized with " + (string) countLoaded + " settings");
  371. llSetText("" , <1,1,1>, 1.0);
  372. return;
  373. }
  374. Get(data);
  375. }
  376. else
  377. {
  378. llOwnerSay("Server Error loading animations");
  379. }
  380. }
  381. }
  382. touch_start(integer total_number)
  383. {
  384. if (llDetectedKey(0) == llGetOwner() )
  385. {
  386. MakeMenu();
  387. }
  388. }
  389. // timed out waitig for a name of an animation
  390. timer()
  391. {
  392. iWantNameFlag = FALSE;
  393. llSetTimerEvent(0);
  394. llOwnerSay(" Timeout waiting for animation name");
  395. llListenRemove(iListenerHandle);
  396. }
  397. listen( integer channel, string name, key id, string message )
  398. {
  399. llListenRemove(iListenerHandle);
  400. // Debug(message);
  401. if (message == "Finish")
  402. {
  403. runtime++;
  404. llOwnerSay("The animator is now locked. Further touches will bring up a list of animations. You must unlock the menu to add more animations");
  405. }
  406. else if (message == "Unlock")
  407. {
  408. runtime = 0;
  409. llOwnerSay("The animator is now unlocked for programming.");
  410. }
  411. else if (message == "Erase")
  412. {
  413. llMessageLinked(LINK_THIS,Erase,"",""); // erase the db
  414. MakeMenu();
  415. }
  416. else if (message == "Clear RAM")
  417. {
  418. ClearRAM();
  419. MakeMenu();
  420. }
  421. else if (message =="Pause")
  422. {
  423. llMessageLinked(LINK_THIS,Add,"sCurrentAnimationName|"
  424. + "-0.1" // sleep 1 tenth a second
  425. + "|"
  426. + "<0,0,0>" // null pos
  427. + "<0,0,0,1>" // null rot
  428. + "|"
  429. + "<0,0,0>",""); // null size
  430. MakeMenu();
  431. }
  432. else if (message == "Recordings")
  433. {
  434. MakeMenu2();
  435. }
  436. else if (message == "Load")
  437. {
  438. countLoaded = 0;
  439. FetchNext(); // start with first line in DB
  440. }
  441. else if (message == "Record")
  442. {
  443. Record();
  444. MakeMenu();
  445. }
  446. else if (message == "Publish")
  447. {
  448. llMessageLinked(LINK_THIS,Name,MyName,""); // in case we reset just the stores
  449. llMessageLinked(LINK_THIS,thisName,MyItemName,"");
  450. llMessageLinked(LINK_THIS,Publish,"","");
  451. MakeMenu();
  452. }
  453. else if (message == "Name")
  454. {
  455. AskForName();
  456. }
  457. else if (message == "Back")
  458. {
  459. MakeMenu();
  460. }
  461. else if (message == "More")
  462. {
  463. MakeMenu();
  464. }
  465. else if (message == "Play All")
  466. {
  467. integer l = llGetListLength(lUserAnimNames);
  468. if (l == 0)
  469. llOwnerSay("Nothing to do");
  470. else
  471. {
  472. integer i = 0;
  473. for ( i = 0; i < l; i++)
  474. {
  475. string ani = llList2String(lUserAnimNames,i);
  476. llMessageLinked(LINK_THIS,Play,ani,"");
  477. llSleep(1);
  478. }
  479. }
  480. MakeMenu();
  481. }
  482. else if (message == "Help")
  483. {
  484. llLoadURL(llGetOwner(),"View online help", "http://www.outworldz.com/secondlife/Posts/Prim-Animator-DB");
  485. }
  486. else if (iWantNameFlag)
  487. {
  488. sCurrentAnimationName = message;
  489. if (llGetListLength(lUserAnimNames) < 11)
  490. {
  491. if (llListFindList(lUserAnimNames,[sCurrentAnimationName]) == -1)
  492. lUserAnimNames += message;
  493. }
  494. else
  495. {
  496. lUserAnimNames = llDeleteSubList(lUserAnimNames,11,99);
  497. }
  498. MakeMenu();
  499. llOwnerSay("Ready to record animation '" + sCurrentAnimationName + "'");
  500. llOwnerSay("Position all child prims, then select the Menu item 'Record', and repeat as necessary. When finished, click the name to play back the animation. Click 'Name' again to start a new animation sequence.");
  501. iWantNameFlag = 0;
  502. llSetTimerEvent(0);
  503. }
  504. else
  505. {
  506. if (llListFindList(lUserAnimNames,[message]) != -1)
  507. {
  508. Debug("playback animation " + message);
  509. llMessageLinked(LINK_THIS,Play,message,"");
  510. MakeMenu();
  511. }
  512. }
  513. }
  514. link_message(integer sender_num, integer num, string message, key id)
  515. {
  516. if (num == countchannel)
  517. {
  518. llSetText("Loaded " + message,<1,1,1>,1.0);
  519. }
  520. else if (num == iPlayChannel) // external messages come in channel 1 - change them to channel Play
  521. {
  522. Debug("playback animation " + message);
  523. llMessageLinked(LINK_THIS,Play,message,"");
  524. }
  525. }
  526. }