Digging and placing
How bot.dig, bot.placeBlock, bot.placeEntity and item use on blocks work on Bedrock, where the server breaks and
places blocks itself. Observed on BDS 1.26.51.1 (protocol 2193, bedrock-protocol 3.60.1).
Server-authoritative block breaking
- Affects:
bot.dig,bot.stopDigging,diggingCompleted,diggingAborted,bot.targetDigBlock - Java: the client sends
block_digstart (status 0), waitsdigTimems itself, sends finish (status 2) and sets the block to air locally; cancel = status 1. - Bedrock:
start_game.server_authoritative_block_breakingis true on BDS. Block actions rideplayer_auth_input.block_action(one input per tick). Measured behaviour:start_break= the mouse goes down on the block. From that input on, BDS adds the break progress itself every tick — the start tick counts — using its own copy of the held item, effects, on-ground and eyes-in-water state, and destroys the block in the input where the progress reaches 1 (ceil(1/speed)inputs after and including the start one) as long as the break is held: no other action is needed. It reports the speed to every viewer (level_event block_start_breakthenblock_break_speedevery tick, data = progress per tick × 65535, floored) and the destruction withupdate_block(air) +particle_destroy, then the drops (add_item_entity).predict_break(the client's "it broke") is accepted from that same input on; one input earlier BDS answers with anupdate_blockrestoring the block (and, while the break is held, still destroys it a tick later).continue_breakrestarts the break on BDS: every one makes it sendblock_stop_break+block_start_breakto all viewers (another player's crack animation and mineflayer'sblockBreakProgressObservedrestart every tick).crack_breakis accepted and changes nothing.abort_breakends the break.stop_breakdoes not: after a completed break BDS keeps "holding" the position and destroys the next block placed there (even by/setblock) on its own.- The face and the look direction are not validated (any face, looking away, reach up to ~7 blocks all break).
- Creative:
start_breakalone breaks instantly (no drops);player_action creative_player_destroy_blockalone does nothing.
- bedboo:
start_break(in the input after the look), nothing while the break is held, thenpredict_breakonce BDS' own per-tick progress reports (block_break_speed) show the break one tick from done — i.e. in the very input BDS completes it while client and server run in step (the earliest input BDS accepts, measured), later when the server runs behind, never early. A purely client-side tick count is not enough: on a loaded host BDS lags behind the client's input count and restores the block. When BDS sends no reports, bedboo uses its own count with one tick of margin.- Completion is the server's
update_block(air, or a liquid for waterlogged blocks / ice), followed byabort_breakto release the break state;digsettles once the input carrying it went out (≤ 1 tick later), so whatever the caller does next — placing a block at that spot, digging on — reaches BDS after the release (measured: a/setblockright after the update was otherwise broken again by BDS). - Creative and instant breaks (progress ≥ 1 in the first tick):
start_break+predict_breakin one input. stopDigging/ a new dig / death / a dimension change:abort_break.- The speed BDS reports for the dug block replaces the local estimate when they differ, so a mismatch never makes the client predict early.
- Upstream's arm swing every 350 ms is kept (
animate). - Legacy (non server-authoritative) servers get
start_break,crack_breakevery tick, thenstop_break+ aninventory_transactionbreak_blockafterdigTime, and the block is predicted locally like upstream. BDS is always server-authoritative, so this path cannot be exercised against it.
- Completion is the server's
dig() completes on the server's confirmation
- Affects:
bot.dig(when the promise settles),diggingCompleted,bot.lastDigTime - Java: the promise resolves when the client's own
digTimetimer fires (block set to air locally). - Bedrock: the server destroys the block; a client-side air would be a guess the server may contradict.
- bedboo:
digresolves (anddiggingCompletedfires with the air block) after the server'supdate_block: it arrivesdigTime− 1 tick + the round trip after the start input (measured over 848 timed digs on a local BDS: median −21 ms, −75…+44 ms vsdigTime), and the dig settles with the release input up to one tick later (see Server-authoritative block breaking).- BDS sends the destroyed block's
update_blockmore than once within about a tick (the destruction, the answers topredict_break/abort_break): code that waits for "the next update" at that position should let them pass first. - "Broken" = air, a liquid (waterlogged blocks, kelp, coral fans and ice leave water; a bubble column over soul sand / magma), or a turtle egg with one egg less.
- If the server shows no sign of breaking the block for 40 ticks after
predict_break(no update, no speed report — BDS reports the speed every tick while it still breaks; e.g. adventure mode, protected or education-edition blocks) the dig is aborted likestopDigging(diggingAborted, rejectionDigging aborted: the server did not break <name> at <pos>); upstream would resolve regardless. - A disconnect also rejects a pending dig (
Digging aborted: the connection ended; upstream's timer would resolve it). bot._bedrock.digging(internal) keeps diagnostics of the last digs (start / end time, ticks, the speed BDS reported, restores).
- BDS sends the destroyed block's
Dig speed: Bedrock status-effect factors
- Affects:
bot.digTime, andblock.digTime(...)(prismarine-block) as called directly by mineflayer-pathfinder / mineflayer-tool - Java: Haste and Conduit Power multiply the speed by
1 + 0.2 × level; Mining Fatigue by 0.3 / 0.09 / 0.0027 / 0.00081 (levels 1–4+). - Bedrock (measured,
level_eventdata): Haste / Conduit Power (the higher level counts) multiply by(1 + 0.2 × level) × 1.2^level(I 1.44, II 2.016, III 2.7648, V 4.9766); Mining Fatigue by0.21^level(= 0.3^level × 0.7^level: I 0.21, II 0.0441, III 0.0093, IV 0.0019, V 0.0004). Everything else is Java's formula, verified on BDS: tool multipliers per material (from the Bedrock data, incl. golden 12 and copper 5), the tool tier still speeds up a non-harvesting tool (wooden pickaxe on iron ore), Efficiencylevel² + 1only when the tool multiplier is above 1, Aqua Affinity on the helmet, eyes in water ÷5, not on ground ÷5 (both: ÷25),canHarvest ? 30 : 100, hardness 0 = instant (BDS reports 65535 = 1.0),ceil(1/speed)ticks. - bedboo:
bot.digTimeuseslib/bedrock/dig_speed.js(the same structure as prismarine-block'sdigTimewith the Bedrock effect factors; without those effects it equals prismarine-block for every block × tool × water / air / enchantment). prismarine-block's ownblock.digTimekeeps Java's effect factors (unpatched): plugin cost estimates that call it under Haste or Mining Fatigue are off by those factors (the dig itself is right, it waits for the server). The patched mineflayer-pathfinder and mineflayer-tool usebot._bedrock.digging.blockDigTimeinstead (see mineflayer-pathfinder, mineflayer-tool). For every diggable block, the speed BDS reports equalsbot.digTime.
Creative: no breaking with swords, the trident or the mace
- Affects:
bot.digTime,bot.digin creative mode - Java:
digTimeis 0 for everything in creative (Java creative players cannot break blocks with a sword either; upstream ignores it and the server restores the block). - Bedrock (measured): BDS restores the block when a creative player breaks it holding any sword, the trident or the mace; spears, tools, other items and the bare hand break instantly.
- bedboo:
digTimeisInfinityin creative with those items, sodigrejects at once with upstream'sdig time for <name> is Infinityinstead of waiting for the server.
Eye-level water includes waterlogged blocks
- Affects:
bot.digTime,bot._getBlockAtEyeLevel(unchanged) - Java: upstream counts the eyes as under water when the eye-level block is
water/flowing_water. - Bedrock: water can also be the block's second layer (waterlogged blocks, kelp, seagrass).
- bedboo: eyes are under water in
water,flowing_water, or a block whose layer 1 is water (block.isWaterlogged).bot.entity.isInWateris not used (same as upstream). Digging with the eyes under water takes 5× longer, and BDS agrees.
'auto' dig face
- Affects:
bot.targetDigFace, the face of the block actions - Java:
dig(block)withdigFace'auto' looks at the block center and sends face 1 (top). - Bedrock: BDS does not validate the face, but the vanilla client sends the face under its crosshair and the face drives the punch particles other players see.
- bedboo: 'auto' (with a look) uses the face through which the line of sight from the eyes to the block center
enters the block (e.g. 4 = west when the bot is west of it, level with it). Face vectors, 'raycast' and
forceLook: 'ignore'(face 1) are upstream's.
Tool durability
- Affects:
bot.heldItemdurability after a dig,heldItemChanged - Java: the server damages the tool and sends
set_slot. - Bedrock: the vanilla client attaches an
item_stack_requestmine_block{ hotbar slot, predicted durability, stack id } to itspredict_break; BDS only accepts it in the exact input the break completes (one input later it answersstatus: error) and then reports the durability in the response'sdurability_correctioninstead of sending the slot. Without the request BDS damages the tool itself and sendsinventory_slotwith the newDamage. - bedboo: no
mine_blockrequest (the prediction lands in the completing input only while the server runs in step, see Server-authoritative block breaking); the inventory model applies the server'sinventory_slot(Damage +1 per block, the tool disappears when used up,heldItemChangedlike Java'sset_slot).
Digging air
- Affects:
bot.dig(air),bot.digTime(air),registry.blocksByName.air.hardness - Java: air has hardness 0:
digTimeis 0 anddigresolves at once withdiggingCompleted. - Bedrock: minecraft-data PR #1335 and BDS's own block dump give air hardness -1 (unbreakable).
- bedboo: the data overlay sets air's hardness to 0 (
packages/bedrock-data/scripts/tables.jsBLOCK_FIXES), sodigTime(air)is 0 like upstream.bot.digof a block that is air in the world (also a stale Block of a block that is gone by now — a door's other half) completes at once withdiggingCompleted(air)and sends nothing (BDS never reports breaking air). A stale air Block whose position holds a block by now is dug normally.
Blocks that cannot be staged or dug
-
Affects:
bot.dig,bot.digTimeacross the whole block registry -
Java: every diggable Java block can be placed and dug (a few excepted).
-
Bedrock: the registry has 1,442 diggable blocks. On BDS 1.26.51.1 about 230 of them cannot be put into a survival test world or are never broken:
- ids
/setblockrefuses: education-editionelement_*, compounds and hardened glass, internal ids such asunknown/info_update/reserved6, and the*_concrete_double_slab/*_wool_double_slabstates BDS 1.26.51.1 does not know; - blocks that do not stay where they are set (coral wall fans, tripwire hooks, soul fire, bubble columns, …);
frosted_ice(melts during the dig);- the education-edition
allow/deny/border_block(BDS never breaks them in survival).
Attachments that face down by default (buttons, item frames, banners, levers) only stay when set on the floor (
facing_direction1) or on a wall. "Gone" after a dig = air or a liquid (ice, kelp, seagrass, coral fans and sea pickles leave water). - ids
-
bedboo: every other block was dug in survival with the fastest of netherite pickaxe / axe / shovel / hoe and shears (Efficiency V), a netherite sword and the bare hand: BDS' reported speed equalled
bot.digTimeand BDS never restored a dug block.
Progress reports after an instant break
- Affects:
bot._bedrock.digging.last.serverSpeedData(diagnostics) - Java: no equivalent (the client times the dig itself).
- Bedrock: after an instant break BDS may report the block-break progress of what replaced the block (the water a
plant in a water source leaves, e.g.
short_dry_grass) — sometimes in the batch before theupdate_blockof the break. - bedboo: an instant break (start and predict in one input) keeps only an instant report (≥ 1 per tick: the dug block's own) as the server's speed; a slower one only counts as server activity.
Placement protocol: click_block wrapped in start/stop_item_use_on
- Affects:
bot._genericPlace,bot.placeBlock,bot._placeBlockWithOptions,bot.placeEntity,blockPlaced - Java:
block_place(location, direction, hand, cursor); the server answers withblock_changefor the clicked block and then the block across the face, whether or not it placed anything. - Bedrock: like the vanilla client, a click on a block face is
player_action start_item_use_on(clicked block, clicked block + face, face) →inventory_transaction item_use click_block(the exact server copy of the held item incl. its stack id, the clicked block's runtime id, the click point on the face, the face, the hotbar slot, the hand, the player position at EYE level, predictionsuccess) →player_action stop_item_use_on(clicked block + face) 150 ms later. Measured answers (≈ 80–120 ms locally): the inventory first (inventory_contentof every window: the count, durability or new stack id after a use), then a burst ofupdate_block— the clicked block, the block across the face, the clicked block's lower neighbour, the block across the face again, its upper neighbour, the clicked block again — and ~20 ms later the destination once more with theplacesound. A refusal (an entity in the way, the player's own hitbox, an item that is not a block, out of the world) gets the same burst with the destination unchanged (plus aset_entity_dataresync) and no inventory change. - bedboo:
bot.placeBlock/bot._placeBlockWithOptionsare upstream's code (vendored verbatim);bot._genericPlace/bot.placeEntitykeep upstream's checks, options, look and events. The answer has Java's shape (reference block first, then the destination), so upstream'splace_block.jsruns unchanged with its error messages (Server refused to place <item> at <pos>: the block is still <name>,Server did not answer the placement at …,must be holding an item to place)._genericPlaceresolves as soon as the click is queued (upstream: right afterblock_place); the stop of a click is sent before the start of the next one (pairs never interleave). Placement is not predicted client-side (like upstream): the block appears with the server's update.
Sneak-placing against interactive blocks
- Affects:
bot._genericPlaceand everything built on it (placeBlock,placeEntity; mineflayer-pathfinder) - Java: mineflayer does not tell the server it sneaks ("TODO" in
generic_place.js); mineflayer-pathfinder presses sneak itself for itsinteractable.json(Java names). - Bedrock: BDS runs the clicked block's use action (open the chest / crafting table / furnace, toggle a door, open
a sign's editor, …) instead of placing unless the player sneaks; the sneak keys travel in
player_auth_input, which the server must have processed before the click (one input of ordering is enough;set_entity_datasneakingis the acknowledgement). A flying player never gets thesneakingstate but the raw sneak keys of the input count. - bedboo: when the reference block is interactive (
lib/bedrock/placement.jsisInteractive, Bedrock names: containers, stations, doors / trapdoors / gates except iron, buttons, levers, repeaters, comparators, signs, beds, cakes, item frames, …)_genericPlaceholds the sneak control, waits until it went out with an input (bot._bedrock.physics.controlsSent()when present, else the next sent input) and the server acknowledged it (not while flying), clicks, then releases the sneak it pressed (a sneak the caller holds, e.g. mineflayer-pathfinder's, is kept). While riding nothing is pressed (sneaking dismounts on Bedrock). While flying the bot may descend a little during that tick (sneak = descend). This places on top of a chest, crafting table, furnace, wooden door, standing sign or barrel in survival, and against a chest in creative flight.
Placements wait for the server's answer to the previous click
- Affects:
bot.placeBlock,bot._placeBlockWithOptions,bot.placeEntity,bot.activateItemwith buckets and boats — when several run at once or back to back - Java:
block_placecarries no item: placements in flight never invalidate each other. - Bedrock: every click carries the exact server copy of the held item; BDS gives the stack a new stack id after
each use (
inventory_content, right before itsupdate_blockanswer) and refuses a click with the old one (live: two placements 0–30 ms apart → the second refused). - bedboo: clicks are serialized in the placer (
lib/bedrock/placement.js): the next click goes out once the held item was updated, the clicked block was answered, or after 500 ms. Sequential awaited placements (e.g. mineflayer-pathfinder) never wait;Promise.allof placements places all of them. A bucket / boat use (activateItem→ the looked-at block) issued while a placement is unanswered keeps its target and hotbar slot and goes out after it. Other item uses (activateBlock, theclick_airofactivateItem) are not serialized: fired without awaiting right after a placement, they can still carry the old stack id.
A click with a stale block state is retried
- Affects:
bot.placeBlock/_placeBlockWithOptionsagainst a block the server changed right before - Java:
block_placecarries no block state. - Bedrock: the click carries the clicked block's runtime id, and BDS refuses a click whose id is not its own state of that block. BDS changes some blocks a tick after a neighbour update (farmland and grass paths turn into dirt under a placed block, 50–90 ms after the placement's answer), so the next click against them was refused.
- bedboo: the answer to a click discloses the server's state of the clicked block; a refusal whose click carried
another state is retried once with the block as it is now (a wrapper of the vendored
place_block.jsingeneric_place.js). Any other refusal rejects like upstream. A click that changed the clicked block itself is never taken for a stale one: against a replaceable block (snow_layer,short_grass,fern,vine,seagrass, …) or a block the held item merges into (the same half slab → double slab, one more candle / sea pickle / snow layer / petal, a candle onto a cake) BDS puts the block into the clicked position and leaves the block across the face as it was — exactly like Java, so the call rejects with upstream'sServer refusedafter one click (instead of clicking again and placing a second block above it); nor is a click that used up an item.
A click whose held stack changed on the server is retried
- Affects:
bot.placeBlock/_placeBlockWithOptionswhile items are picked up, given (/give) or otherwise added to the held stack (dig-then-place loops, mineflayer-pathfinder's scaffolding) - Java:
block_placecarries no item. - Bedrock: the click carries the exact server copy of the held item (its stack id). A pickup that merges into the
held stack between the click and its processing gives the stack a new stack id first (
inventory_transactionnormal, theninventory_content), and BDS refuses the click (measured: 4 of 180 placements of a dig-then-place loop; a/giveright before the click: every time). - bedboo: the placer notes a server-side change of the held slot between the click and its answer (an
inventory_transactionof that slot, or the stack grew); such a refusal is retried once with the server's copy (the client has it by then). Any other refusal rejects like upstream.
Pillaring and bridging (mineflayer-pathfinder scaffolding)
-
Affects:
bot._genericPlace(jump-placing), mineflayer-pathfinderallow1by1towersand bridging -
Java: pathfinder jumps and calls
placeBlockunder its feet as soon as they left the ground; a refused click resets the path (place_error) and it tries again. -
Bedrock: BDS refuses any block that intersects the player's server-side hitbox (measured: an overlap of 0.01 block is refused; nothing is ever placed into the player, so there is no push-out). It processes a click after the player inputs sent before it, so the click must follow an input whose hitbox is clear of the destination.
-
bedboo: while the bot rises out of the destination block, or keeps jumping (jump control held), the click waits (≤ 20 inputs) for the first input with the hitbox clear of the block and follows it; a bot that will not clear it clicks at once and gets the server's refusal like upstream. Measured (survival, gravity, local BDS):
- manual pillar ×4 (place as soon as the feet left the ground): 0 refusals, 0 corrections;
- pathfinder pillar ×5: 0
place_error, 0 corrections (≈ 0.45 s per block, the click goes out 2 ticks after the feet leave the ground); - manual bridge ×4 (sneak backwards to the edge, place against the side of the block below): 0 corrections;
- pathfinder bridge ×5–6: unpatched, 3–4 corrections of 0.16–0.64 block, all from pathfinder's own
fullStop(), which movesbot.entity.positionto the block centre client-side ("the server will not tell the difference" on Java; a server-authoritative BDS does: it corrects the bot back, then it walks on). The patched pathfinder skips that recentring: 0 corrections (see mineflayer-pathfinder).
Pillaring under a ceiling has its own limit: see 1×1 towers.
No placement from the off-hand
- Affects: option
offhandofbot._genericPlace/bot._placeBlockWithOptions/bot._placeEntityWithOptions - Java:
hand: 1places the off-hand item. - Bedrock: the off-hand only holds a few items (shield, totem, arrows, rockets, maps, …, see
Off-hand) and the player never uses it on a block; a click with
hand: off_handand the off-hand item (or the main-hand item) places nothing (measured, with a block forced into the off-hand by/replaceitem). - bedboo: the click is sent like the vanilla client would (hand
off_hand, the off-hand's wire item), the server refuses andplaceBlockrejects with upstream's refusal message; upstream's check for an empty off-hand is kept.
placeEntity
- Affects:
bot.placeEntity,bot._placeEntityWithOptions,entityPlaced - Java: a click on the block (
block_place); boats additionallyuse_item(a server raycast along the look); the entity is found by name (EnderCrystal/end_crystal,boat,armor_stand, the spawn egg's mob) within 2 blocks (3 for boats) of the destination; minecarts are not supported (assertion 'Unimplemented'). - Bedrock: everything is a click on a block: armor stands, end crystals (obsidian / bedrock), spawn eggs, minecarts
(on a rail) and boats (BDS ignores a boat's
click_air; the vanilla client clicks the water it aims at; boats can also be placed on land). Entity names:ender_crystal,boat/chest_boat(chest boats, rafts),armor_stand,minecart/chest_minecart/ …, spawn eggsvillager→villager_v2,zombie_villager→zombie_villager_v2,evoker→evocation_illager,tropical_fish→tropicalfish. A hostile mob's spawn egg spawns nothing in peaceful (the egg is used). - bedboo: upstream's code with:
- a boat whose reference block is a liquid clicks the liquid's top face (it spawns centred on it whatever face was given; the look does not matter, so it never lands on the bot);
- minecarts accepted (on a rail), chest boats also on land;
- the Bedrock names above;
- upstream stops listening after the first
entitySpawneven when it is another entity (and then always times out after 5 s); here the listener stays until the placed entity spawned or the timeout ('Failed to place entity', unchanged).
Item use on blocks: buckets, flint and steel, bone meal, fireworks
- Affects:
bot.placeBlock/bot.activateBlock/bot.activateItemwith these items - Java:
activateItem(use_item) uses a bucket or a boat on the block the player looks at (server raycast);placeBlock/activateBlockwith a bucket, flint and steel or bone meal acts on the clicked block. - Bedrock: BDS ignores
click_airfor buckets and boats (measured: nothing happens); the vanilla client clicks the looked-at block (click_block: an empty bucket on the liquid source itself, a filled bucket on the solid block behind the liquid, the liquid going across the face).click_blockwith flint and steel lights a fire (an obsidian frame becomesportalblocks), bone meal grows the clicked plant, a firework rocket on a block launches it; like Java a rocket used in the air without gliding does nothing. - bedboo:
placeBlockwith a water / lava bucket resolves withblockPlaced(air, water|lava), with flint and steelblockPlaced(air, fire|portal);activateBlock(<liquid source>)with an empty bucket fills it.bot.activateItemwith a bucket or a boat callsbot._bedrock.placement.useOnLookedAtBlock(item, offHand), the Bedrock form of that use: a raycast along the look (liquids where the item acts on them), then the click. Other item uses: see Item use, eating and the shield.