Skip to content

Commit

Permalink
docs: update hook guide
Browse files Browse the repository at this point in the history
  • Loading branch information
Dofes committed Jan 9, 2025
1 parent 69c5fff commit b5562c2
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 51 deletions.
43 changes: 20 additions & 23 deletions docs/main/developer_guides/how_to_guides/hook_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ In [`ll/api/memory/Hook.h`](https://github.com/LiteLDev/LeviLamina/blob/develop/
#define LL_AUTO_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...)
```
The AUTO-marked Hooks automatically register, i.e., call the hook() function to register at runtime.
The TYPED-marked Hooks inherit your DEF_TYPE to the specified type.
The `AUTO`-marked Hooks automatically register, i.e., call the `hook()` function to register at runtime.
The `TYPED`-marked Hooks inherit your `DEF_TYPE` to the specified type.
### STATIC_HOOK
Expand All @@ -50,59 +50,56 @@ For hooking member functions.
!!! note
Generally, unless there's a special need, we do not recommend a very high priority; Normal is sufficient.
`TYPE`: The type to which your defined DEF_TYPE is inherited.
`TYPE`: The type to which your defined `DEF_TYPE` is inherited.
`IDENTIFIER`: The identifier used for the Hook lookup function, which can be: [function's decorated name](https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170), function bytecode, function definition.
`IDENTIFIER`: The identifier used for the Hook lookup function, which can be: [function's decorated name](https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170), function bytecode, or function definition.
`RET_TYPE`: The return type of the Hook function.
`...`: The parameter list of the Hook function.
## Using Hooks
You can refer to static program analysis tools, such as IDA Pro, to obtain the symbols or signatures of the functions you want to Hook.
Or refer to the [`Fake Header`](https://github.com/LiteLDev/LeviLamina/tree/develop/src/mc) provided by LeviLamina to obtain the symbols or definitions of the functions you want to Hook.
You can refer to the [`Fake Header`](https://github.com/LiteLDev/LeviLamina/tree/develop/src/mc) provided by LeviLamina to obtain the definitions of the functions you want to Hook.
### A Simple Hook Example
```cpp
#include "ll/api/Logger.h"
#include "mc/server/common/DedicatedServer.h"
#include "ll/api/memory/Hook.h"
#include "ll/api/io/LoggerRegistry.h"
#include "mc/server/DedicatedServer.h"
ll::Logger dedicatedServerLogger("DedicatedServer");
auto dedicatedServerLogger = ll::io::LoggerRegistry::getInstance().getOrCreate("DedicatedServer");
LL_AUTO_TYPE_INSTANCE_HOOK(
DedicatedServerHook,
DedicatedServerCtorHook,
ll::memory::HookPriority::Normal,
DedicatedServer,
"??0DedicatedServer@@QEAA@XZ",
void
&DedicatedServer::$ctor,
void*
) {
origin();
dedicatedServerLogger.info("DedicatedServer::DedicatedServer");
dedicatedServerLogger->info("DedicatedServer::DedicatedServer");
return origin();
}
```

This code hooks the constructor of DedicatedServer and prints a log message when the constructor is called.
This code hooks the constructor of `DedicatedServer` and prints a log message when the constructor is called.

Analysis:
#### Analysis:

Referring to the [`DedicatedServer.h`](https://github.com/LiteLDev/LeviLamina/blob/cccef6a0307cdcd89342d25f4826271ac298b6a8/src/mc/server/common/DedicatedServer.h#L59C31-L59C32) provided by LeviLamina, we know that the symbol for DedicatedServer's constructor is `??0DedicatedServer@@QEAA@XZ`.
Referring to the [`DedicatedServer.h`](https://github.com/LiteLDev/LeviLamina/blob/594d6897525f902c457428bbbc5bc9fe20305fb8/src/mc/server/DedicatedServer.h#L134) provided by LeviLamina, we know that the constructor of `DedicatedServer` has a thunk function.

Since the constructor is a member function of the class, we used the `INSTANCE_HOOK` type of Hook, which means we don't need to fill in the first [`this pointer`](https://en.cppreference.com/w/cpp/language/this) parameter generated by the compiler.

We used the `AUTO`-marked Hook because we want it to automatically register when the mod is loaded.

Finally, for convenience, we used the `TYPE`-marked Hook, so we can directly call functions under the DedicatedServer type in the function body. Although we did not use it in this code, it is a good habit.
Finally, for convenience, we used the `TYPE`-marked Hook, so we can directly call functions under the `DedicatedServer` type in the function body. Although we did not use it in this code, it is a good habit.

### Registering and Unloading Hooks

#### Registration

For non-automatically registered Hooks, you need

to call the `hook()` function to register at the moment your mod needs to register the Hook.
For non-automatically registered Hooks, you need to call the `hook()` function to register at the moment your mod needs to register the Hook.

#### Unloading

Expand All @@ -112,4 +109,4 @@ All Hooks will automatically unload when BDS unloads. You can also call the `unh

Hook is a very powerful technique but also a double-edged sword. If used improperly, it can cause crashes of the BDS core or mods, and in severe cases, affect the game saves.

Therefore, please be cautious when using Hooks, check your code carefully to avoid unnecessary errors.
Therefore, please be cautious when using Hooks, and check your code carefully to avoid unnecessary errors.
54 changes: 26 additions & 28 deletions docs/main/developer_guides/how_to_guides/hook_guide.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ Hook 是一种在运行时修改函数行为的技术。通常用于在不修改

wikipedia 关于 Hook 的解释:[Hooking](https://en.wikipedia.org/wiki/Hooking)

在 LeviLamina 中,我们提供了封装好的Hook API,使得你可以快速便捷地对 Minecraft 基岩专用服务器(下文称为```BDS```)中的游戏函数进行行为修改。
在 LeviLamina 中,我们提供了封装好的Hook API,使得你可以快速便捷地对 Minecraft 基岩专用服务器(下文称为`BDS`)中的游戏函数进行行为修改。

## Hook的类型

[```ll/api/memory/Hook.h```](https://github.com/LiteLDev/LeviLamina/blob/develop/src/ll/api/memory/Hook.h#L180C1-L180C1) 中,我们定义了以下几种Hook 宏:
[`ll/api/memory/Hook.h`](https://github.com/LiteLDev/LeviLamina/blob/develop/src/ll/api/memory/Hook.h#L180C1-L180C1) 中,我们定义了以下几种Hook 宏:

```cpp
#define LL_TYPE_STATIC_HOOK(DEF_TYPE, PRIORITY, TYPE, IDENTIFIER, RET_TYPE, ...)
Expand All @@ -30,8 +30,7 @@ wikipedia 关于 Hook 的解释:[Hooking](https://en.wikipedia.org/wiki/Hookin
#define LL_AUTO_INSTANCE_HOOK(DEF_TYPE, PRIORITY, IDENTIFIER, RET_TYPE, ...)
```
其中,AUTO 标注的 Hook 会自动注册,即运行时自动调用hook()函数进行注册。
TYPED 标注的 Hook 会给你的 DEF_TYPE 继承到你指定的类型。
其中,AUTO 标注的 Hook 会自动注册,即运行时自动调用hook()函数进行注册。 TYPE 标注的 Hook 会给你的 DEF_TYPE 继承到你指定的类型。
### STATIC_HOOK
Expand All @@ -43,68 +42,67 @@ TYPED 标注的 Hook 会给你的 DEF_TYPE 继承到你指定的类型。
## Hook的参数解释
```DEF_TYPE```:你给你这个 Hook 的起的类型名。
`DEF_TYPE`:你给你这个 Hook 的起的类型名。
```PRIORITY```:[Hook的优先级](https://github.com/LiteLDev/LeviLamina/blob/develop/src/ll/api/memory/Hook.h#L73),例如```ll::memory::HookPriority::Normal```
`PRIORITY`:[Hook的优先级](https://github.com/LiteLDev/LeviLamina/blob/develop/src/ll/api/memory/Hook.h#L73),例如`ll::memory::HookPriority::Normal`
!!! note
一般不是特殊需求,我们不推荐过高的优先级,Normal 即可。
```TYPE```:你的定义的 DEF_TYPE 继承到的类型。
`TYPE`:你的定义的 `DEF_TYPE` 继承到的类型。
```IDENTIFIER```:Hook 的查询函数使用的标识符,可以为:[函数修饰后名称](https://learn.microsoft.com/zh-cn/cpp/build/reference/decorated-names?view=msvc-170),函数的字节码,函数定义。
`IDENTIFIER`:Hook 的查询函数使用的标识符,可以为:[函数修饰后名称](https://learn.microsoft.com/zh-cn/cpp/build/reference/decorated-names?view=msvc-170),函数的字节码,函数定义。
```RET_TYPE```:Hook 的函数的返回值类型。
`RET_TYPE`:Hook 的函数的返回值类型。
```...```:Hook 的函数的参数列表。
`...`:Hook 的函数的参数列表。
## Hook的使用
你可以查阅静态程序分析工具,例如 IDA Pro,来获取你想要Hook的函数的符号或特征码。
或者查阅 LeviLamina 提供的[```Fake Header```](https://github.com/LiteLDev/LeviLamina/tree/develop/src/mc)来获取你想要 Hook 的函数的符号或者定义。
你可以查阅 LeviLamina 提供的[`Fake Header`](https://github.com/LiteLDev/LeviLamina/tree/develop/src/mc)来获取你想要 Hook 的函数的定义。
### 简单的Hook示例
```cpp
#include "ll/api/Logger.h"
#include "mc/server/common/DedicatedServer.h"
#include "ll/api/memory/Hook.h"
#include "ll/api/io/LoggerRegistry.h"
#include "mc/server/DedicatedServer.h"
ll::Logger dedicatedServerLogger("DedicatedServer");
auto dedicatedServerLogger = ll::io::LoggerRegistry::getInstance().getOrCreate("DedicatedServer");
LL_AUTO_TYPE_INSTANCE_HOOK(
DedicatedServerHook,
DedicatedServerCtorHook,
ll::memory::HookPriority::Normal,
DedicatedServer,
"??0DedicatedServer@@QEAA@XZ",
void
&DedicatedServer::$ctor,
void*
) {
origin();
dedicatedServerLogger.info("DedicatedServer::DedicatedServer");
dedicatedServerLogger->info("DedicatedServer::DedicatedServer");
return origin();
}
```

这段代码会 Hook DedicatedServer 的构造函数,并在构造函数被调用时打印一条日志。

解析:
#### 解析:

根据查阅 LeviLamina 提供的[```DedicatedServer.h```](https://github.com/LiteLDev/LeviLamina/blob/cccef6a0307cdcd89342d25f4826271ac298b6a8/src/mc/server/common/DedicatedServer.h#L59C31-L59C32) ,我们可以知道 DedicatedServer 的构造函数的符号为 ```??0DedicatedServer@@QEAA@XZ```
根据查阅 LeviLamina 提供的[`DedicatedServer.h`](https://github.com/LiteLDev/LeviLamina/blob/594d6897525f902c457428bbbc5bc9fe20305fb8/src/mc/server/DedicatedServer.h#L134),我们可以得到 DedicatedServer 的构造函数的thunk函数

又由于构造函数是类的成员函数,所以我们使用了 ```INSTANCE_HOOK```类型的 Hook,这使我们不需要填写由编译器产生的第一个[```this指针```](https://zh.cppreference.com/w/cpp/language/this)参数。
又由于构造函数是类的成员函数,所以我们使用了`INSTANCE_HOOK`类型的Hook,这使我们不需要填写由编译器产生的第一个[`this指针`](https://zh.cppreference.com/w/cpp/language/this)参数。

又由于我们希望在模组被加载的时候自动注册,所以我们使用了 ```AUTO```标注的 Hook。
又由于我们希望在模组被加载的时候自动注册,所以我们使用了 `AUTO`标注的 Hook。

最后由于方便,我们使用了 ```TYPE```标注的 Hook,使得我们可以直接在函数体内调用 DedicatedServer 类型下的函数,虽然在这段代码中我们并没有使用到,但是这是一个好习惯。
最后由于方便,我们使用了 `TYPE`标注的 Hook,使得我们可以直接在函数体内调用 DedicatedServer 类型下的函数,虽然在这段代码中我们并没有使用到,但是这是一个好习惯。

### Hook的注册和卸载

#### 注册

针对非自动注册的 Hook,你需要在你模组需要注册 Hook 的时机调用```hook()```函数进行注册。
针对非自动注册的 Hook,你需要在你模组需要注册 Hook 的时机调用`hook()`函数进行注册。

#### 卸载

所有的 Hook 都会在 BDS 卸载时自动卸载,你也可以在你模组需要卸载 Hook 的时机调用```unhook()```函数进行卸载。
所有的 Hook 都会在 BDS 卸载时自动卸载,你也可以在你模组需要卸载 Hook 的时机调用`unhook()`函数进行卸载。

## 写在最后

Expand Down

0 comments on commit b5562c2

Please sign in to comment.