- C++ 84.6%
- PowerShell 14.4%
- CMake 1%
初始提交。衍生自 MiliastraGME(clearyss,GPL-3.0),沿用其目标与写盘语义, 界面与实现改为 C++23 + 自绘 Win32:公共头文件置于 include/,实现置于 src/, 纯逻辑层不依赖 Win32 并可单元测试;随附 GPL-3.0 许可证全文。 |
||
|---|---|---|
| include | ||
| res | ||
| src | ||
| tests | ||
| third_party/nlohmann | ||
| tools | ||
| .gitattributes | ||
| .gitignore | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
免责声明
本项目衍生自 MiliastraGME(作者 clearyss): 目标、行为语义与写盘结果由该项目移植而来,界面与实现改为 C++23 / Win32 原生。原项目采用 GPL-3.0, 本衍生项目同样遵循 GPL-3.0(见文末「许可证」)。原项目的免责声明与风险提示一并继承,并在下文中展开。
本项目仅用于个人学习研究、本地配置管理与自有设备上的可恢复性测试,不代表、隶属于、授权自或受米哈游 及其关联主体认可,也不代表或受原项目作者认可。使用本项目即表示你已阅读、理解并同意自行承担全部使用 后果;如不同意,请勿下载、运行、传播或基于本项目进行二次开发。
使用者必须遵守所在地现行有效的法律法规、部门规章、监管要求及司法解释,包括但不限于网络安全、数据 安全、个人信息保护、著作权、计算机信息系统安全保护、反不正当竞争、民事责任、行政责任与刑事责任相关 规定;同时必须遵守米哈游游戏的用户协议、游戏规则、社区规范、安全策略、反作弊规则及其后续更新。若本 项目说明、功能或使用方式与法律法规或官方规则存在冲突,应以法律法规和官方规则为准,并立即停止使用、 执行「恢复游戏初始配置」或手动恢复相关配置。
请勿将本项目用于以下场景:
- 绕过、对抗或破坏游戏安全机制、反作弊系统、风控策略、远程配置、运营策略或正常服务秩序;
- 获取不正当优势、影响游戏公平性、干扰其他玩家体验、自动化作弊、外挂、脚本、封包篡改或类似用途;
- 未经授权修改、分发、逆向、复制、抓取或利用米哈游及第三方的客户端、服务端、数据、素材、接口、账号 或商业内容;
- 传播违法违规内容、侵犯他人合法权益,或以任何方式规避法律责任、平台规则、账号处罚或安全审查。
本项目会修改本机 hosts、GME 相关配置和可能的游戏目录文件,可能导致语音功能异常、配置无法更新、游戏
行为异常、安全软件拦截、账号风险提示、账号限制、封禁、数据丢失或其他不可预期后果。请仅在明确理解影响
范围、已备份原始文件、可接受风险且确认不违反官方规则的前提下使用;不再使用时请及时执行「恢复游戏初始
配置」,必要时从 backups/ 手动恢复。
本仓库及其代码、文档、发行物、Issue、讨论区和相关页面可能因合规、版权、平台规则、维护成本或其他原因 随时删除、归档、私有化、迁移或停止更新,作者不承诺持续维护、可用性、兼容性、技术支持或历史版本保留。 请勿将本仓库作为长期可用来源或唯一备份来源。
🎙️ BetterMWVoice
面向 GME 语音链路的本地参数助手(图形界面版):为虚拟麦克风、音乐输入与语音场景写入高音质配置。
把目标语音参数写进 GME 控制配置与本地
av_config.json、屏蔽远程配置域名,并在界面上直接看到 游戏运行时到底在用哪套参数——写入、备份、锁定、验证、恢复,一个窗口完成。
项目简介
BetterMWVoice 是一个 Windows 本地图形工具,用于把 audio_params.json 中定义的目标语音参数写入 GME SDK
相关配置,并通过解析运行时日志确认游戏是否真正使用了这些参数。
它衍生自命令行工具 MiliastraGME:写盘行为兼容
(写出的 gmesdk_control_*.config 与 av_config.json 与原版逐字节一致,hosts 标记段沿用原字符串,
两版可交替使用),区别在于界面与实现——原版是 Python + 命令行,本版是 C++23 + Win32 界面:
| 指标 | 原版 MiliastraGME | 本版 BetterMWVoice |
|---|---|---|
| 形态 | Python 命令行 | C++23 / Win32 原生 GUI |
| 发布目录 | 源码 + Python 运行时 | 0.98 MB / 3 个文件 |
| 运行期依赖 | Python 3.10+ | 无(全静态链接,单 exe) |
| 查看实际参数 | status 文本输出 |
概览页「当前游戏参数」网格卡(启动时后台预读一次) |
当前默认方案面向 虚拟麦克风 / 本机音乐输入:
48 kHz采样率、双声道、128 kbps码率- 关闭
AEC、AGC、ANS、AINS、VAD,保留FEC丢包保护 - 更宽松的 jitter 缓冲(初始
1000 ms,范围1200-2000 ms)
Important
「注入配置」与「恢复游戏初始配置」会写入系统 hosts、GME 配置目录和可能的游戏目录,因此程序声明了
requireAdministrator,启动时会请求一次管理员权限(之后所有操作都在同一个已提权进程内完成)。 修改前会把已有文件备份到数据根的backups/。
Important
参数一旦变化,必须完全退出并重新启动游戏,才会在游戏内体现。 GME 在游戏进程内持有参数, 只重新进入一次语音场景不会重新读取配置文件(真机实测:日志里的
AudParam.始终是旧值)。 凡是改动了参数的路径——参数页「保存」后「注入配置」、设置页「恢复游戏初始配置」——都要重启游戏; 若横幅显示「已生效」,说明游戏已经用上了目标参数,此时不必重启。
核心能力
| Patch | Lock | Verify |
|---|---|---|
|
🛠️ 参数写入 修补 GME 控制配置,生成本地 av_config.json,并统一目标音频参数。
|
🧱 远程锁定 在 hosts 中屏蔽 GME 远程配置域名,减少远程策略覆盖本地参数。 |
🔍 日志验证 解析 GMESDK_*.log 中的实际运行时参数,判断配置是否真正生效。
|
界面流程
| 目标参数 | → | 注入配置 | → | 重启游戏 | → | 检查状态 | → | 恢复游戏初始配置 |
| 参数页调整 / 查看 | 写入配置并锁定 | 让游戏重读配置 | 核对运行时参数 | 按需清理 |
架构
flowchart TD
A["audio_params.json<br/>目标音频参数(参数页「保存」写入)"] --> B["core/audio<br/>读取与校验、内置默认值"]
C["settings.json<br/>进程名与路径配置"] --> D["core/paths + platform/process<br/>定位 GME / 游戏目录"]
B --> E["app/service::run_inject<br/>修补控制配置 + 写 av_config + 装 hosts 段"]
D --> E
E --> F["backups/<br/>修改前备份(每类保留最近 5 份)"]
E --> G["%APPDATA%/GME/进程名<br/>gmesdk_control_*.config / av_config.json"]
D --> H["游戏目录<br/>av_config.json / Plugins/av_config.json"]
E --> H
B --> I["core/hosts<br/>屏蔽远程配置域名"]
I --> J["Windows hosts<br/>gmeconf.qcloud.com / gmeosconf.qcloud.com"]
G --> K["core/logparse<br/>解析 GMESDK 日志与配置摘要"]
H --> K
J --> K
K --> L["data/status.json<br/>生效状态与诊断信息"]
L --> M["ui/ 概览页<br/>状态横幅 + 运行环境卡 + 当前游戏参数网格卡"]
代码分层:src/core/(纯逻辑,不依赖 Win32,可被单元测试直接链接)、src/platform/(Win32 副作用)、
src/app/(把前两者编排成动作,GUI 与静默入口共用)、src/ui/(主窗口、四个页面、自绘控件与主题)。
快速开始
| ① 使用 下载或自行构建 |
→ | ② 启动 同意一次 UAC |
→ | ③ 注入配置 写入并锁定 |
→ | ④ 重启游戏后检查状态 核对实际参数 |
→ | ⑤ 恢复游戏初始配置 按需清理 |
环境要求
| 系统 | Windows 10 / 11 |
依赖 Windows hosts、进程查询与 %APPDATA% 路径;Win11 22H2 及以上启用 Mica 背景,旧系统回退纯色。 |
| 运行时 | 无 |
全静态链接,单个 exe;不需要 Python 或其他运行库。 |
| 权限 | 管理员 |
「注入配置」/「恢复游戏初始配置」需要写 hosts 与游戏配置,程序会请求一次 UAC。 |
| 目标 | GME SDK |
默认进程名 YuanShen.exe,可在设置页修改。 |
1. 使用
下载 release/BetterMWVoice-1.0.0.zip,解压到任意位置即可;也可以按下文「构建」自行编译。
压缩包内容:
BetterMWVoice-1.0.0.zip
├─ BetterMWVoice/
│ ├─ BetterMWVoice.exe ← 单文件程序,双击即用
│ ├─ audio_params.json ← 目标音频参数
│ └─ settings.json ← 进程名与路径配置
├─ LICENSE ← GPL-3.0 许可证全文
└─ README.md ← 本说明
首次运行会有两个系统提示:UAC(请求管理员权限,一次即可)与 SmartScreen(exe 未做商业代码签名时 提示"无法识别的应用",点「更多信息 → 仍要运行」即可)。
2. 启动
双击 BetterMWVoice.exe。数据根就是 exe 所在目录(便携模式,当前生效位置显示在概览页「运行环境」卡片);
若 exe 目录不可写(例如放进 Program Files),自动改用 %APPDATA%\BetterMWVoice\。
窗口尺寸是固定的:不能拖拽边框调整大小(内容比一屏高时用滚轮看,概览 / 参数 / 设置三页都支持滚动)。 需要更大视野时点「最大化」即可全屏,还原后回到原来的尺寸。
3. 调整参数与路径
- 参数页:三组卡片(语音处理 6 个开关 / 音质 / 网络缓冲)。每个参数下方都有一行小字说明(含允许
范围),滑块右端实时显示当前值;采样率与编码模式只能从下拉列表里选,其余为输入框。
改动由「保存」写入
audio_params.json——只写目标值,不碰任何游戏文件;取值超范围会被拒绝保存并 在日志区说明原因。「恢复默认修改参数」把 15 个参数恢复成内置默认值,此时尚未保存,点「保存」才写盘。 - 设置页:进程名 / GME 数据目录(留空自动)/ 游戏目录(留空自动检测)。游戏目录留空时,只有目标进程
正在运行时才能自动探测到;手动填好可以保证游戏目录下的两处
av_config.json一定被写入。
概览 / 参数 / 设置三个页面都支持滚轮滚动:窗口不必开得很大,内容比一屏高时滚轮即可看全 (概览页的命令栏固定在底部,内容滚动时按钮不会被推走)。
4. 注入配置
概览页点「注入配置」(或菜单「操作 → 注入配置」)。它会:
- 校验
audio_params.json; - 给该 GME 目录下的每个
gmesdk_control_*.config写入目标音频参数,把sequence抬到上限,并设为只读; - 写入 GME 数据目录与可检测游戏目录中的
av_config.json(共 3 处); - 在 Windows hosts 中加入 GME 远程配置域名屏蔽段;
- 备份被修改的文件到
backups/(每类保留最近 5 份); - 读写配置与日志,输出一份状态摘要(见日志页)。
5. 重启游戏后检查状态
完全退出游戏、再启动游戏、进入一次语音场景,然后点「检查状态」。概览页会同时给出:
- 状态横幅:「已生效」或「待确认」,说明行会明确指出下一步是"先去注入配置"还是"先重启游戏";
- 「当前游戏参数」卡片:15 项指标按列排成网格。一致的项只写当前值;与目标不一致的项用橙色
箭头标成
实际→目标(卡片标题写的是「若与配置不一致将以橙色箭头标注」),例如采样率 16 kHz→48 kHz、缓冲初始值 200→1000 ms。记录时间在卡片标题右侧。整页只保留这一张 参数卡:原来并排的「目标参数」卡片已去掉,目标值只在不一致的项后面标出(目标参数本身在参数页里看)。
6. 按需清理
设置页点「恢复游戏初始配置」(二次确认):移除 hosts 屏蔽段、删除三处 av_config.json,并把
gmesdk_control_*.config 的音频参数写回游戏原生值、清除只读。它不读 backups/,因此备份文件
缺失也能还原;backups/ 本身不会被删除。之后同样需要重启游戏才会在游戏内体现。
界面操作手册
| 操作 | 位置 | 是否需要管理员 | 说明 |
|---|---|---|---|
| 保存 | 参数页 | 否 | 把界面上的 15 个参数写入 audio_params.json(只写目标值)。 |
| 恢复默认修改参数 | 参数页 | 否 | 把输入框恢复成内置默认值(尚未保存,点「保存」才写盘)。 |
| 注入配置 | 概览页 / 菜单「操作」 | 是 | 修补控制配置、写 av_config.json、安装 hosts 屏蔽段并输出状态摘要。 |
| 检查状态 | 概览页 / 菜单「操作」 | 否 | 读配置、hosts 与最新运行日志,判断参数是否生效。 |
| 恢复游戏初始配置 | 设置页 / 菜单「操作」 | 是 | 移除 hosts 段、删除本地 av_config.json,并把控制配置的音频参数写回游戏原生值。 |
内部还会用到两个不对外文档化的静默通道(由程序自身或脚本调用):
--run=status|params(普通权限,摘要写 stdout)与 --elevated=inject|purge(提权实例的静默执行通道)。
与原项目命令的对应关系
| MiliastraGME | BetterMWVoice |
|---|---|
params |
参数页(概览页只显示游戏当前实际值;目标值在参数页里看) |
inject |
概览页「注入配置」 |
status |
概览页「检查状态」+「当前游戏参数」网格卡(启动时后台预读一次) |
restore(移除 hosts 段与本地 av_config.json) |
已删除:它与「恢复游戏初始配置」语义重叠且更弱,容易让人以为参数已被还原 |
| — | 设置页「恢复游戏初始配置」(把控制配置的音频参数也写回游戏原生值;原项目没有对应命令) |
应用数据
BetterMWVoice/ ← 数据根(便携模式 = exe 同目录)
├─ audio_params.json ← 目标音频参数(参数页「保存」写入)
├─ settings.json ← 进程名与路径配置
├─ data/
│ ├─ status.json ← 最近一次检查状态的完整判定
│ ├─ manifest.json ← 最近一次注入的完整执行记录
│ └─ ui_status_card.txt← 界面回归脚本读取的卡片状态与状态横幅
└─ backups/
├─ hosts.hosts.<timestamp>.bak
├─ gmesdk_control_*.config.control.<timestamp>.bak
└─ av_config.json.av_config.<timestamp>.bak
| 路径 | 内容 |
|---|---|
audio_params.json |
目标音频参数(15 个字段,不再有方案名/说明)。 |
settings.json |
进程名、GME 数据目录、游戏目录。 |
data/status.json |
最近一次状态判定的完整 payload(含游戏实际值、差异明细、诊断结论)。 |
data/manifest.json |
最近一次注入的记录(逐文件结果、备份路径、hosts 变更)。 |
backups/ |
修改前备份,包含 hosts、GME 控制配置和被覆盖的 av_config.json。 |
日志页里的操作摘要只在界面内显示,不落盘;需要留存时用日志页的「复制」。
可能被写入的外部路径:%APPDATA%\GME\<process_name>\gmesdk_control_*.config、
%APPDATA%\GME\<process_name>\av_config.json、<game_dir>\av_config.json、
<game_dir>\YuanShen_Data\Plugins\av_config.json、%SystemRoot%\System32\drivers\etc\hosts。
文本文件一律以 CRLF 写盘(与原项目在 Windows 上的行为一致)。
代码清单
BetterMWVoice/
├─ include/ 公共头文件(子目录与 src/ 一一对应)
│ ├─ core/ platform/ app/ ui/(含 ui/controls/)
├─ src/ 实现(只含 .cpp)
│ ├─ core/ 纯逻辑层:不依赖 Win32,可单元测试
│ │ ├─ audio 读取 / 校验 / 序列化 audio_params.json;内置默认值与游戏原生值
│ │ ├─ codec GME 控制配置的解码 / 编码(字节级可逆变换)
│ │ ├─ config_patch 音频参数改写、av_config.json 生成、写回游戏原生值
│ │ ├─ logparse 解析 GMESDK_*.log,判定运行时参数是否匹配目标
│ │ ├─ summary 中文摘要、状态卡片与状态横幅文案
│ │ ├─ layout 四页布局的纯计算(行高按实测传入,被单元测试锁死)
│ │ ├─ hosts hosts 屏蔽段的纯文本变换
│ │ └─ paths / settings / backup_policy / common / json
│ ├─ platform/ 文件读写、进程查询、提权、环境路径(唯一直接调用 Win32 副作用处)
│ ├─ app/service 把 core 与 platform 编排成 inject / status / purge / params 四个动作
│ └─ ui/
│ ├─ main_window 主窗口、后台动作调度、启动预读、状态横幅与关于对话框
│ ├─ pages 四个页面的构建、绘制与数据绑定(含关于文案)
│ ├─ controls/ 自绘控件(按钮 / 开关 / 滑块 / 导航列表)
│ └─ theme / win_main
├─ tests/ 单元测试;samples/ 为与原版行为逐字节对照的权威样本
├─ tools/ 构建、验证与代码签名脚本
├─ third_party/ nlohmann-json(vendored 单头)
├─ res/ 图标、应用清单、资源脚本与随包分发的默认配置
├─ CMakeLists.txt
├─ README.md
└─ LICENSE
状态判定逻辑
程序会找到 GME 目录下修改时间最新的 GMESDK_*.log,提取其中的 AudParam. / codetype: 行,再结合配置文件的修改时间判断这条记录是否"新鲜",然后逐字段比较 AEC、AGC、ANS、AINS、VAD、FEC、
Frame、SR、CH、Codec、BR 与 jitter 参数:
matched:最新运行时记录已匹配目标参数;matched_config_current:最近记录匹配,且本地配置也匹配目标参数;not_matched:日志有效,但游戏仍在使用旧值;stale_matched/stale_not_matched:日志记录早于本次配置修改,需要重启游戏刷新(只重进语音场景无效);no_sample/no_log:日志里还没有语音参数记录,或没找到 GME 日志。
「生效」的判定是 matches_target,或"日志样本匹配 + 本地配置匹配"两者同时成立。横幅与卡片显示的就是
同一份判定结果,因此不会出现"卡片说一致、横幅说待确认"。
hosts 屏蔽段
工具会写入以下标记包围的 hosts 段:
# BEGIN GME_VOICE_AUTO_INJECTOR
0.0.0.0 gmeconf.qcloud.com
::1 gmeconf.qcloud.com
0.0.0.0 gmeosconf.qcloud.com
::1 gmeosconf.qcloud.com
# END GME_VOICE_AUTO_INJECTOR
重复执行「注入配置」会先移除旧标记段再重新写入,避免重复追加;「恢复游戏初始配置」会删除该段,并兼容
清理原项目的旧标记段 # BEGIN GME_REMOTE_CONTROL_CONFIG_BLOCK … # END …。
构建
前置:把 w64devkit(GCC 16.2 工具链,自带 CMake 与 Ninja)解压到
..\toolchain\w64devkit,然后:
powershell -NoProfile -ExecutionPolicy Bypass -File tools\build.ps1 # 配置 + 构建 + 跑测试 + 组装 + 代码签名
powershell -NoProfile -ExecutionPolicy Bypass -File tools\build.ps1 -Clean # 先清理 build/ 与 release/
powershell -NoProfile -ExecutionPolicy Bypass -File tools\build.ps1 -SkipTests # 跳过测试
产物:
release/BetterMWVoice/:BetterMWVoice.exe+audio_params.json+settings.json(三个文件);release/BetterMWVoice-1.0.0.zip:上表「使用」里那个发布包(同一个目录树 +LICENSE+README.md), 由构建脚本在签名之后自动打包,exe 的签名原样带进 zip。
组装前请先关闭正在运行的窗口——占用中的 exe 会导致拷贝失败(脚本会提示)。
单元测试(纯逻辑层,不需要原项目或 Python 参与):
build\bin\bmv_tests.exe # 全部用例(当前 153 用例 / 6289 断言)
build\bin\bmv_tests.exe layout # 只跑某一组(组名或 组名.用例名)
界面与启动过程的自动化验证(产出一份 asInvoker 版本到 build\verify\,不影响 release\):
powershell -NoProfile -ExecutionPolicy Bypass -File tools/verify-ui.ps1 # 构建 + 截 4 页图到 build\verify\shots\
powershell -NoProfile -ExecutionPolicy Bypass -File tools/verify-overview-status.ps1 # 当前游戏参数网格卡与状态横幅的四种情形断言
powershell -NoProfile -ExecutionPolicy Bypass -File tools/verify-startup-layout.ps1 # 启动期布局:预读前后页宽恒定、卡片贴合、右侧无残留
应用是单实例的(多个界面会各自改写 hosts 与 GME 配置):跑这些脚本前请先关掉你自己开着的窗口, 否则脚本启动的新实例只会激活已有窗口然后退出,脚本就等不到主窗口(它会直接提示原因并退出,不会静默卡住)。 也可以加
-CloseExisting让脚本先关掉已有实例,例如:powershell -NoProfile -ExecutionPolicy Bypass -File tools/verify-startup-layout.ps1 -CloseExisting。 脚本结束时也会兜一次清理,保证不留窗口。 本机环境下 gcc 需要把TMP/TEMP/TMPDIR指向可写目录,否则会以Cannot create temporary file ... Permission denied失败;tools/build.ps1已自动设置。
代码签名(可选,用于消除 SmartScreen 提示)
powershell -NoProfile -ExecutionPolicy Bypass -File tools/new-codesign-cert.ps1 # 生成自签名代码签名证书
powershell -NoProfile -ExecutionPolicy Bypass -File tools/trust-codesign-cert.ps1 # 管理员:导入"受信任的根"与"受信任的发布者"
自签名证书只对本机有意义:分发给别人时需要对方各自导入,或改用商业代码签名证书。
故障排查
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 检查状态一直是「待确认」,卡片显示「未匹配」 | 改了参数但没重启游戏(最常见) | 完全退出游戏 → 重新启动 → 进一次语音场景 → 再点「检查状态」。只重进语音场景不会重新读取配置。 |
| 说明行提示「本地配置尚未按目标写入」 | 只点了「保存」,还没「注入配置」 | 回概览页点「注入配置」,然后重启游戏。 |
| 说明行提示「最近记录早于本次修改」 | 日志记录时间早于配置修改时间 | 重启游戏并进入一次语音场景,让 GME 产生新的 AudParam. 记录。 |
| 「配置已写入,但游戏当前仍使用自己的数值」 | 远程下发的配置仍在生效 | 确认 hosts 屏蔽段在(摘要里「联网配置已锁定」),必要时以管理员重新「注入配置」,检查安全软件/代理。 |
| 「游戏目录:未检测到」 | 游戏未运行且设置里游戏目录为空 | 先启动游戏再操作,或在设置页手动填入游戏目录。 |
| 「未找到游戏日志」 | GME 数据目录里没有 GMESDK_*.log |
确认进程名与 GME 数据目录正确(设置页),并先启动一次游戏。 |
| 组装时提示 exe 正在运行 | 有个窗口(或提权实例)还开着 | 关闭窗口后重新运行构建脚本。 |
注入成功但看不到 backups/ |
数据根不是当前目录(exe 在别处跑),或该目录被重新构建清空过 | 概览页「运行环境」卡片里的「数据根」就是实际位置;确认后重新注入一次即可看到 backups/。 |
| 注入后控制配置无法编辑 | 注入会把控制配置设为只读 | 先取消只读属性再编辑;「恢复游戏初始配置」会清除只读。 |
注意事项
data/与backups/是运行期数据,不随发布包分发:backups/在第一次「注入配置」时创建 (之后每次注入都会新增备份,每类保留最近 5 份)。重新运行tools\build.ps1会清空 release 目录下的data/与backups/(运行期数据不该跟着分发),所以刚构建完、还没注入过时看不到backups/——这是预期行为,不是备份失败。- 修改 hosts 可能影响 GME 远程配置获取;不再使用本工具时请执行「恢复游戏初始配置」。
- 注入后
gmesdk_control_*.config会被设为只读,以减少运行时覆盖;需要手工编辑时先取消只读。 - 目标参数是否产生理想效果仍取决于游戏版本、GME SDK 版本、输入设备、虚拟声卡与系统音频设置。
交流反馈
- 问题反馈:本仓库的 Issues。
- 原项目(命令行版)与作者:MiliastraGME · clearyss
📄 许可证
本项目采用 GPL-3.0 许可证(与原项目一致):它是 MiliastraGME 的衍生作品,原项目作者为 clearyss。分发本项目的修改版本时请同样以 GPL-3.0 提供源代码, 并保留本声明与原项目署名。
衍生自 MiliastraGME