Jump to content

Check if payment information is on file


Guest
 Share

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

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

Recommended Posts

I wanted make a script that checks on touch if an avatar has payment information on file or used. I have written this very simple snippet:

key owner_payment_query;

default
{
   
    touch_start(integer total_number)
    {
        
       owner_payment_query =  llRequestAgentData(llDetectedKey(0),DATA_PAYINFO);
    }
      dataserver(key queryid, string data)
    {
        if ( owner_payment_query == queryid )
        
            llSay(0,data);
            
    }
}

The LSL Wiki for llRequestAgentData says that DATA_PAYINFO returns either 0x1 for PAYMENT_INFO_ON_FILE and 0x2 for PAYMENT_INFO_USED . When I look into my profile it says "Payment info used". So I would expect the dataserver event to return "0x2" or "2". But it returns a "3"?

 

Link to comment
Share on other sites

Since all you're interested in is whether payment info is on file, you only care about that second bit.  So you test for

if ( (integer)data & 2) ) { // PIOF is there }

in the dataserver event and then pass that information wherever you were going to use it.

Link to comment
Share on other sites

It's time to learn binary, Estelle! (forgive me if you already know it and are having difficulty with some other aspect of the problem here).

Wikipedia does a pretty good job of introducing binary here...

https://en.wikipedia.org/wiki/Binary_number

I'm sure you've heard of binary as a true/false or yes/no system of logic, where each yes/no is represented by a single binary bit. As Rhonda explained, the Yes/No (1/0) answers to PAYMENT_INFO_ON_FILE and PAYMENT_INFO_USED are binary bits. To avoid the need to fire a query for every Yes/No thing there is to know about something, llRequestAgentData() packs multiple Yes/No answers into a single returned variable. Your job is to separate them again.

The 0x prefixes on the constant values for PAYMENT_INFO_ON_FILE and PAYMENT_INFO_USED  are the hints that the values are bits. 0x means hexadecimal, which is base 16, a convenient way to represent the value of four binary (base two) bits. Like decimal digits, each bit needs its own position, so ON_FILE gets position 1 and USED gets position 2. If there were a third Yes/No thing to know, it would get bit position 3. In decimal, this would be like giving ON_FILE the ones digit, USED the tens digit and the third thing the hundreds digit. If you then wanted to separate the three things, you'd look at only one digit at a time. That's called masking, and we're doing it in binary here. In binary, rather than ones, tens, hundreds, thousands etc, we have ones, twos, fours and eights, etc.

If the avatar has only PAYMENT_INFO_ON_FILE you'll get 1 in the ones digit, if the avatar has used that payment info, you'll also get one in the twos digit. As Rhonda showed, that would read, in binary, as 11. A binary number that has a one in the ones digit and a one in the twos digit totals three, just as a decimal number with a one in the ones digit and a one in the tens digit totals eleven. (Are ya confused?!)

I don't know if there's a situation in which someone could have used their payment info without having it on file, but that seems wrong. So, if you ask for payment info, it seems the only values you'd get back are...

0 - no PIOF on file, and haven't used it

1 - PIOF on file, haven't used it

3 - PIOF on file, have used it

If you're only interested in PIOF, then 0 means they don't have it and anything else means they do.

If you want to test each thing separately, then you'll have to mask away the bits you don't want, and you do that with "&" (and). Convert the string value returned by the dataserver to an integer and then "&" it with the mask for the desired bit.

To test PAYMENT_INFO_ON_FILE you'd write:

if(   (integer)data & PAYMENT_INFO_ON_FILE){}

To test PAYMENT_INFO_USED, you'd write:

if(   (integer)data & PAYMENT_INFO_USED){}

The result of each test will be zero if the answer is no and the mask value if the answer is yes. Since if() tests only for zero or nonzero, the mask values are unimportant, anything nonzero is... not zero!

If that doesn't confuse you, I'll try harder.

;-).

  • Like 1
Link to comment
Share on other sites

Thank you very much, everyone, for your answers. It helps me to understand the process. Fortunately I enjoyed "numbering systems" at Maths and it is quite clear to me how it works. I have also used such bit masks in the past, for example when checking for permissions. However I have always been copy and pasting existing code examples, incorporating them in my code.

For the payment info, I could not find any such example in the wiki or the forums. It should have been more obvious to me that I do the same thing as in the run_time_permissions event, only in the dataserver event.

Now the way forward in my script is clear to me. However, I would still ask for some clarification on the principle.

(1) I would have expected that the "data" I receive in the dataserver event would result in the bit mask that I can then work with. But the string (or integer?) only contains one digit, in my personal case the "3". What's even more confusing: In the data table for llRequestAgentData, "3" is the integer constant for DATA_BORN. If you look at my script snippet in my first post, you see that I have never asked for DATA_BORN. So what the heck does this "3" mean and in what relation is it to the bit mask? (EDIT: Or is it a hexadecimal translation of the bit mask. Madelaine seems to suggest it, but it's not clear to me.)

(2) My understanding is now that the bit mask cannot be printed out by the script? I can only check with an if clause, which bit mask was returned, but it's not a data value that I can "play" with?

(3) I do not understand why Rollig's if ( (integer)data & 2) ) is the same as Madelaine's if(   (integer)data & PAYMENT_INFO_USED) . In the Wiki for PAYMENT_INFO_USED it is said that the integer constant for it is "0x2" and not "2". So I would have expected Rollig's version to be if ( (integer)data & 0x2) ).

As I have written above, I would be able to get the script working, but I'd like to also understand what is actually happening under the hood. It's good to know which switch to press to put on the light. It's even better to know why the lamp is glowing...

 

Link to comment
Share on other sites

My granddaughter has a toy that is the 2-year-old's version of a matching game.  It's a box with three holes shaped like a square, a circle, and a triangle.  All she has to do is drop the right block through a hole.  Each hole in the box is a mask.  She's testing her blocks with it.  (And occasionally a toy car.)

That's all you're doing too.  The result from llRequestAgentData is a mask that you use to see whether a specific value matches.  The only mildly tricky part is that your mask admits more than one correct answer, but then so does my granddaughter's toy.  She can get a ball to fit through the same hole that a cylinder does, so that hole is really a mask for roundness.

Try this script ...

key gQuery;default{    touch_start(integer total_number)    {        gQuery = llRequestAgentData(llDetectedKey(0),DATA_PAYINFO);    }        dataserver(key id, string data)    {        if (id == gQuery)        {            llSay(0,data);            llSay(0, (string)((integer)data & PAYMENT_INFO_USED));            llSay(0, (string)((integer)data & 0x2));            llSay(0, (string)((integer)data & 2));            if ((integer)data & 2)            {                llSay(0,"Payment Information used.");            }        }    }}

The result you get should be a "3" for the first llSay line because you have both PAYMENT_INFO_USED and PAYMENT_INFO_ON_FILE .  The next three llSay statements should each tell you "2", which is to say "When I try to stuff PAYMENT_INFO_USED or 0x2 or 2 through the value data (011), I get a match that's the same as the second hole -- 011"  All three blocks are equivalent, so they all pass through that hole. The final llSay statement says "Payment information used" because the thing that I tried to stuff through the hole made it.  I could have also tested with

if (((integer)data & 2) == 2)

 What you are asking in each case is to compare the result, 011, bitwise with anything you toss at it. If you toss anything that looks like a "2" at it, the second "1" in 011 will match.  PAYMENT_INFO_USED and 0x2 and 2 all work because they are all ways of saying 010.

Edited a couple of times for clarity. :smileywink:

Link to comment
Share on other sites


Estelle Pienaar wrote:

Thank you very much, everyone, for your answers. It helps me to understand the process. Fortunately I enjoyed "numbering systems" at Maths and it is quite clear to me how it works. I have also used such bit masks in the past, for example when checking for permissions. However I have always been copy and pasting existing code examples, incorporating them in my code.

For the payment info, I could not find any such example in the wiki or the forums. It should have been more obvious to me that I do the same thing as in the run_time_permissions event, only in the dataserver event.

Now the way forward in my script is clear to me. However, I would still ask for some clarification on the principle.

(1) I would have expected that the "data" I receive in the dataserver event would result in the bit mask that I can then work with. But the string (or integer?)
only contains one digit, in my personal case the "3".

 

There's your problem, Estelle. You're still thinking in decimal. The computer is thinking in binary. In binary, the decimal number "3" requires two digits. A binary digit can only represent zero and one. A decimal digit can represent 0-9. In decimal, if you want to represent a number larger than 9, you need more digits. In binary, if you want to represent a number greater than 1, you need more digits (bits).

Here are the available values for a single digit in three different number bases.

Decimal: 0,1,2,3,4,5,6,7,8,9

Hex: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

Binary: 0,1

 

LSL understands only decimal (base 10) and hexadecimal (hex is six, hexadecimal is 16, so base 16) numbers. To differentiate, hex(adecimal) numbers must be prefixed with "0x" (x rhymes with hex). But the computer is always working in binary. For the sake of clarity (something we nefarious usually avoid), I'll use "0d" to indicate decimal and "0b" to indicate binary.

From the LSL documentation, PAYMENT_INFO_ON_FILE = 0x1. We can count that high in all three base systems, so...

0x1 = 0d1 = 0b1.

From the LSL documentation, PAYMENT_INFO_USED = 0x2. We can count that high in decimal and hex, but not binary, so...

0x2 = 0d2 = 0b?

Now we gotta think. In decimal, as we step left through the digits of a number, the value of the digits goes up by ten for each step. Ones, tens, hundreds, etc. In hex, each step is worth 16x more. In binary, 2x. In binary we can only have 0 or 1 in a digit(bit), so we're going to need more digits to represent 0d2. And we'd represent that as zero in the ones digit, and one in the twos digit, or 0b10.

So, 0x2 = 0d2 = 0b10.

Similarly...

0x3 = 0d3 = 0b11

Because we think in decimal, "3" is a one digit number. Because computers think in binary, it's a two digit number. And each digit is representing a different thing (PIOF and USED). It's not unlike 10122007 representing the day, month and year of your first step into SL. There are three different things (mm/dd/yyyy) in that one number, just as there are two different things (used/piof) in the value returned from the dataserver.

Parsing those things from a single number is a subject unto itself, but here's how it's done by computers...

https://en.wikipedia.org/wiki/Mask_(computing)

The reason LSL understand hex is that it's a convenient and compact way to reveal the underlying binary nature of the computer. One hex digit contains exactly four binary bits....

0x0 = 0b0000 = 0d00

0x1 = 0b0001 = 0d01

0x2 = 0b0010 = 0d02

0x3 = 0b0011 = 0d03

0x4 = 0b0100 = 0d04

0x5 = 0b0101 = 0d05

0x6 = 0b0110 = 0d06

0x7 = 0b0111 = 0d07

0x8 = 0b1000 = 0d08

0x9 = 0b1001 = 0d09

0xA = 0b1010 = 0d10

0xB = 0b1011 = 0d11

0xC = 0b1100 = 0d12

0xD = 0b1101 = 0d13

0xE = 0b1110 = 0d14

0xF = 0b1111 = 0d15


(3) I do not understand why Rollig's
if ( (integer)data & 2) )
is the same as Madelaine's
if(   (integer)data & PAYMENT_INFO_USED)
. In the Wiki for PAYMENT_INFO_USED it is said that the integer constant for it is "0x2" and not "2". So I would have expected Rollig's version to be
if ( (integer)data & 0x2) )
.

 

As you say, "PAYMENT_INFO_USED" is defined as 0x2. So anywhere I use that name, I'm referring to the number 0x2. My use of that name is the same as Rolig's use of (0d)2, which is the same a 0x2. I won't complain about Rolig's failure to use 0x, her code will break if she forgets to use it when needed and she'll listen to the bug long before she'll listen to me. 

;-).

 

 

Link to comment
Share on other sites

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