Jump to content

Quistess Alpha

Resident
  • Posts

    3,994
  • Joined

  • Last visited

Everything posted by Quistess Alpha

  1. Can look a bit funky depending on your tastes. One might consider padding the list to a multiple of 3 first: list pad = ["-","-","-"]; buttons += llDeleteSubList(pad, -llGetListLength(buttons)%3, -1);
  2. "Global behavior" is the default for all commands ending in =n (or =add which is a synonym) unless it's easier on the brain to think of it as limited to the object (Ex. @detach prevents detaching the object which called the command, which is arguably global because no other object can make you able to detach the object which called @detach=n ) RLV keeps track of the restricting object along with the restriction. If my heavy shoes and my heavy shirt both issue "@fly=n" I won't be able to fly unless they both release the restriction. If your object gets redirected through a relay however, all bets are off and it's implementation dependent. The DEM relay is good up to 5 independent objects, but some relays can only keep track of one thing restricting them at a time. If you're doing anything with RLV, you should become familiar with the RLV->'RLV Status...' window.
  3. I dunno, I refuse to give some random organization on the web a cellphone number, so I can't get an access key.
  4. Since the original post was over a year ago, is this still 'urgent'? (I'm not actually interested so not messaging the OP in-world)
  5. I'm pretty sure I tried that; it did not. that stops bash which it is debugging, but not the viewer which was spawned as a different process.
  6. on linux the viewer gets run through a bash script. and I'm not familiar enough with gdb to figure out how to tell it to run a program with specific arguments. Running GDB directly on the executable (descriptively named "do-not-directly-run-kokua") just gives an error about shared libraries not being found (because it wasn't run through the bash script which tells it where to find the libraries) rand 'gdb bash' and changed 'run' to 'run path/to/file' and that worked, tried it again incidentally with the SL radio on this time, after loading the non-extant file, the viewer displayed a static image (didn't react to input) for a minute as the music continued, at which point I would have halted it with gdb but didn't know how, then a minute later my window manager crashed bringing gdb + everytrhing else with it.
  7. Exactly, and if you asked it what would happen if you broke a mirror before they went in and hackily patched it, it would say you'll have 7 years of bad luck. https://www.youtube.com/watch?v=w65p_IIp6JY
  8. Yeah, if you're mixing non-SL images with SL ones, I could see that being useful, as long as you know the resolution of all the non-SL images and can figure out a general formula for the vertical texture offset and scaling. or perhaps alternating showing an image with displaying some other kind of media (allowing the back image to remain a "you do not have media enabled" texture). Tangentially relevant: it would only be able to receive clicks on that face if ctrl+clicked in a not-firestorm viewer (or firestorm with an obscure option enabled) or if the image was displayed through a simple page hosted on the prim via the image tag and a link.
  9. If you only want the image on the face of a prim, set the url of the media directly to the image URL, set the media scaling to 256x192, vertical texture scale to .75 and vertical offset to .875 (easier to do via build menu than via script). But at that point, you might as well just set the face as a regular texture.
  10. sort of, the 0 means there are no items directly in the folder "#RLV/Restraints/Leather Cuffs" the 2 means that in some of the sub folders, (specifically the 'arms' subfolder in this example) there are items that are worn, but there also exist items in some of the sub folders which are not worn. if everything in the folder (including children) is worn, you'd get 30, 03, or 33, if nothing is worn you might get 10, 01 or 11 (ETA: or 00); any other combination implies there exist things in the folder or its children that are not worn. which possibility depends on the structure of the folder. If reading the whole string helps: |02 -> 0:There are no wearables contained in the folder directly, 2: but there are some wearables in child folders and some of them but not all are worn. Arms|30 -> 3:There are wearables in the Arms subfolder and they are all worn; 0: there are no wearables in sub folders of the arms folder Legs|10 -> 1:There are wearables in the Legs sub-folder and none of them are worn, 0: there are no wearables in sub folders of the Legs folder
  11. It's possible, but the web interface textures get retrieved as a funky lowish resolution of 256x192. The relevant (X)HTML is "<img src=\"http://secondlife.com/app/image/"+(string)UUID+"/1\"/>" for example https://picture-service.secondlife.com/b2d5eb75-b4bf-7763-28dc-d46a03f8e992/256x192.jpg (for the curious, it seems plugging any other resolution into the above redirect URL does not work.)
  12. That's a bit of a beast of an example to unpack, in summary, if you only care about attachments which exist directly in the specific folder you're interested in, check the 1-index character of the response, or the lesser of the 1-index and 2-index characters* if you're also interested in attachments in the sub-folders of the folder you're interested in. An important caveat is that some RLV folder functions don't work "correctly" on inventory links. I'd do some tests if that's relevant to your application. * actually thinking it through carefully, converting the 2-digits into a single digit for the whole folder is a bit involved: listen(...) { if(2222==chan) { integer wornFolder = (integer)llGetSubString(text,1); integer wornRecursive = (integer)llGetSubString(text,2); integer wornWhole = wornFolder*wornRecursive; if(wornWhole) { if(wornWhole==1) { //wornWhole=1; }else if(wornWhole==9) { wornWhole=3; }else { wornWhole=2; } }else { wornWhole = wornFolder+wornRecursive; } // wornWhole now represents 0: no items in the folder, 1: none worn, 2: some worn, 3: all worn } } if my logic cells work this morning.
  13. You can also 'force-sit' someone who has accepted your experience, while on land with your experience enabled. llSitOnLink()
  14. Teleporting and sitting on something are the only ones I know of that wouldn't be affected by 'locked controls'. Camera focusing can also lead to turning without control input. I'm fairly certain the viewer's autonav functionality (which is bad and hopefully nobody uses seriously) goes through the same control system as regular movement input.
  15. True, but you'd have to ask yourself whether expanding only "odd" characters by a factor of three is better or worse than expanding every character by a factor of 4/3 (and even especially special characters by more than that). for sake of argument, assuming spaces are the only special character. My back of the envolope says EscapeURL might be more efficient for strings with where 'special characters' are 1/8 or fewer of all the characters, base64 would be better if you have shorter words on average than that. You could also do a combined approach where you escapeURL the string, then use the parse/dump trick to replace all the escaped spaces with actual spaces. If you have fewer than 8 'bad characters' and you don't care about accurately recovering them, str = llDumpList2String(llParseStringKeepNulls(str, ["[","other bad chars"], []), " ");
  16. You'd have to do some research based on specific characters, but llEscapeURL() might be worth looking into to remove special characters.
  17. 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) )
  18. 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.
  19. 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.
  20. 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.
  21. 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.
  22. 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?
  23. 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.
  24. 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. . .)
×
×
  • Create New...