Jump to content

problem with channels (I think) on HUD to change textures


Sylvia Wasp
 Share

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

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

Recommended Posts

in this case this solution:

integer CHANNEL_HUD = -32423652;
default
{
    state_entry()
    {
        llListen(CHANNEL_HUD, "", NULL_KEY, "");
    }
    listen( integer channel, string name, key id, string msg)
    {
        if(channel == CHANNEL_HUD)
        {
            string touchid = (string)llGetObjectDetails(id, [OBJECT_OWNER]);
            string ownerid = llGetOwner();
            if(ownerid == touchid)
            {
                //your script
            }
        }
    }
}

 

Edited by Runie Xue
Link to comment
Share on other sites

10 hours ago, Mollymews said:

i give some code examples as a FYI  about what key to channel is, why we use it, how it works, what the implications are, and how we might work around any concerns

the basic reason for using key to channel is so that a sender app and a receiver app can communicate on a known channel. While at the same time spreading app communications across a number of channels on an individual user basis, while also providing some crosstalk protection for two or more users who may be on the same region using our apps.  HUD >> Clothing/Body/Furniture being a typical case where this can happen

the first script walks thru key to channel, and comments on the what and whys



default
{
    state_entry()
    {      
        integer app_channel;
       
        app_channel = (integer)("0x"+(string)llGetOwner()) | 0x80000000;
        // the above code creates a channel number using the 1st 8 hexadecimal numerals
        // of the owner's avatar key: (integer)("0x"+(string)llGetOwner()
        // then uses OR 0x80000000 to convert this into a negative number
        
        // when this is used widely by different script apps then we can get a higher rate of our app
        // receiving understandable messages from other scripts owned by the same person, and scripts
        // owned by others that happen to use the same channel
        // which can result in our app acting on those messages when it shouldn't
        
        // we designate a unique id for our app. Each of our apps has it owns unique id

        integer app_id = 73245;      
        
        // we then XOR the channel with our appid, so that at least our apps owned by the same user 
        // will never crosstalk each other
        
        app_channel = (integer)("0x"+(string)llGetOwner()) ^ app_id | 0x80000000;
        
        // an issue with this as wrote is that we need to ensure that the result of this is not
        // equal to 0. 1 XOR 1 == 0;  When so then our app will communicate on the public channel 0.
        // to avoid this remote (but still possible) happening then we check for it      
        
        app_channel = (integer)("0x"+(string)llGetOwner());
        
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;
        
        // for this part to be safe then our unique app_ids need to be at least 2 values apart. 1, 3, 5, etc
        
        // this doesn't protect our app from two or more of our app users who might happen to have
        // the same first 8 hexadecimal numerals as each other  
        // for protection against this and from crosstalk from other creators apps then relying on the 
        // channel value all by itself is not a safe method. No matter what channel we choose then the
        // possibility of two or more independent scripts from two or more independent creators using 
        // the same channel remains.
        // the code so far only protects our app from our other apps owned by the same user
        
        // to protect from other creators and other users of our app then see the following example codes
        // in the post
    }
}

the next two scripts show example codes putting it all together, also adding in the protective checks for owner and creator


// sender

integer app_id = 73245;

integer app_channel;


default
{
    state_entry()
    {
        app_channel = (integer)("0x"+(string)llGetOwner());
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;
    }
    
    touch_start(integer total_number)
    {
        llRegionSay(app_channel, "Hello! how are you?");
    }
}

// receiver

integer app_id = 73245;

integer app_channel;


default
{
    state_entry()
    {
        app_channel = (integer)("0x"+(string)llGetOwner());
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;
       
        llListen(app_channel, "", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string msg)
    {
        // here we get the owner and the creator of the sender (msg received from)
        key msg_owner = llGetOwnerKey(id);
        key msg_creator = llList2Key(llGetObjectDetails(id, [OBJECT_CREATOR]), 0);
        
        // here we compare the owner and creator of the sender to the owner and creator of
        // the receiver 
        if ((msg_owner == llGetOwner()) && (msg_creator == llGetCreator()))
        {
           llSay(0, "Hi! I am good thank you");    
        }         
    }
}

another thing to consider.  The example receiver is listening for everything on the channel.  A thing that some creators do is to also filter the listener to a named hud object. An upside is that there is a tiny gain in performance.  The downside with a name filter is that we have to make the HUD No-Modify to prevent the user from renaming the HUD which would break the receiver app

Hey thanks for this.  Seriously, a lot of work and it will take me a while to digest.  

After being up most of the night with this I'm still sitting on my building platform trying to figure this out this morning and this will help a lot.  

After many hours of goofing around I finally got Key2Chan to work (I think) in the HUD itself, but my main problem now is that I can't see how a randomly generated channel in the HUD can be received by the mesh since using the same method there would presumably create a completely different random channel number.  

I realise that probably sounds insanely stupid to you scriptures, but it's a very logical hurdle to me, lol.  

I thought that making the listen in the mesh listen to *any* channel from the same ID would be the way but I can't seem to do that.  

Thanks for the suggestion about listening to messages from a specific HUD by name.  I already do that anyway because sometimes I use two HUDs for one product.  I put an automatic re-naming thing in the state entry so if the user renames the HUD then razzing it or resetting it will put the proper name back.  

Sylvia

Edit:   by "I got Key2Chan working"  I just mean that I took the cryptic junk given me and put it in the HUD script in a way it compiles without errors.  I still have no idea whether it's returning anything useful or how to use what it returns.

Edited by Sylvia Wasp
Link to comment
Share on other sites

7 hours ago, Runie Xue said:

Easy solution:

on this line:

llListen(app_channel, "", NULL_KEY, "");

change to this:

llListen(app_channel, "", llGetOwner(), "");

 

After this your script only hear your key and other people on same room not have any problem with that, also you can make more filters inside the event of listen but with this i think works fine.

Hey :)

Thanks for this, I thought of this late last night but I kept getting a script error when I tried it.  

I have no idea why as it seems like a logical thing to do.  I will try it again. 

Link to comment
Share on other sites

Okay, so after the helpful suggestions I *did* get (many thanks to Wolfie and Fennix!), here is what I have (so far) for a new HUD script.

I'm still not sure if Key2Chan is right or even doing anything though, lol.  And I have yet to find a way to get the mesh clothing to receive any messages from this HUD.

Also, not sure why I can't just say

llSay(cmdChannel, button);

instead of saying "button_01" twice.   But it does not compile.

//===== Texture Changing HUD - by Sylvia Wasp ===
//
//      installed in the root prim of a linkset
//      where the other prims are buttons named
//      "button_01", "button_02", etc.
//===============================================

integer cmdChannel;
string  HUD_Name = "Product HUD";

integer Key2Chan(key ID) 
{
    return 0x80000000 | (integer)("0x"+(string)ID);
}

default
{
    state_entry ()
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_NAME,HUD_Name]);
        cmdChannel = Key2Chan(llGetOwner());
    }

    touch_start(integer n)
    {
        string button = llGetLinkName(llDetectedLinkNumber(0));

        if(button == "button_01") {
            llSay(cmdChannel, "button_01" );
            }
        else if(button == "button_02") {
            llSay(cmdChannel, "button_02" );
            }
        else if(button == "button_03") {
            llSay(cmdChannel, "button_03" );
            }
        else if(button == "button_04") {
            llSay(cmdChannel, "button_04" );
            }
        else if(button == "button_05") {
            llSay(cmdChannel, "button_05" );
            }
        else if(button == "button_06") {
            llSay(cmdChannel, "button_06" );
            }
    }                
}

 

Edited by Sylvia Wasp
Link to comment
Share on other sites

27 minutes ago, Sylvia Wasp said:

Also, not sure why I can't just say


llSay(cmdChannel, button);

instead of saying "button_01" twice.   But it does not compile.

Assuming you're within the same scope as the button variable, I would think you should have no problem doing exactly that. The button variable is a string after all, so the following should work (and alleviate the need for that large if-then-else block entirely) :

string button = llGetLinkName(llDetectedLinkNumber(0));
llSay(cmdchannel, button);

If it's not compiling, what error are you seeing?

Additionally, I would again suggest you consider using llRegionSayTo instead of llSay. This makes the HUD speak directly to the target you specify and no one else. You can potentially avoid all the hassle with generating unique channels and instead rely on llRegionSayTo to target the avatar - which would in turn have all its attachments hear the command as per the description on the wiki page.

The corresponding listen handler in the attachments should have some filters to be safe, like only accepting messages form the name of the HUD object (as that would most likely remain constant). If you're still having problems with the relay, post a sample of the attachment's listener too.

Edited by Fenix Eldritch
Link to comment
Share on other sites

2 hours ago, Fenix Eldritch said:

Assuming you're within the same scope as the button variable, I would think you should have no problem doing exactly that. The button variable is a string after all, so the following should work (and alleviate the need for that large if-then-else block entirely) :


string button = llGetLinkName(llDetectedLinkNumber(0));
llSay(cmdchannel, button);

If it's not compiling, what error are you seeing?

Additionally, I would again suggest you consider using llRegionSayTo instead of llSay. This makes the HUD speak directly to the target you specify and no one else. You can potentially avoid all the hassle with generating unique channels and instead rely on llRegionSayTo to target the avatar - which would in turn have all its attachments hear the command as per the description on the wiki page.

The corresponding listen handler in the attachments should have some filters to be safe, like only accepting messages form the name of the HUD object (as that would most likely remain constant). If you're still having problems with the relay, post a sample of the attachment's listener too.

Thanks.  :) 

I will try this again and I will incorporate that change.  The reason I wasn't using llRegionSay is because based on the name, one would assume that it was going to spam the entire region, which I guess it does.  I thought I was being more specific with the llSay and the objects are usually only within a metre of each other anyway.  

The error on the button thing was just the (singularly unhelpful)  "syntax" error I think, which is to say "you did something wrong but it could be anywhere in the script", lol.   I even tried casting "button" specifically as a string (although I shouldn't have to I thought) and it still wouldn't do it. 

My listen handler in the mesh object is still completely deaf to this HUD though.  Assuming the Key2Chan stuff works, that is still the real problem.  I do already filter for the name of the HUD and NULL_KEY and empty string, so it's obviously the Channel argument that isn't working, (the cmdChannel in the example is not right obvs.) but I still can't get my head around what to put there.  

    state_entry ()
    {
        llListen(cmdChannel, "Product HUD", NULL_KEY, "");
    }

How can a listen in the mesh object, listen for a unique channel that's generated in the HUD?  

My only thought is to get the mesh to just listen to any and all channels the HUD might be communicating on but I have failed to find that method so far. I thought that simply putting "integer Channel" would get me what I want, but that wouldn't compile either and I'm really just guessing at this point. 

EDIT

I used llRegionSay as suggested but then that leads to why have the if and else if at all?

The new HUD script is even simpler: 

//===== Texture Changing HUD - by Sylvia Wasp ===
//
//      installed in the root prim of a linkset
//      where the other prims are buttons named
//      "button_01", "button_02", etc.
//===============================================

integer cmdChannel;
string  HUD_Name = "Product HUD";

integer Key2Chan(key ID) 
{
    return 0x80000000 | (integer)("0x"+(string)ID);
}

default
{
    state_entry ()
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_NAME,HUD_Name]);
        cmdChannel = Key2Chan(llGetOwner());
    }

    touch_start(integer n)
    {
        string button = llGetLinkName(llDetectedLinkNumber(0));
        llRegionSay(cmdChannel, button);
    }                
}

which makes me very happy :) 

however, the mesh still doesn't hear anything.  :( 

Sylvia

Edited by Sylvia Wasp
Link to comment
Share on other sites

28 minutes ago, Sylvia Wasp said:

The reason I wasn't using llRegionSay is because based on the name, one would assume that it was going to spam the entire region, which I guess it does.  I thought I was being more specific with the llSay and the objects are usually only within a metre of each other anyway.

That is correct. However, be careful to note that there are two similarly named functions: llRegionSay and llRegionSayTo, which do different things. llRegionSay will act like llSay, but for the whole region. llRegionSayTo will speak across the whole region as well, but is directed only to the target specified by uuid. No one else will hear it, even if they're listening on the same channel. I was advocating for the use of llRegionSayTo which will target a specific avatar or object. [wiki page]

You listener looks ok, so as you said, the remaining problem is getting the channels set up right. Getting to objects to communicate on a generated private channel can get complicated fast. One approach is to have both objects run the same code to generate the same number based off of a public value (like the owner's key).

However, the whole point in my suggestion to use llRegionSayTo was to avoid doing that altogether. By using llRegionSayTo, you can safely use the same command channel across all instances of this product. Because of the targeted nature of the communication, only the target will actually hear the message on the channel.

Try this in your HUD (pick a static cmcChannel number for this test and use the same in your listener) :

 llRegionSayTo( llGetOwner(), cmdChannel, button );

As mentioned previously, if you direct a message to an avatar via llRegionSayTo and use a non-zero channel, then the viewer won't display it in chat - but all of the avatar's worn attachments will be able to hear the message. With this, you can indirectly target your mesh attachments by supplying the uuid of the current owner, That will act as a per-avatar filter.

 

Edit: I just looked back at my previous post and noticed I typed out "cmdchannel" instead of "cmdChannel". That was a typo on my part and if you copied it from my post, could have been why you got your syntax error. The compiler would see that as some new undefined variable. Sorry!

Edited by Fenix Eldritch
Link to comment
Share on other sites

45 minutes ago, Fenix Eldritch said:

That is correct. However, be careful to note that there are two similarly named functions: llRegionSay and llRegionSayTo, which do different things. llRegionSay will act like llSay, but for the whole region. llRegionSayTo will speak across the whole region as well, but is directed only to the target specified by uuid. No one else will hear it, even if they're listening on the same channel. I was advocating for the use of llRegionSayTo which will target a specific avatar or object. [wiki page]

You listener looks ok, so as you said, the remaining problem is getting the channels set up right. Getting to objects to communicate on a generated private channel can get complicated fast. One approach is to have both objects run the same code to generate the same number based off of a public value (like the owner's key).

However, the whole point in my suggestion to use llRegionSayTo was to avoid doing that altogether. By using llRegionSayTo, you can safely use the same command channel across all instances of this product. Because of the targeted nature of the communication, only the target will actually hear the message on the channel.

Try this in your HUD (pick a static cmcChannel number for this test and use the same in your listener) :


 llRegionSayTo( llGetOwner(), cmdChannel, button );

As mentioned previously, if you direct a message to an avatar via llRegionSayTo and use a non-zero channel, then the viewer won't display it in chat - but all of the avatar's worn attachments will be able to hear the message. With this, you can indirectly target your mesh attachments by supplying the uuid of the current owner, That will act as a per-avatar filter.

 

Edit: I just looked back at my previous post and noticed I typed out "cmdchannel" instead of "cmdChannel". That was a typo on my part and if you copied it from my post, could have been why you got your syntax error. The compiler would see that as some new undefined variable. Sorry!

No problem.  Sorry I missed that.  I account for typing mistakes and I don't generally copy and paste.  I may not be the best scripter but I'm no dummy. :) 

Unfortunately, most scriptures I've met and talked to over the years assume that if you can't script you must just be stupid, when in fact it's a very specific skill.  Not everyone can paint a picture and not everyone can script (despite Apples' mantra that they can). 

Edited by Sylvia Wasp
Link to comment
Share on other sites

14 hours ago, Mollymews said:

i give some code examples as a FYI  about what key to channel is, why we use it, how it works, what the implications are, and how we might work around any concerns

the basic reason for using key to channel is so that a sender app and a receiver app can communicate on a known channel. While at the same time spreading app communications across a number of channels on an individual user basis, while also providing some crosstalk protection for two or more users who may be on the same region using our apps.  HUD >> Clothing/Body/Furniture being a typical case where this can happen

the first script walks thru key to channel, and comments on the what and whys

the next two scripts show example codes putting it all together, also adding in the protective checks for owner and creator

another thing to consider.  The example receiver is listening for everything on the channel.  A thing that some creators do is to also filter the listener to a named hud object. An upside is that there is a tiny gain in performance.  The downside with a name filter is that we have to make the HUD No-Modify to prevent the user from renaming the HUD which would break the receiver app

The more I read these scripts the more brilliant they seem. :) 

I had no idea that one could query the owner of the message sent from within the listen for instance, nor get the details on the owner of the object that sent them.  This is of course the actual answer to my problem.

wouldn't this bit though ... 

        app_channel = (integer)("0x"+(string)llGetOwner());
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;

mean that app_channel could be different on occasion between the sender and receiver (and thus the message fails)?  

It seems that you know what you're doing so I guess I'm almost certainly incorrect about that, but you'll have to excuse me as I'm still getting my head around it.  I find I have to rewrite a script (and sit with it for a week) before I completely "get it", lol.

Anyway thanks so much for all of this I think it will solve all. 

Sylvia :)  

Link to comment
Share on other sites

4 hours ago, Sylvia Wasp said:

How can a listen in the mesh object, listen for a unique channel that's generated in the HUD?

6 hours ago, Sylvia Wasp said:

After many hours of goofing around I finally got Key2Chan to work (I think) in the HUD itself, but my main problem now is that I can't see how a randomly generated channel in the HUD can be received by the mesh since using the same method there would presumably create a completely different random channel number.  

Here's a simple way to test things:

integer Key2Chan(key ID)
{
    return 0x80000000 | (integer)("0x"+(string)ID);
}

default
{
    touch_start(integer n)
    {
        integer number = Key2Chan(llGetOwner());
        llOwnerSay((string)number);
    }
}

Every time you touch the object this script is in, it's going to create that unique channel and show it in chat. You'll see that the unique channel is in fact the same one every time, even in separate objects. This is because it's not a random channel. It's just based on the owner's avatar key, making it mostly unique to each avatar because each avatar has a completely unique key.

But why "mostly unique?" Numbers in SL can also be expressed by up to 8 characters (in hexadecimal), but an avatar key is 36 characters long. It's technically possible that any 7-8 characters of an avatar's key that we use will be the same for two different avatars. (The first 8 in this case.)

For example, my avatar key is: 779e1d56-5500-4e22-940a-cd7b5adddbe0. The script above would pick this number: 0x779e1d56 which means 2006850902, combined with 0x80000000 (2147483648) it becomes -140632746 and that would be my channel. Understanding this math/process is tricky but unnecessary. What is important to understand is that this number is not random, it is entirely based on the input. Same input = Same result, always.

So you would use that same function in your HUD and your mesh. Your HUD would use the channel only to say things, while your mesh would use the channel only to listen.

2 hours ago, Sylvia Wasp said:

wouldn't this bit though ... mean that app_channel could be different  on occasion between the sender and receiver (and  thus the message fails)?

The same applies here. If the input is the same in both scripts, they will always choose the same channel. That additional app_id is there to adjust each of your products to talk on different channels. It's not necessary, but depending on what kind of messages your mesh expects, you might might accidentally affect other products from the same owner if they're all on the same channel and you aren't careful.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

9 hours ago, Sylvia Wasp said:

The more I read these scripts the more brilliant they seem. :) 

I had no idea that one could query the owner of the message sent from within the listen for instance, nor get the details on the owner of the object that sent them.  This is of course the actual answer to my problem.

wouldn't this bit though ... 


        app_channel = (integer)("0x"+(string)llGetOwner());
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;

mean that app_channel could be different on occasion between the sender and receiver (and thus the message fails)?  

 

as Wulfie explains when both scripts use the same input values and the same computation method then the result is the same for both scripts

i just say that nothing I have shown here in code is my invention, its all been done before by others. I am just documenting the methods and hopefully providing some helpful explanations of the what and whys

this said, and moving on in the discussion. 

as wrote, and as commented on by others in this discussion the receiver listen: llListen(app_channel, "", NULL_KEY, "") is bit well meh! yes

so we think ok, lets try llListen(app_channel, "My Unique Named HUD", NULL_KEY, "").  A bit better because we have narrowed the listen filter a bit

a question then is can we do better than this ?  As it turns out yes we can. Extending the receiver code:

// receiver

integer app_id = 73245;

integer app_channel;

integer comms_authenticated;
integer hnd_listener;

default
{
    state_entry()
    {
        app_channel = (integer)("0x"+(string)llGetOwner());
        if (app_channel == app_id) ++app_id;
        app_channel = app_channel ^ app_id | 0x80000000;
       
        comms_authenticated = FALSE;
        hnd_listener = llListen(app_channel, "", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string msg)
    {
        if (!comms_authenticated)
        {
           // here we get the owner and the creator of the sender (msg received from)
           key msg_owner = llGetOwnerKey(id);
           key msg_creator = llList2Key(llGetObjectDetails(id, [OBJECT_CREATOR]), 0);
        
           // here we compare the owner and creator of the sender to the owner and creator of
           // the receiver and authenticate them 
           if ((msg_owner == llGetOwner()) && (msg_creator == llGetCreator()))
           {
              // now that we have authenticated the sender, we now only listen for it
              llListenRemove(hnd_listener);
              hnd_listener = llListen(app_channel, "", id, ""); 
              comms_authenticated = TRUE;
           }
        }

        if (comms_authenticated)
        {
           // process the msg
           llSay(0, "Hi! I am good thank you);
        }
    }
}

what we have now done is a one-time authentication of the sender. So that we don't have to authenticate every message received, for a performance gain

which then leaves us with how can we have the sender use llRegionSayTo(), for even more performance gain

i am not going to code this bit up totally here.  I leave that as an exercise for the reader. I give a general description tho of a way how this can be done:

// in the authentication clause of the receiver script above
// we transmit the receiver key to the sender

llRegionSayTo(id, app_channel, (string)llGetKey());

// in the sender script there is a listen:

integer hnd_listener = llListen(app_channel, "", NULL_KEY, "");

// in the sender listen we authenticate the message the same way:  msg_owner and msg_creator

// the sender now has the receiver key

key receiver_id = (key)msg;  comms_authenticated = TRUE;

// thereafter in the sender 

if (comms_authenticated)
    llRegionSayTo(receiver_id, app_channel, msg);
else
    llRegionSay(app_channel, msg);

// remove the sender listen if not needed beyond authentication

 

edit add:  When doing this then we need to ensure that our comms_authentication doesn't give a false positive in some situations (rez and attach for example).  So in the rez and attach/detach event we typically set the comms_authentication flags to FALSE and re-establish our non-authenticated listeners

 

Edited by Mollymews
Link to comment
Share on other sites

OK, so I actually think I'm understanding this and I have two different sets of working scripts which is certainly progress!

Here is a working set of HUD script and mesh script a la 'Wolfie" (if I understand everything correctly)

HUD: 

//===== Texture Changing HUD - by Sylvia Wasp =====
//      installed in the root prim of a linkset
//      where the other prims are *named* buttons
//=================================================

integer cmdChannel;
string  HUD_Name = "Product HUD";

integer Key2Chan(key ID) 
{
    return 0x80000000 | (integer)("0x"+(string)ID);
}

default
{
    state_entry ()
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_NAME,HUD_Name]);
        cmdChannel = Key2Chan(llGetOwner());
    }

    touch_start(integer n)
    {
        string button = llGetLinkName(llDetectedLinkNumber(0));
        llRegionSayTo(llGetOwner(),cmdChannel, button);
        llSay(cmdChannel, button);                      // delete when testing complete
    }                
}

Mesh:

//===== Texture Changer (Mesh) - by Sylvia Wasp ========
//      installed in an item of mesh clothing,
//      receives messages from "Texture Changing HUD"   
//======================================================

integer     cmdChannel;

key         texture_01 = "36e9d64c-3f58-92d1-b2d1-807ddc996558";    
key         texture_02 = "1db31c0c-622a-d120-23dd-52519592d253";
key         texture_03 = "614544ae-4bdf-c8d6-2cb3-0115a990943b";    
key         texture_04 = "06943dd0-0216-16c7-83de-4f40c6185106";
key         texture_05 = "33a2a763-dae0-e4b9-d908-b56d9c50fb47";    
key         texture_06 = "bfba4c48-cea2-3523-b62d-52beafcb3a77";

integer Key2Chan(key ID) 
{
    return 0x80000000 | (integer)("0x"+(string)ID);
}

default
{
    state_entry ()
    {
        cmdChannel = Key2Chan(llGetOwner());
        llListen(cmdChannel, "Product HUD", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string message) 
    {
        if (message == "button_01" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_01, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_02") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_02, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        if (message == "button_03" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_03, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_04") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_04, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        if (message == "button_05" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_05, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_06") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_06, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
    }
} 

I've added an extraneous llSay to the HUD part because when I'm testing a new dress the mesh isn't actually being worn by me and therefore llRegionSayTo fails on the basis of it not being attached. 

Here is my version of the same thing using Molly's advice instead.

HUD:

//===== Texture Changing HUD - by Sylvia Wasp =====
//      installed in the root prim of a linkset
//      where the other prims are *named* buttons
//=================================================

integer     cmdChannel;
integer     app_id = 73245;
string      HUD_Name = "Product HUD";

default
{
    state_entry ()
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_NAME,HUD_Name]);
        cmdChannel = (integer)("0x"+(string)llGetOwner());
        if (cmdChannel == app_id) ++app_id;
        cmdChannel = cmdChannel ^ app_id | 0x80000000;
    }

    touch_start(integer n)
    {
        string button = llGetLinkName(llDetectedLinkNumber(0));
        llRegionSayTo(llGetOwner(),cmdChannel, button);
        llSay(cmdChannel, button);                      // delete when done
    }                
}

Mesh:

//===== Texture Changer (Mesh) - by Sylvia Wasp ========
//      installed in an item of mesh clothing,
//      receives messages from "Texture Changing HUD"   
//======================================================

integer     cmdChannel;
integer     app_id = 73245;

key         texture_01 = "36e9d64c-3f58-92d1-b2d1-807ddc996558";    
key         texture_02 = "1db31c0c-622a-d120-23dd-52519592d253";
key         texture_03 = "614544ae-4bdf-c8d6-2cb3-0115a990943b";    
key         texture_04 = "06943dd0-0216-16c7-83de-4f40c6185106";
key         texture_05 = "33a2a763-dae0-e4b9-d908-b56d9c50fb47";    
key         texture_06 = "bfba4c48-cea2-3523-b62d-52beafcb3a77";

default
{
    state_entry ()
    {
        cmdChannel = (integer)("0x"+(string)llGetOwner());
        if (cmdChannel == app_id) ++app_id;
            cmdChannel = cmdChannel ^ app_id | 0x80000000;
            
        llListen(cmdChannel, "Product HUD", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string message) 
    {
        key msg_owner = llGetOwnerKey(id);
        key msg_creator = llList2Key(llGetObjectDetails(id, [OBJECT_CREATOR]), 0);
        
        if ((msg_owner == llGetOwner()) && (msg_creator == llGetCreator())) {
           llOwnerSay("Hi! I am good thank you");    
            }         

        if (message == "button_01" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_01, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_02") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_02, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        if (message == "button_03" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_03, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_04") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_04, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        if (message == "button_05" ) {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_05, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
        else if (message == "button_06") {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[ PRIM_TEXTURE, ALL_SIDES, texture_06, <1.0, 1.0, 1.0>,ZERO_VECTOR, 0.0 ]);
            }
    }
} 

The only thing I'm concerned about is that the message owner and creator comparison check in the Mesh part seems to fail, but perhaps that is because I didn't actually create the mesh?  

Please point out my "mistakes" (I won't get mad) :o 

Sylvia

Edit: I just saw your other advice (too late!).  

You are suggesting to create a sort of second custom listen and removing the first one?  Makes it more private and secure I suppose?  

I will try to incorporate but perhaps we are entering into overkill territory again? Also if my Owner/Creator check is going to fail, then it won't work for this situation, no?   

Thanks again, 

Sylvia :) 

 

Edited by Sylvia Wasp
Link to comment
Share on other sites

9 minutes ago, Sylvia Wasp said:

OK, so I actually think I'm understanding this and I have two different sets of working scripts which is certainly progress!

The only thing I'm concerned about is that the message owner and creator comparison check in the Mesh part seems to fail, but perhaps that is because I didn't actually create the mesh?  
 

good on you!  yes you are making progress and well done!

about the mesh made by some one else. What you have observed is exactly correct

the recommended advice when using a mesh template / mesh parts made by another person in our product,  is to link the mesh to a root prim of our own creation. So that our users will see our name as the creator of our product. We do this in the main so that our users don't contact the mesh template creator for support for our product. Is the bane of template creators lives when this happens

and when we do this, our scripts being in the root prim will recognize us as the creator of our product

Link to comment
Share on other sites

30 minutes ago, Mollymews said:

the recommended advice when using a mesh template / mesh parts made by another person in our product,  is to link the mesh to a root prim of our own creation. So that our users will see our name as the creator of our product.

...

and when we do this, our scripts being in the root prim will recognize us as the creator of our product

Well, this is exactly what I do of course.  I have my own "label" that I use as a root prim on all the clothes I make. 

But I've been putting the texture changing script in the mesh itself rather than the root, since the mesh is the thing that's having it's texture changed.  I suppose this is bad practice as well?  

I imagine I could probably put it in the root and just change the LINK_THIS in the llSetLinkPrimitiveParamsFast to "1" though.  It just seemed more sensible at the time to put it in the mesh rather than figure out which link was which all the time, but perhaps not.  Most of the time it's just going to be the mesh and the label in the same relationship to each other.  

Link to comment
Share on other sites

23 minutes ago, Sylvia Wasp said:

But I've been putting the texture changing script in the mesh itself rather than the root, since the mesh is the thing that's having it's texture changed.  I suppose this is bad practice as well?  

I imagine I could probably put it in the root and just change the LINK_THIS in the llSetLinkPrimitiveParamsFast to "1" though

we have to weigh all these things up. There is no absolutely true way to do things.  There are just general guidelines that we adapt too, depending on what we are wanting to achieve and the specifics of each situation

in the specific case of a mesh template made by someone else.  If we want to authenticate messages received from a HUD, then the authentication has to go in our own root prim. So yes as a general guideline in this instance we use LINK 1 for efficiency and performance

as if we don't then we would need 2 scripts. One in the root prim for authentication and a second script in the linked mesh to do the applying. Then we would need a way for the scripts to communicate using linkmessage. This adds an extra level of complication and work. A general guideline is to try to keep things as simple as best we can, and try keep our resource usage to as low as we can

Edited by Mollymews
incomplete
Link to comment
Share on other sites

1 minute ago, Mollymews said:

we have to weigh all these things up. There is absolutely true way to do things.  There are just general guidelines that we adapt too, depending on what we are wanting to achieve and the specifics of each situation

in the specifc case of a mesh template made by someone else.  If we want to authenticate messages received from a HUD, then the authentication has to go in our own root prim. So yes  we use LINK 1 for efficiency and performance. If we don't then we would need 2 scripts. One in the root for authentication and a second script in the mesh to do the applying. Then we would need a way for the scripts to communicate using linkmessage. This adds an extrs level of complication and work 

Right.  

Well, I think I know what to do now. Tomorrow I have to derive a final script from all the advice.  I will use your app_id concept, except I will call it productID as that makes more sense for my use (I don't and never will create "apps" lol).  

I will probably move the script to the root and I might use the listen handler thingie too, but maybe not since my usage is again so simple.  

For tonight ... shopping! :) 

Thanks again for all the advice (and to all the others that answered this thread as well).  I'm sure that many people besides myself will find it useful. 

Sylvia

  • Like 3
Link to comment
Share on other sites

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