写给要改代码、跑起来或自己出包的人。界面用法见软件手册; 协作约定(IPC 生成、窗口拆分、临时目录、日志调试、样式规范等)统一在仓库根目录 AGENTS.md。
- 内核:Rust workspace(
mml-core/本体 + 20 个子 crate,edition 2024) - 界面:Tauri 2 桌面壳(
mml-gui/)+ Vue 3 / Vite 前端(mml-vue/) - IPC:Rust 源码是命令与 DTO 的唯一来源,
ipc-gen生成独立的 npm 契约包mml-ipc, 启动器前端与自定义主页面共用 - 渲染:wgpu(方块 / 物品图标、皮肤与披风 2D / 3D)+ glow(皮肤模型预览)
| 目录 | 职责 |
|---|---|
mml-core/ |
启动器内核,多 crate:游戏启动、版本管理、Mod 加载器、整合包、下载、认证、Java 管理、网络 API(Mojang / Modrinth / CurseForge / Fabric 等)、皮肤与贴图渲染、NBT 解析等 |
mml-gui/ |
Tauri 桌面壳;窗口规格与 IPC 命令在 src-tauri/src/windows/,命令与 DTO 由 ipc-gen 扫描生成到 mml-ipc |
mml-vue/ |
前端(Vue3 + Vite);窗口在 src/windows/,通用组件在 src/components/ |
ipc-gen/ |
IPC 契约生成器(gui-ipc-gen)与过程宏(ipc-gen/macros,gui-macros) |
mml-ipc/ |
npm 契约包:按来源拆分的跨 IPC 类型、命令包装、事件订阅函数与自定义主页 window.mml 契约,mml-vue 与 custom/ 下的示例共用 |
custom/ |
四个自定义界面示例:custom-main-demo/(自定义主页面)、custom-ui-demo/(整页主题 · 组件)、custom-ui-html-demo/(整页主题 · HTML)、custom-ui-css-demo/(自定义 CSS);各自构建出可直接导入启动器的 zip,用法见 custom/README.md |
build/ |
版本文件、版本同步 / 打包辅助脚本,以及初始化 / 开发 / 构建脚本 |
design/ |
程序图标的 SVG 源文件;改完用 tauri icon 重新生成各平台图标 |
各子项目的内部目录(mml-core 的各个 crate、mml-gui / mml-vue / mml-ipc 的子目录等)
见根 README 的项目结构。各子项目另有 README:mml-gui、
mml-vue、mml-ipc、custom、
mml-theme-studio。
mml-gui/src-tauri/src/ ipc-gen/ mml-ipc/src/
命令 #[gui_macros::command] ──▶ 扫描 + 生成 ──▶ bindings.ts(createCommands + DTO)
事件 #[gui_macros::emit] listens.ts(事件名常量)
│
┌───────────────┴───────────────┐
▼ ▼
mml-vue(Tauri invoke) custom-main-demo(window.mml 桥接)
- 新增命令加
#[gui_macros::command](过程宏在ipc-gen/macros/,展开成 Tauri 的命令宏), 新增事件加#[gui_macros::emit];改完在mml-gui里跑cargo check --manifest-path src-tauri/Cargo.toml。 mml-ipc/src/下的types/、bindings.ts、listens.ts是生成产物,不要手改:DTO 按 来源 .rs 拆在types/下(types/index.ts是 barrel),bindings.ts是createCommands(invoke)命令包装,listens.ts是事件名、payload 类型映射与createEvents(on)订阅函数。 命令与事件都不绑定传输层,调用方自己给invoke/on;mml-vue/src/lib/bindings.ts只是 绑定 Tauriinvoke的兼容层。- 自定义主页面的
window.mml契约(MmlApi、白名单事件)在mml-ipc/src/home.ts,手写、 不参与扫描;custom-main-demo从这里取类型、事件名与生成的onXxx函数,不再自建一份。 - 生成规则、分组方式与常见坑见 AGENTS.md §4;包内用法见 mml-ipc/README.md。
环境要求(Windows 的 MSVC / WebView2 等)、依赖安装与出包产物见根 README 的构建与运行。
依赖:Rust(含 cargo 与 cargo install tauri-cli --version "^2" --locked)、Node.js。
启动器本体先跑 build/init.ps1 或 bash build/init.sh,它会装好 mml-vue 的 npm 依赖并检查
cargo tauri;custom/ 下前三个示例各自 npm install。
示例的 mml-ipc / mml-vue 由 scripts/deps.mjs 在安装前链接到本仓库,仓库不在时
自动浅克隆一份,不需要单独发布。custom-ui-html-demo 没有 npm 依赖,不用 install。
| 命令 | 说明 |
|---|---|
build/init.ps1 |
首次安装 mml-vue 的 npm 依赖并检查 cargo tauri(bash 版 build/init.sh) |
cd mml-gui && .\tauri.ps1 dev |
桌面开发模式(自动还原 vendor 插件;Linux / macOS 用 bash tauri.sh dev;端口 1420 必须空闲) |
build/dev-frontend.ps1 |
只起 Vite,配合 debug 版 Rust 后端单独运行;tauri dev 已自带 Vite,不要重复起 |
build/build-release.ps1 |
正式发布构建(fat LTO,含安装包,按版本收集到 build_out/;Windows 默认 x64 / arm64;Linux / macOS 的 x64 / arm64 由 CI 原生 runner 出) |
build/build-prerelease.ps1 |
预发布构建(thin LTO,只出 exe,更快;Windows 两种架构,target/prerelease/mml-gui-<arch>.exe) |
bash build/package-flatpak.sh |
用已构建的二进制打 .flatpak,需要 flatpak,不重新编译 |
bash build/package-arch.sh |
用已构建的二进制打 .pkg.tar.zst,不依赖 makepkg,任一 Linux 可跑 |
.\check.ps1 --all |
根目录整仓检查,先还原 vendor 插件再 cargo check(bash 版 bash check.sh --all) |
cd mml-gui && cargo check --manifest-path src-tauri/Cargo.toml |
改过 Rust 侧命令 / DTO 后重新生成 mml-ipc 契约 |
cd mml-vue && npm run shots |
无后端渲染前端页面截图,--scene=<名字> 只跑一张;场景表见前端页面截图目录 |
cd mml-vue && npm run shots:docs |
按 scenarios.mjs 重新生成 docs/screenshots.md |
cd mml-gui && .\tauri.ps1 icon ../design/icon/f-blend.svg |
改过程序图标后重新生成 src-tauri/icons/;会顺带产出 android/ 与 ios/,桌面端用不到可删 |
cd custom/custom-main-demo && npm run build |
构建自定义主页面示例并打包成 custom-main-demo.zip(四个示例的用法见 custom/README.md) |
build/ 下带 PowerShell 版(.ps1,Windows)与 bash 版(.sh,Linux / macOS / Git Bash):
PowerShell 版在 Windows 默认出三架构,bash 版构建当前架构;build/*.mjs 是版本同步与产物打包用的
跨平台辅助脚本。
Flatpak 与 Arch 包不在 build-release 里自动跑,由 build/package-flatpak.sh、
build/package-arch.sh 单独完成,输入都是 target/release/ModernMinecraftLauncher:
Flatpak 走 flatpak build-export + build-bundle,不依赖 SDK / runtime;
Arch 包按 .PKGINFO + tar.zst 直接组装,不依赖 makepkg,有 bsdtar 时顺带生成 .MTREE。
桌面文件与 AppStream 元数据在 build/linux/。
Flatpak 默认声明 org.freedesktop.Platform//25.08,安装时由 Flathub 提供运行时:
flatpak install --user ./mml-linux-x64-0.0.1.flatpak。本地系统比 25.08 新时(例如 Ubuntu 26.04),
编出的二进制可能要求更高版本的 glibc,只有 CI 在 ubuntu-22.04 上编的包才与 25.08 匹配;
要换运行时用 MML_FLATPAK_RUNTIME=26.08 bash build/package-flatpak.sh。
发布版本从 0.0.1 开始,唯一来源是 Git 标签;build-release 先把标签版本同步到
mml-gui/src-tauri/Cargo.toml 与 tauri.conf.json,再把 Tauri 产物按版本重命名到 build_out/。
完整发版流程见根 README 的版本与发布。
版本号在界面上的写法按通道区分(见 src-tauri/src/build_info.rs):
| 通道 | 写法 |
|---|---|
| 正式发布 | 1.0.0,不带日期 |
预发布版(prerelease feature) |
1.0.0.20261028;清单本身带后缀时是 1.0.0-pre.20261028 |
测试版(cargo run / tauri dev) |
1.0.0.20261028 |
日期由 src-tauri/build.rs 在编译期取当天写进 MML_BUILD_DATE,所以查版本时看到的是
这份二进制哪天编出来的,不是运行日期。标签里不带日期,日期不进安装包元数据。
内核的配置版本 mml_names::VERSION 也是同一套写法:测试版 1.0.0.20261028、
正式版 1.0.0。日期由 mml-names/build.rs 注入 ——
配置结构没变、只是换了一天出的包,它也会跟着变,这是"配置是哪天的构建写的"这条线索。
构建 profile 与产物:正式发布是 [profile.release](fat LTO + codegen-units = 1),
预发布是 [profile.prerelease](thin LTO + codegen-units = 16);两者分别在
target/<三元组>/release/ 与 target/<三元组>/prerelease/ 下,来回切不会互相刷缓存。
Windows 的正式 / 预发布脚本默认构建 x64 / arm64:
- 只要一种:
-Arch x64; - arm64 只打 NSIS,x64 出 MSI + NSIS;
- 交叉编译要求
rustup target add aarch64-pc-windows-msvc, 以及 Visual Studio 对应架构的 MSVC 工具链(ARM64 要装「MSVC v143 - VS 2022 C++ ARM64/ARM64EC 生成工具」)。 CI 的 arm64 跑在windows-11-arm原生 runner 上,不需要交叉工具链。 - Linux / macOS 本地只构建当前架构;需要多架构时用
MML_TARGETS指定三元组(空格分隔):MML_TARGETS=x86_64-apple-darwin bash build/build-release.sh可在 Apple Silicon 上交叉出 macOS x64 (需先rustup target add x86_64-apple-darwin);Linux arm64 建议直接在 arm64 机器上构建。 打包类型用MML_BUNDLES限定(如MML_BUNDLES=deb,rpm),不写就交给 tauri 决定该平台的全套。 macOS 通用包可用MML_TARGETS=universal-apple-darwin,仅正式发布支持。
预发布也要安装包时,只能覆盖 release 的设置(tauri CLI 不认 --profile):
$env:CARGO_PROFILE_RELEASE_LTO = 'thin'
$env:CARGO_PROFILE_RELEASE_CODEGEN_UNITS = '16'
cd mml-gui
cargo tauri build --features prerelease--features prerelease 不能漏,否则主界面不会提示「预发布版」,出的包与正式版一样。
vendor 插件的还原方式见 AGENTS.md §3。
测试按改动范围只跑相关的那几个:cargo test -p <crate>(不要整仓全量测试)。
.github/workflows/build.yml 把 init、build-release 与
build-prerelease 三个本地脚本串成三平台流水线,按标签后缀决定走正式发布还是预发布,
不另写一份构建逻辑:
| 触发 | 行为 |
|---|---|
推送正式版标签(如 v0.0.1) |
check-version 用标签名作为版本,随后并行构建三平台安装包,最后汇总成一个 GitHub Release |
推送预发布标签(如 v1.0.0-pre) |
标签带 -pre 这类后缀时走预发布通道:各平台跑 build-prerelease,只出可执行文件,最后汇总成一个标记为 Pre-release 的 GitHub Release |
推送测试构建标签(如 testbuild) |
完整跑一遍构建,版本取最近的可达标签、通道按其后缀决定;产物全部丢弃——upload-artifact 步骤、Flatpak / Arch 附加包与 Release 都不执行,只看构建是否通过 |
推送 releases/** 分支 |
只构建、把产物传成 Actions artifact,不发 Release,用来验证构建 |
每个平台都走同一套骨架,正式版与预发布只在构建脚本和打包方式上分叉:
actions/checkout@v5+actions/setup-node@v5(Node 24,按 lockfile 缓存)+dtolnay/rust-toolchain@stable+Swatinem/rust-cache@v2;- 用
taiki-e/install-action装cargo-binstall,再由它下载 Tauri CLI 的预编译cargo-tauri(GitHub Release 资产),不跑cargo install。上游 binstall 元数据只给 x64 的 zip 包写了格式覆盖,macOS / Windows 的 ARM64 产物其实也是 zip,工作流按平台显式传--pkg-fmt,避免回退到源码编译; - Windows 拆成 x64 / arm64 两行 matrix,各跑
build/init.ps1再按通道跑build/build-release.ps1 -Arch <arch>或build/build-prerelease.ps1 -Arch <arch>(arm64 用windows-11-arm原生 runner);Linux 跑 x64(ubuntu-22.04)与 arm64(ubuntu-24.04-arm), macOS 的 x64 跑macos-26-intel(原生 Intel)、arm64 跑macos-latest,都执行bash build/init.sh再按通道跑build/build-release.sh或build/build-prerelease.sh; - 正式版的 Linux x64 构建完先上传 deb / rpm / AppImage,再单独上传原始二进制;
package-linux-extrajob 下载这份二进制后跑build/package-flatpak.sh与build/package-arch.sh,把.flatpak与.pkg.tar.zst也放进build_out/。附加包失败不影响主产物,但发版 job 会等它,缺包时不发 Release; arm64 只出 deb / rpm / AppImage; - 正式版由脚本把安装包按版本改名到
build_out/,预发布由build/package-prerelease.mjs把可执行文件按 平台 / 架构 / 版本 改名到build_out/,actions/upload-artifact@v6收走; 发版 job(正式版与预发布各一个)用actions/download-artifact@v7取产物并保留每个 artifact 的子目录:正式版按mml-*,预发布按mml-prerelease-*;先检查文件名有无重复, 再由build/release-body.mjs用产物现算 SHA1 / SHA256 生成发布说明,最后交给softprops/action-gh-release@v3。
- Linux runner 固定
ubuntu-22.04作为 glibc 基线,并预装 Tauri 需要的libwebkit2gtk-4.1-dev/libayatana-appindicator3-dev/librsvg2-dev/patchelf/libxdo-dev/rpm/libdbus-1-dev/libudev-dev; FUSE 运行时 x64 用libfuse2、arm64 用libfuse2t64。libdbus-1-dev是mml-sys在 Linux 上 「在文件管理器中显示」用的 D-Bus 绑定,缺了会编译失败;libudev-dev是手柄读取在 Linux 上的后端依赖;libarchive-tools与zstd给 Arch 包生成.MTREE。 - macOS 的 x64 跑
macos-26-intel:这代 Intel 镜像是最后一代 —— Apple 已说明 macOS 26 是 最后一个支持 Intel 的系统,不会再有macos-27-intel。等它退役时 Intel 这条线也就结束了, 那时要么只出 arm64,要么回退到在macos-latest上交叉编译(MML_TARGETS=x86_64-apple-darwin加rustup target add即可,签名与公证不看宿主架构)。 - 产物名与本地一致:
mml-windows-x64-0.0.1.msi、mml-linux-x64-0.0.1.deb、mml-linux-x64-0.0.1.flatpak、mml-arch-x64-0.0.1.pkg.tar.zst、mml-macos-arm64-0.0.1.dmg等,架构取自runner.arch。 - 预发布只出可执行文件:
mml-windows-x64-1.0.0-pre.exe、mml-linux-arm64-1.0.0-pre、mml-macos-x64-1.0.0-pre等;Linux / macOS 下载后要chmod +x。预发布不打安装包, 安装包的版本字段放不下-pre这类后缀。 - Flatpak 不需要在 runner 上装
org.freedesktop.Platform:封装只做 OSTree 提交与 bundle, runtime 是安装时由用户从 Flathub 获取的依赖。Arch 包只是把二进制与.PKGINFO打成 tar.zst, 不需要装base-devel或 WebKitGTK。 - 版本号只来自标签:
check-version用标签名作为版本,标签不是版本号时直接失败, 避免发出错版本的包。标签带-后缀(如v1.0.0-pre)时走预发布通道。 - macOS runner 的
bash是 3.2,build/*.sh与mml-gui/vendor/prepare.sh都不能用mapfile/readarray这类 bash 4 语法。 - FUSE 运行时包在 24.04 改名为
libfuse2t64:工作流装依赖前先用apt-cache show断言包名存在, 将来再改名时直接失败并列出候选包,不会只留一句Unable to locate package。 - macOS 构建会读
APPLE_CERTIFICATE/APPLE_CERTIFICATE_PASSWORD/APPLE_SIGNING_IDENTITY/APPLE_ID/APPLE_PASSWORD/APPLE_TEAM_ID完成签名与公证;APPLE_CERTIFICATE是 base64 后的.p12,APPLE_PASSWORD是 App 专用密码。secrets 没配置时这些变量是空串, 而 Tauri 只看变量是否存在,所以工作流先把空值unset。没有证书时一定要补一道 ad-hoc 签名: 把APPLE_SIGNING_IDENTITY设成单个-,Tauri 就会用codesign --sign -签一遍。 Apple Silicon 上未签名的二进制根本起不来,Intel 上也会被 Gatekeeper 判成「已损坏」。 预发布只有裸可执行文件、不过 Tauri 打包,工作流在收集完之后自己签一道。 ad-hoc 不等于公证,首次打开仍需在「隐私与安全性」里放行。 - 发版前检查产物重名:不同平台产物同名时会在 GitHub Release 上互相覆盖,发现重名直接失败。
- 发布说明里的校验和是当场对下载下来的产物算的:SHA1 与 SHA256 各一列,随 Release 正文发布。
windows-11-arm与ubuntu-24.04-arm是 GitHub 公共预览 runner,私有仓库可能不可用; 届时改自托管,或回退到 x64 runner 交叉编译。- 发版 job 需要
contents: write(工作流默认只给contents: read),只在 tag 触发时执行。