Skip to content

Commit bcf0dc7

Browse files
committed
refactor: 重构 mod 架构并集成游戏侧 IO 仿真
将 AppleChu 从纯内存补丁扩展为内置 segatools 兼容的完整 IO 仿真套件,并把 d3d9 代理/恢复逻辑迁移到 loader 托管的 ABI 回调。 - 新增 chuniio、aime、io4、slider、led、vfd 等游戏侧外设仿真模块 - 新增 iohook、platform、gfx 模块,支持 IAT hook、平台模块注入和图形初始化 - 引入 ChuModLoader submodule,并通过仓库内 chu-abi 路径构建 - 重写 lib.rs 初始化流程,新增 HookMode 诊断开关和 DLL pin - 移除自带 d3d9 代理,改用 loader 的 present callback 与 frame lock API - 新增 fast_restart、net_log 补丁,并将 autoplay 独立成模块 - 更新 manifest 与 README,补充 IO 配置和构建说明
1 parent f63164b commit bcf0dc7

71 files changed

Lines changed: 12137 additions & 1972 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "ChuModLoader"]
2+
path = ChuModLoader
3+
url = https://github.com/MuNET-OSS/ChuModLoader

Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,24 @@ name = "AppleChu"
99
crate-type = ["cdylib"]
1010

1111
[dependencies]
12+
chu-abi = { path = "ChuModLoader/chu-abi" }
1213
toml = "0.8"
1314
once_cell = "1"
15+
windows-sys = { version = "0.52", features = [
16+
"Win32_Foundation",
17+
"Win32_Devices_Communication",
18+
"Win32_Security",
19+
"Win32_Storage_FileSystem",
20+
"Win32_System_IO",
21+
"Win32_System_Kernel",
22+
"Win32_System_LibraryLoader",
23+
"Win32_System_Memory",
24+
"Win32_System_ProcessStatus",
25+
"Win32_System_Pipes",
26+
"Win32_System_Threading",
27+
"Win32_UI_Input_KeyboardAndMouse",
28+
"Win32_UI_WindowsAndMessaging",
29+
] }
1430

1531
[profile.release]
1632
lto = true

ChuModLoader

Submodule ChuModLoader added at 9a07146

README.en.md

Lines changed: 0 additions & 52 deletions
This file was deleted.

README.md

Lines changed: 81 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,103 @@
1-
# AppleChu
1+
# AppleChu
22

3-
[English](README.en.md) | 简体中文
3+
基于 [ChuModLoader](https://github.com/MuNET-OSS/ChuModLoader) 的 CHUNITHM Mod
44

5-
基于 [ChuModLoader](https://github.com/MuNET-OSS/ChuModLoader) 的 CHUNITHM Mod。
5+
<p align="center">
6+
<a href="#许可证"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License"></a>
7+
<img src="https://img.shields.io/badge/platform-Windows%20x86-lightgrey.svg" alt="Platform">
8+
<img src="https://img.shields.io/badge/rust-nightly-orange.svg" alt="Rust">
9+
</p>
10+
11+
## 目录
12+
13+
- [AppleChu](#applechu)
14+
- [目录](#目录)
15+
- [安装](#安装)
16+
- [配置](#配置)
17+
- [功能](#功能)
18+
- [IO 仿真](#io-仿真)
19+
- [构建](#构建)
20+
- [许可证](#许可证)
621

722
## 安装
823

9-
1. 安装 ChuModLoader(将 `version.dll` 放到 `chusanApp.exe` 旁边)
10-
2.`AppleChu.dll` 复制到 `mods/` 目录
11-
3. 启动游戏,`AppleChu.toml` 会自动生成
12-
4. 编辑 `AppleChu.toml` 配置功能
24+
1. 安装 ChuModLoader,将 `winhttp.dll` 放到 `chusanApp.exe` 旁边
25+
2.`AppleChu.dll` 复制到游戏的 `mods/` 目录
26+
3. 启动游戏,`AppleChu.toml` 会在游戏目录自动生成
27+
4. 按需编辑 `AppleChu.toml` 启用功能
28+
29+
> [!TIP]
30+
> 预编译的 `AppleChu.dll` 可在 [Releases](https://github.com/MuNET-OSS/AppleChu/releases) 页面下载
31+
32+
## 配置
33+
34+
所有功能通过游戏目录下的 `AppleChu.toml` 控制。取消注释对应的 `[Section]` 即可启用该功能,并填写其下的键值
35+
36+
> [!NOTE]
37+
> 如需图形化编辑,可使用 [ChuChartManager](https://github.com/MuNET-OSS/ChuChartManager)
1338
1439
## 功能
1540

16-
- 跳过启动画面
17-
- 免费游玩
18-
- 禁用选歌计时器
19-
- 跳过地图动画
20-
- 解锁游玩曲数上限(自定义最大曲数)
21-
- 自定义各场景计时器
22-
- 所有计时器 999
23-
- 解锁 120fps
24-
- 绕过 1080P/120Hz/AppUser 检测
25-
- 强制共享音频 / 双声道输出
26-
- 关闭网络加密 / TLS
27-
- 自定义版本号文本
28-
- 自定义 FREE PLAY 文本
29-
- 自动游玩(智能屏蔽成绩)
30-
- 退出确认对话框
31-
- DPI 感知
32-
- 切换窗口闪退修复 (D3D9)
41+
| 分类 | 功能 | 说明 |
42+
| --- | --- | --- |
43+
| 常用 | 跳过启动画面 | 跳过开机动画直接进入游戏 |
44+
| 常用 | 免费游玩 | 强制 FREE PLAY,可自定义显示文本 |
45+
| 常用 | 禁用选歌计时器 | 选歌界面不再倒计时 |
46+
| 常用 | 跳过地图动画 | 跳过地图过场动画 |
47+
| 游戏 | 解锁曲数上限 | 自定义单局最大游玩曲数 |
48+
| 游戏 | 自定义计时器 | 单独调整各场景计时器 |
49+
| 游戏 | 全部计时器 999 | 将所有计时器统一拉满 |
50+
| 游戏 | 自动游玩 | Autoplay,默认 `Home` 键切换,可配置键位 |
51+
| 显示 | 解锁 120fps | 解除帧率限制 |
52+
| 显示 | FPS 显示 | 屏幕内显示实时帧率(需 d3d9 代理) |
53+
| 显示 | 帧率锁定 | 锁定到自定义目标帧率(需 d3d9 代理) |
54+
| 显示 | 绕过 1080P / 120Hz | 跳过分辨率与刷新率检测 |
55+
| 显示 | DPI 感知 | 启用高 DPI 适配 |
56+
| 音频 | 强制共享音频 | 使用共享模式输出 |
57+
| 音频 | 强制双声道 | 强制 2ch 输出 |
58+
| 网络 | 关闭加密 | 禁用网络加密 |
59+
| 网络 | 关闭 TLS | 禁用 TLS |
60+
| 兼容 | 绕过 AppUser | 跳过 AppUser 检测 |
61+
| 体验 | 退出确认 | 关闭游戏前弹出确认框 |
62+
| 体验 | 设备丢失修复 | 修复切换窗口导致的 D3D9 闪退 |
63+
| 通用 | 自定义版本号 | 覆盖屏幕上显示的版本文本 |
3364

34-
## 配置
65+
## IO 仿真
66+
67+
AppleChu 内置一套与 segatools 配置和 API 完全兼容的游戏侧 IO 仿真,无需 segatools 即可驱动游戏输入与外设
3568

36-
编辑游戏目录下的 `AppleChu.toml`,取消注释 `[Section]` 即可启用功能。
69+
| 模块 | 配置段 | 说明 |
70+
| --- | --- | --- |
71+
| 控制器 IO DLL | `[ChuniIo]` | 加载外部 `chuniio` DLL,支持 `path` / `path32` / `path64` |
72+
| 读卡器 IO DLL | `[AimeIo]` | 加载外部 `aimeio` DLL |
73+
| 按键输入 | `[Buttons]` | Test / Service / 投币 / AIR 模拟键位 |
74+
| AIR 输入 | `[Air]` | AIR 1-6 键位映射 |
75+
| 触摸条键位 | `[Slider]` | 键盘模拟触摸条(Cell 1-32) |
76+
| IO4 仿真 | `[Io4]` | 内置 IO4 主控仿真 |
77+
| 触摸条仿真 | `[SliderDevice]` | 内置触摸条设备仿真 |
78+
| Aime 读卡器 | `[Aime]` |`aime.txt` / `felica.txt` 读卡,支持扫卡键 |
79+
| LED15093 灯板 | `[Led15093]` | LED15093 灯板仿真 |
80+
| VFD 显示板 | `[Vfd]` | VFD 显示板仿真 |
3781

38-
使用 [ChuChartManager](https://github.com/MuNET-OSS/ChuChartManager) 可图形化编辑配置。
82+
> [!IMPORTANT]
83+
> 键位值为 Windows 虚拟键码(VK code)。若同时配置了外部 `[ChuniIo]` / `[AimeIo]` DLL,则优先使用外部 DLL
3984
4085
## 构建
4186

42-
需要 Rust nightly + i686-pc-windows-msvc:
87+
需要 Rust nightly 工具链与 `i686-pc-windows-msvc` 目标
4388

4489
```bash
90+
git submodule update --init --recursive
91+
rustup target add i686-pc-windows-msvc
4592
cargo build --release
4693
```
4794

48-
输出: `target/i686-pc-windows-msvc/release/AppleChu.dll`
95+
产物位于:
96+
97+
```text
98+
target/i686-pc-windows-msvc/release/AppleChu.dll
99+
```
49100

50101
## 许可证
51102

52-
Apache-2.0
103+
[Apache-2.0](LICENSE)

manifest.toml

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ groups = [
1616
{ id = "display", label = { zh = "显示", en = "Display" }, sections = ["Unlock120fps", "Bypass1080p", "Bypass120hz", "DpiAware", "FpsDisplay", "FrameLock"] },
1717
{ id = "audio", label = { zh = "音频", en = "Audio" }, sections = ["ForceSharedAudio", "Force2chAudio"] },
1818
{ id = "network", label = { zh = "网络", en = "Network" }, sections = ["DisableEncryption", "DisableTLS"] },
19+
{ id = "io", label = { zh = "IO", en = "IO" }, sections = ["ChuniIo", "AimeIo", "Buttons", "Air", "Slider", "Io4", "SliderDevice", "Aime", "Led15093", "Vfd"] },
1920
{ id = "compatibility", label = { zh = "兼容", en = "Compatibility" }, sections = ["BypassAppUser"] },
2021
{ id = "ux", label = { zh = "体验", en = "UX" }, sections = ["ExitConfirm", "DeviceLostFix"] },
2122
]
@@ -103,6 +104,12 @@ id = "Autoplay"
103104
default_enabled = true
104105
label = { zh = "自动游玩", en = "Autoplay" }
105106
description = { zh = "只屏蔽成绩数据,角色/设置/地图进度正常保存", en = "Only blocks score data, settings/progress saved normally" }
107+
[[config.sections.entries]]
108+
key = "hotkey"
109+
type = "string"
110+
default = "Home"
111+
label = { zh = "切换键", en = "Toggle key" }
112+
description = { zh = "支持 Home、Insert、F1 或虚拟键码", en = "Supports Home, Insert, F1, or a virtual-key code" }
106113

107114
[[config.sections]]
108115
id = "Unlock120fps"
@@ -185,3 +192,158 @@ description = { zh = "需要 d3d9 proxy", en = "Requires d3d9.dll proxy" }
185192
min = 1
186193
max = 240
187194
label = { zh = "目标帧率", en = "Target FPS" }
195+
196+
[[config.sections]]
197+
id = "ChuniIo"
198+
always_enabled = true
199+
label = { zh = "控制器 IO DLL", en = "Controller IO DLL" }
200+
[[config.sections.entries]]
201+
key = "path"
202+
type = "string"
203+
default = ""
204+
label = { zh = "DLL 路径", en = "DLL path" }
205+
[[config.sections.entries]]
206+
key = "path32"
207+
type = "string"
208+
default = ""
209+
label = { zh = "32 位 DLL 路径", en = "32-bit DLL path" }
210+
[[config.sections.entries]]
211+
key = "path64"
212+
type = "string"
213+
default = ""
214+
label = { zh = "64 位 DLL 路径", en = "64-bit DLL path" }
215+
216+
[[config.sections]]
217+
id = "AimeIo"
218+
always_enabled = true
219+
label = { zh = "读卡器 IO DLL", en = "Card reader IO DLL" }
220+
[[config.sections.entries]]
221+
key = "path"
222+
type = "string"
223+
default = ""
224+
label = { zh = "DLL 路径", en = "DLL path" }
225+
226+
[[config.sections]]
227+
id = "Buttons"
228+
always_enabled = true
229+
label = { zh = "按键输入", en = "Button input" }
230+
[[config.sections.entries]]
231+
key = "test"
232+
type = "int"
233+
default = 112
234+
label = { zh = "Test 键", en = "Test key" }
235+
[[config.sections.entries]]
236+
key = "service"
237+
type = "int"
238+
default = 113
239+
label = { zh = "Service 键", en = "Service key" }
240+
[[config.sections.entries]]
241+
key = "coin"
242+
type = "int"
243+
default = 114
244+
label = { zh = "投币键", en = "Coin key" }
245+
[[config.sections.entries]]
246+
key = "ir"
247+
type = "int"
248+
default = 32
249+
label = { zh = "AIR 模拟键", en = "AIR emulation key" }
250+
251+
[[config.sections]]
252+
id = "Air"
253+
always_enabled = true
254+
label = { zh = "AIR 输入", en = "AIR input" }
255+
[[config.sections.entries]]
256+
key = "air1"
257+
type = "int"
258+
default = 52
259+
label = { zh = "AIR 1", en = "AIR 1" }
260+
[[config.sections.entries]]
261+
key = "air2"
262+
type = "int"
263+
default = 53
264+
label = { zh = "AIR 2", en = "AIR 2" }
265+
[[config.sections.entries]]
266+
key = "air3"
267+
type = "int"
268+
default = 54
269+
label = { zh = "AIR 3", en = "AIR 3" }
270+
[[config.sections.entries]]
271+
key = "air4"
272+
type = "int"
273+
default = 55
274+
label = { zh = "AIR 4", en = "AIR 4" }
275+
[[config.sections.entries]]
276+
key = "air5"
277+
type = "int"
278+
default = 56
279+
label = { zh = "AIR 5", en = "AIR 5" }
280+
[[config.sections.entries]]
281+
key = "air6"
282+
type = "int"
283+
default = 57
284+
label = { zh = "AIR 6", en = "AIR 6" }
285+
286+
[[config.sections]]
287+
id = "Slider"
288+
always_enabled = true
289+
label = { zh = "触摸条键位", en = "Slider keys" }
290+
[[config.sections.entries]]
291+
key = "cell1"
292+
type = "int"
293+
default = 76
294+
label = { zh = "Cell 1", en = "Cell 1" }
295+
[[config.sections.entries]]
296+
key = "cell32"
297+
type = "int"
298+
default = 83
299+
label = { zh = "Cell 32", en = "Cell 32" }
300+
301+
[[config.sections]]
302+
id = "Io4"
303+
default_enabled = true
304+
label = { zh = "IO4 仿真", en = "IO4 emulation" }
305+
[[config.sections.entries]]
306+
key = "enable"
307+
type = "bool"
308+
default = true
309+
label = { zh = "启用", en = "Enable" }
310+
311+
[[config.sections]]
312+
id = "SliderDevice"
313+
default_enabled = true
314+
label = { zh = "触摸条仿真", en = "Slider emulation" }
315+
[[config.sections.entries]]
316+
key = "enable"
317+
type = "bool"
318+
default = true
319+
label = { zh = "启用", en = "Enable" }
320+
321+
[[config.sections]]
322+
id = "Aime"
323+
default_enabled = true
324+
label = { zh = "Aime 读卡器", en = "Aime reader" }
325+
[[config.sections.entries]]
326+
key = "aime_path"
327+
type = "string"
328+
default = "aime.txt"
329+
label = { zh = "Aime 文件", en = "Aime file" }
330+
[[config.sections.entries]]
331+
key = "felica_path"
332+
type = "string"
333+
default = "felica.txt"
334+
label = { zh = "FeliCa 文件", en = "FeliCa file" }
335+
[[config.sections.entries]]
336+
key = "scan"
337+
type = "int"
338+
default = 13
339+
label = { zh = "扫卡键", en = "Scan key" }
340+
341+
[[config.sections]]
342+
id = "Led15093"
343+
default_enabled = true
344+
label = { zh = "LED15093 灯板", en = "LED15093 board" }
345+
346+
[[config.sections]]
347+
id = "Vfd"
348+
default_enabled = true
349+
label = { zh = "VFD 显示板", en = "VFD display" }

0 commit comments

Comments
 (0)