|
1 | 1 | # ChuModLoader |
2 | 2 |
|
3 | | -Mod loading framework for CHUNITHM. Proxies `version.dll` to load mod DLLs from `mods/` at runtime. |
| 3 | +[English](README.en.md) | 简体中文 |
4 | 4 |
|
5 | | -> **[中文说明](README_cn.md)** |
| 5 | +CHUNITHM Mod 加载框架。通过代理 `version.dll`,在游戏启动时自动从 `mods/` 目录加载 mod DLL。 |
6 | 6 |
|
7 | | -> **v2.0.0** — Loader rewritten from C++ to Rust. Mod C ABI unchanged; existing mod DLLs work without modification. C++ mods remain fully supported via `chumod.h` — the header is maintained alongside the Rust codebase and will continue to receive updates. Legacy C++ loader code at tag [`v1.0.0-cpp`](https://github.com/Applesaber/ChuModLoader/tree/v1.0.0-cpp). |
| 7 | +## 功能 |
8 | 8 |
|
9 | | -## Features |
| 9 | +- `version.dll` 代理,转发全部 17 个系统导出 |
| 10 | +- 自动扫描 `mods/*.dll` 加载 |
| 11 | +- Mod API (C ABI):内存读写、AOB 扫描、inline hook、RTTI vtable 查找、mod 间通信 |
| 12 | +- TOML / INI 配置 API |
| 13 | +- 分级日志 (info/warn/error) + 控制台颜色 + per-mod 日志文件 |
| 14 | +- 依赖拓扑排序 |
| 15 | +- 崩溃保护 (catch_unwind) |
| 16 | +- 游戏版本检测 + min_loader_version 检查 |
| 17 | +- 生命周期: init → on_ready → on_frame → shutdown |
| 18 | +- 热重载 (reload_mod API + reload.flag) |
| 19 | +- crash dump + 栈回溯 |
| 20 | +- Rust 编写,mod 可用 Rust、C/C++ 或任何能编译 Win32 DLL 的语言 |
10 | 21 |
|
11 | | -- `version.dll` proxy, forwards all 17 exports to the real system DLL |
12 | | -- Auto-scans `mods/*.dll` on startup, no config needed |
13 | | -- Optional Mod API (`chumod_init`) with memory read/write, AOB scan, inline hook, inter-mod IPC; plain DLLs work too |
14 | | -- `mods.ini` to disable individual mods |
15 | | -- Inline hooking via [retour](https://crates.io/crates/retour) |
16 | | -- Written in Rust, mods can be written in Rust, C/C++, or any language that produces a Win32 DLL |
| 22 | +## 安装 |
17 | 23 |
|
18 | | -## Installation |
| 24 | +1. 构建或下载 `version.dll` |
| 25 | +2. 放到游戏目录(和 `chusanApp.exe` 同级) |
| 26 | +3. 把 mod DLL 放进 `mods/` |
| 27 | +4. 正常启动游戏 |
19 | 28 |
|
20 | | -1. Build or download `version.dll` |
21 | | -2. Place it in the game directory (next to `chusanApp.exe`) |
22 | | -3. Drop mod DLLs into `mods/` |
23 | | -4. Launch the game normally |
| 29 | +## 构建 |
24 | 30 |
|
25 | | -`mods/` directory and `mods.ini` are created automatically on first run. |
26 | | - |
27 | | -## Configuration |
28 | | - |
29 | | -`mods.ini` is auto-generated in the game directory. To disable a mod: |
30 | | - |
31 | | -```ini |
32 | | -[mods] |
33 | | -mod_name.dll=0 |
34 | | -``` |
35 | | - |
36 | | -Mods not listed (or set to `1`) are loaded by default. |
37 | | - |
38 | | -### Per-Mod Configuration (v2) |
39 | | - |
40 | | -Each mod gets its own config file at `mods/config/<mod_name>.ini`, created automatically on first access. Mods read/write settings via the Config API: |
41 | | - |
42 | | -```c |
43 | | -// read with defaults (file created automatically if missing) |
44 | | -int fov = api->config_get_int("fov", 75); |
45 | | -float bloom = api->config_get_float("bloom_intensity", 1.0f); |
46 | | -int unlock = api->config_get_bool("unlock_fps", 0); |
47 | | - |
48 | | -// write (persisted to INI immediately) |
49 | | -api->config_set_int("fov", 90); |
50 | | -api->config_set_bool("unlock_fps", 1); |
51 | | -``` |
52 | | -
|
53 | | -```ini |
54 | | -; mods/config/my_mod.ini |
55 | | -[config] |
56 | | -fov=90 |
57 | | -bloom_intensity=1.0 |
58 | | -unlock_fps=true |
59 | | -``` |
60 | | - |
61 | | -## For Mod Developers |
62 | | - |
63 | | -See [Mod Development Guide](docs/mod-development.md) and [API Reference](docs/api-reference.md). |
64 | | - |
65 | | -### Quick Start (Rust) |
66 | | - |
67 | | -```rust |
68 | | -use std::ffi::{c_char, c_void}; |
69 | | - |
70 | | -#[repr(C)] |
71 | | -pub struct ChuModInfo { |
72 | | - pub api_version: u32, |
73 | | - pub loader_version: *const c_char, |
74 | | - pub game_module: *const c_char, |
75 | | - pub game_base: usize, |
76 | | - pub game_size: u32, |
77 | | - pub text_base: usize, |
78 | | - pub text_size: u32, |
79 | | -} |
80 | | - |
81 | | -#[repr(C)] |
82 | | -pub struct ChuModAPI { |
83 | | - pub struct_size: u32, |
84 | | - pub log: Option<unsafe extern "C" fn(*const c_char, ...)>, |
85 | | - // ... other fields |
86 | | -} |
87 | | - |
88 | | -#[no_mangle] |
89 | | -pub extern "C" fn chumod_name() -> *const c_char { |
90 | | - b"My Rust Mod\0".as_ptr() as *const c_char |
91 | | -} |
92 | | - |
93 | | -#[no_mangle] |
94 | | -pub unsafe extern "C" fn chumod_init( |
95 | | - info: *const ChuModInfo, |
96 | | - _api: *const ChuModAPI, |
97 | | -) -> i32 { |
98 | | - // your init code |
99 | | - 0 |
100 | | -} |
101 | | - |
102 | | -#[no_mangle] |
103 | | -pub extern "C" fn chumod_shutdown() {} |
104 | | -``` |
105 | | - |
106 | | -### Quick Start (C/C++) |
107 | | - |
108 | | -```c |
109 | | -#include "chumod.h" |
110 | | - |
111 | | -CHUMOD_API const char* chumod_name() { return "My Mod"; } |
112 | | - |
113 | | -CHUMOD_API int chumod_init(const ChuModInfo* info, const ChuModAPI* api) { |
114 | | - api->log("game base = 0x%08X, .text = 0x%08X +0x%X", |
115 | | - info->game_base, info->text_base, info->text_size); |
116 | | - return 0; |
117 | | -} |
118 | | - |
119 | | -CHUMOD_API void chumod_shutdown() { } |
120 | | -``` |
121 | | -
|
122 | | -All exports are optional. Plain DLL with `DllMain` only also works. |
123 | | -
|
124 | | -## Building |
125 | | -
|
126 | | -Requires Rust toolchain with `i686-pc-windows-msvc` target: |
| 31 | +需要 Rust nightly + `i686-pc-windows-msvc`: |
127 | 32 |
|
128 | 33 | ```bash |
129 | | -rustup toolchain install nightly --target i686-pc-windows-msvc |
130 | | -cargo +nightly build --release |
| 34 | +cargo build --release |
131 | 35 | ``` |
132 | 36 |
|
133 | | -Output: `target/i686-pc-windows-msvc/release/version.dll` |
134 | | - |
135 | | -> **C++ build**: The loader was previously built with CMake 3.15+ and MSVC (`cmake -B build -A Win32 && cmake --build build --config Release`). |
136 | | -
|
137 | | -## How It Works |
138 | | - |
139 | | -Exploits Windows DLL search order (application directory before System32): |
| 37 | +输出: `target/i686-pc-windows-msvc/release/version.dll` |
140 | 38 |
|
141 | | -1. Loads the real `version.dll` from System32, forwards exports via naked JMP |
142 | | -2. Background thread waits 2s, scans `mods/*.dll`, calls `LoadLibrary` on each |
143 | | -3. Parses PE headers for `.text` section info, calls `chumod_init` on API-exporting mods |
144 | | -4. On exit, calls `chumod_shutdown` in reverse order, then `FreeLibrary` |
| 39 | +## Mod 开发 |
145 | 40 |
|
146 | | -## Logging |
| 41 | +参见 [docs/mod-development.md](docs/mod-development.md) 和 [docs/api-reference.md](docs/api-reference.md)。 |
147 | 42 |
|
148 | | -Output to `chusan_loader.log` and console if available. Format: `[HH:MM:SS.mmm] [loader] message` |
149 | | - |
150 | | -## Project Structure |
151 | | - |
152 | | -``` |
153 | | -ChuModLoader/ |
154 | | -├── include/chumod.h # Mod API header (for C/C++ mods) |
155 | | -├── src/ |
156 | | -│ ├── lib.rs # version.dll proxy entry (DllMain + forward_dll) |
157 | | -│ ├── loader.rs # mod scanning & loading |
158 | | -│ └── api_impl.rs # API implementation (retour hooks, memory, IPC) |
159 | | -├── docs/ |
160 | | -│ ├── mod-development.md |
161 | | -│ └── api-reference.md |
162 | | -├── Cargo.toml |
163 | | -└── build.rs |
164 | | -``` |
| 43 | +头文件: [include/chumod.h](include/chumod.h) |
165 | 44 |
|
166 | | -## License |
| 45 | +## 许可证 |
167 | 46 |
|
168 | | -MIT |
| 47 | +Apache-2.0 |
0 commit comments