Thanks! So ^ pretty much serves the same purpose as != ?
For booleans, yes. It will work for other numbers as well if you used in an if check, but it will still not be a value.
Oh yeah, these are server-sided, correct?
No. These are numerical values, so they can be defined anywhere. However, the $TypeMasks::* values are also available on the client-side, and you can use getType on any object in the ServerConnection. I think you sort of understand what's going on, but I'll explain it a bit more. Everyone is talking about bitwise operators which is correct, but I'll go into a little bit more about bitmasks (which is what these are) and how and why bitwise operations make bitmasks work.
Already mentioned: Bitwise operators (&, |, ^, etc - not to be confused with && and ||, the conditional versions) allow you to manipulate single bit values inside a numerical value. But the reason this works all comes down to the shifting operators being combined with the other bitwise operators
Importantly: a bit can have 2 values, a 0 or 1. This is the binary system. Let's start with the simplest numerical value: 1. But to explain this, I'm going to say it is:
n = 00000000001
Where n is the binary value we're going to work with. It's the same value as decimal 1 and binary 1 and doesn't need the extra zeroes, I just need the zeroes to explain how this works.
What the bitwise shift operators do is shift that 1 bit that is on (on being has a value of 1, instead of 0 which is off) left or right. The << operator is left, the >> operator is right. For example, n << 2 is shifting our value of n two units to the left:
n = 00000000001 (= 1)
<<
n << 2 = 00000000100 (= 4)
As you can see, its shifted that one bit two places to the left. The value of n << 2 is now 4 in the decimal system, and 00000000100 in the binary system. Shifting right is not really important for bitmasks, so we'll ignore that.
Now, the bitwise and operator check compares two numerical values (in binary) and any bits that are the same are turned on whereas any bits that are not the same are turned off. ie, if any bits in the same binary place are both on, keep the final value on otherwise turn it off for that single place. Here's an example of what I mean:
let x = 00000100101 (= 37)
let y = 00000101001 (= 41)
_____v____v
x & y = 00000100001 (= 33)
(the key: v means it was turned on, the underscore means it was turned off)
As you can (hopefully) see, it has gone through each place and turned on any bits that are the same between the two binary numbers and turned off the rest.
The bitwise or operator is similar. It goes through each bit, and if both values are off, it turns the bit off. If either value is on, then it turns the bit on. Pretty simple, here's an example:
let x = 00000100101 (= 37)
let y = 00000101001 (= 41)
_____v_vv_v
x | y = 00000101101 (= 45)
(the key: v means the bit was turned on, _ means it was turned off)
For each place of bits in x and y, if either bit was turned on then that bit was turned on otherwise it was turned off.
The other operators are also useful, but you can look into those. Now finally, I can explain what those explanations were building up to. The way bitmasks work:
First, each option you would like to accept needs a constant value, which is actually a shifted value. For example, all of the $TypeMasks::* values are bitwise-shifted values (to the left) of 1. From what we've gone over, you should know that each consecutive time you shift a value to the left, the bit turned on is being carried over to the next bit place towards the left. So when you are defining the constant values that the user uses for the options, they are consecutive shifts of the binary value 1. These are not the actual values, but here's an example of how typemasks would be defined:
$TypeMasks::Brick = 1; //(= 00001)
$TypeMasks::Terrain = 1 << 2; //(= 00010)
$TypeMasks::Player = 1 << 3; //(= 00100)
$TypeMasks::Interior = 1 << 4; //(= 01000)
$TypeMasks::StaticShape = 1 << 5; //(= 10000)
You'll notice that each constant has a bit in a different place, because each one is consecutively shifted. This is the magic of how bitmasks work. Using the bitwise or operator, we can combine two constants together without the need of an extra argument, while still retaining both the constants in the value. We do this using the bitwise or operation.
You will remember that the bitwise or operator goes through each bit of the two values, and if neither of the values are turned on at that bit place, the new value of the bit in the place is off, otherwise it is on. This can be used with the bitwise-shifted operations to combine the two constants into one value. Example, if were to combine the brick typemask with the player typemask:
$TypeMasks::Brick = 00001 (= 1)
$TypeMasks::Player = 00100 (= 8)
__v_v
$TypeMasks::Brick | $TypeMasks::Player = 00101 (= 5)
The two constants are now combined into one binary value. But you're thinking, the hell can I do with this value? How do I check for each seperate value? That's where the bitwise and operation comes into play. Because the and operator checks each bit and makes sure they're both turned on, it can be used to single out only one constant value's bits inside a combined constant value. Probably hard to explain, so here's an example:
$TypeMasks::Brick | $TypeMasks::Player = 00101 (= 5)
let x = 00101 (from above)
$TypeMasks::Brick && 00101 = 00001 (= 1)
As you can see, it has got rid of any stuff left over from combining it with $TypeMasks::Player. If a certain constant value is inside something you've combined with another constant value and you use bitwise and operator with that certain constant, the value will be 0 if it is not inside it, or a numeric value other than 0 if it is inside it. This can be combined with an if check, so that you can test if a certain constant has been switched on in a value. I know I'm probably not making much sense, so I'll just bring it back to the basics, and what you asked originally:
if(%player.getType() & $TypeMasks::PlayerObjectType)
echo("Yes, the value of %player.getType() has been bitwise or'd with $TypeMasks::PlayerObjectType. It could also be exactly equal to the the typemask as well.");
else
echo("No, it was not combined with that typemask, so the bitwise and has come out as zero, hence the conditional failed.");
There's many reasons to use typemasks. Firstly, it can be used to reduce the number of arguments that you need to pass. For example:
function laugh(%loudly,%snort,%dieafterwards,%stamponthecat,%wishtherewasmoreargumentsonthisfunction,%throwthetableover)
{
if(%loudly)
{
//do this
}
if(%snort)
{
//do this too
}
if(%dieafterwards)
{
//do it omg
}
if(%stamponthecat)
{
//no way
}
if(%wishtherewasmoreargumentsonthisfunction)
{
//keep trying
}
if(%throwthetableover)
{
//(ノಠ益ಠ)ノ彡┻━┻
}
}
laugh(true,true,false,true,false,true);
If you have code like this, usually with a lot of arguments, it can get painfull to remember their order and importance. If you use bitmasks instead:
$LOUDLY = 1;
$SNORT = 1 << 2;
$DIEAFTERWARDS = 1 << 3;
$STAMPONTHECAT = 1 << 4;
$WISHTHEREWASMOREARGUMENTSONTHISFUNCTION = 1 << 5;
$THROWTHETABLEOVER = 1 << 6;
function laugh(%bitmask)
{
if(%bitmask & $LOUDLY)
{
//do this
}
if(%bitmask & $SNORT)
{
//do this too
}
if(%bitmask & $DIEAFTERWARDS)
{
//do it omg
}
if(%bitmask & $STAMPONTHECAT)
{
//no way
}
if(%bitmask & $WISHTHEREWASMOREARGUMENTSONTHISFUNCTION)
{
//keep trying
}
if(%bitmask & $THROWTHETABLEOVER)
{
//(ノಠ益ಠ)ノ彡┻━┻
}
}
laugh($LOUDLY | $SNORT | $STAMPONTHECAT | $THROWTHETABLEOVER);
Then you only need one argument, and it becomes much more readable. The reason Torque uses it for types is so that they can have combinations of types. Say you had a brick that was also a static shape, the typemask would be $TypeMasks::Brick | $TypeMasks::StaticShape and when you bitwise and the combined typemask with each seperate typemask, it will be true for both.
It's also used for raycasts, as you combine each typemask together and pass it to the function (eg. $TypeMasks::fxBrickObject | $TypeMasks::PlayerObjectType, saying I want it collide with a player or brick) and then the raycast check itself does a bitwise and on each object it find's type with the value we passed to it, and if the and returns true then it has collided with a type that we passed.
tl;dr - I suck at explaining stuff, so try this:
http://en.wikipedia.org/wiki/Mask_(computing)
That's where I learnt bitmasks, there was another good one but I lost it. Sorry for any mistakes and the stuff diagrams.