ellestones Posted August 19, 2018 Share Posted August 19, 2018 SEEN_LIST = ListItemDelete(SEEN_LIST, this_SEEN_name); if agents are not being removed from SEEN_LIST then it could be something not quite right with the function ListItemDelete() the function should go something like: list ListItemDelete(list source, string item) { integer i = llListFindList(source, [item]); if (i >= 0) return llDeleteSubList(source, i, i); else return source; } Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 2 hours ago, ellestones said: the function should go something like: list ListItemDelete(list source, string item) { integer i = llListFindList(source, [item]); if (i >= 0) return llDeleteSubList(source, i, i); else return source; } It looks similar to what I've got, it's just the IF part that's a bit different, though it looks to be saying the same thing from what I can tell: list ListItemDelete(list mylist,string element_old) { integer placeinlist = llListFindList(mylist, [element_old]); if (placeinlist != -1) return llDeleteSubList(mylist, placeinlist, placeinlist); return mylist; } Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 19, 2018 Share Posted August 19, 2018 Yes, they are the same. Another option would be to write the IF as if (~placeinlist) I'm not sure that there's any difference in speed/memory use/whatever between the options. You just go with a style that is comfortable for you. I think the real problem in your script is that llKey2Name is often turning up NULL_KEY answers when you don't expect them, so the variable this_agent_key is unreliable. Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 10 hours ago, Rolig Loon said: Uh-oh. I stand corrected. I don't know what I was thinking when I typed that. You just startled me enough that I went back and checked that gate counter script that I pointed the OP to, just to be sure I didn't make the mistake there. I didn't. The script is right (Whew). I just had a brain failure here today. Thanks, Innula. So in light of all that, and using lists instead of strings.. does this make sense for memory checking, or does it have to be a string? if ((llGetListLength(TARGET_LIST) * 4.2) > llGetFreeMemory()) { //Delete the oldest entry in the list which is at the front of the list TARGET_LIST = llDeleteSubList(TARGET_LIST,0,0); } Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 4 minutes ago, Rolig Loon said: I think the real problem in your script is that llKey2Name is often turning up NULL_KEY answers when you don't expect them, so the variable this_agent_key is unreliable. Yeah I've swapped it now to just be a list of UUIDs and I'll convert the key to username on output in llOwnerSay instead. Just about to try it inworld now Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 19, 2018 Share Posted August 19, 2018 (edited) 1 hour ago, Emilee Edenflower said: So in light of all that, and using lists instead of strings.. does this make sense for memory checking, or does it have to be a string? I should explain something that had faded into my own memory . When I wrote that script many years ago, the test I devised was simply to compare llGetFreeMemory with the total available memory (64K for a mono-compiled script). I had a discussion with Void Singer at the time, who pointed out that it would be handier if there were a way to use the number of bytes of memory being used to store a user UUID as the yardstick instead. If you go back and look at Becky Pippen's original article ( https://wiki.secondlife.com/wiki/User:Becky_Pippen/Hashing ), you'll see that she did that calculation and estimated how many hashed/compressed UUIDs her algorithm could store safely before you run out of script memory. I used her number, built in a very conservative margin of error, and decided that the test should be if ((llStringLength( hashedNames ) * 4.2) > llGetFreeMemory()) . So the result is a combination of serious calculation on Becky's part and a really conservative empirical decision on my part. Using your version (with llGetListLength instead of llStringLength ) should make your test end up at roughly the same place as mine, especially given the arbitrary fudge factor I used. If you ask me now to reconstruct how I decided that 4.2 was an appropriate fudge factor, I cannot remember for the life of me. Maybe it was Void who came up with the number. She's good at arcane things like that. I just know that it has worked well in the handful of applications where I have used this approach. Edited August 19, 2018 by Rolig Loon 1 Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 On another note, do I need to do something to define my list as a list of keys? The while loop with the list to list thing doesn't seem to be seeing anything. Keeps returning -1 even though I have keys in my target_list the same as those avi in the region I'm in.. Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 19, 2018 Share Posted August 19, 2018 (edited) A list may have any type of variables in it, or a mixture of many types. However, if you try to read a value from the list and read it with a type other than the one that it had when it was put in the list, you may get a bogus result. For example, if I write string Color = "<1.0,1.0,1.0>"; my_colors += [ Color ]; I cannot expect to get the right answer if I ask for vector new_color = llList2Vector(my_colors,0); because that value was saved as a string, not a vector. I will get ZERO_VECTOR instead. So I have two choices: (1) be sure to save as the same variable type as you plan to read later, or (2) typecast the result as you extract it, as in vector new_color = (vector)llList2String(my_colors,0); Look in the LSL wiki's Types tab to see a full discussion of variable types and a link to a discussion of typecasting, which can be a confusing topic. Edited August 19, 2018 by Rolig Loon Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 I understand the need for typecasting at times, I'm just getting confused about how to do this within LSL, inside a loop whilst using llListFindList if the initial list I made isn't counted as a list of keys Do I need to use llList2Key on my TARGET_LIST and SEEN_LIST somehow for the llListFindList to understand the comparison of keys? I think I've been staring at this for too long now list TARGET_LIST = ["0f2e3a53-b856-413f-823b-71c10ca4aa58", "3a5add55-270d-4076-9e50-d4f37f2ad8af", "a6d06686-5198-4ff7-b42e-a7b4a75aaa5d", "d4b33149-686f-4bf4-b184-e8196a258b7a", "476c19b4-011e-4781-9e98-cefafe8f8606", "3498dd86-e37d-4f43-95c0-436121705a55", "3a5add55-270d-4076-9e50-d4f37f2ad8af"]; list SEEN_LIST; integer i = llGetListLength(SEEN_LIST); list REGION_KEYS = llGetAgentList(AGENT_LIST_REGION, []); integer NUM_KEYS = llGetListLength(REGION_KEYS); key id; while ((--i) >= 0) { id = llList2Key(SEEN_LIST, i); if (llListFindList(REGION_KEYS, [id]) < 0){ SEEN_LIST = llDeleteSubList(SEEN_LIST, i, i); } } // check for any on TARGET_LIST, when so add to SEEN_LIST while ((--NUM_KEYS) >= 0) { id = llList2Key(REGION_KEYS, NUM_KEYS); if (llListFindList((key)TARGET_LIST, [id]) >= 0) { if (llListFindList((key)SEEN_LIST, [id]) < 0) { SEEN_LIST += [id]; llOwnerSay(llGetDisplayName(id) + " is in your region of " + llGetRegionName() + "!"); } } } Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 19, 2018 Share Posted August 19, 2018 (edited) Not quite. A list is a list. You can't typecast it to make it a key. If you do, its value will be NULL_KEY, which is the default value for an empty or invalid key. So 41 minutes ago, Emilee Edenflower said: if (llListFindList((key)TARGET_LIST, [id]) >= 0) and 41 minutes ago, Emilee Edenflower said: if (llListFindList((key)SEEN_LIST, [id]) < 0) won't work. The values in TARGET_LIST are strings, because you loaded them that way. If you want to look for a match between id, which is a key, and something in TARGET_LIST, write it as if ( llListFindList(TARGET_LIST,[(string)id]) >= 0 ) ( or as if ( ~llListFindList(TARGET_LIST, [ (string)id ] ) ) . Your other list, SEEN_LIST, already contains keys, because they were loaded that way when REGION_KEYS was filled by llGetAgentList, so you can write that test as if ( llListFindList( SEEN_LIST, [id] ) < 0 ) ( or as if ( !~llListFindList( SEEN_LIST, [id] ) ) ). Typecasting can sometimes be done implicitly between some types of variables, but frankly, I never trust myself to remember when implicit typecasting is allowed and when it isn't. My fallback solution is to treat everything in a list as a string unless I am absolutely sure. You can always typecast from a string to something else. ========== BTW, the shorthand tests using ~ work because ~n = -( n + 1 ). If you use that shorthand in an if test, where you are asking whether the test value is == TRUE or == FALSE, if ( ~n ) is the same as if ( n >= 0 ) . Remember that in LSL, any test that gives a non-zero result is TRUE. Edited August 19, 2018 by Rolig Loon Typos, as usual Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 19, 2018 Author Share Posted August 19, 2018 22 minutes ago, Rolig Loon said: if ( llListFindList(TARGET_LIST,[(string)id]) >= 0 ) ( or as if ( ~llListFindList(TARGET_LIST, [ (string)id ] ) ) Ah, of course. It seems so obvious now you've said it! Thanks! Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 20, 2018 Author Share Posted August 20, 2018 OK, final question then to make my idea work if possible. I'd like to keep the scanner script separate just for tidiness (since I can't use an include() function) -- so can't lists be sent between scripts with a llMessageLinked ? I don't quite understand how that function works across scripts, and the examples on the docs don't really make it any clearer to me.. Link to comment Share on other sites More sharing options...
ellestones Posted August 20, 2018 Share Posted August 20, 2018 22 hours ago, Rolig Loon said: Another option would be to write the IF as if (~placeinlist) I'm not sure that there's any difference in speed/memory use/whatever between the options. i used to think that ~ would be slower, because it just seemed like it when I was waiting. Then I stumble across the work of Pedro Oval. Where he disassembled the CIL bytecode produced by the Mono LSL compiler // ~x; 11 00 ldloc.s 0 66 not 26 pop // x != y; implemented as: !(x==y) 11 01 ldloc.s 1 // this part is x == y 11 00 ldloc.s 0 FE 01 ceq 16 ldc.i4.0 // this part is 'not' FE 01 ceq 26 pop is pretty interesting what Pedro has shown about all kinds of things in a get to know our compiler way. Lots more here http://wiki.secondlife.com/wiki/User:Pedro_Oval/Mono_code_memory_usage/CIL 1 Link to comment Share on other sites More sharing options...
Rolig Loon Posted August 20, 2018 Share Posted August 20, 2018 5 hours ago, Emilee Edenflower said: OK, final question then to make my idea work if possible. I'd like to keep the scanner script separate just for tidiness (since I can't use an include() function) -- so can't lists be sent between scripts with a llMessageLinked ? I don't quite understand how that function works across scripts, and the examples on the docs don't really make it any clearer to me.. No, sadly. If you look at the parameter string for llMessageLinked, you'll see that it only allows you to send an integer, a string, and a key (which can be fooled into accepting a second string if necessary). If you have a list to send, you'll need to pack it into a string and then parse it back out to a new list at the receiving end. So .... string strPacked_list_to_send = llDumpList2String(My_list,"~"); llMessageLinked( iDestination, iCode, strPacked_list_to_send, NULL_KEY); and then on the receiving end .... link_message (integer from, integer iCode, string message, key id) { list My_new_list = llParseString2List( message, ["~"], [ ] ); } It's slow and clumsy, but it gets the job done. 1 Link to comment Share on other sites More sharing options...
Emilee Edenflower Posted August 20, 2018 Author Share Posted August 20, 2018 1 hour ago, Rolig Loon said: If you have a list to send, you'll need to pack it into a string and then parse it back out to a new list at the receiving end Thanks, this should hopefully accomplish what I'm aiming for Thanks for all the help! Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now