Jump to content
Hillary Davi

LSL Experience Teleporter

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

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

Recommended Posts

The first post just wanted to share some code to create an experience teleporter. If you feel you can make it better please post it here.

The variables on top

teleportme is where you want to go on the sim

textdefault is the title over head which will automatically be changed and reset 

I used and read the following articles, Please read the following to understand the code

  1. http://wiki.secondlife.com/wiki/LlAgentInExperience
  2. https://wiki.secondlife.com/wiki/LlRequestExperiencePermissions
  3. https://wiki.secondlife.com/wiki/LlGetExperienceErrorMessage
vector teleportme = <212,150,1000>;
string MyObjectName;
string textdefault = "Teleport to platform!";
//Begin code
string theerror;
integer error;
key agent;
integer type;
default
{
    state_entry()
    {
        MyObjectName = llGetObjectName();
        llVolumeDetect(TRUE);
        llSetText(textdefault, <1.0, 1.0, 1.0>, 1.0);
    }
    collision_start(integer num)
    { 
       agent = llDetectedKey(0); type = llDetectedType(0);
       if (type == (AGENT | ACTIVE) ) // 1 + 2
        {
            llRequestExperiencePermissions(agent, "");
        }   
    } 
    experience_permissions(key agent) {
            llSetText(llKey2Name(agent) + " is using the teleporter please wait...", <1.0, 1.0, 1.0>, 1.0);
            llTeleportAgent(agent, "", teleportme, teleportme);
            llSleep(1);
             llSetText(textdefault, <1.0, 1.0, 1.0>, 1.0);   
    }
    
    experience_permissions_denied(key agent, integer reason){
        string theerror = llGetExperienceErrorMessage((integer)reason);
        if(reason = XP_ERROR_THROTTLED) {
         llSleep(2);
        } else if (reason = XP_ERROR_REQUEST_PERM_TIMEOUT || reason = XP_ERROR_NOT_PERMITTED || reason = XP_ERROR_NOT_FOUND) {
             llInstantMessage(agent, "Please accept the experience or bad things may happen!"); 
            } 
        if(!llAgentInExperience(agent)) {
         llRequestExperiencePermissions(agent, "");  
         //llRequestExperiencePermissions(llDetectedKey(0), "");
        }
       
    }
    
    touch_start(integer total_number)
    {
     agent = llDetectedKey(0);  type = llDetectedType(0);
       if (type == (AGENT | ACTIVE) ) // 1 + 2
        {
            llRequestExperiencePermissions(agent, "");
        } 
    }
     
}
    

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Looks good, but one question -- why are you using the same vector, teleportme, for both the destination and the look_at vector?   In which direction does <212,150,1000> mean you should look?   

Share this post


Link to post
Share on other sites

Not sure did not look into that function deeply but I know it works. 

Edit- I remember now I think one vector is the location and the other is the offset. I set it this way because if i wanted i can make another variable and change it up quickly. Not sure it's the proper but a nice placeholder. ;)

Edit2: The other is vector look at. http://wiki.secondlife.com/wiki/LlTeleportAgent

Function: llTeleportAgent( key avatar, string landmark, vector position, vector look_at );

Edited by Hillary Davi
update

Share this post


Link to post
Share on other sites

That vector is the position that your teleportee is intended to be facing as she arrives.  It's a global vector, not local relative to the avatar. The Z component is ignored, since an avatar is always vertical. If you use the same vector for both the destination and the LookAt position, I think the default is that you end up facing east. Frankly, I've never tried doing that, but it makes sense.

Elsewhere in the script, I can't think of a situation where it's necessary to specify that an AGENT is also ACTIVE.  Certainly not in teleportation.  You could simplify the script by removing that condition.

Edited by Rolig Loon

Share this post


Link to post
Share on other sites
if(reason = XP_ERROR_THROTTLED) {
         llSleep(2);
        } else if (reason = XP_ERROR_REQUEST_PERM_TIMEOUT || reason = XP_ERROR_NOT_PERMITTED || reason = XP_ERROR_NOT_FOUND)

You're assigning (=) constants instead of evaluating (==) them. And in regards to the errors you're checking,

XP_ERROR_THROTTLED is a KVP throttle error, not a teleport throttle error. The tp throttle is in the form of a script error.

XP_ERROR_REQUEST_PERM_TIMEOUT occurs after 5 minutes of no acknowledgement from the user for perms request.

XP_ERROR_NOT_FOUND is an experience not found server error, not an agent not found error.

The most common errors to occur are XP_ERROR_NOT_PERMITTED with agents blocking or already having blocked the experience and XP_ERROR_NOT_PERMITTED_LAND where the target agent or host object is not over land that has the experience allowed.

 

        if(!llAgentInExperience(agent)) {
         llRequestExperiencePermissions(agent, "");  
         //llRequestExperiencePermissions(llDetectedKey(0), "");
        }

You shouldn't re-request perms inside the exp perms denied event or you will most likely just end up continuously triggering it regardless of the error.

  • Like 1

Share this post


Link to post
Share on other sites
13 minutes ago, villadelfia said:

I don't see the point of sleeping for 1 second upon teleporting someone.

There is sometimes a good reason for putting a llSleep in a teleporter, to avoid running into the region's throttle.  That's not likely to be a problem unless you have a lot of teleporters, or a single teleporter that is designed to TP a crowd of people in a very short time, but it could make sense then.

Edited by Rolig Loon

Share this post


Link to post
Share on other sites

First, I put the second sleep because I kept getting errors when people touched it continuously. You probably don't need it so comment it out ;D All you need to do is add the // to the line.

every time someone calls the touch I also had it do another sleep. The seconds are so small I just figured to keep it there. As the delay was not noticeable. Pick the sleep and just comment out if you don't need. 

experience_permissions_denied( //Added the test and check if there was a throttle

 

Share this post


Link to post
Share on other sites
53 minutes ago, Hillary Davi said:

I put the second sleep because I kept getting errors when people touched it continuously.

That's a very good reason. If people are spam clicking the teleporter, you will indeed hit the region throttle and get an error message. IMO, though, it would be smarter to prevent spam clicking in the first place.  All you need is a global integer (iTouched) that you can use as a flag to flip as soon as someone clicks, and then flip back after the teleport is complete.
 

touch_start (integer num)
{
    if (!iTouched)
    {
        iTouched = TRUE;
        // Do your TP stuff
        llSetTimerEvent(1.0);    // Here's your substitute for a llSleep
    }
}

timer()
{
    llSetTimerEvent(0.0);
    iTouched = FALSE;
}

Then you can get rid of your check for ERROR_THROTTLED and simplify the script.  (In fact, I would remove the entire experience_permissions_denied event, but that's me.)

Share this post


Link to post
Share on other sites

Another way to prevent spam clicking would be something like 

	touch_start(integer total_number)
	{
		if(llGetTime()> 1.0){
			llResetTime();
			//do teleporter stuff
		}
	}

 

Share this post


Link to post
Share on other sites

Thanks to everyone who contributed this is what I Have in the sorta final.

I liked the switch idea by Rolig Loon because it allowed reusing the timer since you can only have one timer in a state. Although I still get errors it might be due to the error checking. I am rethinking the are where Lucia Nightfire posted about.

Lines: 60 61 and 62: 

        } else if (reason = XP_ERROR_REQUEST_PERM_TIMEOUT || reason = XP_ERROR_NOT_PERMITTED || reason = XP_ERROR_NOT_FOUND) {
             llInstantMessage(agent, "Please accept the experience or bad things may happen!"); 
            } 

Might be something there...

 

Here is the final code so far it's working ;) Try it out or post your comments below if you have better ways. There might be a way to make a separate function for the switch and teleports. 

vector teleportme = <212,150,1000>;
string MyObjectName;
string textdefault = "Teleport to platform!";
//Begin code
string theerror;
integer error;
key agent;
integer type;

//this is for the function added to switch on or off globally
//this float is needed for the fuction contributed by Rolig Loon
float iTouched;

default
{
    state_entry()
    {
         iTouched = FALSE;
        MyObjectName = llGetObjectName();
        //llVolumeDetect(TRUE); Removed because testing timer instead of using volume detect
        llSetText(textdefault, <1.0, 1.0, 1.0>, 1.0);
    }
    collision_start(integer num)
    { 
       agent = llDetectedKey(0); type = llDetectedType(0);
       if (type == (AGENT | ACTIVE) ) // 1 + 2
        {
            llRequestExperiencePermissions(agent, "");
        }   
    } 
//Timer added by Rolig Loon https://community.secondlife.com/profile/796876-rolig-loon/
timer()
{
    llSetTimerEvent(0.0);
    iTouched = FALSE;
}
    experience_permissions(key agent) {
        
        //touch function added and contributed by Rolig Loon https://community.secondlife.com/profile/796876-rolig-loon/ with some tweaks
        if (iTouched = TRUE)
        {
       
            // Do your TP stuff
            llSetText(llKey2Name(agent) + " is using the teleporter please wait...", <1.0, 1.0, 1.0>, 1.0);
            llTeleportAgent(agent, "", teleportme, teleportme);
            llSetTimerEvent(2.0);   // Here's your substitute for a llSleep contributed by Rolig Loon 
        }
             llSetText(textdefault, <1.0, 1.0, 1.0>, 1.0);   
    }
    
    experience_permissions_denied(key agent, integer reason){
        string theerror = llGetExperienceErrorMessage((integer)reason);
        if(reason = XP_ERROR_THROTTLED) {
                 //touch function added and contributed by Rolig Loon https://community.secondlife.com/profile/796876-rolig-loon/ 
                 //with some tweaks
                if (iTouched = TRUE)
                {
                    
                     llSetTimerEvent(4.0);    // Here's your substitute for a llSleep contributed by Rolig Loon 
                  }
        } else if (reason = XP_ERROR_REQUEST_PERM_TIMEOUT || reason = XP_ERROR_NOT_PERMITTED || reason = XP_ERROR_NOT_FOUND) {
             llInstantMessage(agent, "Please accept the experience or bad things may happen!"); 
            } 
        if(!llAgentInExperience(agent)) {
         llRequestExperiencePermissions(agent, "");  
         //llRequestExperiencePermissions(llDetectedKey(0), "");
        }
       
    }
    
    touch_start(integer total_number)
    {
      iTouched = TRUE;
     agent = llDetectedKey(0);  type = llDetectedType(0);
                  if (type == (AGENT | ACTIVE) ) // 1 + 2
                   {
                     llRequestExperiencePermissions(agent, "");
                    } 

    }
     
}

 

Share this post


Link to post
Share on other sites

I didn't check the code in detail but in experience_permissions_denied you wrongly use "=" (assignment) instead of "==" (compare) in all if's.

Same in experience_permissions.

And you use llDetectedKey and that doesn't work here - you need to use agent instead.

Share this post


Link to post
Share on other sites

I have checked the code and simplified it and  tidied it up rather.   I've not tested it in-world but I think it looks right.  

It really might be better, in future, if people post code they're working on in the main script forum and only put the finished version here in the library.   I don't think the library is the place for works in progress.


integer iTouched;
vector vTeleportTarget = <212,150,1000>;
string strMyObjectName;
string strTextDefault = "Teleport to platform!";
//Begin code

key kAgent;
//integer iType;

//this is for the function added to switch on or off globally
//this float is needed for the fuction contributed by Rolig Loon


default
{
    state_entry()
    {
        iTouched = FALSE;
        strMyObjectName = llGetObjectName();
        //llVolumeDetect(TRUE); Removed because testing timer instead of using volume detect
        llSetText(strTextDefault, <1.0, 1.0, 1.0>, 1.0);
    }
    collision_start(integer num)
    {
        if(!iTouched){ //ignore it if I'm in use 
           
           if (llDetectedType(0) & AGENT)
            {
                kAgent = llDetectedKey(0);  
                llSetText(llGetDisplayName(kAgent) + " is using the teleporter please wait...", <1.0, 1.0, 1.0>, 1.0);
                llSetTimerEvent(10.0);//need to turn on the timer here in case the agent changes his mind and wanders off.  If this happens, the object eventually becomes touchable again.
                iTouched = TRUE;
                llRequestExperiencePermissions(kAgent, ""); //no need to test for llAgentInExperience -- if the agent is, then he'll be teleported and if he's not, the simulator will ask him to accept the experience.
             }
        }
    }
    //Timer added by Rolig Loon https://community.secondlife.com/profile/796876-rolig-loon/
    timer()
    {
        iTouched =FALSE;
        llSetText(strTextDefault, <1.0, 1.0, 1.0>, 1.0);
        
    }
    experience_permissions(key agent) {
        if(agent == kAgent){//should always be, but it can sometimes be an issue if people leave the region unexpectedly -- eg crash
               // Do your TP stuff
            llTeleportAgent(kAgent, "", vTeleportTarget, vTeleportTarget);
            llSetTimerEvent(2.0);   // Here's your substitute for a llSleep contributed by Rolig Loon

        }
        
    }


    touch_start(integer total_number)
    {
        if(!iTouched){ // no one can touch it again while it's trying to teleport you
           
           if (llDetectedType(0) & AGENT) //though how on earth you can touch things without being an agent is a bit of puzzle
            {
                kAgent = llDetectedKey(0);  
                llSetText(llGetDisplayName(kAgent) + " is using the teleporter please wait...", <1.0, 1.0, 1.0>, 1.0);
                llSetTimerEvent(10.0);//need to turn on the timer here in case the toucher changes his mind and wanders off.  If this happens, the object becomes touchable again.
                iTouched = TRUE;
                llRequestExperiencePermissions(kAgent, ""); //no need to test for llAgentInExperience -- if the agent is, then he'll be teleported and if he's not, the simulator will ask him to accept the experience.
             }
        }
    }

}

 

  • Like 2

Share this post


Link to post
Share on other sites
20 minutes ago, Innula Zenovka said:

It really might be better, in future, if people post code they're working on in the main script forum and only put the finished version here in the library.   I don't think the library is the place for works in progress.

Yes. B|

  • Like 1

Share this post


Link to post
Share on other sites

So I'm wanting to use something like this as a hud for multi-region teleport. I'd be willing to pay someone to figure out which volcano we need to throw SL virgins into to make this happen. Something that like a person could rez a marker on their land and it would update within the experience hud as a location to available to teleport to . 

Share this post


Link to post
Share on other sites
7 minutes ago, Gingir Ghoststar said:

So I'm wanting to use something like this as a hud for multi-region teleport.

That doesn't take any special magic.  You don't even need to have an Experience to make it work, since llTeleportAgent will always teleport the owner of the scripted object, and you are always the owner of any HUD you are wearing. Use either of the first two examples in the LSL wiki at http://wiki.secondlife.com/wiki/LlTeleportAgent#Examples.  Modify them only to the extent of melding them with a basic dialog menu so that you give the owner a selection of possible destinations.  That's all there is to it.

Share this post


Link to post
Share on other sites

Mine is worse, and uglier, but does read landmark for its input. 

Also, I have a more complete reporting of errors that you can copy if you like.  I give the system error first, and then give additional details from the wiki.

I'd like someone to expand mine to read multiple landmarks and present a menu.  I know how, because I have used @Rolig Loon 's fine simple multi-page menu code before on another project.  Right now, I have too many vehicles projects going that keep me busy.

 

 

Share this post


Link to post
Share on other sites

I was trying to create a teleport system using menu button and the code given in this topic with some modification

but I Failed, here is my code can anyone help me to find out where is my mistake ?

 

Note card

Club=<32,96,2500>
Store=<32,96,1000>
Ground=<32,96,34>
Deep=<32,96,1>

 

LSL Script

 

string gCard = "destinations";
string dText = "Touch to Teleport";
vector gTarget;

list gLstMnu;
list gDlabels;
list location;
list address;

integer gCount;
integer gDChan;
integer gDLisn;
integer gLine;
integer lMenu;
integer nMenu;
integer iTouched;

key gQuery;
key kAgent;

list uDlgBtnLst( integer vIntPag ){
    integer vIdxBeg = 10 * (~-vIntPag);          //-- 10 * (vIntPag - 1), enclose "~-X" in parens to avoid LSL bug
    integer vIdxMax = -~(~([] != gLstMnu) / 10); //-- (llGetListLength( gLstMnu ) - 1) / 10 + 1
    lMenu = (vIntPag + (-(vIntPag > 1) | vIdxMax - vIntPag));
    nMenu = (-~((vIntPag < vIdxMax) * vIntPag));
    list vLstRtn = llListInsertList(llList2List(gLstMnu, vIdxBeg, vIdxBeg + 9),["Back"],-1)+["Next"];
    return llList2List(vLstRtn, -3, -1) + llList2List(vLstRtn, -6, -4) + llList2List(vLstRtn, -9, -7) + llList2List(vLstRtn, -12, -10);
}

default{
    
    on_rez(integer start_param){llResetScript();}
    
    changed(integer change){
        if(change & CHANGED_OWNER){llResetScript();}
        if (change & CHANGED_INVENTORY){llResetScript();} //restart if the notecard was modified
    }
    
    state_entry(){
        iTouched = FALSE;
        llSetText(dText, <1.0, 1.0, 1.0>, 1.0);
        if (llGetInventoryKey(gCard) == NULL_KEY){llOwnerSay("destinations notecard missing");}
        else{
            gQuery =llGetNotecardLine(gCard,gLine);
            gCount = 1;
        }
    }
    
    dataserver(key qID, string data){
        if (qID == gQuery){
            if (data != EOF){
                integer idx = llSubStringIndex(data,"=");
                if (~idx){
                    location += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //location names from NC
                    address += [llStringTrim(llGetSubString(data,idx+1,-1),STRING_TRIM)];  //address from NC
                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text
                    gLstMnu += [(string)gCount]; // Button labels
                    ++gCount;
                }
                gQuery = llGetNotecardLine(gCard,++gLine);
            }
        }
    }

    touch_start(integer total_number){
        if(!iTouched){ // no one can touch it again while it's trying to teleport you
            if (llDetectedType(0) & AGENT){ //though how on earth you can touch things without being an agent is a bit of puzzle
                kAgent = llDetectedKey(0);
                llSetText(llGetDisplayName(kAgent) + " is using the teleporter please wait...", <1.0, 1.0, 1.0>, 1.0);
                llSetTimerEvent(10.0);//need to turn on the timer here in case the toucher changes his mind and wanders off.  If this happens, the object becomes touchable again.
                iTouched = TRUE;
                gDChan = (integer)("0xF" + llGetSubString(llDetectedKey(0),0,6));
                gDLisn = llListen(gDChan,"","","");
                string temp = "";
                integer i;
                for (i=0;i<10;++i){temp += llList2String(gDlabels,i);}
                llDialog(kAgent,"Choose a destination \n"+ temp, uDlgBtnLst(1) ,gDChan);
            }
        }
    }
    
    listen (integer channel, string name, key id, string msg){
        if((msg == "Back") | (msg == "Next")){
            llSetTimerEvent(10.0);
            gDLisn = llListen(gDChan,"","","");
            integer menu;
            string temp = "";
            if(msg == "Back"){menu = lMenu;}
            else if(msg == "Next"){menu = nMenu;}
            integer i;
            for (i=(10*(menu-1));i<(10*menu);++i){temp += llList2String(gDlabels,i);}
            llDialog( id, "Choose a destination \n"+ temp, uDlgBtnLst(menu), gDChan );
        }else{
            integer Choice = (integer) msg -1;
            gTarget = (vector)llList2String(address,Choice);
            llRequestExperiencePermissions(kAgent, "");
        }
    }
    
    experience_permissions(key agent){
        if(agent == kAgent){
            llTeleportAgent(kAgent, "", gTarget, ZERO_VECTOR);
            llSetTimerEvent(2.0);
        }
    }
    
    timer(){
        iTouched =FALSE;
        gTarget = ZERO_VECTOR;
        llSetTimerEvent(0.0);
        llListenRemove(gDLisn);
        llSetText(dText, <1.0, 1.0, 1.0>, 1.0);
        llWhisper(0,"Timeout. Please close the dialog box on your screen.");
    }
}
 

Share this post


Link to post
Share on other sites

So, how does it fail?  I works fine for me, although I suggest making a couple of small (mostly cosmetic and personal preference) changes:

1.  Modify your dataserver event by providing an alternate exit when data ==EOF  :

     

        else
        {
            iTouched = FALSE;
        }

      and set iTouched = TRUE in state_entry.  That way, the teleporter is disabled unless the script reads the notecard successfully.

2. Remove the llWhisper line of code at the end of the timer event or replace it with 

          llDialog(kAgent,"\nPlease close this dialog box",["OK"],gDLisn);

    and then move the llListenRemove statement after that line so that the channel is still available for the dialog.  The "OK" response will be unheard, but that's fine.  It will close the dialog.

  • Like 1

Share this post


Link to post
Share on other sites
On 4/28/2020 at 10:43 PM, Rolig Loon said:

So, how does it fail?  I works fine for me, although I suggest making a couple of small (mostly cosmetic and personal preference) changes:

1.  Modify your dataserver event by providing an alternate exit when data ==EOF  :

     


        else
        {
            iTouched = FALSE;
        }

      and set iTouched = TRUE in state_entry.  That way, the teleporter is disabled unless the script reads the notecard successfully.

2. Remove the llWhisper line of code at the end of the timer event or replace it with 

          llDialog(kAgent,"\nPlease close this dialog box",["OK"],gDLisn);

    and then move the llListenRemove statement after that line so that the channel is still available for the dialog.  The "OK" response will be unheard, but that's fine.  It will close the dialog.

everything was working fine in the previous code and I changed as you advised, but still not working.

I have tested in every aspect as possible to me, the problem is in llRequestExperiencePermissions(kAgent, ""); this is not asking any permission and not working further, as the Experience created by me so I thought there might problem in it, so I tested that using collision event TP and that working absolutely fine, but not here... and I tested from another account after removing the experience, still not working not asking the permission of experience..... I checked the generated data is perfect when it calling llRequestExperiencePermissions but still that not actually asking any permission !!!! Strange

Share this post


Link to post
Share on other sites
1 minute ago, raj441977 said:

everything was working fine in the previous code and I changed as you advised, but still not working.

I have tested in every aspect as possible to me, the problem is in llRequestExperiencePermissions(kAgent, ""); this is not asking any permission and not working further, as the Experience created by me so I thought there might problem in it, so I tested that using collision event TP and that working absolutely fine, but not here... and I tested from another account after removing the experience, still not working not asking the permission of experience..... I checked the generated data is perfect when it calling llRequestExperiencePermissions but still that not actually asking any permission !!!! Strange

 

Share this post


Link to post
Share on other sites

So include an experience_permissions_denied event and see what the error is.  That will tell you what's going on.  My almost random guess is that your script isn't really in the Experience.

  • Like 2

Share this post


Link to post
Share on other sites
13 minutes ago, Rolig Loon said:

So include an experience_permissions_denied event and see what the error is.  That will tell you what's going on.  My almost random guess is that your script isn't really in the Experience.

OH MY GOD!!!! I forgotten to enable the experience in the script 😩  ..... now it's working fine... Thank you very much for your help 🙏

  • Like 2

Share this post


Link to post
Share on other sites
You are about to reply to a thread that has been inactive for 76 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...