ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

告别Java jar:用Rust+WebAssembly编写Horizon Mod的入门到发布完整教程

告别Java jar:用Rust+WebAssembly编写Horizon Mod的入门到发布完整教程

【免费下载链接】horizon

Minecraft: Java Edition 26.3 rewritten from scratch in Rust, checked against vanilla with 281 differential harnesses. Get it with the Horizon launcher.

项目地址:https://gitcode.com/gh_mirrors/horizon41/horizon
点击查看免费下载

Horizon 是一款用 Rust 重写的 Minecraft: Java Edition 26.3,而它的 Mod 系统彻底抛弃了 Java jar——Mod 用 Rust 编写,编译为 WebAssembly(Wasm)组件,装进一个跨平台的.hmod文件即可运行。本教程带你从零搭建第一个 Rust Horizon Mod,学会写代码、做离线测试、通过cargo horizon-mod check自检,最终把它发布到官方注册表(Registry),供所有玩家一键安装。

为什么 Horizon Mod 不用 Java jar?

Fabric 和 NeoForge 的 jar 直接调用、甚至打补丁修改 Minecraft 的 Java 类,而 Horizon 里根本没有这些类,所以 Java Mod无法原样运行。Horizon 换了一条路线(详见 docs/mods.md):

维度传统 Java ModHorizon Rust + Wasm Mod
沙箱与游戏同进程,可改游戏代码WebAssembly 沙箱:无文件、网络、进程、时钟访问
崩溃影响可能拖垮整个游戏只停掉该 Mod,游戏继续运行
平台按 OS/架构分发不同 jar一个.hmod跑遍 Windows/macOS/Linux、x86-64/ARM
权限隐式,用户无从得知能力(capabilities)显式声明,玩家开启前可见

核心数字(官方实测):

  • 空tick钩子调用开销仅85.5 ns,加载一个 64 KB 的 Mod 约 50 ms(一次性);
  • 每次调用有"燃耗"(fuel)预算:init20 亿、tick5000 万、frame1000 万——死循环会在不到一秒内被熔断,而不是卡死游戏;
  • 没开任何 Mod 时,游戏不加载引擎、不起线程,几乎零开销。

Horizon Mod 体系的核心概念

一个 Mod 本质上是一个 zip 包(.hmod):

my_mod.hmod = zip { horizon-mod.toml # 清单:id、版本、能力声明 mod.wasm # WebAssembly 组件(你的 Rust 代码编译产物) }

游戏与 Mod 之间的全部接口由一个 WIT 契约文件定义:crates/horizon-mod-sdk/wit/horizon.wit。Mod 通过导入获得能力,通过导出挂接事件:

能力能做什么
log写游戏日志(默认拥有)
game-read读取玩家坐标、朝向、血量、饥饿、维度、游戏时钟
chat给本地玩家显示一行聊天消息
hud在屏幕角落绘制最多 16 行文本面板
storage读写 Mod 专属存档(最多 64 个文件、4 MiB)
command以玩家权限执行原版命令

事件钩子则有 5 个:init(加载时)、tick(每秒 20 次)、frame(每渲染帧)、command(玩家输入/你的命令)、chat(收到聊天消息时)。没申请的钩子不会被调用——不需要逐帧运行的 HUD Mod 每帧零成本。

⚠️ 关键机制:清单里声明的能力必须与 wasm 实际导入的接口一致。代码偷偷导入了清单没声明的能力,游戏会直接拒绝加载(uses capability chat, missing from horizon-mod.toml)——你展示给玩家的权限列表就是事实。

搭建开发环境:两条命令完成准备

1️⃣ 添加 Wasm 编译目标:

rustup target add wasm32-unknown-unknown

2️⃣ 安装官方 Mod 作者工具(提供new / build / run / test / check等子命令,实现见 crates/cargo-horizon-mod/):

cargo install --git https://gitcode.com/gh_mirrors/horizon41/horizon cargo-horizon-mod

工具会自动把 Rust 模块打包为面向horizon:mods/horizon-mod世界的 WebAssembly 组件,无需手动处理 WASI。

创建你的第一个 Mod:模板与清单

cargo horizon-mod new my-mod cd my-mod

一条命令生成完整的 Mod 工程:

my-mod/ ├── Cargo.toml # cdylib + horizon-mod-sdk 依赖 ├── horizon-mod.toml # 清单(能力声明就在这里) ├── src/lib.rs # 你的 Mod 逻辑入口 └── tests/hello.toml # 离线测试脚本

清单 horizon-mod.toml 长这样(未知键会被拒绝,拼写错误不会"静默忽略"):

id = "my_mod" name = "My First Mod" version = "0.1.0" description = "用 Rust 写的第一个 Horizon Mod" authors = ["你"] api = "0.1" # 目标 API 版本线 side = "client" # client | server | both capabilities = ["chat"] # 声明能力,玩家可见

编写 Rust 代码:15 行搞定一个聊天命令 Mod

一个 Mod 就是一个实现了horizon_mod_sdk::Mod的 Rust 类型,状态存放在类型里:

use horizon_mod_sdk::{Mod, Registration, chat}; struct Hello { greeted: u32 } impl Mod for Hello { fn init() -> Result<(Self, Registration), String> { Ok((Hello { greeted: 0 }, Registration::new().command("hello"))) } fn command(&mut self, _name: &str, args: &str) -> Result<Option<String>, String> { self.greeted += 1; chat::show(&format!("Hello {args}! ({} so far)", self.greeted)); Ok(None) } } horizon_mod_sdk::export_mod!(Hello);

没申请tick/frame等钩子时保留默认空实现即可。官方示例 coords-hud(坐标 HUD)展示了完整的tick+ HUD 面板写法,建议直接对照阅读:

热重载开发循环

cargo horizon-mod run # 构建并带 Mod 启动游戏 cargo horizon-mod build # 改完代码重新构建

run以"开发 Mod"方式启动游戏:文件一有变化(约每秒检查一次),游戏自动重载并在聊天框提示 "Mods reloaded",内存状态重置、但storage里保存的数据保留——改一行代码,进游戏立刻见效。

离线脚本测试:不开游戏窗口验证 Mod

这是 Horizon Mod 系统最实用的特性之一:cargo horizon-mod test在无窗口沙箱里"扮演游戏"(推进 tick、帧、时钟、聊天、命令),逐步检查 Mod 的产出。测试脚本是放在tests/下的 TOML 文件,例如官方示例 panel.toml:

[player] x = 12.5 z = -3.25 [[step]] ticks = 1 expect.panel = ["XYZ 12.5 / 64.0 / -3.2", "Facing North (-Z)", "Day 2, 12:00"] expect.corner = "top-left" [[step]] command = "coords" expect.feedback = "Coordinates panel hidden"

每一步中ticks、frames、chat、command依次推进游戏状态,expect检查面板、聊天、命令反馈等——任何一步不符就立即报出"期望值 vs 实际值"。拼错的键直接报错,测试绝不会"静默通过"。

发布前自检:cargo horizon-mod check

提交注册表前,先运行注册表 CI 使用的同一套检查:

cargo horizon-mod check target/horizon-mod/my_mod.hmod # 加 --json 输出报告

它依次做三件事:

  1. 读取清单与内容,拒绝能力未覆盖的导入;
  2. 在沙箱中试跑 40 tick、120 帧、一条聊天和每个命令——必须能启动、不 trap、不超燃耗;
  3. 报告该 Mod 所需的 API level(如 "needs mod API level 1 or newer")。

可选:用 minisign 的 Ed25519 密钥为.hmod生成.minisig签名,注册表会固定你的公钥,其他密钥的"更新"会被拒绝——这是保护玩家不被篡改更新的重要手段。

完整发布流程:从 .hmod 到官方注册表

Horizon 的注册表收录经过人工审核的 Mod(.hmod)、Mod 包(.hpack)与资源包,格式规范见 docs/api/mod-index.md。发布共 5 步:

步骤做什么
1本地跑通cargo horizon-mod check
2源码放到公开仓库,附可运行的许可证(审核者会读源码,且文件必须能由它构建)
3在官网提交页登录并填写:文件、名称摘要、许可证、源码地址、可选的 minisign 公钥与签名
4表单自动生成一个mods/<id>.toml的 Pull Request,CI 在沙箱复跑检查并回帖报告,你与审核者在此沟通
5审核者合并——数分钟内你的 Mod 即成为正式版本,出现在官网和启动器中

发布后的每个文件都有 SHA-256 校验,下载时先比对再落盘;被撤销(revoked)的文件会被启动器拒绝并自动停用。玩家也可在启动器 Mods 页中搜索、安装、开关你的 Mod,且安装前就能看到它声明的权限列表。

进阶方向与版本兼容

  • API 稳定性:契约是版本化的 WIT 包。0.1.x 内只增不删,为 0.1 构建的 Mod 在后续 0.1.N 游戏中持续可加载;破坏性变更才会启用0.2,且游戏会并行链接新旧两版至少一个版本周期。
  • 内容 Mod(API 0.2):无需一行 Rust,用--template content模板即可携带assets/与data/,以数据驱动方式添加方块、物品、配方(参考 ruby-content 示例)。
  • 服务器 Mod(API 0.3,实验性):side = "server",在模拟世界的一端运行,可感知玩家加入/离开、聊天、方块破坏与放置,示例见 welcome 与 beacons。
  • 官方 Mod 参考:FPS Counter、Zoom、Minimap 等官方 Mod 全部只用公开 API 编写,放在 mods/official/,是最好的"生产级"范本。

常见问题速答

Q:Java Mod 能直接跑吗?不能。jar 里的代码会调用 Horizon 不存在的 Java 类;能迁移的是 jar 里的数据与资源(走 Modpack/内容 Mod 通道),代码需要按本文流程用 Rust 重写。

Q:装 Mod 会影响原版性能吗?不装 Mod 时零开销;装了一个 HUD Mod 实测每帧增加不足 0.01 ms(完整数据见 docs/mods.md 的 Performance 一节)。

Q:客户端和服务器 Mod 的区别?客户端 Mod 运行在玩家本地,只读本地快照、只画本地屏幕;服务器 Mod 运行在模拟世界的一端,任何客户端(包括原版 Java 版)都可连接。

Q:去哪里学习更多?完整文档在 docs/mods.md(含设计目标、运行时选型对比、崩溃隔离测试);游戏内 Mods 管理页逻辑在 crates/horizon-client/src/game/mods.rs;注册表服务实现见 crates/horizon-mod-registry/README.md。

现在你已经掌握了 Rust + WebAssembly 编写 Horizon Mod 的完整链路:new脚手架 → 写代码 →run热重载 →test离线验证 →check自检 → 提交注册表。你的第一个.hmod,离上架只差一次cargo horizon-mod build。🚀

【免费下载链接】horizon

Minecraft: Java Edition 26.3 rewritten from scratch in Rust, checked against vanilla with 281 differential harnesses. Get it with the Horizon launcher.

项目地址:https://gitcode.com/gh_mirrors/horizon41/horizon
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进