Jump to content

Quistess Alpha

Resident
  • Posts

    3,878
  • Joined

  • Last visited

Everything posted by Quistess Alpha

  1. You'd have to do some research based on specific characters, but llEscapeURL() might be worth looking into to remove special characters.
  2. If I'm understanding this example correctly, I think "itemsCount" was intended to be the length of the array contained in items, but yeah, a shame. If you ~really just needed the length of the array without iterating, for a sufficiently large array it might be possible to play hot and cold to get the length more efficiently (I.E. is there an element at position 1? yes -> 2? yes-> 4?yes ->8? yes-> 16? -> no 12? no -> 10? yes -> 11? yes -> list has 11 elements (8 checks) )
  3. This specifically seems to be invalid JSON, if you're getting something like this from your server, you'll need to remove the outermost set of curly braces. Cleaning up the formatting of the JSON a little to make it clearer and adding more than one element per array might make things clearer. maybe stepping through the JSON one level at a time might make things clearer before trying to write a general routine? string JSON = "{ \"itemsCount\":1, \"pagesCount\":1, \"items\": [ { \"id\":\"a uuid\", \"name\":\"name of track\", \"artist\":\"name of artist\", \"album\":\"name of album\", \"duration\":\"playing time\", \"genres\": [ { \"id\":12, \"name\":\"Soul/R&B\" }, { \"id\":13, \"name\":\"Funk\" }, ], \"image\": { \"preview\":\"url of album cover\" }, \"price\":n, \"currency\": { \"id\":4,\"name\":\"name of currency\", \"imageUrl\":\"url for currency symbol\" }, \"status\":\"PURCHASED\", \"isNew\":true, \"isPreviewAvailable\":true }, { \"id\":\"another uuid\", \"name\":\"name of a different track\", \"artist\":\"name of other artist\", \"album\":\"name of different album\", \"duration\":\"playing time\", \"genres\": [ { \"id\":12, \"name\":\"Soul/R&B\" }, { \"id\":13, \"name\":\"Funk\" }, ], \"image\": { \"preview\":\"url of album cover\" }, \"price\":n, \"currency\": { \"id\":4, \"name\":\"name of currency\", \"imageUrl\":\"url for currency symbol\" }, \"status\":\"PURCHASED\", \"isNew\":true, \"isPreviewAvailable\":true } ] } "; string json_type2string(string s) { if(s==JSON_OBJECT) { return "JSON_OBJECT"; }else if(s==JSON_ARRAY) { return "JSON_ARRAY"; }else if(s==JSON_NUMBER) { return "JSON_NUMBER"; }else if(s==JSON_STRING) { return "JSON_STRING"; }else if(s==JSON_NULL) { return "JSON_NULL"; }else if(s==JSON_TRUE) { return "JSON_TRUE"; }else if(s==JSON_FALSE) { return "JSON_FALSE"; }else if(s==JSON_DELETE) { return "JSON_DELETE"; } return "JSON_INVALID"; } default { state_entry() { llOwnerSay(llJsonGetValue(JSON,["items"])); // returns a JSON_ARRAY. (surrounded by '[]') llOwnerSay(json_type2string(llJsonValueType(JSON,["items"]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0])); // the 0th element of the array. is a JSON_OBJECT (surrounded by '{}') llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres"])); // returns another JSON_ARRAY. llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres"]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",0])); // returns a JSON_OBJECT llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",0]))); llOwnerSay("\n----\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",0,"name"])); // returns a string: Soul/R&B llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",0,"name"]))); llOwnerSay("\n---\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",1,"name"])); // returns a string: Funk llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",1,"name"]))); llOwnerSay("\n---\n"); llOwnerSay(llJsonGetValue(JSON,["items",0,"genres",2,"name"])); // returns JSON_INVALID (because past end of Array) llOwnerSay(json_type2string(llJsonValueType(JSON,["items",0,"genres",2,"name"]))); llOwnerSay("\n---\n"); } } Big idea, for a JSON_OBJECT, you get something inside by asking for one of the keys of a key-vlaue pair (I'm not actually sure how you would get the keys to ask for without knowing something about the format of the JSON a-priori, or converting the JSON_OBJECT to a strided list with llJson2List). for a JSON_ARRAY you get something inside by asking for an index, and to iterate, you ask for indexes starting at 0 and stopping when you get JSON_INVALID as an answer.
  4. You can actually abuse this in convenient ways sometimes. consider (a bit contrived I know): string myList = "apples, oranges, bananas"; { list myList = llCSV2List(myList); // variable masking integer i = llGetListLength(myList); while(~--i) { string myList = llList2String(myList,i); // double masked. llSay(0,myList); } } you could always use separate variable names, but once in a blue moon, using the same variable name saves some nomenclature headaches.
  5. So, I know this is more a viewer issue, but it seems somewhat relevant here. Could someone confirm for the standard viewer and their particular third-party-viewer of choice that attempting to load a script from a file that doesn't exist* leads to a crash (for me a bad one that takes my window manager down with it ), and if so file a Jira? I would but I'm a few viewer versions behind on Kokua (because linux support is dawdling due to lack of devs) and my windows machine (the only one capable of running the official viewer) is unbearably slow and painful to use. . *From a new script: (upper left of the window) file -> 'load from file...' -> type in the name of a file that doesn't exist. Luckily I didn't lose anything when I accidentally tried to load form a file instead of saving to one. . . drop-downs really have a way too small effective clickable area and my pointering abilities have been declining lately.
  6. default? { ?state_entry?(?) { string? test? = ?"string"; ?llOwnerSay(test); } ?touch_start?(?integer?n) { ?while?(~?--?n) { llRegionSayTo(llDetectedKey(n),0,"Touched"); } } } as evidence for the whitespace hypothesis.
  7. Seems the OP fixed their issue, but for a hypothetical future person with the same issue: Does your viewer have RLV on? If so, what's your current restriction list look like?
  8. Well since you mentioned me, I think I might have shared this before, but just to have it in the correct place, here's an early script I made from cobbling together examples on the wiki to 'select a nearby person'. I'm pretty sure it has a few bugs if there are too many people (with long complicated display names) nearby, but it works 'well enough' in most cases. list gItemList; list gLstMnu; // global list for the menu. integer gChannel; integer gListenHandle; // TODO: make this a strided handler,user list for multiple users. list uDlgBtnLst( integer vIdxPag ){ list vLstRtn; if ((gLstMnu != []) > 12){ //-- we have more than one possible page integer vIntTtl = -~((~([] != gLstMnu)) / 10); //-- Total possible pages integer vIdxBgn = (vIdxPag = (vIntTtl + vIdxPag) % vIntTtl) * 10; //-- first menu index string vStrPag = llGetSubString( " ", 21 - vIdxPag, 21 ); //-- encode page number as spaces //-- get ten (or less for the last page) entries from the list and insert back/fwd buttons vLstRtn = llListInsertList( llList2List( gLstMnu, vIdxBgn, vIdxBgn + 9 ), (list)(" «" + vStrPag), 0xFFFFFFFF ) + (list)(" »" + vStrPag); }else{ //-- we only have 1 page vLstRtn = gLstMnu; //-- just use the list as is } return //-- fix the order for [L2R,T2B] and send it out llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) + llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 ); }/*// Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ] //*/ string uList2nString(list l,integer offset) { integer index = llGetListLength(l); string sReturn; while(index>0) { index--; //string item = "secondlife:///app/agent/" + llList2String(l,index) + "/inspect"; string item = llList2String(l,index); sReturn = (string)(index+offset) + ") " + item + "\n" + sReturn; } return sReturn; } default { link_message(integer sender,integer n,string str,key who) { if(n==3) { gItemList=llParseString2List(str,[";"],[]); /*fill gLstMnu with numbers from 0 to llGetListLength(AgentList)*/ integer index=0; integer max = llGetListLength(gItemList); gLstMnu=[]; while(index<max) { gLstMnu+=(string)(index++); } gChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0); gListenHandle = llListen(gChannel,"",who,""); list items=gItemList; if(llGetListLength(items)>10) items=llList2List(gItemList,0,10); llDialog( who, uList2nString(items,0), uDlgBtnLst( 0 ), gChannel ); llSetTimerEvent(60); // 60 second timeout } } listen( integer vIntChn, string vStrNom, key vKeySpk, string vStrMsg ){ if (!llSubStringIndex( vStrMsg, " " )) { //-- detects (hidden) leading non-breaking space of page change buttons integer vIdxPage = ( llStringLength( vStrMsg ) + llSubStringIndex( vStrMsg, "»" ) - 2 ); integer vIdxBgn = 0; if(vIdxPage !=0) { /* calculate the index of the first item in list for this page*/ integer vIntTtl = -~((~([] != gLstMnu)) / 10); vIdxBgn = (vIdxPage = (vIntTtl + vIdxPage) % vIntTtl) * 10; //-- first menu index } llDialog( vKeySpk, uList2nString( llList2List(gItemList,vIdxBgn, vIdxBgn+9),vIdxBgn ), uDlgBtnLst(vIdxPage), vIntChn ); }else { //-- button was not a page button, your code goes here, //-- use (llListFindList( gLstMnu, (list)vStrMsg ) / 10) for remenu command if present //integer vIdxPage=(llListFindList( gLstMnu, (list)vStrMsg ) / 10); llListenRemove(gListenHandle); ///*DEBUG*/llSay(0,"Test! "+(string)llList2Key(gAgentList,(integer)vStrMsg)); llMessageLinked(LINK_THIS,-3,llList2String(gItemList,(integer)vStrMsg),""); } } timer() { llListenRemove(gListenHandle); llSetTimerEvent(0); } } and a template usage script: key gTarget=NULL_KEY; default { touch_start(integer total_number) { llSay(0, "secondlife:///app/agent/"+(string)gTarget+"/inspect"); llMessageLinked(LINK_THIS,2,"",llDetectedKey(0)); //settarget dialog. } link_message(integer link,integer n,string text,key ID) { if(n==-2) // settarget { gTarget=ID; } } } It's better to not use these sorts of things when possible, but sometimes the action is so common and just annoying enough to implement that it make sense to have it in a sepparate "plugin" script.
  9. Agreed, in my actual use-case I had a copy-pasted block of code in 2 locations in the same function, which I was too tired at that moment to logic around merging. (jump was used as a early exit from a loop; it really would be great if LSL had c-style break and continue, but alas. . .)
  10. I'm a little concerned I didn't get any error though, helpful or not.
  11. So, I've never seen LSL do this; when I save a script including this snippet [2 identical jump labels in similar scopes], the viewer doesn't complain, but the server refuses to run the script (close build menu, re-open and edit script and it is set to not running) default { state_entry() { integer a; integer b; if(a) { if(b) { jump break; } @break; }else { if(b) { jump break; } @break; } llOwnerSay("Hello Avatar"); } touch_start(integer total_number) { llSay(0, "Touched."); } }
  12. IMO the most sane solution to the problem would be to allow access to the KVP datastore from outside experience-enabled parcels, but I don't see that happening.
  13. Just a thought, but if this ends up being a user-facing project, you can use a (x)html website embedded in the script to ask the user to upload a file from their computer to the prim. ETA: actually, nevermind, that method cuts the length of the file to a few hundred less than 2048 chars <form enctype="multipart/form-data" method="POST" > <input type="file" name="fileselect"> </input> <input type="submit"></input> </form>
  14. Since you asked, the documentation is a bit loose on attaching to a specific slot, but some older versions of RLV required you to put the attachent point name in the name of the object or folder to be worn. Whenever I've used it, it 'just works' with the default attachment point.
  15. It still ends up one-line on the new script, which is fine if you just want it to run, not so fine if you're trying to understand why it runs. search replace "{" with "{\n" usually gets you a good start. I dunno if the inworld editor can do newlines, but some external ones can.
  16. I think order of operations works in your favor there, but of it were me, I'd use 5.0/9.0 to avoid mixing integer and float arithmetic, or just multiply by .5555 .
  17. A nice example, but as I read it, it returns a fixed number of digits rather than a fixed precision: Fixed to 3 Digits Fixed Precision 10ths place 12.7 12.7 101. 101.5 1.23 1.2 Whether there's a difference depends on the range of the input though. ETA: Actually I'm wrong as I read through it too quickly and didn't think through the weirdness of SL's default presentation, and tacit negative indexes.
  18. There are various methods, but off the top of my head: float fTemp = formula; // calculate the temperature with full accuracy. fTemp = llRound(fTemp*10)*0.1; // round to desired accuracy. string sTemp = (string)fTemp; // convert to string; sTemp = llGetSubString(sTemp,0,llSubStringIndex(sTemp,".")+1); // remove trailing 0's. (untested) llInsertString() the decimal point into a llRound()ed integer might be a viable alternative approach, but llInsertString doesn't take negative indexes.
  19. It's not too too bad if you also cut movement speed by about half. Last time this discussion came up (found it) someone touted these trailers as being a good example of realistic sizing so I took a blurry video:
  20. The region sim doesn't stream audio itself, it just passes on the stream's URL to interested viewers.
  21. Unfortunately, I don't think you can easily manage the complexity inherent in a project like that with the limited tools LSL has available, unless you limit yourself to some very specific parameters to adjust an 'already finished' build. The main 'do it yourself' building systems I'm aware of are sets of mesh elements that all work together at a specific scale, and not much customization on them is possible beyond llSetScale();. See for example: Zimberlab Blocks, Zimberlab Walls (they're different systems, useful to compare/contrast), Isil's 'Sci-fi' system
  22. Another (rather expensive) method would be to add 14 [1]'s and 1000-14 = 986 [0]'s to a list, llListRandomize() it and step through it, rezing if you pick a [1] from the list, re-randomizing after you hit the end. That would result in a different kind of random distribution.
  23. If @ing those people doesn't work, you could always try filing a jira https://jira.secondlife.com/secure/Dashboard.jspa
  24. it depends on how the asset class ends up being managed. If it's fully configurable using in-world utilities (like a day/night setting object) ho-ray. On the other hand, if LL throws up their hands and implements it more like current textures (no 'fundamental' changes after upload, no-mod practically just applies to the description field) I could see some concerns.
  25. You could try opening the stream URL in an in-world browser session. (ctrl-f seems to open a window in Kokua, YMMV for other viewers)
×
×
  • Create New...