Animator-III 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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:77
  8. // :REV:1
  9. // :WORLD:Second Life
  10. // :DESCRIPTION:
  11. // An almost unlimited space prim animator. It uses multiple Store Scripts, that can hold thousands of prim animations
  12. // The original version of the script. Must be used with Multiple copies of Store 0..1,2, to animate prims
  13. // :CODE:
  14. // author Ferd Frederix
  15. // Prim position root script
  16. // Put this script in the root prim.
  17. // touch the prim to start recording
  18. // Clear - wipe out all recording.
  19. // Name - name a new recording
  20. // Pause - insert a 1 second pause
  21. // Record - store a new set of child prim positions
  22. // Publish - Saves to database
  23. // Help
  24. // >> and << to cycle each animation
  25. // configurable things
  26. string MyName ="horse 5"; // the name of the Entire set of animations, must be unique
  27. string MyPassword = "ferdzee"; // a password just for you and your stuff
  28. integer debug = 0; // if set to TRUE, debug info appears
  29. // remote db reading
  30. key kHttpRequestID;
  31. integer countLoaded = 0; // how many nanims have been loaded via HTTP
  32. integer iPlayChannel = 1; // the playback channel, this is the channel you use in LinkMessages
  33. integer countchannel= 2001; // how many have been saved
  34. integer iDialogChannel ; // dialog boxes
  35. integer iPrimCount ; // total number of prims
  36. integer iWantNameFlag; // flag indicating we are waiting for a name to be chatted
  37. integer imax; // total records in store
  38. integer runtime = 0; // set to 1 after Recording and publishing.
  39. // animation store
  40. string sCurrentAnimationName; // The name of the animation we are playing
  41. string sPriorAniName; // the prior animation name so we can spot differences as we read them in
  42. list lLastPrimList; // storage of the last prim position we learned
  43. integer iLastSTRIDE = 4; // size of the last prim list
  44. integer iListenerHandle; // temp iListenerHandle when we are waiting for them to give us a name
  45. list lUserAnimNames; // animations read from the notecard added to the Menu display
  46. // Commands
  47. integer Clear = 99; // erase local db
  48. integer Erase = 100; // erase Server DB command
  49. integer Add = 101; // add a coordinate
  50. integer Publish = 102; // save to db
  51. integer Name = 103; // send Name to db
  52. integer Password = 104; // send Password to db
  53. integer Play = 1; // play channel to make an animation run
  54. Debug( string msg)
  55. {
  56. if (debug) llOwnerSay(msg);
  57. }
  58. // clear any old listeners and make a new on to control lag
  59. NewListen()
  60. {
  61. iDialogChannel = (integer) (llFrand(400) + 300);
  62. llListenRemove(iListenerHandle);
  63. iListenerHandle = llListen(iDialogChannel,"","","");
  64. }
  65. // prompt the user for an animation name. Uses text box or chat
  66. AskForName()
  67. {
  68. iWantNameFlag = TRUE;
  69. llSetTimerEvent(60);
  70. NewListen();
  71. llOwnerSay("Enter the name in the text box or type the new animation name on channel /" + (string) iDialogChannel );
  72. llTextBox(llGetOwner(),"Type the new animation name",iDialogChannel);
  73. }
  74. Get(string data)
  75. {
  76. Debug("Data was " + data);
  77. list lLine = (llParseString2List(data, ["|"], []));
  78. string sAniName = llList2String(lLine,0);
  79. string sNum = (string) Getline(lLine,1);
  80. float fNum = (float) sNum;
  81. vector vPos = (vector) Getline(lLine,2); // global for calcChild()
  82. rotation rRot = (rotation) Getline(lLine,3); // global for calcChild()
  83. vector vprimSize = (vector) Getline(lLine,4);
  84. countLoaded++;
  85. // the first record is always the root prim size
  86. if (fNum == 0)
  87. {
  88. FetchNext();
  89. return;
  90. }
  91. if (sAniName != sPriorAniName)
  92. {
  93. sPriorAniName = sAniName;
  94. sCurrentAnimationName = sAniName;
  95. if (llListFindList(lUserAnimNames,[sAniName]) == -1)
  96. {
  97. Debug("Loading animation " + sAniName);
  98. lUserAnimNames += sAniName;
  99. }
  100. }
  101. // Debug("Loading Prim #" + (string) fNum);
  102. if(fNum != 1) // skip root prim
  103. {
  104. sCurrentAnimationName = sAniName;
  105. llMessageLinked(LINK_THIS,Add,sAniName
  106. +"|"
  107. + (string) fNum
  108. +"|"
  109. + (string) vPos
  110. + "|"
  111. + (string) rRot
  112. + "|"
  113. + (string) vprimSize,"");
  114. llSetText("Initialising... \n" + (string) (countLoaded) , <1,1,1>, 1.0);
  115. }
  116. llSleep(1); // http throttle avoidance
  117. FetchNext();
  118. }
  119. // in case of hand editing, we wupe out extra stuff at end
  120. string Getline(list Input, integer line)
  121. {
  122. return llStringTrim(llList2String(Input, line),STRING_TRIM);
  123. }
  124. Record()
  125. {
  126. if (llStringLength(sCurrentAnimationName) > 0)
  127. {
  128. integer ifoundmovement = 0; // will be set if any child moved
  129. integer iPrimCounter ; // skip past the root prim
  130. for (iPrimCounter =2; iPrimCounter <= iPrimCount ; iPrimCounter++ )
  131. {
  132. list my_list = llGetLinkPrimitiveParams(iPrimCounter,[PRIM_POSITION,PRIM_ROTATION, PRIM_SIZE ]);
  133. // position is always in region coordinates, even if the prim is a child or the root prim of an attachment.
  134. // rot is always the global rotation, even if the prim is a child or the root prim of an attachment.
  135. // get current prim pos, rot and size
  136. vector vrealPrimPos = llList2Vector (my_list,0) - llGetPos(); // position subtract Global Pos
  137. vrealPrimPos /= llGetRot();
  138. rotation rrealPrimRot = llList2Rot (my_list,1) / llGetRot(); // rotation subtract Global Rot
  139. vector vrealPrimSize = llList2Vector (my_list,2); // size
  140. // compare it to the last one we had, stride of list is a 4, and it is already sorted
  141. integer iindex = (iPrimCounter - 2) * iLastSTRIDE; // zeroth position is fPrimCounter - start, or 2
  142. // get the last thing we remembered about this prim
  143. integer iprimNum = llList2Integer (lLastPrimList, iindex); // must be 0,1,2, in order
  144. vector vlastPrimPos = llList2Vector (lLastPrimList, iindex+1);
  145. rotation rlastPrimRot = llList2Rot (lLastPrimList, iindex+2);
  146. vector vlastPrimSize = llList2Vector (lLastPrimList, iindex+3);
  147. // if anything changed on this prim, we must record it.
  148. if (vlastPrimPos != vrealPrimPos ||
  149. rlastPrimRot != rrealPrimRot ||
  150. vlastPrimSize!= vrealPrimSize
  151. )
  152. {
  153. ifoundmovement++;
  154. //Save them in the master list of all animations
  155. llMessageLinked(LINK_THIS,Add,sCurrentAnimationName+ "|"
  156. + (string) iPrimCounter
  157. + "|"
  158. + (string) vrealPrimPos
  159. + "|"
  160. + (string) rrealPrimRot
  161. + "|"
  162. + (string) vrealPrimSize,"");
  163. imax = llGetListLength(lLastPrimList);
  164. // save the changes in the last prim list so we can keep our lists smaller
  165. lLastPrimList = llListReplaceList(lLastPrimList,[vrealPrimPos],iPrimCounter+1,iPrimCounter+1);
  166. lLastPrimList = llListReplaceList(lLastPrimList,[rrealPrimRot],iPrimCounter+2,iPrimCounter+2);
  167. lLastPrimList = llListReplaceList(lLastPrimList,[vrealPrimSize],iPrimCounter+3,iPrimCounter+3);
  168. //Debug("Saved in history at prim # " + (string) (iPrimCounter));
  169. } // if
  170. } // for
  171. //Debug("history:" + llDumpList2String(lLastPrimList,":"));
  172. //Debug("master:" + llDumpList2String(lAniStore," "));
  173. if (!ifoundmovement)
  174. {
  175. llOwnerSay("You must move at least one child prim.");
  176. }
  177. }
  178. else
  179. {
  180. AskForName();
  181. }
  182. }
  183. // on reset, record the base position in history so we can see changes
  184. ClearRAM()
  185. {
  186. iPrimCount = llGetNumberOfPrims(); // how many we are recording
  187. sCurrentAnimationName = ""; // no name in use
  188. lLastPrimList = []; // wipe last animations list
  189. integer iPrimCounter ;
  190. for (iPrimCounter=2; iPrimCounter <= iPrimCount ; iPrimCounter++ ) // skip 1, which is the root prim
  191. {
  192. list my_list = llGetLinkPrimitiveParams(iPrimCounter,[PRIM_POSITION, PRIM_ROTATION, PRIM_SIZE ]);
  193. // save the local pos and rot, since llGetLinkPrimitiveParams returns global pos and rot
  194. vector primpos = llList2Vector (my_list,0) - llGetPos();
  195. primpos /= llGetRot();
  196. rotation primrot = llList2Rot (my_list,1) / llGetRot();
  197. vector primsize = llList2Vector (my_list,2) ;
  198. lLastPrimList += iPrimCounter;
  199. lLastPrimList += primpos;
  200. lLastPrimList += primrot;
  201. lLastPrimList += primsize;
  202. }
  203. llOwnerSay("RAM is cleared");
  204. }
  205. rotation calcChildRot(rotation rdeltaRot)
  206. {
  207. if (llGetAttached())
  208. return rdeltaRot/llGetLocalRot();
  209. else
  210. return rdeltaRot/llGetRootRotation();
  211. }
  212. MakeMenu()
  213. {
  214. if (runtime)
  215. {
  216. MakeMenu2();
  217. return;
  218. }
  219. list amenu = ["Record","Clear RAM","Pause"] +
  220. ["Erase","Load","Publish"] +
  221. ["Recordings","Name","Play All"] +
  222. ["Help","More", "Finish"];
  223. string menuText = "Available Memory: " + (string) llGetFreeMemory() +
  224. "\n\n" +
  225. "Recordings: Select a named animation\n" +
  226. "Name: Set the animation name\n" +
  227. "Play All: Play all animations\n" +
  228. "Clear RAM: Erase SL memory\n"+
  229. "Erase: Delete Server Data\n" +
  230. "Load: Get from Server\n" +
  231. "Publish: Save to Server\n" +
  232. "Record: Record a snapshot of prim positions\n" +
  233. "Pause: Insert 0.1 second pause\n" +
  234. "Finish: End all programming\n" +
  235. "Help: Help";
  236. NewListen();
  237. llDialog(llGetOwner(), menuText,amenu,iDialogChannel);
  238. }
  239. MakeMenu2()
  240. {
  241. string menuText ;
  242. list menu2 = lUserAnimNames;
  243. menu2 = llDeleteSubList(menu2,11,999); // 11 max
  244. if (runtime)
  245. menu2 += "Unlock";
  246. if (llGetListLength(lUserAnimNames) == 0)
  247. {
  248. menu2 += ["Back"] ;
  249. menuText = " There are no animation names to display\n\n" +
  250. "Back:- Go back to programming menu";
  251. }
  252. else
  253. menuText = "Pick an animation to play.";
  254. NewListen();
  255. llDialog(llGetOwner(), menuText,menu2,iDialogChannel);
  256. }
  257. FetchNext()
  258. {
  259. string url = "http://secondlife.mitsi.com/cgi/animate.plx?Type=Load&Count=" + (string) countLoaded + "&Name=" + llEscapeURL(MyName) + "&Password=" + llEscapeURL(MyPassword);
  260. Debug(url);
  261. kHttpRequestID = llHTTPRequest(url, [], "");
  262. }
  263. default
  264. {
  265. state_entry()
  266. {
  267. llMessageLinked(LINK_THIS,Name,MyName,"");
  268. llMessageLinked(LINK_THIS,Password,MyPassword,"");
  269. if (runtime)
  270. {
  271. ClearRAM();
  272. FetchNext(); // start with first line in DB
  273. }
  274. }
  275. http_response(key queryid, integer status, list metadata, string data)
  276. {
  277. if (queryid == kHttpRequestID )
  278. {
  279. if (status == 200) // HTTP success status
  280. {
  281. if (data == "nothing to do")
  282. {
  283. llOwnerSay("Initialized with " + (string) countLoaded + " settings");
  284. llSetText("" , <1,1,1>, 1.0);
  285. return;
  286. }
  287. Get(data);
  288. }
  289. else
  290. {
  291. llOwnerSay("Server Error loading animations");
  292. }
  293. }
  294. }
  295. touch_start(integer total_number)
  296. {
  297. if (llDetectedKey(0) == llGetOwner() )
  298. {
  299. MakeMenu();
  300. }
  301. }
  302. // timed out waitig for a name of an animation
  303. timer()
  304. {
  305. iWantNameFlag = FALSE;
  306. llSetTimerEvent(0);
  307. llOwnerSay(" Timeout waiting for animation name");
  308. llListenRemove(iListenerHandle);
  309. }
  310. listen( integer channel, string name, key id, string message )
  311. {
  312. llListenRemove(iListenerHandle);
  313. // Debug(message);
  314. if (message == "Finish")
  315. {
  316. runtime++;
  317. llOwnerSay("The animator is now locked. Further touches will bring up a list of animations. You must unlock the menu to add more animations");
  318. }
  319. else if (message == "Unlock")
  320. {
  321. runtime = 0;
  322. llOwnerSay("The animator is now unlocked for programming.");
  323. }
  324. else if (message == "Erase")
  325. {
  326. llMessageLinked(LINK_THIS,Erase,"",""); // erase the db
  327. MakeMenu();
  328. }
  329. else if (message == "Clear RAM")
  330. {
  331. ClearRAM();
  332. MakeMenu();
  333. }
  334. else if (message =="Pause")
  335. {
  336. llMessageLinked(LINK_THIS,Add,"sCurrentAnimationName|"
  337. + "-0.1" // sleep 1 tenth a second
  338. + "|"
  339. + "<0,0,0>" // null pos
  340. + "<0,0,0,1>" // null rot
  341. + "|"
  342. + "<0,0,0>",""); // null size
  343. MakeMenu();
  344. }
  345. else if (message == "Recordings")
  346. {
  347. MakeMenu2();
  348. }
  349. else if (message == "Load")
  350. {
  351. countLoaded = 0;
  352. FetchNext(); // start with first line in DB
  353. }
  354. else if (message == "Record")
  355. {
  356. Record();
  357. MakeMenu();
  358. }
  359. else if (message == "Publish")
  360. {
  361. llMessageLinked(LINK_THIS,Name,MyName,""); // in case we reset just the stores
  362. llMessageLinked(LINK_THIS,Password,MyPassword,"");
  363. llMessageLinked(LINK_THIS,Publish,"","");
  364. MakeMenu();
  365. }
  366. else if (message == "Name")
  367. {
  368. AskForName();
  369. }
  370. else if (message == "Back")
  371. {
  372. MakeMenu();
  373. }
  374. else if (message == "More")
  375. {
  376. MakeMenu();
  377. }
  378. else if (message == "Play All")
  379. {
  380. integer l = llGetListLength(lUserAnimNames);
  381. if (l == 0)
  382. llOwnerSay("Nothing to do");
  383. else
  384. {
  385. integer i = 0;
  386. for ( i = 0; i < l; i++)
  387. {
  388. string ani = llList2String(lUserAnimNames,i);
  389. llMessageLinked(LINK_THIS,iPlayChannel,ani,"");
  390. llSleep(1);
  391. }
  392. }
  393. MakeMenu();
  394. }
  395. else if (message == "Help")
  396. {
  397. llLoadURL(llGetOwner(),"View online help", "http://secondlife.mitsi.com/secondlife/Posts/Prim-Animator-DB");
  398. }
  399. else if (iWantNameFlag)
  400. {
  401. sCurrentAnimationName = message;
  402. if (llGetListLength(lUserAnimNames) < 11)
  403. {
  404. if (llListFindList(lUserAnimNames,[sCurrentAnimationName]) == -1)
  405. lUserAnimNames += message;
  406. }
  407. else
  408. {
  409. lUserAnimNames = llDeleteSubList(lUserAnimNames,11,99);
  410. }
  411. MakeMenu();
  412. llOwnerSay("Ready to record animation '" + sCurrentAnimationName + "'");
  413. 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.");
  414. iWantNameFlag = 0;
  415. llSetTimerEvent(1.0);
  416. }
  417. else
  418. {
  419. if (llListFindList(lUserAnimNames,[message]) != -1)
  420. {
  421. Debug("playback animation " + message);
  422. llMessageLinked(LINK_THIS,iPlayChannel,message,"");
  423. MakeMenu();
  424. }
  425. }
  426. }
  427. link_message(integer sender_num, integer num, string message, key id)
  428. {
  429. if (num == countchannel)
  430. {
  431. llSetText("Loaded " + message,<1,1,1>,1.0);
  432. }
  433. }
  434. }