Jump to content

Puzzling Experience Permission Denied Message


LoneWolfiNTj
 Share

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

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

Recommended Posts

My multi-user, multi-destination teleporter is now working pretty well, but yesterday it was giving some bizarre spurious error messages. The symptom was this: a friend of mine used the teleporter to teleport somewhere, then teleported back. So far, so good. But then he stepped out into the street in front of my house, and immediately the teleporter said "Sorry, but this teleporter is set-up for use by its owner only.". Which is not true. So I investigated what was triggering that, and it was the "experience_permission_denied" event. And, strangely, the "Reason" number was "17", meaning "experience not permitted on land". The "agent_id" gave a UUID which turned out to be the avatar key of my friend who had used the teleporter two minutes earlier. But when I put in some code to check "UUID of avatar sitting on target", that, of course, was now NULL_KEY because no avatar on target.

I was able to stop the spurious messages by checking whether an avatar is still seated (see the "Do nothing, because this is a spurious message" line in the script below), but why do I even have to? Nothing should be requesting "Experience Permission" several minutes after the last time the teleporter was used, as far as I can see. The script is this:


// Teleport.lsl

list    landmarks  = [];        // list of landmarks
integer dlg_chn    = 925813746; // dialog channel
integer lsn_hnd    = 0;         // listen handle
integer page       = 0;         // current menu page
key     ava_key    = NULL_KEY;  // avatar key

reset()
{
    // We need this for llAvatarOnSitTarget to work; 
    // the vectors components must not all be set to 0.0:
    llSitTarget(<0.4, 0.0, 0.8>, ZERO_ROTATION);

    // Don't be listening when there's nothing to liten to:
    llListenRemove(lsn_hnd);
}

get_landmarks()
{
    landmarks = [];
    integer n = llGetInventoryNumber(INVENTORY_LANDMARK);
    integer i;
    for ( i = 0 ; i < n ; ++i )
    {
        landmarks += [llGetInventoryName(INVENTORY_LANDMARK, i)];
    }
}

menu_page()
{
    integer n = llGetListLength(landmarks); // Number of landmarks.
    integer pages = llCeil((float)n/9.0 - 0.00001); // Number of menu pages needed.
    string dia_str = "Landmarks\n";
    dia_str += "Menu page " + (string)(page+1) + " of " + (string)pages + ":";
    list buttons = [];
    if (1 == pages)
    {
        buttons += [" ", "Exit", " "];
    }
    else if (0 == page)
    {
        buttons += [" ", "Exit", ">"];
    }
    else if ( (pages - 1 ) == page )
    {
        buttons += ["<", "Exit", " "];
    }
    else
    {
        buttons += ["<", "Exit", ">"];
    }
    integer i;
    for (i = 9*page ; i < 9*(page+1) && i < n ; ++i)
    {
        buttons += llList2String(landmarks, i);
    }
    llDialog(ava_key, dia_str, buttons, dlg_chn);
}

teleport(string landmark)
{
    llUnSit(ava_key);
    llTeleportAgent(ava_key, landmark,  <0.0, 0.0, 0.0>, <0.0, 0.0, 0.0>);
}

default
{
    state_entry()
    {
        reset();
    }

    on_rez(integer StartParameter)
    {
        reset();
    }

    changed (integer what)
    { 
        if (what & CHANGED_LINK)
        {
            ava_key = llAvatarOnSitTarget();
            if (ava_key != NULL_KEY) 
            {
                llRequestExperiencePermissions(ava_key, "");
            }
        }
    }

    experience_permissions(key agent_id)
    {
        ava_key = llAvatarOnSitTarget();
        if (agent_id == ava_key)
        {
            get_landmarks();
            page = 0;
            lsn_hnd = llListen(dlg_chn, "", NULL_KEY, "");
            menu_page();
        }
    }

    experience_permissions_denied(key agent_id, integer Reason)
    {
        ava_key = llAvatarOnSitTarget();
        if (agent_id == ava_key)
        {
            if (ava_key == llGetOwner())
            {
                llInstantMessage(ava_key, "Experience permissions have been denied, so requesting regular teleport permissions.");
                llRequestPermissions(ava_key, PERMISSION_TELEPORT);
            }
            else
            {
                llInstantMessage(ava_key, "Sorry, but experience permissions have been denied, so this teleporter cannot teleport you.");
                llUnSit(ava_key);
            }
        }
        else
        {
            ; // Do nothing, because this is a spurious message from an
              // avatar which is no-longer seated on the teleporter.
        }
    }

    run_time_permissions(integer perm)
    {
        if (PERMISSION_TELEPORT & perm)
        {
            get_landmarks();
            page = 0;
            lsn_hnd = llListen(dlg_chn, "", NULL_KEY, "");
            menu_page();
        }
        else
        {
            llUnSit(ava_key);
        }
    }

    listen(integer channel, string name, key id, string message)
    {
        if (" " == message)
        {
            menu_page(); // Just re-launch menu, because a blank button has been pressed.
        }
        else if ("<" == message)
        {
            --page;
            menu_page();
        }
        else if (">" == message)
        {
            ++page;
            menu_page();
        }
        else if ("Exit" == message)
        {
            llListenRemove(lsn_hnd);
            llUnSit(ava_key);
        }
        else
        {
            // Otherwise, the pressed button was the name of a landmark,
            // so stop listening and teleport to that landmark:
            llListenRemove(lsn_hnd);
            teleport(message);
        }
    }
}

As far as I can see, the only time Experience Permissions are requested is in the "changed" event for "CHANGED_LINK". That changes on sit, and presumably on unsit, but even if unsit triggers "changed" and "CHANGED_LINK", I test for llAvatarOnSitTarget being NULL_KEY, so llRequestExperiencePermissions shouldn't be called on unsit... and yet, it appears that it is. Or is there some other reason for the unexpected "experience_permissions_denied" event? Color me puzzled.

Edited by LoneWolfiNTj
fixed typo ("a friend of mine" instead of "I")
Link to comment
Share on other sites

Is the script actually set in the Experience?  I know that's an obvious "Is it plugged in?" question, but I can't count the number of times that I have forgotten to click the little Experience box and assign an Experience to the script.  (And Bob is right; you can get a delayed reaction on an experience_permissions or experience_permissions_denied event if you are triggering it several times rapidly.  There's no inherent delay in the llTeleportAgent function itself, but if you are teleporting across region boundaries it takes a while for data to be transferred from one set of servers to another.)  

BTW, you can write your "spurious message" workaround more easily as 

if ( reason == 17) {return;}

Put it as the first thing at the top of the experience_permissions_denied event.

Link to comment
Share on other sites

3 hours ago, LoneWolfiNTj said:

So I investigated what was triggering that, and it was the "experience_permission_denied" event. And, strangely, the "Reason" number was "17", meaning "experience not permitted on land". The "agent_id" gave a UUID which turned out to be the avatar key of my friend who had used the teleporter two minutes earlier.

Unanswered experience permission requests remain active in the background for any one agent up to 5 minutes.

You need to tailor your work flow to only handle one user at a time and ignore denied events from anyone other than the person of interest.

What you encountered is the opposite of someone granting permissions after someone else steps in and has a request made and granted. https://jira.secondlife.com/browse/BUG-228162

In that scenario, we really need a dedicated error code.

Edited by Lucia Nightfire
Link to comment
Share on other sites

2 hours ago, Rolig Loon said:

Is the script actually set in the Experience?  I know that's an obvious "Is it plugged in?" question, but I can't count the number of times that I have forgotten to click the little Experience box and assign an Experience to the script.  (And Bob is right; you can get a delayed reaction on an experience_permissions or experience_permissions_denied event if you are triggering it several times rapidly.  There's no inherent delay in the llTeleportAgent function itself, but if you are teleporting across region boundaries it takes a while for data to be transferred from one set of servers to another.)  

BTW, you can write your "spurious message" workaround more easily as 

if ( reason == 17) {return;}

Put it as the first thing at the top of the experience_permissions_denied event.

Yep, my "Experience LoneWolfiNTj" is baked-into the script, else my friend would not have been able to TP at all. (None of the SL teleport functions work for non-owners without an Experience.)

Nope, I can't reject reason 17, because someone might very well try to run the teleporter on land that's not allowing my Experience, and that would be a valid error for that situation and should trigger "Experience permission has been denied, so I can't teleport you".

Instead, I simply check to see if the key of the avatar currently on sit target is the same as the "agent_id" of the exp_perm_denied event. That stopped the spurious error messages, because "UUID of current avatar" was, of course, NULL_KEY (because no one sitting!), whereas agent_id was "last avatar to teleport". When the two don't match, the "denial' is spurious and can be safely ignored.

So the questions remain, why is the teleporter asking for exp. perms. twice, and why does it think someone standing on the road 10m away is paradoxically also seated on the teleporter?

I think I'll put some code in the changed() event so that every time CHANGED_LINK occurs, it will llSay some diagnostics, because the changed() event has GOT to be where this tomfoolery is originating from, as exp. perms. aren't asked from anywhere else.

Link to comment
Share on other sites

1 hour ago, Lucia Nightfire said:

Unanswered experience permission requests remain active in the background for any one agent up to 5 minutes.

You need to tailor your work flow to only handle one user at a time and ignore denied events from anyone other than the person of interest.

What you encountered is the opposite of someone granting permissions after someone else steps in and has a request made and granted. https://jira.secondlife.com/browse/BUG-228162

In that scenario, we really need a dedicated error code.

Fascinating. That explains why the denial event could happen minutes later, both for me and for my friend.

And yep, that's just what I did: sent exp_perm_denied events from non-seated avatar (eg, standing in the road 10m away) to a "else do nothing" clause.

I'm gonna dig deeper, though, because it bothers the crap out of me that I can't see where the request that results in the denial is even coming from. Time to pepper with llSay and see what's happening.

Edited by LoneWolfiNTj
Link to comment
Share on other sites

1 hour ago, Lucia Nightfire said:

ignore denied events from anyone other than the person of interest

Ok, I'm seeing now that I very much need to do that, yes. After experimenting, I just learned two very interesting things!

  1. The teleporter in front of my house was interacting with the teleporter inside my house! Apparently, Experience permission requests, grants, and denials are broadcast over all devices with the same Experience baked into them. So doing fresh double-checks of what avatar is where when an event happens is vital.
  2. The permissions were NOT being requested twice! The later "denial" was not so much a "denial" as a "revocation"! Still more reason to ignore all such events unless (agent_id == llAvatarOnSitTarget())

I suppose as I gain more experience with Experiences I'll be caught by-surprise by these things less often.

Link to comment
Share on other sites

This just occured to me, but one cool thing about experience permissions is that they only need ot be requested once per avatar. As an alternative to requesting experience permissions, llAgentInExperience() can be used to test if the avatar has already granted permissions, roughly:

safe_teleport(key ID, /*landmark stuff*/)
{	// write landmark stuff to global variables.
  if(llAgentInExperience(ID))
  {	// do the teleport.
  }else
  {	llRequestExperiencePermissions(ID);
  }
}

Edit: actually, not tested Hmm. . .

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

2 hours ago, LoneWolfiNTj said:

Ok, I'm seeing now that I very much need to do that, yes. After experimenting, I just learned two very interesting things!

  1. The teleporter in front of my house was interacting with the teleporter inside my house! Apparently, Experience permission requests, grants, and denials are broadcast over all devices with the same Experience baked into them. So doing fresh double-checks of what avatar is where when an event happens is vital.
  2. The permissions were NOT being requested twice! The later "denial" was not so much a "denial" as a "revocation"! Still more reason to ignore all such events unless (agent_id == llAvatarOnSitTarget())

I suppose as I gain more experience with Experiences I'll be caught by-surprise by these things less often.

There is no "broadcasting". Scripts that contain experience permissions (0x62000) automatically monitor when the perms holder either blocks the experience or enters land that does not have a land scope experience allowed and removes all perms.

1 hour ago, Quistess Alpha said:

This just occured to me, but one cool thing about experience permissions is that they only need ot be requested once per avatar. As an alternative to requesting experience permissions, llAgentInExperience() can be used to test if the avatar has already granted permissions, roughly:

safe_teleport(key ID, /*landmark stuff*/)
{	// write landmark stuff to global variables.
  if(llAgentInExperience(ID))
  {	// do the teleport.
  }else
  {	llRequestExperiencePermissions(ID);
  }
}

Edit: actually, not tested Hmm. . .

FYI, llAgentInExperience() can return false negatives while the target is over land that does not have the land scope experience allowed.

  • Like 2
Link to comment
Share on other sites

6 hours ago, Lucia Nightfire said:

...There is no "broadcasting" ... Scripts that contain experience permissions (0x62000) automatically monitor when the perms holder either blocks the experience or enters land that does not have a land scope experience allowed and removes all perms ... FYI, llAgentInExperience() can return false negatives while the target is over land that does not have the land scope experience allowed.

Re "no broadcasting ... automatically monitor": Ah, so that's it. Yes, makes sense and explains why the teleporter in my house was spewing spurious error messages long after the last time I used it, due to me stepping into the street in front of my house, where my Experience isn't allowed. (I imagine it probably was doing that when I went elsewhere, too, but I wasn't in llSay range of the teleporter so I didn't see it.) All fixed now, though, by just ignoring "true-but-irrelevant information" events.

Re "FYI, llAgentInExperience() can return false negatives while the target is over land that does not have the land scope experience allowed": Well, for the purposes of my teleporter that wouldn't be a false negative, because I need an avatar requesting teleport to not only be in the experience, but also on land that has my experience allowed.

So I think I'll try llAgentInExperience() in my TPer in Cordova Sandbox and see what happens. No experiences are allowed there so it should return "false" meaning "well, he's technically in the experience, but he can't use it here", which would be perfect; I'd then llInstantMessage(ava_key, "Sorry, but \"Experience LoneWolfiNTj\" isn't allowed on this land so I can't teleport you"). I'll also check it outbound from my land to the sandbox and see what happens.

Link to comment
Share on other sites

14 hours ago, Quistess Alpha said:

This just occured to me, but one cool thing about experience permissions is that they only need ot be requested once per avatar. As an alternative to requesting experience permissions, llAgentInExperience() can be used to test if the avatar has already granted permissions, roughly:

safe_teleport(key ID, /*landmark stuff*/)
{	// write landmark stuff to global variables.
  if(llAgentInExperience(ID))
  {	// do the teleport.
  }else
  {	llRequestExperiencePermissions(ID);
  }
}

Edit: actually, not tested Hmm. . .

Ok, I tested that concept, and it doesn't work. I get "Error: attempt to teleport agent without current permission!". So, llAgentInExperience can't be used in lieu of llRequestExperiencePermissions. You have to ask, even if you know the answer is going to be "yes", or llTeleportAgent throws an error.

Link to comment
Share on other sites

31 minutes ago, LoneWolfiNTj said:

Ok, I tested that concept, and it doesn't work. I get "Error: attempt to teleport agent without current permission!". So, llAgentInExperience can't be used in lieu of llRequestExperiencePermissions. You have to ask, even if you know the answer is going to be "yes", or llTeleportAgent throws an error.

I think the confusion here is that a script can only have permissions for one agent at a time, and just because it asked whether an agent is in the Experience doesn't mean that's the agent for which the script gets permissions. (It may ask that about lots of agents from whom it doesn't intend to use permissions.) That's why it needs to llRequestExperiencePermissions  but if the agent is already in the Experience they won't get asked the dialog with the scary litany of component permissions.

Once the script has taken permissions from an agent, though, I think it can ask itself llGetPermissions() and  llGetPermissionsKey() to see if that's the same agent from whom it wants Experience permissions now, and if so, it shouldn't need to request them again, not even tacitly.

  • Like 1
Link to comment
Share on other sites

On 9/29/2021 at 7:26 AM, Qie Niangao said:

Once the script has taken permissions from an agent, though, I think it can ask itself llGetPermissions() and  llGetPermissionsKey() to see if that's the same agent from whom it wants Experience permissions now, and if so, it shouldn't need to request them again, not even tacitly.

The only way I've managed to get llTeleportAgent() to actually work for someone other than the owner of the teleporter is to call it from within a experience_permissions event. And the only way I know to trigger that event is to run the llRequestExperiencePermissions() function. If the agent requesting teleport already gave those permissions in the past, the person's avatar silently says "yes"  back to llRequestExperiencePermissions() (the person sees no dialog box), triggering the experience_permissions event, which can then successfully call llTeleportAgent(). So it appears to me that a script must explicitly ask every time, though agents who have given permission for that Experience in the past don't see the dialog box because the permissions are already "on file".

As for llGetPermissions() and  llGetPermissionsKey(), I don't think those are useful in this context, because they deal with specific "run-time permissions", not "experience permissions" which are a whole different ballgame.

Besides, to actually trigger an event, you'd need to use llRequestPermissions, but that would trigger the run_time_permissions event, which will not allow llTeleportAgent() to work on anyone other than the owner.

Hence, the need to call llRequestExperiencePermissions() instead, in order to trigger a experience_permissions event.

Link to comment
Share on other sites

11 hours ago, LoneWolfiNTj said:

The only way I've managed to get llTeleportAgent() to actually work for someone other than the owner of the teleporter is to call it from within a experience_permissions event.

Not sure there's any real reason to teleport from anything but the experience_permissions event, but the following little script seems to teleport directly from a collision event, after the first time the agent grants permissions, both for me and a non-owning alt.

vector destiny = <41, 89, 20>;
vector facing = <42, 89, 20>;

default
{
    collision_start(integer num_detected)
    {
        key collider = llDetectedKey(0);
        if (ZERO_VECTOR != llGetAgentSize(collider))
        {
            if ((collider == llGetPermissionsKey())
                && (PERMISSION_TELEPORT & llGetPermissions()))
            {
                llWhisper(0, "TELEPORTING FROM collision_start");
                llTeleportAgent(collider, "", destiny, facing);
            }
            else
                llRequestExperiencePermissions(collider, "");
        }
    }
    experience_permissions(key agent)
    {
        llWhisper(0, "teleporting from experience_permissions");
        llTeleportAgent(agent, "", destiny, facing);
    }
    experience_permissions_denied(key agent, integer reason)
    {
        llOwnerSay("NO PERMS, reason:"+(string)reason);
    }
}

Incidentally, to the subject of the thread, this should emit "NO PERMS" messages when the teleported agent steps off experience-scoped land if that works the way I think it does.

 

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 988 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...