Connection and versions
How bedboo connects to a Bedrock server, which versions it speaks, and how the join, the spawn and dimension changes map onto mineflayer's events. Observed on BDS 1.26.51.1 (protocol 2193) with bedrock-protocol 3.60.1.
Versions
- Affects:
bot.version,bot.majorVersion,bot.protocolVersion, the exportstestedVersions,latestSupportedVersion,oldestSupportedVersion,supportFeature(feature, version). - Java: Java versions ('1.21.4', protocol 769); several are supported.
- Bedrock: Bedrock versions; bedboo supports only the latest one.
- bedboo:
bot.version = '1.26.51',majorVersion = '1.26',protocolVersion = 2193;testedVersions = ['1.26.51'].createBot({ version })accepts'1.26.51'orfalse(auto) and, like mineflayer, throws for anything else. The module-levelsupportFeature(feature, version)answers from the Bedrock feature table for 1.26.51 / 'bedrock_1.26.51' / no version, without building a registry, and from minecraft-data for other versions (as upstream).
Protocol client and connect
- Affects:
bot._client,connectevent,createBotoptionsauth,host,port,profilesFolder,onMsaCode. - Java: a minecraft-protocol client;
connectfires when the TCP socket connects. - Bedrock: a bedrock-protocol
Client(RakNet). There is noconnectevent:loggingInfires once the RakNet connection and the network settings are done, when the login packet is sent. - bedboo:
bot._clientis the bedrock-protocol client (on,queue,write);connectis emitted once onloggingIn. Defaults: host 127.0.0.1, port 19132, RakNet (raknet-native),skipPing,conLog: null.auth: 'offline'is the default;auth: 'microsoft'is Xbox Live with prismarine-auth (profilesFolder,onMsaCode,authTitle,floware passed through);auth: 'mojang'throws (there are no Mojang accounts on Bedrock). An explicit bedrock-protocolofflineoption wins. See createBot options.
Transports: RakNet by default, NetherNet on request
-
Affects:
createBotoptionstransport,nethernet;bot._client.connection. -
Java: one transport (TCP, minecraft-protocol).
-
Bedrock: BDS 1.26.51 offers two:
- NetherNet (its default): WebRTC data channels, with signalling over HTTP on
server-portTCP (POST /v1/join/<network id>with the SDP offer, answered with the signed SDP answer), over LAN discovery on UDP 7551, or through Xbox services. - RakNet (
transport=raknet): the transport of every Bedrock version so far. BDS prints aTRANSPORT TYPE ERRORbanner when it is selected, and Mojang announced its removal, possibly in BDS 26.60.
A NetherNet server does not open its RakNet ports and vice versa.
- NetherNet (its default): WebRTC data channels, with signalling over HTTP on
-
bedboo:
transport: 'raknet'is the default (raknet-native).transport: 'nethernet'joins with HTTP signalling onhost:portunlessnethernet.signallingsays'lan'/'services'. bedrock-protocol#831 and node-nethernet#32 (unreleased) are backported aspatches/bedrock-protocol@3.61.0.patchandpatches/nethernet@1.1.2.patch(plus apackageExtensionsentry for nethernet's new jsonwebtoken dependency). The server signs its answer with an identity key; plain HTTP cannot vouch for that key, so it is accepted unlessnethernet.serverKeypins it ('sha256:<hex of the DER SPKI>'; a mismatch is refused withUntrusted Nethernet server key …) ornethernet.onServerKey(fingerprint, url)decides. This is the same trust as RakNet, whose handshake key is not pinned either. Everything above the transport (packets, plugins, events) is identical.
NetherNet: the server port must be free on TCP too
- Affects: servers run with
transport=nethernet. - Java: n/a.
- Bedrock: with
transport=nethernetBDS opens its HTTP signalling listener on TCPserver-portand logsAccepting clients on [::]:<port>. If that TCP port is still held (e.g. byTIME_WAITconnections of the previous server on the same port, for about a minute), BDS starts without the listener and without any error; every client then getsECONNREFUSED. - bedboo: nothing in the library. When a NetherNet join fails with
ECONNREFUSED, check that the server log has theAccepting clientsline and that the TCP port was free when BDS started.
Kick reason
- Affects:
kickedevent. - Java:
reasonis a JSON chat component (a string, or an object since 1.20.3);loggedIntells the play state from the login state. - Bedrock:
disconnect { reason: <code>, hide_disconnect_reason, message }; the message is free text or a translation key (disconnectionScreen.serverFull), often empty (then only the code says why, e.g.server_id_conflict,missing_client). - bedboo:
reason= the message, or the reason code name when the message is empty or hidden;loggedIn= start_game was received. bedrock-protocol closes the connection after a kick, soendfollows.
Keep-alive
- Affects: the connection's keep-alive (no API).
- Java:
ping→pong, keep-alive packets. - Bedrock:
network_stack_latency { timestamp, needs_response }. - bedboo: bedrock-protocol answers
network_stack_latencywith the same timestamp; the game plugin needs no handler.
Resource packs
- Affects:
resourcePackevent,bot.acceptResourcePack(),bot.denyResourcePack(). - Java: one pack per
resource_pack_send/add_resource_pack(url + hash or uuid); the client answers ACCEPTED + SUCCESSFULLY_LOADED or DECLINED; the server decides what a decline means. - Bedrock: all packs come in
resource_packs_infoduring login (before start_game), with uuid, version and an optional CDN url, no hash. The client answersresource_pack_client_responsewith a status name BDS checks:- 'completed': join;
- 'have_all_packs': join without downloading (BDS sends
resource_pack_stack, answered 'completed'); - 'refused' / 'cancel': BDS disconnects (
missing_client), also for optional packs.
- bedboo:
resourcePack(url, hash, uuid)is emitted per pack with url = the CDN url or '' and hash = the Bedrock pack id<uuid>_<version>. Without a listener the packs are accepted at once; with one, the answer waits foracceptResourcePack()('completed') ordenyResourcePack()('have_all_packs' for optional packs = join without them; 'refused' for required packs = BDS kicks,kicked('missing_client', false)). Packs are never downloaded. This needs the bedrock-protocol patch (client.holdResourcePacks/client.respondToResourcePacks).
Client settings
- Affects:
bot.settings.*,bot.setSettings(),bot.game.serverViewDistance. - Java: a
settingspacket (locale, view distance, chat mode, colours, skin parts, main hand, filtering, server listing, particles). - Bedrock: only the chunk radius is negotiated (
request_chunk_radius→chunk_radius_update); skin parts, main hand etc. are part of the login skin data or not configurable. - bedboo: the same
bot.settingsobject, defaults and validation errors as upstream.viewDistance('far' 12, 'normal' 10, 'short' 8, 'tiny' 6 chunks, or a number) is the only setting sent: the join request is bedrock-protocol's (it readsclient.viewDistance, kept in sync), latersetSettingscalls sendrequest_chunk_radius { chunk_radius, max_radius }.bot.game.serverViewDistanceis the radius granted by the server (chunk_radius_update). Every other setting is kept locally only.
Server brand
- Affects:
bot.game.serverBrand. - Java: the
minecraft:brandplugin channel ('vanilla', 'Paper', …). - Bedrock: no brand channel; start_game has an optional
server_identifier(empty on BDS). - bedboo:
server_identifierwhen set, else'vanilla'(BDS is the vanilla Bedrock server).
No player limit on the client
- Affects:
bot.game.maxPlayers. - Java: the login packet carries the server's max players.
- Bedrock: start_game has no player limit; it is only in the unconnected pong, which BDS does not send with
enable-lan-visibility=false(and the bot connects without a ping). - bedboo:
bot.game.maxPlayersstaysundefined.
Level type
- Affects:
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'.
Entity id at login
- Affects:
bot.entity.id,bot.entity.uniqueId. - Java: a proxy may send a second login packet with a new entity id.
- Bedrock: start_game is sent once per connection; a server transfer is a new connection.
- bedboo:
bot.entity.id = Number(start_game.runtime_entity_id)andbot.entity.uniqueId = start_game.entity_id; a re-login with a new entity id on the same connection cannot happen.
Offline players keep their saved data
- Affects:
createBot({ auth: 'offline' }): the player's inventory, position, spawn point, … across reconnects and server restarts. - Java: an offline-mode player's UUID is
nameUUIDFromBytes("OfflinePlayer:" + name): a rejoin is the same player, and the server restores its saved data. - Bedrock: BDS keys an offline (xuid 0) player's saved data by the login's
SelfSignedId, which bedrock-protocol randomizes for every connection. Measured on BDS 1.26.51.1: give items, quit, rejoin (same server, or a server started from a snapshot of the world) → empty inventory at the world spawn. With a fixedSelfSignedIdthe rejoin gets its inventory and position back. - bedboo: for offline auth the
SelfSignedIddefaults to Java's offline-mode UUID of the username (offlineSelfSignedId,lib/client.js);skinData.SelfSignedIdoverrides it; Xbox Live logins are untouched.
Spawn
- Affects:
spawnevent. - Java: emitted on the first health update after login / after a respawn.
- Bedrock: the join is start_game (spawn search height, y 32769.62) →
respawnstate 0 ×2 →respawnstate 1 (the real position) → clientrespawnstate 2 →play_status player_spawn→ clientserverbound_loading_screen1 and 2 (without them BDS does not simulate the player). - bedboo:
spawncomes from the lifecycle (lib/bedrock/lifecycle.js, its only emitter) once the real position is known and the loading screen is acked, afterloginandgame, like mineflayer. It is emitted again after a dimension change and after a respawn.
spawn and the spawn search height
- Affects:
spawnafter the End exit portal and after a respawn into another dimension;bot.spawnPointon a default (non-flat) world. - Java: the server sends the position before the health update that makes mineflayer emit
spawn; the spawn position packet carries the real spawn block. - Bedrock: Bedrock uses a placeholder height (the spawn search height) while the server has not found the real
one:
- The End exit's
change_dimensioncarries y 32767; BDS answers the dimension ack at once and sends the real position ~50 ms later inrespawnstate 1. - In a respawn into another dimension BDS often corrects the respawning player to the search height
(
correct_player_move_predictiony 32768.62, before or after the realrespawnstate 1; seen in 4 of 6 deaths in the nether) and to the real position ~300 ms later. start_game.spawn_positionhas y = 32767 until the server fixed the height (BDS searches the highest safe block when a player spawns there). A pathfinder goal at that y makes a bot pillar upwards.
- The End exit's
- bedboo:
- The
change_dimension/respawnsearch heights are not applied (nomove/forcedMovethere). While the bot's last server position is the search height,spawnwaits for the real one (the nextforcedMovebelow it, emitted first), at most 2 s; meanwhile the input clock stays suspended (End exit) or the bot stays in the respawning state. bot.spawnPoint(lib/plugins/spawn_point.js): a 32767 height is replaced by the spawn column's highest solid block + 1 as soon as that overworld column is loaded (chunkColumnLoad/spawn); x and z are kept, a real height (/setworldspawn) is never touched, and nothing is resolved while the bot is in another dimension. The resolution during the join (the spawn column loads beforespawn) emits nogameof its own: it is part of start_game's spawn position, covered by the login'sgame(mineflayer's order connect → login → game → spawn). A later resolution emitsgamelike upstream on a spawn point change. See also spawn point.
- The
Dimensions
- Affects:
bot.game.dimension,bot.game.minY,bot.game.height,bot._getDimensionName(). - Java: dimension types and heights come from the registry codec; world names
minecraft:overworld,minecraft:the_nether,minecraft:the_end; arespawnpacket switches the dimension. - Bedrock: no codec: dimension ids 0 / 1 / 2 (start_game maps them to 'overworld' / 'nether' / 'end'), fixed
heights (overworld -64..319, nether 0..127, end 0..255). A dimension change is
change_dimension { dimension, position (FEET level), loading_screen_id }; the client acks withplayer_action dimension_change_ack; BDS answers with its owndimension_change_ack(no play_status) once the new dimension is ready, then the client sendsserverbound_loading_screen1 and 2. - bedboo:
bot.game.dimensionuses mineflayer's names ('overworld', 'the_nether', 'the_end'), minY / height come from the fixed table, and_getDimensionName()returnsminecraft:<dimension>. Onchange_dimensionthe world is reset (every column unloaded →chunkColumnUnload, per-positionblockUpdate:listeners called withnull, nulland removed, like upstream's switchWorld),gameis emitted, and the lifecycle emitsspawnagain once the server acked (mineflayer emitsspawnafter a dimension change too, through health). The rest of the dimension flow (respawnevent, End credits, portals) is described in dimension change.