入門
自零而始,迄於行乎遊戲之中:取 SDK,立模塊之工程,事編譯,終納諸資源包。
先決之件
| 工具 | 版本 | 釋義 |
|---|---|---|
| C++ 編譯器 | C++17 | MSVC(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 x64 | my_pids.dll | MSVC;/utf-8 者,SDK 工程已預設之 |
| Linux x64 / ARM64 | libmy_pids.so | GCC / Clang |
| macOS x64 / arm64 | libmy_pids.dylib | 以 -DCMAKE_OSX_ARCHITECTURES=arm64(或 x86_64)擇架構,-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 |
| Android arm64 | libmy_pids.so | NDK 工具鏈交叉而編,API 21+;16 KB 頁對齊之務,工程模板已代之 |
| iOS / iPadOS arm64 | libmy_pids.dylib | Mach-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 / ….dylib | C++ 完整路徑(繫於該副檔名所應之平臺,餘臺則跳過) |
{"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/,惟原生橋居之。二者慎勿相混。遊戲所載,惟當前作業系統所應平臺之庫而已。
驗於遊戲之中
- 安 JCM Yanyang 與 MTR,置資源包於
resourcepacks/而啟之(或以內建之資源,隨存檔而散之)。 - 置所應之方塊(PIDS 之屬),於其配置中擇君之腳本,或使宣告之條生效。
- 啟
logs/latest.log而索native script——模組方載,必印模塊 census 之概:模塊幾何,腳本何類,傳輸何道,具列焉。得見君之example:arrivals,則載入成矣。 - 庫文件既改,按 F3+T 重載資源包,C++ 腳本隨之而新(或以模組所供「重載全部 MTR 腳本」之快捷鍵),無須重啟遊戲也。
必用 Release 版 jar,否則 Complete Build 之產物。push/PR 速成之 CI 產物,原生橋不在焉:日誌必書 native bridge unavailable,諸 C++ 腳本盡棄不載——非君模塊之咎也。