Tutorials

 Reply to this postStart new topic

[CLEO|TuT]Using Thread memory

Deji
post Apr 18 2010, 02:14 AM
Post #1


Coding like a Rockstar!

Group Icon

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 smile.gif


--------------------
Go to the top of the page
 
+Quote Post
Deji
post Apr 19 2010, 12:18 AM
Post #2


Coding like a Rockstar!

Group Icon

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 smile.gif), 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.


--------------------
Go to the top of the page
 
+Quote Post
Deji
post Apr 19 2010, 01:50 AM
Post #3


Coding like a Rockstar!

Group Icon

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 wink.gif

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 smile.gif


--------------------
Go to the top of the page
 
+Quote Post
DK22
post 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?
Go to the top of the page
 
+Quote Post
Deji
post Aug 15 2010, 03:23 PM
Post #5


Coding like a Rockstar!

Group Icon

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 smile.gif

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.


--------------------
Go to the top of the page
 
+Quote Post
DK22
post Aug 16 2010, 08:41 PM
Post #6


Member

Posts: 197
From: Liberty City, Shoreside
Joined: 15-July 10



Thanks, it works=)
Go to the top of the page
 
+Quote Post
Adler
post Aug 16 2010, 10:20 PM
Post #7


Devil's Advocate

Group Icon

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? bunny.gif

This post has been edited by Adler: Aug 16 2010, 10:25 PM


--------------------
Go to the top of the page
 
+Quote Post
Deji
post Aug 16 2010, 10:26 PM
Post #8


Coding like a Rockstar!

Group Icon

Posts: 1,468
From: ???
Joined: 28-May 09



Post count says you're advanced smile.gif I also fixed things so you can change that member title now via "My Controls > Edit Profile".

Yes, that code would work fine.


--------------------
Go to the top of the page
 
+Quote Post
Adler
post Aug 16 2010, 11:10 PM
Post #9


Devil's Advocate

Group Icon

Posts: 413
From: CA US
Joined: 26-July 09



Haha cool. And thanks for this TUT it'll be very useful! cool.gif


--------------------
Go to the top of the page
 
+Quote Post
Reply to this postStart new topic

2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members: