Jump to content

Experience Attach issue


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

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

Recommended Posts

Hey, so, I have a system setup where if you enter the region a hud auto attaches to the avatar.

The way it currently works is. Box A scans the sim and adds all avatars into a "inSim" list. Box A then works through the list, first setting the avatars key as the description of Box A. Box A then rez's Box B. Box B, using llGetObjectDetails, gets the description of Box A, aka avatar in sims key, and then sends a message to that avatar asking them if they already have the system attached. If Box B gets a response, Box B deletes itself. If Box B doesn't get a response after 10 seconds, Box B requests experience permissions and then rez's the system, which uses the same method but grabs the key from Box B description, and then auto attaches to the avatar. The reason Box B asks if you are wearing the HUD first is, this system is working across multiple regions joined together. The reason for so many boxes is....once Box B is Rez and has the key, that frees up Box A to continue working through the inSim list.

The issues im getting are as follows...

1. Occasionally when I cross from one sim into another, the system will detach itself, as if it's trying to attach another version. Which it shouldn't as it's supposed to answer Box B's question of is the hud on. And then delete Box B if it is.

2. The HUD / Box B is occasionally throwing an error about not being able to find an avatar to request the experience from. It should be getting the avatars key from the previous rez description.

3. Is there a better way to do this? The method im using seems like it would be the most sensible but is there a better and more efficient way?

You can ignore the dialog stuff, its just the experience attach and sim scan stuff that im having these issues with.

 

Box A Code - Keys for dev, admin, channel numbers and encryption stuff was removed for privacy reasons

list inSim=[];  //In sim already
list grab=[];   //Temporarily grab all to be sorted

list aMenu=[    //Admin menu
    "Update",
    "DetachAll"
];
list nMenu=[    //Normal menu
    "AttachHUD"
];

list admins=[
];

key admin;
    

//Channels
integer sChan;
integer sList;
integer mChan;
integer mList;
integer mInd;

//Keys
key target;
key dev="";
key player;

//Encryption password
string password="";

//Encrypt
string encrypt(string msg){
    
    return msg;
}
//Decrypt
string decrypt(string msg){
    
    return msg;
}

grabPlayers(){
    //Scan players
    grab=llGetAgentList(AGENT_LIST_REGION,[]);
    integer i=-1;
    integer inCheck;
    //Determine if in the sim already or need to check exp
    while(++i<llGetListLength(grab)){
        if(~inCheck=llListFindList(inSim,[llList2Key(grab,i)])){
            //Already in sim
            //llOwnerSay(llKey2Name(llList2Key(grab,i))+" is already in the sim");
        }else{
            //Not in the sim
            //llOwnerSay(llKey2Name(llList2Key(grab,i))+" is not in the sim");
            inSim+=[llList2Key(grab,i)];
            target=llList2Key(grab,i);
            llSetObjectDesc((string)target);
            //if(target==admin)llRezAtRoot("SystemExpCheck",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
            llRezAtRoot("SystemExpCheck",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
            llSleep(2.0);
            //Check experience
        }
    }
    //Now check inSim list to make sure no one has left
    if(llGetListLength(inSim)>0){
        list temp=inSim;
        i=-1;
        while(++i<llGetListLength(temp)){
            if(~inCheck=llListFindList(grab,[llList2Key(temp,i)])){
                //llOwnerSay(llKey2Name(llList2Key(temp,i))+" is already in sim");
            }else{
                inSim=llDeleteSubList(inSim,i,i);
                //llOwnerSay("Removed "+llList2String(temp,i)+" from list");
            }
        }
    }
}
detachAll(){
    integer i=-1;
    while(++i<llGetListLength(inSim)){
        llRegionSayTo(llList2Key(inSim,i),sChan,encrypt(llList2String(inSim,i)+",detachHUD"));
        llRegionSayTo(llList2Key(inSim,i),sChan,encrypt(llList2String(inSim,i)+",detachMeter"));
    }
}

default{
    state_entry(){
        llListenRemove(sList);
        sList=llListen(sChan,"",NULL_KEY,"");
        llSetTimerEvent(5.0);
    }
    on_rez(integer param){
        llResetScript();
    }
    touch_start(integer x){
        key admin=llDetectedKey(0);
        if(~llListFindList(admins,[(string)admin])){
            mInd=1;
            llListenRemove(mList);
            mChan=11111+(integer)llFrand(99999);
            if(llDetectedKey(0)==admin){
                player=admin;
                mList=llListen(mChan,"",player,"");
                llDialog(player,"\nHUD",aMenu,mChan);
            }
        }else{
            llRegionSayTo(admin,0,"You do not have permission to use this item.");
        }
    }
    listen(integer channel, string name, key id, string message){
        if(channel==mChan){
            if(id==dev){
                //Admin options
                if(mInd==1){
                    if(message=="Update"){
                        inSim=[];
                        detachAll();
                        grabPlayers();
                    }else if(message=="Notice"){
                        return;
                        //mInd=2;
                        //llTextBox(admin,"System Notice",mChan);
                    }else if(message=="DetachAll"){
                        detachAll();
                    }else if(message=="AttachHUD"){
                        return;
                        //llSetObjectDesc((string)dev);
                        //llRezAtRoot("SystemExpCheck",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
                    }
                }else if(mInd==2){
                    integer i=-1;
                    while(++i<llGetListLength(inSim)){
                        llRegionSayTo(llList2Key(inSim,i),sChan,encrypt(llList2String(inSim,i)+",hudNotice,"+message));
                    }
                }
            }else{
                //Normal
                if(message=="AttachHUD"){
                    llSetObjectDesc((string)id);
                    llRezAtRoot("SystemExpCheck",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
                }
            }
        }else if(channel==sChan){
            return;
            list pStr=llCSV2List(decrypt(message));
            if(llList2String(pStr,0)=="attachHUD"){
                llSetObjectDesc(llList2String(pStr,1));
                llRezAtRoot("SystemExpCheck",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
                llSleep(2.0);
            }
        }
    }
    timer(){
        grabPlayers();
    }
}

 

Box B Code - Keys, Channels etc removed for same reasons as above

//Channels
integer sysChan;
integer sysList;

//Encryption
string password="";

//Other
key expCheck;
key av;
integer rezCheck=0;

//Encrypt
string encrypt(string msg){
    
    return msg;
}
//Decrypt
string decrypt(string msg){
    
    return msg;
}

default{
    on_rez(integer param){
        key rez=llList2Key(llGetObjectDetails(llGetKey(),[OBJECT_REZZER_KEY]),0);
        av=llList2Key(llGetObjectDetails(rez,[OBJECT_DESC]),0);
        //llOwnerSay("Av is: "+(string)av);
        llSetObjectDesc((string)av);
        llListenRemove(sysList);
        sysList=llListen(sysChan,"",NULL_KEY,"");
        llRegionSayTo(av,sysChan,encrypt((string)av+",isHudOn,"+(string)llGetKey()));
        llSetTimerEvent(5.0);
    }
    experience_permissions(key id){
        if(id){
            llRezObject("HUD",llGetPos()+<0.0,0.0,2.0>,ZERO_VECTOR,ZERO_ROTATION,1);
        }
    }
    listen(integer channel, string name, key id, string message){
        if(channel==sysChan){
            //System chan
            list pStr=llCSV2List(decrypt(message));
            if(llList2Key(pStr,0)==av){
                if(llList2String(pStr,1)=="hudIsOn"){
                    //llOwnerSay("is on");
                    llDie();
                }
            }
        }
    }
    timer(){
        if(!rezCheck){
            llRequestExperiencePermissions(av,"");
            rezCheck=1;
            llSetTimerEvent(0.0);
            llSetTimerEvent(20.0);
        }else{
            llDie();
        }
    }
}

 

Code inside the system that attaches to the avatar.

integer rez=0;
default{
    on_rez(integer param){
        //Param code check
        if(rez==0){
            rez=1;
            key rez=llList2Key(llGetObjectDetails(llGetKey(),[OBJECT_REZZER_KEY]),0);
            key target=llList2Key(llGetObjectDetails(rez,[OBJECT_DESC]),0);
            llRequestExperiencePermissions(target,"");
            llSetTimerEvent(5.0);
        }
    }
    experience_permissions(key id){
        if(id){
            if(rez){
                rez=0;
                llAttachToAvatarTemp(ATTACH_HUD_CENTER_1);
            }
        }
    }
    timer(){
        if(rez){
           llDie();
        }
        llSetTimerEvent(0.0);
    }
}

 

Edited by ItHadToComeToThis
  • Thanks 1
Link to comment
Share on other sites

15 hours ago, ItHadToComeToThis said:

Is there a better way to do this?

There's a bunch of this I don't understand, but I can't imagine using object descriptions to communicate between objects.

It appears that Box A sets its description, rezzes Box B, and llSleep()s for two seconds in hopes Box B will finish rezzing and reading the description before Box A wakes up and rezzes the next Box B. That'll probably work almost all the time, but it's sure not to work some of the time, and there are multiple widely-used approaches for communicating between a rezzer and its rezzed children. See the object_rez wiki page for a couple cookbook examples, or try something else, perhaps communicating via the Experience's KVP persistent store (since all the scripts can be compiled to that experience), but whatever the medium, the logic mustn't assume the rezzed object is ready to do anything until it says it's ready.

This section, I'm sure, explains why there needs to be a separate Box B instead of just rezzing the HUD directly, but I've reread it a dozen times and can't understand:

15 hours ago, ItHadToComeToThis said:

The reason for so many boxes is....once Box B is Rez and has the key, that frees up Box A to continue working through the inSim list.

It's not obvious to me why a freshly rez'd HUD can't just do everything Box B is doing and then decide whether to attach to the target avatar. If at all possible, I'd remove Box B from the architecture, removing a whole raft of potential failure modes with it.

With the llSleeps between rezzes, it's not surprising that some avatars will escape the region before anything asks whether they have a HUD attached, requests Experience permissions, or tries to attach, but if it remains unexplained after tightening up the delays you could log those attempts (to Experience KVP if nowhere else) to gather more info about which avatars are falling through the cracks, and maybe why.

Maybe somebody who deals with temp-attached objects across region borders will know if they just fall off sometimes, even if both regions have the Experience enabled. It wouldn't seem too surprising, considering that regular attachments fall off occasionally on teleport.

Link to comment
Share on other sites

5 hours ago, Qie Niangao said:

There's a bunch of this I don't understand, but I can't imagine using object descriptions to communicate between objects.

It appears that Box A sets its description, rezzes Box B, and llSleep()s for two seconds in hopes Box B will finish rezzing and reading the description before Box A wakes up and rezzes the next Box B. That'll probably work almost all the time, but it's sure not to work some of the time, and there are multiple widely-used approaches for communicating between a rezzer and its rezzed children. See the object_rez wiki page for a couple cookbook examples, or try something else, perhaps communicating via the Experience's KVP persistent store (since all the scripts can be compiled to that experience), but whatever the medium, the logic mustn't assume the rezzed object is ready to do anything until it says it's ready.

This section, I'm sure, explains why there needs to be a separate Box B instead of just rezzing the HUD directly, but I've reread it a dozen times and can't understand:

It's not obvious to me why a freshly rez'd HUD can't just do everything Box B is doing and then decide whether to attach to the target avatar. If at all possible, I'd remove Box B from the architecture, removing a whole raft of potential failure modes with it.

With the llSleeps between rezzes, it's not surprising that some avatars will escape the region before anything asks whether they have a HUD attached, requests Experience permissions, or tries to attach, but if it remains unexplained after tightening up the delays you could log those attempts (to Experience KVP if nowhere else) to gather more info about which avatars are falling through the cracks, and maybe why.

Maybe somebody who deals with temp-attached objects across region borders will know if they just fall off sometimes, even if both regions have the Experience enabled. It wouldn't seem too surprising, considering that regular attachments fall off occasionally on teleport.

Sorry, I thought I had explained clearly enough but I can see how it might be confusing.

So, the reason for Box B is because of Box B asking the question of "is the hud on", and I wanted to be able to Rez multiple Box B's and leave Box A looping through the people on sim. Then I found out that Box B wasn't grabbing the UUID quick enough so had to start adding delays to allow it to do so.

However, I figured out a better method than asking "is the hud on" and that's checking the avatars attachments for the overhead meter. If the meter is attached, then Box B doesn't Rez and simply dies. The HUD has stopped occasionally detaching when you cross regions now which im happy with, but if theres a better method to be used here then Im happy to explore it.

I will play around with the object_rez method , I had forgotten that event existed to be honest.

Link to comment
Share on other sites

1 hour ago, ItHadToComeToThis said:

So, the reason for Box B is because of Box B asking the question of "is the hud on", and I wanted to be able to Rez multiple Box B's and leave Box A looping through the people on sim.

Yeah, but… I understand that Box A needs to rez something quickly so it can get through potentially multiple avatars in a loop, but what I'm being dense about is why it needs to rez another level of rezzer rather than directly rezzing the HUD and have it determine for itself if it should attach (make sure there's not a HUD attached already) and either llDie or try to temp-attach.

1 hour ago, ItHadToComeToThis said:

However, I figured out a better method than asking "is the hud on" and that's checking the avatars attachments for the overhead meter.

So… the overhead meter (which would be in llGetAttachedList) will always be attached iff the HUD is? 

  • Thanks 1
Link to comment
Share on other sites

2 minutes ago, Qie Niangao said:

Yeah, but… I understand that Box A needs to rez something quickly so it can get through potentially multiple avatars in a loop, but what I'm being dense about is why it needs to rez another level of rezzer rather than directly rezzing the HUD and have it determine for itself if it should attach (make sure there's not a HUD attached already) and either llDie or try to temp-attach.

Peeve: A box can't rez copies of itself from its own inventory! 

Link to comment
Share on other sites

1 hour ago, Love Zhaoying said:

Peeve: A box can't rez copies of itself from its own inventory! 

it can when use a self-replicator.  Which goes:

1) Make a box. Put a copy of the box and a giver script in the box

2) On_rez copy of box from contents. Give the copy of box the contents of the rezzer box

is useful for things like sit teleporters and vehicles which are available for anyone to drive. Saves having to provide a rezzer post.  Person sits on the vehicle. On_sit the vehicle rezzes a copy of itself, person drives away leaving a new vehicle behind in its place for the next person

Link to comment
Share on other sites

2 hours ago, Qie Niangao said:

Yeah, but… I understand that Box A needs to rez something quickly so it can get through potentially multiple avatars in a loop, but what I'm being dense about is why it needs to rez another level of rezzer rather than directly rezzing the HUD and have it determine for itself if it should attach (make sure there's not a HUD attached already) and either llDie or try to temp-attach.

So… the overhead meter (which would be in llGetAttachedList) will always be attached iff the HUD is? 

Yeah, the meter and the hud coexist, if you detach one it detaches the other. You have to be wearing both or none at all.

I guess i could just Rez the hud directly. It would technically just do the same as Box B I guess. I think I was over thinking that bit.

  • Thanks 1
Link to comment
Share on other sites

On 2/15/2024 at 9:25 AM, ItHadToComeToThis said:

The method im using seems like it would be the most sensible but is there a better and more efficient way?

a alternative approach can be multiple scripts in the region monitor. Something like:


1) Scanner script:
   - timer scan for agents on region llGetAgentList(...REGION...)
   - loop thru
      - if (agent no longer on region - llGetAgentSize)) then tag agent KVP Active = False (or remove from KVP) and done
      - if (agent not in experience) then
          - if (agent tagged in KVP as OOC after X invites) then skip/ignore
            else hand off agent key + delegated Ping script id (link_message) to Invite script
        else if (agent in experience) then hand off agent key + KVP Active status (link_message) to available Ping script
2) Invite script:
   - receive agent key + delegated ping script id (link_message)
   - if (agent no longer on region - llGetAgentSize) then tag agent KVP Active = False (or remove from KVP) and done
   - invite agent to experience
   - if (agent accepts invite) then hand off agent key + KVP Active status = False to delegated Ping script
     else if (agent refuses/ignores invite after X scanner-prompted invites) then tag them in KVP as OOC
3) Ping script:
   - receive agent key + KVP Active status (link_message)
   - if (agent no longer on region - llGetAgentSize) then tag agent KVP Active = False (or remove from KVP) and done
   - if (agent no longer in experience) (people can leave an experience at any time) then
        tag agent KVP Active = False and done (inviting them again on next scan)
   - if (agent KVP Active status = False is new entrant) then attach HUD and tag KVP Active = True
     else
       ping the agent's HUD
       - if (ping response) then done
         else if (after X time) attach HUD
          - on_attach HUD (HUD checks for presence of existing HUD)
            - if (existing HUD) then remove/delete the newly attached HUD
4) HUD monitors for presence of companion Meter. Check on HUD attached, Meter detached, and on changed region. Attaching new when Meter not found. When HUD detached then HUD detaches Meter

5) KVP Writer script:
   Any script can read the KVP for info. In the multiple script scenario tho is often better for scripts to pass a Write link_message to a dedicated KVP Writer script to do this work

 

in this approach there are as many Invite and Ping scripts as needed to better handle the volume of agents present at any one time. The scanner script farming (handing off) the work to the Invite and Ping scripts

the objective with this approach is to only rez things when they are needed and to have the scanner script do the least amount of work as possible

 

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

On 2/15/2024 at 11:46 PM, elleevelyn said:

 

 

That was really helpful advice, thank you.

Am I right in thinking that when you cross into a region, the attachments you have on, for a brief second, aren't attached to you while they load into that region? It seems adding a short delay to the meter check, fixed an issue where the HUD would sometimes attach when you enter a new region, as if it couldn't find the meter you were wearing?

Link to comment
Share on other sites

12 hours ago, ItHadToComeToThis said:

Am I right in thinking that when you cross into a region, the attachments you have on, for a brief second, aren't attached to you while they load into that region?

Basically, yes. You could also think about it as the new region taking non-zero time to learn about your attachments from the old region.

Link to comment
Share on other sites

2 minutes ago, Quistess Alpha said:
12 hours ago, ItHadToComeToThis said:

Am I right in thinking that when you cross into a region, the attachments you have on, for a brief second, aren't attached to you while they load into that region?

Basically, yes. You could also think about it as the new region taking non-zero time to learn about your attachments from the old region.

That sounds similar / the same has how vehicles are treated when you cross regions.

In case I missed it, can "temp attachments" cross regions, or always bonked / borked?

Link to comment
Share on other sites

1 hour ago, Love Zhaoying said:

In case I missed it, can "temp attachments" cross regions, or always bonked / borked?

AFAIK the "correct" behavior is that temp attachments only detach when done explicitly (logout/user detach/llDetachFromAvatar) or when entering a parcel/region that doesn't have the experience that requested the permission to attach. A quick test shows that non-experience temp-attachments survive region-changes non-borked.

  • Thanks 1
Link to comment
Share on other sites

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