入門

先決之件

工具版本釋義
C++ 編譯器C++17MSVC(Windows)、GCC、Clang,任擇其一
CMake≥ 3.16薦之,然非硬性之求——SDK 純為頭文件
JDK可省惟行 SDK 自帶 JVM 集成之測試,方須之
要訣

SDK 之供,純乎頭文件(native/include/mtr/);預編譯之庫,一無所賴。以君所素習之構建系統,徑納 include/ 於包含之路即可。

取 SDK

每有 Release,SDK 必刊為 jcm-native-sdk-<版本>.zip(見 GitHub Releases 之附件);啟之,即倉庫 native/ 目錄之源碼:

jcm-native-sdk-2.3.0-1.0.2/
├── include/mtr/          # SDK 諸頭文件盡在(script.hpp 為總門)
│   ├── mtr_native.h      # C ABI:導出函數、快照、繪製記錄、宿主服務
│   ├── script.hpp        # 腳本基類+註冊宏(惟 #include 此一足矣)
│   ├── vehicle.hpp  pids.hpp  lift.hpp  eyecandy.hpp
│   ├── gfx.hpp  gfx2d.hpp  font5x7.hpp  text.hpp  matrices.hpp
│   ├── api.hpp           # mtr::Api(Java API 之全訪)
│   └── crash_guard.hpp ...
├── examples/             # 最小示例模塊凡三
├── bench/                # 測試與器具
└── CMakeLists.txt

立模塊工程

其至簡之法:解 SDK 於君資源包之工程,徑於其 CMakeLists.txt 之末,附以己之目標——蓋 SDK 已括諸平臺鏈結之細務(Windows 無前綴之 .dll、macOS 之 .dylib 與 -undefined dynamic_lookup、Android 之 16 KB 頁對齊)於 mtr_add_script() 一函之中:

# 追加於 SDK native/CMakeLists.txt 之末
mtr_add_script(my_pids src/my_pids.cpp)

若欲別立工程,則下方全模板與彼函數等價:

cmake_minimum_required(VERSION 3.16)
project(my_native_scripts LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# SDK 頭文件路徑(指往解壓所得 SDK 之 include 目錄)
add_library(mtr_script_sdk INTERFACE)
target_include_directories(mtr_script_sdk INTERFACE path/to/sdk/include)

function(mtr_add_script name)          # 與 SDK 同式之模塊目標函數
  add_library(${name} MODULE ${ARGN})
  target_link_libraries(${name} PRIVATE mtr_script_sdk)
  set_target_properties(${name} PROPERTIES CXX_VISIBILITY_PRESET hidden)
  if(WIN32)
    set_target_properties(${name} PROPERTIES PREFIX "" SUFFIX ".dll")
  elseif(APPLE)
    set_target_properties(${name} PROPERTIES PREFIX "lib" SUFFIX ".dylib")
    target_link_options(${name} PRIVATE "-Wl,-undefined,dynamic_lookup")
  elseif(ANDROID)
    target_link_options(${name} PRIVATE "-Wl,-z,max-page-size=16384")
  endif()
endfunction()

mtr_add_script(my_pids src/my_pids.cpp)
按語

腳本者,MODULE 庫也(不鏈 SDK 二進位之物);符號預設而隱,惟導出 ABI 所求之 mtr* 函數凡七(註冊宏於 script.hpp 成之)。C++17 者,其最低之標準也。

第一模塊

至小之 PIDS 到站顯示模塊一首:體完而可編,徑可用於遊戲。

#include <mtr/script.hpp>

struct ArrivalState {};                    // 逐實例恆存之狀態(本例為空)

struct ArrivalDisplay : mtr::PidsScript<ArrivalState> {
    static constexpr auto ID = "example:arrivals";   // 須與資源包之宣告相符

    void render(mtr::PidsContext& ctx, ArrivalState&,
                const mtr::Pids& pids) override {
        for (int row = 0; row < pids.rows(); row++) {
            if (pids.is_row_hidden(row)) continue;

            std::string text = pids.get_custom_message(row).str();
            if (text.empty() && row < pids.arrivals().size())
                text = pids.arrivals().at(row).destination().str();

            if (!text.empty())
                mtr::Text::create()
                    .text(text.c_str())
                    .pos(2, row * 10.0 + 2)
                    .size(pids.width() - 4, 9)
                    .draw(ctx);
        }
    }
};

MTR_REGISTER_PIDS_SCRIPT(ArrivalDisplay)

其要曰:

  • 基類者,定腳本之屬:PidsScript / VehicleScript / LiftScript / EyecandyScript;模板之參,即逐實例狀態之型。
  • 生命週期與 JS 無異:create / render / dispose 三虛函數,按所需而 override(皆可省)。
  • 註冊宏者,敷展全部 ABI 之導出;一翻譯單元,惟註一腳本。

更多之例,具於 SDK 之 examples/:車輛、電梯、裝飾三類,各有至小之樣。

編譯

cmake -S native -B native/build -DCMAKE_BUILD_TYPE=Release
cmake --build native/build --config Release --parallel 4
ctest --test-dir native/build -C Release --output-on-failure   # 可省:行 SDK 自帶之測試
目標平臺產物釋義
Windows x64my_pids.dllMSVC;/utf-8 者,SDK 工程已預設之
Linux x64 / ARM64libmy_pids.soGCC / Clang
macOS x64 / arm64libmy_pids.dylib以 -DCMAKE_OSX_ARCHITECTURES=arm64(或 x86_64)擇架構,-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0
Android arm64libmy_pids.soNDK 工具鏈交叉而編,API 21+;16 KB 頁對齊之務,工程模板已代之
iOS / iPadOS arm64libmy_pids.dylibMach-O 交叉而編,無須簽章(側載之時,重簽之)
要訣

資源包內之庫,以副檔名繫乎平臺:.dll 者繫 Windows,.so 者繫 Linux/Android,.dylib 者繫 macOS/iOS。目錄詳規,具於下節。

納諸資源包

目錄之陳

諸平臺所編之產物,置諸資源包 natives/<platform>/ 之目錄:

my_pack/
├── natives/
│   ├── windows-x64/my_pids.dll
│   ├── windows-arm64/my_pids.dll
│   ├── linux-x64/libmy_pids.so
│   ├── linux-arm64/libmy_pids.so
│   ├── macos-x64/libmy_pids.dylib
│   ├── macos-arm64/libmy_pids.dylib
│   ├── android-arm64/libmy_pids.so
│   └── ios-arm64/libmy_pids.dylib
└── ...(貼圖、模型等其餘資源)

宣之於 mtr_custom_resources.json

language 之欄,無須設之——模組視 scriptLocations 每條之徵,自判其語;同一條目之內,JS 與 C++ 雜用任意之數,皆無不可:

{
    "pids_images": [{
        "id": "example:arrivals",
        "scriptLocations": [
            "mtr:my_pack/natives/my_pids"
        ]
    }]
}

條目解析之規:

scriptLocations 條目所判
…/main.js(不辨大小寫)JavaScript
mtr:my_pack/natives/my_pids(無副檔名)C++ 平臺無關之 stem → 諸平臺自析為 natives/linux-x64/libmy_pids.so、natives/windows-x64/my_pids.dll、natives/macos-arm64/libmy_pids.dylib 等;ARM64 Linux 之境,自動益以 ios-arm64 / android-arm64 之候選
…/libfoo.so / ….dll / ….dylibC++ 完整路徑(繫於該副檔名所應之平臺,餘臺則跳過)
{"windows": …, "linux": …, "macos": …}C++ 按平臺而映之表;許 macos-arm64 等精確之鍵(精確者先於通用者)
  • 四類腳本,同其規:mtr_custom_resources.json 之 vehicleScripts、objectScripts、liftScripts,暨 joban_custom_resources.json 之 pids_images 預設(scriptLocations),皆許上述混雜之宣告。
  • 舊格相容:"language": "cpp" 而加 nativeLibrary / nativeLibraries 者,舊宣告也,依然有效,亦得與 .js 相雜;"language": "javascript" 則強使整條按 JS 解之。
  • JS 之欄如常:prependExpressions / input / dataFetchMode 諸欄之義不變;C++ 側經 api.input() 而讀 input。
  • 視界之外,繪之不輟:PIDS 預設之欄 outOfBound: true(上游 v2.3.0-prerelease.3),屏出相機視界,仍續繪之——投影機之預設,須臾不可停者,賴乎此。
慎之

腳本之模塊(君所編之 .dll/.so/.dylib),屬乎資源包,納諸 natives/<platform>/;模組 jar 自攜之 assets/jcm/natives/,惟原生橋居之。二者慎勿相混。遊戲所載,惟當前作業系統所應平臺之庫而已。

驗於遊戲之中

  1. 安 JCM Yanyang 與 MTR,置資源包於 resourcepacks/ 而啟之(或以內建之資源,隨存檔而散之)。
  2. 置所應之方塊(PIDS 之屬),於其配置中擇君之腳本,或使宣告之條生效。
  3. 啟 logs/latest.log 而索 native script——模組方載,必印模塊 census 之概:模塊幾何,腳本何類,傳輸何道,具列焉。得見君之 example:arrivals,則載入成矣。
  4. 庫文件既改,按 F3+T 重載資源包,C++ 腳本隨之而新(或以模組所供「重載全部 MTR 腳本」之快捷鍵),無須重啟遊戲也。
切記

必用 Release 版 jar,否則 Complete Build 之產物。push/PR 速成之 CI 產物,原生橋不在焉:日誌必書 native bridge unavailable,諸 C++ 腳本盡棄不載——非君模塊之咎也。


繼之:腳本體例與生命週期 —— 四類腳本完備之義;或徑往數據快照,閱可讀之數據。