跳到正文
本頁目錄

連接與版本

bedboo 如何連接 Bedrock 服務器、支持哪些版本,以及加入、出生和維度切換如何對應到 mineflayer 的事件。觀察環境為 BDS 1.26.51.1(protocol 2193)與 bedrock-protocol 3.60.1。

版本

  • 影響: bot.version、bot.majorVersion、bot.protocolVersion,導出項 testedVersions、 latestSupportedVersion、oldestSupportedVersion、supportFeature(feature, version)。
  • Java: Java 版本號('1.21.4',protocol 769),同時支持多個版本。
  • Bedrock: Bedrock 版本號;bedboo 只支持最新的一個。
  • bedboo: bot.version = '1.26.51'、majorVersion = '1.26'、protocolVersion = 2193; testedVersions = ['1.26.51']。createBot({ version }) 接受 '1.26.51' 或 false(自動),其他值會像 mineflayer 一樣拋出異常。模塊級的 supportFeature(feature, version) 在版本為 1.26.51、'bedrock_1.26.51' 或未指定時,直接查 Bedrock 特性表,無需構建 registry;其他版本則與上游一樣查 minecraft-data。

協議客戶端與 connect

  • 影響: bot._client、connect 事件,createBot 選項 auth、host、port、profilesFolder、onMsaCode。
  • Java: minecraft-protocol 客戶端;TCP socket 連上時觸發 connect。
  • Bedrock: bedrock-protocol 的 Client(RakNet)。沒有 connect 事件:RakNet 連接和 network settings 完成、 發送 login 包時觸發 loggingIn。
  • bedboo: bot._client 就是 bedrock-protocol 客戶端(on、queue、write);connect 在 loggingIn 時觸發一次。 默認值:host 127.0.0.1、port 19132、RakNet(raknet-native)、skipPing、conLog: null。默認 auth: 'offline'; auth: 'microsoft' 是通過 prismarine-auth 登錄 Xbox Live(透傳 profilesFolder、onMsaCode、authTitle、flow); auth: 'mojang' 會拋出異常(Bedrock 沒有 Mojang 賬號)。顯式傳入的 bedrock-protocol offline 選項優先。參見 createBot 選項。

傳輸層:默認 RakNet,可選 NetherNet

  • 影響: createBot 選項 transport、nethernet;bot._client.connection。

  • Java: 只有一種傳輸層(TCP,minecraft-protocol)。

  • Bedrock: BDS 1.26.51 提供兩種:

    • NetherNet(BDS 默認):WebRTC data channel,信令可走 server-port TCP 上的 HTTP (POST /v1/join/<network id> 攜帶 SDP offer,返回簽名的 SDP answer)、UDP 7551 上的局域網發現,或 Xbox 服務。
    • RakNet(transport=raknet):迄今所有 Bedrock 版本使用的傳輸層。選用它時 BDS 會打印 TRANSPORT TYPE ERROR 橫幅,Mojang 已宣佈將移除它,可能在 BDS 26.60。

    NetherNet 服務器不會打開 RakNet 端口,反之亦然。

  • bedboo: 默認 transport: 'raknet'(raknet-native)。transport: 'nethernet' 通過 host:port 上的 HTTP 信令加入, 除非 nethernet.signalling 指定 'lan' / 'services'。bedrock-protocol#831 和 node-nethernet#32(尚未發佈)以 patches/bedrock-protocol@3.61.0.patch 與 patches/nethernet@1.1.2.patch 的形式回移(另加一條 packageExtensions,為 nethernet 新增的 jsonwebtoken 依賴)。服務器用身份密鑰對 answer 簽名;純 HTTP 無法擔保該密鑰, 因此默認接受,除非用 nethernet.serverKey 固定它('sha256:<hex of the DER SPKI>',不匹配時以 Untrusted Nethernet server key … 拒絕),或由 nethernet.onServerKey(fingerprint, url) 決定。這與 RakNet 的信任程度 相同,RakNet 的握手密鑰同樣沒有固定。傳輸層之上的一切(數據包、插件、事件)完全相同。

NetherNet:服務器端口的 TCP 也必須空閒

  • 影響: 以 transport=nethernet 運行的服務器。
  • Java: 不適用。
  • Bedrock: 使用 transport=nethernet 時,BDS 在 TCP server-port 上打開 HTTP 信令監聽,並輸出 Accepting clients on [::]:<port>。如果該 TCP 端口仍被佔用(例如同一端口上一臺服務器遺留的 TIME_WAIT 連接, 約持續一分鐘),BDS 會在沒有監聽的情況下啟動,且不報任何錯誤;之後所有客戶端都會得到 ECONNREFUSED。
  • bedboo: 庫中無需處理。若 NetherNet 加入因 ECONNREFUSED 失敗,請檢查服務器日誌中是否有 Accepting clients 這一行,以及 BDS 啟動時該 TCP 端口是否空閒。

踢出原因

  • 影響: kicked 事件。
  • Java: reason 是 JSON 聊天組件(字符串,1.20.3 起也可以是對象);loggedIn 區分遊戲狀態與登錄狀態。
  • Bedrock: disconnect { reason: <code>, hide_disconnect_reason, message };message 是自由文本或翻譯鍵 (disconnectionScreen.serverFull),經常為空(此時只有 code 說明原因,例如 server_id_conflict、missing_client)。
  • bedboo: reason = message;message 為空或被隱藏時取 reason code 的名字;loggedIn = 已收到 start_game。 被踢出後 bedrock-protocol 會關閉連接,隨後觸發 end。

心跳

  • 影響: 連接心跳(無 API)。
  • Java: ping → pong,keep-alive 包。
  • Bedrock: network_stack_latency { timestamp, needs_response }。
  • bedboo: bedrock-protocol 用相同的 timestamp 回應 network_stack_latency;game 插件無需處理。

資源包

  • 影響: resourcePack 事件、bot.acceptResourcePack()、bot.denyResourcePack()。
  • Java: 每個 resource_pack_send / add_resource_pack 一個包(url + hash 或 uuid);客戶端回應 ACCEPTED + SUCCESSFULLY_LOADED 或 DECLINED;拒絕意味著什麼由服務器決定。
  • Bedrock: 所有資源包在登錄期間(start_game 之前)通過 resource_packs_info 一次發來,帶 uuid、版本和可選的 CDN url, 沒有 hash。客戶端以 resource_pack_client_response 回應,BDS 檢查其中的狀態名:
    • 'completed':加入;
    • 'have_all_packs':不下載直接加入(BDS 發送 resource_pack_stack,再回應 'completed');
    • 'refused' / 'cancel':BDS 斷開連接(missing_client),可選包也是如此。
  • bedboo: 每個包觸發一次 resourcePack(url, hash, uuid),url = CDN url 或 '',hash = Bedrock 包 id <uuid>_<version>。沒有監聽器時立即接受所有包;有監聽器時等待 acceptResourcePack()('completed')或 denyResourcePack()(可選包回 'have_all_packs' = 不帶這些包加入;必需包回 'refused' = 被 BDS 踢出, kicked('missing_client', false))。資源包從不下載。此功能依賴 bedrock-protocol 補丁 (client.holdResourcePacks / client.respondToResourcePacks)。

客戶端設置

  • 影響: bot.settings.*、bot.setSettings()、bot.game.serverViewDistance。
  • Java: 一個 settings 包(語言、視距、聊天模式、顏色、皮膚部件、主手、過濾、服務器列表、粒子)。
  • Bedrock: 只協商區塊半徑(request_chunk_radius → chunk_radius_update);皮膚部件、主手等屬於登錄時的皮膚數據, 或者不可配置。
  • bedboo: bot.settings 對象、默認值和校驗錯誤與上游相同。只有 viewDistance('far' 12、'normal' 10、'short' 8、 'tiny' 6 個區塊,或一個數字)會被髮送:加入時的請求由 bedrock-protocol 發出(它讀取保持同步的 client.viewDistance), 之後的 setSettings 調用發送 request_chunk_radius { chunk_radius, max_radius }。bot.game.serverViewDistance 是 服務器批准的半徑(chunk_radius_update)。其他設置只保存在本地。

服務器品牌

  • 影響: bot.game.serverBrand。
  • Java: minecraft:brand 插件頻道('vanilla'、'Paper' 等)。
  • Bedrock: 沒有品牌頻道;start_game 有一個可選的 server_identifier(BDS 上為空)。
  • bedboo: 有 server_identifier 時取其值,否則為 'vanilla'(BDS 即原版 Bedrock 服務器)。

客戶端拿不到玩家上限

  • 影響: bot.game.maxPlayers。
  • Java: login 包攜帶服務器的最大玩家數。
  • Bedrock: start_game 不含玩家上限;它只在 unconnected pong 中,而 BDS 在 enable-lan-visibility=false 時不發送 pong (且機器人連接時不 ping)。
  • bedboo: bot.game.maxPlayers 保持 undefined。

世界類型

  • 影響: bot.game.levelType。
  • Java: 'default'、'flat'、'largeBiomes'、'amplified' 等。
  • Bedrock: start_game.generator:0 legacy、1 infinite、2 flat、3 nether、4 the end、5 void。
  • bedboo: 1 → 'default'、2 → 'flat'、0 → 'legacy'、5 → 'void'、3 / 4 → 'nether' / 'the_end'。

登錄時的實體 id

  • 影響: bot.entity.id、bot.entity.uniqueId。
  • Java: 代理可能發送第二個 login 包,帶新的實體 id。
  • Bedrock: 每個連接只發送一次 start_game;服務器轉移是一個新連接。
  • bedboo: bot.entity.id = Number(start_game.runtime_entity_id),bot.entity.uniqueId = start_game.entity_id;同一連接上以新實體 id 重新登錄的情況不會發生。

離線玩家保留存檔數據

  • 影響: createBot({ auth: 'offline' }):玩家的物品欄、位置、出生點等在重連和服務器重啟後是否保留。
  • Java: 離線模式玩家的 UUID 是 nameUUIDFromBytes("OfflinePlayer:" + name):重新加入仍是同一玩家,服務器恢復其存檔數據。
  • Bedrock: BDS 以登錄中的 SelfSignedId 作為離線(xuid 0)玩家存檔數據的鍵,而 bedrock-protocol 每次連接都會隨機生成它。 在 BDS 1.26.51.1 上實測:給予物品、退出、重新加入(同一服務器,或從世界快照啟動的服務器)→ 物品欄為空,位於世界出生點。 使用固定的 SelfSignedId 重新加入則能取回物品欄和位置。
  • bedboo: 離線認證時 SelfSignedId 默認取用戶名對應的 Java 離線模式 UUID(offlineSelfSignedId,lib/client.js); 可用 skinData.SelfSignedId 覆蓋;Xbox Live 登錄不受影響。

出生

  • 影響: spawn 事件。
  • Java: 在登錄後 / 重生後的第一次生命值更新時觸發。
  • Bedrock: 加入流程為 start_game(出生搜索高度,y 32769.62)→ respawn state 0 ×2 → respawn state 1(真實位置)→ 客戶端 respawn state 2 → play_status player_spawn → 客戶端 serverbound_loading_screen 1 和 2(沒有它們,BDS 不會模擬該玩家)。
  • bedboo: spawn 由生命週期模塊(lib/bedrock/lifecycle.js,唯一的觸發者)在真實位置已知且加載界面已確認後觸發, 順序在 login 和 game 之後,與 mineflayer 一致。維度切換和重生之後會再次觸發。

spawn 與出生搜索高度

  • 影響: 經末地出口傳送門之後、以及重生到另一維度之後的 spawn;默認(非超平坦)世界上的 bot.spawnPoint。
  • Java: 服務器先發送位置,再發送使 mineflayer 觸發 spawn 的生命值更新;出生點數據包攜帶真實的出生方塊。
  • Bedrock: 服務器尚未找到真實高度時,Bedrock 使用一個佔位高度(出生搜索高度):
    • 末地出口的 change_dimension 攜帶 y 32767;BDS 立即回應維度確認,約 50 ms 後才在 respawn state 1 中發送真實位置。
    • 重生到另一維度時,BDS 經常把正在重生的玩家修正到搜索高度(correct_player_move_prediction y 32768.62,在真實的 respawn state 1 之前或之後;下界中 6 次死亡裡見到 4 次),約 300 ms 後再修正到真實位置。
    • 在服務器確定高度之前,start_game.spawn_position 的 y = 32767(有玩家在那裡出生時,BDS 會搜索最高的安全方塊)。 以該 y 為目標的尋路會讓機器人一直向上搭柱子。
  • bedboo:
    • 不應用 change_dimension / respawn 中的搜索高度(這裡不觸發 move / forcedMove)。當機器人最後的服務器位置是 搜索高度時,spawn 會等待真實位置(下一個低於它的 forcedMove,先於 spawn 觸發),最多 2 s;在此期間輸入時鐘保持 暫停(末地出口),或機器人保持在重生中狀態。
    • bot.spawnPoint(lib/plugins/spawn_point.js):一旦出生點所在的主世界區塊列加載完成(chunkColumnLoad / spawn), 32767 的高度就被替換為該列最高實心方塊 + 1;x 和 z 保持不變,真實高度(/setworldspawn)不會被改動,機器人在其他維度時 不做解析。加入期間的解析(出生點區塊列在 spawn 之前加載)不單獨觸發 game:它屬於 start_game 的出生點位置,由登錄時的 game 涵蓋(mineflayer 的順序為 connect → login → game → spawn)。之後的解析會像上游出生點變化時一樣觸發 game。 另見出生點。

維度

  • 影響: bot.game.dimension、bot.game.minY、bot.game.height、bot._getDimensionName()。
  • Java: 維度類型和高度來自 registry codec;世界名為 minecraft:overworld、minecraft:the_nether、 minecraft:the_end;respawn 包切換維度。
  • Bedrock: 沒有 codec:維度 id 為 0 / 1 / 2(start_game 將其映射為 'overworld' / 'nether' / 'end'),高度固定 (主世界 -64..319、下界 0..127、末地 0..255)。維度切換為 change_dimension { dimension, position (FEET level), loading_screen_id };客户端以 player_action dimension_change_ack 確認;新維度 就緒後 BDS 回以它自己的 dimension_change_ack(沒有 play_status),隨後客戶端發送 serverbound_loading_screen 1 和 2。
  • bedboo: bot.game.dimension 使用 mineflayer 的名字('overworld'、'the_nether'、'the_end'),minY / height 來自固定表, _getDimensionName() 返回 minecraft:<dimension>。收到 change_dimension 時重置世界(卸載所有區塊列 → chunkColumnUnload, 按位置註冊的 blockUpdate: 監聽器以 null, null 調用後移除,與上游的 switchWorld 相同),觸發 game,並在服務器確認後由 生命週期再次觸發 spawn(mineflayer 在維度切換後也會通過 health 觸發 spawn)。維度流程的其餘部分(respawn 事件、 末地製作人員名單、傳送門)見維度切換。