Skip to content

Commit

Permalink
0.8.4 release
Browse files Browse the repository at this point in the history
  • Loading branch information
x87 committed Dec 17, 2021
1 parent 6422938 commit 8c40c07
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 14 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
### 0.8.4 - Dec 17, 2021

- for San Andreas: The Definitive Edition:
- new opcodes `0C06 WRITE_MEMORY` and `0C07 READ_MEMORY`, as well as corresponding JavaScript commands: `Memory.Write` and `Memory.Read`. [Read the guide](using-memory-64.md) for more information
- fixed an issue with opcodes `0C01`, `0C02`, `0C03`, `0C04` crashing the game

- for all games:
- improved stability of JS scripts (https://github.com/cleolibrary/CLEO-Redux/issues/22)
- fixed an issue when scripts permissions were not validated for CLEO scripts

#### BREAKING CHANGES

CLEO Redux for San Andreas: The Definitive Edition now uses `sa_unreal.json` from https://github.com/sannybuilder/library.

| Game | Minumum Required Version |
| --- | --- |
| GTA III, re3 | `0.200`
| GTA VC, reVC | `0.201`
| GTA San Andreas (Classic) 1.0 | `0.202`
| San Andreas: The Definitive Edition | `0.204`

### 0.8.3 - Dec 8, 2021

- fixed a critical bug in CS scripts scheduler causing abnormal behavior (mostly resulting in slow execution) (https://github.com/cleolibrary/CLEO-Redux/issues/21)
Expand Down
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ At the moment CLEO Redux only supports San Andreas: The Definitive Edition `1.0.
- function `showTextBox` does not work in JS scripts
- opcodes for custom commands are different, only a few are supported:

- 0C00 [IS_KEY_PRESSED](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C00?p=2&v=4)
- 0C01 [INT_ADD](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C01?p=2&v=4)
- 0C02 [INT_SUB](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C02?p=2&v=4)
- 0C03 [INT_MUL](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C03?p=2&v=4)
- 0C04 [INT_DIV](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C04?p=2&v=4)
- 0C05 [TERMINATE_THIS_CUSTOM_SCRIPT](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C05?p=2&v=4)
- 0C00 [IS_KEY_PRESSED](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C00)
- 0C01 [INT_ADD](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C01)
- 0C02 [INT_SUB](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C02)
- 0C03 [INT_MUL](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C03)
- 0C04 [INT_DIV](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C04)
- 0C05 [TERMINATE_THIS_CUSTOM_SCRIPT](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C05)
- 0C06 [WRITE_MEMORY](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C06)
- 0C07 [READ_MEMORY](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C07)

- Sanny Builder does not support these new opcodes out-of-the-box yet. To enable new opcodes in your CS scripts add the following lines on top of your script:

Expand All @@ -113,6 +115,8 @@ At the moment CLEO Redux only supports San Andreas: The Definitive Edition `1.0.
{$O 0C03=3,%3d% = %1d% * %2d% }
{$O 0C04=3,%3d% = %1d% / %2d% }
{$O 0C05=0,terminate_this_custom_script }
{$O 0C06=5,write_memory %1d% size %2d% value %3d% virtual_protect %4d% ib %5d% }
{$O 0C07=5,%5d% = read_memory %1d% size %2d% virtual_protect %3d% ib %4d% }
```

Use SA Mobile mode to compile CLEO scripts for San Andreas: The Definitive Edition.
Expand Down Expand Up @@ -244,13 +248,14 @@ This line instructs VS Code where to look for the commands definitions for the a

### Prerequisites

When JavaScript is enabled CLEO Redux needs commands definitions from https://library.sannybuilder.com/. On the first run CLEO tries to download the necessary files and puts them into your local `CLEO/.config` directory. If that did not happen, or you don't want to let CLEO make network calls, manually download [gta3.json](https://github.com/sannybuilder/library/blob/master/gta3/gta3.json), [vc.json](https://github.com/sannybuilder/library/blob/master/vc/vc.json), or [sa.json](https://github.com/sannybuilder/library/blob/master/sa/sa.json) and place them in the `CLEO/.config` directory.
When JavaScript is enabled CLEO Redux needs commands definitions from https://library.sannybuilder.com/. On the first run CLEO tries to download them and put into your local `CLEO/.config` directory. If that did not happen, or you don't want to let CLEO make network calls, manually download a required file (see the table below) and place it in the `CLEO/.config` directory.

Minimum required version of the commands definitions:

- `gta3.json`: `0.100`
- `vc.json`: `0.145`
- `sa.json`: `0.175`
| Game | File | Minumum Required Version |
| --- | --- | --- |
| GTA III, re3 | [gta3.json](https://github.com/sannybuilder/library/blob/master/gta3/gta3.json) | `0.200`
| GTA VC, reVC | [vc.json](https://github.com/sannybuilder/library/blob/master/vc/vc.json) | `0.201`
| GTA San Andreas (Classic) 1.0 | [sa.json](https://github.com/sannybuilder/library/blob/master/sa/sa.json) | `0.202`
| San Andreas: The Definitive Edition | [sa_unreal.json](https://github.com/sannybuilder/library/blob/master/sa_unreal/sa_unreal.json) | `0.204`

### Script Lifecycle

Expand Down
116 changes: 116 additions & 0 deletions using-memory-64.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
Note: This guide is for the remastered games running as 64-bit applications. For the information on using the Memory class in classic era games [click here](./using-memory.md).

## Using Memory Object

An intrinsic object `Memory` provides methods for accessing and manipulating the data or code in the current process. It has the following interface:

```ts
interface Memory {
ReadFloat(address: int, vp: boolean, ib: boolean): float;
WriteFloat(address: int, value: float, vp: boolean, ib: boolean): void;
ReadI8(address: int, vp: boolean, ib: boolean): int;
ReadI16(address: int, vp: boolean, ib: boolean): int;
ReadI32(address: int, vp: boolean, ib: boolean): int;
ReadU8(address: int, vp: boolean, ib: boolean): int;
ReadU16(address: int, vp: boolean, ib: boolean): int;
ReadU32(address: int, vp: boolean, ib: boolean): int;
WriteI8(address: int, value: int, vp: boolean, ib: boolean): void;
WriteI16(address: int, value: int, vp: boolean, ib: boolean): void;
WriteI32(address: int, value: int, vp: boolean, ib: boolean): void;
WriteU8(address: int, value: int, vp: boolean, ib: boolean): void;
WriteU16(address: int, value: int, vp: boolean, ib: boolean): void;
WriteU32(address: int, value: int, vp: boolean, ib: boolean): void;
Read(address: int, size: int, vp: boolean, ib: boolean): int;
Write(address: int, size: int, value: int, vp: boolean, ib: boolean): void;

ToFloat(value: int): float;
FromFloat(value: float): int;
ToU8(value: int): int;
ToU16(value: int): int;
ToU32(value: int): int;
ToI8(value: int): int;
ToI16(value: int): int;
ToI32(value: int): int;

Translate(symbol: string): int;
}
```

### Reading and Writing Values

Group of memory access methods (`ReadXXX`/`WriteXXX`) can be used for reading or modifying values stored in the memory. Each method is designed for a particular data type. To change a floating-point value (which occupies 4 bytes in the original game) use `Memory.WriteFloat`, e.g.:

```js
Memory.WriteFloat(address, 1.0, false, false)
```

where `address` is a variable storing the memory location, `1.0` is the value to write, the first `false` means it's not necessary to change the memory protection with `VirtualProtect` (the address is already writable). The second `false` is the value of the `ib` flag that instructs CLEO to treat the `address` either as an absolute address (`ib` = `false`) or a relative offset to the current image base address (`ib` = `true`). As the definitive editions use the ASLR feature their absolute memory addresses change when the game runs because the start address changes. Consider the following example:

```
0x1400000000 ImageBase
...
...
0x1400000020 SomeValue
```
You want to change `SomeValue` that is currently located at `0x1400000020`. You can do it with `Memory.Write(0x1400000020, 1, 1, false, false)`. However on the next game run the memory layout might look like this:

```
0x1500000000 ImageBase
...
...
0x1500000020 SomeValue
```

effectively breaking the script. In this case, calculate a relative offset from the image base ( `0x1500000020` - `0x1500000000` = `0x20` ), that will be permanent for the particular game version. Use Memory.Write as follows: `Memory.Write(0x20, 1, 1, false, true)`. CLEO will sum up the offset (`0x20`) with the current value of the image base (`0x1400000000`, `0x1500000000`, etc) and write to the correct absolute address.

For your convenience you can find the current value of the image base in the `cleo_redux.log`, e.g.:

```
09:27:35 [INFO] Image base address 0x7ff7d1f50000
```

Similarly, to read a value from the memory, use one of the `ReadXXX` methods, depending on what data type the memory address contains. For example, to read a 8-bit signed integer (also known as a `char` or `uint8`) use `Memory.ReadI8`, e.g.:

```js
var x = Memory.ReadI8(offset, true, true)
```

variable `x` now holds a 8-bit integer value in the range (0..255). For the sake of showing possible options, this example uses `true` as the last argument, which means the default protection attribute for this address will be changed to `PAGE_EXECUTE_READWRITE` before the read.

```js
var gravity = Memory.ReadFloat(gravityOffset, false, true);
gravity += 0.05;
Memory.WriteFloat(gravityOffset, gravity, false, true);
```

Finally, last two methods `Read` and `Write` is what other methods use under the hood. They have direct binding to the Rust code that reads and write the memory. In JavaScript code you can use input arguments as large as 53-bit numbers.

The `size` parameter in the `Read` method can only be `1`, `2` or `4`. CLEO treats the `value` as a signed integer stored in the little-endian format.

In the `Write` method any `size` larger than `0` is allowed. Sizes `3` and `5` onwards can only be used together with a single byte `value`. CLEO uses them to fill a continious block of memory starting at the `address` with the given `value` (think of it as `memset` in C++).

```js
Memory.Write(offset, 0x90, 10, true, true) // "noping" 10 bytes of code starting from offset+image base
```

**Note that usage of any of the read/write methods requires the `mem` [permission](README.md#Permissions)**.


### Casting methods

By default `Read` and `Write` methods treat data as signed integer values. It can be inconvinient if the memory holds a floating-point value in IEEE 754 format or a large 32-bit signed integer (e.g. a pointer). In this case use casting methods `ToXXX`/`FromXXX`. They act similarly to [reinterpret_cast](https://docs.microsoft.com/en-us/cpp/cpp/reinterpret-cast-operator?view=msvc-160) operator in C++.

To get a quick idea what to expect from those methods see the following examples:

```js
Memory.FromFloat(1.0) => 1065353216
Memory.ToFloat(1065353216) => 1.0
Memory.ToU8(-1) => 255
Memory.ToU16(-1) => 65535
Memory.ToU32(-1) => 4294967295
Memory.ToI8(255) => -1
Memory.ToI16(65535) => -1
Memory.ToI32(4294967295) => -1
```

Alternatively, use appropriate methods to read/write the value as a float (`ReadFloat`/`WriteFloat`) or as an unsigned integer (`ReadUXXX`/`WriteUXXX`).
4 changes: 3 additions & 1 deletion using-memory.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Note: This guide is for the classic era games. For the information on using the Memory class in the definitive editions [click here](./using-memory-64.md).

## Using Memory Object

An intrinsic object `Memory` provides methods for accessing and manipulating the data or code in the current process. It has the following interface:
Expand Down Expand Up @@ -77,7 +79,7 @@ Group of memory access methods (`ReadXXX`/`WriteXXX`) can be used for reading or

where `address` is a variable storing the memory location, `1.0` is the value to write and `false` means it's not necessary to change the memory protection with `VirtualProtect` (the address is already writable).

Similarly, to read a value from the memory, use one of the `ReadXXX` methods, depending on what data type the memory address contains. For example, to read a 8-bit signed integer (also known as a `char` or `uint8`) use `Memory.ReadI8`, e.g.:
Similarly, to read a value from the memory, use one of the `ReadXXX` methods, depending on what data type the memory address contains. For example, to read a 8-bit signed integer (also known as a `char` or `uint8`) use `Memory.ReadI8`, e.g.:

```js
var x = Memory.ReadI8(address, true)
Expand Down
2 changes: 1 addition & 1 deletion website/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ <h1 class="font-weight-bold d-flex justify-content-center">
href="https://github.com/cleolibrary/CLEO-Redux/releases/latest"
>Download</a
>
<small class="pt-1 text-muted">v0.8.3 | Dec 8, 2021</small>
<small class="pt-1 text-muted">v0.8.4 | Dec 17, 2021</small>
</div>
</div>
</div>
Expand Down

0 comments on commit 8c40c07

Please sign in to comment.