Articron 746 Posted November 28, 2015 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: 00000000000000000000000000000101Slot 1Slot 2Slot 4Slot 8Slot 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. 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
Volta 184 Posted November 28, 2015 @Computor had some information on player settings too XD http://dreambot.org/forums/index.php/topic/3480-dnc-farmer-pro-script-progress-updates/
Articron 746 Author Posted November 28, 2015 @Computor had some information on player settings too XD http://dreambot.org/forums/index.php/topic/3480-dnc-farmer-pro-script-progress-updates/ 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
Volta 184 Posted November 28, 2015 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
Eclipseop 194 Posted August 30, 2016 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.
Hashtag 9045 Posted August 30, 2016 Gonna make an addition... Good and simple way to demonstrate this. Thank you!
Recommended Posts
Archived
This topic is now archived and is closed to further replies.