Jump to content

Welcome to DreamBot!

Download for Free

Supercharge Your Bots

Run unlimited bots today using DreamBot's Covert Mode and
stay more protected.

Upgrade Now
Frequently Asked Questions
  • Are you not able to open the client? Make sure you have Java 8 installed
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS gold? You can purchase vouchers from other users
  • Try asking for help in the chatbox
OSRS Gambling

Interested in advertising your business? Reach out today!

Download the DreamBot client today!
Articron

PlayerSettings : Bitwise operations and bitmasks

Recommended Posts

PlayerSettings class: PlayerSettings

 

AUTHOR NOTE: This tutorial goes somewhat indepth, but I tried my best to break down every single aspect to a much simpler concept.

Keep in mind that this only handles the things you could utilise in scripting, there is lots more to learn about within this field when talking from a general Java perspective. The first few chapters try to give you a basic background on bitwise operations, so that things get easier when applying it to a scripting example.

 

Level: Intermediate

Difficulty: 5/10

 

Tutorial goals

  • The reader can explain in his own words what PlayerSettings are, and in what context they can prove useful.
  • The reader can explain the underlying structure of what an "32-bit integer" CAN represent in this tutorial's context.
  • The reader can utilise bitwise operations to read/manipulate "bit blocks", which he/she can use within script logic.
  • The reader can utilise Bitmasks to differentiate between multiple "bit blocks", which he/she can use within script logic.

1. What PlayerSettings are

 

 

When you start the Dreambot client, it automatically starts a new Runescape client instance. This RS client keeps alot of information and data about you (The Player) or about the client itself. This data is saved and kept track of in the client under what is defined as "PlayerSettings" in the Dreambot API. 


As you can imagine, there's an insane amount of things the client has to keep track of. This means there would be ALOT of variables.

Jagex found a way to "compress" these variables. They "compressed" multiple pieces of data within 1 integer. It just so happens these multi-purpose integers can be retrieved with the PlayerSettings class.

 

Things like wether or not your run mode is enabled, wether or not you're logged in, Grand Exchange progress, Tutorial island progress,... Is all saved within these PlayerSettings. 

 

A playerSetting has an ID, this makes it unique. Every PlayerSetting has an integer linked to them.

We can call upon a certain setting with PlayerSettings#getConfig(int id). The int that is returned is the integer linked to that specific PlayerSetting that carries the data we are interested in.

 

For example: The new deadman interface where you can save/protect certain skills, is all being kept track of with a single integer. 

 

We can utilise these PlayerSettings to our advantage in scripts. For the example above: Instead of checking every WidgetChild for its colour/text/whatever, we could just read the PlayerSetting and know which skills we are saving in deadman, without the need of opening the interface itself. 

 

It's a good scripting ethic to utilise these PlayerSettings. On other people's source codes across several botting communities I've seen alot of scripters not taking advantage of this feature, even though it would improve their script.

 

 

 

2. PlayerSettings are saved with a 32-bit integer

 

 

What do I mean with a "32-bit" integer?

As you know the integer has certain boundaries: Integer.MAX_VALUE and Integer.MIN_VALUE.

 

What we do in programming:

private int number = 5; // DECIMAL

the variable "number" is given a DECIMAL format. However, there are also other formats, like a BINARY format:

private int number = 0b00000000000000000000000000000101; // BINARY (could be 0b101, added 32 bits for clarity)

We use the binary literal 0b to specify we are dealing with a binary format. With "binary literal", I basically mean the 0b prefix.

 

Both variables above are equal to the number 5. Test it out:

public static void main(String... args) 
{
    System.out.println(5);
    System.out.println(0b00000000000000000000000000000101);
}
// output
// 5
// 5

It's in this binary form that we can manipulate/read certain parts of the "bit-chain", (the collection of 0's and 1's). And it is in the binary format where PlayerSettings serve their purpose.

 

 

 

3. How to form a binary format

 

 

If you got this far, good job. This might sound Arabic to you, which is good to hear! This is because Arabic writing has to be read from right to left.

You will understand what I mean by that momentarily.

 

So, let's take our binary number 5 again:

private int number = 0b00000000000000000000000000000101; // BINARY (could be 0b101, added 32 bits for clarity)

Each 0 and 1 is called a "bit". In binary, a bit can only be 0 or 1. In total, you have 32 bits in there (excluding the 0b literal), hence why integers are 32-bit. (Longs for example are 64-bit).

 

Let's just take the 32 bits, and look at nothing else for a second.

00000000000000000000000000000101

Each of these bits have a "slot id". The slots are ordered from right to left, And increment by the power of 2 each time.

 

Here is a colourful representation of what I mean:

 

00000000000000000000000000000101
Slot 1
Slot 2
Slot 4
Slot 8
Slot 16

 

Note: if you expected me to give a colour to each and all 32 bits, you're dizzy af in the head

 

Now let's take a look at which slots have the bit value 1:

 

Slot 1 has a bit value of 1

Slot 4 has a bit value of 1

 

Now hold on! Can you see it before I tell you? Remember that this binary chain is equal to 5.

 

1 + 4 = 5.

 

 

things-that-blew-your-mind-when-you-were

 

 

 

Now here's another mind blower, what if all bits were 1?

0b11111111111111111111111111111111 

^ The above bit number is equal to Integer.MAX_VALUE. There is no way we could add more 1's, because then it wouldn't have 32 bits anymore!

 

 

 

4. Shifting the bits

 

 

Shifting the bits is done with a bitwise operation. In scripting, the most common used is the signed right shift.

 

The signed right shift has an operator. This operator is >>.
 

Example:

private int number = Y >> X;

Shifting bits does as it implies: It shoves the bitchain of Y to the right X amount of times.

 

Example:

0b00000000000000000000000000010000 >> 2 = 0b00000000000000000000000000000100

Did you see what happened there? The 1-bit got shifted to the right twice. 

 

 

Q: But what happens if the 1-bit is already on the right?

 

A: It gets removed, and a 0 is added to the left of the chain.

 

Example:

0b00000000000000000000000000000001 >> 1 = 0b0000000000000000000000000000000

NOTE: ANY 1-bit that falls off the chain because of a shift, gets removed and replaced with an 0 on the left!

 

Example:

0b00000000000000000000000010000000 >> 9 = 0b0000000000000000000000000000000 

In order to evaluate your understanding, put this in your IDE, but DONT run it yet:

public static void main(String... args) 
{
   System.out.println(7 >> 2); 
} 

Try to predict what value will be given when you run this.

TIP: write down the binary chain of 7 down first, it will make things much easier.

 

Answer can be found below:

 

 

ANSWER = 1

 

7 >> 2

7 = 0b00000000000000000000000000000111

SHIFT TO THE RIGHT 2 TIMES

0b00000000000000000000000000000001 = 1

 

 

 

 

 

5. Masking the shifted bits

 

 

Author note: This part is rather irritating to explain, apologies if it is a bit sloppy.

 

Masking part of a bitchain is part of telling your program on what bits to focus on. A bitmask has the & operator. It is officially called the AND operator.

 

Bitmasks can be made in either format, but for the sake of simplicity we will keep it a binary format.

 

Example:

private int number = 7 >> 2 & 0b1;

The number: 7

The shift: 2

The mask: 0b1 

 

Notice how the mask has only 1 digit (excluding the binary literal) ? This means that your application will only look at the first bit slot.

The output = 1.

 

Now let's switch it up to have a bigger example:

0b00000000000010000100100010000010 >> 11 & 0b1111;

So first things first, we shift that bitchain 11 times to the right:

0b00000000000000000000000100001001

Now all that is left is our mask: 0b1111. 

We want to only look at first four bit slots. This is why our mask is 0b1111 (4 times a 1).

 

Visual representation:

 

0b00000000000000000000000100001001

0b1111 mask

 

All the other bits in black, are not being looked at by your application anymore. The 1-bit that is black, will not be counted when applying the bitmask.

 

This means that "1001" is left. 

 

We do the math:

 

1 + 8 = 9.

0b00000000000010000100100010000010 >> 11 & 0b1111
= 9

 

 

 

6. Applying our new knowledge to scripting

Credits to @@Eclipseop for writing a practical addition to this tutorial.

It can be found on this post: https://dreambot.org/forums/index.php/topic/3911-playersettings-bitwise-operations-and-bitmasks/?p=58041

Edited by Articron

Share this post


Link to post
Share on other sites

 

I like to think mine is a little bit more broken down into bits (pun intended) & pieces.

 

I checked his post, and it doesn't seem to have much value for someone who doesn't know anything about the topic.

He also doesn't use bitshifts at all in his example, only bitmasks ;)

Edited by Articron

Share this post


Link to post
Share on other sites

I like to think mine is a little bit more broken down into bits (pun intended) & pieces.

 

I checked his post, and it doesn't seem to have much value for someone who doesn't know anything about the topic.

He also doesn't use bitshifts at all in his example, only bitmasks ;)

im js

Share this post


Link to post
Share on other sites

Gonna make an addition since it's been a while and there has been some talk in chat about how to apply this to player settings.

Let's take runecrafting pouches for an example, and how to make methods for checking if said pouch is full. The player setting 720 refers to the ingame data that is stored regarding the players pouches.

When only the small pouch is full, the setting reads 2, only med pouch is 8, and only full is 32;

Binary counterparts:
0b00000000000000000000000000000010 <- 2 aka small

0b00000000000000000000000000001000 <- 8 aka medium

0b00000000000000000000000000100000 <- 32 aka large

 

Now lets say the setting returns 34, so the binary is:

0b00000000000000000000000000100010

 

By this we can tell that both the large and small pouches are full. Whenever the small pouch is full, the 2nd bit is set to 1, and whenever the large pouch is full, the 6th bit is set to 1.

So how do we use the bitwise ops?

Lets take a look at isMediumPouchFull:

public static final int MEDIUM_POUCH = 0b1000;

private boolean isMediumPouchFull() {
	return (Settings.get(720) & MEDIUM_POUCH) == MEDIUM_POUCH;
}

the mask (&) makes it so we only read the bits we indicate, so since we pass 0b1000 (8) it checks for that bits, and returns the decimal equivalent for the matched bits, example: 

 

10 = 0b1010;

2 = 0b10;

 

10 & 2 would return only 0b10, since that is the only bits that are equal to 1 and are the same, so then once we mask the to the expected amount, we simply check if the returned value is equal to the expected.

Edited by Eclipseop

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...