數據快照
每幀一遭,宿主搬運之唯讀數據也。諸訪問器所為,皆尋常記憶體之讀——零 JNI,零反射,零裝箱。
快照之機
每幀方始,宿主以此實例之數據一舉搬運,為一 POD 快照:定長之首,變長之陣列池,UTF-8 字串之池,三者具焉;連狀態塊之指針,併傳於 mtrRender。SDK 之具型包裝器(mtr::Vehicle、mtr::Pids、mtr::Lift、mtr::EyeCandy)居此記憶體之上,供與 JS Wrapper 同名之訪問器:
- 字串以
mtr::StrView(data+len)而返;.str()則轉為std::string,.empty()則判其虛實。視圖惟本次render一呼之內為效。 - 常式之列,索引越界,則擲
std::out_of_range(與 Java 端IndexOutOfBounds同其義也)。 - 快照之指針與包裝器,慎勿跨幀而存之。
快照所覆者,高頻讀取之欄而已。數據之不在快照者(網路也,檔案也,渲染管理器之深介面也),則經 mtr::Api 而訪之——彼固低頻之通道,勿用於熱路徑也。
Vehicle(車輛)
MTR 四代之制,載具統名曰 vehicle(資源包宣告之鍵 vehicleScripts,Java 側則 VehicleWrapper 是也),故本 SDK 數據包裝之類,名之曰 mtr::Vehicle。前代 SDK 嘗循 MTR 三代之舊,名之曰 mtr::Train;今舊名猶存,為源碼相容之別名——二名並可編譯,所行全同。
按:mtr::Vehicle 之名已入倉庫 SDK 之原碼,將隨次版之 zip 而布;君所用若 2.3.0-1.0.2 或更早之 SDK zip,則請以 mtr::Train 名之(新 SDK 之中,二名並可編譯)。
mtr::Vehicle 所供者,映 JS 之 VehicleWrapper 加 NTETrainWrapper:
| 訪問器 | 類型 | 釋義 |
|---|---|---|
id() / siding_id() / this_route_id() / departure_index() | int64_t | 車輛、側線、當前線路之 id,暨發車之序(64 位 id,全程不失其精) |
car_count() / car(i) | int32_t / Car | 車廂之數與逐廂之據(見下) |
speed_kmh() / speed_ms() | double | 車行之速 |
rail_progress() / rail_progress(car) | double | 軌道之進;帶參者按車廂之長,推第 i 節之位 |
door_value() | double | 車門之開度 0..1 |
notch_level() / notch_position() | int32_t / double | 檔位 0..5 與歸一之位 |
reversed() / on_route() / door_opening() | bool | 反向 / 在線路上 / 車門方開 |
currently_manual() / manual_allowed() | bool | 手動駕駛之狀 |
client_player_riding() / rendered() | bool | 玩家乘焉 / 任一車廂可見 |
total_dwell_time_millis() / elapsed_dwell_time_millis() | double | 停站之總時 / 既停之時 |
game_time_millis() / in_game_time() | int64_t | 宿主之牆鐘(已正伺服器之偏)/ 遊戲內 tick 0..24000 |
stops() / this_route_stops() / next_route_stops() | StopList | 全部 / 當前線路 / 下一線路之站表(見下) |
next_stop_index() | int32_t | 當前線路下一站之索引(宿主既預算之,勿自重算也) |
route_name() / route_color() / circular_state() / circular() | StrView / uint32_t / uint8_t / bool | 當前線路之名 / 色 ARGB / 環線之狀(0 無、1 順時針、2 逆時針) |
getTransportMode() / getTransportType() | TransportMode / StrView | 見交通之模式與類型 |
doorDirection() / getDirectionOfDoorOpening() | DoorDirection / StrView | 開門之向:曰 NOT,左右皆弗啟;曰 LEFT,車頭之左啟;曰 RIGHT,右啟;曰 ALL,兩側皆啟焉。停站之際,門縱未啟、半啟、方闔、既闔,所報皆與全啟時同;行於正線,則測下一站——設車於當泊之處,逐廂循 MTR canOpenDoors 察塊之法。測之所先,乃服端逐線恆記(服端具此模組,則恆存於存檔,逾視距亦可用,塊若有變,自為增補);服端未具,乃退用客端視距內之掃焉。一側苟有一門可啟,舉側悉記可啟;左右以車首為準,行向倒行,皆弗易焉。特詢而已,門實啟閉,仍司於 MTR。與 JS 之 vehicle.getDirectionOfDoorOpening() 同(ABI 11) |
siding_name() | StrView | 側線顯示之名(用戶自定之名 / 述) |
raw() | JcmVehicleSnapshot& | 原始之快照(ABI 細務,見 C ABI) |
Car(車廂)
| 訪問器 | 釋義 |
|---|---|
length() / width() | 車廂之長 / 廣 |
left_door_open() / right_door_open() | 左右門是否全開 |
rendered() | 該廂本幀既剔之後,猶可見否 |
vehicle_type() | 車廂類型之 id(如 mtr_custom_train_demo_cab_1) |
StopList
| 訪問器 | 釋義 |
|---|---|
size() / empty() / at(i) / operator[](i) | 容量與隨機之訪(越界則擲異常) |
next_stop_index(rail_progress, tolerance=0.5) | 按軌道之進而推下一站;當前線路之列,請徑用 Vehicle::next_stop_index()(宿主既預算之) |
Stop / 轉乘 / 出口
mtr::Stop 映 JS 之 VehicleWrapper.Stop:
| 訪問器 | 釋義 |
|---|---|
name() | 站名 |
destination_name() | 該站台終點站顯示之名 |
has_custom_destination() / custom_destination() | 自定之終點站(未設者,JS 返 null;C++ 則以 has_custom_destination() 判之) |
distance() | 軌道之進(不可用時為 -1) |
dwell_time_millis() | 該站停站之時 |
route_id() / station_id() / platform_id() | 線路 / 車站 / 站台之 id(64 位) |
is_route_switchover() | 線路切換之站否 |
route_circular_state() | 該站所屬線路之環線狀(所以辨跨線後方向之變也) |
interchange_count() / interchange(i) | 轉乘之訊:每條含 color(ARGB)、name(線路名)、getTransportMode()、getTransportType() |
exit_count() / exit(i) | 車站之出口:每個含 name(出口之字母,如 "A")與 destination(j)(地標字串之列) |
交通之模式與類型
二者相補之口徑也;與 JS 側 getTransportMode() / getTransportType() 所返之值全同,故跨語言之腳本,得共享布局之邏輯:
- 模式(
mtr::TransportMode枚舉):UNKNOWN / TRAIN / BOAT / CABLE_CAR / AIRPLANE,覆基礎載具凡四。 - 類型(字串 id,
mtr::transport_type常數):基礎模式小寫之名("train"、"boat"、"cable_car"、"airplane"),益以 MAGIC MTR Addon 所擴線路之類train_normal / train_light_rail / train_high_speed / train_metro / train_bus / train_tram / train_sbahn;其不可解者,則為"unknown",或空視圖(舊伺服器之數據也)。
if (vehicle.getTransportType() == mtr::transport_type::TRAIN_METRO) { /* ... */ }
for (int i = 0; i < stop.interchange_count(); i++) {
mtr::Stop::Interchange ic = stop.interchange(i);
if (ic.getTransportType() == mtr::transport_type::TRAIN_HIGH_SPEED) { /* ... */ }
}
MAGIC 諸類之所自:客戶端裝其 addon 者,自本地之配置而解;伺服器裝而客戶端未裝者,經同步數據集而下;舊伺服器不下線路元數據者,返空 / UNKNOWN——裝本模組之伺服器,則供遠端車站以完備之元數據。
Pids(到站之屏)
mtr::Pids 映 JS 之 PIDSWrapper:
| 訪問器 | 釋義 |
|---|---|
width() / height() | 顯示屏之寬高(1.0 單位 = 16 px,螢幕坐標系) |
rows() / is_row_hidden(i) | 文字之行數 / 第 i 行隱否(至多 32 行) |
station_id() | 所在車站之 id |
is_key_block() / is_platform_number_hidden() | 按鍵方塊否(司隱他屏)/ 隱站台之號否 |
get_custom_message(i) | 第 i 行自定之訊;未設則返空(JS 則返 null) |
arrivals() | Arrivals:到站之列(見下) |
game_time_millis() / in_game_time() | 時鐘(已正伺服器之偏) |
Arrivals / Arrival
| 訪問器 | 釋義 |
|---|---|
arrivals().size() / .at(i) | 到站條目之數,與逐條之訪 |
arrivals().next_for_platform(platform_id, out, cursor) | 按站台之序而歷(映 JS 之 forEach(platformId, cb));游標復用,分配則無 |
arrivals().mixed_car_length() | 各條目車廂之數一否(映 mixedCarLength()) |
destination() / route_name() / route_number() / platform_name() | 終點站 / 線路名 / 線路號 / 站台名 |
arrival_time() / departure_time() / deviation() | 到站 / 離站之刻與其偏(epoch 毫秒,已正) |
arrived() / departed() | 已到站 / 已離站否(按當前之刻而較) |
realtime() / terminating() / circular_state() | 即時之據 / 本班之終 / 環線之狀 |
route_id() / platform_id() / route_color() / car_count() / departure_index() | 線路 / 站台之 id、線路之色 ARGB、車廂之數、發車之序 |
Psd(屏蔽之門)
mtr::Psd 映 JS 之 PSDWrapper(psdScripts 之目也,詳見 JS 腳本之類 · PSD 之腳):
| 訪問器 | 釋義 |
|---|---|
type() / is_glass() / is_top() | 所繫之面:Psd::GLASS(玻璃)或 Psd::TOP(其上之板) |
width() / height() | 畫布之廣袤(PIDS 之像素):玻璃者,整段透明之窗也(每方 96 像素,整柱兩格上下相合為一);其上之板,每方寬約 96(除其邊際)× 高 42 |
platform_id() / has_platform() / station_id() | 所事之站台與車站(無站台則 id 為零) |
platform_number() / station_name() | 站台之號(如「一」)與車站之名 |
door_value() / is_door_open() | 全牆今之啟度(0..1),與有門啟否 |
doors() | PsdDoorList:門單元之列(見下) |
arrivals() | PsdArrivalList:將至之車(見下) |
routes() | PsdRouteList:經此站台之線(見下;惟 dataFetchMode 為 ALL 方載諸站) |
stop() / has_station() | 所事車站全備之訊(ABI 13):mtr::PsdStation 諸訪問器見下;全牆無站台 / 車站,則 has_station() 為偽(stop() 虛空) |
game_time_millis() / in_game_time() | 時鐘(已正伺服器之偏) |
PsdDoor(門之單元)
| 訪問器 | 釋義 |
|---|---|
number() | 門單元之號(自一起,沿牆而計)——一面連牆之內,滑門之組(左扉右扉二塊,或奇式三塊)為一單元 |
is_open() / is_locked() | 即時啟閉 / 加鎖之狀(逐幀直讀門之方塊實體) |
x() / y() / z() | 單元首門方塊之位 |
PsdArrival(將至之車)
Pids Arrival 諸訪問器皆備(destination / route_name / route_number / platform_name / arrival_time / departure_time / deviation / realtime / terminating / circular_state / route_id / platform_id / route_color / car_count / departure_index,見 Pids),增益者:
| 訪問器 | 釋義 |
|---|---|
door_count() / door_number(i) | 此車將啟之門號:車停其站,讀實啟之狀(門機未動之隙,退而用預測);車猶未至,則以近似之法測之——車止於站台之中,其長以車輛資源逐卡累加而得 |
PsdRoute / PsdStop(線與站)
| 訪問器 | 釋義 |
|---|---|
id() / name() / route_number() / color() / circular_state() / getTransportType() | 線之 id / 名 / 號 / 色(ARGB)/ 環線之態 / 交通類型之正號 |
stops() | PsdStopList:諸站有序,佈局同車輛之 Stop(name / destination_name / custom_destination / dwell_time_millis / route_id / station_id / platform_id / route_circular_state / interchange(i) / exit(i),見 Stop / 轉乘 / 出口) |
PsdStation(車站之記,ABI 13)
JcmPsdSnapshot.station_offset(位元組之偏 124;-1 者無車站也——此欄於 ABI 12 猶填補之位)所指者,九十六位元組 JcmPsdStation 之記也——與 JS psd.stop() 之物件同其數據:
PsdStation 及其所屬諸訪問器,索引或記錄失實,則返空物、空字串或預設之值,不擲索引之異常。自造快照於宿主之外者,宜以 mtr::Psd(snapshot, byteLength) 傳實有之位元組數;惟傳指針之舊式,須首部及其所宣之緩衝區皆完備可讀,蓋裸指針不能自明所配之大小。
| 欄 | 釋義 |
|---|---|
station_id / name | 車站之 id 與名 |
color / color_hex | 車站之色——ARGB 之整與 #RRGGBB 之文 |
zone1 / zone2 / zone3 | 價區一至三 |
interchanges | 轉乘之線:route_id / color / name / transport_mode / type |
connecting_groups | 鄰站之線,以站名為群(每群者,站名與其線也) |
connected_station_names | 實體相通之站名 |
exits | 出口:其名與所往 |
platform_numbers | 本站站台之號(JS 之側另計其總) |
ABI 12 至 13,純為增補(填補之位原地升格,舊構一無所改),故 ABI 6–12 之模塊,照常載之。
Lift(電梯)
mtr::Lift 者,快照與 Java 包裝器相合之制;此其快照之部也:
| 訪問器 | 釋義 |
|---|---|
id() | 電梯實例之 id |
should_render() / is_double_sided() / is_client_player_riding() | 渲染 / 雙面 / 玩家乘焉 |
width() / height() / depth() | 尺寸 |
door_value() | 門之開度 0..1 |
angle_degrees() / angle_radians() | 朝向之角 |
direction() | 行進之向 |
floor_count() / floor(i) | 樓層之表:每層含 index,current_floor / target_floor 之標,position[3],暨樓層之號與描述之字串(經 string(offset,len) 而取) |
game_time_millis() / in_game_time() | 時鐘 |
渲染管理器、聲音管理器、可見性諸深介面,經 Api 之 wrapper() 而訪之(電梯無獨立之 JS 文檔頁,故以 Java 包裝器為準)。
EyeCandy(裝飾)
mtr::EyeCandy 映 EyecandyBlockEntityWrapper:
| 訪問器 | 釋義 |
|---|---|
model_id() | 當前模型之 id |
translate_x() / _y() / _z() / rotate_x() / _y() / _z() | 用戶所配之平移 / 旋轉 |
facing() | 朝向(MC Direction.ordinal(),0..5) |
facing_angle() | 朝向之角(Direction.asRotation() 之度數:南 0 / 西 90 / 北 180 / 東 270)——與 JS facingAngle() 同 |
full_brightness() | 全亮渲染 |
redstone_level() | 紅石之訊 0..15 |
is_crosshair_target() | 準星所指否 |
block_pos(i) | 方塊坐標之分量(i = 0..2) |
consume_block_use() | 銷本幀所積 onBlockUse 事件之一(每幀至多一遭;同幀連擊,則併而為一——與 JS 事件佇列之行同也) |
game_time_millis() / in_game_time() | 時鐘 |
事件之詳(玩家、手持之物等),經 Api 而讀之:
mtr::Api api(ctx.input());
auto event = api.context().call("events").get("onBlockUse");
if (event.call("occurred").as<bool>()) {
auto detail = event.call("detail");
auto player = detail.call("player");
auto item = detail.call("item");
}
裝飾繪製之上下文 EyeCandyContext,所供者四:draw_model(model, matrices)、play_sound(sound, volume, pitch)、set_outline_shape(boxes, count)、set_collision_shape(boxes, count) 是也(每匣 6 float;碰撞匣之高,沿 Java 端 1.5 格之限,踰之者宿主校而誌於日誌)。電梯復用同一上下文之型(LiftContext = EyeCandyContext)。
器用之型
<mtr/util.hpp> 供輪播與狀態追跡之器具,於熱路徑甚友善(零分配):
// "A|B|C" 每 40 tick 更迭一段,切視圖惟算偏移
mtr::CycleTracker dest{"KOWLOON|TSUEN WAN"};
StrView current = dest.value(vehicle.in_game_time());
| 成員 | 釋義 |
|---|---|
CycleTracker(packed, interval_ticks=40) | 構輪播(映 TextUtil.cycleString) |
value(game_tick) / value_str(game_tick) | 當前活躍之段(視圖 / 字串) |
interval() / part_count() | 更迭之隔與段數 |
StrView | {data, len} 字串之視圖:.str()、.empty(),可比之以 == |
狀態機之追跡,則有 mtr::StateTracker<T> 焉(映上游 StateTrackerJS;時鐘顯傳——快照之 game_time_millis(),天然之準也):以其欄納諸 State,render 之際,一斷其遷而已:
struct State {
mtr::StateTracker<Phase> phase; // 跨幀常存
};
// render 之中:
if (s.phase.set_state(next, vehicle.game_time_millis())) {
// 得 true —— 初入此態之幀也(上游 prerelease.2 新義)
}
double staying = s.phase.state_now_duration(vehicle.game_time_millis());
if (s.phase.changed_from_to(PHASE_IDLE, PHASE_ARRIVING)) { /* 演進場之動畫 */ }
| 成員 | 釋義 |
|---|---|
set_state(value, now_ms) | 更其狀態;所返者,初入此態之幀否(上游 v2.3.0-prerelease.2 起 setState 返布林) |
state_now() / state_last() / state_now_first() | 今態 / 前態;初幀否 |
state_now_duration(now_ms) | 今態所歷之毫秒 |
changed_to(state) / changed_from_to(old, new) | 此幀入某態否 / 自某態而遷否 |
繼之:繪事與畫布 —— 取此數據而繪之。