BDS 筆記
在基岩版專用服務器 1.26.51.1 上運行機器人時值得了解的行為:服務器打印什麼、發送什麼、何時發送。bedboo 已經處理了所有這些情況; 這些筆記在你閱讀數據包日誌或編寫服務器控制台腳本時會有幫助。
啟動與端口
- 就緒行:
[… INFO] Server started.;當transport=raknet時,其後緊跟一個多行的TRANSPORT TYPE ERROR信息塊 ("Your current connection type is not set to NetherNet … Players will not be able to connect")。它是無害的:RakNet 客戶端可以正常連接。BDS 還會輸出Signed in to signaling service successfully。一個全新的超平坦世界大約在進程啟動後 1 秒 就緒。 - 端口被佔用時會打印
ERROR] Port [<port>] may be in use by another process. Free up port and re-run program …, 然後是Exiting program和一份崩潰轉儲;服務器會在一秒內退出。 - NetherNet: BDS 在 TCP
server-port上打開信令監聽,並輸出Accepting clients on [::]:<port>。如果該 TCP 端口 仍被佔用(例如上一個服務器留下的TIME_WAIT連接,約持續一分鐘),服務器會在沒有監聽的情況下運行且不輸出任何信息;客戶端隨後 會得到ECONNREFUSED。 - Ping: 在
enable-lan-visibility=false時 BDS 不響應未連接 ping,因此 bedboo 默認skipPing: true。
傳輸層與後端
- 基於 raknet-native 的 RakNet 可以工作(加入 ≈0.3 秒,
start_game≈0.5 秒,spawn≈1.0 秒)。raknet-native 1.2.3 只捆綁了 x64 預編譯包(linux-5-x64、darwin-21-x64、win32-10-x64),且禁用了源碼構建,因此 arm64 主機(Apple Silicon、 linux-arm64)沒有 RakNet 後端。工作區補丁讓綁定能在較新的內核(linux-6)上找到捆綁的預編譯包;該預編譯包需要 glibc ≥ 2.34。 raknetBackend: 'jsp-raknet'會失敗:BDS 對 open-connection 請求的應答是ID_INCOMPATIBLE_PROTOCOL_VERSION(服務器的 RakNet 協議為 11;jsp-raknet 使用 10)。- 在服務器端口上使用 HTTP 信令的 NetherNet 可以工作(加入 ≈1.7 秒,spawn ≈2.6 秒)。bedrock-protocol 和 node-nethernet 的 HTTP 信令通過工作區補丁回移。
加入流程
start_game.player_position為(0.5, 32769.62, 0.5)(出生點搜索高度),隨後是三個respawn數據包: 32769.62 處的 state 0、32768 處的 state 0,以及位於真實眼睛高度出生點的 state 1(超平坦世界上為(0.5, -58.38, 0.5), 腳部 y = -60)。客戶端以respawn { state: 2, runtime_entity_id }回應 state 1。然後是區塊和play_status player_spawn。- 加載界面閘門: 生成之後,BDS 不會模擬玩家(忽略
player_auth_input中的位置和移動向量,也沒有correct_player_move_prediction),直到客戶端發送serverbound_loading_screen { type: 1 }和{ type: 2 }。此後行走輸入 才會移動玩家,不可能的移動會被糾正。 start_game:rewind_history_size = 40、server_authoritative_block_breaking = true、server_authoritative_inventory = true、block_network_ids_are_hashes = true;player_gamemode為fallback,因此 遊戲模式保存在world_gamemode中。默認server.properties:server-authoritative-movement-strict=false、player-position-acceptance-threshold=0.5。player_list以records: [{ type: 'add', username, … }]的形式到達,此時玩家尚未生成,也無法被選中。
區塊與保存
level_chunk總是以子區塊請求模式到達(sub_chunk_count: 0且帶有highest_subchunk_count),從不內聯子區塊。subchunk_request { dimension, origin, requests: [{ x: 0, y: -4..19, z: 0 }] }返回一個subchunk,其中每個請求對應一個條目 (帶負載的success,或success_all_air)。request_chunk_radius 10之後,network_chunk_publisher_update的半徑從 64 變為 160 格。- 附近沒有玩家時區塊不會加載:
setblock/testforblock會回應Cannot place block outside of the world。 - 修改過的區塊每 5–10 秒才寫入一次 LevelDB,而且
save hold不會刷新它們,因此在線備份可能遺漏最近的改動。正常停止服務器 會保存所有內容。
控制台命令
say/tellraw在控制台上不打印任何內容;命令錯誤是ERROR行(Unknown command: <cmd>. Please check that the command exists …、No targets matched selector、Syntax error: …)。list打印There are n/max players online:以及一行玩家名;querytarget打印一個 JSON 塊(y為眼睛高度);gamerule(不帶參數)在一行中打印所有規則;testforblock打印Successfully found the block at x,y,z./The block at x,y,z is Air (expected: …)。gamemode <m> <player>發送update_player_game_type { gamemode, player_unique_id }(而不是set_player_game_type);玩家已處於該模式時不發送任何內容。遊戲模式命令對已死亡的玩家無效 (No targets matched selector)。tp <p> 10 -60 10會將整數 x/z 居中(Teleported p to 10.50, -60.00, 10.50),並在眼睛高度發送move_player { mode: 'teleport', teleport: { cause: 'command' } }。setblock打印Block placed併發送update_block;再次放置同一方塊會打印The block couldn't be placed且不發送任何內容。summon打印Object successfully summoned併發送add_entity(腳部位置,已居中);kill @e[type=pig]打印Killed Pig, 並依次發送entity_event death_animation、掉落物(add_item_entity),然後是remove_entity。- 創造模式玩家無法被殺死(
Players cannot be killed while they are in Creative mode.),即使使用/damage … void或掉入 虛空也不行。
值得了解的數據包
- 客戶端發出的命令:
command_request { command, origin: { type: 'player', uuid, request_id: '' }, … }由command_output應答,其 origin 回顯的是 uuid(而不是request_id),另外還有一個event { event_type: 'command_executed' }。 - 聊天: 客戶端的
text聊天(type: 'chat'、category: 'authored')會以source_name: '<name>§r'回顯給所有人。 - 物品欄:
/give、/replaceitem(快捷欄 / 物品欄)和/clear(即使沒有清除任何東西)會發送所有窗口的inventory_content(物品欄 36、盔甲 5、ui 54、副手 1);針對盔甲的replaceitem發送inventory_slot;/give還會發送一個inventory_transaction。玩家的物品帶有stack_id。 - 物品欄重發:
inventory_transaction { transaction_type: 'inventory_mismatch' }會讓 BDS 重新發送玩家的物品欄 (inventory_content× 4 +player_hotbar);被拒絕的物品堆疊請求或重新打開物品欄界面都不會觸發重發。 - 死亡: 自身的
entity_event death_animation、death_info、text(death.attack.generic)、死亡位置處的respawnstate 0。重生:客戶端respawnstate 2 → 服務端respawnstate 0(y 32767)+ state 1(眼睛高度的出生點)→ 客戶端player_action respawn→entity_event respawn+set_health 20。 - 時間: 沒有
set_time數據包,即使是/time set也沒有;時間通過sync_world_clocks傳遞。 - 下落方塊: 方塊開始下落以及下落方塊落地都只以
update_block_synced到達,從不以update_block到達 (下落方塊)。 - 生物: 超平坦世界會持續生成被動生物:每分鐘數百個
move_entity_delta。