Jump to content

llRemoteLoadScriptPin() questions


primerib1
 Share

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

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

Recommended Posts

Okay first the scenario

Scenario

Person A wears a HUD A_HUD (C/M/NT) containing two scripts A_sc1 (C/NM/NT) and A_sc2 (C/NM/NT)

Object B (updater) has a script B_sc

  • Person A clicks the "Update" button on their HUD (created by A_sc1)
  • A_sc1 looks around for nearby updater(s) and finds B
  • A_sc1 tells B_sc its version, and B_sc tells A_sc1 that there's an update
  • A_sc1 sets a PIN, and sends the PIN to B, caught by B_sc
  • B_sc uses llRemoteLoadScriptPin() to send a new version of both A_sc1 and A_sc2 scripts
    • Both scripts are set with running = TRUE

Questions

  1. Are the permissions okay?
  2. The documentation says that "state_entry" will be queued; but what state?
    I am assuming the "default" state, am I correct?
  3. What happens to the A_sc1 script (the one that sent the PIN to B_sc and thus triggered the update)?
    Will it be stopped and killed? And all its held resources (listeners, dataservers, etc.) will be released?
    (I do know that LSD is attached to the root prim of A_HUD so all info in LSD will be kept and not touched)
  4. Related to #2 : I am assuming none of old versions's internal states (including global vars) will be copied to new versions's internal states.
    So they are practically just like they had just started running. But with llGetStartParameter() returning whatever was set in llRemoteLoadScriptPin() instead.
    Am I correct?

 

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

[ETA: I didn't really answer #3, so here's the answer: the old copy of A_sc1 just keeps running as if nothing happened. It might detect a CHANGED_INVENTORY if it wants, or otherwise exchange link messages with its updated version, but otherwise it's just business as usual.]

I think your assumptions are okay, although the copied-in scripts will get a new name, so the old "A_sc1" will coexist with the "A_sc1 1" update, then "A_sc1 2" etc., unless something like llRemoveInventory tidies up, and then successive generations will toggle between having and not having the " 1" suffix. Anyway, this coexistence is an opportunity for the old script to propagate state to the update.

Just making sure: the updater object, too, will be owned by Person A, right? because worn attachments can't receive from llRemoteLoadScriptPin called from another owner's object.

Now, here's something I don't know but would want to test: Must the attachment receiving the update be detached into agent inventory and re-attached in order for the update to "stick" especially if the agent crashes? (Yes, I should know this, but I don't.)

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

7 hours ago, Qie Niangao said:

Must the attachment receiving the update be detached into agent inventory and re-attached in order for the update to "stick" especially if the agent crashes?

AFAIK the "copy of the item in user's inventory" only gets updated when the object is detached or when ~cleanly logging out. When you log in, you re-wear everything you were wearing when you (cleanly) logged out, from inventory. So, if the inventory copy wasn't updated, the attached version no longer exists, therefore you "lose" its changes.

The key point, is that even for a "no copy" object, the inventory asset and the attachment are separate things that only share info in limited circumstances. (For example, too lazy to check myself, but notice what happens if you rename a worn attachment in the inventory window, vs the edit window, vs via llSetObjectName() )

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

10 hours ago, primerib1 said:

What happens to the A_sc1 script (the one that sent the PIN to B_sc and thus triggered the update)?
Will it be stopped and killed? And all its held resources (listeners, dataservers, etc.) will be released?
(I do know that LSD is attached to the root prim of A_HUD so all info in LSD will be kept and not touched)

 

8 hours ago, Qie Niangao said:

I think your assumptions are okay, although the copied-in scripts will get a new name, so the old "A_sc1" will coexist with the "A_sc1 1" update, then "A_sc1 2" etc., unless something like llRemoveInventory tidies up, and then successive generations will toggle between having and not having the " 1" suffix. Anyway, this coexistence is an opportunity for the old script to propagate state to the update.

If you are sending a script whose name matches a script that already exists in the target, the target's script is replaced with the sent script.

This means the old script is removed first.

There is no " 1" incrementing of the new script unless it matches the name of a non-script inventory item.

There is no maintaining of script memory.

It is the same as if you dropped the script into the object's inventory manually.

state_entry() in the default state is triggered with whatever start param you specified, which can be read by llGetStartParameter().

The permissions mentioned allow for success worn or rezzed as long as both giver and receiver objects are owned by the same person.

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

Re: for point #3 - One thing I do in this scenario is to name my scripts with their active version number. 

  • In your example it'd be A_sc1_v1 and A_sc2_v1.

Then when the new version of each script is loaded into the object, one of the last things they'd each do is a final cleanup of any script versions that is not them.  A_sc1_v2 would remove any A_sc1_* that's not A_sc1_v2, etc, not just the one prior version.  This catches any skipped updates you might ave published but not yet applied; say they were updating an older copy that still had A_sc1_v1 with the A_sc1_v8 updater for example.  

Yes, this is a bit of extra work in that I have to do a manual cleanup of the script(s) being replaced since I'm not simply overwriting an existing script, but it allows me to have a bit better personal sanity when testing and packaging.  YMMV there, but I'm dyslexic (dyscalculia) and I take what ever extra help I can to keep versions/names/numbers correct in my head.  :)

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

3 hours ago, Lucia Nightfire said:

If you are sending a script whose name matches a script that already exists in the target, the target's script is replaced with the sent script.

Ah, yep, I skipped a step (and a link in the linkset).

This is all from a very old trick for adding memory expansion scripts (now mostly obsolete thanks to LinksetData) that uses a "script mirror" prim to which non-running scripts are merely copied, not yet made to run with llRemoteLoadScriptPin. Instead, that script mirror prim accumulates copies of those non-running scripts in the normal "add 1" naming convention, and with each new copy, remote-loads it, running, back into the original prim. That leaves a bunch of stranded, scripts in the mirror prim, but they're not running and they're tiny (because they're unpopulated memory scripts).

It may be easier to visualize with three links and some simplified scripts:

Link 1: a "script copier object" with two scripts, the "script copier script" and the payload "Copied Script":
the "script copier script":

key script_loading_object_key = NULL_KEY;

default
{
    state_entry()
    {
        integer link = llGetNumberOfPrims();
        do
            if ("script loading object" == llGetLinkName(link))
                script_loading_object_key = llGetLinkKey(link);
        while ((NULL_KEY == script_loading_object_key) && --link);
    }       
    touch_start(integer total_number)
    {
        llGiveInventory(script_loading_object_key, "Copied Script");
    }
}

a simple payload "Copied Script":

default
{
    state_entry()
    {
        if (llGetStartParameter())  // don't run from editor save
            llOwnerSay(llGetScriptName()+" running");
        else
            llSetScriptState(llGetScriptName(), FALSE);
    }
}

Link 2, the "script loading object", gathers those copies and remote-loads them with a "script loading script":

integer PIN = -55;

key script_target_object_key = NULL_KEY;
list scripts;

default
{
    state_entry()
    {
        integer link = llGetNumberOfPrims();
        do
            if ("script target object" == llGetLinkName(link))
                script_target_object_key = llGetLinkKey(link);
        while ((NULL_KEY == script_target_object_key) && --link);
    }
    changed(integer change)
    {
        if (CHANGED_INVENTORY & change)
        {
            llOwnerSay("inventory changed");
            integer invScriptIdx = llGetInventoryNumber(INVENTORY_SCRIPT);
            while (0 <= --invScriptIdx)
            {
                string scriptName = llGetInventoryName(INVENTORY_SCRIPT, invScriptIdx);
                if ((scriptName != llGetScriptName())
                    && (-1 == llListFindList(scripts, [scriptName])))   // handle ONLY script addition
                {
                    llOwnerSay("remote-loading new script: "+scriptName);
                    scripts += scriptName;
                    llRemoteLoadScriptPin(script_target_object_key, scriptName, PIN, TRUE, 99);
                }
            }   // script REMOVAL not handled
        }
    }
}

and Link 3, the "script target object", is where the copied scripts go to run. It just needs to have the PIN set:

integer PIN = -55;

default
{
    state_entry()
    {
        llSetRemoteScriptAccessPin(PIN);
    }
}

So yeah, I definitely forgot that intermediate step. But this part confuses me:

3 hours ago, Lucia Nightfire said:

It is the same as if you dropped the script into the object's inventory manually.

Actually, the above sleight of hand is to get around how llRemoteLoadScriptPin() treats scripts differently from the way llGiveInventory() works—and the way it works dropping multiple copies of a script into an object manually (on which one comes to depend when populating multi-sitter furniture with AVsitter scripts).

Edited by Qie Niangao
stray linebreak
Link to comment
Share on other sites

21 hours ago, Lucia Nightfire said:

If you are sending a script whose name matches a script that already exists in the target, the target's script is replaced with the sent script.

This means the old script is removed first.

There is no " 1" incrementing of the new script unless it matches the name of a non-script inventory item.

There is no maintaining of script memory.

Ah gotcha.

So the old script will be terminated, its resources released, and purged, right?

I don't have to do anything within the old script to do that?

21 hours ago, Lucia Nightfire said:

The permissions mentioned allow for success worn or rezzed as long as both giver and receiver objects are owned by the same person.

Wait, so Object B needs to be owned by user A as well?

So, it is not possible, say for an "update terminal" to perform the script update while A_HUD is being worn by user A?

Link to comment
Share on other sites

1 minute ago, primerib1 said:

So, it is not possible, say for an "update terminal" to perform the script update while A_HUD is being worn by user A?

Interesting question! The answer may explain why "in-world update locations" most often require you to "rez your item on the store counter to the update".  At least they used to..

  • Like 1
Link to comment
Share on other sites

11 minutes ago, Love Zhaoying said:

Interesting question! The answer may explain why "in-world update locations" most often require you to "rez your item on the store counter to the update".  At least they used to..

Well, I know that OpenCollar's updater needs to first be received (either through a giver in their HQ or just take out from the notice notecard), making the updater belongs to the wearer, and then rez in-world to perform update.

Probably because sometimes the wearer is unable to detach the OpenCollar due to the collar's lock status.

But that means person A in my scenario needs to first receive object B, and rez the object in-world, something that person A might not be able to do in my situation.

Oh well.

Link to comment
Share on other sites

2 minutes ago, primerib1 said:

Well, I know that OpenCollar's updater needs to first be received (either through a giver in their HQ or just take out from the notice notecard), making the updater belongs to the wearer, and then rez in-world to perform update.

Probably because sometimes the wearer is unable to detach the OpenCollar due to the collar's lock status.

But that means person A in my scenario needs to first receive object B, and rez the object in-world, something that person A might not be able to do in my situation.

Oh well.

Yeah, I was referring to update instructions for a favorite object.  The MP instructions say go to the in-world store and rez the item for updates.. but the MP store no longer exists. * sad face *  

Link to comment
Share on other sites

I believe in ancient history it was possible for a scripted item to update attachments worn by another owner, but that won't work anymore. I vaguely remember the then near-monopoly merchant of genitalia had to change the process so to get updates customers would have to go to the store and rez their, uh, items on a table to be updated.

Or maybe I just imagined the "put it on the table" part. It sounds now a bit like a bad dream, doesn't it?

Anyway, nowadays updaters are delivered so they're owned by the same agent as the product being updated.

  • Thanks 1
Link to comment
Share on other sites

23 minutes ago, primerib1 said:

Probably because sometimes the wearer is unable to detach the OpenCollar due to the collar's lock status.

Hmm. Now that you mention it, the collar my alt uses for testing at one point got an update that required it to be detached and rezzed next to the updater, even though I owned the updater. I remember the message claiming that it was something special it had to do, but I can't imagine what that would be.

Link to comment
Share on other sites

33 minutes ago, primerib1 said:

But that means person A in my scenario needs to first receive object B, and rez the object in-world, something that person A might not be able to do in my situation.

Not sure of the constraints here, but the updater (object B) could be worn, too, right? wouldn't need to be rezzed on land, I mean.

Link to comment
Share on other sites

27 minutes ago, Qie Niangao said:

Not sure of the constraints here, but the updater (object B) could be worn, too, right? wouldn't need to be rezzed on land, I mean.

Person A might not have access to their inventory so they can't rez/wear the Object B.

Though ... hmmmm ...

It might be possible to "force wear" Object B using RLV ...

Ahahah thanks for the idea!

Link to comment
Share on other sites

4 hours ago, primerib1 said:

"update terminal"

There are  (at least?) 3 ways of transferring ownership of an object to another avatar:

  1. give them the object with llGiveInventory(list)
  2. have them buy the object (perhaps for 0L$), perhaps with the option set to sell the in-world object and not a copy.
  3. temp-attach the object.

1. is viable if you 'give to RLV' BUT, auto-wearing a thing given that way has some timing issues (most viewers are set up to ask confirmation when receiving directly to #RLV, and there is no feedback to the script if/when that confirmation took place)

2. is what ~I would do, for an in-world terminal. rez a separate updater object that is set for sale for 0L$.

3. doesn't require the updated person to have touch allowed, and could be completely automatic with an experience. assuming some automatic communication of version number by the HUD.

ETA: llDetachFromAvatar() while an object is 'locked' with llOwnerSay("@detach=n"); (and having been granted the perms) ~should "update" the inventory so that crashes are less likely to destroy the update. (There's always the slight possibility SL decides to restore your avatar state to before the update. Nothing is 100% safe from bad things happening.)

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

57 minutes ago, Qie Niangao said:

Hmm. Now that you mention it, the collar my alt uses for testing at one point got an update that required it to be detached and rezzed next to the updater, even though I owned the updater. I remember the message claiming that it was something special it had to do, but I can't imagine what that would be.

I've seen both.  I think I had an update on one of the collar versions that needed the object rezzed because it was adding prims/links. That was sometime back though, so my memory is fuzzy. But the past few updates since have all been while it's been worn in place. 

  • Thanks 1
Link to comment
Share on other sites

On 3/3/2023 at 11:47 PM, Quistess Alpha said:

2. is what ~I would do, for an in-world terminal. rez a separate updater object that is set for sale for 0L$.

Unfortunately, if Vict-- I mean, Person A is not allowed to touch, I don't think they can also buy...

 

Eh, after some thoughts about this, I'll just use a "gift giver" and tell 'em to "update your HUD by clicking this thing and get the latest version when you're allowed touch".

Much too much effort to implement llRemoteLoadScriptPin() in my particular use case :P

 

But anyways, good discussion so far!

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

Clear thoughts first thing in the morning..

1. Assumption 1: Generally updaters have to be in the same region due to llSayTo() / llRegionSayTo() use to communicate between the updater and the item being updated. I can see this design decision being made for "at store updaters", where there will only and ever be 1 updater: it will always have the same UUID, which can be hard-coded into the client scripts (scripts that will do the updating in the HUDS).

2. News-to-Me: The need to "not be wearing the item" when updating. Possibly there's a different state running when attached, which doesn't include update functionality. If so, that would be by individual updater / script design. Assumption 2: this design decision may be made so a HUD item cannot be updated "during use".

 

Link to comment
Share on other sites

3 hours ago, Love Zhaoying said:

Assumption 2: this design decision may be made so a HUD item cannot be updated "during use".

Pre-LinksetData, transferring script-only configuration information was a major pain, and god-forbid something changed while the transfer was taking place.

4 hours ago, primerib1 said:

Eh, after some thoughts about this, I'll just use a "gift giver" and tell 'em to "update your HUD by clicking this thing and get the latest version when you're allowed touch".

Yeah, if the thing in question is just a HUD and doesn't need a lot of personal prim-fitting, you could just use llRegionSayTo communication to pass config info from old to new version if there is any.

  • Like 1
Link to comment
Share on other sites

Expanding on my point earlier with the "rez-at-store" update options, and why they probably used "llSayTo()"/"llRegionSayTo()":

- Having a "single" updater means you can embed its UUID in the child scripts.  Having the child objects only update "when rezzed" (vs. when attached) means, they would not always need to have a listener active for the updater's UUID.

- The alternative - not using a "single" updater - means that the updater and "client" would need to "negotiate" (is a valid updater there? is a valid client there?) and trade UUID's so they can communicate with each other. (Assuming one did not rez the other, of course, and pass its UUID / channel info, etc.) For this to work, the client and updater would need to either "always be listening", or have options where you can put them in the "get update" state (via a single-purpose "update script", etc.).

I had to figure out the second option recently for "save Object A's LSD data to Object B".  I wasn't thinking about the "remote update" scenarios at the time, but it's basically a similar / same use-case.

 

 

Link to comment
Share on other sites

18 minutes ago, Love Zhaoying said:

- The alternative - not using a "single" updater - means that the updater and "client" would need to "negotiate" (is a valid updater there? is a valid client there?) and trade UUID's so they can communicate with each other. (Assuming one did not rez the other, of course, and pass its UUID / channel info, etc.) For this to work, the client and updater would need to either "always be listening", or have options where you can put them in the "get update" state (via a single-purpose "update script", etc.).

I had planned on having the Updater object B to listen on a certain channel, waiting for the signal "tellme:XHUD_UPDATER" (sent from the HUD)

It will then respond via whisper "hereiam:XHUD_UPDATER|p=<randomnumber1>" to the HUD

The HUD will need to respond "confirm:XHUD_UPDATER|p=<randomnumber1>,p0=<randomnumber2>"

Then the object responds again "confirmed:XHUD_UPDATER|p0=<randomnumber2>"

Afterwards the HUD can check for update "hasupdate?|p=<HUD_version>"

And the Updater can either respond with "hasupdate|p=<HUD_version>,p0=0" or "hasupdate|p=<HUD_version>,p0=1,p1=<PIN>"

And so on.

  • Like 1
Link to comment
Share on other sites

4 minutes ago, Quistess Alpha said:

are the random numbers to disambiguate speakers/conversation pipes? why not use llRegionSayTo instead of whisper after the initial message?

For security / antigrief mostly.

Whisper is just for the handshake, to ensure that resident is actually nearby, not all the way across the region.

After the handshake, everything happens using llRegionSayTo().

  • Like 1
Link to comment
Share on other sites

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