數據快照

快照之機

每幀方始,宿主以此實例之數據一舉搬運,為一 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 三代之 train → MTR 四代之 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)此幀入某態否 / 自某態而遷否

繼之:繪事與畫布 —— 取此數據而繪之。