Jump to content

A Practical Method for Checking Bit Fields


Bloodsong Termagant
 Share

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

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

Recommended Posts

i know just enough to really screw myself up...

 

i read this:

and this:

and this: https://lslwiki.digiworldz.com/lslwiki/wakka.php?wakka=bitwise

 

and i understand how to do things like:  if(change & CHANGED_INVENTORY)
and i understand binary counting, etc etc.

i don't understand binary notation or hexadecimal? thing?  :/

 

so what i've done is this:

	    integer ERROR = FALSE;
        string s = "RA:Liberty:Standing";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 1; }
        s = "RA:Standing";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 2; }
        s = "RA:Liberty:Walking";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 4; }
        s = "RA:Walking";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 8; }
        s = "RA:Liberty:Running";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 16; }
        s = "RA:Running";
        if(llGetInventoryType(s) != INVENTORY_NOTECARD)
        {  llOwnerSay(s+" notecard not found!");  ERROR += 32; }

if(DEBUG) llOwnerSay(CodeName+"Error code="+(string)ERROR);   

        if(ERROR & 3) SON = FALSE; //--if both stands were nf, no standing
        if(ERROR & 12) WON = FALSE;  //--if both walks were nf, no walking
        if(ERROR & 48)  RON = FALSE;  //--if both runs were nf, no running
        if(!SON && !WON && !RON) //--if they're all off then we have a problem
        {
            llOwnerSay(CodeName+"ERROR: no Random Animation notecards found.  Not running.");
            state error;
        }
        if(ERROR)//--one or more are missing, but it's not a disaster
        {
            llOwnerSay(CodeName+"Warning: not all Random Animation notecards found.  If you don't have animations for a particular set, you don't need to worry.");
            llOwnerSay(CodeName+"Continuing.");
        }

 

i THINK...  if the first two notecards are not found, the +1 and the +2 are binary 11.   and i THINK "ERROR & 3" is saying 'the error contains both the 1 and 2 bitflags on.'  etc.

however, i'm loading only one of each pair of notecards (the non-Liberty ones), and ERROR checks out as 21...  yet i still get the 'no notecards found' error.

 

oh.  did i make a stupid error about all the ! flags &&'d together???  omg.

 

at any rate...  what is the proper format for loading bits?  instead of using the decimal numbers?  and what is the proper syntax for checking the bits.  from what i've read, i'm doing THAT right, at least.  i THINK.

 

thanks, guys!

 

 

um... didn't i hit submit?  anyway, i fixed it.

so (ERROR & 1 & 2) is different from (ERROR & 3)  ... right?  not sure why, though.

and i still need to know how to use the other notation, so i don't have to remember 1 2 4 8 16, etc.  and then add them :X

 

 

Link to comment
Share on other sites

When it comes to creating bitfields (a sequence where individual bits have special meaning), LSL doesn't have a convenient or intuitive way to do it.

In the C language, you could create a bitfield like this: 0b10001000, which would be the integer 136. (4th and 8th bit set to 1.)

 

LSL does have hexadecimal notation, which may simplify things for some people: 0x88, which is also 136.

The way bit-position counting in hex works is like this: 1, 2, 4, 8, then 10, 20, 40, 80, then 100 ("one-zero-zero") and so on. (Notice the sequence from 1 to 8 before repeating.)

It may be easier to understand if you use a converter like this one: https://www.mathsisfun.com/binary-decimal-hexadecimal-converter.html

If you're familiar with the LSL Preprocessor in Firestorm, you could create macros for C-like bitfields to make things a lot more intuitive.

 

1 hour ago, Bloodsong Termagant said:

so (ERROR & 1 & 2) is different from (ERROR & 3)  ... right?  not sure why, though.

Yes, they are different. (ERROR & 1 & 2) would always result in 0 because of the order of operations. (ERROR & 1) could result in 1, but that result & 2 would always be zero because it's impossible for the integers 1 & 2 to have bits in the same position. (ERROR & 3) could result in 1, 2, or 3, but that's not important since you care if it's anything but zero.

The code you've shown seems correct, nothing stands out as an obvious error. Are you sure the problem is here and not somewhere else? The error 21 means that nothing (1+4+16) was found for the Liberty notecards... which leads me to ask, do you have separate notecards for stands/walks/runs?

Actually, I think I found the problem, and what I said was a wrong assumption.

If either RA:Standing or RA:Liberty:Standing fails, you set an error. Then later, you check if either of those errors happened, and turn off the stand if that was the case. So even though you've loaded one notecard for stands, you still turn stands off.

So here's where it gets a tiny bit tricky. You want to isolate the different kinds of errors before checking what the value is. For example, if everything failed to load, your error will be (11 11 11).

To check if both stands failed to load, you need the first two bits from the error value. (ERROR & 3) does that, but to make sure that both bits (both errors) are enabled, you need to check ((ERROR & 3) == 3). Otherwise if the value is 1 or 2, something was loaded and there's no issue. The same applies for the other checks. ((ERROR & 12) == 12) and ((ERROR & 48) == 48).

P.S.

If you wanted to do something similar to (ERROR & 1 & 2), you could do this instead: (ERROR & (1 | 2))

The bitwise OR operator will "combine" the enabled bits of both values. So (1 | 2 == 3) and (ERROR & 3) is where you were.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

//
//   Maze cell storage - 2 bits per cell from 2D maze array
//
integer mazecellget(integer x, integer y)   
{
    assert(x >= 0 && x < gMazeXsize);           // subscript check
    assert(y >= 0 && y < gMazeYsize);
    integer cellix = y*gMazeYsize + x;                   // index into cells
    integer listix = (integer)(cellix / 16);
    integer bitix = (cellix % 16) * 2;
    return ((llList2Integer(gMazeCells,listix) >> bitix) & 0x3);  // 2 bits only
}

//
//  mazecellset -- store into 2D maze array
//    
mazecellset(integer x, integer y, integer newval) 
{   assert(x >= 0 && x < gMazeXsize);           // subscript check
    assert(y >= 0 && y < gMazeYsize);
    assert(newval <= 0x3);                      // only 2 bits
    integer cellix = y*gMazeYsize + x;          // index into cells
    integer listix = (integer)(cellix / 16);          // word index
    integer bitix = (cellix % 16) * 2;          // bit index within word
    integer w = llList2Integer(gMazeCells,listix);             // word to update
    w = (w & (~(0x3<<bitix)))| (newval<<bitix); // insert into word
    gMazeCells = llListReplaceList(gMazeCells,[w],listix, listix); // replace word
}

Here's something I use inside my NPCs. They have a maze solver, and they need to store 2 bits per maze cell. This is the code which does that, with data for 16 cells in each integer.

Link to comment
Share on other sites

in the posted code as wrote there are 27 logic combinations. [0,1,2] * [0,1,2] * [0,1,2]. 3 * 3 * 3 = 27

we don't want to have to test all 27 to find missing notecards. We do have to test tho but we can reduce the checks down to 4 by writing our code a little bit more directly

example using animation sets

list animsets = [
  "RA:Liberty:Standing","RA:Liberty:Walking","RA:Liberty:Running",
  "RA:Standing","RA:Walking","RA:Running"
];
// Liberty list indices 0,1,2
// Other list indices 3,4,5

integer ANIMSET_LENGTH = 3; // stand. walk. run
integer animset_number;  // Liberty = 0. Other = 1

default
{
  state_entry()
  {
    //animset_number = 0; // Liberty
    animset_number = 1;  // Other
   
    // check for animset notecards presence
    integer recordnum = animset_number * ANIMSET_LENGTH; //  recordnum will be 0 or 3  
    integer present;
    integer i;
    for (i = recordnum; i < recordnum + ANIMSET_LENGTH; i++) // 0 + 3 = 3. 3 + 3 = 6
    {
      // multiply 'present' by 2, adding 1 when notecard found
      present = (present << 1) | 
        (llGetInventoryType(llList2String(animsets, i)) == INVENTORY_NOTECARD);
    }
    // present is a 3 bit flag
    // bit 0: running
    // bit 1: walking
    // bit 2: standing

    integer anims_none = !present;
    integer anims_standing = (present >> 2) & 1;
    integer anims_walking = (present >> 1) & 1;
    integer anims_running = present & 1;
 
    // if any of anims_* is FALSE then
    // get substitute from other set(s) or play default anims
  
    llOwnerSay(llDumpList2String([anims_none, anims_standing, anims_walking, anims_running], " "));
    // when all are present then says 0 1 1 1
  }
}

 

Link to comment
Share on other sites

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