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() | 可為 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 與宿主服務 —— 模組邊界的完整契約。