Apr 18 2010, 02:14 AM Post #1 | |
Coding like a Rockstar! Posts: 1,468 From: ??? Joined: 28-May 09 | [CLEO|TuT]Using Thread memory As my internet allowance runs down to it's last pennies that was wasted on data which is supposed to be completely free... I begin to think about other things that run out much sooner than they should... Variables! I was going to post a whole long trail of memory related tutorials leading to this, but since the pennies in my internet are dissapearing with every letter I type. I thought I'd skip it all and treat you to one of the greatest methods of using memory there can possibly be. To complete this tutorial, you need patience. If you don't understand it... Keep reading. Then when you've finished, read it again until you have an idea of what you're doing. Don't expect to pick up from this tutorial in a few minutes. You may have to come back on it for a while. You should already have a good knowledge of creating CLEO Scripts, reading and writing to memory addresses and a basic idea of how CLEO and the main.scm work. Memory Addressing Hopefully you know that we can read memory from the game. Memory is stored in the application (and ultimately, in our RAM). When a CLEO Script, a CLEO Mission or the main.scm is also loaded into the application... (and ultimately, in our RAM). So we can read/write from/to the scripts just like we can with any other memory. Hex Whenever we read or write memory, we usually do it in hex. When we compile a script, it is also compiled to hex. When the game is run, the hex is loaded into the game memory. So in a way, we are already writing hex to the game when we write a script. In pure theory, we could write a script by just writing to the engine... That's what the game engine does, anyway. It reads or script file and stores it's hex in the engine. Now we've got our heads around that... I'll explain how to start using all these methods to our advantage in very special ways. The main.scm File You can probably skip this part, but I recommend a quick read anyway. The code is compiled as hex, so writing this: CODE wait 5 or CODE 0001: wait 5 ms Will compile as this: CODE 0100 04 FA There are about 2/3/4 steps that the compiler takes when it decompiles the second one to the first one. First off, you will notice the first 4 numbers (the opcode) is kinda backwards. It's 0100 instead of 0001. This is just how the game registers it as, but to make it make a little more sense... The compiler switches it to 1. CODE 0001 04 FA The 04 is the data type. This tells the game how many bytes the parameter has to read next. More on that later. The compiler will hide this, since we don't need to see it. CODE 0001 FA Now it looks a little more like the decompiled code. FA is the next thing to translate. FA is hex for 250. So the compiler just switches it from hex to normal numbers: CODE 0001 250 And now all it needs to do is add some text to describe the opcode a bit better... CODE 0001: wait 250 ms And that's how the compiler decompiles hex to something we can understand. If you wanna find out how it compiles it.. Read this whole thing backwards -------------------- | CLEO 4.3.22 | A?i?a?o?3D | UI SDK | Black Market Mod 1.0.1 | GInput 0.3 | Cheat Keyboard | Tactile Cheat Activation | Stream Ini Extender 0.7 | SuperVars | ScrDebug | Vigilante Justice: San Andreas | |
Apr 19 2010, 12:18 AM Post #2 | |
Coding like a Rockstar! Posts: 1,468 From: ??? Joined: 28-May 09 | Putting It Into Code Now we know a lot about how things work (if you don't, you should probably read this all again later ), it's time to put it all into practise. The hex...end structure is a special keyword in Sanny. It lets you code things in hex... So it's basically the same thing (we type opcodes, then parameters) but with a few extra rules. 1 The opcode has to be "backwards". This just means the first two digits of the opcode come last. For example, this: CODE 0919: Should be written as: CODE hex {opcode} 1909 end 2 Appropriate data types MUST come before parameters. I compiled a list of them here. It will let you know which data types should be used with which parameters. For example: CODE 0001: wait 0 Should be written as: CODE hex 0100 04 00 end The first 4 numbers is the opcode. The second is the data type. Make sure that if you use the correct data type! On the data types pages I posted, I included the size. Each 2 numbers in our hex..end structure is 1 byte. We used two 0's for the 0 part of our wait command. So we need data type 4, which says it's for sizes of 1 byte. We can use any number up to 255 (FF), because this is the maximum number we can make with 2 hexadecimal digits. One up from FF is 100 (which we should write as 0100)... Which is 4 bytes. Easy peasy? Didn't think so... 3 00 is special. It does nothing, really. It can be either used as a number (0) or as an indicator, to tell the game we have finished writing a string or a line of code. It's great, though... We can insert them nearly anywhere and it won't matter (except waste a couple of bytes of memory). Still, try and use them properly... Let's create a panel with this method and store it in 8@! CODE 08D4: 0@ = create_panel_with_title 'TITLE' position 29.0 170.0 width 180.0 columns 1 interactive 1 background 1 alignment 0 Should be written as: CODE hex // opcode D408 // 08D4: // title 09 54 49 54 4C 45 00 // 'TITLE' // position x 06 29 // 29.0 // position y 06 AA // 170.0 // width 06 50 // 80.0 // columns 04 01 // 1 // interactive 04 01 // 1 // background 04 01 // 1 // alignment 04 00 // 0 // variable (to store the panel in) 03 08 // 8@ // End 00 end To get a conversion from float to hex, see here: Decimal to Float. If it's a whole number (16.0), you can just enter the hex value for 16. Remember: Sanny changes the order of the parameters from the order we'd usually write them in (if doing it in hex). So we need to make sure everything is in the right order. In the above example, "03 08" comes last, to signify that we want to store this in a local variable and that we want it to be stored in local variable # 08... Which is 8@. It's all simple, really. You already know it. You just have to get used to not seeing text between each parameter. Keep practising. Soon you'll become a pro at writing mods in hex. -------------------- | CLEO 4.3.22 | A?i?a?o?3D | UI SDK | Black Market Mod 1.0.1 | GInput 0.3 | Cheat Keyboard | Tactile Cheat Activation | Stream Ini Extender 0.7 | SuperVars | ScrDebug | Vigilante Justice: San Andreas | |
Apr 19 2010, 01:50 AM Post #3 | |
Coding like a Rockstar! Posts: 1,468 From: ??? Joined: 28-May 09 | Making a mod write to itself! Here we are! You may have had to read this over a few times. Since CLEO 4 is reaching stages where bugs are rare, to make this part of the tutorial easier, I'll show you how to use an opcode that saves you a whole load of code writing. This opcode tells us where a specific thread in our script is. CODE 0AC6: 0@ = label @label offset With this, we can start writing to that particular thread using memory. 0@ is now our memory address. It is indeed a direct address to that part of our code. We could now write stuff to that section while the game is loaded. But it's hard to just go writing stuff to any random thread. The best thing to do is to create a special thread just for writing stuff to. CODE :ThreadMemory // We can now use a hex...end structure to create some bytes for us to write to. hex 00 00 00 00 00 00 00 00 end In this example, I've created a thread with 16 bytes. This means we can write up to 16 bytes of information to it. Now all we have to do is get to the bit we want to write to, then write to it. CODE 0AC6: 0@ = label @ThreadMemory offset 0A8C: write_memory 0@ size 2 value 200 virtual_protect 0 Now I have written the value "200" to :ThreadMemory - If we could see the changes, it would look like this: CODE :ThreadMemory hex C8 00 00 00 00 00 00 00 end C8 is 200 in hex. Only the first 2 bytes are used, the rest is left untouched. Note that if we are only writing 1 byte, the maximum integer value we can write is 255 (0xFF). If we write 2 bytes, the maximum integer value is 65535 (0xFFFF). 4 bytes is... Well, the number is huge. Google it If you want to write a float, just use 4 bytes. I'm not too sure on the specifics of how much a float value takes up. But remember that 232.0 is the same as 232. Now how do we write to the second set of 00's? Well I'll show you.. And assume the value we want to write is over 255. CODE 0AC6: 0@ = label @ThreadMemory offset 000A: 0@ += 2 // skip the first 2 bytes we wrote 0A8C: write_memory 0@ size 4 value 1924 virtual_protect 0 This time, I skipped the first 2 bytes using simple math. Reading memory uses the same concept. Let's read the first 2 bytes we wrote. CODE 0AC6: 0@ = label @ThreadMemory offset 0A8D: 1@ = read_memory 0@ size 2 virtual_protect 0 Note that if we read more than 4 bytes, the rest of the bytes are written to 2@, 3@ etc. It's 4 bytes per variable by default. That's basically it! We can do more advanced things with this power also. But I'll leave that to you to think of for now -------------------- | CLEO 4.3.22 | A?i?a?o?3D | UI SDK | Black Market Mod 1.0.1 | GInput 0.3 | Cheat Keyboard | Tactile Cheat Activation | Stream Ini Extender 0.7 | SuperVars | ScrDebug | Vigilante Justice: San Andreas | |
Aug 15 2010, 11:02 AM Post #4 | |
Member Posts: 197 From: Liberty City, Shoreside Joined: 15-July 10 | I know that its possible to use the assembler's code in hex..end construction, can you please show a simple example? |
Aug 15 2010, 03:23 PM Post #5 | |
Coding like a Rockstar! Posts: 1,468 From: ??? Joined: 28-May 09 | I don't know much ASM. Really all I know is how to read and get the basic idea of what any ASM code is doing... Probably the best I can do is to write memory via ASM. Seemann already made a good topic about this in Russian. SANNY 0@ = -429863 &0(0@,1i) = 0xA49960 &0(0@,1i) += @__AsmInjection 0572: 1 &0(0@,1i) = 0 //............. :__AsmInjection hex 81 05 50CEB700 E8030000 // add [0xB7CE50], 1000 C3 // return end It "adds" 1000 to address B7CE50, the address handling the players cash. add is a really simple ASM command, as is mov, so it's pretty easy to write memory via ASM, but we already have opcodes for that... View the topic here. Problem is, I'm not sure how to get this to work in a CLEO Script... I assumed using: SANNY 0A9F: 0@ = current_thread_pointer Would work, but I can't figure it out right now. EDIT Okay... Managed to figure it out SANNY {$CLEO} 0000: while 80E1: not player 0 pressed_key 4 wait 0 end 0AC6: 1@ = label @__AsmInjection offset 0@ = -429863 0006: &0(0@,1i) = 1@ //0xA49960 0572: 1 0A93: end_custom_thread :__AsmInjection hex 81 05 50CEB700 E8030000 // add [0xB7CE50], 1000 C3 // return end Press the ACTION key to add $1000 to your current cashsum. Works through CLEO 4, but should be possible in CLEO 3 in a longer process, too. -------------------- | CLEO 4.3.22 | A?i?a?o?3D | UI SDK | Black Market Mod 1.0.1 | GInput 0.3 | Cheat Keyboard | Tactile Cheat Activation | Stream Ini Extender 0.7 | SuperVars | ScrDebug | Vigilante Justice: San Andreas | |
Aug 16 2010, 08:41 PM Post #6 | |
Member Posts: 197 From: Liberty City, Shoreside Joined: 15-July 10 | Thanks, it works=) |
Aug 16 2010, 10:20 PM Post #7 | |
Devil's Advocate Posts: 413 From: CA US Joined: 26-July 09 | Errm so... if we wanted to store an actor in our thread we would do: SANNY {$CLEO .cs} // ... Actor.Create(1@, CivMale, _Model, _PX, _PY, PZ) // ... 0AC6: 0@ = label @ThreadMemory offset 0A8C: write_memory 0@ size 4 value 1@ virtual_protect 0 // ... :ThreadMemory hex 00 00 00 00 end Is that how it works? EDIT lol wow just realized that I'm an Advanced Member now. How/When did that happen? This post has been edited by Adler: Aug 16 2010, 10:25 PM -------------------- |
Aug 16 2010, 10:26 PM Post #8 | |
Coding like a Rockstar! Posts: 1,468 From: ??? Joined: 28-May 09 | Post count says you're advanced I also fixed things so you can change that member title now via "My Controls > Edit Profile". Yes, that code would work fine. -------------------- | CLEO 4.3.22 | A?i?a?o?3D | UI SDK | Black Market Mod 1.0.1 | GInput 0.3 | Cheat Keyboard | Tactile Cheat Activation | Stream Ini Extender 0.7 | SuperVars | ScrDebug | Vigilante Justice: San Andreas | |
Aug 16 2010, 11:10 PM Post #9 | |
Devil's Advocate Posts: 413 From: CA US Joined: 26-July 09 | Haha cool. And thanks for this TUT it'll be very useful! -------------------- |