Graal Forums

Graal Forums (https://forums.graalonline.com/forums/index.php)
-   NPC Scripting (https://forums.graalonline.com/forums/forumdisplay.php?f=8)
-   -   Bitflag Tutorial (https://forums.graalonline.com/forums/showthread.php?t=70113)

jake13jake 11-15-2006 09:25 AM

Bitflag Tutorial
 
Why use a bitflag?
  • They require less memory.
  • Bitwise operations take much less execution time than other operations.
  • With the small amount of space they require, you can greatly reduce server traffic.

What is a bitflag? A bitflag is an integer that represents multiple cases of true and false.

In order to understand this, you might take a look at an integer in binary. First of all, how do you read a binary value?

0000 is 0
0001 is 1
0010 is 2
0011 is 2+1
0100 is 4
0101 is 4+1
0111 is 4+2+1

Do you see a pattern of the powers of two emerging? If you don't, I suggest you go get a catscan.

Each value in a binary number on computers is a bit. The bit is either on (1) or off (0).

Amazingly, we have operators to manipulate numbers at the bit level.
& (bitwise and), &= (bitwise and assignment)
| (bitwise or), |= (bitwise or assignment)
xor (bitwise exclusive or), unfortunately gscript lacks xor assignment
<< (left bitshift), <<= (left bitshift assignment)
>> (signed right bitshift), >>= (signed right bitshift assignment)
unfortunately, gscript lacks unsigned right bitshift/assignment.

What can we do with these operators

Let's look at different cases (pretending we're working in 8 bits):

~4
00000100 (4 in binary)
11111011 (~4)
The inversion operator makes all the 0s into 1s and all the 1s into 0s.

4 & 5
00000100 (4 in binary)
00000101 (5 in binary)
00000100 (4 & 5)
If the bits are both on, then the bit in the outcome is on.

4 | 5
00000100
00000101
00000101 (4 | 5)
If either of the bits are on, then the bit in the outcome is on.

4 xor 5
00000100
00000101
00000001 (4 xor 5)
If the bit is one or the other but not both, the bit is on in the outcome.

4 << 1
00000100
00001000 (4 << 1)
What does this do? It shifts all the bits left one and fills in with 0. This is also identical to multiplying by a power of 2, the right operand being the power.

4 >> 1
00000100
00000010 (4 >> 1)
This shifts all the bits right one, and fills in the last bit with a copy of the previous last bit (which in this case would be 0). Other than the last bit, this would be identical to integer division by a power of 2.

This is because the last bit is the SIGN bit.
11111111 would be -1.
11111110 would be -2, and so on.
If you right shifted either of these examples by more than one, the outcome would be -1. If you wanted to fill in the last bit with a 0, you'd need to use an unsigned bit, which gscript lacks.

PHP Code:

//Okay, let's say you want to make constants for a bit flag.
INFECTED = (<< 0); //player has a virus (1)
IMMUNE = (<< 1); //player is immune to the virus (2)
SICK = (<< 2); //player is sick due to the virus (4)
FATAL = (<< 3); //the virus is fatal to the player (8)
//and so on...

//This makes it so that each constant represents a particular bit. 
//You could also make a constant represent all of the bits. 
ALLBITS = -1;

//So now that we have our constants sorted out, we will initialize a bitflag.
player.clientr.flag 0;

//how do we put different values in the flag?
player.clientr.flag |= INFECTED//(sets a bit, or leaves it set)
player.clientr.flag &= ~INFECTED//(unsets a bit or leaves it unset)
player.clientr.flag player.clientr.flag xor INFECTED//(using the xor operator will toggle the bit)

//The player should be infected. 
//How do we check to see if the player is infected?
if (player.clientr.flag INFECTED == INFECTED)
  
doInfectionStuff();

//You can also check for multiple bits at once.
temp.mask INFECTED SICK;
if (
player.clientr.flag temp.mask == temp.mask)
  
doMaskStuff();

//What if you just need one of the bits your checking in the mask to be true?
if (player.clientr.flag temp.maks != 0)
  
doOtherStuff();

//What if you want to know what the first set or first unset bit are?
this.firstset & (~1); // can also be written c & -c;
this.firstunset = ~& (1); 

That pretty much covers the whole concept. Also, keep in mind that you have 32 whole bits you can use for one flag in gscript, not just 4 or 8.

Here are some other neat tricks that you should only use for integers.

var * 2^n;
is equivalent to
var << n;

var / 2^n;
is equivalent to
var >> n; (integer division, 3>>1 returns 1, not 1.5)


var % (2^n);
is equivalent to
var & (2^n - 1);

-var is equivalent to (~var + 1)... though this isn't so useful.

var = var xor var;
is equivalent to and for some computers even faster than
var = 0;

Here's a useful one though. Swapping two numbers without a temp value.
PHP Code:

if (var1 != var2) {
  
var1 var1 xor var2;
  
var2 var2 xor var1;
  
var1 var1 xor var2;


The body without the if branch would work for all values, except for when you're trying to swap a number with itself. This would mean, in essence that var1 is the same variable as var2. The example of this that is most often encountered is by swapping arr[i] and arr[j], when i==j.

I hope you join me in my protest for an unsigned bitshift operator (>>>) and a xor assignment operator, and that you can all use bitflags after reading this.

Rick 11-15-2006 11:41 AM

Quote:

Originally Posted by jake13jake (Post 1243670)
0000 is 0
0001 is 1
0010 is 2
0011 is 2+1
0100 is 4
0101 is 4+1
0111 is 4+2+1

Fixed.
NPC Code:
0000 is 0
0001 is 1
0010 is 2
0011 is 2 | 1
0100 is 4
0101 is 4 | 1
0111 is 4 | 2 | 1


jake13jake 11-15-2006 06:11 PM

Quote:

Originally Posted by Rick (Post 1243690)
Fixed.
NPC Code:
0000 is 0
0001 is 1
0010 is 2
0011 is 2 | 1
0100 is 4
0101 is 4 | 1
0111 is 4 | 2 | 1


They evaluate to the same result, though bitwise or is probably faster. The purpose of that section was just to demonstrate how integers are represented in bits.

Chompy 11-15-2006 11:47 PM

Nice Tutorial! :D

Skyld 11-15-2006 11:54 PM

Indeed a nice tutorial, should perhaps be put on the wiki if not done so already?

jake13jake 11-16-2006 02:12 AM

Of course I don't think saying (4 | 1) against (4 + 1) would really matter anyways because I do believe Graal compiles using constant folding. You can put it on the Wiki if you want. I don't even think Wikipedia has a decent bitflag page.


All times are GMT +2. The time now is 11:40 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2026, vBulletin Solutions Inc.
Copyright (C) 1998-2019 Toonslab All Rights Reserved.