Jump to content

restrict access to building by script


testgenord1
 Share

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

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

Recommended Posts

Hi!
I would like to limit the access to a building to a certain number of avatars, let's say 10 at the same time.
Should an 11th avatar try to access the building, he / she should be teleported back to a central starting point.

In order to do that, the avatars have to be counted and put on a list.
Has a certain number of avatars been put on the list, the list should be closed.
Any avatar not on the list should be teleported back.

The main problem seems to be to exclusively pick the avatars which are not on the list to teleport, as opposed to the avatars that are.
Maybe one of you can help me out?

Here is the script:
Thank you very much in advance!

vector LandingPoint = <77,154,22>; // X,Y,Z landing point for avatar to arrive at
vector LookAt = <1,1,1>; // which way they look at when arriving//
key id;

float Range=20.0; 
float Rate=10.0; 

integer PositionInList;
list visitors;

default
{
	state_entry()
	{
		llSensorRepeat("","",AGENT,Range,PI,Rate);
	}
		sensor(integer num_detected)
		{
  			id = llDetectedKey(0);
			integer i=0;
			while (i<num_detected)
			{
			if (llGetListLength(visitors)<9)
			{
				PositionInList=llListFindList(visitors,[llDetectedName(i)]);
				if (PositionInList==-1)
				{
					visitors=visitors+llDetectedName(i);
				}
				if (PositionInList!=-1)
				{
				llSay(0,"You're already on the list");
				}
			}	

			if (llGetListLength(visitors)>9)
			{
			llTeleportAgent(id,"",LandingPoint,LookAt);
			}
			}
			++i;
		}
}

 

Edited by testgenord1
Link to comment
Share on other sites

You have a few things to think about.

First, there's the matter of deciding whether a person is inside the building or nor.  As written, your script assumes a spherical building, which is probably not realistic.  You can do better by assuming at least a rectangular polygon.  Then you can decide where the boundaries of it are by using llGetBoundingBox.  Then, use llGetAgentList  to find out who's in your parcel and llGetObjectDetails(Av_UUID,[OBJECT_POS]) to get each person's position and then proceed to figure out whether that position is inside the bounding box or not.

Then you have the problem you posed. Once you have the UUID of a person who is in the bounding box, you add the person to your list. Poll the list every few seconds and compare it to what the list looked like the last time you checked.  (The function ListXNotY is handy for things like that.)  If there are more than 2 people on the current list, teleport the ones who didn't appear on the previous version of the list.

Then there's teleporting.  You are proposing to use llTeleportAgent, which won't work unless you are teleporting either the script owner (yourself) or someone in the Experience that the script is set to.  And that assumes that you have created an Experience and are working within it. If not, the best you can do is either llEjectFromLand or llTeleportAgentHome, both of which are a little harsh.

 

  • Like 1
Link to comment
Share on other sites

if use Experience permissions then a better experience for your visitors is:

at the Landing Point request experience permissions from the detected visitor. When they accept the permissions request then teleport them to the room which is elsewhere on the parcel. When they don't accept then don't do anything to them

only if they bypass the experience request and find their own way into the room would we teleport them home from within the room

  • Like 1
Link to comment
Share on other sites

Hi again!
Thanks to all of your help, I've managed to roughly get the script that I wanted.
There is basically only one problem I haven't been able to solve,
and for you guys it's probably a very basic one:

In this version, 2 avatars can stay near that scripted prim at the same time.
The third avatar approaching will be teleported.
(Btw, I'm using the teleporter in school to make sure the students can only go to each task in limited numbers,
so they won't distract each other.)

Now my problem:
With this setting, ONLY the third avatar will be teleported.
Should a fourth avatar arrive at the same time,
he / she would only be teleported after having been in the 3rd slot in the next timer interval.
That avatar would remain in that building throughout the timer interval.

I guess I would have to use a variable for

id = llList2Key(avatarsInRegion, 2);

instead of "2", so that ALL AVATARS starting with the third on the list, will be teleported.

I tried the following, but it hasn't worked:

integer i;
for(i=0; i < numOfAvatars; ++i)
   {
      id = llList2Key(avatarsInRegion, i);
   }

I have to admit, I still haven't quite understood how the "++i" works.
I thought it meant the variable will go through all elements / keys on the list consecutively.

Instead, what it does now is, it only takes the very last key on the list (I guess in the place of "numOfAvatars")
but does not take the other keys on the list.

Maybe you can also help me with this thing?
A short explanation of how "++i" works I would also be thankful for,
because I just couldn't quite understand it from the online materials.

Thank you very much in advance!
Here is the script:

vector LandingPoint = <77,154,22>; // X,Y,Z landing point for avatar to arrive at
vector LookAt = <1,1,1>; // which way they look at when arriving//

list avatarsInRegion;
integer numOfAvatars;

key kbouncer;
list lbouncerpos;
vector vbouncerpos;

integer seconds;
key id;

list lavpos;
vector vavpos;
float fvectordistance;

default
{
    state_entry()
    {
        kbouncer = llGetKey();
        vbouncerpos = llGetPos();
        llSetTimerEvent(1.0);
    }
            timer()
            {
                ++seconds;
  		if(seconds % 10 == 0)
                {
                avatarsInRegion = llGetAgentList(AGENT_LIST_PARCEL, []);
                numOfAvatars = llGetListLength(avatarsInRegion);
                id = llList2Key(avatarsInRegion,2);
                lavpos = llGetObjectDetails(id,[OBJECT_POS]);
                vavpos = llList2Vector(lavpos,0);
                fvectordistance = llVecDist(vbouncerpos, vavpos);
                //llOwnerSay(,(string)fvectordistance);
                if (numOfAvatars >1)
                {
                    if(fvectordistance < 10)
                    {
                        llRegionSayTo(id,0,"Sorry, the task is full.\n \n \nTeleporting you back ...");
                        llTeleportAgent(id,"",LandingPoint,LookAt);
                        avatarsInRegion = llDeleteSubList(avatarsInRegion,2,2); // Remove the person from the Visitor list 
                    }
                }
                }
                if(seconds % 180 == 0)
                {
                    avatarsInRegion = llDeleteSubList(avatarsInRegion,0,10); // Remove the person from the Visitor list 
                }
            }
}

 

Edited by testgenord1
Link to comment
Share on other sites

You almost have it right, but you are identifying only avatar #2 to teleport.  So, take the loop that you already thought of applying

integer i;
for(i=0; i < numOfAvatars; ++i)
   {
      id = llList2Key(avatarsInRegion, i);
   }

and put all the teleporting code inside that loop, so that  the operations in 

 

if(fvectordistance < 10)
                    {
                        llRegionSayTo(id,0,"Sorry, the task is full.\n \n \nTeleporting you back ...");
                        llTeleportAgent(id,"",LandingPoint,LookAt);
                        avatarsInRegion = llDeleteSubList(avatarsInRegion,i,i); // Remove the person from the Visitor list 
                    }

apply to all avatars who meet the criteria, not just avatar #2.  I strongly suggest running that for loop backwards, by the way.  Start with the last avatar in the list and count down toward the first one.  Otherwise, you will have trouble with tis final command:

avatarsInRegion = llDeleteSubList(avatarsInRegion,i,i); // Remove the person from the Visitor list

See if you can figure out why ..... ;)

  • Like 1
Link to comment
Share on other sites

Thank you very much for your quick and helpful reply.
I don't know why, but I'm still failing at this.
I just can't figure it out.
I'm posting it below.
Maybe I cannot see the forest for the trees.
Can you find the mistake?

string Destination = "Sandbox";
vector LandingPoint = <141,108,103>; // X,Y,Z landing point for avatar to arrive at
vector LookAt = <1,1,1>; // which way they look at when arriving//

list avatarsInRegion;
integer numOfAvatars;

key kbouncer;
list lbouncerpos;
vector vbouncerpos;

integer seconds;
key id;

list lavpos;
vector vavpos;
float fvectordistance;

default
{
    state_entry()
    {
        kbouncer = llGetKey();
        vbouncerpos = llGetPos();
        llSetTimerEvent(1.0);
    }
            timer()
            {
                ++seconds;
                if(seconds % 5 == 0)
                { 
                    integer i;
                    for(i=0; i < numOfAvatars; ++i);
                    {
                        avatarsInRegion = llGetAgentList(AGENT_LIST_PARCEL, []);
                        numOfAvatars = llGetListLength(avatarsInRegion);
                        id = llList2Key(avatarsInRegion,i);
                        lavpos = llGetObjectDetails(id,[OBJECT_POS]);
                        vavpos = llList2Vector(lavpos,0);
                        fvectordistance = llVecDist(vbouncerpos, vavpos);
                        //llOwnerSay(,(string)fvectordistance);
                        if (numOfAvatars >1)
                        {
                            if(fvectordistance < 10)
                            {
                                llRegionSayTo(id,0,"Sorry, the task is full.\n \n \nTeleporting you back ...");
                                osTeleportAgent(id,Destination,LandingPoint,LookAt);
                                avatarsInRegion = llDeleteSubList(avatarsInRegion,i,i); // Remove the person from the Visitor list 
                            }
                        }
                    }
                }
                if(seconds % 180 == 0)
                {
                    avatarsInRegion = llDeleteSubList(avatarsInRegion,0,10); // Remove the person from the Visitor list 
                }
            }
}

edit: With this setting, only one avatar is teleported,
and only at his / her first encounter with the prim,
but not at the second encounter any more.

Edited by testgenord1
Link to comment
Share on other sites

kk Here goes,

This function needs a different approach, you want no more then ten people in a certain location on the region/parcel, if this number is exceeded you wish to teleport them out.

first you ask who is on the region with llGetAgentList, then one at the time you find the location of that avatar, if that avatar is inside the zone you check the number of avatars in a second list, if that list = < 9 **edit* and the agent is not already on the list ** you add that uuid to a second list. if the number is > 9 you teleport the agent out

then periodically you check if all the avatars on the second list are still in the region/parcel and within the location, if not you remove the agent of the second list.

point is, you do not want to use the result of llGetAgentList to resolve who can stay or who need to be teleported out, as the order of that list varies, its not like the first ten to arrive on the region are always the first ten on the llGetAgentList result, the result of llGetAgentList can only be used to determine who is on the sim, not when they arrived, so you need to create a routine to do that yourself.

like i said, you add the first ten agents on a second list, and you check if those people are still on the region / parcel every 15 seconds or so. if they left you remove the uuid from the second list so you make room for another (new) agent.

i hope this makes any sense.... ;)

 

Edited by Kardargo Adamczyk
  • Like 1
Link to comment
Share on other sites

Hi again!
Thank you very much for your ideas, Kardargo.
I really appreciate this.
Aftere some more failed attempts, I ended up using a different method again.
It seems to work so far.
I've integrated parts from another script Rolig Loon helped me with:

So thank you very much, once again, Rolig Loon!
I'm posting the script below.
There might still be a lot of room for improvements, so feel free to comment further.
 

string Destination = "your_region";
vector LandingPoint = <77,154,22>; // X,Y,Z landing point for avatar to arrive at
vector LookAt = <1,1,1>; // which way they look at when arriving//

list avatarsInRegion;
integer numOfAvatars;

key id;
string name;

list newkeys;
integer listpos;
integer arrivaltime;

integer seconds;
integer time = 180;

default
{
    state_entry()
    {
        avatarsInRegion = llGetAgentList(AGENT_LIST_PARCEL, []);
        numOfAvatars = llGetListLength(avatarsInRegion);
        llVolumeDetect(TRUE);
    }
    collision_start(integer n)
    {
        llSetTimerEvent(1.0);
        id = llDetectedKey(0);
        name = llKey2Name(id);
        llRegionSayTo(id,0, "Welcome " + name + "!\n \nYou have 3 minutest time.\n \nThen you will be teleported back.");
        if(llListFindList(newkeys,id) == -1)
        {
            arrivaltime = llGetUnixTime();
            integer i;
            for(i=0; i < numOfAvatars; ++i);
            {
                //llShout(0,"key: " + (string)id);
                newkeys += [arrivaltime,id]; // add Unix Time and key to the list; Unix Time first position, key second position
                newkeys = llListSort(newkeys, 2, TRUE);     //  sort strided list by ascending arrivaltime (arrivaltime used because it comes before key [arrivaltime,id]); TRUE means ascending order
                listpos = llListFindList(newkeys,id); // search for key in list
                if(listpos > 7) // if the key is in the 8th onwards position, its agent will be teleported; this means user 5 onwards, because position 8 is in stride 5 (= user 5) (0,1; 2,3; 4,5; 6,7; 8,9 ...)
                {
                    llRegionSayTo(id,0,"Sorry, the task is full.\n \n \nYou are teleported back.");
                    llTeleportAgent(id,"",LandingPoint,LookAt);
                    newkeys = llDeleteSubList(newkeys,4,5); // ... the 3rd avatar arriving (3rd stride) is teleported and removed from the Visitor list
                }
            }
        }
    }
    timer()
    {
        ++seconds;
        if(seconds > time)
        {
        integer k;
        for (k=((newkeys !=[])-1);k>=0;--k) //Look through all the saved visitor times
                {  // For each one ...
                    if((llGetUnixTime() - llList2Integer(newkeys, k)) > time) // If it was more than 180 seconds ago ...
                    {
                        llRegionSayTo(id,0, "Sorry, but your time is up.\n \n You will be teleported back in 3 seconds.\n \nBye!");
                        if(seconds = 3)
                        {
                            llInstantMessage(id, "Teleporting you to : "+ Destination);
                            llTeleportAgent(id,"",LandingPoint,LookAt);
                            
                            //llSay(0,"current keys on list: "+llList2String(newkeys, k+1)); //Check AV key
                            //llSay(0,"current arrivaltimes on list: "+llList2String(newkeys, k)); //Check AV arrivaltime
                            
                            newkeys = llDeleteSubList(newkeys, k+1, k+1); // Remove Av from visitor list
                            newkeys = llDeleteSubList(newkeys, k, k); // Remove Av's arrivaltime, too
                            
                            //llSay(0,"reset keys on list: "+llList2String(newkeys, k+1)); //Check if Av was removed (no key returned)
                            //llSay(0,"reset arrivaltimes on list: "+llList2String(newkeys, k)); //Check if arrivaltime was removed (no integer returned)
                        }
                    }
                }
            }
    }
    
     touch_start(integer num_detected)
    {
       id=llDetectedKey(0);
       integer j;
       for(j = 0; j < numOfAvatars; ++j);
       {
           j = llListFindList(newkeys,id);
           llInstantMessage(id, "Teleporting you to : "+ Destination);
           llTeleportAgent(id,"",LandingPoint,LookAt);
           
           //llSay(0,"keys: "+llList2String(newkeys,j)); // Say key of agent touching
           //llSay(0,"times: "+llList2String(newkeys,j-1)); // Say integer arrivaltime of agent touching
           
           newkeys = llDeleteSubList(newkeys,j,j); // Remove Av from visitor list
           newkeys = llDeleteSubList(newkeys,j-1,j-1); // Remove Av's arrivaltime, too
           
           //llSay(0,"neue keys: "+llList2String(newkeys,j)); //Check if Av was removed (no key returned)
           //llSay(0,"neue times: "+llList2String(newkeys,j-1)); //Check if arrivaltime was removed (no integer returned)
        }
    }
}

 

Edited by testgenord1
  • Like 1
Link to comment
Share on other sites

On 3/4/2020 at 6:12 PM, Rolig Loon said:

I strongly suggest running that for loop backwards, by the way.  Start with the last avatar in the list and count down toward the first one.  Otherwise, you will have trouble with tis final command:

avatarsInRegion = llDeleteSubList(avatarsInRegion,i,i); // Remove the person from the Visitor list

See if you can figure out why ..... ;)

I think I finally figured it out the hard way:
It leads to an endless loop?
At least that's what happened to me for 30 minutes before I eventually remembered your clue.
So thanks for that, too! 🙂

Link to comment
Share on other sites

Removing items sequentially from a list can sometimes lead to odd results.  Suppose you have a list that looks like this:

list My_list = [1, 5, 3, 2, 6, 4];

and you want to remove any items that are less than 4.  You might think to write a loop like this:

integer i;
integer len = llGetListLength(My_list);
while (i < len)
{
    if ( llList2Integer(Mylist, i) < 4 )
    {
        My_list = llDeleteSubList(My_list, i, i);
    }
    ++i;
}

If you do that, though, the script will delete the first list element on its first pass through, leaving you with

My_list = [5, 3, 2, 6, 4];

So far, so good.  Now i == 1, so the loop goes around again, ending up with

My_list = [5, 2, 6, 4];

Still OK, but now i == 2. So, the next time around the script will check llList2Integer(My_list,2,2), which is equal to 6.  It will skip right over the item that used to be llList2Integer(My_list,2,2), but is now llList2Integer(1,1).  So, now we still have

My_list = [5, 2, 6, 4];

Worse yet, i == 3.  You and I know that we have reached the end of the truncated list, but the script doesn't know to stop, because we told it to continue as long as i < 6.  So it will test the 4th element ( == 4), and then look for the 5th one, which no longer exists. You will get a script error (or, at least in some versions of this scenario you will).

There are many versions of this logical problem, and there are several ways to avoid it.  Writing the loop as

while (i < llGetListLength(My_list))   

at least reassesses the length of My_list every time around the loop, which is an improvement, but you'll still be left with the result

My_list = [5, 2, 6, 4];

which is not right.

The smarter solution is to start from the end of the list and loop backwards toward zero.  

integer len = llGetListLength(My_list) -1;
while ( len  >= 0)    // Or you could write     while ( ~len )
{
    if ( llList2Integer(Mylist, len) < 4 )
    {
        My_list = llDeleteSubList(My_list, len, len);
    }
    --len;
}

If you do that, you are always removing elements as you move toward zero.  The list becomes shorter, but the elements behind you that pass the if test are the only ones that remain, and you should end up with

My_list = [5, 6, 4];

==========

Depending on how your script is written, I can also imagine circumstances when you might throw the script into an infinite loop, as you have apparently done.  The underlying lesson here is that strange things can happen if you are altering the contents of a list while looping.  List indices can create a logical pothole if you aren't careful.

Edited by Rolig Loon
Cleaner wording
  • Like 1
Link to comment
Share on other sites

Maths has never been my greatest strength and so I have to admit I haven't understood every detail of how the process works,
I'll have a look at the exact details of the process later.
But I certainly got the point of what you are saying.
I'll just remember to go through such lists from end to start.

So, thank you very much for your clear and detailed explanation! 🙂

Link to comment
Share on other sites

14 minutes ago, testgenord1 said:

So, thank you very much for your clear and detailed explanation! 🙂

You're welcome.  Good luck. It's really not maths as much as logic -- which can be tricky in its own right.  You're just following a rabbit down a hole, asking what happens each time he gets to a new decision point.

  • Like 1
Link to comment
Share on other sites

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

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
 Share

×
×
  • Create New...