Using UUID to code a channel
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-10-2008 04:22
Hi, I want to code items so that they work out the channel they use by using the UUID to create an integer for a channel number. I tried the llBase64toInteger but I gave me a zero, probably too big a number, so if I convert it to a sting is there a left or right 4 character function somewhere, I haven't found one in the wiki,
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
08-10-2008 04:47
Keys are currently implemented as strings, meaning you can actually just do the following: key k = (key)((string)channel); // Encode as key integer channel = (integer)((string)k); // Decode as integer
However, it's very bad practise to pass variables around within a key using the assumption that they will forever be implemented as strings. A key is in fact a 128-bit integer, however, for some reason LL decided to store this in its string representation (hyphen separated hexadecimal).
Can I ask why you specifically need this variable to be passed as a key? And why do you need to move characters left or right? To do that to a string you can do: string str = "----" + (string)channel; // Shift right string str = (string)channel + "----"; // Shift left
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-10-2008 05:16
From: Haravikk Mistral Keys are currently implemented as strings, meaning you can actually just do the following: key k = (key)((string)channel); // Encode as key integer channel = (integer)((string)k); // Decode as integer
However, it's very bad practise to pass variables around within a key using the assumption that they will forever be implemented as strings. A key is in fact a 128-bit integer, however, for some reason LL decided to store this in its string representation (hyphen separated hexadecimal).
Can I ask why you specifically need this variable to be passed as a key? And why do you need to move characters left or right? To do that to a string you can do: string str = "----" + (string)channel; // Shift right string str = (string)channel + "----"; // Shift left Well when my HUD and armor are worn they need to pick a channe but I need a different channel for each owner, so I thought getting that channel derived from the avatars UUID would be the best way. I didn't want to move characters, just grab 4or6 digits from the left or right, would give me a number I can use for a channel. There used to be a function in Basic called Left$(n) where you would get the leftmost n letters of the string.
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|
|
Innula Zenovka
Registered User
Join date: 20 Jun 2007
Posts: 1,825
|
08-10-2008 06:54
From: Tegg Bode Well when my HUD and armor are worn they need to pick a channe but I need a different channel for each owner, so I thought getting that channel derived from the avatars UUID would be the best way. I didn't want to move characters, just grab 4or6 digits from the left or right, would give me a number I can use for a channel. There used to be a function in Basic called Left$(n) where you would get the leftmost n letters of the string. If I've correctly understood you -- you don't want your HUD and armour to listen to your friend's commands and vice versa -- what about default integer MyChannel = -123456 // change this for another long negative number -- I use phone numbers with a minus sign { state_entry() { // listen on MyChannel for any chat spoken by the object owner. llListen(MyChannel,"",llGetOwner(),""); } listen(integer channel, string name, key id, string message) { if (llToLower(message) == "boo") //llToLower so we're not sensitive to case //do stuff } } That way you're sure the devices will listen only to their respective owners, even if two owners happen to be using the same channel. Afterthought: This works if you're sending the message by means of llDialog; that is, if you have an object containing something like default { touch_start(integer total_number) { llDialog(llDetectedKey(0),"Click here to send a message",["boo","hiss"], -12345); } }
It won't work the object itself says something. If you must have an object saying it rather than llDialog, then something like, default {
touch_start(integer total_number) { if (llDetectedKey(0)==llGetOwner()) llSay(-12345, (string)llGetOwner()+"boo"); } }
and default { state_entry() { llListen(-12345,"",NULL_KEY,""); }
listen(integer channel, string name, key id, string message) { if (llDeleteSubString(message, 36,-1) == (string)llGetOwner()&&llDeleteSubString(message,0,35) =="boo" ) { // llDoSomething() } } }
should work.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
08-10-2008 11:08
From your case it sounds like you should really follow Innula's example (use llGetOwner() in your listens), or, if you need objects owned by the same person to listen to each other, then see the example at the very end of this post. However, for a purely theoretical exercise, you could use the last part of the avatar's key to get a channel by doing this: integer channel = (integer)("0x" + llGetSubString((string)llGetOwner(), -8, -1)); Keys are formatted like this; 00000000-0000-0000-0000-000000000000 They do however use hexadecimal numbering, which you can use to represent an integer of any length. Basically in hexadecimal each character is one byte, so for a 32-bit integer (like a channel) you need 8 hexadecimal character to get an integer. LSL will parse hexadecimal numbers, but requires the "0x" at the front so it knows what it's parsing. The hexadecimal for zero as a 32-bit integer is therefore; 0x00000000. The chunk of the key you use is up to you, but I believe the end part typically has the best distribution of values to use. Also, make sure you handle results of zero, either by setting it to a default non-zero channel, or trying another chunk of the key. If both come back with a channel of zero then you're almost certainly looking at a result of NULL_KEY which is invalid anyway. However, since a UUID allows for potentially 2 ^ 128 possible avatars, and you can only have 2 ^ 32 possible channels, then it's possible for there to be collisions (where two avatars have the same key). Your best bet here is to just make sure you either specify llGetOwner() when creating the listen, or in the listen event you do something like: listen(integer channel, string name, key id, string msg) { if (llGetOwnerKey(id) == llGetOwner()) // Handle message }If you want objects to only respond to other objects owned by the same person.
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
08-10-2008 18:24
From: Haravikk Mistral However, for a purely theoretical exercise, you could use the last part of the avatar's key to get a channel by doing this: integer channel = (integer)("0x" + llGetSubString((string)llGetOwner(), -8, -1)); Two specific values you want to avoid, however, are 0 (for obvious reasons), and DEBUG_CHANNEL (0x7FFFFFFF, the highest positive 32-bit integer value). Forcing the value to be negative by ORing it with 0x80000000 will prevent both. From: someone Basically in hexadecimal each character is one byte Close... each hex char is 4bits, ergo 2 chars == 1 byte. 
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-11-2008 00:07
Doh, yep the llGetOwner makes more sense, less likely to get other stuff on same channel causing problems  So if I do the following it will only functon when the "msg" is from the prim called "ACU" worn by owner? state_entry() { llListen(7777,"ACU",llGetOwner(),""  ; } listen(integer chan,string name,key id,string msg) { command =(integer)msg; And on the transmit end I just use LLWhisper (7777,(string)command) Hmm It's not working if I replace Owner with "" it works ok :/ It seems I can either listen to the ACU or Owner, not the owners ACU, if I set it to ACU, it may liasten to anybodies ACU, unless I broadcast the owners name first from the ACU so it knows which ACU UUID to listen to
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
08-11-2008 02:21
You don't want to filter by llGetOwner, because they're not listening for messages from the av, but from objects *owned by* the av. So you can't pre-filter the messages for the owner's key when establishing the listen, you have to filter them inside the listen event handler, as Haravikk describes above.
You *could* filter for the key of the other object, but since these are both attachments, the keys for each will change every time they're re-attached (including relogging), so post-filtering for a common owner is far less trouble, if a tad more laggy.
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-11-2008 02:39
From: Innula Zenovka If I've correctly understood you -- you don't want your HUD and armour to listen to your friend's commands and vice versa -- what about default integer MyChannel = -123456 // change this for another long negative number -- I use phone numbers with a minus sign { state_entry() { // listen on MyChannel for any chat spoken by the object owner. llListen(MyChannel,"",llGetOwner(),""); } listen(integer channel, string name, key id, string message) { if (llToLower(message) == "boo") //llToLower so we're not sensitive to case //do stuff } } That way you're sure the devices will listen only to their respective owners, even if two owners happen to be using the same channel. Hmm problem is I don't want the devices to listen to their owners chat commands, just the HUD the owner is wearing or does the HUD count as being the owner if it's worn by the owner?
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-11-2008 02:42
From: Deanna Trollop You don't want to filter by llGetOwner, because they're not listening for messages from the av, but from objects *owned by* the av. So you can't pre-filter the messages for the owner's key when establishing the listen, you have to filter them inside the listen event handler, as Haravikk describes above.
You *could* filter for the key of the other object, but since these are both attachments, the keys for each will change every time they're re-attached (including relogging), so post-filtering for a common owner is far less trouble, if a tad more laggy. Hmm thanks, I didn't realise UUID's on attachments changed. Ahhh I think I understand now, I have to ad the owners UUID to the beginning of the message 
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
08-11-2008 03:08
From: Tegg Bode Ahhh I think I understand now, I have to ad the owners UUID to the beginning of the message  No, you don't. llGetOwnerKey returns the UUID of the owner of the object identified by the key passed to it. A speaking object's UUID is passed to the listen event handler, hence you can determine who its owner is without including that information in the message itself. As I said, see the code snippet Haravikk posted at the end of his last message above.
|
|
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
|
08-11-2008 03:31
Hashing an avatar key into a channel number IS a good idea even if there is some chance of collision, and even if you still (recommended) filter by owner or other criteria in your code. Why? For one thing because the simulator first tests for listeners on the same channel as the speaking avatar or object. So using a random or pseudo-randomly distributed channel number is a good thing when you can get away with it. Here is the logic I often use to do this: integer stringToNegativeChannel(string str) { string hash = llMD5String(str, 0); int num1 = (integer)("0x"+llGetSubString(hash, 0, 7)); int num2 = (integer)("0x"+llGetSubString(hash, 8, 15)); int num3 = (integer)("0x"+llGetSubString(hash, 16, 23)); int num4 = (integer)("0x"+llGetSubString(hash, 24, 31));
return 0x80000000 | (num1 ^ num2 ^ num3 ^ num4); }
Note that the use of an MD5 hash actually means you can use ANY string, not just a UUID (prim/object name/description, parcel name/description, etc.). It also conveniently produces a 32 character hex result with no dash (-) characters. EDIT: Added second integer parameter to llMD5String() call. May still not compile without a minor syntax fix or two, but it's closer.
|
|
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
|
08-11-2008 05:49
From: Deanna Trollop Close... each hex char is 4bits, ergo 2 chars == 1 byte.  Okay, I can't count, I do know that really, honest =) As Deanna points out though Tegg, you want the snippet I had at the end of my last post, you'll want something like this set-up: default { state_entry() { llListen(channel, "", NULL_KEY, ""); }
listen(integer x, string name, key id, string msg) { if (llGetOwnerKey(id) == llGetOwner()) // If this is true then whoever or whatever sent the message has the // same owner as the object the script is in } }Basically; llGetOwnerKey(id) finds out the owner of an object, and will work even if the command comes from an avatar (since avatars "own" themselves). This way you can test to see if the owners are the same and behave accordingly. To generate channel though I'd probably go with Hewee's suggestion, while it's only really a concern if lots of your products are in the same place at once (thus using the same channel), it's good practise to avoid channel collisions wherever they may be found =)
_____________________
Computer (Mac Pro): 2 x Quad Core 3.2ghz Xeon 10gb DDR2 800mhz FB-DIMMS 4 x 750gb, 32mb cache hard-drives (RAID-0/striped) NVidia GeForce 8800GT (512mb)
|
|
Imaze Rhiano
Registered User
Join date: 27 Dec 2007
Posts: 39
|
08-11-2008 07:35
// Simple DJBHash function that hashes id to channel number. integer KeyToChannel(key id) { string str = (string) id; integer channel = 5381; integer i; for( i = 35 ; i >= 0 ; i-- ) { channel = ( ( channel << 5 ) + channel ) + llSubStringIndex( " -0123456789abcdef", llGetSubString(str, i, i) ); } if( channel == DEBUG_CHANNEL || ( channel >= -100000 && channel<= 100000 ) ) // Don't allow auto generated channels between -100 000 and 100 000 - or debug channel // Reserve them for other purposes (like llDialog) channel = channel + 200001; return channel; } integer g_channelHandle; integer g_channel; default { state_entry() { g_channel = KeyToChannel( llGetOwner() ); g_channelHandle = llListen( g_channel, "", NULL_KEY, "" ); } }
|
|
Tegg Bode
FrootLoop Roo Overlord
Join date: 12 Jan 2007
Posts: 5,707
|
08-12-2008 01:54
From: Haravikk Mistral Okay, I can't count, I do know that really, honest =) As Deanna points out though Tegg, you want the snippet I had at the end of my last post, you'll want something like this set-up: default { state_entry() { llListen(channel, "", NULL_KEY, ""); }
listen(integer x, string name, key id, string msg) { if (llGetOwnerKey(id) == llGetOwner()) // If this is true then whoever or whatever sent the message has the // same owner as the object the script is in } }Basically; llGetOwnerKey(id) finds out the owner of an object, and will work even if the command comes from an avatar (since avatars "own" themselves). This way you can test to see if the owners are the same and behave accordingly. To generate channel though I'd probably go with Hewee's suggestion, while it's only really a concern if lots of your products are in the same place at once (thus using the same channel), it's good practise to avoid channel collisions wherever they may be found =) WOOOT! That worked and was a cool explanation too , cool thanks to all of you for your patience and help, I probably haven't sold enough of them yet to need UUID coding with too many in the sim together yet (ie, got to finish the first one yet  ) but maybe one day it might be handy 
_____________________
Level 38 Builder [Roo Clan]
Free Waterside & Roadside Vehicle Rez Platform, Desire (88, 17, 107)
Avatars & Roadside Seaview shops and vendorspace for rent, $2.00/prim/week, Desire (175,48,107)
|