Jump to content
MalkinAmistery

llGetagentlist - specific avatars only?

Recommended Posts

Ok.. so.. looking to make a hud.. that can tell me if a specific friend is on the same sim as me, I plan to use llGetAgentList - but not sure how to implement the specific avatars (would ideally like to do this via notecard.. which is my weakest link - data lists.. bleh)  - Thoughts, ideas.. S.O.S. Help ;) - Thanks!

Share this post


Link to post
Share on other sites

The way to find out if a particular item is present in a list is to use llListFindList( (list)haystack, (list)needle), where haystack is the list you're searching and needle is the list you're looking for.

So, the code would look something like this:  

		list temp = llGetAgentList(AGENT_LIST_REGION,[]);
		if(llListFindList(temp, [MyFriendsUUID]) != -1){
			//then my friend is on the region
		}

You can also write the test as

   if(~llListFindList(temp,[MyFriendsUUID]))

which means the same thing.

However, that's not how I would do it.   

If you simply want to know if an avatar is on the region, the easiest test is 

		if(llGetAgentSize(MyFriendsUUID) != ZERO_VECTOR){
			//then my friend is on the region
		}

Much easier.   And if you wanted to know a bit more,

		list temp = llGetObjectDetails(MyFriendsUUID,[OBJECT_POS]);
		if(temp!= []){//then my friend is on the region
			vector vMyFriendsPosition = llList2Vector(temp,0);
			//and that's where my friend is.
		}
		else{
			//not on the region
		}

However you do it, though, please remember explicitly to cast the UUID as a key when you read it from the notecard 

        kAvatarUUID = (key) data;

otherwise the script may have problems knowing it's supposed to be a key and not a string when you come to use it.

Edited by Innula Zenovka
removed ambiguity from example
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
3 hours ago, Innula Zenovka said:

to use llListFindList([haystack],[needle]), where

No brackets for haystack, if “haystack” is a list variable. Just pointing it out in case OP focuses on this instead of your example code! 

  • Like 1

Share this post


Link to post
Share on other sites
4 hours ago, Love Zhaoying said:

No brackets for haystack, if “haystack” is a list variable. Just pointing it out in case OP focuses on this instead of your example code! 

Thanks.   Fixed it above.

  • Thanks 1

Share this post


Link to post
Share on other sites
On 1/24/2018 at 2:17 AM, Innula Zenovka said:

The way to find out if a particular item is present in a list is to use llListFindList( (list)haystack, (list)needle), where haystack is the list you're searching and needle is the list you're looking for.

So, the code would look something like this:  


		list temp = llGetAgentList(AGENT_LIST_REGION,[]);
		if(llListFindList(temp, [MyFriendsUUID]) != -1){
			//then my friend is on the region
		}

You can also write the test as

   if(~llListFindList(temp,[MyFriendsUUID]))

which means the same thing.

However, that's not how I would do it.   

If you simply want to know if an avatar is on the region, the easiest test is 


		if(llGetAgentSize(MyFriendsUUID) != ZERO_VECTOR){
			//then my friend is on the region
		}

Much easier.   And if you wanted to know a bit more,


		list temp = llGetObjectDetails(MyFriendsUUID,[OBJECT_POS]);
		if(temp!= []){//then my friend is on the region
			vector vMyFriendsPosition = llList2Vector(temp,0);
			//and that's where my friend is.
		}
		else{
			//not on the region
		}

However you do it, though, please remember explicitly to cast the UUID as a key when you read it from the notecard 

        kAvatarUUID = (key) data;

otherwise the script may have problems knowing it's supposed to be a key and not a string when you come to use it.

Thank you!  That helps a great deal :) 

The main issue I still have though, is the gathering of the data from the notecard..  I suppose I didn't communicate that properly..  

I know the *BASICS* of gathering data.. but.. gathering multiple names (uuids) from a notecard for this use, not sure of the proper way to go about it.. :/ 

 

Edited by MalkinAmistery

Share this post


Link to post
Share on other sites
35 minutes ago, MalkinAmistery said:

Thank you!  That helps a great deal :) 

The main issue I still have though, is the gathering of the data from the notecard..  I suppose I didn't communicate that properly..  

I know the *BASICS* of gathering data.. but.. gathering multiple names (uuids) from a notecard for this use, not sure of the proper way to go about it.. :/ 

 

Suggest that if the notecard has only one purpose..and only 1 script is reading from it:

- Put a UUID on each line, by itself (assume you don't need names, just UUID)

- You have to call llGetNotecardLine() with notecard name and line # (starts with 0) to start reading the notecard.

- Each time dataserver() is read, if string is non-blank then add to your list and call llGetNotecardLine() for next line

- "done" reading notecard is either if data read=EOF constant or if you start out the process with a call to llGetNumberOfNotecardLines() (which also triggers dataserver event().

http://wiki.secondlife.com/wiki/LlGetNotecardLine

 

Share this post


Link to post
Share on other sites

I don't quite understand why you want to use a notecard at all.  If you simply want to find one friend, I think the easiest thing to do is open a text box to type the friend's name in, and then search the list that you get from llGetAgentList for that person.  To make it friendly, I would translate that list into a list of Display names and then do the needle/haystack thing that Innula suggested, something like this:
 

touch_start(integer num)
{
    llListenRemove(iLsn);
    iLsn = llListen(iMy_channel,"","","");
    llTextBox(kOwner,"\n Who do you want to find? \n  Type a Display Name, please.",iMy_channel);
}

listen (integer channel, string name, key id, string message)
{
    llListenRemove(iLsn);
    string strThisName = llToLower(message);
    list lEveryone = llGetAgentList(AGENT_LIST_REGION,[]);
    list lDisplayNames;
    integer i;
    while (i < llGetListLength(lEveryone) )
    {
        string strDName = llToLower(llGetDisplayName( llList2Key(lEveryone,i) ) );
        lDisplayNames += [strDName];
        ++i;
    }
    integer idx = llListFindList (lDisplayNames, [strThisName]);
    if ( ~idx )
    {
        llShout( 0, "I SEE YOU!");    // Or words to that effect, or do whatever else you want, like get the friend's location
    }
}

Make sure to create the appropriate global variables iMy_channel, iLsn, and kOwner and do the right stuff to make it pretty.  I make no guarantee that this is free of typos or other silly mistakes, but this schematic idea should work.

EDIT:  Of course, you don't really need to create lDisplayNames unless you want that list for some other reason. In that while loop, you could simply check each Display Name as it is generated and ask whether it matches the one you typed in the text box.  If not, keep going.  If it's a match, bail out of the loop and declare victory.

Edited by Rolig Loon

Share this post


Link to post
Share on other sites
1 hour ago, Rolig Loon said:

I don't quite understand why you want to use a notecard at all.  If you simply want to find one friend, I think the easiest thing to do is open a text box to type the friend's name in, and then search the list that you get from llGetAgentList for that person.  To make it friendly, I would translate that list into a list of Display names and then do the needle/haystack thing that Innula suggested, something like this:
 


touch_start(integer num)
{
    llListenRemove(iLsn);
    iLsn = llListen(iMy_channel,"","","");
    llTextBox(kOwner,"\n Who do you want to find? \n  Type a Display Name, please.",iMy_channel);
}

listen (integer channel, string name, key id, string message)
{
    llListenRemove(iLsn);
    string strThisName = llToLower(message);
    list lEveryone = llGetAgentList(AGENT_LIST_REGION,[]);
    list lDisplayNames;
    integer i;
    while (i < llGetListLength(lEveryone) )
    {
        string strDName = llToLower(llGetDisplayName( llList2Key(lEveryone,i) ) );
        lDisplayNames += [strDName];
        ++i;
    }
    integer idx = llListFindList (lDisplayNames, [strThisName]);
    if ( ~idx )
    {
        llShout( 0, "I SEE YOU!");    // Or words to that effect, or do whatever else you want, like get the friend's location
    }
}

Make sure to create the appropriate global variables iMy_channel, iLsn, and kOwner and do the right stuff to make it pretty.  I make no guarantee that this is free of typos or other silly mistakes, but this schematic idea should work.

EDIT:  Of course, you don't really need to create lDisplayNames unless you want that list for some other reason. In that while loop, you could simply check each Display Name as it is generated and ask whether it matches the one you typed in the text box.  If not, keep going.  If it's a match, bail out of the loop and declare victory.

The reason I want a notecard, is I want to have a list of names, that I can add to or remove from, in a notecard.

Share this post


Link to post
Share on other sites

Ah, OK.  I was taking your inital post literally:

On 1/23/2018 at 11:22 PM, MalkinAmistery said:

looking to make a hud.. that can tell me if a specific friend is on the same sim as me

So, you can look for a specific friend without needing to store anything.  I see why you might want a notecard to save a list of potential friends.  Even there, I might be tempted to gather a list of names by typing them into a text box and storing them in an internal list, rather than using a notecard, especially if it was not a particularly long list. If I were worried about losing the list if the script is reset, I could save it in a prim description field.  Anyway ..... I do see why you decided on the notecard option, and there's nothing wrong with doing it that way.  Good luck.  ;)

Share this post


Link to post
Share on other sites
4 hours ago, MalkinAmistery said:

he main issue I still have though, is the gathering of the data from the notecard..  I suppose I didn't communicate that properly..  

I know the *BASICS* of gathering data.. but.. gathering multiple names (uuids) from a notecard for this use, not sure of the proper way to go about it.. :/ 

If you simply want to build a list of  uuids by reading a notecard, then I would enter the UUIDs onto a notecard, one to a line (no commas or quote marks or anything else) and then use something like this to read them and build the list

integer counter;

key kQuery;
key kNotecardUUID;
list lList;
string strNotecard;


default {
	state_entry() {
		strNotecard = llGetInventoryName(INVENTORY_NOTECARD,0);//get the name of the first notecard in the object's inventory
		if(llGetInventoryType(strNotecard) == INVENTORY_NOTECARD){//if there is a notecard 
			kNotecardUUID = llGetInventoryKey(strNotecard);//record the UUID
			lList = [];//clear the list
			counter = 0;//zero the counter
			kQuery = llGetNotecardLine(strNotecard, counter);//ask for the first line of the notecard
		}
	}

	changed(integer change){
		if(change & CHANGED_INVENTORY){
			if(llGetInventoryKey(llGetInventoryName(INVENTORY_NOTECARD,0))!=kNotecardUUID){//if the notecard has been changed
				llResetScript();
			}
		}
	}

	dataserver(key queryid, string data) {
		if(kQuery == queryid){//if this is the answer to the current dataserver request
			if(data != EOF){//not reached the end of the file yet

				data = llStringTrim(data,STRING_TRIM);//trim leading and trailing spaces
				if(data){//if there's anything left 
					if(","==llGetSubString(data,-1,-1)){//if the last character on the line is comma
						data = llDeleteSubString(data, -1,-1);//get rid of it
					}
					llOwnerSay("Adding "+data+" to the list");
					lList +=[(key)data];//the dataserver call returns a string.  Cast it as a key, since you're going to be using the list to check UUIDs later, and add it to the list
				}
				kQuery = llGetNotecardLine(strNotecard, ++counter);//ask for the next line of the notecard

			}
			else{
				llOwnerSay("Finished reading the notecard");
			}
		}
	}
}

Then you can simply loop through the list at run time, reading one uuid at a time and saying 

string strName = llGetDisplayName(uuid);
if(llStringLength(strName)){//if the displayName is readable
	llOwnerSay("My friend "+strName+ "is somewhere on this region");
}

 

  • Thanks 1

Share this post


Link to post
Share on other sites

W-Hat is certainly very useful.   There's a danger with any third-party service that it might go offline without warning at any time, but w-Hat has been around for ages.   I use it a lot.   It can't read UUIDs for avatars who have hidden their names from search (or possibly only avatars whose names have always been hidden from search) but it's very thorough and up-to-date.

If I was using it for something like this, I think I would try to read the UUIDs when I read the notecard, and then store the keys and names in separate lists, in the same order, so I could use llListFindList to look up an entry in one list and know that the index returned would enable me to find the corresponding entry in the other list.

So I would do something like this, with a notecard containing people's usernames or legacy names (it converts everything to usernames, though I don't think W-Hat particularly minds what you give it), one per line, and nothing else.    This code compile but I've not tested it (though I've mad this sort of thing recently, and this looks right to me)

integer counter;

key kQuery;
key kWhatRequest;

key kNotecardUUID;
list lKeysList;
list lNamesList;

string strNotecard;
string strTestName;
string strURL   = "http://w-hat.com/name2key"; // name2key url

string agentUsername(string agentLegacyName) {
	return llDumpList2String(llParseString2List(llToLower(agentLegacyName)+" ", [" resident ", " "],[]), ".");
}

default {
	state_entry() {
		strNotecard = llGetInventoryName(INVENTORY_NOTECARD,0);//get the name of the first notecard in the object's inventory
		if(llGetInventoryType(strNotecard) == INVENTORY_NOTECARD){//if there is a notecard
			kNotecardUUID = llGetInventoryKey(strNotecard);//record the UUID
			lKeysList =[];
			lNamesList=[];
			counter = 0;//zero the counter
			kQuery = llGetNotecardLine(strNotecard, counter);//ask for the first line of the notecard
		}
	}

	changed(integer change){
		if(change & CHANGED_INVENTORY){
			if(llGetInventoryKey(llGetInventoryName(INVENTORY_NOTECARD,0))!=kNotecardUUID){//if the notecard has been changed
				llResetScript();
			}
		}
	}

	dataserver(key queryid, string data) {
		if(kQuery == queryid){//if this is the answer to the current dataserver request
			if(data != EOF){//not reached the end of the file yet

				data = llStringTrim(data,STRING_TRIM);//trim leading and trailing spaces
				if(data){//if there's anything left
					if(","==llGetSubString(data,-1,-1)){//if the last character on the line is comma
						data = llDeleteSubString(data, -1,-1);//get rid of it
					}
					strTestName = agentUsername(data);//impose a consistent format, to be neat
					llOwnerSay("Looking up UUID for  "+strTestName);
					kWhatRequest =  llHTTPRequest( strURL + "/" + llEscapeURL(strTestName), [], "" );
				}
				else{//must have been an empty line, so read the next one
					kQuery = llGetNotecardLine(strNotecard, ++counter);//ask for the next line of the notecard
				}
			}
			else{
				llOwnerSay("Finished reading the notecard");
			}
		}
	}

	http_response(key request_id, integer status, list metadata, string body) {
		if(request_id == kWhatRequest){
			if(200 == status){//request succeeded
				lKeysList +=[(key)body];//add the uuid it has returned to lKeysList
				lNamesList +=[strTestName];//add the name to the names list.   The two lists should remain in synch
				llOwnerSay(strTestName+"'s uuid is "+body+". Added them both to the appropriate lists.");
			}
			else{
				if(499 == status){
					llOwnerSay("Request timed out.");
				}
				else if (400 == status){
					llOwnerSay(strTestName +" is not a valid name.");
				}
				else if (404 == status){
					llOwnerSay("No key found for "+strTestName);
				}
				else{
					llOwnerSay("Did not receive a reply from the W-Hat server because of error code "+(string)body);
				}

				llOwnerSay("Dropping "+strTestName+" and checking the next line on the card.");
			}

			kQuery = llGetNotecardLine(strNotecard, ++counter);//ask for the next line of the notecard

		}
	}
}
Edited by Innula Zenovka
  • Thanks 2

Share this post


Link to post
Share on other sites

You are very welcome.  While I don't usually post full scripts, I'm normally happy to demonstrate useful techniques and methods, particularly when they're ones that I know I found  difficult to understand until I saw a working example.

  • Thanks 1

Share this post


Link to post
Share on other sites

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