Jump to content
Emilee Edenflower

Display message only once in a timer for loop

You are about to reply to a thread that has been inactive for 716 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

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;
}

 

Share this post


Link to post
Share on other sites
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;
}

 

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
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);
        }

 

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 by Rolig Loon
  • Like 1

Share this post


Link to post
Share on other sites

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.. :/ 

Share this post


Link to post
Share on other sites

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 by Rolig Loon

Share this post


Link to post
Share on other sites

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() + "!");
         }
      }
   } 

 

Share this post


Link to post
Share on other sites

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 by Rolig Loon
Typos, as usual

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites

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.. 

Share this post


Link to post
Share on other sites
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

 

  • Thanks 1

Share this post


Link to post
Share on other sites
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.  

  • Thanks 1

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
You are about to reply to a thread that has been inactive for 716 days.

Please take a moment to consider if this thread is worth bumping.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...