Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

  .-')     _ (`-.)  _  .-')                            .-') _
 ( OO ).  ( (OO  )( \( -O )                          (  OO) )
(_)---\_)_.`     \ ,------.  .-'),-----.  ,--. ,--.  /     '._
/    _ |(__...--'' |   /`. '( OO'  .-.  ' |  | |  |  |'--...__)
\  :``. |  /  | | |  /  | |/   |  | |  | |  | | .-')'--.  .--'
 '..`''.)|  |_.' | |  |_.' |\_) |  |\|  | |  |_|( OO )  |  |
.-._)   \|  .___.' |  .  '.'  \ |  | |  | |  | | `-' /  |  |
\       /|  |      |  |\  \    `'  '-'  '('  '-'(_.-'   |  |
 `-----' `--'      `--' '--'     `-----'   `-----'      `--'
  

sprout

a minecraft wheat farm daemon
node index.js

plant. harvest. restock. repeat.


overview

sprout is a mineflayer bot that operates a wheat farm autonomously. connects to a server, scans the farmland, and runs a three-phase loop: plant empty plots, wait for growth, harvest and replant. chests are discovered via item-frame labels — no hardcoded positions.

setup

npm install
node index.js
step detail
1. set the server address from the terminal menu
2. place item frames on chests: wheat item → wheat chest, seeds item → seed chest
3. select start

note: on Paper servers (1.20.4+), chest interaction requires /op Sprout due to a server-side packet validation bug (mineflayer#3459). vanilla servers work without op.

architecture

flowchart LR
  subgraph Bot
    TUI[terminal menu<br/>config + status]
    F[FarmTick loop<br/>500ms–2000ms]
    M[manageInventory<br/>wheat deposit<br/>seed restock]
    S[scanFarm<br/>33x33 bounding box<br/>3s cooldown]
    C[scanChests<br/>item-frame labels]
  end

  subgraph Server
    MC[Minecraft server<br/>1.20.6]
  end

  subgraph Dashboard
    W[HTTP :8080<br/>SSE events]
    H[HTML canvas<br/>map + stats]
  end

  TUI --> F
  F --> S & M
  C --> M
  MC <--> F
  W <--> F
  H --> W
Loading

state machine

stateDiagram-v2
  state "FarmTick" as T {
    [*] --> Phase1 : empty plots exist

    state Phase1 {
      direction LR
      p1[sort by distance] --> p2[navigate to plot]
      p2 --> p3[place seed<br/>raw block_place packet]
      p3 --> p4[mark stage=0 locally]
      p4 --> p1 : more plots
    }

    Phase1 --> Phase2 : all plots occupied

    state Phase2 {
      direction LR
      w1[manageInventory<br/>wheat deposit + seed restock] --> w2[wait 2000ms]
    }

    Phase2 --> Phase3 : mature crops detected

    state Phase3 {
      direction LR
      h1[sort mature by distance] --> h2[navigate reach=4]
      h2 --> h3[break crop<br/>raw block_dig instant]
      h3 --> h4[place seed<br/>raw block_place]
      h4 --> h5[mark stage=0 locally]
      h5 --> h1 : more mature
    }

    Phase3 --> Phase1 : batch complete
    Phase2 --> Phase2 : rescan after 2s
  }
Loading

internals

farmland discovery

scanFarm() performs an O(n³) bounding-box scan from a centroid (farmCenter) that is recomputed after every scan. initial position is the bot's location at start; subsequent scans recenter on the mean x/z of all discovered farmland blocks. this keeps the farm visible even when the bot walks to distant chests.

// centroid self-corrects as new farmland is discovered
const avgX = plots.reduce((s, p) => s + p.pos.x, 0) / plots.length
const avgZ = plots.reduce((s, p) => s + p.pos.z, 0) / plots.length
farmCenter = new Vec3(Math.floor(avgX), center.y, Math.floor(avgZ))

chest discovery

scanChests() iterates all loaded item_frame / glow_item_frame entities, reads the item in slot 8 (1.20.6+ slot format via itemCount), resolves the attached chest block via 6-direction neighbor search, and filters type === 'right' to deduplicate double-chest halves. chests are stored as deduplicated arrays (seedChests[], wheatChests[]).

protocol-level optimization

crops are instant-break (hardness 0). sprout bypasses mineflayer's bot.dig() — which performs a lookAt, sends block_dig status=0, waits for an elapsed timer, then sends status=2 — and instead sends both packets back-to-back with a swingArm(). same for seed placement (block_place written directly without waitForBlockUpdate). this eliminates ~100ms of per-call latency and matches the server's natural tick processing.

bot._client.write('block_dig', { status: 0, location: crop.position, face: 1 })
bot._client.write('block_dig', { status: 2, location: crop.position, face: 1 })
bot.swingArm()

inventory management

inventory size targets are derived from the plot count. the bot maintains exactly plots.length seeds in inventory — any surplus is deposited to the seed chest on the next chest trip. wheat is deposited to the wheat chest when any stack reaches 64. chest contents for the dashboard are read from chest.containerItems() during actual chest operations (no extra chest opens for UI).

real-time dashboard

an HTTP server on :8080 pushes SSE events at 60fps. the payload includes plot state (x, z, stage), chest positions, bot location, inventory summary, and cumulative stats. the browser renders a canvas 2D map with colored plot squares (brown→green→gold for stage 0→7), diamond markers for chests, and a dot for the bot. zero framework dependencies — vanilla canvas API + EventSource.

dashboard

open http://localhost:8080 while sprout runs.

dependencies

  • mineflayer — minecraft protocol client
  • mineflayer-pathfinder — A* navigation
  • minecraft-data, prismarine-block, vec3 — transitive, resolved by mineflayer

zero runtime deps beyond the mineflayer stack.

license

ISC

About

Minecraft efficient wheat bot for smp farming.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages