From 1a995e73d34290ce848133dcdea4d3e78282afba Mon Sep 17 00:00:00 2001 From: Seemann Date: Wed, 12 Jan 2022 10:51:42 -0500 Subject: [PATCH] 0.8.6 release --- CHANGELOG.md | 13 +++++++ unsupported.md | 2 ++ using-memory-64.md | 85 +++++++++++++++++++++++++++++++++++++++++++++- using-memory.md | 2 +- website/index.html | 2 +- 5 files changed, 101 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c894813..94b0488 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +### 0.8.6 - Jan 12, 2022 + +- add [CALL_FUNCTION](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C08) and [CALL_FUNCTION_RETURN](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C09) commands in San Andreas: The Definitive Edition +- add `Memory.Fn.X64` convenience methods for [calling functions from JavaScript on the x64 platform](using-memory-64.md#calling-foreign-functions) +- `showTextBox` now works in San Andreas: The Definitive Edition +- fixed an issue with FxtStore object not showing in VS Code autocomplete +- fixed an issue with text draw not working in GTA San Andreas +- fixed an issue in CLEO dev builds causing the game crash on startup while checking for an update + +#### BREAKING CHANGE + +- minimum required version of `sa_unreal.json` is `0.209` + ### 0.8.5 - Jan 1, 2022 - add support for [static FXT files](using-fxt.md#static-fxt-files) in `CLEO_TEXT` folder - add support for [private FXT storage](using-fxt.md#fxtstore) in each JS script diff --git a/unsupported.md b/unsupported.md index 96575fa..3eb1b9a 100644 --- a/unsupported.md +++ b/unsupported.md @@ -18,3 +18,5 @@ The following items are known to be not working and there is no specific timelin - commands implicitly loading models or textures (such as widgets) [Tracking issue](https://github.com/cleolibrary/CLEO-Redux/issues/12). You can circumvent the issue by preloading needed resources, e.g. by calling them in a .CS script first. - you can't call the game functions that need references to variables to store the result. There is no "take an address of the variable" syntax. + +- in x64 games (SA: DE) you can't call game functions that need floating-point values. All input arguments are treated as 64-bit signed integers. You may need to use other means to invoke the native code (e.g. DLL injection) diff --git a/using-memory-64.md b/using-memory-64.md index 1fac905..10ff474 100644 --- a/using-memory-64.md +++ b/using-memory-64.md @@ -32,7 +32,18 @@ interface Memory { ToI16(value: int): int; ToI32(value: int): int; - Translate(symbol: string): int; + CallFunction(address: int, ib: boolean, numParams: int, ...funcParams: number[]): void; + CallFunctionReturn(address: int, ib: boolean, numParams: int, ...funcParams: number[]): int; + Fn: { + X64(address: int, ib: boolean): (...funcParams: int[]) => int; + X64I8(address: int): (...funcParams: int[]) => int; + X64I16(address: int): (...funcParams: int[]) => int; + X64I32(address: int): (...funcParams: int[]) => int; + X64U8(address: int): (...funcParams: int[]) => int; + X64U16(address: int): (...funcParams: int[]) => int; + X64U32(address: int): (...funcParams: int[]) => int; + } + } ``` @@ -114,3 +125,75 @@ To get a quick idea what to expect from those methods see the following examples ``` Alternatively, use appropriate methods to read/write the value as a float (`ReadFloat`/`WriteFloat`) or as an unsigned integer (`ReadUXXX`/`WriteUXXX`). + +### Calling Foreign Functions + +`Memory` object allows to invoke a foreign (native) function by its address using one of the following methods: + +- `Memory.CallFunction` - binds to [00C8 CALL_FUNCTION](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C08) +- `Memory.CallFunctionReturn` - binds to [00C9 CALL_FUNCTION_RETURN](https://library.sannybuilder.com/#/sa_unreal/CLEO/0C09) + + +```js + Memory.CallFunction(0xEFFB30, true, 1, 13) +``` +where `0xEFFB30` is the function offset relative to IMAGE BASE (think of it a randomized start address of the game memory), `true` is the `ib` flag (see below), `1` is the number of input arguments, and `13` are the only argument passed into the function. + + +The `ib` parameter in `Memory.CallFunction` has the same meaning as in memory read/write commands. When set to `true` CLEO adds the current known address of the image base to the value provided as the first argument to calculate the absolute memory address of the function. When set to `false` no changes to the first argument are made. + +`Memory.CallFunctionReturn` has the same interface but additionally it writes the result of the function to a variable. + +CLEO Redux supports calling foreign functions with up to 16 parameters. + +**Note that usage of any of the call methods requires the `mem` [permission](README.md#Permissions)**. + +**KNOWN ISSUE** + +Due to implementation details on x64 platform CLEO currently does not support passing floating-point arguments to a callee function. You can only use integer numbers. For the same reason you can't call functions returning a floating-point value with `Memory.CallFunctionReturn`. + +#### Convenience methods with Fn object + +`Memory.Fn` provides convenient methods for calling different types of foreign functions. + +```ts + Fn: { + X64(address: int, ib: boolean): (...funcParams: int[]) => int; + X64I8(address: int): (...funcParams: int[]) => int; + X64I16(address: int): (...funcParams: int[]) => int; + X64I32(address: int): (...funcParams: int[]) => int; + X64U8(address: int): (...funcParams: int[]) => int; + X64U16(address: int): (...funcParams: int[]) => int; + X64U32(address: int): (...funcParams: int[]) => int; + } +``` + +These methods is designed to cover all supported return types. For example, this code + +```js + Memory.CallFunction(0xEFFB30, true, 1, 13) +``` + +can also be written as + +```js + Memory.Fn.X64(0xEFFB30, true)(13) +``` + +Note a few key differences here. First of all, `Memory.Fn` methods don't invoke a foreign function directly. Instead, they return a new JavaScript function that can be stored in a variable and reused to call the associated foreign function many times with different arguments: + +```js + var f = Memory.Fn.X64(0xEFFB30, true); + f(13) // calls function 0xEFFB30 with the argument of 13 + f(11) // calls method 0xEFFB30 with the argument of 11 +``` + +The second difference is that there is no `numParams` parameter. Each `Fn` method figures it out automatically. + +By default a returned result is considered a 64-bit signed integer value. If the function returns another type (e.g. a boolean), use one of the methods matching the function signature: + +```js + var flag = Memory.Fn.X64U8(0x1234567, true)() +``` + +This code invokes a function at `0x1234567` + IMAGE_BASE with no arguments and stores the result as a 8-bit unsigned integer value. diff --git a/using-memory.md b/using-memory.md index 92add41..249f83a 100644 --- a/using-memory.md +++ b/using-memory.md @@ -230,7 +230,7 @@ Note a few key differences here. First of all, `Memory.Fn` methods don't invoke The second difference is that there are no `numParams` and `pop` parameters. Each `Fn` method figures them out automatically. -By default a returned result is considered a 32-bit signed integer value. If the function something another type (a floating-point value, or a signed integer), use one of the methods matching the function signature, e.g.: +By default a returned result is considered a 32-bit signed integer value. If the function returns another type (a floating-point value, or a signed integer), use one of the methods matching the function signature, e.g.: ```js var flag = Memory.Fn.CdeclU8(0x1234567)() diff --git a/website/index.html b/website/index.html index 18a5b0c..f06ef88 100644 --- a/website/index.html +++ b/website/index.html @@ -128,7 +128,7 @@

href="https://github.com/cleolibrary/CLEO-Redux/releases/latest" >Download - v0.8.5 | Jan 01, 2022 + v0.8.6 | Jan 12, 2022