mtr::Api 与 Java 互操作
JavaScript 脚本能访问的公开 Java API,C++ 一行不缺。Api 调用的是与 JS 相同的公开对象——不是让 C++ 去执行 JavaScript。
每次 Api 调用 = 一次 JSON 编码 + 反射 + JSON 解码往返。只在 create()、后台任务、或每秒屈指可数的低频调用里用;绝不放进逐绘制调用——历史上「每帧每车一次 Api」正是周期性 GC 卡顿的来源。高频数据读快照,高频绘制走记录流。
什么时候用 Api
| 需求 | 通道 |
|---|---|
| 车辆 / 到站 / 电梯 / 装饰的逐帧状态 | 快照包装器(零成本) |
| 文字 / 贴图 / 模型 / 声音绘制 | 绘制记录流(零 JVM 穿越) |
脚本 input 配置、一次性资源创建、跨帧缓存的对象句柄 | Api(create 时调用,句柄存 State) |
| 网络请求、文件、BackgroundWorker、声音管理器等深接口 | Api(后台任务中调用) |
对象与调用
用当前帧的输入构造 Api;从根对象(context() / wrapper())、静态类或 new 出发导航:
struct State { mtr::Api::Object tracker; };
struct Example : mtr::PidsScript<State> {
static constexpr auto ID = "example:arrivals";
void create(mtr::PidsContext& ctx, State& state, const mtr::Pids&) override {
mtr::Api api(ctx.input());
state.tracker = api.create("StateTracker"); // new StateTracker()
api.context().call("setZOrderStep", {0.0002}); // ctx.setZOrderStep(0.0002)
}
void render(mtr::PidsContext& ctx, State& state, const mtr::Pids&) override {
mtr::Api api(ctx.input());
auto arrivals = api.wrapper().call("arrivals"); // wrapper.arrivals()
if (arrivals.call("size").as<int>() == 0) return;
auto arrival = arrivals.call("get", {0});
if (arrival.is_null()) return;
auto text = api.call("Text", "create"); // new Text()
text.call("text", {arrival.call("destination")});
text.call("pos", {2.0, 3.0});
text.call("draw", {api.context()});
}
};
MTR_REGISTER_PIDS_SCRIPT(Example)
| Api 成员 | 作用 |
|---|---|
api.context() / api.wrapper() | 当前脚本的上下文 / 包装器(与 JS 同一对对象) |
api.input() | 资源包声明里的 input JSON(= JS 的 SCRIPT_INPUT) |
api.create(class, args) | new 一个 Java 对象 |
api.call(class, member, args) / api.get(class, member) | 静态方法 / 静态字段 |
api.root(name) | 按名字取根对象:api.root("console")、api.root("Timing")… |
| Object 成员 | 作用 |
|---|---|
obj.call(member, args) | 实例方法调用,返回新 Object |
obj.get(member) / obj.set(member, value) | 字段读 / 写(含继承的公开成员、标准集合) |
obj.as<T>() | 取原始值(int、double、bool、std::string…) |
obj.is_null() | 可空判空 |
obj.enum_name() | Java 枚举的名字(如 "BOAT") |
obj.close() | 显式调用 close()(会话清理也会兜底关闭遗留资源) |
Java 对象由会话按引用计数管理,句柄用十进制字符串表示;Object 析构即释放引用,把要跨帧保留的对象存进 State。数值 id(含 64 位)全程不丢精度。字段与方法按真实 Java 类型解析,含继承的公开成员与标准 Java 集合。
JS ↔ C++ 对照表
| JavaScript | C++ |
|---|---|
Resources.id("example:file") | api.call("Resources", "id", {"example:file"}) |
new Matrices() | api.create("Matrices") |
ctx.getRenderManager() | api.context().call("getRenderManager") |
obj.method(a, b) | obj.call("method", {a, b}) |
obj.field / obj.field = v | obj.get("field") / obj.set("field", v) |
TransportMode.BOAT | api.get("TransportMode", "BOAT") |
SCRIPT_INPUT | api.input()(JSON 值) |
console.log(...) / print(...) | api.root("console").call("log", {...}) |
Timing.delta() | api.root("Timing").call("delta").as<double>() |
array.length / array[i] | array.call("length") / array.call("get", {i}) |
include(...) | C++ 编译期 #include |
AWT 类用全限定名:java.awt.Color、java.awt.Font、java.awt.BasicStroke、java.awt.geom.AffineTransform。GraphicsTexture 的公开字段 graphics / bufferedImage 暴露真实 Java2D 对象。资源路径解析:Resources.idr 按本模块的声明路径解析(多库声明时各用各的);Resources.manager() 与 JS 在 MTR 4 上一样为 null。上游 v2.3.0-prerelease.2 新增的成员——Resources.id(id, suffix) 拼接形式、Resources.mgr() 别名(ANTE 资源包兼容)、VanillaText.withFont(String) 等字符串参数变体——经同一 JSON-RPC 通道开箱可用。上游文档标注为未实现的能力(车辆连接件的 drawConnModel / drawConnStretchTexture)本模组同样不虚构行为。
后台回调
Api::Callback 把 C++ 函数包装成 Java 函数式接口(Runnable / Consumer / Function…)。回调对象必须存活到 Java 不再可能调用为止——放进 State:
struct State {
std::unique_ptr<mtr::Api::Callback> task; // 保存到销毁
};
void create(mtr::PidsContext& ctx, State& s, const mtr::Pids&) {
mtr::Api api(ctx.input());
s.task = std::make_unique<mtr::Api::Callback>([api](mtr::Json) {
auto response = api.call("Networking", "fetch",
{"https://example.org/data"});
// 把结果发布进自己的同步状态;render 里读
return mtr::Json();
});
api.root("BackgroundWorker").call("submit", {*s.task});
}
- render 与回调可能并发——共享可变 C++ 状态自己加锁。
- 重载会先停回调、等在途调用返回,再销毁状态与卸载代码。
- 后台准备好的 GPU 模型用
DynamicModelHolder.uploadLater上传;直接ModelManager.upload仍要求 Java 渲染线程(从create或主线程回调里调用)。
覆盖范围
常用 API 面:console、Resources、ModelManager / Model / RawModel / RawMeshBuilder / DynamicModelHolder、Vector3f、Matrices、GraphicsTexture 与 Java2D、RenderManager / QuadDrawCall、SoundManager / TickableSoundInstance、MinecraftClient、PlayerEntity / ItemStack / VanillaText / VoxelShape、Files、Networking、BackgroundWorker、TextUtil / Timing / StateTracker / CycleTracker / RateLimit、DataReader、MTRClientData、TSC 数据类与 DisplayHelper。PIDS / 装饰 / 车辆的可调用成员清单记录在仓库的 bench/api-coverage.json,电梯以其 Java 包装器为准。
编译后可对照真实 MTR jar 审计你的调用面:
python native/bench/api_coverage.py \
--classes fabric/build/classes/java/main \
--jar path/to/mtr.jar
MTRClientData 的内部字段与 JS 侧一样受版本稳定性限制;标注 deprecated 的方法仍可调用。快照与包装器里的等价数据优先——更快也更稳。
接下来:C ABI 与宿主服务 —— 模块边界的完整契约。