mtr::Api 與 Java 互通
熱路徑之禁

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++ 對照表

JavaScriptC++
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 = vobj.get("field") / obj.set("field", v)
TransportMode.BOATapi.get("TransportMode", "BOAT")
SCRIPT_INPUTapi.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() 於 MTR 4,與 JS 同為 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 與宿主服務 —— 模塊疆界之全約也。