texture_server.lsl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. // :CATEGORY:XS Pet
  2. // :NAME:XS Pet Robot
  3. // :AUTHOR:Ferd Frederix
  4. // :KEYWORDS: Pet,XS,breed,breedable,companion,Ozimal,Meeroo,Amaretto,critter,Fennux,Pets
  5. // :CREATED:2013-09-06
  6. // :EDITED:2014-07-29
  7. // :ID:988
  8. // :NUM:1453
  9. // :REV:0.54
  10. // :WORLD:Second Life, OpenSim, Opensim
  11. // :DESCRIPTION:
  12. // XS Pet textures server
  13. // :CODE:
  14. // Revisions 0.51 changed llCeil to llFloor to not skip texture 0 and changed an index to not run off the end for texture 1.0
  15. // revision 0.54 07-28-2014 fixed server to actually work.
  16. // Xs_Pets textures
  17. /////////////////////////////////////////////////////////////////////
  18. // This code is licensed as Creative Commons Attribution/NonCommercial/Share Alike
  19. // See http://creativecommons.org/licenses/by-nc-sa/3.0/
  20. // Noncommercial -- You may not use this work for commercial purposes
  21. // If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.
  22. // This means that you cannot sell this code but you may share this code.
  23. // You must attribute authorship to me and leave this notice intact.
  24. //
  25. // Exception: I am allowing this script to be sold inside an original build.
  26. // You are not selling the script, you are selling the build.
  27. // Ferd Frederix
  28. ////////////////////////////////////////////////////////////////////y
  29. // You must put any textures you want to send to your pets in the same prim as this server.
  30. // You MUST have a notecard named "Breed"
  31. // Each line of the notecard must be the name of the pet Breed type. The first line matches the first texture, and so on.
  32. // example notecard for a two texture chicken:
  33. // Fat Yellow Chicken
  34. // Scrawny Red Chicken
  35. // The first one will be the name of the breed for Body 0, Head 0
  36. // The Scrawny red chicken wiol be the breed name for Body 1, Head 1
  37. // Colors such as color1 and color2 are stored in the Description of the pet prims. Use the prim Name for the texture name
  38. //
  39. // The names must match the following pattern:
  40. // PrimName N
  41. // Where PrimName is the name you put in the prim to be textured, and N is a number from 0 to however many sets of skins you have.
  42. //
  43. // 2-prime xample: Body 0
  44. // Head 0
  45. // Body 1
  46. // Head 1
  47. //
  48. // In this case, there should be at least two prims in the pet whoes prim name is Body/Head
  49. // So you will end up with two possible breeds for your pets, either the 0th or the 1st textures.
  50. //
  51. // If the breedable param Color1.x value (Red coloration) is < 0.5, you get Body 0 and Head 0, and the name will be Fat Yellow Chicken
  52. // If the breedable param Color1.x value (Red coloration) is > 0.5, you get Body 1 and Head 1 and the name will be Scrawny Red Chicken
  53. // The pets breed by mixing colors. If a 1.0 (all Red) breeds with a 0.0 (No Red), you get a code near the average, or 0.5.
  54. // Root prim:
  55. // There is a special name 'root' for the root prim since your pet could be renamed, whioch would change the name of the root prim..
  56. // root 0 would be the name to use for the first root prim texture, root 1 for the second, and so on.
  57. // If your root prim is an invisible prim or is not to be textured, you can ignore this 'root' name.
  58. // Deeper example:
  59. // You have a pet robot with 3 sets of breedable skins, and 4 prims, called 'head'. 'body', 'leg' and 'tail'.
  60. // You will need 3X4, or 12 textures in all.
  61. // edit the pet, and change the name of the head to 'head', change the body name to 'body', the left leg to 'leg', and the right leg to 'leg'.
  62. // each texture must also a single digit after it to represent the breed type:
  63. // head 0, head 1 and head 2
  64. // body 0, body 1, and body 2
  65. // leg 0, leg 1, and leg 2
  66. // tail 0 , tail 1, and tail 2
  67. // you may have up to 254 total textures in the server. In the above example, there are
  68. // 4 textures per skin set, so you can have 254/4, or 63 skins for your pet.
  69. // What about the root prim?
  70. // The last prim you link to is the root prim. It holds the xs_pet scripts.
  71. // This prim gets renamed in various objects, so you cannot add a name to the prim that matches a
  72. // texture. A special texture name 'root 0', 'root 1' etc. is set aside for this prim.
  73. // Most xs_pets will not need to use the root prim texture, because the root prim is the base of the pet
  74. // and it usually is made invisible. If your root prim needs to be visible and textured,
  75. // just add a root 0, root1 and so on texture for each texture set.
  76. //////////////////////////////////////////////////////////
  77. // CONFIGURATION //
  78. //////////////////////////////////////////////////////////
  79. // you must put in a UUID from this web site here and in the brain script
  80. //http://gridurl.appspot.com/random
  81. string UUID = "48246356-a7c5-474b-a6fe-f2cec98926b2";
  82. integer debug = TRUE; // set to 1 or TRUE for debuging information to the owner
  83. integer LSLEDIT = FALSE; // set to TRUE if debugging in LSLEditor as it does not support the HTTP headers we need.
  84. // Type "POST" in the [method] field and click [http_response]
  85. // You should get a response based on "teststring" below
  86. float testBreed = 0.01;
  87. // 1/13/2, 1/2 the number of textures.
  88. //for testing to fake out HTTP traffic for a breed value of whatever this string is.
  89. // 0.0 is the first, 1.0 is the last
  90. float testIncrement = 0.076923077;
  91. // 1/13 , the number of test textures
  92. integer testCounter = 0; // just for testing in LSLEditor.
  93. //////////////////////////////////////////////////////////
  94. // INTERNALS //
  95. //////////////////////////////////////////////////////////
  96. key notecardQueryId;
  97. string notecardName = "Breeds"; // the notecard
  98. integer notecardLine; // script-wise, the first notecard line is line 0, the second line is line 1, etc.
  99. list textureDB; // texture storage
  100. integer nTextures; // how many we find
  101. integer nServed; // how many we served
  102. integer nPrims ; // how many prims there must be
  103. integer nBreeds; // how man breeds
  104. list lNames; // a list of names
  105. list lBreedNames; // a list of breed names read from the notecard
  106. key gtextureUUID; // The UUID of the detected texture
  107. string gtextureName; // the name of the detected texture
  108. key URLReq = NULL_KEY;
  109. string url; // sop we can release HTTP-In keys
  110. key urlRequestId;
  111. getNoteCard()
  112. {
  113. notecardLine = 0;
  114. notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
  115. }
  116. request_url()
  117. {
  118. DEBUG("get URL");
  119. llReleaseURL(url);
  120. url = "";
  121. urlRequestId = llRequestURL();
  122. }
  123. getImage(integer breedNum, string Name)
  124. {
  125. DEBUG("Seeking Number " + (string) breedNum );
  126. integer i;
  127. integer j = llGetListLength(textureDB);
  128. for (i = 0; i < j; i += 3)
  129. {
  130. integer myBreedParam = llList2Integer(textureDB,i);
  131. string humanName = llList2String(textureDB,i+1);
  132. key UUID = llList2Key(textureDB,i+2);
  133. gtextureName = humanName;
  134. gtextureUUID = UUID;
  135. if (myBreedParam >= breedNum && Name == humanName)
  136. {
  137. DEBUG("saving " + humanName + " " + (string) myBreedParam);
  138. return;
  139. }
  140. }
  141. return;
  142. }
  143. list ListUnique( list lAll ) {
  144. integer i;
  145. list lFiltered = llList2List(lAll, 0, 0);
  146. integer iAll = llGetListLength( lAll );
  147. for (i = 1; i < iAll; ++i) {
  148. if ( llListFindList(lFiltered, llList2List(lAll, i, i) ) == -1 ) {
  149. lFiltered += llList2List(lAll, i, i);
  150. }
  151. }
  152. return lFiltered;
  153. }
  154. list parsePostData(string message)
  155. {
  156. list postData = [];
  157. list parsedMessage = llParseString2List(message,["&"],[]);
  158. integer len = ~llGetListLength(parsedMessage);
  159. while(++len) {
  160. string currentField = llList2String(parsedMessage, len);
  161. integer split = llSubStringIndex(currentField,"=");
  162. if(split == -1) {
  163. postData += [llUnescapeURL(currentField),""];
  164. } else {
  165. postData += [llUnescapeURL(llDeleteSubString(currentField,split,-1)), llUnescapeURL(llDeleteSubString(currentField,0,split))];
  166. }
  167. }
  168. return postData ;
  169. }
  170. getTextures()
  171. {
  172. textureDB = [];
  173. lNames = [];
  174. integer j = llGetInventoryNumber(INVENTORY_TEXTURE);
  175. integer i;
  176. for (i = 0; i < j ; i++)
  177. {
  178. string textureName = llGetInventoryName(INVENTORY_TEXTURE,i);
  179. list splits = llParseString2List(textureName,[" "],[]);
  180. string humanName = llList2String(splits,0);
  181. integer breedParam = (integer) llList2String(splits,1);
  182. key UUID = llGetInventoryKey(textureName);
  183. DEBUG("Name:" + humanName);
  184. DEBUG("breedParam:" + (string) breedParam);
  185. textureDB += breedParam;
  186. textureDB += humanName;
  187. textureDB += UUID;
  188. lNames += humanName;
  189. }
  190. nTextures = llGetListLength(textureDB)/3;
  191. lNames = ListUnique(lNames);
  192. nPrims = llGetListLength(lNames);
  193. if (nPrims == 0) {
  194. llOwnerSay("No Textures!");
  195. nPrims = 1; // prevent divide by zero errors.
  196. }
  197. DEBUG("Number of colorable prims = " + (string) nPrims);
  198. nBreeds = nTextures / nPrims;
  199. textureDB = llListSort(textureDB,3,1);
  200. DEBUG(llDumpList2String(textureDB,"-"));
  201. DEBUG("Number of textures = " + (string) nTextures);
  202. DEBUG("Number of breeds = " + (string) nBreeds);
  203. llSetText("Textures Loaded",<0,1,0>,1.0);
  204. request_url();
  205. }
  206. string getTexture(string body)
  207. {
  208. DEBUG("Parsing " + body);
  209. list incomingMessage = parsePostData(body);
  210. // fake out a http header
  211. if (LSLEDIT)
  212. incomingMessage = llParseString2List(body,["="],[]);
  213. DEBUG("Params: " + llDumpList2String(incomingMessage,"\n"));
  214. if (llList2String(incomingMessage,0) == "breed")
  215. {
  216. float myBreed = (float) llList2String(incomingMessage,1);
  217. DEBUG("myBreed = " + (string) myBreed);
  218. if (myBreed > 1)
  219. myBreed = 1;
  220. integer myBreedNum = llFloor((myBreed * (nBreeds)));
  221. DEBUG("myBreedNum = " + (string) myBreedNum);
  222. string Name = llList2String(lBreedNames,myBreedNum);
  223. string response = Name + "|"; // frst param is the notecard line
  224. DEBUG("Scanning for Breed named: " + Name + " for value = " + (string) myBreed);
  225. llSetText("Served:" + (string) nServed + "\nLast Breed:"+ (string) Name ,<1,1,1>,1.0);
  226. integer i;
  227. for (i = 0; i < nPrims; i++)
  228. {
  229. string breedName = llList2String(lNames,i);
  230. DEBUG("Fetching prim number: " + (string) i);
  231. getImage(myBreedNum,breedName);
  232. response += gtextureName + "|";
  233. response += (string) gtextureUUID + "|";
  234. }
  235. // LSLEDIT DIAGNOSTOCS
  236. if (LSLEDIT)
  237. {
  238. DEBUG("test # "+(string) testCounter);
  239. DEBUG("Name "+ Name);
  240. DEBUG("S.b. "+ llList2String(lBreedNames,testCounter));
  241. if ( Name == llList2String(lBreedNames,testCounter))
  242. {
  243. DEBUG("test Passed************");
  244. } else {
  245. DEBUG("test Failed************");
  246. }
  247. }
  248. return "texture|" + response;
  249. }
  250. return "texture|blank|blank|" + (string) TEXTURE_BLANK; // no name, no prim type, no texture
  251. }
  252. key Request(string URL)
  253. {
  254. llSetText("Registering",<1,1,1>,1.0);
  255. string url = "http://gridurl.appspot.com/reg?service=" + UUID + "&url=" + llEscapeURL(URL) + "/";
  256. return llHTTPRequest( url, [HTTP_METHOD, "GET"], "");
  257. }
  258. throw_exception(string inputString)
  259. {
  260. key owner = llGetOwner();
  261. llInstantMessage(owner, inputString);
  262. llSleep(60); // so we do not flood owner with IM's
  263. llResetScript();
  264. }
  265. DEBUG(string msg)
  266. {
  267. if (debug)
  268. llSay(0,llGetScriptName() + " : " + msg);
  269. }
  270. default
  271. {
  272. state_entry()
  273. {
  274. getNoteCard();
  275. llSetText("Initializing",<1,1,1>,1.0);
  276. }
  277. on_rez(integer param)
  278. {
  279. llResetScript();
  280. }
  281. http_request(key id, string method, string body)
  282. {
  283. DEBUG("Response:" + body);
  284. if (method == URL_REQUEST_GRANTED)
  285. {
  286. DEBUG(body);
  287. url = body; // save body response so we can release it.
  288. URLReq = Request(body);
  289. }
  290. else if(method == URL_REQUEST_DENIED)
  291. {
  292. llOwnerSay("ERROR: URL REQUEST was DENIED "+body);
  293. llSetText("ERROR: URL REQUEST was DENIED",<1,0,0>,1.0);
  294. llSleep(5);
  295. llResetScript();
  296. }
  297. else if(id == URLReq)
  298. {
  299. if (body == "OK")
  300. {
  301. llSetText("OK",<1,0,0>,1.0);
  302. }
  303. else
  304. {
  305. llSetText("Unable to register",<0,0,1>,1.0);
  306. }
  307. }
  308. else if(method == "POST")
  309. {
  310. nServed++;
  311. string resp;
  312. if (LSLEDIT) {
  313. resp = getTexture("breed=" + (string) testBreed);
  314. testBreed += testIncrement; // 1/13
  315. testCounter++;
  316. }
  317. else
  318. resp = getTexture(llGetHTTPHeader(id, "x-query-string"));
  319. DEBUG("Response:" + resp);
  320. llHTTPResponse(id, 200, resp);
  321. }
  322. else
  323. {
  324. llSetText("Not Implemented",<1,0,0>,1.0);
  325. llHTTPResponse(id, 501, "Not Implemented "+method);
  326. }
  327. }
  328. http_response(key request_id, integer status, list metadata, string body)
  329. {
  330. if(URLReq == request_id)
  331. {
  332. URLReq = NULL_KEY;
  333. if(status == 200)
  334. {
  335. llSetText("Ok",<1,1,1>,1.0);
  336. }
  337. else
  338. {
  339. llSetText("Request failed",<1,0,0>,1.0);
  340. llOwnerSay("Request failed status="+(string)status+" "+body);
  341. llSleep(10);
  342. request_url();
  343. }
  344. }
  345. }
  346. dataserver(key query_id, string data)
  347. {
  348. if (query_id == notecardQueryId)
  349. {
  350. if (data == EOF) {
  351. llSetText("Done reading notecard.\n" + (string) llGetListLength(lBreedNames) + " breeds saved.",<1,1,1>,1.0);
  352. DEBUG("Notecard contained: " + llDumpList2String(lBreedNames,","));
  353. getTextures();
  354. }
  355. else
  356. {
  357. list stuff = llParseString2List(data,[" "],[]);
  358. string comment = llList2String(stuff,0);
  359. if (comment != "//") {
  360. lBreedNames += data;
  361. DEBUG( "Reading Breed name =" + data );
  362. }
  363. // bump line number for reporting purposes and in preparation for reading next line
  364. ++notecardLine;
  365. notecardQueryId = llGetNotecardLine(notecardName, notecardLine);
  366. }
  367. }
  368. }
  369. changed (integer what)
  370. {
  371. if (what & CHANGED_INVENTORY)
  372. {
  373. getNoteCard();
  374. }
  375. if (what & (CHANGED_REGION_START ))
  376. {
  377. llReleaseURL(url);
  378. llResetScript();
  379. }
  380. }
  381. }