[
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\nopen_collective: prismarinejs\ncustom: https://rysolv.com/repos/detail/74691b23-938d-4b2f-b65a-5c47bf5b3f0f\ngithub: PrismarineJS\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: possible bug,Stage1\nassignees: ''\n\n---\n\n- [ ] The [FAQ](https://github.com/PrismarineJS/mineflayer/blob/master/docs/FAQ.md) doesn't contain a resolution to my issue \n\n## Versions\n - mineflayer: #.#.#\n - server: vanilla/spigot/paper #.#.#\n - node: #.#.#\n\n## Detailed description of a problem\nA clear and concise description of what the problem is, with as much context as possible.\nWhat are you building? What problem are you trying to solve?\n\n## What did you try yet?\n\nDid you try any method from the API?\nDid you try any example? Any error from those?\n\n## Your current code\n```js\n\n/*\nSome code here, replace this\n*/\n\n\n```\n\n## Expected behavior\nA clear and concise description of what you expected to happen.\n\n## Additional context\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Github Discussions\n    url: https://github.com/PrismarineJS/mineflayer/discussions\n    about: Please make a post in our Github Discussions for questions and support requests.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: new feature,Stage1\nassignees: ''\n\n---\n\n## Is your feature request related to a problem? Please describe.\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n## Describe the solution you'd like\nA clear and concise description of what you want to happen.\n\n## Describe alternatives you've considered\nA clear and concise description of any alternative solutions or features you've considered.\n\n## Additional context\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: npm\n  directory: \"/\"\n  schedule:\n    interval: daily\n  open-pull-requests-limit: 10\n  ignore:\n  - dependency-name: \"@types/node\"\n    versions:\n    - 15.0.0\n"
  },
  {
    "path": ".github/helper/package.json",
    "content": "{\r\n  \"dependencies\": {\r\n    \"gh-helpers\": \"^1.0.0\"\r\n  }\r\n}"
  },
  {
    "path": ".github/helper/updator.js",
    "content": "#!/usr/bin/env node\r\n/**\r\n * Updator script triggered from minecraft-data repository to auto generate PR\r\n */\r\nconst fs = require('fs')\r\nconst cp = require('child_process')\r\nconst assert = require('assert')\r\nconst github = require('gh-helpers')()\r\nconst { join } = require('path')\r\nconst exec = (cmd) => github.mock ? console.log('> ', cmd) : (console.log('> ', cmd), cp.execSync(cmd, { stdio: 'inherit' }))\r\n\r\nconsole.log('Starting update process...')\r\n// Sanitize and validate environment variables all non alpha numeric / underscore / dot\r\nconst newVersion = process.env.NEW_MC_VERSION?.replace(/[^a-zA-Z0-9_.]/g, '_')\r\nconst triggerBranch = process.env.MCDATA_BRANCH?.replace(/[^a-zA-Z0-9_.]/g, '_')\r\nconst mcdataPrURL = process.env.MCDATA_PR_URL\r\nconsole.log({ newVersion, triggerBranch, mcdataPrURL })\r\n\r\nassert(newVersion)\r\nassert(triggerBranch)\r\n\r\nasync function main () {\r\n  const currentSupportedPath = require.resolve('../../lib/version.js')\r\n  const readmePath = join(__dirname, '../../docs/README.md')\r\n  const ciPath = join(__dirname, '../../.github/workflows/ci.yml')\r\n\r\n  // Update the version.js\r\n  const currentSupportedVersion = require('../../lib/version.js')\r\n  const currentContents = fs.readFileSync(currentSupportedPath, 'utf8')\r\n  console.log('Current supported version:', currentContents)\r\n  const latestV = currentSupportedVersion.testedVersions.at(-1)\r\n  const newContents = currentContents.includes(newVersion)\r\n    ? currentContents\r\n    : currentContents\r\n      .replace(`, '${latestV}'`, `, '${latestV}', '${newVersion}'`)\r\n\r\n  // Update the README.md\r\n  const currentContentsReadme = fs.readFileSync(readmePath, 'utf8')\r\n  if (!currentContentsReadme.includes(newVersion)) {\r\n    const newReadmeContents = currentContentsReadme\r\n      .replace(/Minecraft 1\\.8 to [0-9A-Za-z._-]+ \\(/, `Minecraft 1.8 to ${newVersion} (`)\r\n      .replace(') <!--version-->', `, ${newVersion}) <!--version-->`)\r\n    fs.writeFileSync(readmePath, newReadmeContents)\r\n    console.log('Updated README with new version:', newVersion)\r\n  }\r\n  fs.writeFileSync(currentSupportedPath, newContents)\r\n\r\n  // Update the CI workflow\r\n  const currentContentsCI = fs.readFileSync(ciPath, 'utf8')\r\n  if (!currentContentsCI.includes(newVersion)) {\r\n    const newCIContents = currentContentsCI.replace(\r\n      'run: npm install', `run: npm install\r\n      - run: cd node_modules && cd minecraft-data && mv minecraft-data minecraft-data-old && git clone -b ${triggerBranch} https://github.com/PrismarineJS/minecraft-data --depth 1 && node bin/generate_data.js\r\n      - run: curl -o node_modules/protodef/src/serializer.js https://raw.githubusercontent.com/extremeheat/node-protodef/refs/heads/dlog/src/serializer.js && curl -o node_modules/protodef/src/compiler.js https://raw.githubusercontent.com/extremeheat/node-protodef/refs/heads/dlog/src/compiler.js\r\n`)\r\n    fs.writeFileSync(ciPath, newCIContents)\r\n    console.log('Updated CI workflow with new version:', newVersion)\r\n  }\r\n\r\n  const branchName = 'pc' + newVersion.replace(/[^a-zA-Z0-9_]/g, '_')\r\n  exec(`git checkout -b ${branchName}`)\r\n  exec('git config user.name \"github-actions[bot]\"')\r\n  exec('git config user.email \"41898282+github-actions[bot]@users.noreply.github.com\"')\r\n  exec('git add --all')\r\n  exec(`git commit -m \"Update to version ${newVersion}\"`)\r\n  exec(`git push origin ${branchName} --force`)\r\n  //     createPullRequest(title: string, body: string, fromBranch: string, intoBranch?: string): Promise<{ number: number, url: string }>;\r\n  const pr = await github.createPullRequest(\r\n    `🎈 ${newVersion}`,\r\n    `This automated PR sets up the relevant boilerplate for Minecraft version ${newVersion}.\r\n\r\nRef: ${mcdataPrURL}\r\n\r\n* You can help contribute to this PR by opening a PR against this <code branch>${branchName}</code> branch instead of <code>master</code>.\r\n    `,\r\n    branchName,\r\n    'master'\r\n  )\r\n  console.log(`Pull request created`, pr)\r\n}\r\n\r\nmain().catch(err => {\r\n  console.error('Error during update process:', err)\r\n  process.exit(1)\r\n})\r\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n\njobs:\n  Lint:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js 22.x\n      uses: actions/setup-node@v1.4.4\n      with:\n        node-version: 22.x\n    - run: npm i && npm run lint\n  \n  PrepareSupportedVersions:\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.set-matrix.outputs.matrix }}\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Use Node.js 22.x\n      uses: actions/setup-node@v1.4.4\n      with:\n        node-version: 22.x\n    - id: set-matrix\n      run: |\n        node -e \"\n          const testedVersions = require('./lib/version').testedVersions;\n          console.log('matrix='+JSON.stringify({'include': testedVersions.map(mcVersion => ({mcVersion}))}))\n        \" >> $GITHUB_OUTPUT\n\n  MinecraftServer:\n    needs: PrepareSupportedVersions\n    runs-on: ubuntu-latest\n    strategy:\n      matrix: ${{fromJson(needs.PrepareSupportedVersions.outputs.matrix)}}\n      fail-fast: false\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Use Node.js 22.x\n        uses: actions/setup-node@v1.4.4\n        with:\n          node-version: 22.x\n      - name: Setup Java JDK\n        uses: actions/setup-java@v1.4.3\n        with:\n          java-version: 21\n          java-package: jre\n      - name: Install Dependencies\n        run: npm install\n\n      - name: Start Tests\n        run: npm run mocha_test -- -g ${{ matrix.mcVersion }}v\n"
  },
  {
    "path": ".github/workflows/commands.yml",
    "content": "name: Repo Commands\r\n\r\non:\r\n  issue_comment:        # Handle comment commands\r\n    types: [created]\r\n  pull_request:         # Handle renamed PRs\r\n    types: [edited]\r\n\r\njobs:\r\n  comment-trigger:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n    - name: Check out repository\r\n      uses: actions/checkout@v3\r\n    - name: Run command handlers\r\n      uses: PrismarineJS/prismarine-repo-actions@master\r\n      with:\r\n        # NOTE: You must specify a Personal Access Token (PAT) with repo access here. While you can use the default GITHUB_TOKEN, actions taken with it will not trigger other actions, so if you have a CI workflow, commits created by this action will not trigger it.\r\n        token: ${{ secrets.PAT_PASSWORD }}\r\n        # See `Options` section below for more info on these options\r\n        install-command: npm install\r\n        /fixlint.fix-command: npm run fix"
  },
  {
    "path": ".github/workflows/handle-update.yml",
    "content": "name: Update from minecraft-data\r\n\r\non:\r\n  workflow_dispatch:\r\n    inputs:\r\n      new_mc_version:\r\n        description: New minecraft version number\r\n        required: true\r\n        type: string\r\n      mcdata_branch:\r\n        description: minecraft-data branch for this version\r\n        required: true\r\n        type: string\r\n      mcdata_pr_url:\r\n        description: minecraft-data PR number to open a PR here against\r\n        required: false\r\n        default: ''\r\n        type: string\r\n      nmp_branch:\r\n        description: minecraft-protocol branch for this version\r\n        required: true\r\n        type: string\r\n      nmp_pr_url:\r\n        description: minecraft-protocol PR number to open a PR here against\r\n        required: false\r\n        default: ''\r\n        type: string\r\n\r\njobs:\r\n  update:\r\n    runs-on: ubuntu-latest\r\n    \r\n    steps:\r\n    - name: Checkout repository\r\n      uses: actions/checkout@v4\r\n      with:\r\n        token: ${{ secrets.PAT_PASSWORD }}\r\n\r\n    - name: Use Node.js 22.x\r\n      uses: actions/setup-node@v1.4.4\r\n      with:\r\n        node-version: 22.x\r\n\r\n    - run: npm install PrismarineJS/node-minecraft-protocol#${{ github.event.inputs.nmp_branch }}\r\n\r\n    - name: Run updator script\r\n      run: cd .github/helper && npm install && node updator.js\r\n      env:\r\n        GITHUB_TOKEN: ${{ secrets.PAT_PASSWORD }}\r\n        NEW_MC_VERSION: ${{ github.event.inputs.new_mc_version }}\r\n        MCDATA_BRANCH: ${{ github.event.inputs.mcdata_branch }}\r\n        MCDATA_PR_URL: ${{ github.event.inputs.mcdata_pr_url }}\r\n        NMP_BRANCH: ${{ github.event.inputs.nmp_branch }}\r\n        NMP_PR_URL: ${{ github.event.inputs.nmp_pr_url }}\r\n"
  },
  {
    "path": ".github/workflows/npm-publish.yml",
    "content": "name: npm-publish\non:\n  push:\n    branches:\n      - master # Change this to your default branch\njobs:\n  npm-publish:\n    name: npm-publish\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@master\n    - name: Set up Node.js\n      uses: actions/setup-node@master\n      with:\n        node-version: 22.0.0\n    - id: publish\n      uses: JS-DevTools/npm-publish@v1\n      with:\n        token: ${{ secrets.NPM_AUTH_TOKEN }}\n    - name: Create Release\n      if: steps.publish.outputs.type != 'none'\n      id: create_release\n      uses: actions/create-release@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        tag_name: ${{ steps.publish.outputs.version }}\n        release_name: Release ${{ steps.publish.outputs.version }}\n        body: ${{ steps.publish.outputs.version }}\n        draft: false\n        prerelease: false\n"
  },
  {
    "path": ".gitignore",
    "content": "# shared with .npmignore\n# different than .npmignore\nnode_modules\npackage-lock.json\nyarn.lock\n/README.md\nversions/\nserver_jars/\ntest/server_*\n.vscode\n.DS_Store\nlauncher_accounts.json\ndata"
  },
  {
    "path": ".gitpod.yml",
    "content": "tasks:\n- command: npm install && sdk install java\n"
  },
  {
    "path": ".npmignore",
    "content": "# shared with .gitignore\n# different than .gitignore\ntest\n"
  },
  {
    "path": ".npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Andrew Kelley\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "content": "# Contribute\n\nMineflayer has originally been made mostly by [andrewrk](http://github.com/andrewrk)\nbut has since then be improved and fixed by many [contributors](https://github.com/andrewrk/mineflayer/graphs/contributors).\nThat's why it is important to know the best ways to contribute to mineflayer.\n\n## Issue organization\n\nWe have 3 stage labels to try to organize issues:\n\n* Stage 1: just created by someone new to the project, we don't know yet if it deserves an implementation / a fix\n* Stage 2: promising idea, but needs more thinking before implementation\n* Stage 3: idea is precisely specified, only coding is left to do\n\nLinks like https://github.com/PrismarineJS/mineflayer/issues?q=is%3Aopen+is%3Aissue+-label%3AStage1 can be used to filter out stage 1 if you're looking for things that are ready for contribution\n\n## Creating tests\nMineflayer has two kind of tests :\n\n * [internal tests](test/internalTest.js) : tests that are done against a simple server created with node-minecraft-protocol\n * [external tests](test/externalTests/) : tests that are done against the vanilla server\n \nThe objective of these tests is to know automatically what works and what doesn't in mineflayer, so it's easier to make mineflayer work.\n\n\n## Running tests\nYou can run tests for Different Minecraft versions using the `-g` flag with npm run mocha_test. For example:\n\n```bash\n# Run all tests in all supported versions\nnpm run test\n\n# Run a specific test in Minecraft 1.20.4\nnpm run mocha_test -- -g \"mineflayer_external 1.20.4v.*exampleBee\"\n\n# Run all tests in just version 1.20.4\nnpm run mocha_test -- -g \"mineflayer_external 1.20.4v\"\n```\n\n\n### Creating an external test\n\nIn order to add an external test now you only need to create a file in [test/externalTests](test/externalTests)\n\nAn example : [test/externalTests/digAndBuild.js](https://github.com/PrismarineJS/mineflayer/blob/master/test/externalTests/digAndBuild.js)\n\nThat file needs to export a function returning a function or an array of function taking as parameter the bot object and a done callback,\n it should contain asserts to test if the tested functionality failed.\n\n\n## Creating a third party plugin\nMineflayer is pluggable; anyone can create a plugin that adds an even higher level API on top of Mineflayer.\n\nSeveral such third party plugins have already been [created](https://github.com/andrewrk/mineflayer#third-party-plugins)\n\nIn order to create a new one you need to :\n\n1. create a new repo\n2. in your index.js file, exports an init function taking in argument mineflayer ([example](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L18))\n3. that function returns a inject function taking in argument the bot object ([example](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L23))\n4. that inject function add functionalities to the bot object ([example](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L32))\n\nSince the mineflayer object is passed in parameter, that new package doesn't need to depend on mineflayer (no mineflayer dependency in the package.json)\n\nSee a [full example](https://github.com/andrewrk/mineflayer-navigate/tree/e24cb6a868ce64ae43bea2d035832c15ed01d301) here.\n\n## Reporting bugs\nMineflayer works well for most usages, but it sometimes still has bugs.\n\nWhen finding one it's best to report an issue providing these information :\n\n* what you want to do (the objective in english)\n* what you tried (the code)\n* what happened\n* what you expected to happen\n\n## Mineflayer code\nSome things to think about when submitting a Pull Request or making a commit :\n\n### Error handling\nIn most cases, mineflayer shouldn't crash the bot. Even if something fails, the bot can take an alternative route to get to its objective.\n\nWhat that means is we shouldn't use `throw(new Error(\"error\"))` but instead use the node.js convention of passing the error in the callback.\n\nFor example : \n\n```js\nfunction myfunction (param1, callback) {\n  // do stuff\n  let toDo = 1\n  toDo = 2\n  if (toDo === 2) { // everything worked\n    callback()\n  } else {\n    callback(new Error('something failed'))\n  }\n}\n```\n\nSee an other example of that in [mineflayer code](https://github.com/andrewrk/mineflayer/blob/a8736c4ea473cf1a609c5a29046c0cdad006d429/lib/plugins/bed.js#L10)\n\n### Updating the documentation\nThe table of content of docs/api.md is made with doctoc. After updating that file, you should run doctoc docs/api.md to update the table of content.\n"
  },
  {
    "path": "docs/FAQ.md",
    "content": "## FAQ\n\nThis Frequently Asked Question document is meant to help people for the most common things.\n\n### I get an error (ie. protocol/data) when bot is trying to connect to minecraft server\n\nMake sure the Minecraft server version is supported (cf. root readme), else you should retry using one of the [mineflayer tested versions](../lib/version.js).\n\n### I get an error when trying to login with a microsoft account.\n\nMake sure the email you entered into the username option in createBot can be used to login to `minecraft.net` using the 'Login with Microsoft' button.\nMake sure you have the option `auth: 'microsoft'` in your createBot options. \n\nWhen you get an error that says something about invalid credentials or 'Does this account own Minecraft?' try removing the password field in the `createBot` options and try again.\n\n### How to hide errors ?\n\nUse `hideErrors: true` in createBot options\nYou may also choose to add these listeners :\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n### I'm not getting chat event on a custom server, how can I solve it ?\n\nSpigot servers, in particular some plugins, use custom chat formats, you need to parse it with a custom regex / parser.\nRead and adapt [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) to make it work for your particular\nchat plugin. Also read http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat\n\n### How can I collect info from an custom plugin in chat ?\n\nMost custom minecraft servers have plugin support, and a lot of these plugins say something in chat when something happens. If it is just one message, it's best to use the solution discussed in the solution above, but when these messages are split into many small messages, another option is using the `\"messagestr\"` event as it allows for easily parsing multi-line messages.\n\n**Example:**\n\nchat message in chat looks like:\n```\n(!) U9G has won the /jackpot and received\n$26,418,402,450! They purchased 2,350,000 (76.32%) ticket(s) out of the\n3,079,185 ticket(s) sold!\n```\n```js\nconst regex = {\n  first: /\\(!\\) (.+) has won the \\/jackpot and received +/,\n  second: /\\$(.+)! They purchased (.+) \\((.+)%\\) ticket\\(s\\) out of the /,\n  third: /(.+) ticket\\(s\\) sold!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n### How can I send a command ?\n\nBy using `bot.chat()`.\n\n**Example:**\n```js\nbot.chat('/give @p diamond')\n```\n\n### Is it possible to login multiple accounts using bot = mineflayer.createbot while controlling them all separately ?\n\nCreate different bot instances by calling createBot then do different things for each, see multiple.js\n\n### How would I make the bot drop it's entire inventory?\n\nbot.inventory.items() returns an array of the bot's items. You can use a recursive function to loop through them and drop every item using bot.toss(). Click [here](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9) to see an example\n\n### How do I check packets that are sent/received ?\n\nEnabled debug mode https://github.com/PrismarineJS/mineflayer#debug\n\n### I want to avoid disconnection even in case of server lag, how can I achieve this ?\n\nOne way is to increase the [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) option (to set in createBot) to an higher value (for example `300*1000` which is 5min instead of the default 30s). If you still get disconnected, you can auto reconnect using something like this example https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js\n\n### How to get the lore / text of an item ?\n\nYou can use the `item.nbt` property. It is also recommended to use the `prismarine-nbt` library. The `nbt.simplify()` method may be useful.\n\n**Example:**\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### How can I send message from the console to the server?\n\nYou can use a library like `repl` to read the console input and use `bot.chat()` to send it. You can find an example [here.](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js)\n\n### When creating a plugin, how can I specify another plugin as a dependency?\n\nIn the `inject()` function for your plugin, you can safely call `bot.loadPlugin(anotherPlugin)` to make sure that plugin is loaded. If the plugin was already loaded before, nothing happens.\n\nNote that the order in which plugins are loaded is dynamic, so you should never call another plugin in your `inject()` function.\n\n### How can I use a socks5 proxy?\n\nIn the options object for `mineflayer.createBot(options)`, remove your `host` option from the options object, have the following variables declared `PROXY_IP, PROXY_PORT, PROXY_USERNAME, PROXY_PASSWORD, MC_SERVER_ADDRESS, MC_SERVER_PORT` and add this to your options object:\n```js\nconnect: (client) => {\n    socks.createConnection({\n      proxy: {\n        host: PROXY_IP,\n        port: PROXY_PORT,\n        type: 5,\n        userId: PROXY_USERNAME,\n        password: PROXY_PASSWORD\n      },\n      command: 'connect',\n      destination: {\n        host: MC_SERVER_ADDRESS,\n        port: MC_SERVER_PORT\n      }\n    }, (err, info) => {\n      if (err) {\n        console.log(err)\n        return\n      }\n      client.setSocket(info.socket)\n      client.emit('connect')\n    })\n  }\n  ```\n  `socks` is declared with `const socks = require('socks').SocksClient` and uses [this](https://www.npmjs.com/package/socks) package.\n  Some servers might reject the connection. If that happens try adding `fakeHost: MC_SERVER_ADDRESS` to your createBot options.\n  \n# Common Errors\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\nThis is what happens when either you gave mineflayer the wrong server version, or mineflayer detects the wrong server version\n\n### `TypeError: Cannot read property '?' of undefined`\n\nYou may be trying to use something on the bot object that isn't there yet, try calling the statement after the `spawn` event\n\n### `SyntaxError: Unexpected token '?'`\n\nUpdate your node version.\n\n### The bot can't break/place blocks or open chests\n\nCheck that spawn protection isn't stopping the bot from it's action\n\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Mineflayer\n\n[![NPM version](https://img.shields.io/npm/v/mineflayer.svg?color=success&label=npm%20package&logo=npm)](https://www.npmjs.com/package/mineflayer)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/PrismarineJS/mineflayer/ci.yml.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Try it on gitpod](https://img.shields.io/static/v1.svg?label=try&message=on%20gitpod&color=brightgreen&logo=gitpod)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n[![Open In Colab](https://img.shields.io/static/v1.svg?label=open&message=on%20colab&color=blue&logo=google-colab)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/PrismarineJS)](https://github.com/sponsors/PrismarineJS)\n\n[![Official Discord](https://img.shields.io/static/v1.svg?label=OFFICIAL&message=DISCORD&color=blue&logo=discord&style=for-the-badge)](https://discord.gg/GsEFRM8)\n\n| <sub>EN</sub> [English](README.md) | <sub>RU</sub> [русский](ru/README_RU.md) | <sub>ES</sub> [Español](es/README_ES.md) | <sub>FR</sub> [Français](fr/README_FR.md) | <sub>TR</sub> [Türkçe](tr/README_TR.md) | <sub>ZH</sub> [中文](zh/README_ZH_CN.md) | <sub>BR</sub> [Português](br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|-------------------------|--------------------|\n\nCreate Minecraft bots with a powerful, stable, and high level JavaScript [API](api.md), also usable from Python.\n\nFirst time using Node.js? You may want to start with the [tutorial](tutorial.md). Know Python? Checkout some [Python examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples/python) and try out [Mineflayer on Google Colab](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb).\n\n## Features\n\n * Supports Minecraft 1.8 to 1.21.11 (1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.21, 1.21.9, 1.21.11) <!--version-->\n * Entity knowledge and tracking.\n * Block knowledge. You can query the world around you. Milliseconds to find any block.\n * Physics and movement - handle all bounding boxes\n * Attacking entities and using vehicles.\n * Inventory management.\n * Crafting, chests, dispensers, enchantment tables.\n * Digging and building.\n * Miscellaneous stuff such as knowing your health and whether it is raining.\n * Activating blocks and using items.\n * Chat.\n\n### Roadmap\n\n Checkout [this page](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects) to see what our current projects are.\n\n## Installation\n\nFirst install Node.js >= 18 from [nodejs.org](https://nodejs.org/) then:\n\n```bash\nnpm install mineflayer\n```\n\nTo update mineflayer (or any Node.js) package and its dependencies, use \n```bash\nnpm update\n```\n\n## Documentation\n\n| link | description |\n|---|---|\n|[tutorial](tutorial.md) | Begin with Node.js and mineflayer |\n| [FAQ.md](FAQ.md) | Got a question ? go there first |\n| **[api.md](api.md)** <br/>[unstable_api.md](unstable_api.md) | The full API reference |\n| [history.md](history.md) | The changelog for mineflayer |\n| [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Checkout all the mineflayer examples |\n\n\n## Contribute\n\nPlease read [CONTRIBUTING.md](CONTRIBUTING.md) and [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute)\n\n## Usage\n\n**Videos**\n\nA tutorial video explaining the basic set up process for a bot can be found [here.](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n\nIf you want to learn more, more video tutorials are [there,](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) and the corresponding source codes for those bots is [there.](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials)\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Getting Started**\n\nWithout a version specified, the version of the server will be guessed automatically.\nWithout auth specified, the mojang auth style will be guessed.\n\n### Echo Example\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // minecraft server ip\n  username: 'Bot', // username to join as if auth is `offline`, else a unique identifier for this account. Switch if you want to change accounts\n  auth: 'microsoft' // for offline mode servers, you can set this to 'offline'\n  // port: 25565,              // set if you need a port that isn't 25565\n  // version: false,           // only set if you need a specific version or snapshot (ie: \"1.8.9\" or \"1.16.5\"), otherwise it's set automatically\n  // password: '12345678'      // set if you want to use password-based auth (may be unreliable). If specified, the `username` must be an email\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// Log errors and kick reasons:\nbot.on('kicked', console.log)\nbot.on('error', console.log)\n```\n\nIf `auth` is set to `microsoft`, you will be prompted to login to microsoft.com with a code in your browser. After signing in on your browser, \nthe bot will automatically obtain and cache authentication tokens (under your specified username) so you don't have to sign-in again. \n\nTo switch the account, update the supplied `username`. By default, cached tokens will be stored in your user's .minecraft folder, or if `profilesFolder` is specified, they'll instead be stored there.\nFor more information on bot options see node-minecraft-protocol's [API doc](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions).\n\n#### Connecting to a Realm\n\nTo join a Realm that your Minecraft account has been invited to, you can pass a `realms` object with a selector function like below.\n\n```js\nconst client = mineflayer.createBot({\n  username: 'email@example.com', // minecraft username\n  realms: {\n    // This function is called with an array of Realms the account can join. It should return the one it wants to join.\n    pickRealm: (realms) => realms[0]\n  },\n  auth: 'microsoft'\n})\n```\n\n### See what your bot is doing\n\nThanks to the [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) project, it's possible to display in a browser window what your bot is doing.\nJust run `npm install prismarine-viewer` and add this to your bot:\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // port is the minecraft server port, if first person is false, you get a bird's-eye view\n})\n```\nAnd you'll get a *live* view looking like this:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### More Examples\n\n| example | description |\n|---|---|\n|[viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | Display your bot world view in the browser |\n|[pathfinder](https://github.com/PrismarineJS/mineflayer/tree/master/examples/pathfinder) | Make your bot go to any location automatically |\n|[chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | Use chests, furnaces, dispensers, enchantment tables |\n|[digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | Learn how to create a simple bot that is capable of digging blocks |\n|[discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | Connect a discord bot with a mineflayer bot |\n|[jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | Learn how to move, jump, ride vehicles, attack nearby entities |\n|[ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | Display your bot's chat with all of the chat colors shown in your terminal |\n|[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Make a bot guard a defined area from nearby mobs |\n|[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Add a text file with accounts and have them all login |\n\nAnd many more in the [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) folder.\n\n### Modules\n\nA lot of the active development is happening inside of small npm packages which are used by mineflayer.\n\n#### The Node Way&trade;\n\n> \"When applications are done well, they are just the really application-specific, brackish residue that can't be so easily abstracted away. All the nice, reusable components sublimate away onto github and npm where everybody can collaborate to advance the commons.\" — substack from [\"how I write modules\"](https://gist.github.com/substack/5075355)\n\n#### Modules\n\nThese are the main modules that make up mineflayer:\n\n| module | description |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Parse and serialize minecraft packets, plus authentication and encryption.\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | Language independent module providing minecraft data for minecraft clients, servers and libraries.\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) | Provide the physics engine for minecraft entities\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | A class to hold chunk data for Minecraft\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | 3d vector math with robust unit tests\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | Represent a minecraft block with its associated data\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | A parser for a minecraft chat message (extracted from mineflayer)\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Node.js library to interact with Mojang's authentication system, known as Yggdrasil\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | The core implementation of worlds for prismarine\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | Represent minecraft windows\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | Represent a minecraft item with its associated data\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | An NBT parser for node-minecraft-protocol\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | Represent minecraft recipes\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | Represent a minecraft biome with its associated data\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) | Represent a minecraft entity\n\n\n### Debug\n\nYou can enable some protocol debugging output using `DEBUG` environment variable:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nOn windows :\n```\nset DEBUG=minecraft-protocol\nnode your_script.js\n```\n\n## Third Party Plugins\n\nMineflayer is pluggable; anyone can create a plugin that adds an even\nhigher level API on top of Mineflayer.\n\nThe most updated and useful are :\n\n * [minecraft-mcp-server](https://github.com/yuniko-software/minecraft-mcp-server) A MCP server for mineflayer, allowing using mineflayer from an LLM\n * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - advanced A* pathfinding with a lot of configurable features\n * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - simple web chunk viewer\n * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web based inventory viewer\n * [statemachine](https://github.com/PrismarineJS/mineflayer-statemachine) - A state machine API for more complex bot behaviors\n * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - automatic armor management\n * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Frontend dashboard for mineflayer bot\n * [PVP](https://github.com/PrismarineJS/mineflayer-pvp) - Easy API for basic PVP and PVE.\n * [Auto Eat](https://github.com/link-discord/mineflayer-auto-eat) - Automatic eating of food.\n * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Automatic placing & breaking of end crystals.\n * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - A utility for automatic tool/weapon selection with a high level API.\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - A utility for using auto-aim with bows.\n * [GUI](https://github.com/firejoust/mineflayer-GUI) - Interact with nested GUI windows using async/await\n * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Get the required launch angle for projectiles\n * [Movement](https://github.com/firejoust/mineflayer-movement) - Smooth and realistic player movement, best suited for PvP\n * [Collect Block](https://github.com/PrismarineJS/mineflayer-collectblock) - Quick and simple block collection API.\n\n But also check out :\n\n * [radar](https://github.com/andrewrk/mineflayer-radar/) - web based radar\n   interface using canvas and socket.io. [YouTube Demo](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n * [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - chat-based bot authentication\n * [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - determine who and what is responsible for damage to another entity\n * [tps](https://github.com/SiebeDW/mineflayer-tps) - get the current tps (processed tps)\n * [panorama](https://github.com/IceTank/mineflayer-panorama) - take Panorama Images of your world\n * [player-death-event](https://github.com/tuanzisama/mineflayer-death-event) - emit player death event in Mineflayer.\n\n## Projects Using Mineflayer\n\n * [Voyager](https://github.com/MineDojo/Voyager) An Open-Ended Embodied Agent with Large Language Models\n * [mindcraft](https://github.com/kolbytn/mindcraft) Lib for using mineflayer with LLMs\n * [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - building a spiral staircase](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - replicating a building](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n * [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualize what\n   the bot is up to using voxel.js\n * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) -  log player activity onto an online API\n * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (last open source version, built by AlexKvazos) -  Minecraft web based chat client\n * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - Plugin based bot with a clean GUI. Made with Node-Webkit.\n * [Chaoscraft](https://github.com/schematical/chaoscraft) - Minecraft bot using genetic algorithms, see [its youtube videos](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) -  Minecraft - Telegram bridge, build on top of mineflayer & telegraf.\n * [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - Prints minecraft schematics in survival, keeping orientation\n * [SilkePilon/OpenDeliveryBot](https://github.com/SilkePilon/OpenDeliveryBot) - Minecraft bot in python to deliver items from place to place.\n * [and hundreds more](https://github.com/PrismarineJS/mineflayer/network/dependents) - All the projects that github detected are using mineflayer\n\n\n## Testing\n\n### Testing everything\n\nSimply run: \n\n```bash\nnpm test\n```\n\n### Testing specific version\nRun \n\n```bash\nnpm run mocha_test -- -g <version>\n```\n\nwhere `<version>` is a minecraft version like `1.12`, `1.15.2`...\n\n### Testing specific test\nRun \n\n```bash\nnpm run mocha_test -- -g <test_name>\n```\n\nwhere `<test_name>` is a name of the test like `bed`, `useChests`, `rayTrace`...\n\n### Example\n\n```bash\nnpm run mocha_test -- -g \"1.18.1.*BlockFinder\"\n```\nto run the block finder test for 1.18.1\n\n## License\n\n[MIT](/LICENSE)\n"
  },
  {
    "path": "docs/_sidebar.md",
    "content": "- Getting Started\n  - [Introduction](/)\n  - [API](api.md)\n  - [FAQ](FAQ.md)\n  - [Demos](demos.md)\n  - [Tutorial](tutorial.md)\n  - [Unstable API](unstable_api.md)\n  - [Contribute](CONTRIBUTING.md)\n  - [History](history.md)"
  },
  {
    "path": "docs/api.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API](#api)\n  - [Enums](#enums)\n    - [minecraft-data](#minecraft-data)\n    - [mcdata.blocks](#mcdatablocks)\n    - [mcdata.items](#mcdataitems)\n    - [mcdata.materials](#mcdatamaterials)\n    - [mcdata.recipes](#mcdatarecipes)\n    - [mcdata.instruments](#mcdatainstruments)\n    - [mcdata.biomes](#mcdatabiomes)\n    - [mcdata.entities](#mcdataentities)\n  - [Classes](#classes)\n    - [vec3](#vec3)\n    - [mineflayer.Location](#mineflayerlocation)\n    - [Entity](#entity)\n      - [Player Skin Data](#player-skin-data)\n    - [Block](#block)\n    - [Biome](#biome)\n    - [Item](#item)\n    - [windows.Window (base class)](#windowswindow-base-class)\n      - [window.deposit(itemType, metadata, count, nbt)](#windowdeposititemtype-metadata-count-nbt)\n      - [window.withdraw(itemType, metadata, count, nbt)](#windowwithdrawitemtype-metadata-count-nbt)\n      - [window.close()](#windowclose)\n    - [Recipe](#recipe)\n    - [mineflayer.Container](#mineflayercontainer)\n    - [mineflayer.Furnace](#mineflayerfurnace)\n      - [furnace \"update\"](#furnace-update)\n      - [furnace.takeInput()](#furnacetakeinput)\n      - [furnace.takeFuel()](#furnacetakefuel)\n      - [furnace.takeOutput()](#furnacetakeoutput)\n      - [furnace.putInput(itemType, metadata, count)](#furnaceputinputitemtype-metadata-count)\n      - [furnace.putFuel(itemType, metadata, count)](#furnaceputfuelitemtype-metadata-count)\n      - [furnace.inputItem()](#furnaceinputitem)\n      - [furnace.fuelItem()](#furnacefuelitem)\n      - [furnace.outputItem()](#furnaceoutputitem)\n      - [furnace.fuel](#furnacefuel)\n      - [furnace.progress](#furnaceprogress)\n    - [mineflayer.EnchantmentTable](#mineflayerenchantmenttable)\n      - [enchantmentTable \"ready\"](#enchantmenttable-ready)\n      - [enchantmentTable.targetItem()](#enchantmenttabletargetitem)\n      - [enchantmentTable.xpseed](#enchantmenttablexpseed)\n      - [enchantmentTable.enchantments](#enchantmenttableenchantments)\n      - [enchantmentTable.enchant(choice)](#enchantmenttableenchantchoice)\n      - [enchantmentTable.takeTargetItem()](#enchantmenttabletaketargetitem)\n      - [enchantmentTable.putTargetItem(item)](#enchantmenttableputtargetitemitem)\n      - [enchantmentTable.putLapis(item)](#enchantmenttableputlapisitem)\n    - [mineflayer.anvil](#mineflayeranvil)\n      - [anvil.combine(itemOne, itemTwo[, name])](#anvilcombineitemone-itemtwo-name)\n      - [anvil.combine(item[, name])](#anvilcombineitem-name)\n      - [villager \"ready\"](#villager-ready)\n      - [villager.trades](#villagertrades)\n      - [villager.trade(tradeIndex, [times])](#villagertradetradeindex-times)\n    - [mineflayer.ScoreBoard](#mineflayerscoreboard)\n      - [ScoreBoard.name](#scoreboardname)\n      - [ScoreBoard.title](#scoreboardtitle)\n      - [ScoreBoard.itemsMap](#scoreboarditemsmap)\n      - [ScoreBoard.items](#scoreboarditems)\n    - [mineflayer.Team](#mineflayerteam)\n      - [Team.name](#teamname)\n      - [Team.friendlyFire](#teamfriendlyfire)\n      - [Team.nameTagVisibility](#teamnametagvisibility)\n      - [Team.collisionRule](#teamcollisionrule)\n      - [Team.color](#teamcolor)\n      - [Team.prefix](#teamprefix)\n      - [Team.suffix](#teamsuffix)\n      - [Team.members](#teammembers)\n    - [mineflayer.BossBar](#mineflayerbossbar)\n      - [BossBar.title](#bossbartitle)\n      - [BossBar.health](#bossbarhealth)\n      - [BossBar.dividers](#bossbardividers)\n      - [BossBar.entityUUID](#bossbarentityuuid)\n      - [BossBar.shouldDarkenSky](#bossbarshoulddarkensky)\n      - [BossBar.isDragonBar](#bossbarisdragonbar)\n      - [BossBar.createFog](#bossbarcreatefog)\n      - [BossBar.color](#bossbarcolor)\n    - [mineflayer.Particle](#mineflayerparticle)\n      - [Particle.id](#particleid)\n      - [Particle.name](#particlename)\n      - [Particle.position](#particleposition)\n      - [Particle.offset](#particleoffset)\n      - [Particle.longDistanceRender](#particlelongdistancerender)\n      - [Particle.count](#particlecount)\n      - [Particle.movementSpeed](#particlemovementspeed)\n  - [Bot](#bot)\n    - [mineflayer.createBot(options)](#mineflayercreatebotoptions)\n    - [Properties](#properties)\n      - [bot.registry](#botregistry)\n      - [bot.world](#botworld)\n        - [world \"blockUpdate\" (oldBlock, newBlock)](#world-blockupdate-oldblock-newblock)\n        - [world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#world-blockupdatex-y-z-oldblock-newblock)\n      - [bot.entity](#botentity)\n      - [bot.entities](#botentities)\n      - [bot.username](#botusername)\n      - [bot.spawnPoint](#botspawnpoint)\n      - [bot.heldItem](#bothelditem)\n      - [bot.usingHeldItem](#botusinghelditem)\n      - [bot.game.levelType](#botgameleveltype)\n      - [bot.game.dimension](#botgamedimension)\n      - [bot.game.difficulty](#botgamedifficulty)\n      - [bot.game.gameMode](#botgamegamemode)\n      - [bot.game.hardcore](#botgamehardcore)\n      - [bot.game.maxPlayers](#botgamemaxplayers)\n      - [bot.game.serverBrand](#botgameserverbrand)\n      - [bot.game.minY](#botgameminy)\n      - [bot.game.height](#botgameheight)\n      - [bot.physicsEnabled](#botphysicsenabled)\n      - [bot.player](#botplayer)\n      - [bot.players](#botplayers)\n      - [bot.tablist](#bottablist)\n      - [bot.isRaining](#botisraining)\n      - [bot.rainState](#botrainstate)\n      - [bot.thunderState](#botthunderstate)\n      - [bot.chatPatterns](#botchatpatterns)\n      - [bot.settings.chat](#botsettingschat)\n      - [bot.settings.colorsEnabled](#botsettingscolorsenabled)\n      - [bot.settings.viewDistance](#botsettingsviewdistance)\n      - [bot.settings.difficulty](#botsettingsdifficulty)\n      - [bot.settings.skinParts](#botsettingsskinparts)\n        - [bot.settings.skinParts.showCape - boolean](#botsettingsskinpartsshowcape---boolean)\n        - [bot.settings.skinParts.showJacket - boolean](#botsettingsskinpartsshowjacket---boolean)\n        - [bot.settings.skinParts.showLeftSleeve - boolean](#botsettingsskinpartsshowleftsleeve---boolean)\n        - [bot.settings.skinParts.showRightSleeve - boolean](#botsettingsskinpartsshowrightsleeve---boolean)\n        - [bot.settings.skinParts.showLeftPants - boolean](#botsettingsskinpartsshowleftpants---boolean)\n        - [bot.settings.skinParts.showRightPants - boolean](#botsettingsskinpartsshowrightpants---boolean)\n        - [bot.settings.skinParts.showHat - boolean](#botsettingsskinpartsshowhat---boolean)\n      - [bot.settings.enableTextFiltering - boolean](#botsettingsenabletextfiltering---boolean)\n      - [bot.settings.enableServerListing - boolean](#botsettingsenableserverlisting---boolean)\n      - [bot.experience.level](#botexperiencelevel)\n      - [bot.experience.points](#botexperiencepoints)\n      - [bot.experience.progress](#botexperienceprogress)\n      - [bot.health](#bothealth)\n      - [bot.food](#botfood)\n      - [bot.foodSaturation](#botfoodsaturation)\n      - [bot.oxygenLevel](#botoxygenlevel)\n      - [bot.physics](#botphysics)\n      - [bot.fireworkRocketDuration](#botfireworkrocketduration)\n      - [bot.simpleClick.leftMouse (slot)](#botsimpleclickleftmouse-slot)\n      - [bot.simpleClick.rightMouse (slot)](#botsimpleclickrightmouse-slot)\n      - [bot.time.doDaylightCycle](#bottimedodaylightcycle)\n      - [bot.time.bigTime](#bottimebigtime)\n      - [bot.time.time](#bottimetime)\n      - [bot.time.timeOfDay](#bottimetimeofday)\n      - [bot.time.day](#bottimeday)\n      - [bot.time.isDay](#bottimeisday)\n      - [bot.time.moonPhase](#bottimemoonphase)\n      - [bot.time.bigAge](#bottimebigage)\n      - [bot.time.age](#bottimeage)\n      - [bot.quickBarSlot](#botquickbarslot)\n      - [bot.inventory](#botinventory)\n      - [bot.targetDigBlock](#bottargetdigblock)\n      - [bot.isSleeping](#botissleeping)\n      - [bot.scoreboards](#botscoreboards)\n      - [bot.scoreboard](#botscoreboard)\n      - [bot.teams](#botteams)\n      - [bot.teamMap](#botteammap)\n      - [bot.controlState](#botcontrolstate)\n    - [Events](#events)\n      - [\"chat\" (username, message, translate, jsonMsg, matches)](#chat-username-message-translate-jsonmsg-matches)\n      - [\"whisper\" (username, message, translate, jsonMsg, matches)](#whisper-username-message-translate-jsonmsg-matches)\n      - [\"actionBar\" (jsonMsg, verified)](#actionbar-jsonmsg-verified)\n      - [\"message\" (jsonMsg, position, sender, verified)](#message-jsonmsg-position-sender-verified)\n      - [\"messagestr\" (message, messagePosition, jsonMsg, sender, verified)](#messagestr-message-messageposition-jsonmsg-sender-verified)\n      - [\"inject_allowed\"](#inject_allowed)\n      - [\"login\"](#login)\n      - [\"spawn\"](#spawn)\n      - [\"respawn\"](#respawn)\n      - [\"game\"](#game)\n      - [\"resourcePack\" (url, hash)](#resourcepack-url-hash)\n      - [\"title\" (title, type)](#title-title-type)\n      - [\"title_times\" (fadeIn, stay, fadeOut)](#title_times-fadein-stay-fadeout)\n      - [\"title_clear\"](#title_clear)\n      - [\"rain\"](#rain)\n      - [\"weatherUpdate\"](#weatherupdate)\n      - [\"time\"](#time)\n      - [\"kicked\" (reason, loggedIn)](#kicked-reason-loggedin)\n      - [\"end\" (reason)](#end-reason)\n      - [\"error\" (err)](#error-err)\n      - [\"spawnReset\"](#spawnreset)\n      - [\"death\"](#death)\n      - [\"health\"](#health)\n      - [\"breath\"](#breath)\n      - [\"entityAttributes\" (entity)](#entityattributes-entity)\n      - [\"entitySwingArm\" (entity)](#entityswingarm-entity)\n      - [\"entityHurt\" (entity)](#entityhurt-entity)\n      - [\"entityDead\" (entity)](#entitydead-entity)\n      - [\"entityTaming\" (entity)](#entitytaming-entity)\n      - [\"entityTamed\" (entity)](#entitytamed-entity)\n      - [\"entityShakingOffWater\" (entity)](#entityshakingoffwater-entity)\n      - [\"entityEatingGrass\" (entity)](#entityeatinggrass-entity)\n      - [\"entityHandSwap\" (entity)](#entityhandswap-entity)\n      - [\"entityWake\" (entity)](#entitywake-entity)\n      - [\"entityEat\" (entity)](#entityeat-entity)\n      - [\"entityCriticalEffect\" (entity)](#entitycriticaleffect-entity)\n      - [\"entityMagicCriticalEffect\" (entity)](#entitymagiccriticaleffect-entity)\n      - [\"entityCrouch\" (entity)](#entitycrouch-entity)\n      - [\"entityUncrouch\" (entity)](#entityuncrouch-entity)\n      - [\"entityEquip\" (entity)](#entityequip-entity)\n      - [\"entitySleep\" (entity)](#entitysleep-entity)\n      - [\"entitySpawn\" (entity)](#entityspawn-entity)\n      - [\"entityElytraFlew\" (entity)](#entityelytraflew-entity)\n      - [\"itemDrop\" (entity)](#itemdrop-entity)\n      - [\"playerCollect\" (collector, collected)](#playercollect-collector-collected)\n      - [\"entityGone\" (entity)](#entitygone-entity)\n      - [\"entityMoved\" (entity)](#entitymoved-entity)\n      - [\"entityDetach\" (entity, vehicle)](#entitydetach-entity-vehicle)\n      - [\"entityAttach\" (entity, vehicle)](#entityattach-entity-vehicle)\n      - [\"entityUpdate\" (entity)](#entityupdate-entity)\n      - [\"entityEffect\" (entity, effect)](#entityeffect-entity-effect)\n      - [\"entityEffectEnd\" (entity, effect)](#entityeffectend-entity-effect)\n      - [\"playerJoined\" (player)](#playerjoined-player)\n      - [\"playerUpdated\" (player)](#playerupdated-player)\n      - [\"playerLeft\" (player)](#playerleft-player)\n      - [\"blockUpdate\" (oldBlock, newBlock)](#blockupdate-oldblock-newblock)\n      - [\"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#blockupdatex-y-z-oldblock-newblock)\n      - [\"blockPlaced\" (oldBlock, newBlock)](#blockplaced-oldblock-newblock)\n      - [\"chunkColumnLoad\" (point)](#chunkcolumnload-point)\n      - [\"chunkColumnUnload\" (point)](#chunkcolumnunload-point)\n      - [\"soundEffectHeard\" (soundName, position, volume, pitch)](#soundeffectheard-soundname-position-volume-pitch)\n      - [\"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)](#hardcodedsoundeffectheard-soundid-soundcategory-position-volume-pitch)\n      - [\"noteHeard\" (block, instrument, pitch)](#noteheard-block-instrument-pitch)\n      - [\"pistonMove\" (block, isPulling, direction)](#pistonmove-block-ispulling-direction)\n      - [\"chestLidMove\" (block, isOpen, block2)](#chestlidmove-block-isopen-block2)\n      - [\"blockBreakProgressObserved\" (block, destroyStage, entity)](#blockbreakprogressobserved-block-destroystage-entity)\n      - [\"blockBreakProgressEnd\" (block, entity)](#blockbreakprogressend-block-entity)\n      - [\"diggingCompleted\" (block)](#diggingcompleted-block)\n      - [\"diggingAborted\" (block)](#diggingaborted-block)\n      - [\"usedFirework\" (fireworkEntityId)](#usedfirework-fireworkentityid)\n      - [\"move\"](#move)\n      - [\"forcedMove\"](#forcedmove)\n      - [\"mount\"](#mount)\n      - [\"dismount\" (vehicle)](#dismount-vehicle)\n      - [\"windowOpen\" (window)](#windowopen-window)\n      - [\"windowClose\" (window)](#windowclose-window)\n      - [\"sleep\"](#sleep)\n      - [\"wake\"](#wake)\n      - [\"experience\"](#experience)\n      - [\"scoreboardCreated\" (scoreboard)](#scoreboardcreated-scoreboard)\n      - [\"scoreboardDeleted\" (scoreboard)](#scoreboarddeleted-scoreboard)\n      - [\"scoreboardTitleChanged\" (scoreboard)](#scoreboardtitlechanged-scoreboard)\n      - [\"scoreUpdated\" (scoreboard, item)](#scoreupdated-scoreboard-item)\n      - [\"scoreRemoved\" (scoreboard, item)](#scoreremoved-scoreboard-item)\n      - [\"scoreboardPosition\" (position, scoreboard)](#scoreboardposition-position-scoreboard)\n      - [\"teamCreated\" (team)](#teamcreated-team)\n      - [\"teamRemoved\" (team)](#teamremoved-team)\n      - [\"teamUpdated\" (team)](#teamupdated-team)\n      - [\"teamMemberAdded\" (team)](#teammemberadded-team)\n      - [\"teamMemberRemoved\" (team)](#teammemberremoved-team)\n      - [\"bossBarCreated\" (bossBar)](#bossbarcreated-bossbar)\n      - [\"bossBarDeleted\" (bossBar)](#bossbardeleted-bossbar)\n      - [\"bossBarUpdated\" (bossBar)](#bossbarupdated-bossbar)\n      - [\"heldItemChanged\" (heldItem)](#helditemchanged-helditem)\n      - [\"physicsTick\" ()](#physicstick-)\n      - [\"chat:name\" (matches)](#chatname-matches)\n      - [\"particle\"](#particle)\n    - [Functions](#functions)\n      - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)\n      - [bot.waitForChunksToLoad()](#botwaitforchunkstoload)\n      - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)\n      - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)\n      - [bot.entityAtCursor(maxDistance=3.5)](#botentityatcursormaxdistance35)\n      - [bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)](#botblockatentitycursorentitybotentity-maxdistance256)\n      - [bot.canSeeBlock(block)](#botcanseeblockblock)\n      - [bot.findBlocks(options)](#botfindblocksoptions)\n      - [bot.findBlock(options)](#botfindblockoptions)\n      - [bot.canDigBlock(block)](#botcandigblockblock)\n      - [bot.recipesFor(itemType, metadata, minResultCount, craftingTable)](#botrecipesforitemtype-metadata-minresultcount-craftingtable)\n      - [bot.recipesAll(itemType, metadata, craftingTable)](#botrecipesallitemtype-metadata-craftingtable)\n      - [bot.nearestEntity(match = (entity) => { return true })](#botnearestentitymatch--entity---return-true-)\n    - [Methods](#methods)\n      - [bot.end(reason)](#botendreason)\n      - [bot.quit(reason)](#botquitreason)\n      - [bot.tabComplete(str, [assumeCommand], [sendBlockInSight], [timeout])](#bottabcompletestr-assumecommand-sendblockinsight-timeout)\n      - [bot.chat(message)](#botchatmessage)\n      - [bot.whisper(username, message)](#botwhisperusername-message)\n      - [bot.chatAddPattern(pattern, chatType, description)](#botchataddpatternpattern-chattype-description)\n      - [bot.addChatPattern(name, pattern, chatPatternOptions)](#botaddchatpatternname-pattern-chatpatternoptions)\n      - [bot.addChatPatternSet(name, patterns, chatPatternOptions)](#botaddchatpatternsetname-patterns-chatpatternoptions)\n      - [bot.removeChatPattern(name)](#botremovechatpatternname)\n      - [bot.awaitMessage(...args)](#botawaitmessageargs)\n      - [bot.setSettings(options)](#botsetsettingsoptions)\n      - [bot.loadPlugin(plugin)](#botloadpluginplugin)\n      - [bot.loadPlugins(plugins)](#botloadpluginsplugins)\n      - [bot.hasPlugin(plugin)](#bothaspluginplugin)\n      - [bot.sleep(bedBlock)](#botsleepbedblock)\n      - [bot.isABed(bedBlock)](#botisabedbedblock)\n      - [bot.wake()](#botwake)\n      - [bot.setControlState(control, state)](#botsetcontrolstatecontrol-state)\n      - [bot.getControlState(control)](#botgetcontrolstatecontrol)\n      - [bot.clearControlStates()](#botclearcontrolstates)\n      - [bot.getExplosionDamages(entity, position, radius, [rawDamages])](#botgetexplosiondamagesentity-position-radius-rawdamages)\n      - [bot.lookAt(point, [force])](#botlookatpoint-force)\n      - [bot.look(yaw, pitch, [force])](#botlookyaw-pitch-force)\n      - [bot.updateSign(block, text, back = false)](#botupdatesignblock-text-back--false)\n      - [bot.equip(item, destination)](#botequipitem-destination)\n      - [bot.unequip(destination)](#botunequipdestination)\n      - [bot.tossStack(item)](#bottossstackitem)\n      - [bot.toss(itemType, metadata, count)](#bottossitemtype-metadata-count)\n      - [bot.elytraFly()](#botelytrafly)\n      - [bot.dig(block, [forceLook = true], [digFace])](#botdigblock-forcelook--true-digface)\n      - [bot.stopDigging()](#botstopdigging)\n      - [bot.digTime(block)](#botdigtimeblock)\n      - [bot.acceptResourcePack()](#botacceptresourcepack)\n      - [bot.denyResourcePack()](#botdenyresourcepack)\n      - [bot.placeBlock(referenceBlock, faceVector)](#botplaceblockreferenceblock-facevector)\n      - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)\n      - [bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botactivateblockblock-direction-vec3-cursorpos-vec3)\n      - [bot.activateEntity(entity)](#botactivateentityentity)\n      - [bot.activateEntityAt(entity, position)](#botactivateentityatentity-position)\n      - [bot.consume()](#botconsume)\n      - [bot.fish()](#botfish)\n      - [bot.activateItem(offHand=false)](#botactivateitemoffhandfalse)\n      - [bot.deactivateItem()](#botdeactivateitem)\n      - [bot.useOn(targetEntity)](#botuseontargetentity)\n      - [bot.attack(entity, swing = true)](#botattackentity-swing--true)\n      - [bot.swingArm([hand], showHand)](#botswingarmhand-showhand)\n      - [bot.mount(entity)](#botmountentity)\n      - [bot.dismount()](#botdismount)\n      - [bot.moveVehicle(left,forward)](#botmovevehicleleftforward)\n      - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)\n      - [bot.craft(recipe, count, craftingTable)](#botcraftrecipe-count-craftingtable)\n      - [bot.writeBook(slot, pages)](#botwritebookslot-pages)\n      - [bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)](#botopencontainercontainerblock-or-containerentity-direction-cursorpos)\n      - [bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)](#botopenchestchestblock-or-minecartchestentity-direction-cursorpos)\n      - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)\n      - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)\n      - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)\n      - [bot.openAnvil(anvilBlock)](#botopenanvilanvilblock)\n      - [bot.openVillager(villagerEntity)](#botopenvillagervillagerentity)\n      - [bot.trade(villagerInstance, tradeIndex, [times])](#bottradevillagerinstance-tradeindex-times)\n      - [bot.setCommandBlock(pos, command, [options])](#botsetcommandblockpos-command-options)\n      - [bot.supportFeature(name)](#botsupportfeaturename)\n      - [bot.waitForTicks(ticks)](#botwaitforticksticks)\n      - [bot.respawn()](#botrespawn)\n    - [Lower level inventory methods](#lower-level-inventory-methods)\n      - [bot.clickWindow(slot, mouseButton, mode)](#botclickwindowslot-mousebutton-mode)\n      - [bot.putSelectedItemRange(start, end, window, slot)](#botputselecteditemrangestart-end-window-slot)\n      - [bot.putAway(slot)](#botputawayslot)\n      - [bot.closeWindow(window)](#botclosewindowwindow)\n      - [bot.transfer(options)](#bottransferoptions)\n      - [bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botopenblockblock-direction-vec3-cursorpos-vec3)\n      - [bot.openEntity(entity)](#botopenentityentity)\n      - [bot.moveSlotItem(sourceSlot, destSlot)](#botmoveslotitemsourceslot-destslot)\n      - [bot.updateHeldItem()](#botupdatehelditem)\n      - [bot.getEquipmentDestSlot(destination)](#botgetequipmentdestslotdestination)\n    - [bot.creative](#botcreative)\n      - [bot.creative.setInventorySlot(slot, item)](#botcreativesetinventoryslotslot-item)\n      - [bot.creative.clearSlot(slot)](#botcreativeclearslotslot)\n      - [bot.creative.clearInventory()](#botcreativeclearinventory)\n      - [bot.creative.flyTo(destination)](#botcreativeflytodestination)\n      - [bot.creative.startFlying()](#botcreativestartflying)\n      - [bot.creative.stopFlying()](#botcreativestopflying)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API\n\n## Enums\n\nThese enums are stored in the language independent [minecraft-data](https://github.com/PrismarineJS/minecraft-data) project,\n and accessed through [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\n### minecraft-data\nThe data is available in [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data) module\n\n`require('minecraft-data')(bot.version)` gives you access to it.\n\n### mcdata.blocks\nblocks indexed by id\n\n### mcdata.items\nitems indexed by id\n\n### mcdata.materials\n\nThe key is the material. The value is an object with the key as the item id\nof the tool and the value as the efficiency multiplier.\n\n### mcdata.recipes\nrecipes indexed by id\n\n### mcdata.instruments\ninstruments indexed by id\n\n### mcdata.biomes\nbiomes indexed by id\n\n### mcdata.entities\nentities indexed by id\n\n## Classes\n\n### vec3\n\nSee [andrewrk/node-vec3](https://github.com/andrewrk/node-vec3)\n\nAll points in mineflayer are supplied as instances of this class.\n\n * x - south\n * y - up\n * z - west\n\nFunctions and methods which require a point argument accept `Vec3` instances\nas well as an array with 3 values, and an object with `x`, `y`, and `z`\nproperties.\n\n### mineflayer.Location\n\n### Entity\n\nEntities represent players, mobs, and objects. They are emitted\nin many events, and you can access your own entity with `bot.entity`.\nSee [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)\n\n#### Player Skin Data\n\nThe skin data is stored in the `skinData` property of the player object, if present.\n\n```js\n// player.skinData\n{\n  url: 'http://textures.minecraft.net/texture/...',\n  model: 'slim' // or 'classic'\n}\n```\n\n### Block\n\nSee [prismarine-block](https://github.com/PrismarineJS/prismarine-block)\n\nAlso `block.blockEntity` is additional field with block entity data as `Object`. The data in this varies between versions.\n```js\n// sign.blockEntity example from 1.19\n{\n  GlowingText: 0, // 0 for false, 1 for true\n  Color: 'black',\n  Text1: '{\"text\":\"1\"}',\n  Text2: '{\"text\":\"2\"}',\n  Text3: '{\"text\":\"3\"}',\n  Text4: '{\"text\":\"4\"}'\n}\n```\n\nNote if you want to get a sign's plain text, you can use [`block.getSignText()`](https://github.com/PrismarineJS/prismarine-block/blob/master/doc/API.md#sign) instead of unstable blockEntity data.\n```java\n> block = bot.blockAt(new Vec3(0, 60, 0)) // assuming a sign is here\n> block.getSignText()\n[ \"Front text\\nHello world\", \"Back text\\nHello world\" ]\n```\n\n### Biome\n\nSee [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome)\n\n### Item\n\nSee [prismarine-item](https://github.com/PrismarineJS/prismarine-item)\n\n### windows.Window (base class)\n\nSee [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows)\n\n#### window.deposit(itemType, metadata, count, nbt)\n\nThis function returns a `Promise`, with `void` as its argument when done depositing.\n\n * `itemType` - numerical item id\n * `metadata` - numerical value. `null` means match anything.\n * `count` - how many to deposit. `null` is an alias to 1.\n * `nbt` - match nbt data. `null` is do not match nbt.\n\n#### window.withdraw(itemType, metadata, count, nbt)\n\nThis function returns a `Promise`, with `void` as its argument when done withdrawing. Throws and error if the bot has no free room in its inventory.\n\n * `itemType` - numerical item id\n * `metadata` - numerical value. `null` means match anything.\n * `count` - how many to withdraw. `null` is an alias to 1.\n * `nbt` - match nbt data. `null` is do not match nbt.\n\n#### window.close()\n\n### Recipe\n\nSee [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)\n\n### mineflayer.Container\n\nExtends windows.Window for chests, dispensers, etc...\nSee `bot.openContainer(chestBlock or minecartchestEntity)`.\n\n### mineflayer.Furnace\n\nExtends windows.Window for furnace, smelter, etc...\nSee `bot.openFurnace(furnaceBlock)`.\n\n#### furnace \"update\"\n\nFires when `furnace.fuel` and/or `furnace.progress` update.\n\n#### furnace.takeInput()\n\nThis function returns a `Promise`, with `item` as its argument upon completion.\n\n\n#### furnace.takeFuel()\n\nThis function returns a `Promise`, with `item` as its argument upon completion.\n\n\n#### furnace.takeOutput()\n\nThis function returns a `Promise`, with `item` as its argument upon completion.\n\n\n#### furnace.putInput(itemType, metadata, count)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n#### furnace.putFuel(itemType, metadata, count)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n#### furnace.inputItem()\n\nReturns `Item` instance which is the input.\n\n#### furnace.fuelItem()\n\nReturns `Item` instance which is the fuel.\n\n#### furnace.outputItem()\n\nReturns `Item` instance which is the output.\n\n#### furnace.fuel\n\nHow much fuel is left between 0 and 1.\n\n#### furnace.progress\n\nHow much cooked the input is between 0 and 1.\n\n### mineflayer.EnchantmentTable\n\nExtends windows.Window for enchantment tables\nSee `bot.openEnchantmentTable(enchantmentTableBlock)`.\n\n#### enchantmentTable \"ready\"\n\nFires when `enchantmentTable.enchantments` is fully populated and you\nmay make a selection by calling `enchantmentTable.enchant(choice)`.\n\n#### enchantmentTable.targetItem()\n\nGets the target item. This is both the input and the output of the\nenchantment table.\n\n#### enchantmentTable.xpseed\n\nThe 16 bits xpseed sent by the server.\n\n#### enchantmentTable.enchantments\n\nArray of length 3 which are the 3 enchantments to choose from.\n`level` can be `-1` if the server has not sent the data yet.\n\nLooks like:\n\n```js\n[\n  {\n    level: 3\n  },\n  {\n    level: 4\n  },\n  {\n    level: 9\n  }\n]\n```\n\n#### enchantmentTable.enchant(choice)\n\nThis function returns a `Promise`, with `item` as its argument when the item has been enchanted.\n\n * `choice` - [0-2], the index of the enchantment you want to pick.\n\n#### enchantmentTable.takeTargetItem()\n\nThis function returns a `Promise`, with `item` as its argument upon completion.\n\n\n#### enchantmentTable.putTargetItem(item)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n\n#### enchantmentTable.putLapis(item)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n\n### mineflayer.anvil\n\nExtends windows.Window for anvils\nSee `bot.openAnvil(anvilBlock)`.\n\n#### anvil.combine(itemOne, itemTwo[, name])\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n\n#### anvil.combine(item[, name])\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\n\n#### villager \"ready\"\n\nFires when `villager.trades` is loaded.\n\n#### villager.trades\n\nArray of trades.\n\nLooks like:\n\n```js\n[\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: true,\n    secondaryInput: Item,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  }\n]\n```\n\n#### villager.trade(tradeIndex, [times])\nIs the same as [bot.trade(villagerInstance, tradeIndex, [times])](#bottradevillagerinstance-tradeindex-times)\n\n### mineflayer.ScoreBoard\n\n#### ScoreBoard.name\n\nName of the scoreboard.\n\n#### ScoreBoard.title\n\nThe title of the scoreboard (does not always equal the name)\n\n#### ScoreBoard.itemsMap\n\nAn object with all items in the scoreboard in it\n```js\n{\n  wvffle: { name: 'wvffle', value: 3 },\n  dzikoysk: { name: 'dzikoysk', value: 6 }\n}\n```\n\n#### ScoreBoard.items\n\nAn array with all sorted items in the scoreboard in it\n```js\n[\n  { name: 'dzikoysk', value: 6 },\n  { name: 'wvffle', value: 3 }\n]\n```\n\n### mineflayer.Team\n\n#### Team.name\n\nName of the team\n\n#### Team.friendlyFire\n\n#### Team.nameTagVisibility\n\nOne of `always`, `hideForOtherTeams`, `hideForOwnTeam`\n\n#### Team.collisionRule\n\nOne of `always`, `pushOtherTeams`, `pushOwnTeam`\n\n#### Team.color\n\nColor (or formatting) name of team, e.g. `dark_green`, `red`, `underlined`\n\n#### Team.prefix\n\nA chat component containing team prefix\n\n#### Team.suffix\n\nA chat component containing team suffix\n\n#### Team.members\n\nArray of team members. Usernames for players and UUIDs for other entities.\n\n### mineflayer.BossBar\n\n#### BossBar.title\n\nTitle of boss bar, instance of ChatMessage\n\n#### BossBar.health\n\nPercent of boss health, from `0` to `1`\n\n#### BossBar.dividers\n\nNumber of boss bar dividers, one of `0`, `6`, `10`, `12`, `20`\n\n#### BossBar.entityUUID\n\nBoss bar entity uuid\n\n#### BossBar.shouldDarkenSky\n\nDetermines whether or not to darken the sky\n\n#### BossBar.isDragonBar\n\nDetermines whether or not boss bar is dragon bar\n\n#### BossBar.createFog\n\nDetermines whether or not boss bar creates fog\n\n#### BossBar.color\n\nDetermines what color the boss bar color is, one of `pink`, `blue`, `red`, `green`, `yellow`, `purple`, `white`\n\n### mineflayer.Particle\n\n#### Particle.id\n\nParticle ID, as defined in the [protocol](https://minecraft.wiki/w/Protocol#Particle)\n\n#### Particle.name\n\nParticle Name, as defined in the [protocol](https://minecraft.wiki/w/Protocol#Particle)\n\n#### Particle.position\n\nVec3 instance of where the particle was created\n\n#### Particle.offset\n\nVec3 instance of the particle's offset\n\n#### Particle.longDistanceRender\n\nDetermines whether or not to force the rendering of a particle despite client particle settings and increases maximum view distance from 256 to 65536\n\n#### Particle.count\n\nAmount of particles created\n\n#### Particle.movementSpeed\n\nParticle speed in a random direction\n\n## Bot\n\n### mineflayer.createBot(options)\n\nCreate and return an instance of the class bot.\n`options` is an object containing the optional properties :\n * username : default to 'Player'\n * port : default to 25565\n * password : can be omitted (if the tokens are also omitted then it tries to connect in offline mode)\n * host : default to localhost\n * version : default to automatically guessing the version of the server. Example of value : \"1.12.2\"\n * auth : default to 'mojang', can also be 'microsoft'\n * clientToken : generated if a password is given\n * accessToken : generated if a password is given\n * logErrors : true by default, catch errors and log them\n * hideErrors : true by default, do not log errors (even if logErrors is true)\n * keepAlive : send keep alive packets : default to true\n * checkTimeoutInterval : default to `30*1000` (30s), check if keepalive received at that period, disconnect otherwise.\n * loadInternalPlugins : defaults to true\n * storageBuilder : an optional function, takes as argument version and worldName and return an instance of something with the same API as prismarine-provider-anvil. Will be used to save the world.\n * client : an instance of node-minecraft-protocol, if not specified, mineflayer makes its own client. This can be used to enable using mineflayer through a proxy of many clients or a vanilla client and a mineflayer client.\n * brand : the brand name for the client to use. Defaults to vanilla. Can be used to simulate custom clients for servers that require it.\n * respawn : when set to false disables bot from automatically respawning, defaults to true.\n * plugins : object : defaults to {}\n   - pluginName : false : don't load internal plugin with given name ie. `pluginName`\n   - pluginName : true : load internal plugin with given name ie. `pluginName` even though loadInternalplugins is set to false\n   - pluginName : external plugin inject function : loads external plugin, overrides internal plugin with given name ie. `pluginName`\n * physicsEnabled : true by default, should the bot be affected by physics? can later be modified via bot.physicsEnabled\n * [chat](#bot.settings.chat)\n * [colorsEnabled](#bot.settings.colorsEnabled)\n * [viewDistance](#bot.settings.viewDistance)\n * [difficulty](#bot.settings.difficulty)\n * [skinParts](#bot.settings.skinParts)\n * [enableTextFiltering](#bot.settings.enableTextFiltering)\n * [enableServerListing](#bot.settings.enableServerListing)\n * chatLengthLimit : the maximum amount of characters that can be sent in a single message. If this is not set, it will be 100 in < 1.11 and 256 in >= 1.11.\n * defaultChatPatterns: defaults to true, set to false to not add the patterns such as chat and whisper\n\n### Properties\n\n#### bot.registry\n\nInstance of minecraft-data used by the bot. Pass this to constructors that expect an instance of minecraft-data, such as prismarine-block.\n\n#### bot.world\n\nA sync representation of the world. Check the doc at http://github.com/PrismarineJS/prismarine-world\n\n##### world \"blockUpdate\" (oldBlock, newBlock)\n\nFires when a block updates. Both `oldBlock` and `newBlock` provided for\ncomparison.\n`oldBlock` may be `null` with normal block updates.\n\n##### world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\nFires for a specific point. Both `oldBlock` and `newBlock` provided for\ncomparison. All listeners receive null for `oldBlock` and `newBlock` and get automatically removed when the world is unloaded.\n`oldBlock` may be `null` with normal block updates.\n\n\n#### bot.entity\n\nYour own entity. See `Entity`.\n\n#### bot.entities\n\nAll nearby entities. This object is a map of entityId to entity.\n\n#### bot.username\n\nUse this to find out your own name.\n\n#### bot.spawnPoint\n\nCoordinates to the main spawn point, where all compasses point to.\n\n#### bot.heldItem\n\nThe item in the bot's hand, represented as a [prismarine-item](https://github.com/PrismarineJS/prismarine-item) instance specified with arbitrary metadata, nbtdata, etc.\n\n#### bot.usingHeldItem\n\nWhether the bot is using the item that it's holding, for example eating food or using a shield.\n\n#### bot.game.levelType\n\n#### bot.game.dimension\n\nThe bot's current dimension, such as `overworld`, `the_end` or `the_nether`.\n\n#### bot.game.difficulty\n\n#### bot.game.gameMode\n\n#### bot.game.hardcore\n\n#### bot.game.maxPlayers\n\n#### bot.game.serverBrand\n\n#### bot.game.minY\n\nminimum y of the world\n\n#### bot.game.height\n\nworld height\n\n#### bot.physicsEnabled\n\nEnable physics, default true.\n\n#### bot.player\n\nBot's player object\n```js\n{\n  username: 'player',\n  displayName: { toString: Function }, // ChatMessage object.\n  gamemode: 0,\n  ping: 28,\n  entity: entity // null if you are too far away\n}\n```\n\nA player's ping starts at 0, you might have to wait a bit for the server to send their actual ping.\n\n#### bot.players\n\nMap of username to people playing the game.\n\n#### bot.tablist\n\nbot's tablist object has two keys, `header` and `footer`.\n\n```js\n{\n  header: { toString: Function }, // ChatMessage object.\n  footer: { toString: Function } // ChatMessage object.\n}\n```\n\n#### bot.isRaining\n\n#### bot.rainState\n\nA number indicating the current rain level. When it isn't raining, this\nwill be equal to 0. When it starts to rain, this value will increase\ngradually up to 1. When it stops raining, this value gradually decreases back to 0.\n\nEach time `bot.rainState` is changed, the \"weatherUpdate\" event is emitted.\n\n#### bot.thunderState\n\nA number indicating the current thunder level. When there isn't a thunderstorm, this\nwill be equal to 0. When a thunderstorm starts, this value will increase\ngradually up to 1. When the thunderstorm stops, this value gradually decreases back to 0.\n\nEach time `bot.thunderState` is changed, the \"weatherUpdate\" event is emitted.\n\nThis is the same as `bot.rainState`, but for thunderstorms.\nFor thunderstorms, both `bot.rainState` and `bot.thunderState` will change.\n\n#### bot.chatPatterns\n\nThis is an array of pattern objects, of the following format:\n{ /regex/, \"chattype\", \"description\")\n * /regex/ - a regular expression pattern, that should have at least two capture groups\n * 'chattype' - the type of chat the pattern matches, ex \"chat\" or \"whisper\", but can be anything.\n * 'description' - description of what the pattern is for, optional.\n\n#### bot.settings.chat\n\nChoices:\n\n * `enabled` (default)\n * `commandsOnly`\n * `disabled`\n\n#### bot.settings.colorsEnabled\n\nDefault true, whether or not you receive color codes in chats from the server.\n\n#### bot.settings.viewDistance\n\nCan be a string listed below or a positive number.\nChoices:\n * `far` (default)\n * `normal`\n * `short`\n * `tiny`\n\n#### bot.settings.difficulty\n\nSame as from server.properties.\n\n#### bot.settings.skinParts\n\nThese boolean Settings control if extra Skin Details on the own players' skin should be visible\n\n##### bot.settings.skinParts.showCape - boolean\n\nIf you have a cape you can turn it off by setting this to false.\n\n##### bot.settings.skinParts.showJacket - boolean\n\n##### bot.settings.skinParts.showLeftSleeve - boolean\n\n##### bot.settings.skinParts.showRightSleeve - boolean\n\n##### bot.settings.skinParts.showLeftPants - boolean\n\n##### bot.settings.skinParts.showRightPants - boolean\n\n##### bot.settings.skinParts.showHat - boolean\n\n#### bot.settings.enableTextFiltering - boolean\nUnused, defaults to false in Notchian (Vanilla) client.\n#### bot.settings.enableServerListing - boolean\nThis setting is sent to the server to determine whether the player should show up in server listings\n#### bot.experience.level\n\n#### bot.experience.points\n\nTotal experience points.\n\n#### bot.experience.progress\n\nBetween 0 and 1 - amount to get to the next level.\n\n#### bot.health\n\nNumber in the range [0, 20] representing the number of half-hearts.\n\n#### bot.food\n\nNumber in the range [0, 20] representing the number of half-turkey-legs.\n\n#### bot.foodSaturation\n\nFood saturation acts as a food \"overcharge\". Food values will not decrease\nwhile the saturation is over zero. Players logging in automatically get a\nsaturation of 5.0. Eating food increases the saturation as well as the food bar.\n\n#### bot.oxygenLevel\n\nNumber in the range [0, 20] representing the number of water-icons known as oxygen level.\n\n#### bot.physics\n\nEdit these numbers to tweak gravity, jump speed, terminal velocity, etc.\nDo this at your own risk.\n\n#### bot.fireworkRocketDuration\n\nHow many physics ticks worth of firework rocket boost are left.\n\n#### bot.simpleClick.leftMouse (slot)\n\nabstraction over `bot.clickWindow(slot, 0, 0)`\n\n#### bot.simpleClick.rightMouse (slot)\n\nabstraction over `bot.clickWindow(slot, 1, 0)`\n\n#### bot.time.doDaylightCycle\n\nWhether or not the gamerule doDaylightCycle is true or false.\n\n#### bot.time.bigTime\n\nThe total number of ticks since day 0.\n\nThis value is of type BigInt and is accurate even at very large values. (more than 2^51 - 1 ticks)\n\n#### bot.time.time\n\nThe total numbers of ticks since day 0.\n\nBecause the Number limit of Javascript is at 2^51 - 1 bot.time.time becomes inaccurate higher than this limit and the use of bot.time.bigTime is recommended.\nRealistically though you'll probably never need to use bot.time.bigTime as it will only reach 2^51 - 1 ticks naturally after ~14280821 real years.\n\n#### bot.time.timeOfDay\n\nTime of the day, in ticks.\n\nTime is based on ticks, where 20 ticks happen every second. There are 24000\nticks in a day, making Minecraft days exactly 20 minutes long.\n\nThe time of day is based on the timestamp modulo 24000. 0 is sunrise, 6000\nis noon, 12000 is sunset, and 18000 is midnight.\n\n#### bot.time.day\n\nDay of the world.\n\n#### bot.time.isDay\n\nWhether it is day or not.\n\nBased on whether the current time of day is between 0 and 13000 ticks (day + sunset).\n\n#### bot.time.moonPhase\n\nPhase of the moon.\n\n0-7 where 0 is full moon.\n\n#### bot.time.bigAge\n\nAge of the world, in ticks.\n\nThis value is of type BigInt and is accurate even at very large values. (more than 2^51 - 1 ticks)\n\n#### bot.time.age\n\nAge of the world, in ticks.\n\nBecause the Number limit of Javascript is at 2^51 - 1 bot.time.age becomes inaccurate higher than this limit and the use of bot.time.bigAge is recommended.\nRealistically though you'll probably never need to use bot.time.bigAge as it will only reach 2^51 - 1 ticks naturally after ~14280821 real years.\n\n#### bot.quickBarSlot\n\nWhich quick bar slot is selected (0 - 8).\n\n#### bot.inventory\n\nA [`Window`](https://github.com/PrismarineJS/prismarine-windows#windowswindow-base-class) instance representing your inventory.\n\n#### bot.targetDigBlock\n\nThe `block` that you are currently digging, or `null`.\n\n#### bot.isSleeping\n\nBoolean, whether or not you are in bed.\n\n#### bot.scoreboards\n\nAll scoreboards known to the bot in an object scoreboard name -> scoreboard.\n\n#### bot.scoreboard\n\nAll scoreboards known to the bot in an object scoreboard displaySlot -> scoreboard.\n\n * `belowName` - scoreboard placed in belowName\n * `sidebar` - scoreboard placed in sidebar\n * `list` - scoreboard placed in list\n * `0-18` - slots defined in [protocol](https://minecraft.wiki/w/Protocol#Display_Scoreboard)\n\n#### bot.teams\n\nAll teams known to the bot\n\n#### bot.teamMap\n\nMapping of member to team. Uses usernames for players and UUIDs for entities.\n\n#### bot.controlState\n\nAn object whose keys are the main control states: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'].\n\nSetting values for this object internally calls [bot.setControlState](#botsetcontrolstatecontrol-state).\n\n### Events\n\n#### \"chat\" (username, message, translate, jsonMsg, matches)\n\nOnly emitted when a player chats publicly.\n\n * `username` - who said the message (compare with `bot.username` to ignore your own chat)\n * `message` - stripped of all color and control characters\n * `translate` - chat message type. Null for most bukkit chat messages\n * `jsonMsg` - unmodified JSON message from the server\n * `matches` - array of returned matches from regular expressions. May be null\n\n#### \"whisper\" (username, message, translate, jsonMsg, matches)\n\nOnly emitted when a player chats to you privately.\n\n * `username` - who said the message\n * `message` - stripped of all color and control characters\n * `translate` - chat message type. Null for most bukkit chat messages\n * `jsonMsg` - unmodified JSON message from the server\n * `matches` - array of returned matches from regular expressions. May be null\n\n#### \"actionBar\" (jsonMsg, verified)\n\nEmitted for every server message which appears on the Action Bar.\n\n * `jsonMsg` - unmodified JSON message from the server\n * `verified` -> null if non signed, true if signed and correct, false if signed and incorrect\n\n#### \"message\" (jsonMsg, position, sender, verified)\n\nEmitted for every server message, including chats.\n\n * `jsonMsg` - [ChatMessage](https://github.com/PrismarineJS/prismarine-chat) object containing the formatted chat message. Might additionally have the following properties:\n   * unsigned - Unsigned ChatMessage object. Only present in 1.19.2+, and only when the server allows insecure chat and the server modified the chat message without the user's signature\n\n * `position` - (>= 1.8.1): position of Chat message can be\n   * chat\n   * system\n   * game_info\n\n * `sender` - UUID of sender if known (1.16+), else null\n\n * `verified` -> null if non signed, true if signed and correct, false if signed and incorrect\n\n#### \"messagestr\" (message, messagePosition, jsonMsg, sender, verified)\n\nAlias for the \"message\" event but it calls .toString() on the prismarine-message object to get a string for the message before emitting.\n\n * `sender` - UUID of sender if known (1.16+), else null\n\n * `verified` -> null if non signed, true if signed and correct, false if signed and incorrect\n\n#### \"inject_allowed\"\nFires when the index file has been loaded, you can load mcData and plugins here but it's better to wait for \"spawn\" event.\n\n#### \"login\"\n\nFires after you successfully login to the server.\nYou probably want to wait for the `spawn` event\nbefore doing anything though.\n\n#### \"spawn\"\n\nEmitted once after you log in and spawn for the first time\nand then emitted when you respawn after death.\n\nThis is usually the event that you want to listen to\nbefore doing anything on the server.\n\n#### \"respawn\"\n\nEmitted when you change dimensions and just before you spawn.\nUsually you want to ignore this event and wait until the \"spawn\"\nevent instead.\n\n#### \"game\"\n\nEmitted when the server changes any of the game properties.\n\n#### \"resourcePack\" (url, hash)\n\nEmitted when the server sends a resource pack.\n\n#### \"title\" (title, type)\n\nEmitted when the server sends a title\n\n* `title` - title's text\n* `type` - title's type \"subtitle\", \"title\"\n\n#### \"title_times\" (fadeIn, stay, fadeOut)\n\nEmitted when the server sends a title times packet (i.e., when the fade-in, stay, and fade-out times for titles are set or updated).\n\n * `fadeIn` - fade-in time in ticks (number)\n * `stay` - stay time in ticks (number)\n * `fadeOut` - fade-out time in ticks (number)\n\nExample:\n\n```js\nbot.on('title_times', (fadeIn, stay, fadeOut) => {\n  console.log(`Title times: fadeIn=${fadeIn}, stay=${stay}, fadeOut=${fadeOut}`)\n})\n```\n\n#### \"title_clear\"\n\nEmitted when the server clears all titles.\n\n#### \"rain\"\n\nEmitted when it starts or stops raining. If you join a\nserver where it is already raining, this event will fire.\n\n#### \"weatherUpdate\"\n\nEmitted when either `bot.thunderState` or `bot.rainState` changes.\nIf you join a server where it is already raining, this event will fire.\n\n#### \"time\"\n\nEmitted when the server sends a time update. See `bot.time`.\n\n#### \"kicked\" (reason, loggedIn)\n\nEmitted when the bot is kicked from the server. `reason`\nis a chat message explaining why you were kicked. `loggedIn`\nis `true` if the client was kicked after successfully logging in,\nor `false` if the kick occurred in the login phase.\n\n#### \"end\" (reason)\n\nEmitted when you are no longer connected to the server.\n`reason` is a string explaining why the client was disconnected. (defaults to 'socketClosed')\n\n#### \"error\" (err)\n\nEmitted when an error occurs.\n\n#### \"spawnReset\"\n\nFires when you cannot spawn in your bed and your spawn point gets reset.\n\n#### \"death\"\n\nFires when you die.\n\n#### \"health\"\n\nFires when your hp or food change.\n\n#### \"breath\"\n\nFires when your oxygen level change.\n\n#### \"entityAttributes\" (entity)\n\nFires when an attribute of an entity changes.\n\n#### \"entitySwingArm\" (entity)\n#### \"entityHurt\" (entity)\n#### \"entityDead\" (entity)\n#### \"entityTaming\" (entity)\n#### \"entityTamed\" (entity)\n#### \"entityShakingOffWater\" (entity)\n#### \"entityEatingGrass\" (entity)\n#### \"entityHandSwap\" (entity)\n#### \"entityWake\" (entity)\n#### \"entityEat\" (entity)\n#### \"entityCriticalEffect\" (entity)\n#### \"entityMagicCriticalEffect\" (entity)\n#### \"entityCrouch\" (entity)\n#### \"entityUncrouch\" (entity)\n#### \"entityEquip\" (entity)\n#### \"entitySleep\" (entity)\n#### \"entitySpawn\" (entity)\n#### \"entityElytraFlew\" (entity)\n\nAn entity started elytra flying.\n\n#### \"itemDrop\" (entity)\n#### \"playerCollect\" (collector, collected)\n\nAn entity picked up an item.\n\n * `collector` - entity that picked up the item.\n * `collected` - the entity that was the item on the ground.\n\n#### \"entityGone\" (entity)\n#### \"entityMoved\" (entity)\n#### \"entityDetach\" (entity, vehicle)\n#### \"entityAttach\" (entity, vehicle)\n\nAn entity is attached to a vehicle, such as a mine cart\nor boat.\n\n * `entity` - the entity hitching a ride\n * `vehicle` - the entity that is the vehicle\n\n#### \"entityUpdate\" (entity)\n#### \"entityEffect\" (entity, effect)\n#### \"entityEffectEnd\" (entity, effect)\n#### \"playerJoined\" (player)\n#### \"playerUpdated\" (player)\n#### \"playerLeft\" (player)\n\n#### \"blockUpdate\" (oldBlock, newBlock)\n\n(It is better to use this event from bot.world instead of bot directly) Fires when a block updates. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\nNote that `oldBlock` may be `null`.\n\n#### \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\n(It is better to use this event from bot.world instead of bot directly) Fires for a specific point. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\nNote that `oldBlock` may be `null`.\n\n#### \"blockPlaced\" (oldBlock, newBlock)\n\nFires when bot places block. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\nNote that `oldBlock` may be `null`.\n\n#### \"chunkColumnLoad\" (point)\n#### \"chunkColumnUnload\" (point)\n\nFires when a chunk has updated. `point` is the coordinates to the corner\nof the chunk with the smallest x, y, and z values.\n\n#### \"soundEffectHeard\" (soundName, position, volume, pitch)\n\nFires when the client hears a named sound effect.\n\n * `soundName`: name of the sound effect\n * `position`: a Vec3 instance where the sound originates\n * `volume`: floating point volume, 1.0 is 100%\n * `pitch`: integer pitch, 63 is 100%\n\n#### \"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)\n\n  Fires when the client hears a hardcoded sound effect.\n\n   * `soundId`: id of the sound effect\n   * `soundCategory`: category of the sound effect\n   * `position`: a Vec3 instance where the sound originates\n   * `volume`: floating point volume, 1.0 is 100%\n   * `pitch`: integer pitch, 63 is 100%\n\n#### \"noteHeard\" (block, instrument, pitch)\n\nFires when a note block goes off somewhere.\n\n * `block`: a Block instance, the block that emitted the noise\n * `instrument`:\n   - `id`: integer id\n   - `name`: one of [`harp`, `doubleBass`, `snareDrum`, `sticks`, `bassDrum`].\n * `pitch`: The pitch of the note (between 0-24 inclusive where 0 is the\n   lowest and 24 is the highest). More information about how the pitch values\n   correspond to notes in real life are available on the\n   [official Minecraft wiki](http://minecraft.wiki/w/Note_Block).\n\n#### \"pistonMove\" (block, isPulling, direction)\n\n#### \"chestLidMove\" (block, isOpen, block2)\n* `block`: a Block instance, the block whose lid opened. The right block if it's a double chest\n* `isOpen`: number of players that have the chest open. 0 if it's closed\n* `block2`: a Block instance, the other half of the block whose lid opened. null if it's not a double chest\n\n#### \"blockBreakProgressObserved\" (block, destroyStage, entity)\n\nFires when the client observes a block in the process of being broken.\n\n * `block`: a Block instance, the block being broken\n * `destroyStage`: integer corresponding to the destroy progress (0-9)\n * `entity`: the entity which is breaking the block.\n\n#### \"blockBreakProgressEnd\" (block, entity)\n\nFires when the client observes a block stops being broken.\nThis occurs whether the process was completed or aborted.\n\n * `block`: a Block instance, the block no longer being broken\n * `entity`: the entity which has stopped breaking the block\n\n#### \"diggingCompleted\" (block)\n\n * `block` - the block that no longer exists\n\n#### \"diggingAborted\" (block)\n\n * `block` - the block that still exists\n\n#### \"usedFirework\" (fireworkEntityId)\n\nFires when the bot uses a firework while elytra flying.\n\n * `fireworkEntityId` - the entity id of the firework.\n\n#### \"move\"\n\nFires when the bot moves. If you want the current position, use\n`bot.entity.position` and for normal moves if you want the previous position, use\n`bot.entity.position.minus(bot.entity.velocity)`.\n\n#### \"forcedMove\"\n\nFires when the bot is force moved by the server (teleport, spawning, ...). If you want the current position, use\n`bot.entity.position`.\n\n#### \"mount\"\n\nFires when you mount an entity such as a minecart. To get access\nto the entity, use `bot.vehicle`.\n\nTo mount an entity, use `mount`.\n\n#### \"dismount\" (vehicle)\n\nFires when you dismount from an entity.\n\n#### \"windowOpen\" (window)\n\nFires when you begin using a workbench, chest, brewing stand, etc.\n\n#### \"windowClose\" (window)\n\nFires when you may no longer work with a workbench, chest, etc.\n\n#### \"sleep\"\n\nFires when you sleep.\n\n#### \"wake\"\n\nFires when you wake up.\n\n#### \"experience\"\n\nFires when `bot.experience.*` has updated.\n\n#### \"scoreboardCreated\" (scoreboard)\n\nFires when a scoreboard is added.\n\n#### \"scoreboardDeleted\" (scoreboard)\n\nFires when a scoreboard is deleted.\n\n#### \"scoreboardTitleChanged\" (scoreboard)\n\nFires when a scoreboard's title is updated.\n\n#### \"scoreUpdated\" (scoreboard, item)\n\nFires when the score of a item in a scoreboard is updated.\n\n#### \"scoreRemoved\" (scoreboard, item)\n\nFires when the score of a item in a scoreboard is removed.\n\n#### \"scoreboardPosition\" (position, scoreboard)\n\nFires when the position of a scoreboard is updated.\n\n#### \"teamCreated\" (team)\n\nFires when a team is added.\n\n#### \"teamRemoved\" (team)\n\nFires when a team is removed.\n\n#### \"teamUpdated\" (team)\n\nFires when a team is updated.\n\n#### \"teamMemberAdded\" (team)\n\nFires when a team member or multiple members are added to a team.\n\n#### \"teamMemberRemoved\" (team)\n\nFires when a team member or multiple members are removed from a team.\n\n#### \"bossBarCreated\" (bossBar)\n\nFires when new boss bar is created.\n\n#### \"bossBarDeleted\" (bossBar)\n\nFires when new boss bar is deleted.\n\n#### \"bossBarUpdated\" (bossBar)\n\nFires when new boss bar is updated.\n\n#### \"heldItemChanged\" (heldItem)\n\nFires when the held item is changed.\n\n#### \"physicsTick\" ()\n\nFires every tick if bot.physicsEnabled is set to true.\n\n#### \"chat:name\" (matches)\n\nFires when the all of a chat pattern's regexs have matches\n\n#### \"particle\"\n\nFires when a particle is created\n\n### Functions\n\n#### bot.blockAt(point, extraInfos=true)\n\nReturns the block at `point` or `null` if that point is not loaded. If `extraInfos` set to true, also returns information about signs, paintings and block entities (slower).\nSee `Block`.\n\n#### bot.waitForChunksToLoad()\n\nThis function returns a `Promise`, with `void` as its argument when many chunks have loaded.\n\n#### bot.blockInSight(maxSteps, vectorLength)\n\nDeprecated, use `blockAtCursor` instead.\n\nReturns the block at which bot is looking at or `null`\n * `maxSteps` - Number of steps to raytrace, defaults to 256.\n * `vectorLength` - Length of raytracing vector, defaults to `5/16`.\n\n#### bot.blockAtCursor(maxDistance=256)\n\nReturns the block at which bot is looking at or `null`\n * `maxDistance` - The maximum distance the block can be from the eye, defaults to 256.\n\n#### bot.entityAtCursor(maxDistance=3.5)\n\nReturns the entity at which bot is looking at or `null`\n * `maxDistance` - The maximum distance the entity can be from the eye, defaults to 3.5.\n\n#### bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)\n\nReturns the block at which specific entity is looking at or `null`\n * `entity` - Entity data as `Object`\n * `maxDistance` - The maximum distance the block can be from the eye, defaults to 256.\n\n#### bot.canSeeBlock(block)\n\nReturns true or false depending on whether the bot can see the specified `block`.\n\n#### bot.findBlocks(options)\n\nFinds the closest blocks from the given point.\n * `options` - Options for the search:\n   - `point` - The start position of the search (center). Default is the bot position.\n   - `matching` - A function that returns true if the given block is a match. Also supports this value being a block id or array of block ids.\n   - `useExtraInfo` - To preserve backward compatibility can result in two behavior depending on the type\n      - **boolean** - Provide your `matching` function more data - noticeably slower approach\n      - **function** - Creates two stage matching, if block passes `matching` function it is passed further to `useExtraInfo` with additional info\n   - `maxDistance` - The furthest distance for the search, defaults to 16.\n   - `count` - Number of blocks to find before returning the search. Default to 1. Can return less if not enough blocks are found exploring the whole area.\n\nReturns an array (possibly empty) with the found block coordinates (not the blocks). The array is sorted (closest first)\n\n#### bot.findBlock(options)\n\nAlias for `bot.blockAt(bot.findBlocks(options)[0])`. Return a single block or `null`.\n\n#### bot.canDigBlock(block)\n\nReturns whether `block` is diggable and within range.\n\n#### bot.recipesFor(itemType, metadata, minResultCount, craftingTable)\n\nReturns a list of `Recipe` instances that you could use to craft `itemType`\nwith `metadata`.\n\n * `itemType` - numerical item id of the thing you want to craft\n * `metadata` - the numerical metadata value of the item you want to craft\n   `null` matches any metadata.\n * `minResultCount` - based on your current inventory, any recipe from the\n   returned list will be able to produce this many items. `null` is an\n   alias for `1`.\n * `craftingTable` - a `Block` instance. If `null`, only recipes that can\n   be performed in your inventory window will be included in the list.\n\n#### bot.recipesAll(itemType, metadata, craftingTable)\n\nThe same as bot.recipesFor except that it does not check whether the bot has enough materials for the recipe.\n\n#### bot.nearestEntity(match = (entity) => { return true })\n\nReturn the nearest entity to the bot, matching the function (default to all entities). Return null if no entity is found.\n\nExample:\n```js\nconst cow = bot.nearestEntity(entity => entity.name.toLowerCase() === 'cow') // we use .toLowercase() because in 1.8 cow was capitalized, for newer versions that can be omitted\n```\n\n### Methods\n\n#### bot.end(reason)\n\nEnd the connection with the server.\n* `reason` - Optional string that states the reason of the end.\n\n#### bot.quit(reason)\n\nGracefully disconnect from the server with the given reason (defaults to 'disconnect.quitting').\n\n#### bot.tabComplete(str, [assumeCommand], [sendBlockInSight], [timeout])\n\nThis function returns a `Promise`, with `matches` as its argument upon completion.\n\nRequests chat completion from the server.\n * `str` - String to complete.\n * `assumeCommand` - Field sent to server, defaults to false.\n * `sendBlockInSight` - Field sent to server, defaults to true. Set this option to false if you want more performance.\n * `timeout` - Timeout in milliseconds, after which the function will return an empty array, defaults to 5000.\n\n#### bot.chat(message)\n\nSends a publicly broadcast chat message. Breaks up big messages into multiple chat messages as necessary.\n\n#### bot.whisper(username, message)\n\nShortcut for \"/tell <username>\". All split messages will be whispered to username.\n\n#### bot.chatAddPattern(pattern, chatType, description)\n\nDeprecated, use `addChatPattern` instead.\n\nAdds a regex pattern to the bot's chat matching. Useful for bukkit servers where the chat format changes a lot.\n * `pattern` - regular expression to match chat\n * `chatType` - the event the bot emits when the pattern matches. Eg: \"chat\" or \"whisper\"\n * 'description ' - Optional, describes what the pattern is for\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\n** this is an alias of `bot.addChatPatternSet(name, [pattern], chatPatternOptions)`\n\nmake an event that is called every time the pattern is matched to a message,\nthe event will be called `\"chat:name\"`, with name being the name passed\n* `name` - the name used to listen for the event\n* `pattern` - regular expression to match to messages received\n* `chatPatternOptions` - object\n  * `repeat` - defaults to true, whether to listen for this event after the first match\n  * `parse` - instead of returning the actual message that was matched, return the capture groups from the regex\n  * `deprecated` - (**unstable**) used by bot.chatAddPattern to keep compatibility, likely to be removed\n\nreturns a number which can be used with bot.removeChatPattern() to only delete this pattern\n\n- :eyes: cf. [examples/chat_parsing](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js#L17-L36)\n\n#### bot.addChatPatternSet(name, patterns, chatPatternOptions)\n\nmake an event that is called every time all patterns have been matched to messages,\nthe event will be called `\"chat:name\"`, with name being the name passed\n* `name` - the name used to listen for the event\n* `patterns` - array of regular expression to match to messages received\n* `chatPatternOptions` - object\n  * `repeat` - defaults to true, whether to listen for this event after the first match\n  * `parse` - instead of returning the actual message that was matched, return the capture groups from the regex\n\nreturns a number which can be used with bot.removeChatPattern() to only delete this patternset\n\n- :eyes: cf. [examples/chat_parsing](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js#L17-L36)\n\n#### bot.removeChatPattern(name)\n\nremoves a chat pattern(s)\n* `name` : string or number\n\nif name is a string, all patterns that have that name will be removed\nelse if name is a number, only that exact pattern will be removed\n\n#### bot.awaitMessage(...args)\n\npromise that is resolved when one of the messages passed as an arg is resolved\n\nExample:\n\n```js\nasync function wait () {\n  await bot.awaitMessage('<flatbot> hello world') // resolves on \"hello world\" in chat by flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world']) // resolves on \"hello\" or \"world\" in chat by flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world'], ['<flatbot> im', '<flatbot> batman']) // resolves on \"hello\" or \"world\" or \"im\" or \"batman\" in chat by flatbot\n  await bot.awaitMessage('<flatbot> hello', '<flatbot> world') // resolves on \"hello\" or \"world\" in chat by flatbot\n  await bot.awaitMessage(/<flatbot> (.+)/) // resolves on first message matching the regex\n}\n```\n\n#### bot.setSettings(options)\n\nSee the `bot.settings` property.\n\n#### bot.loadPlugin(plugin)\n\nInjects a Plugin. Does nothing if the plugin is already loaded.\n\n * `plugin` - function\n\n```js\nfunction somePlugin (bot, options) {\n  function someFunction () {\n    bot.chat('Yay!')\n  }\n\n  bot.myPlugin = {} // Good practice to namespace plugin API\n  bot.myPlugin.someFunction = someFunction\n}\n\nconst bot = mineflayer.createBot({})\nbot.loadPlugin(somePlugin)\nbot.once('login', function () {\n  bot.myPlugin.someFunction() // Yay!\n})\n```\n\n#### bot.loadPlugins(plugins)\n\nInjects plugins see `bot.loadPlugin`.\n * `plugins` - array of functions\n\n#### bot.hasPlugin(plugin)\n\nChecks if the given plugin is loaded (or scheduled to be loaded) on this bot.\n\n#### bot.sleep(bedBlock)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nSleep in a bed. `bedBlock` should be a `Block` instance which is a bed.\n\n#### bot.isABed(bedBlock)\n\nReturn true if `bedBlock` is a bed\n\n#### bot.wake()\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nGet out of bed.\n\n#### bot.setControlState(control, state)\n\nThis is the main method controlling the bot movements. It works similarly to pressing keys in minecraft.\nFor example forward with state true will make the bot move forward. Forward with state false will make the bot stop moving forward.\nYou may use bot.lookAt in conjunction with this to control movement. The jumper.js example shows how to use this.\n\n * `control` - one of ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n * `state` - `true` or `false`\n\n#### bot.getControlState(control)\n\nReturns true if a control state is toggled.\n\n* `control` - one of ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n\n#### bot.clearControlStates()\n\nSets all controls to off.\n\n#### bot.getExplosionDamages(entity, position, radius, [rawDamages])\n\nReturns how much damage will be done to the entity in a radius around the position of the explosion.\nIt will return `null` if the entity has no armor and rawDamages is not set to true, since the function can't calculate the damage with armor if there is no armor.\n\n* `entity` - Entity instance\n* `position` - [Vec3](https://github.com/andrewrk/node-vec3) instance\n* `radius` - the explosion radius as a number\n* `rawDamages` - optional, if true it ignores armor in the calculation\n\n#### bot.lookAt(point, [force])\n\nThis function returns a `Promise`, with `void` as its argument when you are looking at `point`.\n\n * `point` [Vec3](https://github.com/andrewrk/node-vec3) instance - tilts your head so that it is directly facing this point.\n * `force` - See `force` in `bot.look`\n\n#### bot.look(yaw, pitch, [force])\n\nThis function returns a `Promise`, with `void` as its argument called when you are looking at `yaw` and `pitch`.\n\nSet the direction your head is facing.\n\n * `yaw` - The number of radians to rotate around the vertical axis, starting\n   from due east. Counter clockwise.\n * `pitch` - Number of radians to point up or down. 0 means straight forward.\n   pi / 2 means straight up. -pi / 2 means straight down.\n * `force` - If present and true, skips the smooth server-side transition.\n   Specify this to true if you need the server to know exactly where you\n   are looking, such as for dropping items or shooting arrows. This is not\n   needed for client-side calculation such as walking direction.\n\n#### bot.updateSign(block, text, back = false)\n\nChanges the text on the sign. On Minecraft 1.20 and newer, a truthy `back` will try setting the text on the back of a sign (only visible if not attached to a wall).\n\n#### bot.equip(item, destination)\n\nThis function returns a `Promise`, with `void` as its argument when you have successfully equipped the item or when you learn that you have failed to equip the item.\n\nEquips an item from your inventory. If the argument `item` is of Instance `Item` equip will equip this specific item from its window slot. If the argument `item` is of type `number` equip will equip the first item found with that id searched by rising slot id (Hotbar is searched last. Armor, crafting, crafting result and off-hand slots are excluded).\n\n * `item` - `Item` instance or `number` for item id. See `window.items()`.\n * `destination`\n   - `\"hand\"` - `null` aliases to this\n   - `\"head\"`\n   - `\"torso\"`\n   - `\"legs\"`\n   - `\"feet\"`\n   - `\"off-hand\"` - when available\n\n#### bot.unequip(destination)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nRemove an article of equipment.\n\n#### bot.tossStack(item)\n\nThis function returns a `Promise`, with `void` as its argument when tossing is done.\n\n * `item` - the stack of items you wish to toss\n   truthy, you were not able to complete the toss.\n\n#### bot.toss(itemType, metadata, count)\n\nThis function returns a `Promise`, with `void` as its argument once tossing is complete.\n\n * `itemType` - numerical id of the item you wish to toss\n * `metadata` - metadata of the item you wish to toss. Use `null`\n   to match any metadata\n * `count` - how many you want to toss. `null` is an alias for `1`.\n\n#### bot.elytraFly()\n\nThis function returns a `Promise`, with `void` as its argument once activating\nelytra flight is complete. It will throw an Error if it fails.\n\n#### bot.dig(block, [forceLook = true], [digFace])\n\nThis function returns a `Promise`, with `void` as its argument when the block is broken or you are interrupted.\n\nBegin digging into `block` with the currently equipped item.\nSee also \"diggingCompleted\" and \"diggingAborted\" events.\n\nNote that once you begin digging into a block, you may not\ndig any other blocks until the block has been broken, or you call\n`bot.stopDigging()`.\n\n * `block` - the block to start digging into\n * `forceLook` - (optional) if true, look at the block and start mining instantly. If false, the bot will slowly turn to the block to mine. Additionally, this can be assigned to 'ignore' to prevent the bot from moving its head at all. Also, this can be assigned to 'raycast' to raycast from the bots head to place where the bot is looking.\n * `digFace` - (optional) Default is 'auto' looks at the center of the block and mines the top face. Can also be a vec3 vector\n of the face the bot should be looking at when digging the block. For example: ```vec3(0, 1, 0)``` when mining the top. Can also be 'raycast' raycast checks if there is a face visible by the bot and mines that face. Useful for servers with anti cheat.\n\nIf you call bot.dig twice before the first dig is finished, you will get a fatal 'diggingAborted' error.\n\n#### bot.stopDigging()\n\n#### bot.digTime(block)\n\nTells you how long it will take to dig the block, in milliseconds.\n\n#### bot.acceptResourcePack()\n\nAccepts resource pack.\n\n#### bot.denyResourcePack()\n\nDenies resource pack.\n\n#### bot.placeBlock(referenceBlock, faceVector)\n\nThis function returns a `Promise`, with `void` as its argument when the server confirms that the block has indeed been placed.\n\n * `referenceBlock` - the block you want to place a new block next to\n * `faceVector` - one of the six cardinal directions, such as `new Vec3(0, 1, 0)` for the top face,\n   indicating which face of the `referenceBlock` to place the block against.\n\nThe new block will be placed at `referenceBlock.position.plus(faceVector)`.\n\n#### bot.placeEntity(referenceBlock, faceVector)\n\nThis function returns a `Promise`, with `Entity` as its argument upon completion.\n\n * `referenceBlock` - the block you want to place the entity next to\n * `faceVector` - one of the six cardinal directions, such as `new Vec3(0, 1, 0)` for the top face,\n   indicating which face of the `referenceBlock` to place the block against.\n\nThe new block will be placed at `referenceBlock.position.plus(faceVector)`.\n\n#### bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nPunch a note block, open a door, etc.\n\n * `block` - the block to activate\n * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.\n * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.\n\n#### bot.activateEntity(entity)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nActivate an entity, useful for villager for example.\n\n * `entity` - the entity to activate\n\n#### bot.activateEntityAt(entity, position)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nActivate an entity at the given position, useful for armor stands.\n\n * `entity` - the entity to activate\n * `position` - the world position to click at\n\n#### bot.consume()\n\nThis function returns a `Promise`, with `void` as its argument when consume ends.\n\nEat / drink currently held item\n\n\n#### bot.fish()\n\nThis function returns a `Promise`, with `void` as its argument when fishing ends.\n\nUse fishing rod\n\n\n#### bot.activateItem(offHand=false)\n\nActivates the currently held item. This is how you eat, shoot bows, throw an\negg, activate firework rockets, etc.\n\nOptional parameter is `false` for main hand and `true` for off hand.\n\n#### bot.deactivateItem()\n\nDeactivates the currently held item. This is how you release an arrow, stop eating, etc.\n\n#### bot.useOn(targetEntity)\n\nUse the currently held item on an `Entity` instance. This is how you apply a saddle and\nuse shears.\n\n#### bot.attack(entity, swing = true)\n\nAttack a player or a mob.\n\n * `entity` is a type of entity. To get a specific entity use [bot.nearestEntity()](#botnearestentitymatch--entity---return-true-) or [bot.entities](#botentities).\n * `swing` Default to `true`. If false the bot does not swing its arm when attacking.\n\n#### bot.swingArm([hand], showHand)\n\nPlay an arm swing animation.\n\n * `hand` can take `left` or `right` which is the arm that is animated. Default: `right`\n * `showHand` is a boolean whether to add the hand to the packet, Default: `true`\n\n#### bot.mount(entity)\n\nMount a vehicle. To get back out, use `bot.dismount`.\n\n#### bot.dismount()\n\nDismounts from the vehicle you are in.\n\n#### bot.moveVehicle(left,forward)\n\nMoves the vehicle :\n\n * left can take -1 or 1 : -1 means right, 1 means left\n * forward can take -1 or 1 : -1 means backward, 1 means forward\n\nAll the direction are relative to where the bot is looking at\n\n#### bot.setQuickBarSlot(slot)\n\n * `slot` - 0-8 the quick bar slot to select.\n\n#### bot.craft(recipe, count, craftingTable)\n\nThis function returns a `Promise`, with `void` as its argument when the crafting is complete and your inventory is updated.\n\n * `recipe` - A `Recipe` instance. See `bot.recipesFor`.\n * `count` - How many times you wish to perform the operation.\n   If you want to craft planks into `8` sticks, you would set\n   `count` to `2`. `null` is an alias for `1`.\n * `craftingTable` - A `Block` instance, the crafting table you wish to\n   use. If the recipe does not require a crafting table, you may use\n   `null` for this argument.\n\n#### bot.writeBook(slot, pages)\n\nThis function returns a `Promise`, with `void` as its argument when the writing was successfully or an error occurred.\n\n * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).\n * `pages` is an array of strings represents the pages.\n\n#### bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)\nOpens a block container or entity.\n\n * `containerBlock` or `containerEntity` The block instance to open or the entity to open.\n * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.\n * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.\n\nReturns a promise on a `Container` instance which represents the container you are opening.\n\n#### bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)\n\nDeprecated. Same as `openContainer`\n\n#### bot.openFurnace(furnaceBlock)\n\nReturns a promise on a `Furnace` instance which represents the furnace you are opening.\n\n#### bot.openDispenser(dispenserBlock)\n\nDeprecated. Same as `openContainer`\n\n#### bot.openEnchantmentTable(enchantmentTableBlock)\n\nReturns a promise on an `EnchantmentTable` instance which represents the enchantment table\nyou are opening.\n\n#### bot.openAnvil(anvilBlock)\n\nReturns a promise on an `anvil` instance which represents the anvil you are opening.\n\n#### bot.openVillager(villagerEntity)\n\nReturns a promise on a `Villager` instance which represents the trading window you are opening.\nYou can listen to the `ready` event on this `Villager` to know when it's ready\n\n#### bot.trade(villagerInstance, tradeIndex, [times])\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nUses the open `villagerInstance` to trade.\n\n#### bot.setCommandBlock(pos, command, [options])\n\nSet a command block's properties at `pos`.\nExample `options` argument:\n```js\n{\n  mode: 2,\n  trackOutput: true,\n  conditional: false,\n  alwaysActive: true\n}\n```\noptions.mode can have 3 values: 0 (SEQUENCE), 1 (AUTO), 2 (REDSTONE)\nAll options attributes are false by default, except mode which is 2 (as to replicate the default command block in Minecraft).\n\n#### bot.supportFeature(name)\n\nThis can be used to check is a specific feature is available in the current Minecraft version. This is usually only required for handling version-specific functionality.\n\nThe list of available features can be found inside the [./lib/features.json](https://github.com/PrismarineJS/mineflayer/blob/master/lib/features.json) file.\n\n#### bot.waitForTicks(ticks)\n\nThis is a promise-based function that waits for a given number of in-game ticks to pass before continuing. This is useful for quick timers that need to function with specific timing, regardless of the given physics tick speed of the bot. This is similar to the standard Javascript setTimeout function, but runs on the physics timer of the bot specifically.\n\n#### bot.respawn()\n\nWhen `respawn` option is disabled, you can call this method manually to respawn.\n\n### Lower level inventory methods\n\nThese are lower level methods for the inventory, they can be useful sometimes but prefer the inventory methods presented above if you can.\n\n#### bot.clickWindow(slot, mouseButton, mode)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nmode support:\n  - stable:\n    - mouse clicks (0)\n\n  - experimental:\n    - shift clicks (1)\n    - number clicks (2)\n    - middle clicks (3)\n    - drop clicks (4)\n\n  - unimplemented:\n    - drag clicks (5)\n    - double clicks (6)\n\nClick on the current window. See details at https://minecraft.wiki/w/Protocol#Click_Container\n\nPrefer using bot.simpleClick.*\n\n#### bot.putSelectedItemRange(start, end, window, slot)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nPut the item at `slot` in the specified range.\n\n#### bot.putAway(slot)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nPut the item at `slot` in the inventory.\n\n#### bot.closeWindow(window)\n\nClose the `window`.\n\n#### bot.transfer(options)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nTransfer some kind of item from one range to an other. `options` is an object containing :\n\n * `window` : Optional. the window where the item will be moved\n * `itemType` : the type of the moved items\n * `metadata` : Optional. the metadata of the moved items\n * `sourceStart` and `sourceEnd` : the source range. `sourceEnd` is optional and will default to `sourceStart` + 1\n * `destStart` and `destEnd` : the dest Range. `destEnd` is optional and will default to `destStart` + 1\n * `count` : the amount of items to transfer. Default: `1`\n * `nbt` : nbt data of the item to transfer. Default: `nullish` (ignores nbt)\n\n#### bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)\n\nOpen a block, for example a chest, returns a promise on the opening `Window`.\n\n * `block` is the block the bot will open.\n * `direction` Optional defaults to `new Vec3(0, 1, 0)` (up). A vector off the direction the container block should be interacted with. Does nothing when a container entity is targeted.\n * `cursorPos` Optional defaults to `new Vec3(0.5, 0.5, 0.5)` (block center). The curos position when opening the block instance. This is send with the activate block packet. Does nothing when a container entity is targeted.\n\n#### bot.openEntity(entity)\n\nOpen an entity with an inventory, for example a villager, returns a promise on the opening `Window`.\n\n * `entity` is the entity the bot will open\n\n#### bot.moveSlotItem(sourceSlot, destSlot)\n\nThis function returns a `Promise`, with `void` as its argument upon completion.\n\nMove an item from `sourceSlot` to `destSlot` in the current window.\n\n#### bot.updateHeldItem()\n\nUpdate `bot.heldItem`.\n\n#### bot.getEquipmentDestSlot(destination)\n\nGets the inventory equipment slot id for the given equipment destination name.\n\nAvailable destinations are:\n* head\n* torso\n* legs\n* feet\n* hand\n* off-hand\n\n### bot.creative\n\nThis collection of apis is useful in creative mode.\nDetecting and changing gamemodes is not implemented here,\nbut it is assumed and often required that the bot be in creative mode for these features to work.\n\n#### bot.creative.setInventorySlot(slot, item)\n\nThis function returns a `Promise`, with `void` as its argument when gets fired when the server sets the slot.\n\nGives the bot the specified item in the specified inventory slot.\n\n * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).\n * `item` is a [prismarine-item](https://github.com/PrismarineJS/prismarine-item) instance specified with arbitrary metadata, nbtdata, etc.\n    If `item` is `null`, the item at the specified slot is deleted.\n\nIf this method changes anything, you can be notified via `bot.inventory.on(\"updateSlot\")`.\n\n#### bot.creative.clearSlot(slot)\n\nThis function returns a `Promise`, with `void` as its argument when gets fired when the server clears the slot.\n\nMakes the sets the item in the slot given to null.\n\n * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).\n\n#### bot.creative.clearInventory()\n\nThis function returns a `Promise`, with `void` as its argument when gets fired when the server clears the slot.\n\n#### bot.creative.flyTo(destination)\n\nThis function returns a `Promise`, with `void` as its argument when the bot arrives at the destination.\n\nCalls `startFlying()` and moves at a constant speed through 3d space in a straight line to the destination.\n`destination` is a `Vec3`, and often the `x` and `z` coordinates will end with `.5`.\nThis operation will not work if there is an obstacle in the way,\nso it is advised to fly very short distances at a time.\n\nThis method does not attempt any path finding.\nIt is expected that a path finding implementation will use this method to move < 2 blocks at a time.\n\nTo resume normal physics, call `stopFlying()`.\n\n#### bot.creative.startFlying()\n\nSets `bot.physics.gravity` to `0`.\nTo resume normal physics, call `stopFlying()`.\n\nThis method is useful if you want to hover while digging the ground below you.\nIt is not necessary to call this function before calling `flyTo()`.\n\nNote that while flying, `bot.entity.velocity` will not be accurate.\n\n#### bot.creative.stopFlying()\n\nRestores `bot.physics.gravity` to its original value.\n"
  },
  {
    "path": "docs/br/CONTRIBUTING_BR.md",
    "content": "# Contribuir\n\nO Mineflayer foi originalmente criado principalmente por [andrewrk](http://github.com/andrewrk), mas tem sido muito aprimorado e corrigido por muitos [contribuidores](https://github.com/andrewrk/mineflayer/graphs/contributors). Portanto, é importante saber a melhor maneira de contribuir para o Mineflayer.\n\n## Organização de Problemas\n\nTemos 3 etiquetas para 3 fases de organização de problemas:\n\n* Estágio 1: (Fase 1) criado por alguém novo no projeto, não sabemos se merece uma implementação / solução\n* Estágio 2: (Fase 2) ideia promissora, mas é necessário pensar mais sobre o assunto antes de implementá-lo\n* Estágio 3: (Fase 3) a ideia é muito precisa, só precisa ser programada\n\nLinks como https://github.com/PrismarineJS/mineflayer/issues?q=is%3Aopen+is%3Aissue+-label%3AStage1 podem ser usados como filtro para a fase 1 se você estiver procurando coisas prontas para serem contribuídas.\n\n## Criando Testes\nO Mineflayer possui dois tipos de testes:\n\n * [Testes internos](test/internalTest.js): testes feitos com um servidor simples criado com o node-minecraft-protocol\n * [Testes externos](test/externalTests/): testes feitos com um servidor Vanilla\n \nO objetivo desses testes é determinar automaticamente o que funciona e o que não funciona no Mineflayer, tornando mais fácil a correção de problemas.\n\n### Criando um Teste Externo\n\nPara criar um teste externo, basta criar um arquivo em [test/externalTests](test/externalTests).\n\nUm exemplo: [test/externalTests/digAndBuild.js](https://github.com/PrismarineJS/mineflayer/blob/master/test/externalTests/digAndBuild.js)\n\nEsse arquivo deve exportar uma função que retorna uma função ou um array de funções que recebem o objeto bot e um callback como parâmetros, e deve conter verificações para determinar se a função testada falhou.\n\n## Criando um Plugin de Terceiros\nO Mineflayer suporta plugins; qualquer pessoa pode criar um plugin que adiciona uma API de nível mais alto acima do Mineflayer.\n\nVários plugins de terceiros foram [criados](https://github.com/andrewrk/mineflayer#third-party-plugins).\n\nPara criar um novo plugin, você deve:\n\n1. Criar um novo repositório.\n2. No seu arquivo index.js, exportar uma função para inicializar o plugin com o argumento Mineflayer ([exemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L18)).\n3. Essa função deve retornar uma função para introduzir o plugin com o objeto bot ([exemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L23)).\n4. A partir dessa função, você pode adicionar mais funcionalidades ao bot ([exemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L32)).\n\nComo o objeto Mineflayer é passado como argumento, esse plugin de terceiros não deve depender do Mineflayer (não deve haver referência ao Mineflayer no package.json).\n\nVeja um [exemplo completo](https://github.com/andrewrk/mineflayer-navigate/tree/e24cb6a868ce64ae43bea2d035832c15ed01d301) aqui.\n\n## Relatando Bugs\nO Mineflayer funciona bem na maioria das situações, mas às vezes ainda pode ter bugs.\n\nAo encontrar um bug, é melhor relatar o erro fornecendo as seguintes informações:\n\n* O que você está tentando fazer (o objetivo em inglês).\n* O que você tentou (o código).\n* O que aconteceu.\n* O que você esperava que acontecesse.\n\n## Código do Mineflayer\nAqui estão algumas coisas a se considerar ao criar uma solicitação de pull (pull request) ou fazer um commit:\n\n### Tratamento de Erros\nNa maioria dos casos, o Mineflayer não deve quebrar ou travar o bot. Mesmo se algo der errado, o bot pode seguir uma rota alternativa para alcançar o objetivo.\n\nIsso significa que não devemos usar `throw new Error(\"erro\")`, mas sim passar o erro junto com o callback.\n\nPor exemplo:\n\n```js\nfunction myfunction (param1, callback) {\n  let toDo = 1\n  toDo = 2\n  if (toDo === 2) { // everything worked (todo está funcionado)\n    callback()\n  } else {\n    callback(new Error('something failed')) // (algo falhou)\n  }\n}\n```\n\nVeja outro exemplo no [código do Mineflayer](https://github.com/andrewrk/mineflayer/blob/a8736c4ea473cf1a609c5a29046c0cdad006d429/lib/plugins/bed.js#L10).\n\n### Atualizando a Documentação\nA tabela de conteúdo no arquivo docs/api.md é gerada com o Doctoc. Após atualizar o arquivo, você deve executar doctoc docs/api.md para atualizar a tabela de conteúdo.\n\nEsta documentação não é oficialmente mantida; para ver as informações mais recentes, consulte a documentação original: [unstable_api](../CONTRIBUTING.md)."
  },
  {
    "path": "docs/br/FAQ_BR.md",
    "content": "## Perguntas Frequentes\n\nEste documento de perguntas frequentes tem o objetivo de ajudar as pessoas com informações básicas.\n\n## Como ocultar erros?\n\nPara ocultar erros, você pode adicionar a opção `hideErrors: true` nas configurações ao criar o bot. Também é possível usar os seguintes eventos:\n\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n## Meu evento de chat não está sendo emitido em um servidor personalizado. Como posso resolver isso?\n\nAlguns servidores Spigot, em particular certos plugins, utilizam formatos personalizados de chat. Nesse caso, é necessário analisar esses formatos com expressões regulares personalizadas. Recomenda-se ler e modificar o arquivo [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) para que funcione com o plugin de chat específico do seu servidor. Você também pode consultar http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat para obter mais informações.\n\n## Como posso coletar informações de um plugin de chat personalizado?\n\nA maioria dos servidores de Minecraft possui plugins que enviam mensagens ao chat quando ocorrem eventos. Se a informação enviada for simples, você pode utilizar a solução mencionada anteriormente. No entanto, se as mensagens contêm muita informação em um único bloco de texto, outra opção é utilizar o evento `\"messagestr\"`, que permite analisar as mensagens de forma mais fácil.\n\n**Exemplo:**\n\nSuponha que a mensagem seja semelhante a esta:\n\n```\n(!) U9G ganhou o /jackpot e recebeu\n$26,418,402,450! Eles compraram 2,350,000 (76.32%) bilhetes\nde um total de 3,079,185 bilhetes vendidos!\n```\n\n```js\nconst regex = {\n  first: /\\(!\\) (.+) ganhou o \\/jackpot e recebeu +/,\n  second: /\\$(.+)! Eles compraram (.+) \\((.+)%\\) bilhetes do total de /,\n  third: /(.+) bilhetes vendidos!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n\n## Como posso enviar um comando?\n\nUsando `bot.chat()`.\n\n**Exmemplo:**\n```js\nbot.chat('/give @p diamond')\n```\n\n### É possível criar vários bots e controlá-los separadamente?\n\nVocê pode criar bots diferentes com a função `createBot` e executar ações diferentes para cada um deles. Dê uma olhada no arquivo `multiple.js` para mais informações.\n\n### Como faço para o bot largar todo o seu inventário?\n\nVocê pode usar a função `bot.inventory.items()` para obter uma matriz dos itens no inventário do bot. Você pode criar uma função recursiva para largar cada item usando `bot.toss()`. Veja um exemplo [aqui](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9).\n\n### Como vejo os pacotes que foram enviados/recebidos?\n\nVocê pode ativar o modo de depuração. Para obter mais informações, consulte [este link](https://github.com/PrismarineJS/mineflayer/blob/master/docs/br/README_BR.md#depuraci%C3%B3n).\n\n### Quero evitar desconexões devido a lag no servidor, como posso fazer isso?\n\nUma maneira de evitar desconexões devido à latência no servidor é aumentar o valor na opção `checkTimeoutInterval` (por exemplo, `300*1000`, que representa 5 minutos, em vez do valor padrão, que é 30 segundos). Se mesmo assim você continuar sendo desconectado do servidor, você pode se reconectar automaticamente usando este exemplo [aqui](https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js).\n\n### Como posso obter a descrição/texto de um item?\n\nVocê pode usar a propriedade `item.nbt`. É recomendável utilizar a biblioteca `prismarine-nbt`. O método `nbt.simplify()` pode ser útil para simplificar a obtenção da descrição de um item.\n\n**Exemplo:**\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### Como posso enviar uma mensagem do console para o servidor?\n\nVocê pode usar uma biblioteca como `repl` para ler o que você escreve no console e usar `bot.chat()` para enviá-lo para o servidor. Você pode encontrar um exemplo [aqui](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js).\n\n### Ao criar um plugin, como posso especificar outro plugin como dependência?\n\nNa função `inject()` do seu plugin, você pode executar a função `bot.loadPlugin()` para carregar esse plugin. Se o plugin já estiver carregado anteriormente, nada acontecerá.\n\nNota: a ordem em que os plugins são carregados é dinâmica; você nunca deve chamar outro plugin em sua função `inject()`.\n\n### Como posso usar um proxy SOCKS5?\n\nNas opções de `mineflayer.createBot(opções)`, remova o seu `host` das opções e coloque as informações necessárias nas variáveis `PROXY_IP`, `PROXY_PORT`, `PROXY_USERNAME`, `PROXY_PASSWORD`, `MC_SERVER_IP` e `MC_SERVER_PORT`. Em seguida, adicione o seguinte ao seu objeto de opções:\n\n```js\nconnect: (client) => {\n  socks.createConnection({\n    proxy: {\n      host: PROXY_IP,\n      port: PROXY_PORT,\n      type: 5,\n      userId: PROXY_USERNAME,\n      password: PROXY_PASSWORD\n    },\n    command: 'connect',\n    destination: {\n      host: MC_SERVER_IP,\n      port: MC_SERVER_PORT\n    }\n  }, (err, info) => {\n    if (err) {\n      console.log(err)\n      return\n    }\n    client.setSocket(info.socket)\n    client.emit('connect')\n  })\n}\n```\n\n# Erros Comuns\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\nIsso ocorre quando você fornece uma versão incorreta ao mineflayer, ou o mineflayer detecta a versão errada.\n\n### `TypeError: Cannot read property '?' of undefined`\n\nVocê pode estar tentando acessar uma propriedade do bot que ainda não existe; tente acessar a propriedade após o evento `spawn`.\n\n### `SyntaxError: Unexpected token '?'`\n\nAtualize a versão do seu Node.js.\n\n### O bot não consegue quebrar/colocar blocos ou abrir baús\n\nVerifique se a proteção do spawn não está impedindo o bot de realizar a ação.\n\nEsta documentação não é oficial. Para as informações mais atualizadas, consulte a documentação original: [FAQ](../FAQ.md)."
  },
  {
    "path": "docs/br/README_BR.md",
    "content": "# Mineflayer\n\n[![NPM version](https://badge.fury.io/js/mineflayer.svg)](http://badge.fury.io/js/mineflayer)\n[![Build Status](https://github.com/PrismarineJS/mineflayer/workflows/CI/badge.svg)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)\n[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)\n[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)\n\n[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n\n| <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) | <sub>BR</sub> [Português](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|-----------------|-----------------|\n\nCrie bots para o Minecraft com uma API JavaScript poderosa, estável e de alto nível.\n\nPrimeira vez usando o Node.js? Você pode querer começar com o tutorial [tutorial](../tutorial.md)\n\n## Recursos\n\n * Suporta Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 e 1.20.\n * Conhecimento e rastreamento de entidades.\n * Conhecimento de blocos. Você pode consultar o mundo ao seu redor em milissegundos para encontrar qualquer bloco.\n * Física e movimento - lida com todas as caixas delimitadoras.\n * Ataque a entidades e uso de veículos.\n * Gerenciamento de inventário.\n * Criação, baús, dispensadores, mesas de encantamento.\n * Escavação e construção.\n * Diversas funcionalidades, como saber sua saúde e se está chovendo.\n * Ativação de blocos e uso de itens.\n * Chat.\n\n### Planos para o Futuro\n- Dê uma olhada em nossos [projetos atuais](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects)\n\n## Instalação\n- Primeiro, instale o Node.js >= 18 a partir do [nodejs.org](https://nodejs.org/)\n\n`npm install mineflayer`\n\n## Documentação\n\n| Link | Descrição |\n|---|---|\n| [tutorial](../tutorial.md) | Comece com o Node.js e o Mineflayer |\n| [FAQ_BR.md](FAQ_BR.md) | Alguma dúvida? Confira isso |\n| [api_br.md](api_br.md) [unstable_api_br.md](unstable_api_br.md) | Toda a documentação da API |\n| [history.md](../history.md) | Histórico de mudanças do Mineflayer |\n| [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Todos os exemplos do Mineflayer |\n\n## Contribuições\n\nPor favor, leia [CONTRIBUTING_BR.md](CONTRIBUTING_BR.md) e [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute)\n\n## Uso\n\n**Vídeos**\n\nVocê pode encontrar um tutorial que explica o processo de começar um bot [aqui](https://www.youtube.com/watch?v=ltWosy4Z0Kw) (em inglês).\n\nSe você quiser aprender mais, pode verificar [aqui,](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) os códigos usados nos vídeos [aqui](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials)\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Começando**\n\nSe não for especificada uma versão, a versão do servidor será detectada automaticamente. Se nenhuma forma de autenticação for especificada, o login da Mojang será usado automaticamente.\n\n### Exemplo: echo\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // IP do servidor de Minecraft\n  username: 'email@example.com', // Nome de usuário da conta, e-mail se for premium\n  password: '12345678' // Senha para servidores premium\n  // port: 25565, // Altere apenas se for um servidor que não usa a porta padrão (25565)\n  // version: false, // Altere apenas se for necessário uma versão específica\n  // auth: 'mojang', // Altere apenas se você tiver uma conta Microsoft (nesse caso, seria auth: 'microsoft')\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// Imprimir erros e o motivo do kick se você for expulso:\nbot.on('kicked', (reason, loggedIn) => console.log(reason, loggedIn))\nbot.on('error', err => console.log(err))\n```\n\n### Veja o que o seu bot faz\n\nGraças ao projeto [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer), você pode visualizar em uma guia do seu navegador o que o seu bot está fazendo.\n\nTudo o que você precisa fazer é executar `npm install prismarine-viewer` e adicionar o seguinte ao seu bot:\n\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // a porta é onde o plug-in será hospedado no navegador, e firstPerson é para escolher se você deseja a visualização em primeira pessoa ou não\n})\n```\n\nE você poderá ver uma representação *ao vivo* como esta:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### Exemplos Ruins\n\n| Exemplo | Descrição |\n|---|---|\n| [viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | Visualize o que seu bot vê no jogo |\n| [pathfinder](https://github.com/Karang/mineflayer-pathfinder/blob/master/examples/test.js) | Faça seu bot se locomover automaticamente para qualquer localização |\n| [chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | Aprenda a usar baús, fornos, dispensadores e mesas de encantamento |\n| [digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | Aprenda como criar um bot que pode quebrar blocos |\n| [discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | Conecte um bot Discord com um bot Mineflayer |\n| [jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | Aprenda a se mover, pular, usar veículos e atacar entidades próximas |\n| [ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | Exibe todas as mensagens do chat no console com suas cores correspondentes |\n| [guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Crie um bot que defenda uma área predefinida de mobs |\n| [multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Use um arquivo de texto com contas para criar bots |\n\nMais exemplos na pasta de [exemplos](https://github.com/PrismarineJS/mineflayer/tree/master/examples)\n\n### Módulos\n\nA maioria do desenvolvimento está ocorrendo em pequenos módulos npm que são usados pelo Mineflayer.\n\n#### O Caminho do Node™\n\n> \"Quando os aplicativos são bem feitos, eles são apenas o resíduo realmente específico da aplicação que não pode ser tão facilmente abstraído. Todos os componentes legais e reutilizáveis sublimam no GitHub e no npm, onde todos podem colaborar para avançar a comunidade.\" — substack de [\"como eu escrevo módulos\"](https://gist.github.com/substack/5075355)\n\n#### Módulos\nEstes são os principais módulos que compõem o Mineflayer:\n\n| Módulo | Descrição |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Analisa e cria pacotes do Minecraft, autenticação e criptografia.\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | Módulo independente de linguagem que fornece dados do Minecraft para clientes, servidores e bibliotecas.\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) | Motor de física para entidades do Minecraft\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | Representa um pedaço do Minecraft\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | Usa vetores 3D com testes sólidos\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | Representa um bloco e suas informações associadas no Minecraft\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | Analisador de mensagens de chat do Minecraft (retirado do Mineflayer)\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Biblioteca Node.js para interagir com o sistema de autenticação da Mojang conhecido como Yggdrasil.\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | Implementação principal dos mundos do Minecraft para o Prismarine\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | Representa as interfaces do Minecraft\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | Representa um item e suas informações associadas no Minecraft\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | Analisador de NBT para node-minecraft-protocol\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | Representa receitas de crafting do Minecraft\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | Representa um bioma e suas informações associadas no Minecraft\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) | Representa uma entidade e suas informações associadas no Minecraft\n\n### Depuração\n\nVocê pode habilitar a depuração do protocolo usando a variável de ambiente `DEBUG`:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nNo Windows:\n```\nset DEBUG=minecraft-protocol\nnode seu_arquivo.js\n```\n\n## Plugins de Terceiros\n\nMineflayer tem a capacidade de instalar plugins; qualquer pessoa pode criar um plugin que adiciona uma API de alto nível ao Mineflayer.\n\nOs mais atualizados e úteis são:\n\n* [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - algoritmo de busca A* avançado com muitos recursos configuráveis\n* [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - visualizador de chunks na web\n* [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - visualizador de inventário na web\n* [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - API para comportamentos mais complexos\n* [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - gerenciamento automático de armaduras\n* [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - API rápida e simples para coletar blocos.\n* [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Painel de controle para um bot do Mineflayer\n* [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - API simples para PVP e PVE.\n* [auto-eat](https://github.com/LINKdiscordd/mineflayer-auto-eat) - Plugin para comer automaticamente.\n* [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - Plugin com uma API de alto nível para selecionar automaticamente a melhor arma/ferramenta.\n* [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - Plugin para mirar automaticamente com arcos.\n\nMas também dê uma olhada em:\n\n* [radar](https://github.com/andrewrk/mineflayer-radar/) - interface de radar na web usando canvas e socket.io [Demo no Youtube](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n* [blockfinder](https://github.com/Darthfett/mineflayer-blockFinder) - encontra blocos no mundo tridimensional\n* [scaffold](https://github.com/andrewrk/mineflayer-scaffold) - ir para um destino específico mesmo que seja necessário construir ou quebrar blocos para alcançá-lo [Demo no Youtube](http://youtu.be/jkg6psMUSE0)\n* [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - autenticação automática por chat\n* [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - determina quem e/ou o que é responsável por causar dano a outra entidade\n* [tps](https://github.com/SiebeDW/mineflayer-tps) - obter o tps atual (tps processado)\n* [panorama](https://github.com/IceTank/mineflayer-panorama) - tirar imagens panorâmicas do seu mundo\n\n## Projetos que Usam o Mineflayer\n\n* [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - construindo uma escada espiral](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - replicando uma estrutura](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n* [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n* [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualiza o que o bot está fazendo usando voxel.js\n* [JonnyD/Skynet](https://github.com/JonnyD/Skynet) - registra a atividade de um jogador em uma API online\n* [MinecraftChat](https://github.com/rom1504/MinecraftChat) (última versão de código aberto, criada por AlexKvazos) - Interface de chat na web para o Minecraft <https://minecraftchat.net/>\n* [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - bot com uma interface limpa. Feito com Node-Webkit. http://bot.ezcha.net/\n* [Chaoscraft](https://github.com/schematical/chaoscraft) - bot de Minecraft que usa algoritmos genéticos, veja [seus vídeos no YouTube](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n* [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - ponte para o Telegram, feita com Mineflayer e Telegraf.\n* [e centenas mais](https://github.com/PrismarineJS/mineflayer/network/dependents) - todos os projetos que usam o Mineflayer e foram detectados pelo GitHub.\n\n## Testes\n\n### Executar Todos os Testes\n\nBasta executar:\n\n```bash\nnpm test\n```\n\n### Executar Testes para uma Versão Específica do Minecraft\n\nExecute\n\n```bash\nnpm test -- -g <versão>\n```\n\nonde `<versão>` é uma versão do Minecraft, como `1.12`, `1.15.2`...\n\n### Executar um Teste Específico\n\nExecute\n```bash\nnpm test -- -g <nome_do_teste>\n```\n\nonde `<nome_do_teste>` é o nome do teste que você deseja executar, como `bed`, `useChests`, `rayTrace`...\n\n## Licença\n\n[MIT](../../LICENSE)\n\nEsta documentação não é oficialmente mantida. Para ver as últimas atualizações, consulte a documentação original: [unstable_api](../README.md)\n"
  },
  {
    "path": "docs/br/api_br.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Tabela de conteúdos** *gerada com [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API](#api)\n  - [Enums](#enums)\n    - [minecraft-data](#minecraft-data)\n    - [mcdata.blocks](#mcdatablocks)\n    - [mcdata.items](#mcdataitems)\n    - [mcdata.materials](#mcdatamaterials)\n    - [mcdata.recipes](#mcdatarecipes)\n    - [mcdata.instruments](#mcdatainstruments)\n    - [mcdata.biomes](#mcdatabiomes)\n    - [mcdata.entities](#mcdataentities)\n  - [Clases](#clases)\n    - [vec3](#vec3)\n    - [mineflayer.Location](#mineflayerlocation)\n    - [Entity](#entity)\n    - [Block](#block)\n    - [Biome](#biome)\n    - [Item](#item)\n    - [windows.Window (base class)](#windowswindow-base-class)\n      - [window.deposit(itemType, metadata, count, [callback])](#windowdeposititemtype-metadata-count-callback)\n      - [window.withdraw(itemType, metadata, count, [callback])](#windowwithdrawitemtype-metadata-count-callback)\n      - [window.close()](#windowclose)\n    - [Recipe](#recipe)\n    - [mineflayer.Container](#mineflayercontainer)\n    - [mineflayer.Furnace](#mineflayerfurnace)\n      - [furnace \"update\"](#furnace-update)\n      - [furnace.takeInput([callback])](#furnacetakeinputcallback)\n      - [furnace.takeFuel([callback])](#furnacetakefuelcallback)\n      - [furnace.takeOutput([callback])](#furnacetakeoutputcallback)\n      - [furnace.putInput(itemType, metadata, count, [cb])](#furnaceputinputitemtype-metadata-count-cb)\n      - [furnace.putFuel(itemType, metadata, count, [cb])](#furnaceputfuelitemtype-metadata-count-cb)\n      - [furnace.inputItem()](#furnaceinputitem)\n      - [furnace.fuelItem()](#furnacefuelitem)\n      - [furnace.outputItem()](#furnaceoutputitem)\n      - [furnace.fuel](#furnacefuel)\n      - [furnace.progress](#furnaceprogress)\n    - [mineflayer.EnchantmentTable](#mineflayerenchantmenttable)\n      - [enchantmentTable \"ready\"](#enchantmenttable-ready)\n      - [enchantmentTable.targetItem()](#enchantmenttabletargetitem)\n      - [enchantmentTable.xpseed](#enchantmenttablexpseed)\n      - [enchantmentTable.enchantments](#enchantmenttableenchantments)\n      - [enchantmentTable.enchant(choice, [callback])](#enchantmenttableenchantchoice-callback)\n      - [enchantmentTable.takeTargetItem([callback])](#enchantmenttabletaketargetitemcallback)\n      - [enchantmentTable.putTargetItem(item, [callback])](#enchantmenttableputtargetitemitem-callback)\n      - [enchantmentTable.putLapis(item, [callback])](#enchantmenttableputlapisitem-callback)\n    - [mineflayer.anvil](#mineflayeranvil)\n      - [anvil.combine(itemOne, itemTwo[, name, callback])](#anvilcombineitemone-itemtwo-name-callback)\n      - [anvil.combine(item[, name, callback])](#anvilcombineitem-name-callback)\n      - [villager \"ready\"](#villager-ready)\n      - [villager.trades](#villagertrades)\n      - [villager.trade(tradeIndex, [times], [cb])](#villagertradetradeindex-times-cb)\n    - [mineflayer.ScoreBoard](#mineflayerscoreboard)\n      - [ScoreBoard.name](#scoreboardname)\n      - [ScoreBoard.title](#scoreboardtitle)\n      - [ScoreBoard.itemsMap](#scoreboarditemsmap)\n      - [ScoreBoard.items](#scoreboarditems)\n    - [mineflayer.BossBar](#mineflayerbossbar)\n      - [BossBar.title](#bossbartitle)\n      - [BossBar.health](#bossbarhealth)\n      - [BossBar.dividers](#bossbardividers)\n      - [BossBar.entityUUID](#bossbarentityuuid)\n      - [BossBar.shouldDarkenSky](#bossbarshoulddarkensky)\n      - [BossBar.isDragonBar](#bossbarisdragonbar)\n      - [BossBar.createFog](#bossbarcreatefog)\n      - [BossBar.color](#bossbarcolor)\n  - [Bot](#bot)\n    - [mineflayer.createBot(options)](#mineflayercreatebotoptions)\n    - [Properties](#properties)\n      - [bot.world](#botworld)\n        - [world \"blockUpdate\" (oldBlock, newBlock)](#world-blockupdate-oldblock-newblock)\n        - [world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#world-blockupdatex-y-z-oldblock-newblock)\n      - [bot.entity](#botentity)\n      - [bot.entities](#botentities)\n      - [bot.username](#botusername)\n      - [bot.spawnPoint](#botspawnpoint)\n      - [bot.heldItem](#bothelditem)\n      - [bot.game.levelType](#botgameleveltype)\n      - [bot.game.dimension](#botgamedimension)\n      - [bot.game.difficulty](#botgamedifficulty)\n      - [bot.game.gameMode](#botgamegamemode)\n      - [bot.game.hardcore](#botgamehardcore)\n      - [bot.game.maxPlayers](#botgamemaxplayers)\n      - [bot.game.serverBrand](#botgameserverbrand)\n    - [bot.physicsEnabled](#botphysicsenabled)\n    - [bot.player](#botplayer)\n      - [bot.players](#botplayers)\n      - [bot.isRaining](#botisraining)\n      - [bot.rainState](#botrainstate)\n      - [bot.thunderState](#botthunderstate)\n      - [bot.chatPatterns](#botchatpatterns)\n      - [bot.settings.chat](#botsettingschat)\n      - [bot.settings.colorsEnabled](#botsettingscolorsenabled)\n      - [bot.settings.viewDistance](#botsettingsviewdistance)\n      - [bot.settings.difficulty](#botsettingsdifficulty)\n      - [bot.settings.skinParts](#botsettingsskinparts)\n        - [bot.settings.skinParts.showCape](#botsettingsskinpartsshowcape)\n        - [bot.settings.skinParts.showJacket](#botsettingsskinpartsshowjacket)\n        - [bot.settings.skinParts.showLeftSleeve](#botsettingsskinpartsshowleftsleeve)\n        - [bot.settings.skinParts.showRightSleeve](#botsettingsskinpartsshowrightsleeve)\n        - [bot.settings.skinParts.showLeftPants](#botsettingsskinpartsshowleftpants)\n        - [bot.settings.skinParts.showRightPants](#botsettingsskinpartsshowrightpants)\n        - [bot.settings.skinParts.showHat](#botsettingsskinpartsshowhat)\n      - [bot.experience.level](#botexperiencelevel)\n      - [bot.experience.points](#botexperiencepoints)\n      - [bot.experience.progress](#botexperienceprogress)\n      - [bot.health](#bothealth)\n      - [bot.food](#botfood)\n      - [bot.foodSaturation](#botfoodsaturation)\n      - [bot.oxygenLevel](#botoxygenlevel)\n      - [bot.physics](#botphysics)\n      - [bot.simpleClick.leftMouse (slot)](#botsimpleclickleftmouse-slot)\n      - [bot.simpleClick.rightMouse (slot)](#botsimpleclickrightmouse-slot)\n      - [bot.time.doDaylightCycle](#bottimedodaylightcycle)\n      - [bot.time.bigTime](#bottimebigtime)\n      - [bot.time.time](#bottimetime)\n      - [bot.time.timeOfDay](#bottimetimeofday)\n      - [bot.time.day](#bottimeday)\n      - [bot.time.isDay](#bottimeisday)\n      - [bot.time.moonPhase](#bottimemoonphase)\n      - [bot.time.bigAge](#bottimebigage)\n      - [bot.time.age](#bottimeage)\n      - [bot.quickBarSlot](#botquickbarslot)\n      - [bot.inventory](#botinventory)\n      - [bot.targetDigBlock](#bottargetdigblock)\n      - [bot.isSleeping](#botissleeping)\n      - [bot.scoreboards](#botscoreboards)\n      - [bot.scoreboard](#botscoreboard)\n      - [bot.controlState](#botcontrolstate)\n    - [Events](#events)\n      - [\"chat\" (username, message, translate, jsonMsg, matches)](#chat-username-message-translate-jsonmsg-matches)\n      - [\"whisper\" (username, message, translate, jsonMsg, matches)](#whisper-username-message-translate-jsonmsg-matches)\n      - [\"actionBar\" (jsonMsg)](#actionbar-jsonmsg)\n      - [\"message\" (jsonMsg, position)](#message-jsonmsg-position)\n      - [\"messagestr\" (message, messagePosition, jsonMsg)](#messagestr-message-messageposition-jsonmsg)\n      - [\"inject_allowed\"](#inject_allowed)\n      - [\"login\"](#login)\n      - [\"spawn\"](#spawn)\n      - [\"respawn\"](#respawn)\n      - [\"game\"](#game)\n      - [\"resourcePack\" (url, hash)](#resourcepack-url-hash)\n      - [\"title\" (title, type)](#title-title-type)\n      - [\"rain\"](#rain)\n      - [\"weatherUpdate\"](#weatherupdate)\n      - [\"time\"](#time)\n      - [\"kicked\" (reason, loggedIn)](#kicked-reason-loggedin)\n      - [\"end\"](#end)\n      - [\"error\" (err)](#error-err)\n      - [\"spawnReset\"](#spawnreset)\n      - [\"death\"](#death)\n      - [\"health\"](#health)\n      - [\"breath\"](#breath)\n      - [\"entitySwingArm\" (entity)](#entityswingarm-entity)\n      - [\"entityHurt\" (entity)](#entityhurt-entity)\n      - [\"entityDead\" (entity)](#entitydead-entity)\n      - [\"entityTaming\" (entity)](#entitytaming-entity)\n      - [\"entityTamed\" (entity)](#entitytamed-entity)\n      - [\"entityShakingOffWater\" (entity)](#entityshakingoffwater-entity)\n      - [\"entityEatingGrass\" (entity)](#entityeatinggrass-entity)\n      - [\"entityWake\" (entity)](#entitywake-entity)\n      - [\"entityEat\" (entity)](#entityeat-entity)\n      - [\"entityCriticalEffect\" (entity)](#entitycriticaleffect-entity)\n      - [\"entityMagicCriticalEffect\" (entity)](#entitymagiccriticaleffect-entity)\n      - [\"entityCrouch\" (entity)](#entitycrouch-entity)\n      - [\"entityUncrouch\" (entity)](#entityuncrouch-entity)\n      - [\"entityEquip\" (entity)](#entityequip-entity)\n      - [\"entitySleep\" (entity)](#entitysleep-entity)\n      - [\"entitySpawn\" (entity)](#entityspawn-entity)\n      - [\"itemDrop\" (entity)](#itemdrop-entity)\n      - [\"playerCollect\" (collector, collected)](#playercollect-collector-collected)\n      - [\"entityGone\" (entity)](#entitygone-entity)\n      - [\"entityMoved\" (entity)](#entitymoved-entity)\n      - [\"entityDetach\" (entity, vehicle)](#entitydetach-entity-vehicle)\n      - [\"entityAttach\" (entity, vehicle)](#entityattach-entity-vehicle)\n      - [\"entityUpdate\" (entity)](#entityupdate-entity)\n      - [\"entityEffect\" (entity, effect)](#entityeffect-entity-effect)\n      - [\"entityEffectEnd\" (entity, effect)](#entityeffectend-entity-effect)\n      - [\"playerJoined\" (player)](#playerjoined-player)\n      - [\"playerUpdated\" (player)](#playerupdated-player)\n      - [\"playerLeft\" (player)](#playerleft-player)\n      - [\"blockUpdate\" (oldBlock, newBlock)](#blockupdate-oldblock-newblock)\n      - [\"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#blockupdatex-y-z-oldblock-newblock)\n      - [\"blockPlaced\" (oldBlock, newBlock)](#blockplaced-oldblock-newblock)\n      - [\"chunkColumnLoad\" (point)](#chunkcolumnload-point)\n      - [\"chunkColumnUnload\" (point)](#chunkcolumnunload-point)\n      - [\"soundEffectHeard\" (soundName, position, volume, pitch)](#soundeffectheard-soundname-position-volume-pitch)\n      - [\"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)](#hardcodedsoundeffectheard-soundid-soundcategory-position-volume-pitch)\n      - [\"noteHeard\" (block, instrument, pitch)](#noteheard-block-instrument-pitch)\n      - [\"pistonMove\" (block, isPulling, direction)](#pistonmove-block-ispulling-direction)\n      - [\"chestLidMove\" (block, isOpen, block2)](#chestlidmove-block-isopen-block2)\n      - [\"blockBreakProgressObserved\" (block, destroyStage)](#blockbreakprogressobserved-block-destroystage)\n      - [\"blockBreakProgressEnd\" (block)](#blockbreakprogressend-block)\n      - [\"diggingCompleted\" (block)](#diggingcompleted-block)\n      - [\"diggingAborted\" (block)](#diggingaborted-block)\n      - [\"move\"](#move)\n      - [\"forcedMove\"](#forcedmove)\n      - [\"mount\"](#mount)\n      - [\"dismount\" (vehicle)](#dismount-vehicle)\n      - [\"windowOpen\" (window)](#windowopen-window)\n      - [\"windowClose\" (window)](#windowclose-window)\n      - [\"sleep\"](#sleep)\n      - [\"wake\"](#wake)\n      - [\"experience\"](#experience)\n      - [\"scoreboardCreated\" (scoreboard)](#scoreboardcreated-scoreboard)\n      - [\"scoreboardDeleted\" (scoreboard)](#scoreboarddeleted-scoreboard)\n      - [\"scoreboardTitleChanged\" (scoreboard)](#scoreboardtitlechanged-scoreboard)\n      - [\"scoreUpdated\" (scoreboard, item)](#scoreupdated-scoreboard-item)\n      - [\"scoreRemoved\" (scoreboard, item)](#scoreremoved-scoreboard-item)\n      - [\"scoreboardPosition\" (position, scoreboard)](#scoreboardposition-position-scoreboard)\n      - [\"bossBarCreated\" (bossBar)](#bossbarcreated-bossbar)\n      - [\"bossBarDeleted\" (bossBar)](#bossbardeleted-bossbar)\n      - [\"bossBarUpdated\" (bossBar)](#bossbarupdated-bossbar)\n      - [\"heldItemChanged\" (heldItem)](#helditemchanged-helditem)\n      - [\"physicsTick\" ()](#physicstick-)\n      - [\"chat:name\" (matches)](#chatname-matches)\n    - [Functions](#functions)\n      - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)\n      - [bot.waitForChunksToLoad(cb)](#botwaitforchunkstoloadcb)\n      - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)\n      - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)\n      - [bot.canSeeBlock(block)](#botcanseeblockblock)\n      - [bot.findBlocks(options)](#botfindblocksoptions)\n      - [bot.findBlock(options)](#botfindblockoptions)\n      - [bot.canDigBlock(block)](#botcandigblockblock)\n      - [bot.recipesFor(itemType, metadata, minResultCount, craftingTable)](#botrecipesforitemtype-metadata-minresultcount-craftingtable)\n      - [bot.recipesAll(itemType, metadata, craftingTable)](#botrecipesallitemtype-metadata-craftingtable)\n      - [bot.nearestEntity(match = (entity) => { return true })](#botnearestentitymatch--entity---return-true-)\n    - [Methods](#methods)\n      - [bot.end()](#botend)\n      - [bot.quit(reason)](#botquitreason)\n      - [bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])](#bottabcompletestr-cb-assumecommand-sendblockinsight)\n      - [bot.chat(message)](#botchatmessage)\n      - [bot.whisper(username, message)](#botwhisperusername-message)\n      - [bot.chatAddPattern(pattern, chatType, description)](#botchataddpatternpattern-chattype-description)\n      - [bot.addChatPattern(name, pattern, chatPatternOptions)](#botaddchatpatternname-pattern-chatpatternoptions)\n      - [bot.addChatPatternSet(name, patterns, chatPatternOptions)](#botaddchatpatternsetname-patterns-chatpatternoptions)\n      - [bot.removeChatPattern(name)](#botremovechatpatternname)\n      - [bot.awaitMessage(...args)](#botawaitmessageargs)\n      - [bot.setSettings(options)](#botsetsettingsoptions)\n      - [bot.loadPlugin(plugin)](#botloadpluginplugin)\n      - [bot.loadPlugins(plugins)](#botloadpluginsplugins)\n      - [bot.hasPlugin(plugin)](#bothaspluginplugin)\n      - [bot.sleep(bedBlock, [cb])](#botsleepbedblock-cb)\n      - [bot.isABed(bedBlock)](#botisabedbedblock)\n      - [bot.wake([cb])](#botwakecb)\n      - [bot.setControlState(control, state)](#botsetcontrolstatecontrol-state)\n      - [bot.getControlState(control)](#botgetcontrolstatecontrol)\n      - [bot.clearControlStates()](#botclearcontrolstates)\n      - [bot.lookAt(point, [force], [callback])](#botlookatpoint-force-callback)\n      - [bot.look(yaw, pitch, [force], [callback])](#botlookyaw-pitch-force-callback)\n      - [bot.updateSign(block, text)](#botupdatesignblock-text)\n      - [bot.equip(item, destination, [callback])](#botequipitem-destination-callback)\n      - [bot.unequip(destination, [callback])](#botunequipdestination-callback)\n      - [bot.tossStack(item, [callback])](#bottossstackitem-callback)\n      - [bot.toss(itemType, metadata, count, [callback])](#bottossitemtype-metadata-count-callback)\n      - [bot.dig(block, [forceLook = true], [digFace], [callback])](#botdigblock-forcelook--true-digface-callback)\n      - [bot.stopDigging()](#botstopdigging)\n      - [bot.digTime(block)](#botdigtimeblock)\n      - [bot.acceptResourcePack()](#botacceptresourcepack)\n      - [bot.denyResourcePack()](#botdenyresourcepack)\n      - [bot.placeBlock(referenceBlock, faceVector, cb)](#botplaceblockreferenceblock-facevector-cb)\n      - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)\n      - [bot.activateBlock(block, [callback])](#botactivateblockblock-callback)\n      - [bot.activateEntity(entity, [callback])](#botactivateentityentity-callback)\n      - [bot.activateEntityAt(entity, position, [callback])](#botactivateentityatentity-position-callback)\n      - [bot.consume(callback)](#botconsumecallback)\n      - [bot.fish(callback)](#botfishcallback)\n      - [bot.activateItem(offHand=false)](#botactivateitemoffhandfalse)\n      - [bot.deactivateItem()](#botdeactivateitem)\n      - [bot.useOn(targetEntity)](#botuseontargetentity)\n      - [bot.attack(entity)](#botattackentity)\n      - [bot.swingArm([hand], showHand)](#botswingarmhand-showhand)\n      - [bot.mount(entity)](#botmountentity)\n      - [bot.dismount()](#botdismount)\n      - [bot.moveVehicle(left,forward)](#botmovevehicleleftforward)\n      - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)\n      - [bot.craft(recipe, count, craftingTable, [callback])](#botcraftrecipe-count-craftingtable-callback)\n      - [bot.writeBook(slot, pages, [callback])](#botwritebookslot-pages-callback)\n      - [bot.openContainer(containerBlock or containerEntity)](#botopencontainercontainerblock-or-containerentity)\n      - [bot.openChest(chestBlock or minecartchestEntity)](#botopenchestchestblock-or-minecartchestentity)\n      - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)\n      - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)\n      - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)\n      - [bot.openAnvil(anvilBlock)](#botopenanvilanvilblock)\n      - [bot.openVillager(villagerEntity)](#botopenvillagervillagerentity)\n      - [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n      - [bot.setCommandBlock(pos, command, [options])](#botsetcommandblockpos-command-options)\n      - [bot.supportFeature(name)](#botsupportfeaturename)\n      - [bot.waitForTicks(ticks)](#botwaitforticksticks)\n    - [Lower level inventory methods](#lower-level-inventory-methods)\n      - [bot.clickWindow(slot, mouseButton, mode, cb)](#botclickwindowslot-mousebutton-mode-cb)\n      - [bot.putSelectedItemRange(start, end, window, slot)](#botputselecteditemrangestart-end-window-slot)\n      - [bot.putAway(slot)](#botputawayslot)\n      - [bot.closeWindow(window)](#botclosewindowwindow)\n      - [bot.transfer(options, cb)](#bottransferoptions-cb)\n      - [bot.openBlock(block)](#botopenblockblock)\n      - [bot.openEntity(entity)](#botopenentityentity)\n      - [bot.moveSlotItem(sourceSlot, destSlot, cb)](#botmoveslotitemsourceslot-destslot-cb)\n      - [bot.updateHeldItem()](#botupdatehelditem)\n      - [bot.getEquipmentDestSlot(destination)](#botgetequipmentdestslotdestination)\n    - [bot.creative](#botcreative)\n      - [bot.creative.setInventorySlot(slot, item, [callback])](#botcreativesetinventoryslotslot-item-callback)\n      - [bot.creative.flyTo(destination, [cb])](#botcreativeflytodestination-cb)\n      - [bot.creative.startFlying()](#botcreativestartflying)\n      - [bot.creative.stopFlying()](#botcreativestopflying)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API\n\n## Enums\n\nEsses enums estão armazenados em um projeto independente da linguagem [minecraft-data](https://github.com/PrismarineJS/minecraft-data) e acessados pelo [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\n### minecraft-data\nOs dados estão disponíveis no módulo [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data)\n\n`require('minecraft-data')(bot.version)` te dá acesso a eles.\n\n### mcdata.blocks\nBlocos ordenados por ID.\n\n### mcdata.items\nItens ordenados por ID.\n\n### mcdata.materials\nA chave é o material. O valor é um objeto com a chave sendo o ID da ferramenta e o valor é o multiplicador de eficiência.\n\n### mcdata.recipes\nReceitas ordenadas por ID.\n\n### mcdata.instruments\nFerramentas ordenadas por ID.\n\n### mcdata.biomes\nBiomas ordenados por ID.\n\n### mcdata.entities\nEntidades ordenadas por ID.\n\n## Clases\n\n### vec3\n\nVeja [andrewrk/node-vec3](https://github.com/andrewrk/node-vec3)\n\nTodos os pontos no mineflayer são instâncias dessa classe.\n\n- x - sul\n- y - para cima\n- z - oeste\n\nFunções e métodos que requerem um ponto aceitam instâncias `Vec3`, uma matriz com 3 valores e um objeto com as propriedades `x`, `y` e `z`.\n\n### mineflayer.Location\n\n### Entity\n\nEntidades representam jogadores, mobs e objetos. Elas são emitidas em muitos eventos, mas você pode acessar sua própria entidade com `bot.entity`.\nVeja [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)\n\n### Block\n\nVeja [prismarine-block](https://github.com/PrismarineJS/prismarine-block)\n\nAlém disso, `block.blockEntity` é um campo adicional com os dados da entidade do bloco em formato de `Object`.\n```js\n// sign.blockEntity\n{\n  x: -53,\n  y: 88,\n  z: 66,\n  id: 'minecraft:sign', // 'Sign' in 1.10\n  Text1: { toString: Function }, // ChatMessage object\n  Text2: { toString: Function }, // ChatMessage object\n  Text3: { toString: Function }, // ChatMessage object\n  Text4: { toString: Function } // ChatMessage object\n}\n```\n\n### Biome\n\nVeja [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome)\n\n### Item\n\nVeja [prismarine-item](https://github.com/PrismarineJS/prismarine-item)\n\n### windows.Window (base class)\n\nVeja [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows)\n\n#### window.deposit(itemType, metadata, count, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento ao ser concluída.\n\n- `itemType` - ID numérico do item.\n- `metadata` - valor numérico. `null` significa que qualquer valor coincide.\n- `count` - quantos itens devem ser depositados. `null` é um alias para 1.\n- `callback(err)` - (opcional) - executado ao ser concluída.\n\n#### window.withdraw(itemType, metadata, count, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento ao ser concluída.\n\n * `itemType` - ID numérico do item\n * `metadata` - valor numérico. `null` significa que qualquer valor é correspondente.\n * `count` - quantos itens devem ser retirados. `null` é um alias para 1.\n * `callback(err)` - (opcional) - executado ao finalizar\n\n#### window.close()\n\nFecha a interface/janela.\n\n### Recipe\n\nVeja [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe).\n\n### mineflayer.Container\n\nEstende windows.Window para baús, dispensadores, etc...\nVeja `bot.openContainer(blocoDoBaú ou entidadeDeCarrinhoDeMinério)`.\n\n### mineflayer.Furnace\n\nEstende windows.Window para fornalhas, fundidores, etc...\nVeja `bot.openFurnace(blocoDaFornalha)`.\n\n#### Furnace \"update\"\n\nÉ emitido quando `fornalha.combustível` e/ou `fornalha.progresso` são atualizados.\n\n#### furnace.takeInput([callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `callback(err, item)`\n\n#### furnace.takeFuel([callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `callback(err, item)`\n\n#### furnace.takeOutput([callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `callback(err, item)`\n\n#### furnace.putInput(itemType, metadata, count, [cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n#### furnace.putFuel(itemType, metadata, count, [cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n#### furnace.inputItem()\n\nRetorna uma instância `Item` que é o item de entrada.\n\n#### furnace.fuelItem()\n\nRetorna uma instância `Item` que é o combustível.\n\n#### furnace.outputItem()\n\nRetorna uma instância `Item` que é o item de saída.\n\n#### furnace.fuel\n\nQuanto combustível resta, variando de 0 a 1.\n\n#### furnace.progress\n\nQuanto o item está avançado no processo, variando de 0 a 1.\n\n### mineflayer.EnchantmentTable\n\nEstende windows.Window para mesas de encantamento.\nVeja `bot.openEnchantmentTable(blocoDaMesaDeEncantamento)`.\n\n#### enchantmentTable \"ready\"\n\nÉ emitido quando `mesaDeEncantamento.encantamentos` está completo e você pode escolher um encantamento executando `mesaDeEncantamento.encantar(escolha)`.\n\n#### enchantmentTable.targetItem()\n\nRetorna os itens de entrada e saída.\n\n#### enchantmentTable.xpseed\n\nA semente de XP de 16 bits enviada pelo servidor.\n\n#### enchantmentTable.enchantments\n\nArray de comprimento 3 com três encantamentos que você pode escolher.\n`level` pode ser -1 se o servidor ainda não enviou os dados.\n\nParece com:\n\n```js\n[\n  {\n    level: 3\n  },\n  {\n    level: 4\n  },\n  {\n    level: 9\n  }\n]\n```\n\n#### enchantmentTable.enchant(choice, [callback])\n\nEsta função também retorna uma `Promise`, com o `item` como argumento quando concluída.\n\n* `escolha` - [0-2], o índice do encantamento que você deseja escolher.\n* `callback(err, item)` - (opcional) executado ao finalizar.\n\n#### enchantmentTable.takeTargetItem([callback])\n\nEsta função também retorna uma `Promise`, com o `item` como argumento quando concluída.\n\n* `callback(err, item)`\n\n#### enchantmentTable.putTargetItem(item, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n* `callback(err)`\n\n#### enchantmentTable.putLapis(item, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n* `callback(err)`\n\n### mineflayer.anvil\n\nEstende a janela de janelas para bigornas.\nVeja `bot.openAnvil(anvilBlock)`.\n\n#### anvil.combine(itemUm, itemDois[, nome, callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n* `callback(err)` - para usar o retorno de chamada, o nome deve estar vazio ('').\n\n#### anvil.combine(item[, nome, callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n* `callback(err)`\n\n#### villager \"ready\"\n\nÉ emitido quando `vilarejo.trocas` foram carregadas.\n\n#### villager.trades\n\nArray de negociações\n\nSemelhante a:\n\n```js\n[\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: true,\n    secondaryInput: Item,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  }\n]\n```\n\n#### villager.trade(tradeIndex, [times], [cb])\nÉ o mesmo que [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n\n### mineflayer.ScoreBoard\n\n#### ScoreBoard.name\n\nNome do placar.\n\n#### ScoreBoard.title\n\nO título do placar (nem sempre é o mesmo que o nome).\n\n#### ScoreBoard.itemsMap\n\nUm objeto com todos os itens do placar nele.\n```js\n{\n  wvffle: { name: 'wvffle', value: 3 },\n  dzikoysk: { name: 'dzikoysk', value: 6 }\n}\n```\n\n#### ScoreBoard.items\n\nUma matriz com todos os itens no placar.\n```js\n[\n  { name: 'dzikoysk', value: 6 },\n  { name: 'wvffle', value: 3 }\n]\n```\n\n### mineflayer.BossBar\n\n#### BossBar.title\n\nTítulo da barra de vida do chefe, instância de ChatMessage\n\n#### BossBar.health\n\nPorcentagem da vida do chefe, de `0` a `1`\n\n#### BossBar.dividers\n\nNúmero de divisores na barra, pode ser `0`, `6`, `10`, `12` ou `20`\n\n#### BossBar.entityUUID\n\nUUID da entidade do chefe\n\n#### BossBar.shouldDarkenSky\n\nDetermina se o céu deve escurecer ou não\n\n#### BossBar.isDragonBar\n\nDetermina se a barra é a barra de vida do dragão\n\n#### BossBar.createFog\n\nDetermina se a barra cria neblina ou não\n\n#### BossBar.color\n\nDetermina el color de la barra entre `pink`, `blue`, `red`, `green`, `yellow`, `purple` y `white` (`rosa`, `azul`, `rojo`, `verde`, `amarillo`, `morado` y `blanco`)\n\n## Bot\n\n### mineflayer.createBot(options)\n\nCrie e retorne uma instância da classe Bot.\n\n`options` é um objeto que contém propriedades opcionais:\n * username : (usuário) o valor padrão é 'Player'\n * port : (porta) o valor padrão é 25565\n * password : (senha) pode ser omitida (se os tokens também forem omitidos, tentará conectar no modo offline)\n * host : (ip) o valor padrão é localhost\n * version : se omitido, tentará determinar automaticamente a versão. Por exemplo: \"1.12.2\"\n * auth : (autenticação) o valor padrão é 'mojang', também pode ser 'microsoft'\n * clientToken : gerado se uma senha for fornecida\n * accessToken : gerado se uma senha for fornecida\n * logErrors : o valor padrão é true, retém erros e os imprime\n * hideErrors : o valor padrão é true, para ocultar erros (mesmo se logErrors for true)\n * keepAlive : envia pacotes keepAlive: o valor padrão é true\n * checkTimeoutInterval : o valor padrão é `30*1000` (30s), verifica se o pacote keepAlive foi recebido neste período, desconecta o bot se não for recebido.\n * loadInternalPlugins : o valor padrão é true\n * storageBuilder : uma função opcional, que recebe a versão e o nome do mundo (worldName) como argumentos e retorna uma instância de algo com a mesma API que prismarine-provider-anvil. Será usado para salvar o mundo.\n * client : uma instância de node-minecraft-protocol, se não for especificado, o mineflayer criará seu próprio cliente. Isso é útil para usar o mineflayer por meio de um proxy de vários clientes ou para um cliente vanilla e um cliente mineflayer.\n * plugins : objeto: o valor padrão é {}\n   - pluginName : false : não carrega o plugin interno com esse nome, por exemplo, `pluginName`\n   - pluginName : true : carrega o plugin interno com esse nome, por exemplo, `pluginName`, mesmo se loadInternalPlugins estiver definido como false\n   - pluginName : função para introduzir : carrega um plugin de terceiros (externo), anulando o plugin interno com o mesmo nome, por exemplo, `pluginName`\n * physicsEnabled : o valor padrão é true, se o bot deve ser afetado pela física, pode ser modificado através de bot.physicsEnabled\n * [chat](#bot.settings.chat)\n * [colorsEnabled](#bot.settings.colorsEnabled)\n * [viewDistance](#bot.settings.viewDistance)\n * [difficulty](#bot.settings.difficulty)\n * [skinParts](#bot.settings.skinParts)\n * chatLengthLimit : o valor máximo de caracteres que podem ser enviados com uma única mensagem. Se não for especificado, será 100 em versões anteriores à 1.11 e 256 na 1.11 e posteriores.\n\n### Properties\n\n#### bot.world\n\nUma representação sincronizada do mundo. Confira a documentação em http://github.com/PrismarineJS/prismarine-world\n\n#### world \"blockUpdate\" (oldBlock, newBlock)\n\nÉ emitido quando um bloco é atualizado. Retorna o bloco antigo `oldBlock` e o novo bloco `newBlock`.\n\nObservação: `oldBlock` pode ser `null`.\n\n#### world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\nÉ emitido quando um bloco em uma coordenada é atualizado. Retorna o bloco antigo `oldBlock` e o novo bloco `newBlock`.\n\nObservação: `oldBlock` pode ser `null`.\n\n\n#### bot.entity\n\nSua própria entidade. Consulte `Entity`.\n\n#### bot.entities\n\nTodas as entidades próximas. Este objeto é um mapa de entityId (id da entidade) para entity (entidade).\n\n#### bot.username\n\nUse isso para descobrir seu próprio nome.\n\n#### bot.spawnPoint\n\nCoordenadas do ponto de spawn, para onde todas as bússolas apontam.\n\n#### bot.heldItem\n\nO item na mão do bot, apresentado como uma instância [prismarine-item](https://github.com/PrismarineJS/prismarine-item) especificado com seus metadados, dados NBT, etc.\n\n#### bot.game.levelType\n\nTipo do nível do jogo.\n\n#### bot.game.dimension\n\nTipo da dimensão.\n\n#### bot.game.difficulty\n\nTipo de dificuldade do jogo.\n\n#### bot.game.gameMode\n\nModo de jogo do bot.\n\n#### bot.game.hardcore\n\nSe o jogo está no modo hardcore ou não.\n\n#### bot.game.maxPlayers\n\nO número máximo de jogadores no jogo.\n\n#### bot.game.serverBrand\n\nA marca do servidor.\n\n#### bot.physicsEnabled\n\nSe a física deve ser habilitada, o valor padrão é true.\n\n#### bot.player\n\nObjeto do jogador do bot\n```js\n{\n  username: 'player',\n  displayName: { toString: Function }, // Objeto ChatMessage.\n  gamemode: 0,\n  ping: 28,\n  entity: entity // nulo se você estiver muito longe (fora da zona renderizada)\n}\n```\n\n#### bot.players\n\nMapa dos nomes dos jogadores no jogo.\n\n#### bot.isRaining\n\nDetermina se está chovendo.\n\n#### bot.rainState\n\nUm número indicando o nível de chuva atual. Se não estiver chovendo, este valor será 0. Quando começa a chover, o valor aumenta gradualmente para 1. E quando para de chover, diminui gradualmente para 0.\n\nCada vez que `bot.rainState` muda, o evento \"weatherUpdate\" é emitido.\n\n#### bot.thunderState\n\nUm número indicando o nível de tempestade de raios atual. Se não houver tempestade, este valor será 0. Quando começa uma tempestade, o valor aumenta gradualmente para 1. E quando a tempestade para, diminui gradualmente para 0.\n\nCada vez que `bot.thunderState` muda, o evento \"weatherUpdate\" é emitido.\n\nIsso é semelhante ao `bot.rainState`, mas para tempestades de raios. Para tempestades de raios, `bot.rainState` e `bot.thunderState` mudarão.\n\n#### bot.chatPatterns\n\nIsso é uma matriz de objetos de padrões, no seguinte formato:\n{ /regex/, \"chattype\", \"descrição\")\n * /regex/ - um padrão regex, deve ter pelo menos dois grupos de captura.\n * 'chattype' - o tipo de chat que deve corresponder, pode ser \"chat\" (conversa) ou \"whisper\" (sussurro), ou qualquer outro.\n * 'descrição' - descrição do padrão, opcional.\n\n#### bot.settings.chat\n\nOpções:\n\n * `enabled` (ativado) (padrão)\n * `commandsOnly` (apenasComandos)\n * `disabled` (desativado)\n\n#### bot.settings.colorsEnabled\n\nSeu valor padrão é verdadeiro, se deve receber códigos de cor do servidor.\n\n#### bot.settings.viewDistance\n\nOpções:\n * `far` (distante) (padrão)\n * `normal`\n * `short` (curto)\n * `tiny` (minúsculo)\n\n#### bot.settings.difficulty\n\nO mesmo que em server.properties.\n\n#### bot.settings.skinParts\n\nEsses booleanos controlam se as partes externas da skin do jogador devem ser visíveis.\n\n##### bot.settings.skinParts.showCape\n\nSe você tem uma capa, pode desativá-la alterando isso para falso.\n\n##### bot.settings.skinParts.showJacket\n\nSe a parte externa do peito deve ser mostrada.\n\n##### bot.settings.skinParts.showLeftSleeve\n\nSe a parte externa do braço esquerdo deve ser mostrada.\n\n##### bot.settings.skinParts.showRightSleeve\n\nSe a parte externa do braço direito deve ser mostrada.\n\n##### bot.settings.skinParts.showLeftPants\n\nSe a parte externa da perna esquerda deve ser mostrada.\n\n##### bot.settings.skinParts.showRightPants\n\nSe a parte externa da perna direita deve ser mostrada.\n\n##### bot.settings.skinParts.showHat\n\nSe a parte externa da cabeça deve ser mostrada.\n\n#### bot.experience.level\n\nO nível de experiência do bot.\n\n#### bot.experience.points\n\nTotal de pontos de experiência do bot.\n\n#### bot.experience.progress\n\nEntre 0 e 1 - a quantidade que falta para atingir o próximo nível.\n\n#### bot.health\n\nNúmeros entre 0 e 20 representando o número de metades de coração.\n\n#### bot.food\n\nNúmeros de 0 a 20 representando o número de metades de coxas de frango.\n\n#### bot.foodSaturation\n\nA saturação atua como um \"suprimento\" de comida. Se a saturação for maior que 0, o nível de comida não diminuirá. Os jogadores que entram no jogo têm automaticamente uma saturação de 5,0. Comer aumenta a saturação e o nível de comida.\n\n#### bot.oxygenLevel\n\nNúmero de 0 a 20 representando o número de metades de bolhas do nível de oxigênio.\n\n#### bot.physics\n\nModifique esses números para alterar a gravidade, velocidade de salto, velocidade terminal, etc. Faça isso por sua própria conta e risco.\n\n#### bot.simpleClick.leftMouse (slot)\n\nAbstração de `bot.clickWindow(slot, 0, 0)`\n\n#### bot.simpleClick.rightMouse (slot)\n\nAbstração de `bot.clickWindow(slot, 1, 0)`\n\n#### bot.time.doDaylightCycle\n\nSe o gamerule doDaylightCycle está ativado ou desativado.\n\n#### bot.time.bigTime\n\nO número total de ticks desde o dia 0.\n\nEste valor é do tipo BigInt e é muito preciso, mesmo com valores muito grandes (mais de 2^51 - 1 ticks).\n\n#### bot.time.time\n\nO número total de ticks desde o dia 0.\n\nComo o limite de números em JavaScript é 2^51 - 1, bot.time.time é menos preciso em valores mais altos que esse limite. Portanto, é recomendado o uso de bot.time.bigTime. Sendo realista, provavelmente você nunca terá que usar bot.time.bigTime, já que ele naturalmente alcançará 2^51 - 1 ticks após cerca de 14.280.821 anos reais.\n\n#### bot.time.timeOfDay\n\nHora do dia, em ticks.\n\nA hora é baseada em ticks, onde 20 ticks ocorrem a cada segundo. Há 24.000 ticks em um dia, o que torna os dias em Minecraft exatamente 20 minutos. A hora do dia é baseada no módulo 24.000 do timestamp. 0 é o amanhecer, 6.000 é o meio-dia, 12.000 é o anoitecer e 18.000 é a meia-noite.\n\n#### bot.time.day\n\nDia do mundo.\n\n#### bot.time.isDay\n\nSe é dia ou não.\n\nBaseado no horário atual estar entre 0 e 13000 ticks (dia + pôr do sol).\n\n#### bot.time.moonPhase\n\nFase da lua.\n\nDe 0 a 7, onde 0 é lua cheia.\n\n#### bot.time.bigAge\n\nIdade do mundo, em ticks.\n\nEste valor é do tipo BigInt e é preciso mesmo em valores muito altos (mais de 2^51 - 1 ticks).\n\n#### bot.time.age\n\nIdade do mundo, em ticks.\n\nComo o limite de números em JavaScript é 2^51 - 1, bot.time.age é menos preciso em valores mais altos que esse limite. Portanto, é recomendado o uso de bot.time.bigAge. Sendo realista, provavelmente você nunca terá que usar bot.time.bigAge, já que ele naturalmente alcançará 2^51 - 1 ticks após cerca de 14.280.821 anos reais.\n\n#### bot.quickBarSlot\n\nQual slot está selecionado na barra de acesso rápido (0 - 8).\n\n#### bot.inventory\n\nUma instância de janela (interface) representando seu inventário.\n\n#### bot.targetDigBlock\n\nO bloco que você está quebrando no momento, ou `null`.\n\n#### bot.isSleeping\n\nBooleano representando se você está dormindo ou não.\n\n#### bot.scoreboards\n\nTodos os placares que o bot conhece em um objeto com o formato nome do placar -> placar.\n\n#### bot.scoreboard\n\nTodos os placares que o bot conhece em um objeto com o formato exibição de placar -> placar.\n- `belowName` - placar exibido abaixo do nome\n- `sidebar` - placar exibido na barra lateral\n- `list` - placar exibido na lista\n- `0-18` - entradas definidas no protocolo\n\n#### bot.controlState\n\nUm objeto que contém os estados de controle principais: ['frente', 'trás', 'esquerda', 'direita', 'pular', 'correr', 'agachar'].\n\nEsses valores podem ser usados em bot.setControlState.\n\n### Events\n\n#### \"chat\" (username, message, translate, jsonMsg, matches)\n\nSomente é emitido quando um jogador conversa publicamente.\n- `username` - o jogador que enviou a mensagem (compare com `bot.username` para ignorar suas próprias mensagens).\n- `message` - mensagem sem códigos de cores.\n- `translate` - tipo de mensagem no chat. Nulo para a maioria das mensagens do Bukkit.\n- `jsonMsg` - mensagem JSON não modificada do servidor.\n- `matches` - matriz de correspondências retornadas pelas expressões regulares. Pode ser nulo.\n\n#### \"whisper\" (username, message, translate, jsonMsg, matches)\n\nSomente é emitido quando um jogador conversa com você em particular (sussurro).\n- `username` - o jogador que enviou a mensagem.\n- `message` - mensagem sem códigos de cores.\n- `translate` - tipo de mensagem no chat. Nulo para a maioria das mensagens do Bukkit.\n- `jsonMsg` - mensagem JSON não modificada do servidor.\n- `matches` - matriz de correspondências retornadas pelas expressões regulares. Pode ser nulo.\n\n#### \"actionBar\" (jsonMsg)\n\nEste evento é emitido para cada mensagem do servidor que aparece na barra de ação.\n\n * `jsonMsg` - mensagem JSON não modificada do servidor\n\n#### \"message\" (jsonMsg, position)\n\nEste evento é emitido para cada mensagem do servidor, incluindo chats.\n\n * `jsonMsg` - mensagem JSON não modificada do servidor\n\n * `position` - (>= 1.8.1): a posição da mensagem de chat pode ser\n   * chat\n   * sistema\n   * informações_do_jogo\n\n#### \"messagestr\" (message, messagePosition, jsonMsg)\n\nSimilar a \"message\", mas converte a mensagem JSON em uma string antes de ser emitida.\n\n#### \"inject_allowed\"\n\nEste evento é emitido quando o arquivo index é carregado. Você pode carregar mcData ou os plugins aqui, mas é melhor esperar pelo evento \"spawn\".\n\n#### \"login\"\n\nÉ emitido após se registrar no servidor. No entanto, provavelmente você desejará aguardar o evento \"spawn\" antes de fazer qualquer coisa.\n\n#### \"spawn\"\n\nÉ emitido quando você se registra e aparece no mundo ou quando ressurge após a morte. Normalmente, este é o evento que você deseja receber antes de fazer qualquer coisa no servidor.\n\n#### \"respawn\"\n\nÉ emitido ao mudar de dimensões ou imediatamente antes de aparecer. Normalmente, você vai querer ignorar esse evento e esperar até que o evento \"spawn\" seja emitido.\n\n#### \"game\"\n\nÉ emitido quando o servidor altera algumas de suas propriedades.\n\n#### \"resourcePack\" (url, hash)\n\nÉ emitido quando o servidor envia um pacote de recursos.\n\n#### \"title\" (title, type)\n\nÉ emitido quando o servidor exibe um título.\n\n * `title` - texto do título\n * `type` - tipo do título \"subtitle\" ou \"title\"\n\n#### \"rain\"\n\nÉ emitido quando começa a chover ou quando para de chover. Se estiver chovendo quando você entrar no servidor, este evento será emitido.\n\n#### \"weatherUpdate\"\n\nÉ emitido quando o estado de chuva (`bot.thunderState` ou `bot.rainState`) muda. Se estiver chovendo quando você entrar no servidor, este evento será emitido.\n\n#### \"time\"\n\nÉ emitido quando o servidor altera ou atualiza a hora. Veja `bot.time`.\n\n#### \"kicked\" (reason, loggedIn)\n\nÉ emitido quando o bot é expulso do servidor. `motivo` é uma mensagem de chat com o motivo da expulsão. `loggedIn` será `true` se o cliente já estava conectado quando foi expulso e `false` se o cliente foi expulso durante o processo de registro.\n\n#### \"end\"\n\nÉ emitido quando você não está mais conectado ao servidor.\n\n#### \"error\" (err)\n\nÉ emitido quando ocorre um erro.\n\n#### \"spawnReset\"\n\nÉ emitido quando você não pode mais ressurgir em sua cama e seu ponto de ressurgimento é redefinido.\n\n#### \"death\"\n\nÉ emitido ao morrer.\n\n#### \"health\"\n\nÉ emitido quando sua vida ou nível de comida mudam.\n\n#### \"breath\"\n\nÉ emitido quando seu nível de oxigênio muda.\n\n#### \"entitySwingArm\" (entity)\n\nÉ emitido quando uma entidade move o braço.\n\n#### \"entityHurt\" (entity)\n\nÉ emitido quando uma entidade se machuca.\n\n#### \"entityDead\" (entity)\n\nÉ emitido quando uma entidade morre.\n\n#### \"entityTaming\" (entity)\n\nÉ emitido quando uma entidade está sendo domesticada.\n\n#### \"entityTamed\" (entity)\n\nÉ emitido quando uma entidade é domesticada.\n\n#### \"entityShakingOffWater\" (entity)\n\nÉ emitido quando uma entidade se sacode para se secar (por exemplo, lobos).\n\n#### \"entityEatingGrass\" (entity)\n\nÉ emitido quando uma entidade come grama.\n\n#### \"entityWake\" (entity)\n\nÉ emitido quando uma entidade acorda.\n\n#### \"entityEat\" (entity)\n\nÉ emitido quando uma entidade come.\n\n#### \"entityCriticalEffect\" (entity)\n\nÉ emitido quando uma entidade recebe um ataque crítico.\n\n#### \"entityMagicCriticalEffect\" (entity)\n\nÉ emitido quando uma entidade recebe um ataque crítico com poções.\n\n#### \"entityCrouch\" (entity)\n\nÉ emitido quando uma entidade se agacha.\n\n#### \"entityUncrouch\" (entity)\n\nÉ emitido quando uma entidade para de se agachar.\n\n#### \"entityEquip\" (entity)\n\nÉ emitido quando uma entidade equipa algo.\n\n#### \"entitySleep\" (entity)\n\nÉ emitido quando uma entidade dorme.\n\n#### \"entitySpawn\" (entity)\n\nÉ emitido quando uma entidade aparece.\n\n#### \"itemDrop\" (entity)\n\nÉ emitido quando uma entidade solta itens (os itens também são entidades).\n\n#### \"playerCollect\" (collector, collected)\n\nÉ emitido quando uma entidade coleta um item.\n\n * `coletor` - a entidade que coletou o item.\n * `coletado` - a entidade que foi coletada (o item).\n\n#### \"entityGone\" (entity)\n\nÉ emitido quando uma entidade desaparece (morre, despawna).\n\n#### \"entityMoved\" (entity)\n\nÉ emitido quando uma entidade se move.\n\n#### \"entityDetach\" (entity, vehicle)\n\nÉ emitido quando uma entidade sai de um veículo.\n\n#### \"entityAttach\" (entity, vehicle)\n\nÉ emitido quando uma entidade entra em um veículo.\n\n * `entidade` - a entidade que entrou\n * `veículo` - a entidade do veículo (carrinho, cavalo)\n\n#### \"entityUpdate\" (entity)\n\nÉ emitido quando uma entidade atualiza uma de suas propriedades.\n\n#### \"entityEffect\" (entity, effect)\n\nÉ emitido quando uma entidade recebe um efeito.\n\n#### \"entityEffectEnd\" (entity, effect)\n\nÉ emitido quando um efeito em uma entidade termina.\n\n#### \"playerJoined\" (player)\n\nÉ emitido quando um jogador entra no servidor.\n\n#### \"playerUpdated\" (player)\n\nÉ emitido quando um jogador atualiza uma de suas propriedades.\n\n#### \"playerLeft\" (player)\n\nÉ emitido quando um jogador se desconecta do servidor.\n\n#### \"blockUpdate\" (oldBlock, newBlock)\n\n(É melhor usar este evento a partir de bot.world em vez de bot diretamente) É emitido quando um bloco é atualizado. Retorna `blocoAntigo` e `blocoNovo`.\n\nObservação: `blocoAntigo` pode ser `null`.\n\n#### \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\n(É melhor usar este evento a partir de bot.world em vez de bot diretamente) É emitido quando um bloco em uma coordenada específica é atualizado. Retorna `blocoAntigo` e `blocoNovo`.\n\nObservação: `blocoAntigo` pode ser `null`.\n\n#### \"blockPlaced\" (oldBlock, newBlock)\n\nÉ emitido quando o bot coloca um bloco. Retorna `blocoAntigo` e `blocoNovo`.\n\nObservação: `blocoAntigo` pode ser `null`.\n\n#### \"chunkColumnLoad\" (point)\n\nÉ emitido quando um chunk é carregado.\n\n#### \"chunkColumnUnload\" (point)\n\nÉ emitido quando um chunk é descarregado. `ponto` é a coordenada do canto do chunk com os valores x, y e z mais baixos.\n\n#### \"soundEffectHeard\" (soundName, position, volume, pitch)\n\nIsso ocorre quando o cliente ouve um efeito sonoro com um nome específico.\n\n * `nomeSom`: nome do efeito sonoro\n * `posição`: uma instância Vec3 indicando o ponto de onde o som originou\n * `volume`: volume em ponto flutuante, 1.0 é 100%\n * `altura`: pitch em números inteiros, 63 é 100%\n\n#### \"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)\n\nIsso ocorre quando o cliente ouve um efeito sonoro codificado.\n\n   * `idSom`: ID do efeito sonoro\n   * `categoriaSom`: categoria do efeito sonoro\n   * `posição`: uma instância Vec3 indicando o ponto de onde o som originou\n   * `volume`: volume em ponto flutuante, 1.0 é 100%\n   * `altura`: pitch em números inteiros, 63 é 100%\n\n#### \"noteHeard\" (block, instrument, pitch)\n\nIsso ocorre quando um bloco de notas é disparado em algum lugar.\n\n * `bloco`: uma instância de Bloco, o bloco que emitiu o som\n * `instrumento`:\n   - `id`: identificação numérica\n   - `nome`: um dos seguintes [`harpa`, `contrabaixo`, `caixa de bateria`, `baquetas`, `bateria grave`]\n * `tom`: O tom da nota (entre 0 e 24, inclusivos, onde 0 é o mais baixo e 24 é o mais alto). Você pode ler mais (sobre como os valores de tom correspondem às notas na vida real) aqui: [Página oficial da Minecraft Wiki](http://minecraft.wiki/w/Note_Block).\n\n#### \"pistonMove\" (block, isPulling, direction)\n\nIsso ocorre quando um pistão se move.\n\n#### \"chestLidMove\" (block, isOpen, block2)\n\nIsso ocorre quando a tampa de um baú se move.\n\n* `bloco`: uma instância de Bloco, o bloco da tampa que se moveu. O bloco à direita se for um baú duplo.\n* `estáAberto`: número de jogadores que têm o baú aberto.\n* `bloco2`: uma instância de Bloco, a outra metade do bloco onde a tampa se moveu. Nulo se não for um baú duplo.\n\n#### \"blockBreakProgressObserved\" (block, destroyStage)\n\nIsso ocorre quando o cliente observa um bloco enquanto ele está sendo quebrado.\n\n * `bloco`: uma instância de Bloco, o que está sendo quebrado.\n * `estágioDestruicao`: número inteiro correspondente ao progresso (0-9).\n\n#### \"blockBreakProgressEnd\" (block)\n\nIsso ocorre quando o cliente observa um bloco que termina de ser quebrado.\nIsso ocorre quando o processo foi concluído ou cancelado.\n\n * `bloco`: uma instância de Bloco, o bloco que não está mais sendo quebrado.\n\n#### \"diggingCompleted\" (block)\n\nIsso ocorre quando a quebra de um bloco foi concluída.\n * `bloco` - o bloco que já não existe.\n\n#### \"diggingAborted\" (block)\n\nIsso ocorre quando o processo de quebra de um bloco foi abortado.\n * `bloco` - o bloco que ainda existe.\n\n#### \"move\"\n\nSe emite cuando o bot se move. Se deseja a posição atual, você pode usar `bot.entity.position` e se quiser descobrir a posição anterior, use `bot.entity.positon.minus(bot.entity.velocity)`.\n\n#### \"forcedMove\"\n\nSe emite quando o bot é movido forçadamente pelo servidor (teletransporte, spawn, ...). Se deseja a posição atual, use `bot.entity.position`.\n\n#### \"mount\"\n\nSe emite quando o bot sobe em uma entidade, como um minecart. Para acessar a entidade, use `bot.vehicle`.\n\nPara subir em uma entidade, use `mount`.\n\n#### \"dismount\" (vehicle)\n\nSe emite quando você desce de uma entidade.\n\n#### \"windowOpen\" (window)\n\nSe emite quando você começa a usar uma mesa de criação, baú, mesa de poções, etc.\n\n#### \"windowClose\" (window)\n\nSe emite quando você não está mais usando uma mesa de criação, baú, etc.\n\n#### \"sleep\"\n\nSe emite quando você dorme.\n\n#### \"wake\"\n\nSe emite quando você acorda.\n\n#### \"experience\"\n\nSe emite quando `bot.experience.*` muda.\n\n#### \"scoreboardCreated\" (scoreboard)\n\nSe emite quando um placar é criado.\n\n#### \"scoreboardDeleted\" (scoreboard)\n\nSe emite quando um placar é excluído.\n\n#### \"scoreboardTitleChanged\" (scoreboard)\n\nSe emite quando o título de um placar é atualizado.\n\n#### \"scoreUpdated\" (scoreboard, item)\n\nSe emite quando a pontuação de um item no placar é atualizada.\n\n#### \"scoreRemoved\" (scoreboard, item)\n\nSe emite quando a pontuação de um item no placar é removida.\n\n#### \"scoreboardPosition\" (position, scoreboard)\n\nSe emite quando a posição de um placar é atualizada.\n\n#### \"bossBarCreated\" (bossBar)\n\nSe emite quando uma barra de vida de chefe é criada.\n\n#### \"bossBarDeleted\" (bossBar)\n\nSe emite quando uma barra é excluída.\n\n#### \"bossBarUpdated\" (bossBar)\n\nSe emite quando uma barra é atualizada.\n\n#### \"heldItemChanged\" (heldItem)\n\nSe emite quando o item que você está segurando muda.\n\n#### \"physicsTick\" ()\n\nSe emite a cada tick se bot.physicsEnabled estiver em true.\n\n#### \"chat:name\" (matches)\n\nSe emite quando todos os padrões de chat têm correspondências.\n\n### Functions\n\n#### bot.blockAt(point, extraInfos=true)\n\nRetorna o bloco no `point` (um Vec3) ou `null` se esse ponto não estiver carregado. Se `extraInfos` estiver definido como true, também retorna informações sobre placas, quadros e entidades de blocos (mais lento). Veja `Block`.\n\n#### bot.waitForChunksToLoad(cb)\n\nEssa função também retorna uma `Promise`, com `void` como argumento quando a carga dos chunks estiver completa.\n\nO `cb` é executado quando bastantes chunks são carregados.\n\n#### bot.blockInSight(maxSteps, vectorLength)\n\nObsoleto, usar `blockAtCursor` no lugar.\n\nRetorna o bloco que está no cursor do bot ou `null`.\n * `maxSteps` - Número de passos do traçado de raios, o valor padrão é 256.\n * `vectorLength` - Comprimento do vetor do traçado de raios, o valor padrão é `5/16`.\n\n#### bot.blockAtCursor(maxDistance=256)\n\nRetorna o bloco que está no cursor do bot ou `null`.\n * `maxDistance` - Distância máxima à qual o bloco pode estar do olho, o valor padrão é 256.\n\n#### bot.canSeeBlock(block)\n\nRetorna verdadeiro ou falso dependendo se o bot pode ver o `block` (bloco).\n\n#### bot.findBlocks(options)\n\nEncontra os blocos mais próximos do ponto especificado.\n * `options` - Opções de pesquisa:\n   - `point` - A posição a partir da qual começar a pesquisa (centro). Padrão: a posição do bot.\n   - `matching` - Uma função que retorna verdadeiro se o bloco atender às condições. Também pode ser um ID de bloco ou uma matriz de IDs.\n   - `useExtraInfo` - Pode ser de dois tipos para manter a compatibilidade inversa.\n      - **boolean** - Você fornece sua função `matching` com mais informações - mais lento.\n      - **function** - É feito em duas etapas, se o bloco atender às condições da função `matching`, ele passa para `useExtraInfo` com informações adicionais.\n   - `maxDistance` - A distância máxima de pesquisa, padrão: 16.\n   - `count` - Número de blocos a serem encontrados antes de retornar os resultados. Padrão: 1. Pode retornar menos se não houver blocos suficientes.\n\nRetorna um array (pode estar vazio) com as coordenadas dos blocos encontrados (não retorna instâncias de blocos). O array é ordenado (os mais próximos primeiro).\n\n#### bot.findBlock(options)\n\nSemelhante a `bot.blockAt(bot.findBlocks(options)[0])`. Retorna um único bloco ou `null`.\n\n#### bot.canDigBlock(block)\n\nRetorna se o `block` está dentro do alcance e se pode ser escavado.\n\n#### bot.recipesFor(itemType, metadata, minResultCount, craftingTable)\n\nRetorna uma lista de instâncias `Recipe` (receita) que você pode usar para criar `itemType` com `metadata`.\n\n * `itemType` - ID numérico do item que deseja criar.\n * `metadata` - o valor numérico da metadados do item que deseja criar, `null` significa \"com qualquer valor de metadados\".\n * `minResultCount` - baseia-se no seu inventário atual, qualquer receita da lista retornada poderá produzir esse número de itens. `null` significa `1`.\n * `craftingTable` - uma instância `Block` (mesa de criação). Se for `null`, apenas receitas que podem ser feitas no inventário serão incluídas na lista.\n\n#### bot.recipesAll(itemType, metadata, craftingTable)\n\nSemelhante a bot.recipesFor, mas não verifica se o bot tem materiais suficientes para a receita.\n\n#### bot.nearestEntity(match = (entity) => { return true })\n\nRetorna a entidade mais próxima do bot, correspondendo à função (padrão: todas as entidades).\nRetorna null se nenhuma entidade for encontrada.\n\n### Methods\n\n#### bot.end()\n\nEncerra a conexão com o servidor.\n\n#### bot.quit(reason)\n\nPara se desconectar do servidor de forma elegante com um motivo (padrão: 'disconnect.quitting').\n\n#### bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])\n\nEssa função também retorna uma `Promise`, com `matches` como argumento quando a conclusão é feita.\n\nSolicita a conclusão da mensagem de chat (para comandos).\n * `str` - String para completar.\n * `callback(matches)`\n   - `matches` - Array de strings correspondentes.\n * `assumeCommand` - Campo enviado ao servidor, padrão: false.\n * `sendBlockInSight` - Campo enviado ao servidor, padrão: true. Mude para false se desejar maior eficiência.\n\n#### bot.chat(message)\n\nEnvia uma mensagem pública no chat. Divide mensagens grandes em pedaços e as envia como várias mensagens, se necessário.\n\n#### bot.whisper(username, message)\n\nAtalho para \"/tell <username>\" (usuário). Todas as partes serão sussurradas ao usuário.\n\n#### bot.chatAddPattern(pattern, chatType, description)\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\nAdicione um padrão regex à lista de padrões do bot. Útil para servidores Bukkit onde o formato do chat muda com frequência.\n * `pattern` - padrão regex para corresponder\n * `chatType` - o evento que o bot emite quando o padrão corresponde, por exemplo, \"chat\" ou \"whisper\"\n * 'description' - Opcional, descrição do padrão\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\n** isso é semelhante a `bot.addChatPatternSet(name, [pattern], chatPatternOptions)`\n\nCria um evento que é emitido sempre que um padrão corresponde, o evento será chamado \"chat:name\", sendo \"name\" o nome fornecido.\n* `name` - o nome usado para o evento\n* `pattern` - expressão regular a ser testada nas mensagens\n* `chatPatternOptions` - objeto\n  * `repeat` - padrão: true, se continuar testando após corresponder uma vez\n  * `parse` - em vez de retornar a mensagem, retorne os grupos capturados pela regex\n  * `deprecated` - (**unstable**) usado por bot.chatAddPattern para manter a compatibilidade, provavelmente será removido\n\nRetorna um número que pode ser usado em bot.removeChatPattern() para remover esse padrão.\n\n#### bot.addChatPatternSet(name, patterns, chatPatternOptions)\n\nCria um evento que é emitido sempre que todos os padrões correspondem, o evento será chamado \"chat:name\", sendo \"name\" o nome fornecido.\n* `name` - o nome usado para o evento\n* `patterns` - expressões regulares a serem testadas nas mensagens\n* `chatPatternOptions` - objeto\n  * `repeat` - padrão: true, se continuar testando após corresponder uma vez\n  * `parse` - em vez de retornar a mensagem, retorne os grupos capturados pela regex\n\nRetorna um número que pode ser usado em bot.removeChatPattern() para remover esse conjunto de padrões.\n\n#### bot.removeChatPattern(name)\n\nRemove um padrão / conjuntos de padrões\n* `name`: string ou número\n\nSe o nome for uma string, todos os padrões com esse nome serão removidos; caso contrário, se for um número, apenas o padrão exato será removido.\n\n#### bot.awaitMessage(...args)\n\nPromessa que é resolvida quando uma das mensagens fornecidas é cumprida.\n\nExemplo:\n\n```js\nasync function wait () {\n  await bot.awaitMessage('<flatbot> hello world') // resolve \"hello world\" no chat por flatbot (se resolve quando um usuário chamado flatbot escreve \"hello world\" no chat)\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world']) // resolve \"hello\" ou \"world\" no chat por flatbot (se resolve quando um usuário chamado flatbot escreve \"hello\" ou \"world\" no chat)\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world'], ['<flatbot> im', '<flatbot> batman']) // resolve \"hello\" ou \"world\" ou \"im\" ou \"batman\" no chat por flatbot (se resolve quando um usuário chamado flatbot escreve \"hello world\", \"world\", \"im\" ou \"batman\" no bater papo)\n  await bot.awaitMessage('<flatbot> hello', '<flatbot> world') // resolve \"hello\" ou \"world\" no chat do flatbot\n  await bot.awaitMessage(/<flatbot> (.+)/) // resolve na primeira mensagem correspondente ao regex (se resolve quando um usuário chamado flatbot escreve algo que coincide com o padrão)\n}\n```\n\n#### bot.setSettings(options)\n\nVeja a propriedade `bot.settings`.\n\n#### bot.loadPlugin(plugin)\n\nIntroduz um Plugin. Não faz nada se o plugin já estiver carregado/introduzido.\n\n * `plugin` - função\n\n```js\nfunction somePlugin (bot, options) {\n  function someFunction () {\n    bot.chat('Yay!')\n  }\n\n  bot.myPlugin = {} // Boas práticas para API de plugin de namespace (faça isso para evitar erros como myPlugin não está definido)\n  bot.myPlugin.someFunction = someFunction\n}\n\nconst bot = mineflayer.createBot({})\nbot.loadPlugin(somePlugin)\nbot.once('login', function () {\n  bot.myPlugin.someFunction() // Yay!\n})\n```\n\n#### bot.loadPlugins(plugins)\n\nIntroduz plugins, veja `bot.loadPlugin`.\n * `plugins` - array de funções\n\n#### bot.hasPlugin(plugin)\n\nVerifica se o plugin já está carregado (ou previsto para carregar) no bot.\n\n#### bot.sleep(bedBlock, [cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nDormir em uma cama. `bedBlock` deve ser uma instância `Block` que é uma cama. `cb` é uma função que pode ter um parâmetro de erro se o bot não conseguir dormir.\n\n#### bot.isABed(bedBlock)\n\nRetorna verdadeiro se `bedBlock` for uma cama.\n\n#### bot.wake([cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nAcordar de uma cama. `cb` é uma função que pode ter um parâmetro de erro se o bot não conseguir acordar.\n\n#### bot.setControlState(control, state)\n\nEste é o método principal para controlar os movimentos do bot. É semelhante a pressionar teclas no Minecraft.\nPor exemplo, forward como true fará o bot se mover para a frente. Forward como false fará o bot parar de se mover para a frente.\nVocê pode usar bot.lookAt com isso para controlar o movimento. O exemplo jumper.js mostra como fazer isso.\n\n * `control` - Um dos seguintes: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n * `state` - `true` ou `false`\n\n#### bot.getControlState(control)\n\n#### bot.getControlState(control)\n\nRetorna verdadeiro se o controle estiver ativado.\n\n* `control` - um dos seguintes ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n\n#### bot.clearControlStates()\n\nDesativa todos os controles.\n\n#### bot.lookAt(point, [force], [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nMove a cabeça.\n\n * `point` - uma instância [Vec3](https://github.com/andrewrk/node-vec3) - move a cabeça para olhar para este ponto.\n * `force` - Veja `force` em `bot.look`.\n * `callback()` - opcional, executado quando você está olhando para o `point`.\n\n#### bot.look(yaw, pitch, [force], [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nMove a cabeça.\n\n * `yaw` - O número de radianos para girar em torno do eixo vertical, começando pelo leste, no sentido anti-horário.\n * `pitch` - O número de radianos para olhar para cima ou para baixo. 0 significa olhar em frente. PI / 2 significa para cima. -PI / 2 significa para baixo.\n * `force` - Se presente e verdadeiro, pula a transição suave. Especifique como verdadeiro se você quiser valores precisos para soltar itens ou atirar flechas. Isso não é necessário para cálculos do lado do cliente, como mover-se.\n * `callback()` - opcional, executado quando você está olhando para `yaw` e `pitch`.\n\n#### bot.updateSign(block, text)\n\nAltera o texto em um sinal.\n\n#### bot.equip(item, destination, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nEquipar um item do inventário.\n\n * `item` - instância `Item`. Veja `window.items()`.\n * `destination` - `\"hand\"` (mão), `null` é um alias para isso.\n   - `\"head\"` (cabeça)\n   - `\"torso\"` (peito)\n   - `\"legs\"` (pernas)\n   - `\"feet\"` (pés)\n   - `\"off-hand\"` (mão esquerda), quando disponível.\n * `callback(error)` - opcional, executado quando o bot equipou o item ou quando falhou em fazê-lo.\n\n#### bot.unequip(destination, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nRemove um item do destino.\n\n#### bot.tossStack(item, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nDescarta a pilha de itens especificada.\n * `item` - a pilha de itens que você deseja descartar.\n * `callback(error)` - opcional, executado quando o bot terminou de descartar ou quando falhou em fazê-lo.\n\n#### bot.toss(itemType, metadata, count, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `itemType` - ID numérico do item que você deseja descartar.\n * `metadata` - metadados do item que você deseja descartar. `null` para qualquer metadados.\n * `count` - quantos itens você deseja descartar. `null` significa `1`.\n * `callback(err)` - (opcional) executado quando o bot terminou de descartar ou quando falhou em fazê-lo.\n\n#### bot.dig(block, [forceLook = true], [digFace], [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nComeça a quebrar o `block` (bloco) com o item na mão.\nObserve os eventos \"diggingCompleted\" e \"diggingAborted\".\n\nNota: ao começar a quebrar um bloco, você não poderá quebrar outro bloco até terminar de quebrar aquele bloco ou executar `bot.stopDigging()`.\n\n * `block` - o bloco que você deseja quebrar.\n * `forceLook` - (opcional) se for verdadeiro, olha rapidamente para o bloco e começa a quebrá-lo. Se for falso, olha lentamente para o bloco antes de começar a quebrá-lo. Além disso, pode ser 'ignore', para que o bot não olhe para o bloco ao quebrá-lo.\n * `digFace` - (opcional) Padrão: 'auto', olha para o centro do bloco e quebra-o a partir do topo. Também pode ser um vetor Vec3 da face do bloco para onde o bot deve olhar. Por exemplo: ```vec3(0, 1, 0)``` para quebrar a face de cima. Também pode ser 'raycast', isso verifica se alguma face é visível para começar a quebrar por essa face, o que é útil em servidores com um anti-cheat.\n * `callback(err)` - (opcional) executado quando o bot quebrou o bloco ou quando falhou em fazê-lo.\n\n#### bot.stopDigging()\n\nParar de quebrar o escavar o bloco.\n\n#### bot.digTime(block)\n\nRetorna quanto tempo levará para quebrar o bloco, em milissegundos.\n\n#### bot.acceptResourcePack()\n\nAceitar o pacote de recursos.\n\n#### bot.denyResourcePack()\n\nNegar o pacote de recursos.\n\n#### bot.placeBlock(referenceBlock, faceVector, cb)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `referenceBlock` - o bloco ao lado do bloco que deseja colocar\n * `faceVector` - uma das seis direções cardeais, por exemplo, `new Vec3(0, 1, 0)` para o lado de cima, indicando a face do bloco de referência.\n * `cb` será executado quando o servidor confirmar que o bloco foi colocado.\n\nO bloco será colocado em `referenceBlock.position.plus(faceVector)` (posição do bloco de referência mais o vetor de face).\n\n#### bot.placeEntity(referenceBlock, faceVector)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `referenceBlock` - o bloco ao lado de onde deseja colocar a entidade.\n * `faceVector` - uma das seis direções cardeais, por exemplo, `new Vec3(0, 1, 0)` para a face de cima, indicando a face do bloco de referência.\n\nA entidade será colocada em `referenceBlock.position.plus(faceVector)` (posição do bloco de referência mais o vetor de face).\n\n#### bot.activateBlock(block, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nAtivar um bloco, como bater em um bloco de nota ou abrir uma porta.\n\n * `block` - o bloco a ser ativado.\n * `callback(err)` - (opcional) executado quando o bot ativa o bloco ou falha ao fazê-lo.\n\n#### bot.activateEntity(entity, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nAtivar uma entidade, por exemplo, com aldeões.\n\n * `entity` - a entidade a ser ativada.\n * `callback(err)` - (opcional) executado quando o bot ativa a entidade ou falha ao fazê-lo.\n\n#### bot.activateEntityAt(entity, position, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nAtivar uma entidade na posição especificada, útil para suportes de armadura.\n\n * `entity` - a entidade a ser ativada.\n * `position` - a posição onde você deve clicar.\n * `callback(err)` - (opcional) executado quando o bot ativa a entidade ou falha ao fazê-lo.\n\n#### bot.consume(callback)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nConsumir ou beber o item na mão.\n\n * `callback(error)` - executado quando o bot consome o item ou falha ao fazê-lo.\n\n#### bot.fish(callback)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nPescar com a vara de pescar na mão.\n\n * `callback(error)` - (opcional) executado quando o bot pescou algo ou falhou ao fazê-lo.\n\n#### bot.activateItem(offHand=false)\n\nAtivar o item na mão. Isso é usado para comer, atirar flechas, jogar ovos, etc.\nO parâmetro opcional pode ser `false` para a mão esquerda.\n\n#### bot.deactivateItem()\n\nDesativar o item na mão. Isso é como atirar uma flecha, parar de comer, etc.\n\n#### bot.useOn(targetEntity)\n\nUsar o item na mão na instância de `Entity` (entidade). Isso é usado para colocar uma sela em um cavalo, ou usar tesouras em uma ovelha, por exemplo.\n\n#### bot.attack(entity)\n\nAtacar a entidade ou criatura.\n\n#### bot.swingArm([hand], showHand)\n\nReproduz a animação de mover o braço.\n\n * `mão` - a mão que será animada, pode ser `esquerda` ou `direita`. Padrão: `direita`\n * `mostrarMão` - um booleano que indica se adicionar a mão ao pacote para mostrar a animação. Padrão: `verdadeiro`\n\n#### bot.mount(entity)\n\nSubir em uma entidade. Para descer, use `bot.dismount`.\n\n#### bot.dismount()\n\nDesce da entidade em que você está montado.\n\n#### bot.moveVehicle(left,forward)\n\nMover o veículo:\n\n * esquerda pode ser -1 ou 1: -1 significa direita, 1 significa esquerda\n * frente pode ser -1 ou 1: -1 significa para trás, 1 significa para a frente\n\nTodas as direções são relativas à direção em que o bot está olhando.\n\n#### bot.setQuickBarSlot(slot)\n\n * `slot` - pode ser de 0 a 8, a posição da barra de acesso rápido\n\n#### bot.craft(recipe, count, craftingTable, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `receita` - Uma instância de `Receita`. Veja `bot.receitasPara`.\n * `quantidade` - Quantas vezes você deseja repetir a ação.\n   Se você deseja criar `8` varas com tábuas de madeira, você colocaria\n   `quantidade` como `2`. `null` significa `1`.\n * `mesaDeCriação` - Uma instância de `Bloco`, a mesa de criação que você deseja usar. Se a criação não exigir uma mesa, este argumento pode ser deixado como `null`.\n * `retorno` - (opcional) Executado quando o bot terminou a criação e o inventário foi atualizado.\n\n#### bot.writeBook(slot, pages, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\n * `slot` é um número de posição no inventário (36 é o primeiro slot, etc.).\n * `páginas` é um array de strings representando as páginas.\n * `retorno(erro)` - opcional. Executado quando o bot terminou de escrever ou ocorreu um erro.\n\n#### bot.openContainer(containerBlock or containerEntity)\n\nAbre um recipiente.\nRetorna uma promise com uma instância de `Container` que representa o recipiente que você está abrindo.\n\n#### bot.openChest(chestBlock or minecartchestEntity)\n\nObsoleto. O mesmo que `openContainer`\n\n#### bot.openFurnace(furnaceBlock)\n\nAbre um forno.\nRetorna uma promise com uma instância de `Forno` que representa o forno que você está abrindo.\n\n#### bot.openDispenser(dispenserBlock)\n\nObsoleto. O mesmo que `openContainer`\n\n#### bot.openEnchantmentTable(enchantmentTableBlock)\n\nRetorna uma promise com uma instância de `MesaDeEncantamento` que representa a mesa de encantamento que você está abrindo.\n\n#### bot.openAnvil(anvilBlock)\n\nRetorna uma promise com uma instância de `bigorna` que representa a bigorna que você está abrindo.\n\n#### bot.openVillager(villagerEntity)\n\nRetorna uma promise com uma instância de `Aldeão` que representa a janela de negociação que você está abrindo\nO evento `pronto` na instância de `Aldeão` pode ser usado para saber quando as negociações estão prontas\n\n#### bot.trade(villagerInstance, tradeIndex, [times], [cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nUse a instância de `Aldeão` para fazer negociações.\n\n#### bot.setCommandBlock(pos, command, [options])\n\nAltera as propriedades de um bloco de comandos na posição `posição`.\nExemplo de `opções`:\n```js\n{\n  modo: 2,\n  rastrearSaída: verdadeiro,\n  condicional: falso,\n  sempreAtivo: verdadeiro\n}\n```\nopções.modo pode ter 3 valores: 0 (SEQUÊNCIA), 1 (AUTO), 2 (REDSTONE)\nTodas as opções têm padrão como falso, exceto modo que é 2 (para se assemelhar ao bloco de comandos do Minecraft).\n\n#### bot.supportFeature(name)\n\nIsso pode ser usado para verificar se uma característica está disponível na versão do bot do Minecraft. Normalmente, isso é usado para lidar com funções específicas de uma versão.\n\nVocê pode encontrar a lista de características em [./lib/features.json](https://github.com/PrismarineJS/mineflayer/blob/master/lib/features.json) arquivo.\n\n#### bot.waitForTicks(ticks)\n\nEsta função retorna uma promessa e espera que o número de ticks especificado passe no jogo; esta função é semelhante à função setTimeout do JavaScript, mas funciona com o relógio físico do jogo.\n\n### Lower level inventory methods\n\nEsses são métodos de nível mais baixo para o inventário e podem ser úteis em algumas situações, mas é melhor usar os métodos apresentados acima sempre que possível.\n\n#### bot.clickWindow(slot, mouseButton, mode, cb)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nClique na janela/interface atual; os detalhes estão em https://minecraft.wiki/w/Protocol#Click_Window\n * slot - número que representa a posição na janela\n * mouseButton - 0 para clique esquerdo e 1 para clique direito\n * mode - mineflayer só tem o modo 0 disponível\n\n#### bot.putSelectedItemRange(start, end, window, slot)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nMova o item na posição `slot` em um intervalo especificado.\n\n#### bot.putAway(slot)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nMova o item para a posição `slot` no inventário.\n\n#### bot.closeWindow(window)\n\nFeche a janela/interface.\n * janela - a janela a ser fechada\n\n#### bot.transfer(options, cb)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nTransfira um item de um intervalo para outro. `opções` é um objeto com:\n\n * `janela`: a janela para onde o item será movido\n * `tipoItem`: o tipo de item a ser movido (ID numérico)\n * `metadata`: a metadados do item a ser movido\n * `inícioOrigem` e `fimOrigem`: o intervalo de origem\n * `inícioDestino` e `fimDestino`: o intervalo de destino\n\n#### bot.openBlock(block)\n\nAbra um bloco, como um baú; retorna uma promessa com `Janela` sendo a janela aberta.\n\n * `bloco` é o bloco a ser aberto\n\n#### bot.openEntity(entity)\n\nAbra uma entidade com um inventário, como um aldeão; retorna uma promessa com `Janela` sendo a janela aberta.\n\n * `entidade` é a entidade a ser aberta\n\n#### bot.moveSlotItem(sourceSlot, destSlot, cb)\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nMova um item de uma posição `origemSlot` para outra `destinoSlot` em uma janela.\n\n#### bot.updateHeldItem()\n\nAtualize `bot.heldItem`.\n\n#### bot.getEquipmentDestSlot(destination)\n\nRetorna o ID da posição de equipamento pelo nome do destino.\n\nO destino pode ser:\n* cabeça - (cabeça)\n* peito - (peito)\n* pernas - (pernas)\n* pés - (pés)\n* mão - (mão)\n* mão secundária - (mão esquerda)\n\n### bot.creative\n\nEsta coleção de APIs é útil no modo criativo.\nA detecção e a troca de modo não estão implementadas,\nmas é assumido e muitas vezes é necessário que o bot esteja no modo criativo para que essas funcionalidades funcionem.\n\n#### bot.creative.setInventorySlot(slot, item, [callback])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nFornece ao bot o item especificado na posição especificada.\nSe for executado duas vezes antes que a primeira execução seja concluída, a primeira execução conterá um erro.\n\n * `slot` é um número de posição no inventário (onde 36 é a primeira posição, etc.).\n * `item` é uma instância de [prismarine-item](https://github.com/PrismarineJS/prismarine-item) com seus metadados, dados nbt, etc.\n    Se `item` for `null`, o item nessa posição será removido\n * `retorno(erro)` (opcional) é uma função de retorno que é executada quando o servidor aceita a transação ou quando a transação falha.\n\nSe este método alterar algo, será emitido `bot.inventory.on(\"updateSlot\")`.\n\n#### bot.creative.flyTo(destination, [cb])\n\nEsta função também retorna uma `Promise`, com `void` como argumento quando concluída.\n\nExecute `startFlying()` e mova-se a uma velocidade constante em um espaço tridimensional em linha reta até o destino.\n`destino` é um `Vec3`, e as coordenadas `x` e `z` às vezes terminarão em `.5`.\nEssa operação não funcionará se houver algum obstáculo no caminho,\nportanto, é recomendável voar distâncias curtas.\n\nQuando o bot chegar ao destino, `cb` será executado.\n\nEste método não procurará automaticamente o caminho.\nEspera-se que uma implementação de busca de caminho use este método para se mover < 2 blocos de cada vez.\n\nPara parar de voar (voltar à física normal), você pode executar `stopFlying()`.\n\n#### bot.creative.startFlying()\n\nAltera `bot.physics.gravity` para `0`.\nPara voltar à física normal, você pode executar `stopFlying()`.\n\nEste método é útil se você quiser flutuar enquanto quebra o bloco abaixo de você.\nNão é necessário executar esta função antes de executar `flyTo()`.\n\nObservação: enquanto você voa, `bot.entity.velocity` não é preciso.\n\n#### bot.creative.stopFlying()\n\nRestaura `bot.physics.gravity` ao seu valor original.\n"
  },
  {
    "path": "docs/br/unstable_api_br.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Tabla de contenidos**  *generado con [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API inestable : bot._](#api-instable--bot_)\n  - [bot._client](#bot_client)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API instável: bot._\n\nEsses métodos e classes são úteis em alguns casos especiais, mas não são estáveis e podem mudar a qualquer momento.\n\n## bot._client\n\n`bot._client` é criado usando [node-minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol).\nLida com a escrita e recepção de pacotes.\nO comportamento pode mudar (por exemplo, em cada nova versão do Minecraft), portanto, é melhor usar os métodos do mineflayer, se possível.\n\nEsta documentação não é oficialmente mantida. Se você deseja ver as últimas novidades, por favor, consulte a documentação original: [unstable_api](../unstable_api.md)\n"
  },
  {
    "path": "docs/demos.md",
    "content": "## mineflayer-navigate\n\n[navigate](https://github.com/andrewrk/mineflayer-navigate/) - get around\n   easily using A* pathfinding\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/O6lQdmRz8eE\" frameborder=\"0\"></iframe>\n\n## rbot\n\n[rom1504/rbot](https://github.com/rom1504/rbot) smart bot based on mineflayer\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/0cQxg9uDnzA\" frameborder=\"0\"></iframe>\n\n## chaoscraft\n\n[Chaoscraft](https://github.com/schematical/chaoscraft) Minecraft bot using genetic algorithms\n\n\n​<iframe width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/videoseries?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/es/CONTRIBUTING_ES.md",
    "content": "# Contribuir\n\nMineflayer originalmente fue hecho mayormemente por [andrewrk](http://github.com/andrewrk)\npero ha sido arreglado y mejorado mucho por muchos [contribuyentes](https://github.com/andrewrk/mineflayer/graphs/contributors).\nPor eso es importante saber cual es la mejor manera de contribuir a mineflayer.\n\n## Organización de problemas\n\nTenemos 3 etiquetas para 3 fases de organizar los problemas:\n\n* Stage 1: (Fase 1) creado por alguien nuevo al proyecto, no sabemos si merece una implementación / solución\n* Stage 2: (Fase 2) idea prometedora, pero se necesita pensar más sobre el tema antes de implementarlo\n* Stage 3: (Fase 3) la idea es muy precisa, solo hace falta programarlo\n\nLos links como https://github.com/PrismarineJS/mineflayer/issues?q=is%3Aopen+is%3Aissue+-label%3AStage1 se pueden usar como filtro para la fase 1 si estás buscando cosas que están listas para que sean contribuidas\n\n## Creando tests\nMineflayer tiene dos tipos de tests :\n\n * [tests internos](test/internalTest.js) : tests que se hacen con un servidor simple creado con node-minecraft-protocol\n * [tests externos](test/externalTests/) : tests que se hacen con un servidor vanilla\n \nEl objectivo de estos tests es saber automáticamente qué funciona y qué no funciona en mineflayer, así es más fácil hacer funcionar mineflayer.\n\n### Creando un text externo\n\nPara crear un test externo solo tienes que crear un archivo en [test/externalTests](test/externalTests)\n\nUn ejemplo : [test/externalTests/digAndBuild.js](https://github.com/PrismarineJS/mineflayer/blob/master/test/externalTests/digAndBuild.js)\n\nEse archivo tiene que exportar una función que devuelve una función o un array de funciones que necesitan como parámetros el object de bot y un callback para cuando haya finalizado, debería contener asserts para saber si la función testeada ha fallado.\n\n\n## Creando un plugin de terceros\nMineflayer admite plugins; cualquiera puede crear un plugin que añade una API con un nivel más alto encima de Mineflayer.\n\nBastantes plugins de terceros han sido [creados](https://github.com/andrewrk/mineflayer#third-party-plugins)\n\nPara crear un plugin nuevo tienes que :\n\n1. crear un repositorio nuevo\n2. en tu archivo index.js, exportar una función para inicializar el plugin con argumento mineflayer ([ejemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L18))\n3. esa función devuelve una función para introducir el plugin con argumento el object del bot ([ejemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L23))\n4. a partir de esa función se pueden añadir más funcionalidades al bot ([ejemplo](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L32))\n\nComo el object de mineflayer fue pasado como argumento, ese plugin de terceros no tiene que depender en mineflayer (no hay mineflayer en el package.json)\n\nMira un [ejemplo completo](https://github.com/andrewrk/mineflayer-navigate/tree/e24cb6a868ce64ae43bea2d035832c15ed01d301) here.\n\n## Reportando bugs\nMineflayer funciona bien para la mayoría de cosas, pero a veces sigue teniendo bugs.\n\nCuando encuentras uno es mejor que informes sobre el error proporcionando esta información :\n\n* que quieres hacer (el objetivo en english)\n* que es lo que has intentado (el código)\n* que ha pasado\n* que esperabas que pasara\n\n## Código de Mineflayer\nAlgunas cosas para pensar al crear un Pull Request (solicitud de pull) o hacer un commit :\n\n### Gestión de errores\nEn la mayoría de casos, mineflayer no debería romper/crashear el bot. Incluso si algo falla, el bot puede coger una ruta alternativa para coseguir el objetivo.\n\nCon esto se refiere a que no deberíamos usar el `throw new Error(\"error\")` sino pasar el error junto al callback.\n\nPor ejemplo : \n\n```js\nfunction myfunction (param1, callback) {\n  // do stuff\n  let toDo = 1\n  toDo = 2\n  if (toDo === 2) { // everything worked (todo ha funcionado)\n    callback()\n  } else {\n    callback(new Error('something failed')) // (algo ha fallado)\n  }\n}\n```\n\nMira otro ejemplo en el [código de mineflayer](https://github.com/andrewrk/mineflayer/blob/a8736c4ea473cf1a609c5a29046c0cdad006d429/lib/plugins/bed.js#L10)\n\n### Actualizando la documentación\nLa tabla de contenidos del docs/api.md está hecho con doctoc. Tras actualizar el archivo, deberías ejecutar doctoc docs/api.md para actualizar la tabla de contenidos.\n\n\nEsta documentación no está mantenida oficialmente, si quiere ver las últimas novedades, por favor dirijase a la documentación original: [unstable_api](../CONTRIBUTING.md)\n"
  },
  {
    "path": "docs/es/FAQ_ES.md",
    "content": "## FAQ\n\nEste documento sobre preguntas frecuentes es para ayudar la gente en cosas básicas\n\n## Como ocultar errores?\n\nEscribe `hideErrors: true` en las opciones de createBot\nTambién puedes usar estos eventos:\n\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n## Mi evento de chat no se emite en un servidor personalizado, cómo lo resuelvo?\n\nLos servidores spigot, en particular algunos plugins, usan formatos personalizados de chat, tienes que analizarlos con un regex personalizado.\nLee y modifica [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) para que funcione con tu plugin de chat particular. Lee también http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat\n\n### Como puedo recolectar información de un plugin de chat personalizado?\n\nLa mayoría de servidores de minecraft tienen plugins, que mandan mensajes al chat cuando ocurre algo. Si es algo sencillo, se puede utilizar la solución anterior, pero si tiene mucha información en un solo mensaje, la otra opción sería usar el evento `\"messagestr\"` que te permite analizar los mensajes fácilmente.\n\n**Ejemplo:**\n\nEl mensaje podría ser así:\n```\n(!) U9G has won the /jackpot and received\n$26,418,402,450! They purchased 2,350,000 (76.32%) ticket(s) out of the\n3,079,185 ticket(s) sold!\n```\n```js\nconst regex = {\n  first: /\\(!\\) (.+) has won the \\/jackpot and received +/,\n  second: /\\$(.+)! They purchased (.+) \\((.+)%\\) ticket\\(s\\) out of the /,\n  third: /(.+) ticket\\(s\\) sold!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n\n### Como puedo mandar un comando?\n\nUsando `bot.chat()`.\n\n**Ejemplo:**\n```js\nbot.chat('/give @p diamond')\n```\n\n### Es posible crear multiples bots y controlarlos separadamente?\n\nCrea diferentes bots con createBot y haz diferentes cosas para cada uno, echa un vistazo a multiple.js\n\n### Como hago para que el bot dropee/tire todo su inventario?\n\nbot.inventory.items() te proporciona un array de los ítems del bot. Puedes usar una función recursiva para tirar cada ítem usando bot.toss(). Haz click [aquí](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9) para ver un ejemplo\n\n### Como veo los paquetes que con mandados/recibidos?\n\nActiva el modo de depuración https://github.com/PrismarineJS/mineflayer/blob/master/docs/es/README_ES.md#depuraci%C3%B3n\n\n### Quiero prevenir una desconexión en caso de lag en el servidor, como puedo hacerlo?\n\nUna forma de hacerlo es aumentar el valor en la opción [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) (por ejemplo `300*1000` que es 5 minutos en vez del valor predeterminado, que es 30 segundos). Si con eso todavía te desconecta del servidor, puedes reconectarte automáticamente con este ejemplo https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js\n\n### Como puedo obtener el lore / texto de un ítem?\n\nPuedes usar la propiedad `item.nbt`. Está recomendado usar la librería `prismarine-nbt`. El método nbt.simplify() podría ser útil.\n\n**Ejemplo:**\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### Como puedo mandar un mensaje de la consola al servidor?\n\nPuedes usar una librería como `repl` para leer lo que escribes en la consola y usar `bot.chat()` para mandarlo al servidor. Puedes encontrar un ejemplo [aquí](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js)\n\n### Cuando creo un plugin, como puedo especificar otro plugin como dependencia?\n\nEn la función `inject()` the tu plugin, puedes ejecutar la función `bot.loadPlugin()` para cargar ese plugin. Si el plugin ya estaba cargado de antes, no pasará nada.\n\nNota: el orden en el cual los plugins son cargados es dinámico, nunca deberías llamar otro plugin en tu función `inject()`.\n\n### Como puedo usar un proxy socks5?\n\nEn las opciones de `mineflayer.createBot(opciones)`, quita tu `host` de las opciones y pon las cosas que se necesite en estas variables `PROXY_IP`, `PROXY_PORT`, `PROXY_USERNAME`, `PROXY_PASSWORD`, `MC_SERVER_IP`, `MC_SERVER_PORT`, y añade esto a tus opciones:\n```js\nconnect: (client) => {\n  socks.createConnection({\n    proxy: {\n      host: PROXY_IP,\n      port: PROXY_PORT,\n      type: 5,\n      userId: PROXY_USERNAME,\n      password: PROXY_PASSWORD\n    },\n    command: 'connect',\n    destination: {\n      host: MC_SERVER_IP,\n      port: MC_SERVER_PORT\n    }\n  }, (err, info) => {\n    if (err) {\n      console.log(err)\n      return\n    }\n    client.setSocket(info.socket)\n    client.emit('connect')\n  })\n}\n```\n\n# Errores frecuentes\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\nEsto pasa cuando proporcionas una versión equivocada a mineflayer o mineflayer detecta la versión equivocada\n\n### `TypeError: Cannot read property '?' of undefined`\n\nPodrías estar intentando usar una propiedad del bot que todavía no existe, intenta usar la propiedad despues del evento `spawn`\n\n### `SyntaxError: Unexpected token '?'`\n\nActualiza la versión de tu node\n\n### The bot can't break/place blocks or open chests\n\nComprueba que la protección de spawn no está impidiendo el bot de realizar la acción\n\n\nEsta documentación no está mantenida oficialmente, si quiere ver las últimas novedades, por favor dirijase a la documentación original: [FAQ](../FAQ.md)\n"
  },
  {
    "path": "docs/es/README_ES.md",
    "content": "# Mineflayer\n\n[![NPM version](https://badge.fury.io/js/mineflayer.svg)](http://badge.fury.io/js/mineflayer)\n[![Build Status](https://github.com/PrismarineJS/mineflayer/workflows/CI/badge.svg)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)\n[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)\n[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)\n\n[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n\n| <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) | <sub>BR</sub> [Português](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|\n\nCrea bots para Minecraft con una API de JavaScript potente, estable y de alto nivel.\n\n¿Primera vez usando node.js? Puede que quieras empezar con el tutorial [tutorial](../tutorial.md)\n\n## Características\n\n * Soporta Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 y 1.20.\n * Rastreo e información de entidades.\n * Información sobre bloques. Puedes solicitar información de todo lo que te rodea. Encuentra bloques en milisegundos\n * Físicas y movimientos básicos - maneja todos los cuadros de colisión\n * Atacar entidades y usar vehículos.\n * Gestión del inventario.\n * Crafteo, cofres, dispensadores, mesas de encantamiento.\n * Cavar y contruir.\n * Diversas cosas como saber tu salud y si está lloviendo.\n * Activar bloques y usar ítems.\n * Chatear/Hablar.\n\n### Planes para el futuro\n\nEcha un vistazo a nuestros [proyectos actuales](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects)\n\n## Instalación\nPrimero instala Node.js >= 18 desde [nodejs.org](https://nodejs.org/)\n\n`npm install mineflayer`\n\n## Documentación\n\n| link | descripción |\n|---|---|\n|[tutorial](../tutorial.md) | Empieza con node.js y mineflayer |\n| [FAQ.md](FAQ_ES.md) | Alguna duda? Echa un vistazo a esto |\n| [api.md](api_es.md) [unstable_api.md](unstable_api_es.md) | Toda la documentación de la API |\n| [history.md](../history.md) | Historial de cambios de Mineflayer |\n| [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Todos los ejemplos de mineflayer |\n\n## Contribuir\n\nPor favor, lee [CONTRIBUTING.md](CONTRIBUTING_ES.md) y [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute)\n\n## Uso\n\n**Vídeos**\n\nPuedes encontrar un tutorial que explica el proceso de como empezar un bot [aquí](https://www.youtube.com/watch?v=ltWosy4Z0Kw) (en inglés).  \n\nSi quieres aprender más, puedes mirar [aquí, ](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) los códigos usados en los vídeos [aquí](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials)\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Empezando**\n\nSi no se especifica una versión, la versión del servidor se detectará automáticamente. Si no se especifica ningún tipo de autenticación, se utilizará el login de Mojang automáticamente. \n\n### Ejemplo: echo\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // ip del servidor de minecraft\n  username: 'email@example.com', // usuario de la cuenta, e-mail si es premium\n  password: '12345678' // para servidores premium\n  // port: 25565, // modificar solo si es un servidor que no utiliza el puerto predeterminado (25565)\n  // version: false, // modificar solo si se necesita una version específica\n  // auth: 'mojang', // solo modificar si tienes una cuenta microsoft (en ese caso sería auth: 'microsoft')\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// Imprimir errores y la razón del kickeo si te kickean:\nbot.on('kicked', (reason, loggedIn) => console.log(reason, loggedIn))\nbot.on('error', err => console.log(err))\n```\n\n### Mira lo que hace tu bot\n\nGracias al proyecto [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer), puedes ver en una pestaña del navegador qué está haciendo tu bot.\nSolo tienes que ejecutar `npm install prismarine-viewer` y añadir lo siguiente a tu bot:\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // el puerto es en que puerto del buscador hostear el plugin, y firstPerson es por si quieres la vista en primera persona o no\n})\n```\nY podrás ver una representación *en vivo* como esta:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### Más ejemplos\n\n| ejemplo | descripción |\n|---|---|\n|[viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | Visualiza lo que ve tu bot en el buscador |\n|[pathfinder](https://github.com/Karang/mineflayer-pathfinder/blob/master/examples/test.js) | Haz que tu bot vaya a cualquier ubicación automáticamente |\n|[chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | Aprende a usar cofres, hornos, dispensadores y mesas de encantamiento |\n|[digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | Aprende como crear un bot que pueda romper un bloque |\n|[discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | Conecta un bot de discord con un bot de mineflayer |\n|[jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | Aprende a moverte, saltar, ir en vehiculos y atacar entidades cercanas |\n|[ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | Muestra todos los mensajes que mandan al chat en tu consola con sus colores correspondientes |\n|[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Haz un bot que defienda un área predefinida de mobs |\n|[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Usa un archivo de texto con cuentas para crear bots |\n\nMás ejemplos en la carpeta de [ejemplos](https://github.com/PrismarineJS/mineflayer/tree/master/examples)\n\n### Módulos\n\nLa mayoría del desarrollo se está produciendo dentro de pequeños módulos npm que son usados por mineflayer\n\n#### The Node Way&trade;\n\n> \"When applications are done well, they are just the really application-specific, brackish residue that can't be so easily abstracted away. All the nice, reusable components sublimate away onto github and npm where everybody can collaborate to advance the commons.\" — substack from [\"how I write modules\"](https://gist.github.com/substack/5075355)\n\n#### Módulos\nEstos son los módulos principales que forman mineflayer:\n\n| módulo | descripción |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Analiza y crea paquetes de minecraft, autentificación and encriptación.\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | Módulo independiente del lenguaje que provee datos de minecraft para clientes, servidores y librerías.\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) | Motor de físicas para las entidades de minecraft\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | Representa un chunk de minecraft\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | Usa vectores 3d con pruebas sólidas\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | Representa un bloque y su información asociada de Minecraft\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | Analizador para los mensajes de chat de minecraft (extraído de mineflayer)\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Librería Node.js para interactuar con el sistema de autentificación de Mojang conocido como Yggdrasil.\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | Implementación principal de los mundos de Minecraft para Prismarine\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | Representa las interfaces de minecraft\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | Representa un item y su información asociada de Minecraft\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | Analizador de NBT para node-minecraft-protocol\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | Representa recetas/crafteos de Minecraft\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | Representa un bioma y su información asociada de Minecraft\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) | Representa una entidad y su información asociada de Minecraft\n\n### Depuración\n\nPuedes habilitar la depuración del protocolo utilizando la variable de entorno `DEBUG`:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nEn windows :\n```\nset DEBUG=minecraft-protocol\nnode tu_archivo.js\n```\n## Plugins de terceros\n\nMineflayer tiene la capacidad de instalar plugins; cualquiera puede crear un plugin que agregue\nun API de nivel superior a Mineflayer.\n\nLos más actualizados y útiles son:\n\n * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - algoritmo de busqueda A* avanzado con muchas características configurables\n * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - visualizador de chunks en la web\n * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - visualizador de inventario en la web\n * [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - API para comportamientos más complejos\n * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - gestión automática de armaduras\n * [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - API rápida y simple para recolectar bloques.\n * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Panel de instrumentos para un bot de Mineflayer\n * [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - API sencilla para PVP y PVE.\n * [auto-eat](https://github.com/LINKdiscordd/mineflayer-auto-eat) - Plugin para comer automáticamente.\n * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - Plugin con un API de alto nivel para seleccionar automáticamente la mejor arma/herramienta.\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - Plugin para apuntar automáticamente con arcos.\n\n\nPero también echa un vistazo a:\n\n * [radar](https://github.com/andrewrk/mineflayer-radar/) - interfaz de radar en la web utilizando canvas y socket.io [Demo en Youtube](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n * [blockfinder](https://github.com/Darthfett/mineflayer-blockFinder) - encuentra bloques en el mundo tridimensional\n * [scaffold](https://github.com/andrewrk/mineflayer-scaffold) - ir a un destino específico incluso si es necesario construir o rompler bloques para lograrlo [Demo en Youtube](http://youtu.be/jkg6psMUSE0)\n * [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - autentificación automática por chat\n * [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - determina quién y/o qué es responsable de dañar a otra entidad\n * [tps](https://github.com/SiebeDW/mineflayer-tps) - obtener el tps actual (tps procesado)\n * [panorama](https://github.com/IceTank/mineflayer-panorama) - toma imágenes panorámicas de tu mundo\n\n## Proyectos que utilizan Mineflayer\n\n * [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - construyendo una escalera en espiral](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - replicando una estructura](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n * [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualiza que está\n   haciendo el bot, utilizando voxel.js\n * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) -  registra la actividad de un jugador en una API en línea\n * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (última versión de código libre, creada por AlexKvazos) -  Interfaz de chat en la web para Minecraft <https://minecraftchat.net/>\n * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - bot con una interfaz limpia. Hecho con Node-Webkit. http://bot.ezcha.net/\n * [Chaoscraft](https://github.com/schematical/chaoscraft) - bot de Minecraft que utiliza algoritmos genéticos, ver [sus videos de youtube](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) -  puente para Telegram, hecho con Mineflayer y Telegraf.\n * [and hundreds more](https://github.com/PrismarineJS/mineflayer/network/dependents) - todos los proyectos que usan mineflayer y que han sido detectados por github\n\n## Pruebas\n\n### Ejecuta todas las pruebas\n\nSimplemente ejecuta:\n\n```bash\nnpm test\n```\n\n### Ejecuta pruebas para una versión específica de Minecraft\n\nEjecuta\n```bash\nnpm test -- -g <version>\n```\n\ndonde `<version>` es una versión de minecraft como `1.12`, `1.15.2`...\n\n### Ejecuta una prueba específica\n\nEjecuta\n```bash\nnpm test -- -g <test_name>\n```\n\ndonde `<test_name>` es el nombre de la prueba que quieres ejecutar como `bed`, `useChests`, `rayTrace`...\n\n## Licencia\n\n[MIT](../../LICENSE)\n\n\nEsta documentación no está mantenida oficialmente, si quiere ver las últimas novedades, por favor dirijase a la documentación original: [unstable_api](../README.md)\n"
  },
  {
    "path": "docs/es/api_es.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Tabla de contenidos**  *generado con [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API](#api)\n  - [Enums](#enums)\n    - [minecraft-data](#minecraft-data)\n    - [mcdata.blocks](#mcdatablocks)\n    - [mcdata.items](#mcdataitems)\n    - [mcdata.materials](#mcdatamaterials)\n    - [mcdata.recipes](#mcdatarecipes)\n    - [mcdata.instruments](#mcdatainstruments)\n    - [mcdata.biomes](#mcdatabiomes)\n    - [mcdata.entities](#mcdataentities)\n  - [Clases](#clases)\n    - [vec3](#vec3)\n    - [mineflayer.Location](#mineflayerlocation)\n    - [Entity](#entity)\n    - [Block](#block)\n    - [Biome](#biome)\n    - [Item](#item)\n    - [windows.Window (base class)](#windowswindow-base-class)\n      - [window.deposit(itemType, metadata, count, [callback])](#windowdeposititemtype-metadata-count-callback)\n      - [window.withdraw(itemType, metadata, count, [callback])](#windowwithdrawitemtype-metadata-count-callback)\n      - [window.close()](#windowclose)\n    - [Recipe](#recipe)\n    - [mineflayer.Container](#mineflayercontainer)\n    - [mineflayer.Furnace](#mineflayerfurnace)\n      - [furnace \"update\"](#furnace-update)\n      - [furnace.takeInput([callback])](#furnacetakeinputcallback)\n      - [furnace.takeFuel([callback])](#furnacetakefuelcallback)\n      - [furnace.takeOutput([callback])](#furnacetakeoutputcallback)\n      - [furnace.putInput(itemType, metadata, count, [cb])](#furnaceputinputitemtype-metadata-count-cb)\n      - [furnace.putFuel(itemType, metadata, count, [cb])](#furnaceputfuelitemtype-metadata-count-cb)\n      - [furnace.inputItem()](#furnaceinputitem)\n      - [furnace.fuelItem()](#furnacefuelitem)\n      - [furnace.outputItem()](#furnaceoutputitem)\n      - [furnace.fuel](#furnacefuel)\n      - [furnace.progress](#furnaceprogress)\n    - [mineflayer.EnchantmentTable](#mineflayerenchantmenttable)\n      - [enchantmentTable \"ready\"](#enchantmenttable-ready)\n      - [enchantmentTable.targetItem()](#enchantmenttabletargetitem)\n      - [enchantmentTable.xpseed](#enchantmenttablexpseed)\n      - [enchantmentTable.enchantments](#enchantmenttableenchantments)\n      - [enchantmentTable.enchant(choice, [callback])](#enchantmenttableenchantchoice-callback)\n      - [enchantmentTable.takeTargetItem([callback])](#enchantmenttabletaketargetitemcallback)\n      - [enchantmentTable.putTargetItem(item, [callback])](#enchantmenttableputtargetitemitem-callback)\n      - [enchantmentTable.putLapis(item, [callback])](#enchantmenttableputlapisitem-callback)\n    - [mineflayer.anvil](#mineflayeranvil)\n      - [anvil.combine(itemOne, itemTwo[, name, callback])](#anvilcombineitemone-itemtwo-name-callback)\n      - [anvil.combine(item[, name, callback])](#anvilcombineitem-name-callback)\n      - [villager \"ready\"](#villager-ready)\n      - [villager.trades](#villagertrades)\n      - [villager.trade(tradeIndex, [times], [cb])](#villagertradetradeindex-times-cb)\n    - [mineflayer.ScoreBoard](#mineflayerscoreboard)\n      - [ScoreBoard.name](#scoreboardname)\n      - [ScoreBoard.title](#scoreboardtitle)\n      - [ScoreBoard.itemsMap](#scoreboarditemsmap)\n      - [ScoreBoard.items](#scoreboarditems)\n    - [mineflayer.BossBar](#mineflayerbossbar)\n      - [BossBar.title](#bossbartitle)\n      - [BossBar.health](#bossbarhealth)\n      - [BossBar.dividers](#bossbardividers)\n      - [BossBar.entityUUID](#bossbarentityuuid)\n      - [BossBar.shouldDarkenSky](#bossbarshoulddarkensky)\n      - [BossBar.isDragonBar](#bossbarisdragonbar)\n      - [BossBar.createFog](#bossbarcreatefog)\n      - [BossBar.color](#bossbarcolor)\n  - [Bot](#bot)\n    - [mineflayer.createBot(options)](#mineflayercreatebotoptions)\n    - [Properties](#properties)\n      - [bot.world](#botworld)\n        - [world \"blockUpdate\" (oldBlock, newBlock)](#world-blockupdate-oldblock-newblock)\n        - [world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#world-blockupdatex-y-z-oldblock-newblock)\n      - [bot.entity](#botentity)\n      - [bot.entities](#botentities)\n      - [bot.username](#botusername)\n      - [bot.spawnPoint](#botspawnpoint)\n      - [bot.heldItem](#bothelditem)\n      - [bot.game.levelType](#botgameleveltype)\n      - [bot.game.dimension](#botgamedimension)\n      - [bot.game.difficulty](#botgamedifficulty)\n      - [bot.game.gameMode](#botgamegamemode)\n      - [bot.game.hardcore](#botgamehardcore)\n      - [bot.game.maxPlayers](#botgamemaxplayers)\n      - [bot.game.serverBrand](#botgameserverbrand)\n    - [bot.physicsEnabled](#botphysicsenabled)\n    - [bot.player](#botplayer)\n      - [bot.players](#botplayers)\n      - [bot.isRaining](#botisraining)\n      - [bot.rainState](#botrainstate)\n      - [bot.thunderState](#botthunderstate)\n      - [bot.chatPatterns](#botchatpatterns)\n      - [bot.settings.chat](#botsettingschat)\n      - [bot.settings.colorsEnabled](#botsettingscolorsenabled)\n      - [bot.settings.viewDistance](#botsettingsviewdistance)\n      - [bot.settings.difficulty](#botsettingsdifficulty)\n      - [bot.settings.skinParts](#botsettingsskinparts)\n        - [bot.settings.skinParts.showCape](#botsettingsskinpartsshowcape)\n        - [bot.settings.skinParts.showJacket](#botsettingsskinpartsshowjacket)\n        - [bot.settings.skinParts.showLeftSleeve](#botsettingsskinpartsshowleftsleeve)\n        - [bot.settings.skinParts.showRightSleeve](#botsettingsskinpartsshowrightsleeve)\n        - [bot.settings.skinParts.showLeftPants](#botsettingsskinpartsshowleftpants)\n        - [bot.settings.skinParts.showRightPants](#botsettingsskinpartsshowrightpants)\n        - [bot.settings.skinParts.showHat](#botsettingsskinpartsshowhat)\n      - [bot.experience.level](#botexperiencelevel)\n      - [bot.experience.points](#botexperiencepoints)\n      - [bot.experience.progress](#botexperienceprogress)\n      - [bot.health](#bothealth)\n      - [bot.food](#botfood)\n      - [bot.foodSaturation](#botfoodsaturation)\n      - [bot.oxygenLevel](#botoxygenlevel)\n      - [bot.physics](#botphysics)\n      - [bot.simpleClick.leftMouse (slot)](#botsimpleclickleftmouse-slot)\n      - [bot.simpleClick.rightMouse (slot)](#botsimpleclickrightmouse-slot)\n      - [bot.time.doDaylightCycle](#bottimedodaylightcycle)\n      - [bot.time.bigTime](#bottimebigtime)\n      - [bot.time.time](#bottimetime)\n      - [bot.time.timeOfDay](#bottimetimeofday)\n      - [bot.time.day](#bottimeday)\n      - [bot.time.isDay](#bottimeisday)\n      - [bot.time.moonPhase](#bottimemoonphase)\n      - [bot.time.bigAge](#bottimebigage)\n      - [bot.time.age](#bottimeage)\n      - [bot.quickBarSlot](#botquickbarslot)\n      - [bot.inventory](#botinventory)\n      - [bot.targetDigBlock](#bottargetdigblock)\n      - [bot.isSleeping](#botissleeping)\n      - [bot.scoreboards](#botscoreboards)\n      - [bot.scoreboard](#botscoreboard)\n      - [bot.controlState](#botcontrolstate)\n    - [Events](#events)\n      - [\"chat\" (username, message, translate, jsonMsg, matches)](#chat-username-message-translate-jsonmsg-matches)\n      - [\"whisper\" (username, message, translate, jsonMsg, matches)](#whisper-username-message-translate-jsonmsg-matches)\n      - [\"actionBar\" (jsonMsg)](#actionbar-jsonmsg)\n      - [\"message\" (jsonMsg, position)](#message-jsonmsg-position)\n      - [\"messagestr\" (message, messagePosition, jsonMsg)](#messagestr-message-messageposition-jsonmsg)\n      - [\"inject_allowed\"](#inject_allowed)\n      - [\"login\"](#login)\n      - [\"spawn\"](#spawn)\n      - [\"respawn\"](#respawn)\n      - [\"game\"](#game)\n      - [\"resourcePack\" (url, hash)](#resourcepack-url-hash)\n      - [\"title\" (title, type)](#title-title-type)\n      - [\"rain\"](#rain)\n      - [\"weatherUpdate\"](#weatherupdate)\n      - [\"time\"](#time)\n      - [\"kicked\" (reason, loggedIn)](#kicked-reason-loggedin)\n      - [\"end\"](#end)\n      - [\"error\" (err)](#error-err)\n      - [\"spawnReset\"](#spawnreset)\n      - [\"death\"](#death)\n      - [\"health\"](#health)\n      - [\"breath\"](#breath)\n      - [\"entitySwingArm\" (entity)](#entityswingarm-entity)\n      - [\"entityHurt\" (entity)](#entityhurt-entity)\n      - [\"entityDead\" (entity)](#entitydead-entity)\n      - [\"entityTaming\" (entity)](#entitytaming-entity)\n      - [\"entityTamed\" (entity)](#entitytamed-entity)\n      - [\"entityShakingOffWater\" (entity)](#entityshakingoffwater-entity)\n      - [\"entityEatingGrass\" (entity)](#entityeatinggrass-entity)\n      - [\"entityWake\" (entity)](#entitywake-entity)\n      - [\"entityEat\" (entity)](#entityeat-entity)\n      - [\"entityCriticalEffect\" (entity)](#entitycriticaleffect-entity)\n      - [\"entityMagicCriticalEffect\" (entity)](#entitymagiccriticaleffect-entity)\n      - [\"entityCrouch\" (entity)](#entitycrouch-entity)\n      - [\"entityUncrouch\" (entity)](#entityuncrouch-entity)\n      - [\"entityEquip\" (entity)](#entityequip-entity)\n      - [\"entitySleep\" (entity)](#entitysleep-entity)\n      - [\"entitySpawn\" (entity)](#entityspawn-entity)\n      - [\"itemDrop\" (entity)](#itemdrop-entity)\n      - [\"playerCollect\" (collector, collected)](#playercollect-collector-collected)\n      - [\"entityGone\" (entity)](#entitygone-entity)\n      - [\"entityMoved\" (entity)](#entitymoved-entity)\n      - [\"entityDetach\" (entity, vehicle)](#entitydetach-entity-vehicle)\n      - [\"entityAttach\" (entity, vehicle)](#entityattach-entity-vehicle)\n      - [\"entityUpdate\" (entity)](#entityupdate-entity)\n      - [\"entityEffect\" (entity, effect)](#entityeffect-entity-effect)\n      - [\"entityEffectEnd\" (entity, effect)](#entityeffectend-entity-effect)\n      - [\"playerJoined\" (player)](#playerjoined-player)\n      - [\"playerUpdated\" (player)](#playerupdated-player)\n      - [\"playerLeft\" (player)](#playerleft-player)\n      - [\"blockUpdate\" (oldBlock, newBlock)](#blockupdate-oldblock-newblock)\n      - [\"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#blockupdatex-y-z-oldblock-newblock)\n      - [\"blockPlaced\" (oldBlock, newBlock)](#blockplaced-oldblock-newblock)\n      - [\"chunkColumnLoad\" (point)](#chunkcolumnload-point)\n      - [\"chunkColumnUnload\" (point)](#chunkcolumnunload-point)\n      - [\"soundEffectHeard\" (soundName, position, volume, pitch)](#soundeffectheard-soundname-position-volume-pitch)\n      - [\"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)](#hardcodedsoundeffectheard-soundid-soundcategory-position-volume-pitch)\n      - [\"noteHeard\" (block, instrument, pitch)](#noteheard-block-instrument-pitch)\n      - [\"pistonMove\" (block, isPulling, direction)](#pistonmove-block-ispulling-direction)\n      - [\"chestLidMove\" (block, isOpen, block2)](#chestlidmove-block-isopen-block2)\n      - [\"blockBreakProgressObserved\" (block, destroyStage)](#blockbreakprogressobserved-block-destroystage)\n      - [\"blockBreakProgressEnd\" (block)](#blockbreakprogressend-block)\n      - [\"diggingCompleted\" (block)](#diggingcompleted-block)\n      - [\"diggingAborted\" (block)](#diggingaborted-block)\n      - [\"move\"](#move)\n      - [\"forcedMove\"](#forcedmove)\n      - [\"mount\"](#mount)\n      - [\"dismount\" (vehicle)](#dismount-vehicle)\n      - [\"windowOpen\" (window)](#windowopen-window)\n      - [\"windowClose\" (window)](#windowclose-window)\n      - [\"sleep\"](#sleep)\n      - [\"wake\"](#wake)\n      - [\"experience\"](#experience)\n      - [\"scoreboardCreated\" (scoreboard)](#scoreboardcreated-scoreboard)\n      - [\"scoreboardDeleted\" (scoreboard)](#scoreboarddeleted-scoreboard)\n      - [\"scoreboardTitleChanged\" (scoreboard)](#scoreboardtitlechanged-scoreboard)\n      - [\"scoreUpdated\" (scoreboard, item)](#scoreupdated-scoreboard-item)\n      - [\"scoreRemoved\" (scoreboard, item)](#scoreremoved-scoreboard-item)\n      - [\"scoreboardPosition\" (position, scoreboard)](#scoreboardposition-position-scoreboard)\n      - [\"bossBarCreated\" (bossBar)](#bossbarcreated-bossbar)\n      - [\"bossBarDeleted\" (bossBar)](#bossbardeleted-bossbar)\n      - [\"bossBarUpdated\" (bossBar)](#bossbarupdated-bossbar)\n      - [\"heldItemChanged\" (heldItem)](#helditemchanged-helditem)\n      - [\"physicsTick\" ()](#physicstick-)\n      - [\"chat:name\" (matches)](#chatname-matches)\n    - [Functions](#functions)\n      - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)\n      - [bot.waitForChunksToLoad(cb)](#botwaitforchunkstoloadcb)\n      - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)\n      - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)\n      - [bot.canSeeBlock(block)](#botcanseeblockblock)\n      - [bot.findBlocks(options)](#botfindblocksoptions)\n      - [bot.findBlock(options)](#botfindblockoptions)\n      - [bot.canDigBlock(block)](#botcandigblockblock)\n      - [bot.recipesFor(itemType, metadata, minResultCount, craftingTable)](#botrecipesforitemtype-metadata-minresultcount-craftingtable)\n      - [bot.recipesAll(itemType, metadata, craftingTable)](#botrecipesallitemtype-metadata-craftingtable)\n      - [bot.nearestEntity(match = (entity) => { return true })](#botnearestentitymatch--entity---return-true-)\n    - [Methods](#methods)\n      - [bot.end()](#botend)\n      - [bot.quit(reason)](#botquitreason)\n      - [bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])](#bottabcompletestr-cb-assumecommand-sendblockinsight)\n      - [bot.chat(message)](#botchatmessage)\n      - [bot.whisper(username, message)](#botwhisperusername-message)\n      - [bot.chatAddPattern(pattern, chatType, description)](#botchataddpatternpattern-chattype-description)\n      - [bot.addChatPattern(name, pattern, chatPatternOptions)](#botaddchatpatternname-pattern-chatpatternoptions)\n      - [bot.addChatPatternSet(name, patterns, chatPatternOptions)](#botaddchatpatternsetname-patterns-chatpatternoptions)\n      - [bot.removeChatPattern(name)](#botremovechatpatternname)\n      - [bot.awaitMessage(...args)](#botawaitmessageargs)\n      - [bot.setSettings(options)](#botsetsettingsoptions)\n      - [bot.loadPlugin(plugin)](#botloadpluginplugin)\n      - [bot.loadPlugins(plugins)](#botloadpluginsplugins)\n      - [bot.hasPlugin(plugin)](#bothaspluginplugin)\n      - [bot.sleep(bedBlock, [cb])](#botsleepbedblock-cb)\n      - [bot.isABed(bedBlock)](#botisabedbedblock)\n      - [bot.wake([cb])](#botwakecb)\n      - [bot.setControlState(control, state)](#botsetcontrolstatecontrol-state)\n      - [bot.getControlState(control)](#botgetcontrolstatecontrol)\n      - [bot.clearControlStates()](#botclearcontrolstates)\n      - [bot.lookAt(point, [force], [callback])](#botlookatpoint-force-callback)\n      - [bot.look(yaw, pitch, [force], [callback])](#botlookyaw-pitch-force-callback)\n      - [bot.updateSign(block, text)](#botupdatesignblock-text)\n      - [bot.equip(item, destination, [callback])](#botequipitem-destination-callback)\n      - [bot.unequip(destination, [callback])](#botunequipdestination-callback)\n      - [bot.tossStack(item, [callback])](#bottossstackitem-callback)\n      - [bot.toss(itemType, metadata, count, [callback])](#bottossitemtype-metadata-count-callback)\n      - [bot.dig(block, [forceLook = true], [digFace], [callback])](#botdigblock-forcelook--true-digface-callback)\n      - [bot.stopDigging()](#botstopdigging)\n      - [bot.digTime(block)](#botdigtimeblock)\n      - [bot.acceptResourcePack()](#botacceptresourcepack)\n      - [bot.denyResourcePack()](#botdenyresourcepack)\n      - [bot.placeBlock(referenceBlock, faceVector, cb)](#botplaceblockreferenceblock-facevector-cb)\n      - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)\n      - [bot.activateBlock(block, [callback])](#botactivateblockblock-callback)\n      - [bot.activateEntity(entity, [callback])](#botactivateentityentity-callback)\n      - [bot.activateEntityAt(entity, position, [callback])](#botactivateentityatentity-position-callback)\n      - [bot.consume(callback)](#botconsumecallback)\n      - [bot.fish(callback)](#botfishcallback)\n      - [bot.activateItem(offHand=false)](#botactivateitemoffhandfalse)\n      - [bot.deactivateItem()](#botdeactivateitem)\n      - [bot.useOn(targetEntity)](#botuseontargetentity)\n      - [bot.attack(entity)](#botattackentity)\n      - [bot.swingArm([hand], showHand)](#botswingarmhand-showhand)\n      - [bot.mount(entity)](#botmountentity)\n      - [bot.dismount()](#botdismount)\n      - [bot.moveVehicle(left,forward)](#botmovevehicleleftforward)\n      - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)\n      - [bot.craft(recipe, count, craftingTable, [callback])](#botcraftrecipe-count-craftingtable-callback)\n      - [bot.writeBook(slot, pages, [callback])](#botwritebookslot-pages-callback)\n      - [bot.openContainer(containerBlock or containerEntity)](#botopencontainercontainerblock-or-containerentity)\n      - [bot.openChest(chestBlock or minecartchestEntity)](#botopenchestchestblock-or-minecartchestentity)\n      - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)\n      - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)\n      - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)\n      - [bot.openAnvil(anvilBlock)](#botopenanvilanvilblock)\n      - [bot.openVillager(villagerEntity)](#botopenvillagervillagerentity)\n      - [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n      - [bot.setCommandBlock(pos, command, [options])](#botsetcommandblockpos-command-options)\n      - [bot.supportFeature(name)](#botsupportfeaturename)\n      - [bot.waitForTicks(ticks)](#botwaitforticksticks)\n    - [Lower level inventory methods](#lower-level-inventory-methods)\n      - [bot.clickWindow(slot, mouseButton, mode, cb)](#botclickwindowslot-mousebutton-mode-cb)\n      - [bot.putSelectedItemRange(start, end, window, slot)](#botputselecteditemrangestart-end-window-slot)\n      - [bot.putAway(slot)](#botputawayslot)\n      - [bot.closeWindow(window)](#botclosewindowwindow)\n      - [bot.transfer(options, cb)](#bottransferoptions-cb)\n      - [bot.openBlock(block)](#botopenblockblock)\n      - [bot.openEntity(entity)](#botopenentityentity)\n      - [bot.moveSlotItem(sourceSlot, destSlot, cb)](#botmoveslotitemsourceslot-destslot-cb)\n      - [bot.updateHeldItem()](#botupdatehelditem)\n      - [bot.getEquipmentDestSlot(destination)](#botgetequipmentdestslotdestination)\n    - [bot.creative](#botcreative)\n      - [bot.creative.setInventorySlot(slot, item, [callback])](#botcreativesetinventoryslotslot-item-callback)\n      - [bot.creative.flyTo(destination, [cb])](#botcreativeflytodestination-cb)\n      - [bot.creative.startFlying()](#botcreativestartflying)\n      - [bot.creative.stopFlying()](#botcreativestopflying)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API\n\n## Enums\n\nEstos enums están guardados en un proyecto independiente del lenguaje [minecraft-data](https://github.com/PrismarineJS/minecraft-data),\n y accedidos por [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\n### minecraft-data\nLos datos están disponibles en el módulo [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data)\n\n`require('minecraft-data')(bot.version)` te da acceso a él.\n\n### mcdata.blocks\nbloques ordenados por id\n\n### mcdata.items\nitems ordenados por id\n\n### mcdata.materials\n\nEl key es el material. El valor es un objeto con key como el id de la herramienta y el valor es el multiplicador de eficiencia.\n\n### mcdata.recipes\nrecetas ordenadas por id\n\n### mcdata.instruments\nherramientas ordenadas por id\n\n### mcdata.biomes\nbiomas ordenados por id\n\n### mcdata.entities\nentidades ordenadas por id\n\n## Clases\n\n### vec3\n\nMira [andrewrk/node-vec3](https://github.com/andrewrk/node-vec3)\n\nTodos los puntos en mineflayer son instancias de esta clase.\n\n * x - south\n * y - up\n * z - west\n\nLas funciones y los métodos que necesitan un punto aceptan instancias `Vec3`, un array con 3 valores, y un objeto con las propiedades `x`, `y`, y `z`.\n\n### mineflayer.Location\n\n### Entity\n\nLas entidades representan jugadores, mobs, y objetos. Se emiten en muchos eventos, pero puedes acceder a tu propia entidad con `bot.entity`.\nMira [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)\n\n### Block\n\nMira [prismarine-block](https://github.com/PrismarineJS/prismarine-block)\n\nTambién, `block.blockEntity` es un campo adicional con los datos de la entidad del bloque como `Object`\n```js\n// sign.blockEntity\n{\n  x: -53,\n  y: 88,\n  z: 66,\n  id: 'minecraft:sign', // 'Sign' in 1.10\n  Text1: { toString: Function }, // ChatMessage object\n  Text2: { toString: Function }, // ChatMessage object\n  Text3: { toString: Function }, // ChatMessage object\n  Text4: { toString: Function } // ChatMessage object\n}\n```\n\n### Biome\n\nMira [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome)\n\n### Item\n\nMira [prismarine-item](https://github.com/PrismarineJS/prismarine-item)\n\n### windows.Window (base class)\n\nMira [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows)\n\n#### window.deposit(itemType, metadata, count, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `itemType` - id numérico del item\n * `metadata` - valor numérico. `null` significa que conicide cualquiera.\n * `count` - cuantos items hay que depositar. `null` es un alias de 1.\n * `callback(err)` - (opcional) - ejecutado al finalizar\n\n#### window.withdraw(itemType, metadata, count, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `itemType` - id numérico del item\n * `metadata` - valor numérico. `null` significa que coincide cualquiera.\n * `count` - cuantos items hay que retirar. `null` es un alias de 1.\n * `callback(err)` - (opcional) - ejecutado al finalizar\n\n#### window.close()\n\nCierra la interfaz/ventana\n\n### Recipe\n\nMira [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)\n\n### mineflayer.Container\n\nExtiende windows.Window para cofres, dispensadores, etc...\nMira `bot.openContainer(chestBlock o minecartchestEntity)`.\n\n### mineflayer.Furnace\n\nExtiende windows.Window para hornos, fundidores, etc...\nMira `bot.openFurnace(funaceBlock)`.\n\n#### furnace \"update\"\n\nSe emite cuando `furnace.fuel` y/o `furnace.progress` se actualizan.\n\n#### furnace.takeInput([callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err, item)`\n\n#### furnace.takeFuel([callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err, item)`\n\n#### furnace.takeOutput([callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err, item)`\n\n#### furnace.putInput(itemType, metadata, count, [cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n#### furnace.putFuel(itemType, metadata, count, [cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n#### furnace.inputItem()\n\nDevuelve una instancia `Item` que es el item de entrada.\n\n#### furnace.fuelItem()\n\nDevuelve una instancia `Item` que es el combustible\n\n#### furnace.outputItem()\n\nDevuelve una instancia `Item` que es el item de salida.\n\n#### furnace.fuel\n\nCuanto combustible queda del 0 al 1\n\n#### furnace.progress\n\nCuanto esta hecho el item del 0 al 1\n\n### mineflayer.EnchantmentTable\n\nExtiende windows.Window para mesas de encantamiento\nMira `bot.openEnchantmentTable(enchantmentTableBlock)`.\n\n#### enchantmentTable \"ready\"\n\nSe emite cuando `enchantmentTable.enchantments` está completo y puedes elegir un encantamiento ejecutando `enchantmentTable.enchant(choice)`.\n\n#### enchantmentTable.targetItem()\n\nDevuelve los items de entrada y de salida\n\n#### enchantmentTable.xpseed\n\nLa semilla de XP de 16 bits mandada por el servidor\n\n#### enchantmentTable.enchantments\n\nArray de longitud 3 donde están 3 encantamientos que puedes elegir.\n`level` puede ser `-1` si el servidor no ha mandado los datos todavía\n\nSe parece a:\n\n```js\n[\n  {\n    level: 3\n  },\n  {\n    level: 4\n  },\n  {\n    level: 9\n  }\n]\n```\n\n#### enchantmentTable.enchant(choice, [callback])\n\nEsta función también devueve un `Promise`, con `item` como argumento al finalizar.\n\n * `choice` - [0-2], el índice del encantamiento que quieres escoger.\n * `callback(err, item)` - (opcional) ejecutado al finalizar\n\n#### enchantmentTable.takeTargetItem([callback])\n\nEsta función también devueve un `Promise`, con `item` como argumento al finalizar.\n\n * `callback(err, item)`\n\n#### enchantmentTable.putTargetItem(item, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err)`\n\n#### enchantmentTable.putLapis(item, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err)`\n\n### mineflayer.anvil\n\nExtiende windows.Window para yunques\nMira `bot.openAnvil(anvilBlock)`.\n\n#### anvil.combine(itemOne, itemTwo[, name, callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err)` - para poder usar el callback, el nombre tiene que estar vacío ('')\n\n#### anvil.combine(item[, name, callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `callback(err)`\n\n#### villager \"ready\"\n\nSe emite cuando `villager.trades` se ha cargado.\n\n#### villager.trades\n\nArray de tradeos\n\nSe parece a:\n\n```js\n[\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: true,\n    secondaryInput: Item,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  }\n]\n```\n\n#### villager.trade(tradeIndex, [times], [cb])\nEs el mismo que [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n\n### mineflayer.ScoreBoard\n\n#### ScoreBoard.name\n\nNombre del scoreboard.\n\n#### ScoreBoard.title\n\nEl título del scoreboard (no es siempre igual al nombre)\n\n#### ScoreBoard.itemsMap\n\nUn object con todos los items del scoreboard en él\n```js\n{\n  wvffle: { name: 'wvffle', value: 3 },\n  dzikoysk: { name: 'dzikoysk', value: 6 }\n}\n```\n\n#### ScoreBoard.items\n\nUn array con todos los items en el scoreboard en él\n```js\n[\n  { name: 'dzikoysk', value: 6 },\n  { name: 'wvffle', value: 3 }\n]\n```\n\n### mineflayer.BossBar\n\n#### BossBar.title\n\nTítulo de la barra de vida del jefe, instancia de ChatMessage\n\n#### BossBar.health\n\nPorcentaje de la vida del jefe, del `0` al `1`\n\n#### BossBar.dividers\n\nNúmero de separadores en la barra, puede ser `0`, `6`, `10`, `12` o `20`\n\n#### BossBar.entityUUID\n\nUUID de la entidad del jefe\n\n#### BossBar.shouldDarkenSky\n\nDetermina si el cielo debería oscurecerse o no\n\n#### BossBar.isDragonBar\n\nDetermina si la barra es la barra de vida del dragón\n\n#### BossBar.createFog\n\nDetermina si la barra crea niebla o no\n\n#### BossBar.color\n\nDetermina el color de la barra entre `pink`, `blue`, `red`, `green`, `yellow`, `purple` y `white` (`rosa`, `azul`, `rojo`, `verde`, `amarillo`, `morado` y `blanco`)\n\n## Bot\n\n### mineflayer.createBot(options)\n\nCrea y devuelve una instancia de la clase Bot.\n`options` es un object que contiene las propiedades opcionales :\n * username : (usuario) el valor predeterminado es 'Player'\n * port : (puerto) el valor predeterminado es 25565\n * password : (contraseña) se puede omitir (si los tokens también son omitidos intentará conectarse en modo offline)\n * host : (ip) el valor predeterminado es localhost\n * version : si se omite intentará averiguar automáticamente la versión. Por ejemplo : \"1.12.2\"\n * auth : (autentificación) el valor predeterminado es 'mojang', también puede ser 'microsoft'\n * clientToken : generado si se proporciona una contraseña\n * accessToken : generado si se proporciona una contraseña\n * logErrors : el valor predeterminado es true, retiene errores y los imprime\n * hideErrors : el valor predeterminado es true, para ocultar errores (incluso si logErrors es true)\n * keepAlive : manda paquetes keepAlive : el valor predeterminado es true\n * checkTimeoutInterval : el valor predeterminado es `30*1000` (30s), comprueba si el paquete keepAlive ha sido recibido en ese periodo, desconectar el bot si no ha sido recibido.\n * loadInternalPlugins : (cargarPluginsInternos) el valor predeterminado es true\n * storageBuilder : una función opcional, toma como argumentos la versión y el nombre del mundo (worldName) y devuelve una instancia de algo con la misma API que prismarine-provider-anvil. Se usará para guardar el mundo.\n * client : una instancia de node-minecraft-protocol, si no se especifíca, mineflayer creará su propio cliente. Esto sirve para usar mineflayer a través de un proxy de muchos clientes o para un cliente vanilla y un cliente mineflayer.\n * plugins : object : el valor predeterminado es {}\n   - pluginName : false : no cargar el plugin interno con ese nombre ej. `pluginName`\n   - pluginName : true : carga el plugin interno con ese nombre ej. `pluginName` incluso si loadInternalPlugins está en false\n   - pluginName : función para introducir : carga un plugin de terceros (externo), anula el plugin interno con el mismo nombre ej. `pluginName`\n * physicsEnabled : el valor predeterminado es true, si el bot debería ser afectado por las físicas, puede modificarse mediante bot.physicsEnabled\n * [chat](#bot.settings.chat)\n * [colorsEnabled](#bot.settings.colorsEnabled)\n * [viewDistance](#bot.settings.viewDistance)\n * [difficulty](#bot.settings.difficulty)\n * [skinParts](#bot.settings.skinParts)\n * chatLengthLimit : el valor máximo de carácteres que se pueden mandar con un solo mensaje. Si no se especifíca, será 100 en versiones anteriores a la 1.11 y 256 en la 1.11 a las posteriores de la 1.11\n\n### Properties\n\n#### bot.world\n\nUna representación sincronizada del mundo. Mira su documentación en http://github.com/PrismarineJS/prismarine-world\n\n##### world \"blockUpdate\" (oldBlock, newBlock)\n\nSe emite cuando un bloque se actualiza. Devuelve el bloque antiguo `oldBlock` y el bloque nuevo `newBlock`.\n\nNota: `oldBlock` podría ser `null`.\n\n##### world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\nSe emite cuando un bloque en una coordenada se actualiza. Devuelve el bloque antiguo `oldBlock` y el bloque nuevo `newBlock`.\n\nNota: `oldBlock` podría ser `null`.\n\n\n#### bot.entity\n\nTu propia entidad. Mira `Entity`.\n\n#### bot.entities\n\nTodas las entidades cercanas. Este object es un map de entityId (id de la entidad) a entity (entidad)\n\n#### bot.username\n\nUsa esto para averiguar tu propio nombre.\n\n#### bot.spawnPoint\n\nCoordenadas del punto de spawn, donde todas las brújulas apuntan.\n\n#### bot.heldItem\n\nEl item en la mano del bot, presentado como una instancia [prismarine-item](https://github.com/PrismarineJS/prismarine-item) especificado con su metadata, nbtdata, etc.\n\n#### bot.game.levelType\n\nTipo del nivel de juego\n\n#### bot.game.dimension\n\nTipo de dimension\n\n#### bot.game.difficulty\n\nTipo de dificultad de juego\n\n#### bot.game.gameMode\n\nGamemode del bot\n\n#### bot.game.hardcore\n\nSi el juego está en hardcore o no\n\n#### bot.game.maxPlayers\n\nEl número máximo de jugadores del juego\n\n#### bot.game.serverBrand\n\nLa marca del servidor\n\n### bot.physicsEnabled\n\nSi las físicas deberían habilitarse, el valor predeterminado es true.\n\n### bot.player\n\nObject del jugador del bot\n```js\n{\n  username: 'player',\n  displayName: { toString: Function }, // ChatMessage object.\n  gamemode: 0,\n  ping: 28,\n  entity: entity // null si estás demasiado lejos (fuera de la zona renderizada)\n}\n```\n\n#### bot.players\n\nMap de los nombres de los jugadores del juego\n\n#### bot.isRaining\n\n#### bot.rainState\n\nUn número indicano el nivel de lluvia actual. Si no está lloviendo, este valdrá 0. Cuando empiece a llover, el valor aumentará gradualmente a 1. Y cuando pare de llover, disminuirá gradualmente a 0.\n\nCada vez que `bot.rainState` cambia, se emitirá el evento \"weatherUpdate\"\n\n#### bot.thunderState\n\nUn número indicando el nivel de tormenta de rayos actual. Si no hay tormenta, este valdrá 0. Cuando empiece una tormenta, el valor aumentará gradualmente a 1. Y cuando pare la tormenta, disminuirá gradualmente a 0.\n\nCada vez que `bot.thunderState` cambia, se emitirá el evento \"weatherUpdate\".\n\nEsto es lo mismo que `bot.rainState`, pero para tormentas de rayos.\nPara tormentas de rayos, `bot.rainState` y `bot.thunderState` cambiarán.\n\n#### bot.chatPatterns\n\nEsto es un array de objects de patrones, del siguiente formato:\n{ /regex/, \"chattype\", \"description\")\n * /regex/ - un patrón regex, debería tener al menos dos grupos de captura\n * 'chattype' - el tipo de chat que debería coincidir, puede ser \"chat\" o \"whisper\" (susurro), o también puede ser cualquiera.\n * 'description' - descripción del patrón, opcional.\n\n#### bot.settings.chat\n\nOpciones:\n\n * `enabled` (habilitado) (predeterminado)\n * `commandsOnly` (soloComandos)\n * `disabled` (deshabilitado)\n\n#### bot.settings.colorsEnabled\n\nSu valor predeterminado es true, si debería recibir códigos de color del servidor\n\n#### bot.settings.viewDistance\n\nOpciones:\n * `far` (lejano) (predeterminado)\n * `normal`\n * `short` (cercano)\n * `tiny` (diminuto)\n\n#### bot.settings.difficulty\n\nLo mismo que server.properties.\n\n#### bot.settings.skinParts\n\nEstos booleans controlan si las partes externas de la skin del jugadordebería ser visible\n\n##### bot.settings.skinParts.showCape\n\nSi tienes una capa puedes desactivarla cambiando esto a false\n\n##### bot.settings.skinParts.showJacket\n\nSi debería mostrarse la skin externa del pecho\n\n##### bot.settings.skinParts.showLeftSleeve\n\nSi debería mostrarse la skin externa del brazo izquierdo\n\n##### bot.settings.skinParts.showRightSleeve\n\nSi debería mostrarse la skin externa del brazo derecho\n\n##### bot.settings.skinParts.showLeftPants\n\nSi debería mostrarse la skin externa de la pierna izquierda\n\n##### bot.settings.skinParts.showRightPants\n\nSi debería mostrarse la skin externa de la pierna derecha\n\n##### bot.settings.skinParts.showHat\n\nSi debería mostrarse la skin externa de la cabeza\n\n\n#### bot.experience.level\n\nEl nivel de experiencia del bot\n\n#### bot.experience.points\n\nTotal de los puntos de experiencia del bot\n\n#### bot.experience.progress\n\nEntre 0 y 1 - cantidad que falta para llegar al siguiente nivel.\n\n#### bot.health\n\nNúmeros entre el 0 y el 20 representando el número de mitades de corazón.\n\n#### bot.food\n\nNúmeros entre el 0 y el 20 representando el número de mitades de muslos de pollo.\n\n#### bot.foodSaturation\n\nLa saturación actúa como una \"sobrecarga\" de la comida. Si la saturación es mayor que 0, el nivel de la comida no disminuirá. Los jugadores que entran al juego automáticamente tienen una saturación de 5.0. Comer aumenta la saturación y el nivel de la comida.\n\n#### bot.oxygenLevel\n\nNúmero entre el 0 y el 20 representando el número de mitades de burbujas del nivel de oxígeno.\n\n#### bot.physics\n\nModifica estos números para cambiar la gravedad, velocidad del salto, velocidad terminal, etc. Hazlo bajo tu propio riesgo\n\n#### bot.simpleClick.leftMouse (slot)\n\nabstracción de `bot.clickWindow(slot, 0, 0)`\n\n#### bot.simpleClick.rightMouse (slot)\n\nabstracción de `bot.clickWindow(slot, 1, 0)`\n\n#### bot.time.doDaylightCycle\n\nSi el gamerule doDaylightCycle es true o false.\n\n#### bot.time.bigTime\n\nEl número total de ticks desde el día 0.\n\nEste valor es de tipo BigInt y es muy preciso incluso con valores muy grandes. (más de 2^51 - 1 tick)\n\n#### bot.time.time\n\nEl número total de ticks desde el día 0.\n\nYa que el límite de números en Javascript es de 2^51 - 1 bot.time.time es menos preciso en valores más altos que este límite, por eso es recomendado el uso de bot.time.bigTime.\nSiendo realistas, probablemente nunca tendrás que usar bot.time.bigTime ya que alcanzará naturalmente 2^51 - 1 tick tras ~14280821 años reales.\n\n#### bot.time.timeOfDay\n\nHora del día, en ticks.\n\nLa hora está basada en ticks, donde 20 ticks ocurren cada segundo. Hay 24000 ticks al día, haciendo que los días en Minecraft sean exactamente 20 minutos.\n\nLa hora del día está basada en el módulo timestamp 24000. 0 es el amanecer, 6000 es el mediodía, 12000 es el anochecer, y 18000 es medianoche.\n\n#### bot.time.day\n\nDía del mundo\n\n#### bot.time.isDay\n\nSi es de día o no.\n\nBasado en si la hora actual está entre 0 y 13000 ticks (día + atardecer).\n\n#### bot.time.moonPhase\n\nFase de la luna.\n\nEntre 0 y 7 donde 0 es luna llena.\n\n#### bot.time.bigAge\n\nEdad del mundo, en ticks\n\nEste valor es de tipo BigInt y es preciso incluso en valores muy altos. (más de 2^51 - 1 tick)\n\n#### bot.time.age\n\nAge of the world, in ticks.\n\nYa que el límite de números en Javascript es de 2^51 - 1 bot.time.age es menos preciso en valores más altos que este límite, por eso es recomendado el uso de bot.time.bigAge.\nSiendo realistas, probablemente nunca tendrás que usar bot.time.bigAge ya que alcanzará naturalmente 2^51 - 1 tick tras ~14280821 años reales.\n\n#### bot.quickBarSlot\n\nQue casilla está seleccionada en la barra de acceso rápido (0 - 8).\n\n#### bot.inventory\n\nUna instancia [`Window`](https://github.com/PrismarineJS/prismarine-windows#windowswindow-base-class) (ventana/interfaz) representando tu inventario.\n\n#### bot.targetDigBlock\n\nEl `block` (bloque) que estás picando/rompiendo en ese momento, o `null`.\n\n#### bot.isSleeping\n\nBoolean representando si estás durmiendo o no.\n\n#### bot.scoreboards\n\nTodos los scoreboards que el bot conoce en un object de forma nombre scoreboard -> scoreboard\n\n#### bot.scoreboard\n\nTodos los scoreboards que el bot conoce en un object de forma casilla de visualización -> scoreboard.\n\n * `belowName` - scoreboard que está debajo del nombre\n * `sidebar` - scoreboard que está en la barra del lado\n * `list` - scoreboard que está en la lista\n * `0-18` - casillas definidas en el [protocol](https://minecraft.wiki/w/Protocol#Display_Scoreboard)\n\n#### bot.controlState\n\nUn object que contiene los estados de control principales: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']. ('adelante', 'atrás', 'izquierda', 'derecha', 'salto', 'sprint/correr', 'agachado')\n\nEstos valores se pueden usar en [bot.setControlState](#botsetcontrolstatecontrol-state).\n\n### Events\n\n#### \"chat\" (username, message, translate, jsonMsg, matches)\n\nSolo se emite cuando un jugador chatea públicamente.\n\n * `username` - el jugador que ha mandado el mensaje (compáralo con `bot.username` para ignorar tus propios mensajes)\n * `message` - mensaje sin códigos de color\n * `translate` - tipo de mensaje de chat. Null para la mayoría de mensajes de bukkit\n * `jsonMsg` - mensaje JSON sin modificar del servidor\n * `matches` - array de las coincidencias devueltas de las expresiones regulares. Puede ser Null\n\n#### \"whisper\" (username, message, translate, jsonMsg, matches)\n\nSolos se emite cuando un jugador chatea contigo en privado (susurro).\n\n * `username` - el jugador que ha mandado el mensaje\n * `message` - mensaje sin códigos de color\n * `translate` - tipo de mensaje de chat. Null para la mayoría de mensajes de bukkit\n * `jsonMsg` - mensaje JSON sin modificar del servidor\n * `matches` - array de las coincidencias devueltas de las expresiones regulares. Puede ser Null\n\n#### \"actionBar\" (jsonMsg)\n\nSe emite por cada mensaje del servidor que aparece en la barra de acción.\n\n * `jsonMsg` - mensaje JSON sin modificar del servidor\n\n#### \"message\" (jsonMsg, position)\n\nSe emite por cada mensaje del servidor, incluye chats.\n\n * `jsonMsg` - mensaje JSON sin modificar del servidor\n\n * `position` - (>= 1.8.1): la posición del mensaje de chat puede ser\n   * chat\n   * system\n   * game_info\n\n#### \"messagestr\" (message, messagePosition, jsonMsg)\n\nParecido a \"message\" pero ejecuta .toString() en el mensaje JSON para obtener un string del mensaje antes de que se emita.\n\n#### \"inject_allowed\"\nSe enute cuando el archivo index se ha cargado, puedes cargar mcData o los plugins aquí, pero es mejor esperar al evento \"spawn\".\n\n#### \"login\"\n\nSe emite tras registrarse en el servidor.\nAunque probablemente quieras esperar al evento \"spawn\" antes de hacer algo.\n\n#### \"spawn\"\n\nSe emite cuando te registras y spawneas y cuando respawneas al morir.\n\nNormalmente este es el evento que quieres recibir antes de hacer algo en el servidor.\n\n#### \"respawn\"\n\nSe emite al cambiar dimensiones o justo antes de spawnear.\nNormalmente querrás ignorar este evento y esperar hasta que el evento \"spawn\" se emita.\n\n#### \"game\"\n\nSe emite cuando el servidor cambia cualquiera de sus propiedades\n\n#### \"resourcePack\" (url, hash)\n\nSe emite cuando el servidor manda un paquete de recursos\n\n#### \"title\" (title, type)\n\nSe emite cuando el servidor manda/muestra un título\n\n * `title` - texto del título\n * `type` - tipo del título \"subtitle\" o \"title\"\n\n#### \"rain\"\n\nSe emite cuando empieza a llover o cuando para. Si cuando entras a un servidor ya está lloviendo, este evento se emitirá.\n\n#### \"weatherUpdate\"\n\nSe emite cuando `bot.thunderState` o `bot.rainState` cambia.\nSi cuando entras a un servidor y está lloviendo, este evento se emitirá.\n\n#### \"time\"\n\nSe emite cuando el servidor cambia/actualiza su hora. Mira `bot.time`.\n\n#### \"kicked\" (reason, loggedIn)\n\nSe emite cuando el bot es echado del servidor. `reason` es un mensaje de chat con la razón del kickeo. `loggedIn` será `true` si el cliente ya estaba conectado cuando se le echó, y `false` si el cliente fue echado durante el proceso de registración.\n\n#### \"end\"\n\nSe emite cuando ya no estás conectado en el servidor.\n\n#### \"error\" (err)\n\nSe emite cuando ocurre un error.\n\n#### \"spawnReset\"\n\nSe emite cuando no puedes spawnear en tu cama, y se resetea tu spawn.\n\n#### \"death\"\n\nSe emite al morir\n\n#### \"health\"\n\nSe emite cuando tu vida o el nivel de comida cambia.\n\n#### \"breath\"\n\nSe emite cuando tu nivel de oxígeno cambia.\n\n#### \"entitySwingArm\" (entity)\n\nSe emite cuando una entidad mueve su brazo.\n\n#### \"entityHurt\" (entity)\n\nSe emite cuando una entidad se hace daño.\n\n#### \"entityDead\" (entity)\n\nSe emite cuando una entidad muere.\n\n#### \"entityTaming\" (entity)\n\nSe emite cuando una entidad está siendo domesticada.\n\n#### \"entityTamed\" (entity)\n\nSe emite cuando una entidad es domesticada.\n\n#### \"entityShakingOffWater\" (entity)\n\nSe emite cuando una entidad se seca (lobos por ejemplo).\n\n#### \"entityEatingGrass\" (entity)\n\nSe emite cuando una entidad come hierba.\n\n#### \"entityWake\" (entity)\n\nSe emite cuando una entidad se despierta.\n\n#### \"entityEat\" (entity)\n\nSe emite cuando una entidad come.\n\n#### \"entityCriticalEffect\" (entity)\n\nSe emite cuando una entidad recibe un ataque crítico.\n\n#### \"entityMagicCriticalEffect\" (entity)\n\nSe emite cuando una entidad recibe un ataque crítico con pociones.\n\n#### \"entityCrouch\" (entity)\n\nSe emite cuando una entidad se agacha.\n\n#### \"entityUncrouch\" (entity)\n\nSe emite cuando una entidad deja de agacharse.\n\n#### \"entityEquip\" (entity)\n\nSe emite cuando una entidad equipa algo.\n\n#### \"entitySleep\" (entity)\n\nSe emite cuando una entidad se duerme.\n\n#### \"entitySpawn\" (entity)\n\nSe emite cuando una entidad aparece.\n\n#### \"itemDrop\" (entity)\n\nSe emite cuando una entidad se dropea (los items también son entidades).\n\n#### \"playerCollect\" (collector, collected)\n\nSe emite cuando una entidad recoge un item.\n\n * `collector` - la entidad que ha recogido el item.\n * `collected` - la entidad que fue recogida (el item).\n\n#### \"entityGone\" (entity)\n\nSe emite cuando una entidad desaparece (muere, despawnea).\n\n#### \"entityMoved\" (entity)\n\nSe emite cuando una entidad se mueve.\n\n#### \"entityDetach\" (entity, vehicle)\n\nSe emite cuando una entidad se baja en un vehículo.\n\n#### \"entityAttach\" (entity, vehicle)\n\nSe emite cuando una entidad se sube en un vehículo.\n\n * `entity` - la entidad que se ha subido\n * `vehicle` - la entidad del vehículo (minecart, caballo)\n\n#### \"entityUpdate\" (entity)\n\nSe emite cuando una entidad actualiza una de sus propiedades.\n\n#### \"entityEffect\" (entity, effect)\n\nSe emite cuando una entidad obtiene un efecto.\n\n#### \"entityEffectEnd\" (entity, effect)\n\nSe emite cuando una entidad finaliza un efecto.\n\n#### \"playerJoined\" (player)\n\nSe emite cuando un jugador se une al servidor.\n\n#### \"playerUpdated\" (player)\n\nSe emite cuando un jugador actualiza una de sus propiedades.\n\n#### \"playerLeft\" (player)\n\nSe emite cuando un jugador se desconecta del servidor.\n\n#### \"blockUpdate\" (oldBlock, newBlock)\n\n(Es mejor usar este evento desde bot.world en vez que desde bot directamente) Se emite cuando un bloque se actualiza. Devuelve `oldBlock` y `newBlock`.\n\nNota: `oldBlock` puede ser `null`.\n\n#### \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\n(Es mejor usar este evento desde bot.world en vez que desde bot directamente) Se emite cuando un bloque en una coordenada específica se actualiza. Devuelve `oldBlock` y `newBlock`.\n\nNota: `oldBlock` puede ser `null`.\n\n#### \"blockPlaced\" (oldBlock, newBlock)\n\nSe emite cuando el bot coloca un bloque. Devuelve `oldBlock` y `newBlock`.\n\nNota: `oldBlock` puede ser `null`.\n\n#### \"chunkColumnLoad\" (point)\n\nSe emite cuando un chunk se carga\n\n#### \"chunkColumnUnload\" (point)\n\nSe emite cuando un chunk se actualiza. `point` es la coordenada de la esquina del chunk con los valores x, y, y z más pequeños.\n\n#### \"soundEffectHeard\" (soundName, position, volume, pitch)\n\nSe emite cuando el cliente oye un efecto de sonido con nombre.\n\n * `soundName`: nombre del efecto de sonido\n * `position`: una instancia Vec3 indicando el punto de donde el sonido ha originado\n * `volume`: volumen con punto flotante, 1.0 es 100%\n * `pitch`: tono con números enteros, 63 es 100%\n\n#### \"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)\n\n  Se emite cuando el cliente oye un efecto de sonido codificado.\n\n   * `soundId`: id del efecto de sonido\n   * `soundCategory`: categoría del efecto de sonido\n   * `position`: una instancia Vec3 indicando el punto de donde el sonido ha originado\n   * `volume`: volumen con punto flotante, 1.0 es 100%\n   * `pitch`: tono con números enteros, 63 es 100%\n\n#### \"noteHeard\" (block, instrument, pitch)\n\nSe emite cuando un bloque de notas se dispara en algún sitio\n\n * `block`: una instancia Block, el bloque que ha emitido el sonido\n * `instrument`:\n   - `id`: id con números enteros\n   - `name`: uno de estos [`harp`, `doubleBass`, `snareDrum`, `sticks`, `bassDrum`]. (`harpa`, `dobleBajo`, `tambor`, `palos`, `tamborBajo`)\n * `pitch`: El tono de la nota (entre 0 y 24 ambos incluídos donde 0 es el más bajo y 24 es el más alto). Se puede leer más (sobre como los valores de los tonos corresponden a las notas en la vida real) aquí: [official Minecraft wiki](http://minecraft.wiki/w/Note_Block).\n\n#### \"pistonMove\" (block, isPulling, direction)\n\nSe emite cuando un pistón se mueve.\n\n#### \"chestLidMove\" (block, isOpen, block2)\n\nSe emite cuando la tapa de un cofre se mueve\n\n* `block`: una instancia de Block, el bloque de la tapadera que se ha movido. El bloque derecho si es un cofre doble\n* `isOpen`: número de jugadores que tienen el cofre abierto\n* `block2`: una instancia de Block, la otra mitad del bloque donde la tapadera se movió. null si no es un cofre doble\n\n#### \"blockBreakProgressObserved\" (block, destroyStage)\n\nSe emite cuando el cliente observa un bloque mientras este se está rompiendo\n\n * `block`: una instancia de Block, el que se está rompiendo\n * `destroyStage`: número entero correspondiente al progreso (0-9)\n\n#### \"blockBreakProgressEnd\" (block)\n\nSe emite cuando el cliente observa un bloque que termina de romperse\nEsto ocurre cuando el proceso fue completado o abortado.\n\n * `block`: una instancia de Block, el bloque que ya no está siendo roto\n\n#### \"diggingCompleted\" (block)\n\nSe emite cuando se ha terminado de romper un bloque.\n * `block` - el bloque que ya no existe\n\n#### \"diggingAborted\" (block)\n\nSe emite cuando se ha abortado el proceso de rotura de un bloque.\n * `block` - el bloque que todavía existe\n\n#### \"move\"\n\nSe emite cuando el bot se mueve. Si quieres la posición actual, puedes usar `bot.entity.position` y si quieres averiguar la posición anterior, usa `bot.entity.positon.minus(bot.entity.velocity)`\n\n#### \"forcedMove\"\n\nSe emite cuando el bot es movido forzadamente por el servidor (teletransporte, spawnear, ...). Si quieres la posición actual, usa `bot.entity.position`.\n\n#### \"mount\"\n\nSe emite cuando el bot se sube a una entidad como un minecart. Para tener acceso a la entidad, usa `bot.vehicle`.\n\nPara subirte a una entidad, usa `mount`.\n\n#### \"dismount\" (vehicle)\n\nSe emite cuando te bajas de una entidad.\n\n#### \"windowOpen\" (window)\n\nSe emite cuando empiezas a usar una mesa de crafteo, cofre, mesa de pociones, etc.\n\n#### \"windowClose\" (window)\n\nSe emite cuando ya no estás usando una mesa de crafteo, cofre, etc.\n\n#### \"sleep\"\n\nSe emite cuando duermes.\n\n#### \"wake\"\n\nSe emite cuando te despiertas.\n\n#### \"experience\"\n\nSe emite cuando `bot.experience.*` cambia.\n\n#### \"scoreboardCreated\" (scoreboard)\n\nSe emite cuando se crea un scoreboard.\n\n#### \"scoreboardDeleted\" (scoreboard)\n\nSe emite cuando se elimina un scoreboard.\n\n#### \"scoreboardTitleChanged\" (scoreboard)\n\nSe emite cuando el título de un scoreboard se actualiza.\n\n#### \"scoreUpdated\" (scoreboard, item)\n\nSe emite cuando la puntuación de un item en el scoreboard se actualiza.\n\n#### \"scoreRemoved\" (scoreboard, item)\n\nSe emite cuando la puntuación de un item en el scoreboard se elimina.\n\n#### \"scoreboardPosition\" (position, scoreboard)\n\nSe emite cuando la posición de un scoreboard se actualiza.\n\n#### \"bossBarCreated\" (bossBar)\n\nSe emite cuando se crea una barra de vida de jefe.\n\n#### \"bossBarDeleted\" (bossBar)\n\nSe emite cuando se elimina una barra.\n\n#### \"bossBarUpdated\" (bossBar)\n\nSe emite cuando se actualiza una barra.\n\n#### \"heldItemChanged\" (heldItem)\n\nSe emite cuando el item que sostienes cambia.\n\n#### \"physicsTick\" ()\n\nSe emite por cada tick si bot.physicsEnabled está en true.\n\n#### \"chat:name\" (matches)\n\nSe emite cuando todos patrones de chat tienen coincidencias.\n\n### Functions\n\n#### bot.blockAt(point, extraInfos=true)\n\nDevuelve el bloque en el `point` (punto: un Vec3) o `null` si ese punto no está cargado. Si `extraInfos` está en true, también devuelve informaciones sobre carteles, cuadros y entidades de bloques (más lento). Mira `Block`.\n\n#### bot.waitForChunksToLoad(cb)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nEl cb se ejecuta cuando se han cargado bastantes chunks.\n\n#### bot.blockInSight(maxSteps, vectorLength)\n\nObsoleto, usar `blockAtCursor` en su lugar.\n\nDevuelve el bloque que se encuentra en el cursor del bot o `null`\n * `maxSteps` - Número de pasos del trazado de rayos, el valor predeterminado es 256.\n * `vectorLength` - Longitud del vector del trazado de rayos, el valor predeterminado es `5/16`.\n\n#### bot.blockAtCursor(maxDistance=256)\n\nDevuelve el bloque que se encuentra en el cursor del bot o `null`\n * `maxDistance` - Distancia máxima a la que el bloque puede estar del ojo, el valor predeterminado es 256.\n\n#### bot.canSeeBlock(block)\n\nDevuelve true o false dependiendo de si el bot puede ver el `block` (bloque).\n\n#### bot.findBlocks(options)\n\nEncuentra los bloques más cercanos al punto establecido.\n * `options` - Opciones de búsqueda:\n   - `point` - La posición por donde empezar la búsqueda (centro). Predeterminado: la posición del bot.\n   - `matching` - Una función que devuelve true si el bloque cumple las condiciones. También puede ser un ID de un bloque o un array de IDs.\n   - `useExtraInfo` - Puede ser de dos tipos para preservar una compatibilidad a la inversa.\n      - **boolean** - Proporcionas tu función `matching` más datos - más lento\n      - **function** - Se hace mediante dos pasos, si el bloque pasa las condiciones de la función `matching` se pasa a `useExtraInfo` con información adicional\n   - `maxDistance` - La distancia máxima de búsqueda, predeterminado: 16.\n   - `count` - Número de bloques que hay que encontrar antes de devolver los resultados. Predeterminado: 1. Puede devolver menos si no hay suficientes bloques.\n\nDevuelve un array (puede estar vació) con las coordenadas de los bloques encontrados (no devuelve instancias de bloques). El array es ordenado (los más cercanos primero)\n\n#### bot.findBlock(options)\n\nParecido a `bot.blockAt(bot.findBlocks(options)[0])`. Devuelve un único bloque o `null`.\n\n#### bot.canDigBlock(block)\n\nDevuelve si `block` está dentro del rango y si es posible picarlo.\n\n#### bot.recipesFor(itemType, metadata, minResultCount, craftingTable)\n\nDevuelve una lista de instancias `Recipe` (receta) que puedes usar para craftear `itemType` con `metadata`.\n\n * `itemType` - ID numérico de la cosa que quieres craftear\n * `metadata` - el valor numérico de metada del item que quieres craftear, `null` significa \"con cualquier valor de metadata\".\n * `minResultCount` - se basa en tu inventario actual, cualquier receta de la lista devuelta podrá producir este número de items. `null` significa `1`.\n * `craftingTable` - (mesa de crafteo) una instancia `Block`. Si es `null`, solo recetas que se pueden hacer en el inventario estarán incluidas en la lista.\n\n#### bot.recipesAll(itemType, metadata, craftingTable)\n\nParecido a bot.recipesFor pero este no comprueba si el bot tiene suicientes materiales para la receta.\n\n#### bot.nearestEntity(match = (entity) => { return true })\n\nDevuelve la entidad más cercana al bot, correspondiendo a la función (predeterminado: todas las entidades).\nDevuelve null si no se encuentra una entidad.\n\n### Methods\n\n#### bot.end()\n\nTermina la conexión con el servidor.\n\n#### bot.quit(reason)\n\nPara desconectarse con elegancia del servidor con una razón (predeterminado: 'disconnect.quitting')\n\n#### bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])\n\nEsta función también devueve un `Promise`, con `matches` como argumento al finalizar.\n\nSolicita completar el mensaje de chat (para comandos).\n * `str` - String para completar.\n * `callback(matches)`\n   - `matches` - Array de strings que coinciden.\n * `assumeCommand` - Campo mandado al servidor, predeterminado: false.\n * `sendBlockInSight` - Campo mandado al servidor, predeterminado: true. Cambiarlo a false si quiere más eficacia.\n\n#### bot.chat(message)\n\nManda un mensaje público al chat. Rompe grandes mensajes en trozos y los manda como múltiples mensajes si es necesario.\n\n#### bot.whisper(username, message)\n\nAtajo de \"/tell <username>\" (usuario). Todos los trozos serán susurrados al usuario.\n\n#### bot.chatAddPattern(pattern, chatType, description)\n\nObsoleto, usar `addChatPattern` en su lugar.\n\nAñade un patrón regex a la lista de patrones del bot. Útil para servidores bukkit donde el formato de chat cambia mucho.\n * `pattern` - patrón regex para concidir\n * `chatType` - el evento que el bot emite cuando el patrón coincide: Ej. \"chat\" or \"whisper\"\n * 'description ' - Opcional, descripción del patrón\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\n** esto es parecido a `bot.addChatPatternSet(name, [pattern], chatPatternOptions)`\n\ncrea un evento que se emite cada vez que coincide un patrón, el evento se llamará `\"chat:nombre\"`, siendo nombre el nombre que se ha proporcionado\n* `name` - el nombre usado para el evento\n* `pattern` - expresión regular para probar en los mensajes\n* `chatPatternOptions` - object\n  * `repeat` - predeterminado: true, si seguir probando despues de coincidir una vez\n  * `parse` - en vez de devolver el mensaje, devolver los grupos de captura del regex\n  * `deprecated` - (**unstable**) (inestable) usado por bot.chatAddPattern para mantener compatibilidad, seguramente sea quitado\n\ndevuelve un número que puede usarse en bot.removeChatPattern() para eliminar ese patrón\n\n#### bot.addChatPatternSet(name, patterns, chatPatternOptions)\n\ncrea un evento que se emite cada vez que coinciden todos los patrones, el evento se llamará `\"chat:nombre\"`, siendo nombre el nombre que se ha proporcionado\n* `name` - el nombre usado para el evento\n* `patterns` - expresión regular para probar en los mensajes\n* `chatPatternOptions` - object\n  * `repeat` - predeterminado: true, si seguir probando despues de coincidir una vez\n  * `parse` - en vez de devolver el mensaje, devolver los grupos de captura del regex\n\ndevuelve un número que puede usarse en bot.removeChatPattern() para eliminar ese set de patrones\n\n#### bot.removeChatPattern(name)\n\nElimina un patrón / unos patrones\n* `name` : string o número\n\nsi name es un string, todos los patrones con ese nombre serán eliminados, al contrario, si es un número, solo se eliminará ese patrón exacto\n\n#### bot.awaitMessage(...args)\n\npromise (promesa) que se resuelve cuando uno de los mensajes proporcionados se resuelve\n\nEjemplo:\n\n```js\nasync function wait () {\n  await bot.awaitMessage('<flatbot> hello world') // resolves on \"hello world\" in chat by flatbot (se resuelve cuando un usuario llamado flatbot escribe \"hello world\" en el chat)\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world']) // resolves on \"hello\" or \"world\" in chat by flatbot (se resuelve cuando un usuario llamado flatbot escribe \"hello\" o \"world\" en el chat)\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world'], ['<flatbot> im', '<flatbot> batman']) // resolves on \"hello\" or \"world\" or \"im\" or \"batman\" in chat by flatbot (se resuelve cuando un usuario llamado flatbot escribe \"hello world\", \"world\", \"im\" o \"batman\" en el chat)\n  await bot.awaitMessage('<flatbot> hello', '<flatbot> world') // resolves on \"hello\" or \"world\" in chat by flatbot\n  await bot.awaitMessage(/<flatbot> (.+)/) // resolves on first message matching the regex (se resuelve cuando un usuario llamado flatbot escribe algo que coincide con el patrón)\n}\n```\n\n#### bot.setSettings(options)\n\nMira la propiedad `bot.settings`.\n\n#### bot.loadPlugin(plugin)\n\nIntroduce un Plugin. No have nada si el plugin ya está cargado/introducido.\n\n * `plugin` - función\n\n```js\nfunction somePlugin (bot, options) {\n  function someFunction () {\n    bot.chat('Yay!')\n  }\n\n  bot.myPlugin = {} // Good practice to namespace plugin API (hacer esto para evitar errores como que myPlugin no está definido)\n  bot.myPlugin.someFunction = someFunction\n}\n\nconst bot = mineflayer.createBot({})\nbot.loadPlugin(somePlugin)\nbot.once('login', function () {\n  bot.myPlugin.someFunction() // Yay!\n})\n```\n\n#### bot.loadPlugins(plugins)\n\nIntroduce plugins, mira `bot.loadPlugin`.\n * `plugins` - array (lista) de funciones\n\n#### bot.hasPlugin(plugin)\n\nComprueba si el plugin ya está cargado (o previsto para cargar) en el bot.\n\n#### bot.sleep(bedBlock, [cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nDormir en una cama. `bedBlock` tiene que ser una instancia `Block` que es una cama. `cb` es una función que puede tener un parámetro de error por si el bot no puede dormir.\n\n#### bot.isABed(bedBlock)\n\nDevuelve true si `bedBlock` es una cama\n\n#### bot.wake([cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nLevantarse de una cama. `cb` es una función que puede tener un parámetro de error por si el bot no puede levantarse.\n\n#### bot.setControlState(control, state)\n\nEste es el método principal para controlar los movimientos del bot. Es parecido a presionar teclas en minecraft.\nPor ejemplo, forward con true hará que el bot se mueva hacia adelante. Forward con false hará que el bot deje de moverse hacia adelante.\nPuedes usar bot.lookAt con esto para controlar el movimiento. El ejemplo jumper.js te enseña como hacerlo\n\n * `control` - Uno de estos: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'] ('adelante', 'atrás', 'izquierda', 'derecha', 'salto', 'sprint/correr', 'agachado')\n * `state` - `true` o `false`\n\n#### bot.getControlState(control)\n\nDevuelve true si el control está activado.\n\n* `control` - uno de estos ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'] ('adelante', 'atrás', 'izquierda', 'derecha', 'salto', 'sprint/correr', 'agachado')\n\n#### bot.clearControlStates()\n\nDeshabilita todos los controles.\n\n#### bot.lookAt(point, [force], [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nMueve la cabeza.\n\n * `point` una instancia [Vec3](https://github.com/andrewrk/node-vec3) - mueve la cabeza para que este mirando este punto\n * `force` - Mira `force` en `bot.look`\n * `callback()` opcional, ejecutado cuando esás mirando al `point`\n\n#### bot.look(yaw, pitch, [force], [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nMueve la cabeza.\n\n * `yaw` - El número de radianes para rotar alrededor del eje vertical, empezando por el este. Sentido anti-horario.\n * `pitch` - Número de radianes para mirar arriba o abajo. 0 significa recto hacia adelante. PI / 2 significa arriba. -PI / 2 significa abajo.\n * `force` - Si está presente y es true, salta la suave transición. Especifícalo como true si quieres valores precisos para soltar items o disparar flechas. Esto no es necesario para cálculos por parte del cliente como para moverse.\n * `callback()` opcional, ejecutado cuando estás mirando al `yaw` y `pitch`\n\n#### bot.updateSign(block, text)\n\nCambia el texto en un cartel.\n\n#### bot.equip(item, destination, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nEquipar un item del inventario.\n\n * `item` - instancia `Item`. Mira `window.items()`.\n * `destination` (destino)\n   - `\"hand\"` - (mano) `null` es un alias de esto\n   - `\"head\"` - cabeza\n   - `\"torso\"` - pecho\n   - `\"legs\"` - piernas\n   - `\"feet\"` - pies\n   - `\"off-hand\"` - (mano izquierda) when available\n * `callback(error)` - opcional. ejecutado cuando el bot ha equipado el item o cuando ha fallado al hacerlo.\n\n#### bot.unequip(destination, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nQuita un item del destino.\n\n#### bot.tossStack(item, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nSuelta el stack de items especificado.\n * `item` - el stack de items que quieres soltar\n * `callback(error)` - opcional, ejecutado cuando el bot ha terminado de soltar o cuando ha fallado al hacerlo.\n\n#### bot.toss(itemType, metadata, count, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `itemType` - ID numérico del item que quieres soltar\n * `metadata` - metadata del item que quieres soltar. `null` para cualquier metadata\n * `count` - cuantos items quieres soltar. `null` significa `1`.\n * `callback(err)` - (opcional) ejecutado cuando el bot ha terminado de soltar o cuando ha fallado al hacerlo\n\n#### bot.dig(block, [forceLook = true], [digFace], [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nEmpezar a picar el `block` (bloque) con el item de la mano.\nMira los eventos \"diggingCompleted\" y \"diggingAborted\".\n\nNota: al empezar a romper un bloque, no podrás romper otro bloque hasta que terminas de romper ese bloque o ejecutas `bot.stopDigging()`.\n\n * `block` - el bloque que quieres picar\n * `forceLook` - (opcional) si es true, mirar al bloque rápidamente y empezar a picarlo. Si es false, mirar al bloque lentamente antes de picarlo. Adicionalemente, se puede poner 'ignore', para que el bot no mire el bloque al picarlo.\n * `digFace` - (opcional) Predeterminado: 'auto', mira al centro del bloque y lo rompe desde la cara de arriba, también puede ser un vector Vec3 de la cara del bloque donde el bot debería estar mirando. Por ejemplo: ```vec3(0, 1, 0)``` para picar la cara de arriba. También puede ser 'raycast', esto comprueba si alguna cara es visible para empezar a picar por esa cara, esto es útil en servidores con un anti cheat.\n * `callback(err)` - (opcional) ejecutado cuando el bot ha roto el bloque o cuando ha fallado al hacerlo\n\n#### bot.stopDigging()\n\nParar de romper el bloque.\n\n#### bot.digTime(block)\n\nDevuelve cuanto va a tardar en romper el bloque, en milisegundos.\n\n#### bot.acceptResourcePack()\n\nAcepta el paquete de recursos\n\n#### bot.denyResourcePack()\n\nDeniega el paquete de recursos\n\n#### bot.placeBlock(referenceBlock, faceVector, cb)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `referenceBlock` - (bloque de referencia) el bloque al lado del bloque que quieres colocar\n * `faceVector` - una de las seis direcciones cardinales, por ejemplo, `new Vec3(0, 1, 0)` para la cara de arriba, indicando la cara del bloque de referencia.\n * `cb` será ejecutado cuando el servidor confirma que el bloque ha sido roto\n\nEl bloque será colocado en `referenceBlock.position.plus(faceVector)` (posición del bloque de referencia más el vector de cara).\n\n#### bot.placeEntity(referenceBlock, faceVector)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `referenceBlock` - (bloque de referencia) el bloque al lado de donde quieres colocar la entidad\n * `faceVector` - una de las seis direcciones cardinales, por ejemplo, `new Vec3(0, 1, 0)` para la cara de arriba, indicando la cara del bloque de referencia.\n\nLa entidad será colocada en `referenceBlock.position.plus(faceVector)` (posición del bloque de referencia más el vector de cara).\n\n#### bot.activateBlock(block, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nGolpea un bloque de notas, abre una puerta, etc.\n\n * `block` - el bloque que hay que activar\n * `callback(err)` - (opcional) ejecutado cuando el bot ha activado el bloque o ha fallado al hacerlo\n\n#### bot.activateEntity(entity, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nActiva una entidad, por ejemplo con aldeanos.\n\n * `entity` - la entidad que hay que activar\n * `callback(err)` - (opcional) ejecutado cuano el bot ha activado la entidad o ha fallado al hacerlo\n\n#### bot.activateEntityAt(entity, position, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nActiva una entitdad en la posición especificada, útil para los soportes de armadura.\n\n * `entity` - la entidad que hay que activar\n * `position` - la posición donde hay que hacer click\n * `callback(err)` - (opcional) ejecutado cuano el bot ha activado la entidad o ha fallado al hacerlo\n\n#### bot.consume(callback)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nConsumir / beber el item en la mano\n\n * `callback(error)` - ejecutado cuano el bot ha consuimdo el item o ha fallado al hacerlo\n\n#### bot.fish(callback)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nPescar con la caña en la mano\n\n * `callback(error)` - (opcional) ejecutado cuano el bot ha pescado algo o ha fallado al hacerlo\n\n#### bot.activateItem(offHand=false)\n\nActiva el item en la mano. Esto es para comer, disparar flechas, tirar huevos, etc.\nEl parámetro opcional puede ser `false` para la mano izquierda.\n\n#### bot.deactivateItem()\n\nDesactiva el item en la mano. Esto es como disparas la flecha, dejas de comer, etc.\n\n#### bot.useOn(targetEntity)\n\nUsar el item en la mano en la instancia de `Entity` (entidad). Esto es como colocas un sillín en un caballo o usas las tijeras en una oveja.\n\n#### bot.attack(entity)\n\nAtaca la entidad o el mob.\n\n#### bot.swingArm([hand], showHand)\n\nReproduce la animación de mover el brazo.\n\n * `hand` la mano qe se va a animar, puede ser `left` (izquierda) o `right` (derecha). Predeterminado: `right`\n * `showHand` es un boolean que indica si añadir la mano al paquete para mostrar la animación. Predeterminado: `true`\n\n#### bot.mount(entity)\n\nSubirse a una entidad. Para bajarse, usar `bot.dismount`.\n\n#### bot.dismount()\n\nBaja de la entidad en la que estás montado.\n\n#### bot.moveVehicle(left,forward)\n\nMover el vehículo :\n\n * left puede ser -1 o 1 : -1 significa derecha, 1 significa izquierda\n * forward puede ser -1 o 1 : -1 significa hacia atrás, 1 significa hacia adelante\n\nTodas las direcciones son relativas a donde está mirando el bot\n\n#### bot.setQuickBarSlot(slot)\n\n * `slot` - puede ser de 0 a 8, la casilla de la barra de acceso rápido\n\n#### bot.craft(recipe, count, craftingTable, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `recipe` - Una instancia `Recipe`. Mira `bot.recipesFor`.\n * `count` - Cuantas veces quieres repetir la acción.\n   Si quieres craftear `8` palos con tablas de madera, pondrías\n   `count` a `2`. `null` significa `1`.\n * `craftingTable` - Una instancia de `Block`, la mesa de crafteo que quieres usar. Si el crafteo no necesita una mesa, este argumento se puede dejar como `null`.\n * `callback` - (opcional) Ejecutado cuando el bot ha terminado de craftear y el inventario ha sido actualizado.\n\n#### bot.writeBook(slot, pages, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\n * `slot` es un número de casilla del inventario (36 es la primera casilla, etc.).\n * `pages` es un array de strings representando las páginas.\n * `callback(error)` - opcional. Ejecutado cuando el bot ha terminado de escribir o ha ocurrido un error.\n\n#### bot.openContainer(containerBlock or containerEntity)\n\nAbre un contenedor.\nDevuelve un promise con una instancia `Container` que representa el contenedor que estás abriendo.\n\n#### bot.openChest(chestBlock or minecartchestEntity)\n\nObsoleto. Lo mismo que `openContainer`\n\n#### bot.openFurnace(furnaceBlock)\n\nAbre un horno.\nDevuelve un promise con una instancia `Furnace` que representa el horno que estás abriendo.\n\n#### bot.openDispenser(dispenserBlock)\n\nObsoleto. Lo mismo que `openContainer`\n\n#### bot.openEnchantmentTable(enchantmentTableBlock)\n\nDevuelve un promise con una instancia `EnchantmentTable` que representa la mesa de encantamiento que estás abriendo.\n\n#### bot.openAnvil(anvilBlock)\n\nDevuelve un promise con una instancia `anvil` que representa el yunque que estás abriendo.\n\n#### bot.openVillager(villagerEntity)\n\nDevuelve un promise con una instancia `Villager` que representa la ventana de tradeo que estás abriendo\nEl evento `ready` en la instancia `Villager` se puede usar para saber cuando están listos los tradeos\n\n#### bot.trade(villagerInstance, tradeIndex, [times], [cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nUsa la instancia `Villager` para comerciar.\n\n#### bot.setCommandBlock(pos, command, [options])\n\nCambia las propiedadezs de un bloque de comandos en la posición `pos`.\nEjemplo de `options`:\n```js\n{\n  mode: 2,\n  trackOutput: true,\n  conditional: false,\n  alwaysActive: true\n}\n```\noptions.mode puede tener 3 valores: 0 (SEQUENCE) (secuencia), 1 (AUTO), 2 (REDSTONE)\nTodas las opciones tienen como predeterminado false, excepto modo que es 2 (para parecerse al bloque de comandos de Minecraft).\n\n#### bot.supportFeature(name)\n\nEsto puede usarse para ver si una característica está disponible en la versión del bot de Minecraft. Normalmente esto es solo para manejar funciones que son específicas de una versión.\n\nPuedes encontrar la lista de características en [./lib/features.json](https://github.com/PrismarineJS/mineflayer/blob/master/lib/features.json) file.\n\n#### bot.waitForTicks(ticks)\n\nEsta función devuelve un promise y espera a que el número de ticks especificado pase dentro del juego, esta función es similar a la función setTimeout de Javascript pero esta funciona con el reloj físico del juego.\n\n### Lower level inventory methods\n\nEstos son métodos de un nivel más bajo para el inventario, pueden ser útils algunas veces pero es mejor usar los métodos presentados arriba si es posible.\n\n#### bot.clickWindow(slot, mouseButton, mode, cb)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nHacer click en la ventana/interfaz actual, los detalles están en https://minecraft.wiki/w/Protocol#Click_Window\n * slot - número que representa la casilla de la ventan\n * mouseButton - 0 para click izquierdo, y 1 para click derecho\n * mode - mineflayer solo tiene disponible el modo 0\n\n#### bot.putSelectedItemRange(start, end, window, slot)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nMover el item en la casilla `slot` en un rango especificado\n\n#### bot.putAway(slot)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nMover el item a la casilla `slot` en el inventario.\n\n#### bot.closeWindow(window)\n\nCerrar la ventana/interfaz.\n * window - la ventana a cerrar\n\n#### bot.transfer(options, cb)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nTransferir un item de un rango a otro. `options` es un object con :\n\n * `window` : la ventana donde el item será movido\n * `itemType` : el tipo de item a mover (id numérico)\n * `metadata` : la metadata del item a mover\n * `sourceStart` and `sourceEnd` : el rango\n * `destStart` and `destEnd` : el rango de destino\n\n#### bot.openBlock(block)\n\nAbre un bloque, por ejemplo un cofre, devuelve un promise con `Window` siendo la ventana abierta.\n\n * `block` es el bloque a abrir\n\n#### bot.openEntity(entity)\n\nAbre una entidad con un inventario, por ejemplo un aldeano, devuelve un promise con `Window` siendo la ventana abierta.\n\n * `entity` es la entidad a abrir\n\n#### bot.moveSlotItem(sourceSlot, destSlot, cb)\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nMover un item de una casilla `sourceSlot` a otra `destSlot` en una ventana.\n\n#### bot.updateHeldItem()\n\nActualiza `bot.heldItem`.\n\n#### bot.getEquipmentDestSlot(destination)\n\nDevuelve el id de la casilla de equipamiento por nombre del destino.\n\nEl destino puede ser:\n* head - (cabeza)\n* torso - (pecho)\n* legs - (piernas)\n* feet - (pies)\n* hand - (mano)\n* off-hand - (mano izquierda)\n\n### bot.creative\n\nEsta colección de apis es útil en modo creativo.\nDetectar y cambiar de modo no está implementado,\npero se asume y muchas veces se necesita que el bot esté en modo creativo para que estas características funcionen.\n\n#### bot.creative.setInventorySlot(slot, item, [callback])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nProporciona al bot el item especificado en la casilla especificada.\nSi se ejecuta dos veces antes de que la primera ejecución no haya terminado, la primera ejecución contendrá un error.\n\n * `slot` es un número de casilla del inventario (donde 36 es la primera casilla, etc.).\n * `item` es una instancia [prismarine-item](https://github.com/PrismarineJS/prismarine-item) con su metadata, nbtdata, etc.\n    Si `item` es `null`, el item en esa casilla será eliminado\n * `callback(err)` (opcional) es un callback que es ejecutado cuando el servidor acepta la transacción o cuando falla al hacerlo.\n\nSi este método cambia algo, se emitirá `bot.inventory.on(\"updateSlot\")`\n\n#### bot.creative.flyTo(destination, [cb])\n\nEsta función también devueve un `Promise`, con `void` como argumento al finalizar.\n\nEjecuta `startFlying()` y se mueve a una velocidad constante en un espacio tridimensional en línea recta hasta el destino.\n`destination` es un `Vec3`, y las coordenadas `x` y `z` a veces terminarán en `.5`.\nEstá operación no funcionará si hay algún obstáculo en el camino,\npor eso es recomendable volar distancias cortas.\n\nCuando el bot llega al destino, `cb` es ejecutado.\n\nEste método no va a buscar el camino automáticamente.\nSe espera que una implementación de path finding usará este método para moverse < 2 bloques a la vez.\n\nPara dejar de volar (volver a las físicas normales), se puede ejecutar `stopFlying()`.\n\n#### bot.creative.startFlying()\n\nCambia `bot.physics.gravity` a `0`.\nPara volver a las físicas normales, se puede ejecutar `stopFlying()`.\n\nEste método es útil si quieres levitar mientras rompes el bloque debajo de tí.\nNo es necesario ejecutar esta función antes de ejecutar `flyTo()`.\n\nNota: mientras vuelas, `bot.entity.velocity` no es preciso.\n\n#### bot.creative.stopFlying()\n\nRestablece `bot.physics.gravity` a su valor original.\n"
  },
  {
    "path": "docs/es/unstable_api_es.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Tabla de contenidos**  *generado con [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API inestable : bot._](#api-instable--bot_)\n  - [bot._client](#bot_client)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API inestable : bot._\n\nEstos métodos y clases son útiles en algunos casos especiales pero no son estables y pueden cambiar en cualquier momento\n\n## bot._client\n\n`bot._client` es creado usando [node-minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol).\nManeja escribir y recibir paquetes.\nEl comportamiento puede cambiar (por ejemplo en cada versión nueva de minecraft), por eso es mejor usar los métodos de mineflayer si es posible.\n\n\nEsta documentación no está mantenida oficialmente, si quiere ver las últimas novedades, por favor dirijase a la documentación original: [unstable_api](../unstable_api.md)\n"
  },
  {
    "path": "docs/fr/FAQ_FR.md",
    "content": "## FAQ\n\nCe document de foire aux questions a pour but d'aider les gens pour les choses les plus courantes.\n\n### Je reçois une erreur lorsque j'essaie de me connecter avec un compte Microsoft.\n\nAssurez-vous que l'email que vous avez entré dans l'option username de createBot peut être utilisé pour vous connecter à `minecraft.net` en utilisant le bouton 'Login with Microsoft'.\nAssurez-vous que vous avez l'option `auth : 'microsoft'` dans vos options createBot.\n\nLorsque vous obtenez une erreur qui dit quelque chose au sujet des informations d'identification invalides ou \"Ce compte possède Minecraft ?\", essayez de supprimer le champ du mot de passe dans les options `createBot` et réessayez.\n\n### Comment masquer les erreurs ?\n\nUtiliser `hideErrors : true` dans les options de createBot\nVous pouvez également choisir d'ajouter ces listeners :\n\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n### Je ne reçois pas d'événement de chat sur un serveur personnalisé, comment puis-je résoudre ce problème ?\n\nLes serveurs Spigot, en particulier certains plugins, utilisent des formats de chat personnalisés, vous devez les analyser avec une expression rationnelle / un analyseur syntaxique personnalisé.\nLisez et adaptez [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js) pour qu'il fonctionne pour vos besoins particuliers.\nplugin de chat. A lire également <http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat>\n\n### Comment puis-je collecter les informations d'un plugin personnalisé dans le chat ?\n\nLa plupart des serveurs Minecraft personnalisés ont le support des plugins, et beaucoup de ces plugins disent quelque chose dans le chat quand quelque chose se passe. Si c'est juste un message, il est préférable d'utiliser la solution discutée dans la solution ci-dessus, mais quand ces messages sont divisés en plusieurs petits messages, une autre option est d'utiliser l'événement `\"messagestr\"` car il permet d'analyser facilement les messages de plusieurs lignes.\n\n**Exemple:**\n\nLe message du chat dans le chat ressemble à ceci :\n\n```\n(!) U9G has won the /jackpot and received\n$26,418,402,450! They purchased 2,350,000 (76.32%) ticket(s) out of the\n3,079,185 ticket(s) sold!\n```\n\n```js\nconst regex = {\n  first: /\\(!\\) (.+) has won the \\/jackpot and received +/,\n  second: /\\$(.+)! They purchased (.+) \\((.+)%\\) ticket\\(s\\) out of the /,\n  third: /(.+) ticket\\(s\\) sold!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n\n### Comment puis-je envoyer une commande ?\n\nEn utilisant `bot.chat()`.\n\n**Example:**\n\n```js\nbot.chat('/give @p diamond')\n```\n\n### Est-il possible de se connecter à plusieurs comptes en utilisant bot = mineflayer.createbot tout en les contrôlant tous séparément ?\n\nCréer différentes instances de bot en appelant createBot puis faire différentes choses pour chacune, voir multiple.js\n\n### Comment faire pour que le robot lâche tout son inventaire ?\n\nbot.inventory.items() renvoie un tableau des objets du bot. Vous pouvez utiliser une fonction récursive pour les parcourir en boucle et déposer chaque objet en utilisant bot.toss(). Cliquez [ici](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9) pour voir un exemple.\n\n### Comment vérifier les paquets qui sont envoyés/reçus ?\n\nActivation du mode de débogage <https://github.com/PrismarineJS/mineflayer#debug>\n\n### Je veux éviter la déconnexion même en cas de lag du serveur, comment puis-je y parvenir ?\n\nUn moyen est d'augmenter l'option [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) (à définir dans createBot) à une valeur plus élevée (par exemple `300*1000` qui est 5min au lieu des 30s par défaut). Si vous êtes toujours déconnecté, vous pouvez vous reconnecter automatiquement en utilisant quelque chose comme cet exemple <https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js>\n\n### Comment obtenir l'histoire / le texte d'un objet ?\n\nVous pouvez utiliser la propriété `item.nbt`. Il est également recommandé d'utiliser la bibliothèque `prismarine-nbt`. La méthode `nbt.simplify()` peut être utile.\n\n**Exemple:**\n\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### Comment puis-je envoyer un message de la console au serveur ?\n\nYou can use a library like `repl` to read the console input and use `bot.chat()` to send it. You can find an example [here.](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js)\n\n### Lors de la création d'un plugin, comment puis-je spécifier un autre plugin comme dépendance ?\n\nDans la fonction `inject()` de votre plugin, vous pouvez appeler sans risque `bot.loadPlugin(anotherPlugin)` pour vous assurer que ce plugin est chargé. Si le plugin a déjà été chargé auparavant, rien ne se passe.\n\nNotez que l'ordre dans lequel les plugins sont chargés est dynamique, donc vous ne devriez jamais appeler un autre plugin dans votre fonction `inject()`.\n\n### Comment puis-je utiliser un proxy socks5 ?\n\nIn the options object for `mineflayer.createBot(options)`, remove your `host` option from the options object, have the following variables declared `PROXY_IP, PROXY_PORT, PROXY_USERNAME, PROXY_PASSWORD, MC_SERVER_ADDRESS, MC_SERVER_PORT` and add this to your options object:\n\n```js\nconnect: (client) => {\n    socks.createConnection({\n      proxy: {\n        host: PROXY_IP,\n        port: PROXY_PORT,\n        type: 5,\n        userId: PROXY_USERNAME,\n        password: PROXY_PASSWORD\n      },\n      command: 'connect',\n      destination: {\n        host: MC_SERVER_ADDRESS,\n        port: MC_SERVER_PORT\n      }\n    }, (err, info) => {\n      if (err) {\n        console.log(err)\n        return\n      }\n      client.setSocket(info.socket)\n      client.emit('connect')\n    })\n  }\n  ```\n\n`socks` est déclaré avec `const socks = require('socks').SocksClient` et utilise le paquet [this](https://www.npmjs.com/package/socks).\nCertains serveurs peuvent rejeter la connexion. Si cela se produit, essayez d'ajouter `fakeHost : MC_SERVER_ADDRESS` aux options de votre createBot.\n  \n# Erreurs courantes\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\nVoici ce qui se passe lorsque vous avez donné à Mineflayer la mauvaise version du serveur, ou que Mineflayer détecte la mauvaise version du serveur.\n\n### `TypeError: Cannot read property '?' of undefined`\n\nVous essayez peut-être d'utiliser quelque chose sur l'objet bot qui n'existe pas encore, essayez d'appeler l'instruction après l'événement `spawn`.\n\n### `SyntaxError: Unexpected token '?'`\n\nMettez à jour la version de votre node.\n\n### The bot can't break/place blocks or open chests\n\nVérifiez que la protection contre le spawn n'empêche pas le bot d'agir.\n"
  },
  {
    "path": "docs/fr/README_FR.md",
    "content": "# Mineflayer\n\n[![NPM version](https://badge.fury.io/js/mineflayer.svg)](http://badge.fury.io/js/mineflayer)\n[![Build Status](https://github.com/PrismarineJS/mineflayer/workflows/CI/badge.svg)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)\n[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)\n[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)\n[![Issue Hunt](https://github.com/BoostIO/issuehunt-materials/blob/master/v1/issuehunt-shield-v1.svg)](https://issuehunt.io/r/PrismarineJS/mineflayer)\n\n[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n\n| <sub>EN</sub> [Anglais](../README.md) | <sub>RU</sub> [Russe](../ru/README_RU.md) | <sub>ES</sub> [Espagnol](../es/README_ES.md) | <sub>FR</sub> [Français](README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [Chinois](../zh/README_ZH_CN.md) | <sub>BR</sub> [Portuguese](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|\n\nCréé des robots Minecraft avec API stable, puissante et facilement maniable, [API](api.md).\n\nSi c'est la première fois que vous utilisez Node.js, il vaut mieux commencer avec le [tutoriel](tutorial.md)\n\n## Caractéristiques:\n\n * Compatible avec Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 et 1.20.\n * Reconnaissante et pistage des entités.\n * Identification des blocs. Vous pouvez passer en revue le monde autour de vous. Quelques millisecondes suffisent pour trouver n'importe quel bloc.\n * Information sur la physique et mouvements, données sur la taille des blocs...\n * Peut attaquer des entitées et utiliser des véhicules.\n * Gestion d'inventaire.\n * Gestion de l'établi, coffre, distributeur, table d'enchantement.\n * creuser et construire.\n * Autres actions diverses, telle que connaitre tes points de vie ou si il pleut.\n * Utiliser les blocs et items.\n * Discuter avec le chat.\n\n### Projets à venir:\n\n Visite cette page pour voir nos projets [projets](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects). \n \n## Installation\n\nEn premier installer Node.js (version minimale requise: 14) sur [nodejs.org](https://nodejs.org/) puis taper dans la console:\n\n`npm install mineflayer`\n\n## Documentation\n\n| lien | description |\n|---|---|\n| [tutoriel](tutorial.md) | Démarre par un tutoriel node js et mineflayer |\n| [FAQ](FAQ.md) | Une question? Regardez d'abord ici ! |\n| [API](api.md) [unstable_api.md](unstable_api.md) | L'API intégrale |\n| [changement](history.md) | Les derniers changements dans mineflayer |\n| [exemples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | quelques exemples réalisables avec mineflayer |\n\n\n## Pour Aider\n\nAllez lire [CONTRIBUTING.md](CONTRIBUTING.md) et [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute).\n\n## Utilisation\n\n**Vidéos**\n\nUn tutoriel vidéo qui explique comment mettre en place un robot mineflayer est disponible [ici.](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n\nSi vous voulez en apprendre plus, des video peuvent être trouvées [ici,](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) et le code source correspondant peut être trouvé [ici.](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials)\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Introduction à mineflayer**\n\nSi aucune version n'est specifiée, la version du serveur est automatiquement détectée.\nVous pouvez toujours en specifier une manuellement dans les options:\nPar exemple `version:\"1.16.5\"`.\n\n### Echo Example\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // optionel\n  port: 25565, // optionel\n  username: 'email@example.com', // l'email et le mot de passe sont requis seulement pour les serveurs\n  password: '12345678', // online-mode=true\n  version: false, // faux, corresponds pour la detection automatique(par défaut), met \"1.8.8\" par exemple si tu a besoin d'une version specifique\n  auth: 'mojang' // optionel; par defaut utilise mojang, si vous utilisez un compte microsoft, preciser 'microsoft'\n})\n\nbot.on('chat', function (username, message) {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// erreur de code, ou raison de kick:\nbot.on('kicked', (reason, loggedIn) => console.log(reason, loggedIn))\nbot.on('error', err => console.log(err))\n```\n\n### Observer ce que fait votre robot en temp réel\nGrace au projet [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer), il est maintenant possible de voir ce que votre robot fait.\nIl suffit de lancer `npm install prismarine-viewer` dans votre console et d'ajouter ceci à votre code:\n```js\nconst mineflayerViewer = require('prismarine-viewer').mineflayer\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true })\n})\n```\net vous obtiendrez un affichage en *direct* qui ressemble à ceci:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### Exemples:\n\n| exemple | description |\n|---|---|\n|[maps](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | afficher ce que votre robot fait en direct |\n|[pathfinder](https://github.com/Karang/mineflayer-pathfinder/blob/master/examples/test.js) | Faire votre robot se déplacer la oû vous voulez |\n|[coffre](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | Utiliser les coffres, fours, distrubuteurs, tables d'enchantements |\n|[pelteuse](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | Aprener comment créer un robot simple capable de creuser |\n|[discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | connectez un bot discord avec un robot mineflayer |\n|[jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | Un robot simple qui peut bouger, sauter, conduire des véhicules, attaquer des créatures proches |\n|[ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | Afficher le chat du robot avec les couleurs du chat dans votre terminal |\n|[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Faire un robot qui garde une zone definie |\n|[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | fichier texte avec tous vos comptes minecraft |\n\nEt de nombreux exemples dans le dossier [exemples](https://github.com/PrismarineJS/mineflayer/tree/master/examples)\n\n### Modules\n\nBeaucoup de development arrive à l'interieur de petit package npm, qui sont utilisé par mineflayer\n\n#### The Node Way&trade;\n\n> \"When applications are done well, they are just the really application-specific, brackish residue that can't be so easily abstracted away. All the nice, reusable components sublimate away onto github and npm where everybody can collaborate to advance the commons.\" — substack from [\"how I write modules\"](https://gist.github.com/substack/5075355)\n\n#### Modules\n\nVoici les modules principales qui contruisent mineflayer:\n\n| module | description |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Traduis et serialise les packets minecraft, plus l'authentication et l'encryption.\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | Module qui provide des données minecraft pour les clients minecraft, les serveurs et les librairies.\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) | provide les moteurs de physique pour les entitées minecraft.\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | Une class pour contenir les chunks minecraft\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | Mathematique de vecteur 3D\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | Represente un block minecraft avec les données associés.\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | Une traducteur pour les messages de chat minecraft (extracté depuis mineflayer)\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Une librairies Node.js pour intéragir avecles systeme d'authenfication de mojang, connue sous le nom de Yggdrasil\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | l'implementation des mondes pour prismarine\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | Represente une fenetre minecraft\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | Contient les items minecraft et les donnnées qui y sont associé\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | Un traducteur NBT pour node-minecraft-protocol\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | Contient les récettes minecraft\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | Contient les biome et leur données \n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) | Represente une entitées minecraft\n\n\n### Debug\n\nVous pouvez activer le debug du protocole en utilisant `DEBUG` comme variable d'environnement:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nSur windows :\n```\nset DEBUG=minecraft-protocol\nnode your_script.js\n```\n\n## Third Party Plugins\n\nMineflayer peut être amélioré avec plusieurs plugins; tout le monde peut créer un plugin qui ajoute une API de plus haut niveaux au-dessus de Mineflayer.\n\nLes plugins les plus récents et les plus utiles sont :\n\n * [pathfinder](https://github.com/PrismarineJS/mineflayer-pathfinder) - advanced A* pathfinding avec de nombres paramètres configurables\n * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - Un simple inspecteur web de chunk\n * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - un inspecteur d'inventaire en ligne\n * [statemachine](https://github.com/PrismarineJS/mineflayer-statemachine) - Une API pour state machine pour robots aux comportements complexes\n * [Armor Manager](https://github.com/PrismarineJS/MineflayerArmorManager) - gestion d'armure automatique\n * [Collect Block](https://github.com/PrismarineJS/mineflayer-collectblock) - Une API rapide et flexible pour colleter des blocs.\n * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - intertace en ligne pour robots mineflayer\n * [PVP](https://github.com/PrismarineJS/mineflayer-pvp) - Une API facile pour les combats contre les entités et les joueurs.\n * [auto-eat](https://github.com/LINKdiscordd/mineflayer-auto-eat) - pour manger automatiquement de la nouriture.\n * [Tool](https://github.com/PrismarineJS/mineflayer-tool) - Un plugin pour choisir automatiquement le meilleur outil pour une tâche donnée\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - Un plugin pour viser à la perfection avec des arcs.\n\n\nLaissez un coup d'oeil à ses projets :\n \n * [radar](https://github.com/andrewrk/mineflayer-radar/) - interface web utilisant un canvas et une communication socket.io. [YouTube Demo](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n * [blockfinder](https://github.com/Darthfett/mineflayer-blockFinder) - trouver des blocs dans un monde 3D\n * [scaffold](https://github.com/PrismarineJS/mineflayer-scaffold) - trouver le meilleur chemin vers une destination précise en cassant et dispoant des blocs\n   [YouTube Demo](http://youtu.be/jkg6psMUSE0)\n * [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - remplissage de compte de capchat pour serveur hors-ligne\n * [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - determiner ce qui a attaqué une autre entité.\n * [tps](https://github.com/SiebeDW/mineflayer-tps) - trouver le tps du serveur\n * [panorama](https://github.com/IceTank/mineflayer-panorama) - prendre des photos panoramiques de vos mondes.\n\n## Projets utilisant Mineflayer\n\n * [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - créé un escalier en collimasson](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - réplicé une contruction](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n * [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - visualiser se qui se passe avec son robot grâce à [voxel.js](https://www.voxeljs.com/)\n * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) -  Afficher les info des joueurs sur une API en ligne\n * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (derniere version open source, par AlexKvazos) -  Un client minecraft basé seulement sur le chat<https://minecraftchat.net/>\n * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - Un robot basé sur les plugins, qui a une jolie interface. Réalisée avec Node-Webkit. http://bot.ezcha.net/\n * [Chaoscraft](https://github.com/schematical/chaoscraft) - Des robots minecraft qui utilisent des algorithmes génétiques, regarder [ces videos youtube](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) -  Minecraft - une API telgram, construite sur Mineflayer et Telegraf.\n * [ProZedd/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - \"Imprimme\" un .schematic dans Minecraft\n * [et beaucoup plus](https://github.com/PrismarineJS/mineflayer/network/dependents) - Tous les les projets utilisant Mineflayer\n\n\n## Test\n\n### Tout tester\n\nExécuter seulement :\n\n```bash\nnpm test\n```\n\n### Tester une version spécifique\n\nExécutez\n\n```bash\nnpm test -g <version>\n```\n\noù `<version>` est une version de Minecraft comme `1.12`, `1.15.2`...\n\n### Tester un test spécifique\n\nExecuter\n\n```bash\nnpm test -g <test_name>\n```\n\noù `<test_name>` est le nom d'un teste comme `lit`, `utiliseCoffre`, `rayTrace`...\n\n## Licence\n\n[MIT](../../LICENSE)\n"
  },
  {
    "path": "docs/history.md",
    "content": "## 4.35.0\n* [🎈 1.21.11 (#3781)](https://github.com/PrismarineJS/mineflayer/commit/597745c7c061943620fcacba7254bccee05b7a3e) (thanks @rom1504bot)\n* [Fix chat pattern and event listener in tutorial (#3783)](https://github.com/PrismarineJS/mineflayer/commit/48586138f560991de60bea639c71fa82954cf50f) (thanks @brentspine)\n* [Update history.md](https://github.com/PrismarineJS/mineflayer/commit/c9f766513d5bb5a93c5b86c07827128716c0afdb) (thanks @extremeheat)\n\n## 4.34.0\n* [🎈 1.21.9/1.21.10 support (#3754)](https://github.com/PrismarineJS/mineflayer/commit/f0afaf73061c15b67e5d3457b60ed543e711acb6) (thanks @rom1504bot)\n* [Update russian docs (#3762)](https://github.com/PrismarineJS/mineflayer/commit/887b52b933d943c8d605d7835d6d55d198208fee) (thanks @fungoza)\n* [Swap out deprecated bot.chatAddPattern() in tutorial.md (#3709)](https://github.com/PrismarineJS/mineflayer/commit/e5fcf1f022656c7432ef11b4e458ca9b2e08c1ee) (thanks @TheSharkyOfficial)\n* [Add missing uuid-1345 dep](https://github.com/PrismarineJS/mineflayer/commit/464000aa05fc44cc6da236fc370bce6911648a75) (thanks @extremeheat)\n* [Update README.md](https://github.com/PrismarineJS/mineflayer/commit/9d7ea28c3321170f9958f54dfe24cedf48f1113f) (thanks @extremeheat)\n* [Resolved type mismatch (#3748)](https://github.com/PrismarineJS/mineflayer/commit/266af6786edc78d17e7afad77a3e89fc7649e0e0) (thanks @BF5258)\n\n## 4.33.0\n* [Add update workflow (#3727)](https://github.com/PrismarineJS/mineflayer/commit/9c335366d435b58cfe45bbfbbc534b99ee669dc2) (thanks @extremeheat)\n* [Add support for Minecraft 1.21.8 (#3732)](https://github.com/PrismarineJS/mineflayer/commit/ec8220d7c63b72acb4bf16f30cdf4ba346b83f98) (thanks @rom1504)\n\n## 4.32.0\n* [1.21.6 (#3713)](https://github.com/PrismarineJS/mineflayer/commit/01f537c394fc78bf2e765b28a8b24a30c1d1fd2e) (thanks @extremeheat)\n* [Fix knockback physics crash (#3715)](https://github.com/PrismarineJS/mineflayer/commit/e3f89d17418ece9e9fac4b111d8243dfe1a5d376) (thanks @Omena0)\n\n## 4.31.0\n* [Cursor 1 21 5 (#3701)](https://github.com/PrismarineJS/mineflayer/commit/8770129d26a85f9b077d2a8969d45436fa09c3f3) (thanks @rom1504)\n\n## 4.30.0\n* [Update player_info handling (#3689)](https://github.com/PrismarineJS/mineflayer/commit/3f2fd6d393bc39167410df5a292759c93c9b249f) (thanks @extremeheat)\n* [Bump @types/node from 22.15.33 to 24.0.6 (#3686)](https://github.com/PrismarineJS/mineflayer/commit/12e50a2e2d0a921d075ebae8aa835437672a2b29) (thanks @dependabot[bot])\n* [Replace wiki.vg by minecraft.wiki. Close #3596](https://github.com/PrismarineJS/mineflayer/commit/c2794e43da71b346278818ff68acb690ec66a4fb) (thanks @rom1504)\n\n## 4.29.0\n* [Sound test (#3657)](https://github.com/PrismarineJS/mineflayer/commit/51495665bbc3789ddc4284403c1ef288fea18ddc) (thanks @rom1504)\n* [Add boss bar test (#3655)](https://github.com/PrismarineJS/mineflayer/commit/b6950e9c42324c0f6fba6f2f802d0c87973a8c92) (thanks @rom1504)\n\n## 4.28.0\n* [Add a test for title and improve the title functionality in mineflayer (#3653)](https://github.com/PrismarineJS/mineflayer/commit/4593da148afd84d9a298074123c5e022f1f8d3e4) (thanks @rom1504)\n* [Add experience test (#3652)](https://github.com/PrismarineJS/mineflayer/commit/32d9d8434465bcea6705d5d6b073a8497adb7c34) (thanks @rom1504)\n* [Add new external test for time. (#3650)](https://github.com/PrismarineJS/mineflayer/commit/52938fe604096887872a831a7ed0c8feca7ee272) (thanks @rom1504)\n* [Add minecraft-mcp-server: mineflayer mcp server to readme](https://github.com/PrismarineJS/mineflayer/commit/cab65b115f0f8737b6756e811995ea095e776858) (thanks @rom1504)\n* [Add Entity Attacker Detection into EntityHurt emitter (#3631)](https://github.com/PrismarineJS/mineflayer/commit/5688f18df4a7a5e47e6a3435902be1c7226e0b0a) (thanks @1tsMeMario)\n* [Added if(vehicle) check (#3619)](https://github.com/PrismarineJS/mineflayer/commit/52c622a4f006e3631f20e6cded236e4424c38d36) (thanks @SinanAkkoyun)\n\n## 4.27.0\n* [Entity Passengers get pushed wrongly (#3601)](https://github.com/PrismarineJS/mineflayer/commit/deb03b52d1e015ece9df1f14536f168f64895c81) (thanks @SinanAkkoyun)\n* [Update bot.clickWindow documentation (#3574)](https://github.com/PrismarineJS/mineflayer/commit/188db17bbb95461743aec2823695c360685559b0) (thanks @kaduvert)\n* [Saving uuid for non-players too (#3603)](https://github.com/PrismarineJS/mineflayer/commit/9937be9b49bb3dd7cd5502c0424809fa66eb60b3) (thanks @SinanAkkoyun)\n\n## 4.26.0\n* [Use node 22 (#3570)](https://github.com/PrismarineJS/mineflayer/commit/dbff9314418d30df203c32fe83f2a1b56653d0a6) (thanks @rom1504)\n* [Fix infinity setTimeout by throwing error (#3561)](https://github.com/PrismarineJS/mineflayer/commit/69539494c88c2ca718330142839a35414ecd3bda) (thanks @BBpezsgo)\n* [Prevent TypeError when removing event lPrevent TypeError when removing event listeners in switchWorld (BunJS issue maybe)isteners in switchWorld (#3544)](https://github.com/PrismarineJS/mineflayer/commit/e974e703a875d16f5e36d35574bf334a20c76b1b) (thanks @0x15d3v2)\n* [Mounting for other entities and fix bot not dismounting when the vehicle is gone (#3384)](https://github.com/PrismarineJS/mineflayer/commit/08b7317b57ca5c2f1a6ddd116bd0c74c2e10c20c) (thanks @qwqtoday)\n\n## 4.25.0\n* [1.21.4 (#3546)](https://github.com/PrismarineJS/mineflayer/commit/8bbf5669f5ff3ea8a708633e51b47c312dc7a26b) (thanks @extremeheat)\n\n## 4.24.0\n* [Support 1.21.3. (#3489)](https://github.com/PrismarineJS/mineflayer/commit/58ae9e5b5abf75139f4ba93fe4f34ef7ed3936e8) (thanks @rom1504)\n* [Fix out of bounds access leading to crash at spawn (#3535)](https://github.com/PrismarineJS/mineflayer/commit/3187368397e880ba8b32bb03affa18203cbcbb42) (thanks @wAIfu-DEV)\n* [fix: use dimension data on 1.16.2 (#3397)](https://github.com/PrismarineJS/mineflayer/commit/f6187f66c16dd122165287be7864c78b2fe7c32c) (thanks @zardoy)\n* [update contribution docs to show test running commands (#3511)](https://github.com/PrismarineJS/mineflayer/commit/71a3a262681a173db86b8911aec82402a6993d21) (thanks @Madlykeanu)\n* [Update inventory.js (#3507)](https://github.com/PrismarineJS/mineflayer/commit/a0e92cad5887181bf7e235f69378c8ede14a350c) (thanks @Pix3lPirat3)\n* [Update FAQ.md - add mineflayer tested versions : lib/version.js (#3517)](https://github.com/PrismarineJS/mineflayer/commit/f2dd3a37505b374bf63119633659e35ec2ce3542) (thanks @boly38)\n* [Bump protodef from 1.17.0 to 1.18.0 (#3523)](https://github.com/PrismarineJS/mineflayer/commit/06faa36c2da3da399bd5370869700aea6c65c9b0) (thanks @dependabot[bot])\n* [Bump mocha from 10.8.2 to 11.0.1 (#3516)](https://github.com/PrismarineJS/mineflayer/commit/166971d317db3ec68cf3eebeda37f509152628fd) (thanks @dependabot[bot])\n* [Fix chatterbox example (#3506)](https://github.com/PrismarineJS/mineflayer/commit/386200759556aa261fa212f26c43992a66cfa8ac) (thanks @ShiftSad)\n* [Proper title event (#3498)](https://github.com/PrismarineJS/mineflayer/commit/3829a25150eec782bc045a222476865af7b0ac72) (thanks @SMEDjs)\n* [Set `sequence` field correctly in activateItem (#3445)](https://github.com/PrismarineJS/mineflayer/commit/fdba03737ecdeaaf419e3175b9be33291db4e085) (thanks @GenerelSchwerz)\n* [increase timeout in external test common](https://github.com/PrismarineJS/mineflayer/commit/3d6e2344751c38428701dc52e9f29dda73f7f782) (thanks @rom1504)\n\n## 4.23.0\n* [1.21 (#3480)](https://github.com/PrismarineJS/mineflayer/commit/4aa10fb45431940504c7809f078f1f410e7fa7a3) (thanks @Madlykeanu)\n* [Adding mindcraft to mineflayer readme](https://github.com/PrismarineJS/mineflayer/commit/dd00db42ba20682418d8fbd5629e1033dfb0ff20) (thanks @rom1504)\n\n## 4.22.0\n* [Remove debug logging (#3478)](https://github.com/PrismarineJS/mineflayer/commit/eb29d350ede0590fce17e04bf21071807a87e3a1) (thanks @extremeheat)\n\n## 4.21.0\n* [1.20.6 (#3412)](https://github.com/PrismarineJS/mineflayer/commit/44fad41c18be5024564e24e1cdee624d35d4d387) (thanks @extremeheat)\n* [Update README.md (#3420)](https://github.com/PrismarineJS/mineflayer/commit/1c2a5c0fa78f74a63fabd7edde85c4a74db32dee) (thanks @SilkePilon)\n* [types: add pitchSpeed as an option in typings (#3446)](https://github.com/PrismarineJS/mineflayer/commit/05b48ad0dad4cf64a1c11660bac256d7b4015841) (thanks @GenerelSchwerz)\n* [Fixed a bug with not closing the window when changing the subserver (#3424)](https://github.com/PrismarineJS/mineflayer/commit/d00c386cfe51cefc361c0ff4d30b100aee9f114a) (thanks @DenisKvak1)\n* [Bump @types/node from 20.14.14 to 22.1.0 (#3431)](https://github.com/PrismarineJS/mineflayer/commit/1d461616b514969fdece38e49bfbec747ab8d76a) (thanks @dependabot[bot])\n* [Fix updateSlot event type (#3425)](https://github.com/PrismarineJS/mineflayer/commit/5d39db26a6ab17baac38b68af8ccd3eeb4af3def) (thanks @DenisKvak1)\n* [Player hitbox fixes (#3382)](https://github.com/PrismarineJS/mineflayer/commit/78b4eccb4572a821b11c3124b7a593f3b91f1180) (thanks @AreaDenial)\n* [Typo fixes (#3418)](https://github.com/PrismarineJS/mineflayer/commit/ef042a242ca9f5fc5820fe4dc2e1d997ef1db202) (thanks @kgurchiek)\n* [Added support for 1.18+ edit book packet #3204 (#3373)](https://github.com/PrismarineJS/mineflayer/commit/eb9982aa04973b0086aac68a2847005d77f01a3d) (thanks @unlimitedcoder2)\n* [Fix typos (#3381)](https://github.com/PrismarineJS/mineflayer/commit/d581ea7cee4d5b7df9606f671656bb0be0fdbf91) (thanks @data-miner00)\n* [Fix typescript types syntax for setCommandBlock (#3366)](https://github.com/PrismarineJS/mineflayer/commit/315cdfc4b1fc2760e4a8a36feb718626a66d5056) (thanks @undefined)\n* [Remove invalid sign check (#3328)](https://github.com/PrismarineJS/mineflayer/commit/ec76468c8ac4c6232bad3c2b66d4160f95f58396) (thanks @zardoy)\n* [refactor: simplifying the code of blockAtCursor (#3337)](https://github.com/PrismarineJS/mineflayer/commit/dc70f932ac9aaab6e6cdb15057b409b15c3232dd) (thanks @SnowRunescape)\n* [Updated setCommandBlock's 3rd argument (#3356)](https://github.com/PrismarineJS/mineflayer/commit/04ad6db404f0da779004b3ddd0e049bf2c6be0a3) (thanks @FlooferLand)\n* [Added the serverBrand property to index.d.ts (#3355)](https://github.com/PrismarineJS/mineflayer/commit/0bb2707d2f6d0d64a467d4e0d6ddc52adf526127) (thanks @Khaogamermain01)\n\n## 4.20.1\n* [Add bossBarCreated event in index.d.ts (#3340)](https://github.com/PrismarineJS/mineflayer/commit/8299288526cd7ff24bcd87511814221f8ad62507) (thanks @gguio)\n* [Update scoreboard.js (#3318)](https://github.com/PrismarineJS/mineflayer/commit/195b3cbd70a110080af9b77a4659991c5d9e484a) (thanks @vicdum)\n* [Fix hardcoded diggingface for cancel digging (#3322)](https://github.com/PrismarineJS/mineflayer/commit/ab78bf855929a476386b5eb6efcf3b271d02455e) (thanks @Vinciepincie)\n* [Fix 1.20.4 server resource pack error (#3320)](https://github.com/PrismarineJS/mineflayer/commit/7c01eeb970647ed2933c10cb2b94fd7b44c777f5) (thanks @TerminalCalamitas)\n* [Fix scoreboard delete handler not first checking if scoreboard exists (#3324)](https://github.com/PrismarineJS/mineflayer/commit/d9e9e15aeb646d81da2a3e2987566de47e3bae04) (thanks @Ynfuien)\n\n## 4.20.0\n* [Update api.md - addChatPattern[Set] link to example of usage (#3304)](https://github.com/PrismarineJS/mineflayer/commit/bb3e5877b7b3b8ab063b39a5b47d103b819da1c2) (thanks @boly38)\n* [Fixed deleted scoreboards not being removed from ScoreBoard.positions (#3306)](https://github.com/PrismarineJS/mineflayer/commit/643023df91bf428d3e7d30e8f2eab97e3238b0b2) (thanks @Ynfuien)\n* [Support 1.20.4 (#3310)](https://github.com/PrismarineJS/mineflayer/commit/aa99daa7d63ee9549f2dda5a79c140e30e19a89b) (thanks @rom1504)\n\n## 4.19.0\n* [Clarify readme createBot username handling (#3300)](https://github.com/PrismarineJS/mineflayer/commit/7a2680bc07f53d16626679537ea1f07aae180549) (thanks @extremeheat)\n* [fix world typing (#3302)](https://github.com/PrismarineJS/mineflayer/commit/5dc36d6cdeaf4be72ea023827d45b9d78e575f66) (thanks @GenerelSchwerz)\n* [modified the README.md files for other languages and fixed a linking issue at those files. (#3297)](https://github.com/PrismarineJS/mineflayer/commit/cc98f1307e3ab48477d2a9ff29da4447f42b30bc) (thanks @Axwaizee)\n* [formatted docs/README.md for easy copy (#3295)](https://github.com/PrismarineJS/mineflayer/commit/468c8aa9d382a7872ec991c3b834b98cbe495e8d) (thanks @Axwaizee)\n* [Added missing bot.teams definition (#3294)](https://github.com/PrismarineJS/mineflayer/commit/fb8ee7aa619bd38cc97d5dbd870bb11455d51d39) (thanks @Ynfuien)\n* [Timeout for bot.tabComplete() (#3293)](https://github.com/PrismarineJS/mineflayer/commit/4231a169d579d08ac7b9ec0694e18b1f6ac837ea) (thanks @Ynfuien)\n* [:label: Update types to be updated with what's in JavaScript (#3287)](https://github.com/PrismarineJS/mineflayer/commit/210785e86c031f7e3323d7d2ffe5152d2d4a5eb6) (thanks @fantomitechno)\n* [Fixed some typo (#3290)](https://github.com/PrismarineJS/mineflayer/commit/ba53a953d03a6edb34aa5bf38bccde58e65d816d) (thanks @SilianZ)\n* [Updated digging code to account for raycasted tall grass checks (#3285)](https://github.com/PrismarineJS/mineflayer/commit/bd0fb5c4d3b665f264009f62f9288828f3018cea) (thanks @GenerelSchwerz)\n\n## 4.18.0\n* [Minecraft 1.20.2 support (#3262)](https://github.com/PrismarineJS/mineflayer/commit/2ff9919760d714be57dcb678f8ab5ecff69f5fee) (thanks @rom1504)\n* [Update recommended Node.js version (#3279)](https://github.com/PrismarineJS/mineflayer/commit/5c71edf48bb2f2dfa16cddb9af5baa0c4d55cf0d) (thanks @Nyaasu66)\n* [feat: bot.respawn, fix respawn with flying squid (#3206)](https://github.com/PrismarineJS/mineflayer/commit/3a6ce543b4ba8a3d0f55777670d142968af14571) (thanks @zardoy)\n* [Add `maxCatchupTicks`, improve `supportFeature` typing (#3277)](https://github.com/PrismarineJS/mineflayer/commit/91108d392c4c5800204dd4674ce9247495ac98e0) (thanks @zardoy)\n* [Fixed typo of \"fromt\" to \"from\" (#3273)](https://github.com/PrismarineJS/mineflayer/commit/216cab742db1cd053d9fa23bd7293b770239085b) (thanks @BorretSquared)\n\n## 4.17.0\n* [Exclude browser from node version check (#3268)](https://github.com/PrismarineJS/mineflayer/commit/c466d327227796865c53bfd24e66668911be4af5) (thanks @rom1504)\n* [Fix for a possible error in lib/plugins/entities.js file (#3254)](https://github.com/PrismarineJS/mineflayer/commit/15cfeb4fa59edfcddf7a0b70a966294b24d798ed) (thanks @Mykola1453)\n* [Make explicit supported versions in readme (#3264)](https://github.com/PrismarineJS/mineflayer/commit/931a4187965aef686c6188b944de84455c65b827) (thanks @rom1504)\n\n## 4.16.0\n* [Fix version check (#3259)](https://github.com/PrismarineJS/mineflayer/commit/88d361f9209cdc2bc4620b32118fb2245f6dcdf9) (thanks @extremeheat)\n\n## 4.15.0\n* [Fix several bugs in villager trading (#3230)](https://github.com/PrismarineJS/mineflayer/commit/1caa2c216b3a10a2bccd7b78a22f3809cb359fe3) (thanks @evan-goode)\n* [Fix `bot.heldItem` and `bot.entity.equipment` (#3225)](https://github.com/PrismarineJS/mineflayer/commit/9865ab72f7438fff9d74f2fe19a138da870c41aa) (thanks @szdytom)\n* [Improve CI per version setup (#3256)](https://github.com/PrismarineJS/mineflayer/commit/48c3ca71ea5822c4304ec74951970dbefd5026eb) (thanks @rom1504)\n* [added Readme Português-BR (#3219)](https://github.com/PrismarineJS/mineflayer/commit/70a652ee5b6c0151826e17b38efd458357fc93ac) (thanks @LukeTheNeko)\n* [Fixes `fireworkRocketDuration` calculation (#3222)](https://github.com/PrismarineJS/mineflayer/commit/3d8a1aaed036c2df74c2e607245cefab12409761) (thanks @szdytom)\n* [Update Minecraft Wiki links to new domain after fork (#3203)](https://github.com/PrismarineJS/mineflayer/commit/08208e2f110af2c6de41fac9a389597aac916412) (thanks @misode)\n* [typings: add entityAtCursor to bot (#3200)](https://github.com/PrismarineJS/mineflayer/commit/7016c19f9c736671d8af1401ac25d5175401891f) (thanks @SnowRunescape)\n* [Handle unknown scoreboard objectives (#3191)](https://github.com/PrismarineJS/mineflayer/commit/2e02cee82d6d154b3b7bfb30d213479e7c4fbc59) (thanks @frej4189)\n* [Sidebar fixes (#3188)](https://github.com/PrismarineJS/mineflayer/commit/e571e54edf46ac6da000e1c84f36bec3b75ccf24) (thanks @FurnyGo)\n* [Fix ci : fix lint in MD (#3192)](https://github.com/PrismarineJS/mineflayer/commit/7987e3c546038de0eaa6d573596f51d3edc383bb) (thanks @frej4189)\n* [Updating RU docs (#3178)](https://github.com/PrismarineJS/mineflayer/commit/7474564da5432295c682e8a4f827f58e3c3f3be8) (thanks @FurnyGo)\n\n## 4.14.0\n* [Update Jupyter notebook to install node 18, update the server in example (#3176)](https://github.com/PrismarineJS/mineflayer/commit/e8a967d4e832f72d665781492c037d26169ae5a0) (thanks @extremeheat)\n* [Update index.d.ts (#3175)](https://github.com/PrismarineJS/mineflayer/commit/d4db3991c135344180937b69621c0ee31daa39f0) (thanks @StayWithMeSenpai)\n* [Add elytra flying support and rocket support (#3163)](https://github.com/PrismarineJS/mineflayer/commit/010460e9dd752a56195d8a48f35a62e704dcf99f) (thanks @lkwilson)\n\n## 4.13.0\n* [Switch to entity.displayName (#3168)](https://github.com/PrismarineJS/mineflayer/commit/2409ad458b952173de669a7d9cfaeb770effe3ae) (thanks @lkwilson)\n* [Update readme auth doc (#3169)](https://github.com/PrismarineJS/mineflayer/commit/f5d4a288a768ca6717fa4d22c72fb0267428c684) (thanks @extremeheat)\n* [Add OpenDeliveryBot to \"Projects Using Mineflayer\" (#3162)](https://github.com/PrismarineJS/mineflayer/commit/ab3c0cf25d0cc28ccba89640b2ceff6ab6b4dace) (thanks @SilkePilon)\n* [Use node 18 on CI (#3157)](https://github.com/PrismarineJS/mineflayer/commit/d3df34dcaa804a71bf0d8cc50a419990d4a2dce3) (thanks @extremeheat)\n* [Fix ambigious function naming (#3161)](https://github.com/PrismarineJS/mineflayer/commit/9ecdf201794bfa350486839a01e318dfd94b3bfb) (thanks @frej4189)\n\n## 4.12.0\n* [Mineflayer physics refactor (#2492)](https://github.com/PrismarineJS/mineflayer/commit/d0eb3a1afe6cda7b04ae2f88052cd868ba0c0c4f) (thanks @U5B)\n\n## 4.11.0\n* [Import changedSlots computation from prismarine-windows (#3134)](https://github.com/PrismarineJS/mineflayer/commit/e5b5eeecf1133c1c80c0ef48d6e72fed77d84834) (thanks @kaduvert)\n* [Make the place block success check ignore block updates received with no block type changes (#3090)](https://github.com/PrismarineJS/mineflayer/commit/bbdd93afe2e31d1f1e899176e7edf8e73af5d5d3) (thanks @PondWader)\n* [Use node-minecraft-protocol for chat (#3110)](https://github.com/PrismarineJS/mineflayer/commit/385fba65ed6ebe632c870c7cf234666cacf5a766) (thanks @lkwilson)\n* [Extended useChests.js tests (#3132)](https://github.com/PrismarineJS/mineflayer/commit/131a7ea63c9c6b2cce41ebb29a26c898f859471d) (thanks @kaduvert)\n* [Allow more click modes (#3133)](https://github.com/PrismarineJS/mineflayer/commit/a315653bb94274113c9d6078d4c2ab840af0f62a) (thanks @kaduvert)\n* [Add nether test (#2932)](https://github.com/PrismarineJS/mineflayer/commit/6b1d6ea15c72edc5b761b78765a53d2ab7d0d274) (thanks @frej4189)\n* [Explicitly depend on pitem 1.14.0 with fix](https://github.com/PrismarineJS/mineflayer/commit/acc6ec9b5e61d566facb76e9c3ff512cc9a5137f) (thanks @rom1504)\n* [Make sure we pass a string to a storagebuilder (#2645)](https://github.com/PrismarineJS/mineflayer/commit/fc95843dac69bc1101dd5ec898a2aaf4dcfbf520) (thanks @u9g)\n* [extra types for enchantments (#3123)](https://github.com/PrismarineJS/mineflayer/commit/b336d2259d1ce0935bf8e10a4edb3c0a9030fb10) (thanks @zisis912)\n* [Add 1.20 to supported versions in readme (#3111)](https://github.com/PrismarineJS/mineflayer/commit/d764706f53dbe7ba16cf49645d66d192a309cc5c) (thanks @litfa)\n* [Handle hand swap entity status (#3097)](https://github.com/PrismarineJS/mineflayer/commit/a80d69a8f1a637ab1a0720ec776fc4f05c38afed) (thanks @PondWader)\n* [Add command gh workflow allowing to use release command in comments (#3116)](https://github.com/PrismarineJS/mineflayer/commit/5a55744ee0dc670f984229ec2629239bdc3e5705) (thanks @rom1504)\n\n## 4.10.1\n\n* Fix attempting to access unloaded chunks (@frej4189)\n\n## 4.10.0\n\n* Fix handling for entities with unknown metadata (@extremeheat)\n* support 1.20 (@PondWader)\n\n## 4.9.0\n\n* Fix bot not updating world height on respawn packet (@frej4189)\n* Persist properties received in player_info packet (@Paulomart)\n* Fix reference error with block updates (@IceTank)\n* Add spectator to gameModes array (@williamd5)\n* Standardize dimensions for all versions (@sefirosweb)\n* Emit inject_allowed after a timeout of 0 (@IceTank)\n* Add window transaction timeout (@firejoust)\n* Made bot auto respawning togglable (@Averagess)\n* support 1.19.4 (@extremeheat)\n\n## 4.8.1\n\n* Fix client crashing when player_remove contains unknown player (@frej4189)\n* Improve look and fix bug slow craft (@sefirosweb)\n* Fix player entity being unset when player is updated (@frej4189)\n* Fix type (@sefirosweb)\n* Improve crafting stacks (@sefirosweb)\n* add example for using the node:readline module (@Jovan-04)\n\n## 4.8.0\n\n* Update chat parsing (@frej4189)\n* Fix message event not including chat position (@frej4189)\n* 1.19.3  (@frej4189)\n\n## 4.7.0\n\n* 1.19.2 support (@frej4189)\n\n## 4.6.0\n\n* Fix unhandled promise rejection in onceWithCleanup (@IceTank) [#2833](https://github.com/PrismarineJS/mineflayer/pull/2833)\n* Extend every window that is opened with mineflayer specific window functions (@IceTank) [#2768][https://github.com/PrismarineJS/mineflayer/pull/2768]\n* Fix example command line usage messages (@maximmasiutin) [#2853](https://github.com/PrismarineJS/mineflayer/pull/2853)\n* Update README_ES.md (@PanIntegralus) [#2803](https://github.com/PrismarineJS/mineflayer/pull/2803)\n* Fix block face position target when digging (@WhoTho) [#2801](https://github.com/PrismarineJS/mineflayer/pull/2801)\n* Add a native mineflayer event for particles (@NyxaYu) [#2813](https://github.com/PrismarineJS/mineflayer/pull/2813)\n* Fix viewDistance type (@Nciklol) [#2824](Fix viewDistance type (#2824) ) \n* Add French FAQ (@AugustinMauroy) [#2817](https://github.com/PrismarineJS/mineflayer/pull/2817)\n\n## 4.5.1\n\n* Fixed syntax error in TypeScript definitions (@JungleDome) [commit](https://github.com/PrismarineJS/mineflayer/commit/2c6a4036d84bedb5f349ea5a82d743e344c34224)\n\n## 4.5.0\n\n* 1.19 support (@extremeheat @rom1504 @FCKJohni @Shorent)\n* refactoring examples to use bot.registry (@Epirito)\n* Added barrel and coloured shulker boxes to openable windows (@lazydancer)\n* types: Fix return type for openBlock and openEntity (@sefirosweb)\n* Update activateEntity and activateEntityAt types (@amoraschi)\n\n## 4.4.0\n\n* Fix chatterbox example not getting dropped item (@u9g) [commit](https://github.com/PrismarineJS/mineflayer/commit/f860eac01a0418f4a3de749482d8cab681acc48a)\n* Fix 404d link to license (@BalaM314) [#2601](https://github.com/PrismarineJS/mineflayer/pull/2601)\n* Add bot.clickWindow mode disclaimer (@IceTank) [#2595](https://github.com/PrismarineJS/mineflayer/pull/2595)\n* Add spectator to GameMode types (@IceTank) [#2627](https://github.com/PrismarineJS/mineflayer/pull/2627)\n* Update types for isABed (@amoraschi) [#2628](https://github.com/PrismarineJS/mineflayer/pull/2628)\n* Replace openChest with openContainer in docs and examples (@slightly-imperfect) [#2656](https://github.com/PrismarineJS/mineflayer/pull/2656)\n* Add ender chests as a chest type (@RoseChilds) [#2642](https://github.com/PrismarineJS/mineflayer/pull/2642)\n* Added method to wait until sleep function is in reality sleeping (@sefirosweb) [#2617](https://github.com/PrismarineJS/mineflayer/pull/2617)\n* Added type on move event (@sefirosweb) [#2712](https://github.com/PrismarineJS/mineflayer/pull/2712)\n* Added thunderState type (@sefirosweb) [#2711](https://github.com/PrismarineJS/mineflayer/pull/2711)\n* Fix type error on chest open (@IceTank) [#2684](https://github.com/PrismarineJS/mineflayer/pull/2684)\n* Add support for repeating and chain command blocks. (@mirkokral) [#2669](https://github.com/PrismarineJS/mineflayer/pull/2669)\n* Add player object to blockBreakProgressEnd & observed. (@JackCrispy) [#2647](https://github.com/PrismarineJS/mineflayer/pull/2647)\n* Add entity to blockBreakProgress (@JackCrispy ) [#2648](https://github.com/PrismarineJS/mineflayer/pull/2648)\n* Add direction support to activateBlock, openBlock (@IceTank) [#2039](https://github.com/PrismarineJS/mineflayer/pull/2039)\n* Add entityAtCursor function (@O-of) [#2077](https://github.com/PrismarineJS/mineflayer/pull/2077)\n* Fix regex dos (@IceTank) [#2350](https://github.com/PrismarineJS/mineflayer/pull/2350)\n\n## 4.3.0\n\n* Cache 'positionUpdateSentEveryTick' feature lookup (@IceTank)\n* Remove old teams from bot.teamMap (@U9G)\n* mcdata 3.0.0\n\n## 4.2.0\n\n* add missing extraInfos argument to Bot.blockAt function (@dumbasPL)\n* Emit window close event AFTER updating the inventory (@imharvol)\n* Move supportFeature to mcdata (@U9G)\n* Update lib/ and test/ to use prismarine-registry (@extremeheat)\n* only open chests with openContainer (@U9G)\n* Add bot.creative.clearSlot and bot.creative.clearInventory (@U9G)\n* remove transaction warning\n\n## 4.1.0\n\n* 1.18.2 support\n* Add nbt option to withdraw and deposit\n\n## 4.0.0\n\n* useEntity maintains sneak state\n* BREAKING: remove all callbacks in favor of promises\n\n## 3.18.0\n\n* remove callbacks from types and docs\n\n## 3.17.0\n\n* callback are now depreciated with mineflayer. Any use of them will print a warning\n\n## 3.16.0\n\n* Use prismarine-chunk for block entities\n\n## 3.15.0\n\n* Supports 1.18\n\n## 3.14.1\n\n* Fix arm_animation and use_entity (@amorashi)\n\n## 3.14.0\n\n* Make prismarine-entity versioned (@u9g)\n* fix(typings): Added OpenContainer (@SaubereSache)\n\n## 3.13.1\n\n* Fix bug with force lastSentPitch in bot.look (@KadaverBrutalo10)\n* Fix typo harming type safety (@Eagle-Anne)\n\n## 3.13.0\n\n* compute scoreboard displayName dynamically (@U9G)\n* SkinsRestorer fix (@U5B)\n* Fix bot not swinging arm on block place (@IceTank)\n\n## 3.12.0\n\n* Bypass anticheats that detect sensitivity (@mat-1)\n* Fix removing many players at once from tab list (@mat-1)\n* Added blockAtEntityCursor function (@DatArnoGuy)\n* add option to disable default chat patterns (@U5B)\n* Fixed wrong arm swinging (@IceTank)\n* Add pitch speed to look (@IceTank)\n* Console spam fix (@IceTank)\n* Update openVillager function to return a promise (@amoraschi)\n* Send arm_animation before use_entity (@aesthetic0001)\n* Add reason for the end of a mineflayer bot (@U5B)\n* added rejection of invalid transaction packets (anticheat fix) (@U5B)\n\n## 3.11.2\n* Remove unnecessary and buggy inventory check in place block (@Karang)\n* Make all events allow async cb typings (@u9g)\n\n## 3.11.1\n* Get rid of nowaiting (@nickelpro)\n* update readme (@inthmafr)\n* Fix Typings (@link-discord, @IceTank, @u9g)\n\n## 3.11.0\n* better chat, equipping and consuming errors (@u9g)\n* add bot.usingHeldItem (@mat1)\n* 1.17.1 support (mainly work from @nickelpro and @u9g, but also @Archengius @extremeheat @imharvol @willocn and @rom1504)\n\n## 3.10.0\n* Add Chinese translations (@Nyaasu66)\n* Fix bot.equip failing with off-hand (@IceTank)\n* window.withdraw no longer will drop items if it takes too many items (@Zn10plays)\n* No longer have to await ready for enchanting (@u9g)\n* Remove polling, recursive calling, rechecks for bot.waitForChunksToLoad (@u9g)\n* Add crystal placing example (@u9g)\n* Fixes physicsEnabled check for knockback (@u9g)\n* Default swingArm to left hand (@u9g)\n* Add support for teams (@builder-247)\n* Add missing bot.transfer documentation (@IceTank)\n\n## 3.9.0\n* Fix crash on blocks without registered blockId (@Furry)\n* Move when hit by an explsion (@u9g)\n* Add getExplosionDamages() function (@Karang)\n* doc of get explosion (@link-discord)\n\n## 3.8.0\n* Improved index.d.ts (@DrMoraschi)\n* Added resource pack support (@kaffinpx)\n* Fixed bot.dig error (@MoneyMakingTornado)\n* Added timeout to #consume (@SeanmcCord)\n* Added example for resource pack (@u9g)\n* Improved workflow (@u9g)\n* Linted JS in md files (@u9g)\n* Added bot oxygen Level management (@kaffinpx)\n* Improved links (@satyamedh)\n* Improved links (@AwesomestCode)\n* Improved typing (@u9g)\n* Refactored chat.js (@u9g)\n* Expanded placeBlockWith Options to offhand (@aestetic)\n* Added anvil test (@u9g)\n* Added placeEntity() (@u9g)\n* Improved oxygen typings (@DrMoraschi)\n* Improved socket snippet (@iceTank)\n* Improved placeEntity (@u9g)\n* Renamed bot.quit to end (@u9g)\n* Updated Spanish readme (@DrMoraschi)\n* Added French Translations (@creeper09)\n* Corrected java version in gitpod (@rom)\n* Improved readme lint (@rom)\n* Added container and dropper to allowWindowTypes (@IceTank)\n\n\n## 3.7.0\n* Add bot.removeChatPattern() (@BlueBurgersTDD)\n* Add events to typings (@DrMoraschi)\n* Add TR translation (@KaffinPX)\n* Create plugin example (@Zn10plays)\n* Revise readme (@IceTank)\n* Revise chat_parsing example comments (@U5B)\n* Revise raycast example (@IceTank)\n* allow passing nmpclient as an option in createbot (@u9g)\n* Add bot.awaitMessage() (@u9g)\n* Add modular example (@u9g)\n* Fix bug with chat patterns (@u9g)\n* Fix bug with game event (@u9g)\n\n## 3.6.0\n* add bot.addChatPattern() & bot.addChatPatternSet() & deprecate bot.chatAddPattern() (@U9G)\n\n## 3.5.0\n* Add common errors to FAQ (@U9G)\n* Move mosts of index.js to lib/loader.js (@U9G)\n* Improve packet_info handling (@Karang)\n* Add getControlState function (@Camezza)\n\n## 3.4.0\n* fix once leak in placeBlock (@Karang)\n* allow sleeping during rain/thunderstorms (@qrvd)\n* Change transaction apology packet to match vanilla client (@FeldrinH)\n\n## 3.3.3\n* fix world switch leak\n\n## 3.3.2\n* fix entity names\n\n## 3.3.1\n* fix stop digging (@Karang)\n\n## 3.3.0\n* trading fix (@validgem)\n* fix enchantments (@goncharovchik)\n* fix newListener and removeListener stacking on world change (@U5B)\n* add a 'messagestr' event (@U9G)\n* Add an option forceLook for place block similar to the digging one (@CyberPatrick)\n* Can see block add intersect match (@sefirosweb)\n* Add ability to use an anvil fully (@U9G)\n\n## 3.2.0\n* Fix position in getBlock()\n\n## 3.1.0\n* Fix typings of findBlock and findBlocks (@csorfab)\n* place block improvements (@Karang)\n* add face option to dig (@IceTank)\n* trading fixes (@validgem)\n* world events exposed by pworld (@u9g)\n* fix wait for ticks and expose physicsEnabled (@Karang)\n\n## 3.0.0\n* added null or undefined check in inventory (@u9g)\n* Removed broken use of \"this\" in physics.js (@TheDudeFromCI)\n* Promisify testCommon (@ArcticZeroo)\n* Fixed Bot not skipping end credits (@IceTank)\n* BREAKING: Simplify windows API and promisify tests (@Karang) : several methods and events from window API were changed:\n  * Removed Chest, EnchantmentTable, Furnace, Dispenser and Villager classes (they all are Windows now)\n  * Dispensers are now handled by the same code as other containers, hopper too (they were missing)\n  * There is now only 2 events signaling a slot update (\"updateSlot\" and \"updateSlot:slotId\" of the Window class) (before there was: \"setSlot\", \"setSlot:windowId\", \"windowUpdate\", \"updateSlot\", on 3 different eventEmitter (and not all of them were working properly))\n  * All windows (present and future) now have a withdraw and deposit function\n\n## 2.41.0\n* Fix Time type definition (@hivivo)\n* Add face for block in sight result (@Karang)\n* Fix skin restorer bug (@TheDudeFromCI)\n* Improve enchantment table info (@Karang)\n* 1.16.5 support (@rom1504)\n\n## 2.40.1\n* Fix for not handling negative numbers in time plugin (@Naomi)\n* Fix typescript Bot definition (@rom1504)\n\n## 2.40.0\n* fix for dig ignore (@TheDudeFromCI)\n* better calculation of digging range (@goncharovchik)\n* emit death once (@extremeheat)\n* add waitForTicks function (@TheDudeFromCI)\n* add null check for sign text (@u9g)\n\n## 2.39.2\n* explicit node 14 support\n\n## 2.39.1\n* add null check in bot.dig (@rom1504)\n* Fix deprecation warning for block in sight (@Karang)\n\n## 2.39.0\n* Add number support to bot.chat (@BlueBurgersTDD)\n* Fixed && Improved blockFind function with useExtraInfo = true (@magicaltoast)\n* Added option to allow the bot to keep it's head in place when mining. (@TheDudeFromCI)\n\n## 2.38.0\n* Add bot.game.serverBrand property (@Karang)\n* set extraInfos to false in blockIsNotEmpty (@mat-1)\n* make the ChatMessage.toAnsi:lang argument optional (@Antonio32A)\n* Fixed message types (@TheDudeFromCI)\n* by default hideErrors is now true (@rom1504)\n\n## 2.37.1\n* Optimize lookAt promise behavior (@ph0t0shop)\n\n## 2.37.0\n* Promisify villager & Trader (thanks @ph0t0shop)\n* protect against action id going over 32767 (@rom1504)\n* fix incorrect handling of username definition (@rom1504)\n\n## 2.36.0\n* all async method now both return promises and take a callback (thanks @ph0t0shop for this great improvement)\n\n## 2.35.0\n* Extra position packet after TP\n* Add blockAtCursor\n* Deprecate blockInSight\n* TS typing fixes\n\n## 2.34.0\n* 1.16.4 support\n\n## 2.33.0\n* block_actions fix (thanks @SpikeThatMike)\n* typescript fixes (thanks @TheDudeFromCI and @NotSugden)\n* add uuid by objectUUID handling (thanks @Rob9315)\n* fix bed packet (thanks @imharvol)\n* better plugin handling (thanks @TheDudeFromCI)\n\n## 2.32.0\n* 1.16.3 support (thanks @GroobleDierne and @TheDudeFromCI)\n* fix bug with entity width (thanks @TheDudeFromCI)\n* Add ability to call openChest on shulker boxes (thanks @efunneko)\n\n## 2.31.0\n* Fix furnace and add tests (thanks @ImHarvol)\n* Add offhand param to d.ts (thanks @TheDudeFromCI)\n* Add hasAttackCooldown feature (thanks @TheDudeFromCI)\n* Add type validation for bot.chat (thanks @BlueBurgersTDD)\n* Add chat position to message event (thanks @larspapen)\n\n## 2.30.0\n* Add support for Barrel (#1344) (thanks @ImHarvol)\n* Fix attack cooldown bug (thanks @TheDudeFromCI)\n* Exposed getDestSlot (thanks @TheDudeFromCI)\n* Simplify setCommandBlock arguments (thanks @ImHarvol)\n* hide unknown transaction warning if hideErrors option is enabled\n\n## 2.29.1\n* fix findblock typescript def (thanks @TheDudeFromCI)\n* fix setCommandBlock for recent versions (thanks @ImHarvol)\n\n## 2.29.0\n* Add hand parameter to activateItem (thanks @Karang)\n* remove _chunkColumn from the api (bot.world should now be used)\n* Handle MC|AdvCmd misspelling (thanks @ImHarvol)\n\n## 2.28.1\n* fix findBlocks (thanks @Karang)\n\n## 2.28.0\n* add nearestEntity function (thanks @Karang)\n\n## 2.27.0\n* add heldItemChanged\n\n## 2.26.0\n* use and expose prismarine-world as bot.world\n* add itemDrop event (thanks @ImHarvol)\n* fix bot.fish callback (thanks @GroobleDierne)\n* parse entity metadata for crouching (thanks @IdanHo)\n* fix bot.time.day (thanks @Naomi-alt)\n* improve find blocks options (thanks @Karang)\n\n## 2.25.0\n* emit chestLidMove (thanks @imharvol)\n* add options for main hand selection (thanks @Colten-Covington)\n* fix respawning columns issues (thanks @Karang)\n\n## 2.24.0\n* Fix getBlockAt when outside bounds\n* Improve documentation and examples\n* Add ability to change the skin parts of a bot (thanks @Naomi-alt)\n\n## 2.23.0\n* 1.16 support\n* fix noteheard (thanks @Naomi-alt)\n\n## 2.22.1\n* better typedef (thanks @Konstantin)\n* fix off by 1 error in findBlocks (thanks @Karang)\n* physics.js look fix (thanks @thesourceoferror)\n* fix chat message bracketing (thanks @Nurutomo)\n* use prismarine-physics\n\n## 2.22.0\n* Improve digTime computation (thanks @Karang)\n* expose blockEntity.raw (thanks @SiebeDW)\n* improve typedef for find block options (thanks @TheDudeFromCI)\n\n## 2.21.0\n* don't log errors if hideErrors is true\n\n## 2.20.0\n* add extra infos option in find block\n\n## 2.19.2\n* fix ground up for 1.13->1.15\n\n## 2.19.1\n* fix find block (thanks @Karang)\n* improve sign parsing (thanks @cookiedragon234)\n\n## 2.19.0\n* much faster findBlock (thanks @Karang)\n\n## 2.18.0\n* fix bugs in lookAt and setQuickBarSlot\n* add auto_totem example (thanks @AlexProgrammerDE)\n* improve blockAt speed\n\n## 2.17.0\n* physics engine refactor (thanks @Karang)\n* mcdata update for better 1.14 and 1.15 support\n\n## 2.16.0\n* use protodef compiler (thanks @Karang)\n* off-hand support (thanks @Karang)\n* fix type definitions (thanks @dada513)\n\n## 2.15.0\n* fix transfer bugs (thanks @Karang)\n* add typescript definitions (thanks @IdanHo)\n\n## 2.14.1\n* fix openVillager\n\n## 2.14.0\n* 1.15 support\n* russian translation (thanks @shketov)\n\n## 2.13.0\n* 1.14 support : more tests, refactored pwindows, feature flags (thanks @Karang)\n* Look at the center of the face when placing block\n* improve bot.sleep : don't sleep if mob are present (thanks @ImHarvol)\n\n## 2.12.0\n* 1.13 support (thanks @Karang, @hornta, @SiebeDW)\n* better fishing support (thanks @hutu13879513663)\n\n## 2.11.0\n* Expose columns & blockEntities (thanks @SiebeDW)\n* Create discord.js (thanks @SiebeDW)\n* change amount of slots based on version (thanks @IdanHo)\n* Fix 'respawn' event (thanks @ImHarvol)\n* Add callback to creative set block (thanks @wvffle)\n\n## 2.10.0\nLot of fixes from @wvffle in this release :\n* more checks when digging\n* expose a bot.swingArgm() function\n* better toString to chat message\n* fix handling of empty signs\n* correct handling of entity metadata change\nAnd some others :\n* new tps plugin by @SiebeDW\n* correct handling of chunk unloading by @IdanHo\n\n## 2.9.6\n* fix logErrors option\n\n## 2.9.5\n* fix logErrors\n\n## 2.9.4\n* enable catching and logging of errors by default\n\n## 2.9.3\n* fix typo in variable name actionId\n\n## 2.9.2\n* improve pushback (thanks @Vap0r1ze)\n* more robust handling of tablist (thanks @wvffle)\n* ignore (with a warning) transaction without previous click\n\n## 2.9.1\n* improve boss bar\n* add checks in scoreboard implementation\n\n## 2.9.0\n\n* add universal chat patterns to support more chat plugins\n\n## 2.8.1\n\n* fix error on scoreboard removal\n\n## 2.8.0\n\nlot of new features from @wvffle :\n\n* support for block entities\n* improved block bars support\n* add block in sight\n* fix scoreboard support\n* add eating support\n* add tab complete support\n* add fishing support\n* better sign text support\n* repl example\n\n## 2.7.5\n\n* improve basic find block a bit\n\n## 2.7.4\n\n* start the bot alive in all cases\n* correct run speed and use it to limit the speed properly (thanks @CheezBarger)\n* emit error instead of throwing when loading a chunk (thanks @ArcticZeroo)\n\n## 2.7.3\n\n* use docsify for docs\n\n## 2.7.2\n\n* don't do anything if transaction.action < 0 (fix for some non-vanilla plugins)\n\n## 2.7.1\n\n* include fixes from pchunk, protodef and mcdata\n\n## 2.7.0\n\n* fix cannot jump repeatedly\n* fix spaces in chatmessage (thanks @Gjum)\n* add bot.getControlStates (thanks @ArcticZeroo)\n* Support end dimension (thanks @iRath96)\n* Added sneaking option to controll states (thanks @Meldiron)\n* add title event (thanks @yario-o)\n* Update sound.js to include hardcoded sound effects (thanks @jeresuikkila)\n* Support for the new launcher_profiles.json format  (thanks @Amezylst)\n* update api about checkTimeoutInterval\n\n## 2.6.1\n\n* fix chatmessage\n* add plugins to bot options to be able to disable an internal plugin\n\n## 2.6.0\n\n* improve ChatMessage translation functionality (thanks @plexigras)\n* added eslint\n* es6\n* fix autoversion in online mode\n\n## 2.5.0\n\n* don't swing arm when activating an entity\n* new plugin loading api\n\n## 2.4.1\n\n* better 1.12 support\n\n## 2.4.0\n\n* auto version detection (thanks @plexigras)\n\n## 2.3.0\n\n* support version 1.12 (thanks @jonathanperret)\n* add example to use minecraft session file for auth (thanks @plexigras)\n\n## 2.2.0\n\n* added book writing plugin (thanks @plexigras)\n* Make sure bot.time.day is between 0 and 24000 (thanks @roblabla)\n* Pass skyLightSent to Chunk.load (thanks @iRath96)\n\n## 2.1.1\n\n* use protodef aliases to properly define channels\n\n## 2.1.0\n\n* add bot.canSeeBlock (thanks @Nixes)\n* handle unknown entities and entities sent with their internal id\n* add bloodhound to plugin list\n* fix chat hoverEvent for 1.9\n\n## 2.0.0\n\n* added support for minecraft chests (thanks @plexigras)\n* cross version support : 1.8, 1.9, 1.10 and 1.11 now supported\n* [BREAKING] prismarine classes (Block, Entity, Recipe, ...) are now available only by requiring them, not in mineflayer.X. It was required to make cross version possible. minecraft-data is also to be required directly and not available as mineflayer.blocks. The code depending on this should be updated, hence the major version.\n\n## 1.8.0\n\n* add actionBar event (thanks @ArcticZeroo)\n* added support for villager trading (thanks @plexigras)\n\n## 1.7.5\n\n* bump dependencies\n\n## 1.7.4\n\n* update minecraft-data\n\n## 1.7.3\n\n* add callback to activateBlock\n\n## 1.7.2\n\n* update dependencies\n\n## 1.7.1\n\n * update minecraft-protocol, minecraft-data and protodef\n\n## 1.7.0\n\n * listen for disconnect in login phase (thanks @deathcap)\n * fix multi_block_change (thanks @Corgano)\n * remove chat filter : fix utf8 in chat\n * add extra tolerance for malformed sign packets (thanks @G07cha)\n * adapt to new minecraft data entities format\n * update minecraft-protocol to 0.17.2\n\n\n## 1.6.0\n\n * add functionalities to use scoreboard (thanks @jakibaki)\n * update to minecraft-data 0.16.3\n * 50 -> 20 tps for physics\n * Remove requireindex, for browserify support\n * add bot.setCommandBlock\n\n## 1.5.3\n\n * fix entity_status\n\n## 1.5.2\n\n * use prismarine-recipe and prismarine-windows\n * use require-self to be able to do require('mineflayer') in the examples\n * fix viewDistance sending\n\n## 1.5.1\n\n * add checkTimeoutInterval to createBot\n\n## 1.5.0\n\n * fix achievements parsing in toString()\n * update to nmp 0.16\n * use prismarine-item\n * add example to run multiple bots\n * uuid is now a dashed string\n * remove digging interruption : this doesn't happen in 1.8 servers (and caused problem in some spigot servers)\n\n## 1.4.0\n\n * improve placeBlock : now use lookAt before placing and has a callback\n * fix soulsand speed\n * use new multi-version version of (node-)minecraft-data\n\n## 1.3.0\n\n * swing arm on placing a block, look at center of block when activating a block (thanks gipsy-king)\n * refactor examples (thanks Pietro210)\n * add clickWindow support to ContainerWindow (thanks Gnomesley)\n * fix skylight in the nether\n * update node-mojangson to display unparsed text in case of error\n\n## 1.2.1\n\n * Prevent crash when an unknown entity is spawned\n * add createBot to api.md\n\n## 1.2.0\n\n * update minecraft-protocol to 0.14.0 : several fixes (error are now catchable, packets are in-order, packets fixes, etc.)\n * add ContainerWindow to support non-Vanilla plugins and add /invsee example (thanks Pietro210)\n * add a callback to bot.look and bot.lookAt\n * when receiving a remove effect packet : if the corresponding effect doesn't exist yet, emit an event with just the id of the effect (thanks Pietro210)\n * swing arm immediately when digging (thanks gipsy-king)\n * now updates bot.entity.heldItem when bot.heldItem is updated\n * fix cli args in examples\n * add forcedMove event\n * fix equipment api\n * new minecraft data version : better metadata handling\n\n## 1.1.2\n\n * a small fix in chat.js\n * add a licence file\n\n## 1.1.1\n\n * bot.transfer is faster\n * fix arm_animation\n * using mojangson parser for chat hoverevent\n * add chat patterns for unidentified chat messages\n * fix player leaving\n\n## 1.1.0\n\nLot of fixes and improvements in this version in order to support mineflayer 1.8.3, including :\n\n * minecraft 1.8.3 support\n * update minecraft protocol to 0.13.4\n * move enums data to minecraft-data\n * add automatic testing with a vanilla minecraft server on circle ci\n * add argv arguments to examples\n * refactor inventory.js\n * use new recipe format handling metadata better\n * fix lot of things to support 1.8.3 including :\n  * block format change\n  * position change : y is now always at the feet of the bot\n\n## 1.0.0\n\n * updated minecraft protocol to 0.11 (Minecraft 1.6.2 support).\n * small changes in the arguments of some events: `chat`, `whisper` and `message`. See [doc/api.md](https://github.com/andrewrk/mineflayer/blob/master/doc/api.md).\n\n## 0.1.1\n\n * updated minecraft protocol to 0.10 (Minecraft 1.5.2 support).\n\n## 0.1.0\n\nHuge thanks to [zuazo](https://github.com/zuazo) for debugging and\neliminating the problems with 1.5.1 protocol update and node 0.10 update!\n\n * update minecraft-protocol to 0.9.0 - includes many fixes\n * blocks: fix buffer length assertion error (thanks zuazo)\n * physics: fix assertion error (thanks zuazo)\n\n## 0.0.35\n\n * inventory: window clicking waits a bit if you have just dug\n   fixes a rejected transaction race condition.\n\n## 0.0.34\n\n * inventory: equipping makes the quick bar a basic LRU cache.\n   This can alleviate some race conditions when trying to equip a\n   different tool immediately after digging.\n\n## 0.0.33\n\n * crafting: fix shapeless recipe support\n * inventory: fix several instances which could cause transaction rejected\n * add missing recipes (thanks rom1504)\n * `recipe.delta` data structure changed.\n\n## 0.0.32\n\n * digging: fix crash when not holding a tool\n\n## 0.0.31\n\n * only stationary water has a negative effect on digging\n * digging: if you dig while already digging, instead of crashing,\n   mineflayer will cancel the in progress dig and start the new one.\n * digging: in creative mode dig time is 0\n * digging interruption error has a code so you can check for it\n\n## 0.0.30\n\n * expose the materials enum as `mineflayer.materials`\n\n## 0.0.29\n\n * digging is faster and has less bugs\n * you can stop digging with `bot.stopDigging()`.\n * `bot.dig(block, [timeout], [callback])` changed to `bot.dig(block, [callback])`.\n * add `bot.digTime(block)`\n * add `block.material`\n * add `block.harvestTools`\n * add `window.emptySlotCount()`\n * block and item enums are cleaned up. Every block and item has an\n   unambiguous `name` and `displayName`.\n\n## 0.0.28\n\n * add missing recipe for wooden planks\n * fix various crafting and inventory bugs\n * unequip works with hand as a destination\n\n## 0.0.27\n\n * add `mineflayer.Location` which can help you locate chunk boundaries\n * `entity.metadata` is formatted as an object instead of an array for\n   easier access\n * `canDigBlock` returns `false` if `block` is `null` instead of crashing.\n\n## 0.0.26\n\n * fix `bot.heldItem` being wrong sometimes\n * water and lava are not solid\n\n## 0.0.25\n\n * `bot.equip` - wait at least a tick before calling callback\n\n## 0.0.24\n\n * fix digging leaves not calling callback.\n\n## 0.0.23\n\n * add enchantment table support. See `examples/chest.js` for an example.\n * rename `bot.tell` to `bot.whisper` to be consistent with 'whisper' event.\n   (thanks Darthfett)\n\n## 0.0.22\n\n * update vec3 to 0.1.3\n * add \"whisper\" chat event\n\n## 0.0.21\n\nThis release is feature-complete with the old\n[C++/Qt based version of mineflayer](https://github.com/andrewrk/mineflayer/blob/cpp-qt-end).\n\n * add `bot.activateItem()`\n * add `bot.deactivateItem()`\n * add `bot.useOn(targetEntity)`\n\n## 0.0.20\n\n * add dispenser support\n   - add `mineflayer.Dispenser`\n   - add `bot.openDispenser(dispenserBlock)`\n\n## 0.0.19\n\n * add furnace support\n   - add `mineflayer.Furnace`\n   - add `bot.openFurnace(furnaceBlock)`\n * `mineflayer.Chest`: \"update\" event renamed to \"updateSlot\"\n * `bot.equip(itemType, destination, [callback])` changed to\n   `bot.equip(item, destination, [callback])`. Use `bot.inventory.items()`\n   to get a list of what items you can choose from to equip.\n * fix `bot.openChest` not working for ender chests\n * fix incorrectly scaled fuel percentage\n * upgrade to minecraft-protocol 0.7.0\n   - `mineflayer.createBot` no longer takes a `email` argument.\n   - The `username` and `password` arguments are used to authenticate with the\n     official minecraft servers and determine the case-correct username. If\n     you have migrated your user account to a mojang login, `username` looks\n     like an email address.\n   - If you leave out the `password` argument, `username` is used to connect\n     directly to the server. In this case you will get kicked if the server is\n     in online mode.\n\n## 0.0.18\n\n * fix crash for some block updates\n\n## 0.0.17\n\nrecalled\n\n## 0.0.16\n\n * add chest support\n   - add `mineflayer.Chest`\n   - add `bot.openChest(chestBlock)`\n * `block.meta` renamed to `block.metadata`\n * `item.meta` renamed to `item.metadata`\n * fix crash when player causes entityGone message\n * update to minecraft-protocol 0.6.6\n\n## 0.0.15\n\n * fix `bot.sleep` not working at all\n * add `bot.isSleeping`\n * add \"sleep\" event\n * add \"wake\" event\n * `bot.sleep(bedPoint)` changed to `bot.sleep(bedBlock)`\n * fix `mineflayer.Recipe` not exposed\n\n## 0.0.14\n\n * add crafting support\n   - add `mineflayer.windows`\n   - add `mineflayer.Recipe`\n   - `bot.inventory` is now an instance of `InventoryWindow`\n   - `bot.inventory.count` is no longer a map of id to count.\n     `Window` instances have a `count(itemType, [metadata])` method.\n   - `bot.inventory.quickBarSlot` moved to `bot.quickBarSlot`.\n   - add `'windowOpen' (window)` event\n   - add `'windowClose' (window)` event\n   - add `bot.craft(recipe, count, craftingTable, [callback])`\n   - add `bot.recipesFor(itemType, metadata, minResultCount, craftingTable)`\n * `block.pos` renamed to `block.position`.\n * `'blockUpdate' (point)` event signature changed to\n   `'blockUpdate' (oldBlock, newBlock)`\n * `'blockUpdate:(x, y, z)'` event signature changed to\n   `'blockUpdate:(x, y, z)' (oldBlock, newBlock)`\n * add `'diggingAborted' (block)` event\n * add `bot.unequip(destination, [callback])`\n * add `bot.toss(itemType, metadata, count, [callback])`\n * `bot.startDigging(block)` changed to `bot.dig(block, [timeout], [callback])`.\n * add `bot.activateBlock(block)`\n\n## 0.0.13\n\n * fix `bot.equip` when already equipping the item\n * fix some incorrect block physics\n * add `mineflayer.recipes` enum\n * fix crash when digging at a high elevation\n\n## 0.0.12\n\n * add inventory support\n   - add `Item` class which is exposed on `mineflayer`\n   - add `bot.inventory` (see docs for more details)\n   - add `bot.equip(itemType, destination, [callback])`\n   - add `bot.tossStack(item, [callback])`\n * add digging support\n   - add `bot.startDigging(block)`\n   - add `bot.canDigBlock(block)`\n * blocks: add `blockUpdate:(x, y, z)` event.\n * add building support\n   - add `bot.placeBlock(referenceBlock, faceVector)`\n * add `block.painting`\n * add `Painting` class which is exposed on `mineflayer`\n * add experience orb support\n   - `entity.type` can be `orb` now\n   - `entity.count` is how much experience you get for collecting it\n\n## 0.0.11\n\n * physics: skip frames instead of glitching out\n * default bot name to Player - `createBot` can take no arguments now.\n\n## 0.0.10\n\n * physics: fix bug: walking too slowly on Z axis\n\n## 0.0.9\n\n * ability to sprint (thanks ruan942)\n * fix color code stripping (thanks rom1504)\n * event \"onNonSpokenChat\" deleted\n * new event \"message\" which fires for all messages\n * `bot.chat` no longer checks for \"/tell\" at the beginning\n * add `bot.tell(username, message)` method\n * fix crash when an entity effect occurs\n\n## 0.0.8\n\n * chat: no longer suppress \"chat\" events for your own chat (thanks Darthfett).\n * ability to mount / dismount vehicles and attack\n * physics: fix tall grass and dead bushes treated as solid\n * fix \"respawn\" event firing twice sometimes\n * remove `bot.spawn()` and `autoSpawn` option. auto spawn is now mandatory.\n * fix sending spawn packet twice on init\n * fix bots spawning with their heads on backwards\n * fix bots jumping when they get hit\n * update player heights when they crouch\n * add support for signs: `block.signText` and `bot.updateSign(block, text)`\n\n## 0.0.7\n\n * add `bot.time.day` and `bot.time.age` and \"time\" event\n * add `bot.entities` which is a map of the entities around you\n * add `bot.look(yaw, pitch, force)` and `bot.lookAt(point, force)`\n\n## 0.0.6\n\n * add a physics engine which understands gravity\n * add jumper example, jumps whenever you chat\n * add `respawn` event which fires when you die or change dimensions\n * Block instances have a `boundingBox` property, which is currently either\n   `solid` or `empty`.\n * fix `game` event to fire correctly\n * `bot.game.spawnPoint` moved to `bot.spawnPoint`.\n * `bot.game.players` moved to `bot.players`.\n * `bot.quit` has a default reason of \"disconnect.quitting\" (thanks Darthfett)\n\n## 0.0.5\n\n * unload chunks when changing dimensions\n * blocks: handle all forms of block changing so that `blockAt` is always\n   accurate.\n\n## 0.0.4\n\n * expose Block, Biome, and Entity\n\n## 0.0.3\n\n * add `bot.blockAt(point)` which returns a `Block`\n * add `mineflayer.blocks`, `mineflayer.biomes`, and `mineflayer.items`\n * add bot `chunk` event\n * fix `spawn` event and `settings.showCape`\n * added chatterbox example\n * changed `entityDetach` event to have a vehicle argument\n * changed `entityEffectEnd` event to have an effect argument\n   instead of `effectId`\n * fix prefixes in pseudos in chat. (thanks rom1504)\n * update vec3 to 0.1.0 which uses euclidean modulus\n\n## 0.0.2\n\n * add bot.game.spawnPoint\n * add spawn support\n * add rain support\n * add support for getting kicked\n * add settings support\n * add experience support\n * add bed support\n * health status knowledge\n * add entity tracking API\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>mineflayer - create minecraft bots with a stable, high level API</title>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n  <meta name=\"description\" content=\"create minecraft bots with a stable, high level API\">\n  <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n  <link rel=\"stylesheet\" href=\"//unpkg.com/docsify/lib/themes/vue.css\">\n    <style>\n        .markdown-section {\n            max-width:1400px;\n        }\n    </style>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-128628977-3\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'UA-128628977-3');\n    </script>\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script>\n    window.$docsify = {\n      name: 'mineflayer',\n      repo: 'https://github.com/PrismarineJS/mineflayer',\n      loadSidebar: true,\n      subMaxLevel: 2,\n      auto2top: true\n    }\n  </script>\n  <script src=\"//unpkg.com/docsify/lib/docsify.min.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/llm_contribute.md",
    "content": "# Contributing to Mineflayer Tests as an LLM\n\nThis guide explains how to add and modify tests in Mineflayer, based on the experience of working with the time-related functionality. It provides a structured approach for LLMs to help with test development and debugging.\n\n## Test Structure\n\n### Location\n- Tests are located in `test/externalTests/`\n- Each test file corresponds to a specific functionality\n- Test files follow the naming convention of the feature they test (e.g., `time.js` for time-related tests)\n\n### Basic Test Template\n```javascript\nconst assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test implementation\n}\n```\n\n## Writing Tests\n\n### 1. Property Testing\n- Define expected properties and their types\n- Use `assert.strictEqual` for type checking\n- Verify value ranges where applicable\n\nExample:\n```javascript\nconst timeProps = {\n  doDaylightCycle: 'boolean',\n  bigTime: 'bigint',\n  time: 'number'\n}\n\nObject.entries(timeProps).forEach(([prop, type]) => {\n  assert.strictEqual(typeof bot.time[prop], type)\n})\n```\n\n### 2. Helper Functions\n- Create reusable helper functions for common operations\n- Include functions for waiting and state verification\n- Use descriptive names that explain their purpose\n\nExample:\n```javascript\nconst waitForTime = async () => {\n  await once(bot, 'time')\n  await bot.test.wait(200)\n}\n```\n\n### 3. Test Cases\n- Organize test cases in arrays for better maintainability\n- Include descriptive names and expected outcomes\n- Group related tests together\n\nExample:\n```javascript\nconst timeTests = [\n  { time: 18000, name: 'midnight', isDay: false },\n  { time: 6000, name: 'noon', isDay: true }\n]\n```\n\n## Running Tests\n\n### Basic Test Execution\n```bash\nnpm run mocha_test -- -g \"mineflayer_external 1.20.4v.*time\"\n```\n\n### Version-Specific Testing\n- Test against multiple Minecraft versions\n- Common versions to test: 1.14.4, 1.20.4, 1.21.3\n- Example:\n```bash\n# Test for 1.14.4\nnpm run mocha_test -- -g \"mineflayer_external 1.14.4v.*time\"\n\n# Test for 1.21.3\nnpm run mocha_test -- -g \"mineflayer_external 1.21.3v.*time\"\n```\n\n## Debugging Tests\n\n### 1. Adding Debug Logs\n- Use `console.log` for debugging (remove before final commit)\n- Log important state changes and values\n- Example:\n```javascript\nconsole.log('Time properties:', bot.time)\n```\n\n### 2. Common Issues\n- Timing issues: Adjust wait times if needed (default 200ms)\n- Version compatibility: Check packet formats across versions\n- State synchronization: Ensure proper event handling\n\n### 3. Test Output\n- Watch for server startup messages\n- Monitor bot commands and responses\n- Check for any error messages or warnings\n\n## Best Practices\n\n1. **Test Organization**\n   - Group related tests together\n   - Use descriptive test names\n   - Keep tests focused and atomic\n\n2. **Error Handling**\n   - Include clear error messages\n   - Test edge cases\n   - Verify state after each operation\n\n3. **Performance**\n   - Minimize wait times\n   - Clean up resources\n   - Avoid redundant tests\n\n4. **Documentation**\n   - Comment complex logic\n   - Explain test purposes\n   - Document version-specific behavior\n\n## Common Commands\n\n### Server Commands\n```javascript\nbot.test.sayEverywhere('/time set 0') // Set time\nbot.test.sayEverywhere('/gamerule doDaylightCycle false') // Toggle game rules\n```\n\n### Bot Operations\n```javascript\nasync function f () {\n  await bot.test.wait(200) // Wait for specified milliseconds\n  await once(bot, 'time') // Wait for specific event\n}\n```\n\n## Version Compatibility\n\n- Test against multiple Minecraft versions\n- Handle version-specific packet formats\n- Consider backward compatibility\n- Document version-specific behavior\n\n## Adding a New Test\n\nWhen adding a new test, follow these steps:\n\n1. **Create a new test file** in the `test/externalTests` directory. For example, `experience.js`.\n2. **Write the test logic** using async/await. Avoid using the `done` callback if possible.\n3. **Handle version differences** if necessary. For example, the experience command syntax differs between Minecraft versions:\n   - For versions older than 1.13, use `/xp <amount> [player]`.\n   - For versions 1.13 and newer, use `/xp add <player> <amount> points` or `/xp add <player> <amount> levels`.\n4. **Add event listeners** for debugging if needed, and ensure they are removed at the end of the test to prevent memory leaks.\n5. **Use `bot.chat`** to issue commands directly instead of `bot.test.runCommand`.\n6. **Run the test** for different Minecraft versions to ensure compatibility.\n\nExample test structure:\n```javascript\nconst assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test logic here\n  // Example: Check bot's experience state\n  console.log('[experience test] Bot username:', bot.username)\n  await bot.test.becomeSurvival()\n  // ... more test logic ...\n  // Remove event listeners at the end\n  bot.removeListener('experience', expListener)\n  console.log('[experience test] All checks passed!')\n}\n```\n\n## Specific Details from Recent Experience\n\n- **Version-Specific Command Syntax**: Always check the Minecraft Wiki or existing tests for the correct command syntax for each version. For example, the experience command syntax changed in 1.13.\n- **Event Listener Cleanup**: Always remove event listeners at the end of the test to prevent memory leaks. Use `bot.removeListener('eventName', listenerFunction)`.\n- **Use `bot.chat`**: For issuing commands, use `bot.chat` directly instead of `bot.test.runCommand` to ensure commands are sent correctly.\n- **Debugging**: Use `console.log` for debugging, but remove these statements before finalizing the test.\n\n## Title Plugin Implementation Details\n\n### Version-Specific Title Handling\n- Title packets changed significantly between versions:\n  - 1.8.8 uses a single `title` packet with an action field\n  - 1.14.4+ uses separate packets for different title operations\n- Use `bot.supportFeature('titleUsesLegacyPackets')` to detect version\n- Handle both JSON and plain text title formats\n\n### Title Testing Strategy\n```javascript\nasync function f () {\n  // Example of testing title functionality\n  const titleTests = [\n    { type: 'title', text: 'Main Title' },\n    { type: 'subtitle', text: 'Subtitle Text' },\n    { type: 'clear' }\n  ]\n  for (const test of titleTests) {\n    if (test.type === 'clear') {\n      bot.test.sayEverywhere('/title @a clear')\n    } else {\n      bot.test.sayEverywhere(`/title @a ${test.type} {\"text\":\"${test.text}\"}`)\n    }\n    await once(bot, 'title')\n    // Verify title state\n  }\n}\n```\n\n### Title-Specific Best Practices\n1. **Event Handling**\n   - Listen for both legacy and modern title events\n   - Handle title clear events separately\n   - Parse JSON title text properly\n\n2. **Version Compatibility**\n   - Test title display, subtitle, and clear operations\n   - Verify title timing settings work\n   - Check title text parsing across versions\n\n3. **Error Prevention**\n   - Handle malformed JSON in title text\n   - Provide fallbacks for unsupported operations\n   - Log title-related errors for debugging\n\n## Conclusion\n\nWhen adding or modifying tests:\n1. Understand the feature being tested\n2. Write clear, focused tests\n3. Test across multiple versions\n4. Include proper error handling\n5. Clean up debug code before committing\n6. Document any version-specific behavior\n\nRemember to remove any debugging `console.log` statements before finalizing the changes. \n"
  },
  {
    "path": "docs/mineflayer.ipynb",
    "content": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"mineflayer.ipynb\",\n      \"provenance\": [],\n      \"collapsed_sections\": [],\n      \"authorship_tag\": \"ABX9TyO3/6T3HTMoRxL7FoQ4bWrl\",\n      \"include_colab_link\": true\n    },\n    \"kernelspec\": {\n      \"name\": \"python3\",\n      \"display_name\": \"Python 3\"\n    },\n    \"language_info\": {\n      \"name\": \"python\"\n    }\n  },\n  \"cells\": [\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"view-in-github\",\n        \"colab_type\": \"text\"\n      },\n      \"source\": [\n        \"<a href=\\\"https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb\\\" target=\\\"_parent\\\"><img src=\\\"https://colab.research.google.com/assets/colab-badge.svg\\\" alt=\\\"Open In Colab\\\"/></a>\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"2BAYqsdOgKNJ\"\n      },\n      \"source\": [\n        \"# Using mineflayer in Python\\n\",\n        \"\\n\",\n        \"This is a tutorial on how to use mineflayer in Python. This example will connect you to the PrismarineJS test server. You can join it with prismarine-viewer or your Minecraft client at server IP **pjs.deptofcraft.com:25565**.\\n\",\n        \"\\n\",\n        \"If you're new to Jupyter Notebooks, you can press the \\\"Play\\\" button at the left of each code block to run it. Make sure that you run the blocks in a correct order.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"qM2rVyxGf2Yv\"\n      },\n      \"source\": [\n        \"## Setup\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"K2ol06QOhL6s\"\n      },\n      \"source\": [\n        \"First, make sure you have Python version 3.10 and Node.js version 18 or newer installed. You can get Node.js 18 it from https://nodejs.org/en/download or use [Node.js version managers](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm) like [`nvm`](https://github.com/creationix/nvm) or [`n`](https://github.com/tj/n) to install via the command line. Here we'll use `n` to install Node.js v18, then check our Node and Python versions:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": 1,\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\"\n        },\n        \"id\": \"8zCSpx8Bif5m\",\n        \"outputId\": \"90ebac14-fc75-4136-f81d-34c5b2033da0\"\n      },\n      \"outputs\": [\n        {\n          \"name\": \"stdout\",\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"v18.17.1\\n\",\n            \"Python 3.10.12\\n\"\n          ]\n        }\n      ],\n      \"source\": [\n        \"# Use `n` to install nodejs 18, if it's not already installed:\\n\",\n        \"!curl -fsSL https://raw.githubusercontent.com/tj/n/master/bin/n | bash -s lts > /dev/null\\n\",\n        \"# Now write the Node.js and Python version to the console\\n\",\n        \"!node --version\\n\",\n        \"!python --version\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"C7omnDs3lNaV\"\n      },\n      \"source\": [\n        \"Now, we can use pip to install the `javascript` Python package to access Node.js libraries from Python.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"DKnwzSZQ8Taf\"\n      },\n      \"source\": [\n        \" !pip install javascript\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"_RAKlcScgKtV\"\n      },\n      \"source\": [\n        \"## Usage\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"bxAdFbBfmdCd\"\n      },\n      \"source\": [\n        \"If all is well, we can import the `javascript` library. We can then import the `require` function which works similarly to the `require` function in Node.js, but does the dependency management for us.\\n\",\n        \"\\n\",\n        \"You may notice the extra imports : On, Once, off and AsyncTask. These will be discussed later on.\\n\",\n        \"\\n\",\n        \"\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"54Lnq3aH4Tee\"\n      },\n      \"source\": [\n        \"from javascript import require, On, Once, AsyncTask, once, off\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"cy7-0cWxdhU8\"\n      },\n      \"source\": [\n        \"We can now import Mineflayer\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"8jgkTVniDPUZ\"\n      },\n      \"source\": [\n        \"mineflayer = require('mineflayer')\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"WBAj5rSkgjKX\"\n      },\n      \"source\": [\n        \"Once we've done that, we can create a new `bot` instance, through the `createBot` function. You can see the docs for this function [here](https://github.com/PrismarineJS/mineflayer/blob/master/docs/api.md#bot). In the line below we specify a hostname and a port for the server, but do not pass any `auth` or `password` options, so it will connect to the server in offline mode.\\n\",\n        \"\\n\",\n        \"Below that, we also a call to the `once` function, which pauses the thread until an event has been triggered, then returns the output. Here, we print out  \\\"I spawned\\\" after the `login` event has been triggered on `bot`.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"execution_count\": null,\n      \"metadata\": {\n        \"id\": \"1gfZSAUCDVMg\"\n      },\n      \"outputs\": [],\n      \"source\": [\n        \"random_number = id([]) % 1000 # Give us a random number upto 1000\\n\",\n        \"BOT_USERNAME = f'colab_{random_number}'\\n\",\n        \"\\n\",\n        \"bot = mineflayer.createBot({ 'host': 'pjs.deptofcraft.com', 'port': 25565, 'username': BOT_USERNAME, 'hideErrors': False })\\n\",\n        \"\\n\",\n        \"# The spawn event\\n\",\n        \"once(bot, 'login')\\n\",\n        \"bot.chat('I spawned')\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"yvYZYbi0k8Za\"\n      },\n      \"source\": [\n        \"If your bot spawned, we can now take a look at the bot's position\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"swMd1VvXYuKn\"\n      },\n      \"source\": [\n        \"bot.entity.position\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"EdSjlgmilZ3O\"\n      },\n      \"source\": [\n        \"### Listening to events\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"23FTp0XrioMg\"\n      },\n      \"source\": [\n        \"You can register an event handler with the `@On` or `@Once` decorator. This decorator takes two arguments, first it's the **Event Emitter** (the object that is sending events) and the second is the **event name**, what event you want to listen to. *Do not use the .on or .once methods on bot, use the decorators instead.*\\n\",\n        \"\\n\",\n        \"A decorator always has a function under it which is being decorated, which can have any name. The first parameter to any event emitter callback is the `this` argument. \\n\",\n        \"\\n\",\n        \"In the code below, we create an event emitter on `bot` that listens to `playerJoin` events, then print that out.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"s8QGmC4nHjnH\"\n      },\n      \"source\": [\n        \"@On(bot, 'playerJoin')\\n\",\n        \"def end(this, player):\\n\",\n        \"  bot.chat('Someone joined!')\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"Onkn-TDsne9P\"\n      },\n      \"source\": [\n        \"In Python, you cannot leave any arguments for an event handler callback blank like in JavaScript. Instead, you can use the asterisk (`*`) operator in Python to capture all remaining arguments to the right, much like the `...` rest/spread operator in JavaScript. The parameter with the asterisk will be a tuple containing the captured arguments.\\n\",\n        \"\\n\",\n        \"You can stop listening for events through an event handler by using the imported `off` function. It takes three parameters: the emitter, event name, and a reference to the Python function.\\n\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"S4y9qAe6oh8H\"\n      },\n      \"source\": [\n        \"@On(bot, 'chat')\\n\",\n        \"def onChat(this, user, message, *rest):\\n\",\n        \"  print(f'{user} said \\\"{message}\\\"')\\n\",\n        \"\\n\",\n        \"  # If the message contains stop, remove the event listener and stop logging.\\n\",\n        \"  if 'stop' in message:\\n\",\n        \"    off(bot, 'chat', onChat)\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"OybQNxGAq4P2\"\n      },\n      \"source\": [\n        \"You need to `off` all the event listeners you listen to with `@On`, else the Python process won't exit until all of the active event emitters have been off'ed. If you only need to listen once, you can use the `@Once` decroator like in the example above.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"iOzZeWfHozeX\"\n      },\n      \"source\": [\n        \"## Asynchronous tasks\\n\",\n        \"\\n\",\n        \"By default, all the operations you do run on the main thread. This means you can only do one thing at a time. To multitask, you can use the `@AsyncTask` decroator to run a function in a new thread, while not obstructing the main thread.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"xJUk8b21pOzg\"\n      },\n      \"source\": [\n        \"### Block breaking\\n\",\n        \"\\n\",\n        \"Take a look at the example below. Here we listen for a \\\"break\\\" trigger in a chat message, then we start digging the block underneath, while simultaneously sending a message that the bot has \\\"started digging\\\".\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"yhoAlhAhpSTL\"\n      },\n      \"source\": [\n        \"@On(bot, 'chat')\\n\",\n        \"def breakListener(this, sender, message, *args):\\n\",\n        \"  if sender and (sender != BOT_USERNAME):\\n\",\n        \"    if 'break' in message:\\n\",\n        \"      pos = bot.entity.position.offset(0, -1, 0)\\n\",\n        \"      blockUnder = bot.blockAt(pos)\\n\",\n        \"      if bot.canDigBlock(blockUnder):\\n\",\n        \"        bot.chat(f\\\"I'm breaking the '{blockUnder.name}' block underneath\\\")\\n\",\n        \"        # The start=True parameter means to immediately invoke the function underneath\\n\",\n        \"        # If left blank, you can start it with the `start()` function later on.\\n\",\n        \"        try:\\n\",\n        \"          @AsyncTask(start=True)\\n\",\n        \"          def break_block(task):\\n\",\n        \"            bot.dig(blockUnder)\\n\",\n        \"          bot.chat('I started digging!')\\n\",\n        \"        except Exception as e:\\n\",\n        \"          bot.chat(f\\\"I had an error {e}\\\")\\n\",\n        \"      else:\\n\",\n        \"        bot.chat(f\\\"I can't break the '{blockUnder.name}' block underneath\\\")\\n\",\n        \"    if 'stop' in message:\\n\",\n        \"      off(bot, 'chat', breakListener)\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"JMgoMA-MriAt\"\n      },\n      \"source\": [\n        \"## Using mineflayer plugins\\n\",\n        \"\\n\",\n        \"Pick the plugin you want from the list [here](https://github.com/PrismarineJS/mineflayer#third-party-plugins), then `require()` it and register it to the bot. Some plugins have different ways to register to the bot, look at the plugin's README for usage steps.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"OVAJCyxcsfig\"\n      },\n      \"source\": [\n        \"### mineflayer-pathfinder\\n\",\n        \"\\n\",\n        \"`mineflayer-pathfinder` is a essential plugin that helps your bot move between places through A* pathfinding. Let's import it:\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"mH6eXm8TtTKh\"\n      },\n      \"source\": [\n        \"pathfinder = require('mineflayer-pathfinder')\\n\",\n        \"bot.loadPlugin(pathfinder.pathfinder)\\n\",\n        \"# Create a new minecraft-data instance with the bot's version\\n\",\n        \"mcData = require('minecraft-data')(bot.version)\\n\",\n        \"# Create a new movements class\\n\",\n        \"movements = pathfinder.Movements(bot, mcData)\\n\",\n        \"# How far to be from the goal\\n\",\n        \"RANGE_GOAL = 1\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"Ju8MPkSauTBb\"\n      },\n      \"source\": [\n        \"Now let's have create a goal for the bot to move to where another player wants, based on a chat message.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"8jIp8bxnudDK\"\n      },\n      \"source\": [\n        \"bot.removeAllListeners('chat')\\n\",\n        \"@On(bot, 'chat')\\n\",\n        \"def handleMsg(this, sender, message, *args):\\n\",\n        \"  if sender and (sender != BOT_USERNAME):\\n\",\n        \"    bot.chat('Hi, you said ' + message)\\n\",\n        \"    if 'come' in message:\\n\",\n        \"      player = bot.players[sender]\\n\",\n        \"      target = player.entity\\n\",\n        \"      if not target:\\n\",\n        \"        bot.chat(\\\"I don't see you !\\\")\\n\",\n        \"        return\\n\",\n        \"      pos = target.position\\n\",\n        \"      bot.pathfinder.setMovements(movements)\\n\",\n        \"      bot.pathfinder.setGoal(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z, RANGE_GOAL))\\n\",\n        \"    if 'stop' in message:\\n\",\n        \"      off(bot, 'chat', handleMsg)\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"K36XDP09k1aH\"\n      },\n      \"source\": [\n        \"## Analyzing the world\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"xK1Ww1ACmLZl\"\n      },\n      \"source\": [\n        \"You can also interact with mineflayer through any other Python package.\"\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"5QatUqxeW6b_\"\n      },\n      \"source\": [\n        \"Let's analyze some block frequencies...\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"colab\": {\n          \"base_uri\": \"https://localhost:8080/\",\n          \"height\": 417\n        },\n        \"id\": \"k2XyRgzi8otw\",\n        \"outputId\": \"a4de38b7-ec53-4e38-df0c-8b7f1067965e\"\n      },\n      \"source\": [\n        \"import matplotlib.pyplot as plt\\n\",\n        \"figure = plt.figure()\\n\",\n        \"axes = figure.add_axes([0,0,1,1])\\n\",\n        \"Vec3 = require('vec3').Vec3\\n\",\n        \"\\n\",\n        \"columns = bot.world.getColumns()\\n\",\n        \"block_freqs = {}\\n\",\n        \"for c in range(0, 3): # iterate through some of the loaded chunk columns\\n\",\n        \"  cc = columns[c].column\\n\",\n        \"  for y in range(1, 40):\\n\",\n        \"    for x in range(1, 16):\\n\",\n        \"      for z in range(1, 16):\\n\",\n        \"        block = cc.getBlock(Vec3(x, y, z))\\n\",\n        \"        if block.name in block_freqs:\\n\",\n        \"          block_freqs[block.name] += 1\\n\",\n        \"        else:\\n\",\n        \"          block_freqs[block.name] = 1\\n\",\n        \"\\n\",\n        \"print(block_freqs)\\n\",\n        \"axes.bar(block_freqs.keys(), block_freqs.values())\\n\",\n        \"plt.xticks(rotation=45)\\n\",\n        \"plt.show()\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": [\n        {\n          \"output_type\": \"stream\",\n          \"text\": [\n            \"{'bedrock': 1321, 'stone': 19258, 'diorite': 1123, 'lava': 64, 'granite': 1704, 'andesite': 1459, 'redstone_ore': 68, 'iron_ore': 156, 'coal_ore': 282, 'gold_ore': 26, 'lapis_ore': 5, 'dirt': 570, 'emerald_ore': 3, 'diamond_ore': 9, 'gravel': 66, 'air': 211}\\n\"\n          ],\n          \"name\": \"stdout\"\n        },\n        {\n          \"output_type\": \"display_data\",\n          \"data\": {\n            \"image/png\": \"iVBORw0KGgoAAAANSUhEUgAAAeUAAAFrCAYAAADvipHKAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deZwcZbX/8c8hYSchAUIMSdgDCogBIvuOhLAGENkhAhJAULmigiiLCAgKqAjiDRoNXnYREiUIARFUQEgAWUQkLF6SGyAIij9U1vP745xiKsNMpqe7Z6Ym832/Xv2a7qerq57qrqnzbPWUuTsiIiLS8xbr6QyIiIhIUFAWERGpCAVlERGRilBQFhERqQgFZRERkYpQUBYREamI/h0tYGYjgSuAoYADk9z9u2a2AnAtsDrwHLC/u79qZgZ8F9gN+BfwSXd/MNc1Afhqrvpsd5+S6ZsAPwGWBqYDn/MOrtVaaaWVfPXVV+/MvoqIiPS4WbNmvezuQ9p6zzq6TtnMhgHD3P1BMxsAzAL2Bj4JvOLu55nZKcBgdz/ZzHYDPkME5c2A77r7ZhnEZwJjiOA+C9gkA/n9wGeBPxBB+WJ3v2Vh+RozZozPnDmzxq9ARESkGsxslruPaeu9Dpuv3X1eUdN1938CTwDDgfHAlFxsChGoyfQrPNwHDMrAvgsww91fcfdXgRnAuHxvoLvfl7XjK0rrEhER6TM61adsZqsDGxE12qHuPi/feoFo3oYI2M+XPjYn0xaWPqeN9La2P9HMZprZzPnz53cm6yIiIpVXc1A2s+WAG4AT3f218ntZw+3y+TrdfZK7j3H3MUOGtNkcLyIi0mvVFJTNbHEiIF/p7j/P5Bez6bnod34p0+cCI0sfH5FpC0sf0Ua6iIhIn9JhUM7R1D8CnnD3i0pvTQMm5PMJwNRS+uEWNgf+kc3ctwJjzWywmQ0GxgK35nuvmdnmua3DS+sSERHpMzq8JArYCjgMeNTMHs60U4HzgOvM7Cjgr8D++d50YuT1bOKSqCMA3P0VM/s68EAud5a7v5LPP03LJVG35ENERKRP6fCSqKrSJVEiItIbNXRJlIiIiHQPBWUREZGKUFAWERGpCAVlERGRilBQFhERqYhaLomSJlj9lJubur7nztu9qesTEZGep5qyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEV0GJTNbLKZvWRmj5XSrjWzh/PxnJk9nOmrm9m/S+/9oPSZTczsUTObbWYXm5ll+gpmNsPMnsq/g7tiR0VERKqulpryT4Bx5QR3P8DdR7v7aOAG4Oelt58u3nP3Y0vplwFHA6PyUazzFOAOdx8F3JGvRURE+pwOg7K73w280tZ7WdvdH7h6Yesws2HAQHe/z90duALYO98eD0zJ51NK6SIiIn1Ko33K2wAvuvtTpbQ1zOwhM7vLzLbJtOHAnNIyczINYKi7z8vnLwBD29uYmU00s5lmNnP+/PkNZl1ERKRaGg3KB7FgLXkesKq7bwR8HrjKzAbWurKsRftC3p/k7mPcfcyQIUPqzbOIiEgl9a/3g2bWH9gX2KRIc/c3gDfy+SwzexpYB5gLjCh9fESmAbxoZsPcfV42c79Ub55ERER6s0Zqyh8D/uzu7zVLm9kQM+uXz9ckBnQ9k83Tr5nZ5tkPfTgwNT82DZiQzyeU0kVERPqUWi6Juhq4F1jXzOaY2VH51oG8f4DXtsAjeYnUz4Bj3b0YJPZp4IfAbOBp4JZMPw/Y2cyeIgL9eQ3sj4iISK/VYfO1ux/UTvon20i7gbhEqq3lZwIbtJH+N2CnjvIhIiKyqNOMXiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRHQZlM5tsZi+Z2WOltDPNbK6ZPZyP3UrvfdnMZpvZk2a2Syl9XKbNNrNTSulrmNkfMv1aM1uimTsoIiLSW9RSU/4JMK6N9G+7++h8TAcws/WAA4H18zPfN7N+ZtYPuBTYFVgPOCiXBTg/17U28CpwVCM7JCIi0lt1GJTd/W7glRrXNx64xt3fcPdngdnApvmY7e7PuPubwDXAeDMzYEfgZ/n5KcDendwHERGRRUIjfconmNkj2bw9ONOGA8+XlpmTae2lrwj83d3fbpXeJjObaGYzzWzm/PnzG8i6iIhI9dQblC8D1gJGA/OAC5uWo4Vw90nuPsbdxwwZMqQ7NikiItJt+tfzIXd/sXhuZpcDv8yXc4GRpUVHZBrtpP8NGGRm/bO2XF5eRESkT6mrpmxmw0ov9wGKkdnTgAPNbEkzWwMYBdwPPACMypHWSxCDwaa5uwN3Avvl5ycAU+vJk4iISG/XYU3ZzK4GtgdWMrM5wBnA9mY2GnDgOeAYAHd/3MyuA/4EvA0c7+7v5HpOAG4F+gGT3f3x3MTJwDVmdjbwEPCjpu2diIhIL9JhUHb3g9pIbjdwuvs5wDltpE8HpreR/gwxOltERKRP04xeIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFaGgLCIiUhEKyiIiIhXRYVA2s8lm9pKZPVZK+5aZ/dnMHjGzG81sUKavbmb/NrOH8/GD0mc2MbNHzWy2mV1sZpbpK5jZDDN7Kv8O7oodFRERqbpaaso/Aca1SpsBbODuGwJ/Ab5ceu9pdx+dj2NL6ZcBRwOj8lGs8xTgDncfBdyRr0VERPqcDoOyu98NvNIq7TZ3fztf3geMWNg6zGwYMNDd73N3B64A9s63xwNT8vmUUrqIiEif0ow+5SOBW0qv1zCzh8zsLjPbJtOGA3NKy8zJNICh7j4vn78ADG1vQ2Y20cxmmtnM+fPnNyHrIiIi1dFQUDazrwBvA1dm0jxgVXffCPg8cJWZDax1fVmL9oW8P8ndx7j7mCFDhjSQcxERkerpX+8HzeyTwB7AThlMcfc3gDfy+SwzexpYB5jLgk3cIzIN4EUzG+bu87KZ+6V68yQiItKb1VVTNrNxwJeAvdz9X6X0IWbWL5+vSQzoeiabp18zs81z1PXhwNT82DRgQj6fUEoXERHpUzqsKZvZ1cD2wEpmNgc4gxhtvSQwI69sui9HWm8LnGVmbwHvAse6ezFI7NPESO6liT7ooh/6POA6MzsK+Cuwf1P2TEREpJfpMCi7+0FtJP+onWVvAG5o572ZwAZtpP8N2KmjfIiIiCzqNKOXiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEXUFJTNbLKZvWRmj5XSVjCzGWb2VP4dnOlmZheb2Wwze8TMNi59ZkIu/5SZTSilb2Jmj+ZnLjYza+ZOioiI9Aa11pR/AoxrlXYKcIe7jwLuyNcAuwKj8jERuAwiiANnAJsBmwJnFIE8lzm69LnW2xIREVnk1RSU3f1u4JVWyeOBKfl8CrB3Kf0KD/cBg8xsGLALMMPdX3H3V4EZwLh8b6C73+fuDlxRWpeIiEif0Uif8lB3n5fPXwCG5vPhwPOl5eZk2sLS57SR/j5mNtHMZprZzPnz5zeQdRERkeppykCvrOF6M9bVwXYmufsYdx8zZMiQrt6ciIhIt2okKL+YTc/k35cyfS4wsrTciExbWPqINtJFRET6lEaC8jSgGEE9AZhaSj88R2FvDvwjm7lvBcaa2eAc4DUWuDXfe83MNs9R14eX1iUiItJn9K9lITO7GtgeWMnM5hCjqM8DrjOzo4C/Avvn4tOB3YDZwL+AIwDc/RUz+zrwQC53lrsXg8c+TYzwXhq4JR8iIiJ9Sk1B2d0PauetndpY1oHj21nPZGByG+kzgQ1qyYuIiMiiSjN6iYiIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEXUHZTNbF0ze7j0eM3MTjSzM81sbil9t9Jnvmxms83sSTPbpZQ+LtNmm9kpje6UiIhIb9S/3g+6+5PAaAAz6wfMBW4EjgC+7e4XlJc3s/WAA4H1gVWA281snXz7UmBnYA7wgJlNc/c/1Zs3ERGR3qjuoNzKTsDT7v5XM2tvmfHANe7+BvCsmc0GNs33Zrv7MwBmdk0uq6AsIiJ9SrP6lA8Eri69PsHMHjGzyWY2ONOGA8+XlpmTae2lv4+ZTTSzmWY2c/78+U3KuoiISDU0HJTNbAlgL+D6TLoMWIto2p4HXNjoNgruPsndx7j7mCFDhjRrtSIiIpXQjObrXYEH3f1FgOIvgJldDvwyX84FRpY+NyLTWEi6iIhIn9GM5uuDKDVdm9mw0nv7AI/l82nAgWa2pJmtAYwC7gceAEaZ2RpZ6z4wlxUREelTGqopm9myxKjpY0rJ3zSz0YADzxXvufvjZnYdMYDrbeB4d38n13MCcCvQD5js7o83ki8REZHeqKGg7O6vAyu2SjtsIcufA5zTRvp0YHojeREREentNKOXiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhUhIKyiIhIRSgoi4iIVISCsoiISEU0HJTN7Dkze9TMHjazmZm2gpnNMLOn8u/gTDczu9jMZpvZI2a2cWk9E3L5p8xsQqP5EhER6W2aVVPewd1Hu/uYfH0KcIe7jwLuyNcAuwKj8jERuAwiiANnAJsBmwJnFIFcRESkr+iq5uvxwJR8PgXYu5R+hYf7gEFmNgzYBZjh7q+4+6vADGBcF+VNRESkkpoRlB24zcxmmdnETBvq7vPy+QvA0Hw+HHi+9Nk5mdZe+gLMbKKZzTSzmfPnz29C1kVERKqjfxPWsbW7zzWzlYEZZvbn8pvu7mbmTdgO7j4JmAQwZsyYpqxTRESkKhquKbv73Pz7EnAj0Sf8YjZLk39fysXnAiNLHx+Rae2li4iI9BkNBWUzW9bMBhTPgbHAY8A0oBhBPQGYms+nAYfnKOzNgX9kM/etwFgzG5wDvMZmmoiISJ/RaPP1UOBGMyvWdZW7/8rMHgCuM7OjgL8C++fy04HdgNnAv4AjANz9FTP7OvBALneWu7/SYN5ERER6lYaCsrs/A3ykjfS/ATu1ke7A8e2sazIwuZH8iIiI9Gaa0UtERKQiFJRFREQqQkFZRESkIhSURUREKkJBWUREpCIUlEVERCpCQVlERKQiFJRFREQqQkFZRESkIhSURUREKkJBWUREpCIUlEVERCpCQVlERKQiFJRFREQqQkFZRESkIhSURUREKkJBWUREpCIUlEVERCpCQVlERKQiFJRFREQqQkFZRESkIhSURUREKkJBWUREpCIUlEVERCpCQVlERKQiFJRFREQqou6gbGYjzexOM/uTmT1uZp/L9DPNbK6ZPZyP3Uqf+bKZzTazJ81sl1L6uEybbWanNLZLIiIivVP/Bj77NnCSuz9oZgOAWWY2I9/7trtfUF7YzNYDDgTWB1YBbjezdfLtS4GdgTnAA2Y2zd3/1EDeREREep26g7K7zwPm5fN/mtkTwPCFfGQ8cI27vwE8a2azgU3zvdnu/gyAmV2Tyyooi4hIn9KUPmUzWx3YCPhDJp1gZo+Y2WQzG5xpw4HnSx+bk2ntpYuIiPQpDQdlM1sOuAE40d1fAy4D1gJGEzXpCxvdRmlbE81sppnNnD9/frNWKyIiUgkNBWUzW5wIyFe6+88B3P1Fd3/H3d8FLqeliXouMLL08RGZ1l76+7j7JHcf4+5jhgwZ0kjWRUREKqeR0dcG/Ah4wt0vKqUPKy22D/BYPp8GHGhmS5rZGsAo4H7gAWCUma1hZksQg8Gm1ZsvERGR3qqR0ddbAYcBj5rZw5l2KnCQmY0GHHgOOAbA3R83s+uIAVxvA8e7+zsAZnYCcCvQD5js7o83kC8REZFeqZHR178DrI23pi/kM+cA57SRPn1hnxMREekLNKOXiIhIRSgoi4iIVISCsoiISEUoKIuIiFSEgrKIiEhFKCiLiIhURCPXKYt0idVPubmp63vuvN2buj4Rka6imrKIiEhFKCiLiIhUhJqvpU9SE7mIVJFqyiIiIhWhmjKqNYmISDWopiwiIlIRCsoiIiIVoebrRYia4UVEejfVlEVERCpCQVlERKQiFJRFREQqQkFZRESkIhSURUREKkJBWUREpCIUlEVERCpC1ymLiDSB5gmQZlBNWUREpCIUlEVERCpCQVlERKQi1KcsIu1SP6lI96pMUDazccB3gX7AD939vB7OkoiI9EK9uTBZiaBsZv2AS4GdgTnAA2Y2zd3/1LM5E6mu3nziEZG2VSIoA5sCs939GQAzuwYYDygoV4wCQe2a+V0tyt+T9C06hyycuXtP5wEz2w8Y5+6fyteHAZu5+wmtlpsITMyX6wJPdmtGYSXgZW1D2+hl21gU9kHb6HvbWBT2oT2rufuQtt6oSk25Ju4+CZjUU9s3s5nuPkbb0DZ60zYWhX3QNvreNhaFfahHVS6JmguMLL0ekWkiIiJ9RlWC8gPAKDNbw8yWAA4EpvVwnkRERLpVJZqv3f1tMzsBuJW4JGqyuz/ew9lqS3c0nWsb2kZvW7+2oW30xvV31zY6pRIDvURERKQ6zdciIiJ9noKyiIhIRSgoi4hIr2Nm1tN56AoKyiIi3agIJotqUOlKZjbEzE4ys2Xc3Rv5Dqv6/SsoN4ml0uuBPZmfRlT1YK1V6aS3eHdta1GxqO1P1ZjZAKA4Llfuybz0UhsAHwJONLOl6w3MZmaeo5zNbPvuOFfUSqOvm8TMlnL3/+TzQ4HV3f3sJq1733z6D3e/oxnrbLX+9w7Q3rDeGre9K7A98E/gauBZd3+3ydso/2PvSRRy5wEPuvvbzdxWVyv2xcwWd/e3unIbrdIWa+bv0s42mn4c1rNOM+sPHAK8Q0yWtDOwC/B2T/2ftKc7fqt65M2LdgT2BF4CLnT3f9f7G5vZXsCZwI7u/vemZrZOlbhOuTfLUtqawD1mtkXeVGNxckYyM+vn7u80sP7jgMOAi4EZZraNu/++CVl/TymwHAV8BPgrcK+731PvOlsFrE8Cg4D57n5l4znucNvbA98iToA3EvPbfhFo6gmltH9fAHYHfgtsA5wP/KqZ21qYUkDdkNjXJ4CXaw2upc/vDOxvZg8Az7n7bV2Qx92IwtJixC1a/9wF29iBqIUu7u7/01UB2cx2AfYFngfuX9j3lQHtbTO7G7gNWAbYtasKQI0o7d92ZG3e3a/vqkKtmQ0nfqvnOlrW3d8xs9uB/xCTTH3BzC6oNTCb2druPjuf7wx8G5jg7n83syXc/c2m7WCd1HzdoDxQngYmA3eb2QiiJLxMvl9XQM7W8FWBscCuwPLAr4H7zKzpv5uZHU8EsZuAfXK7dSsFrM8QNxF5BPiJmX2xwazWYhvgC8Rv8DJRmn4rZ4trilIT+UhgU3ffAXgDeB24zcyWbta2OpIntvHAFCJIXAHs0MnP70jcz/w64GBgr2Z+X7mNcUSt5OfAhsC5zTyWS9u4mGghmWJmxzRr/a22swtwLvF9fRg4OmvC79Oqhjkc+A7wNLClma3Uatke7z7I/dsTuBBYDjjFzP6rC7dzE/BNM5tqZu9r0i8Xgszsc8BJ7v5b4HqiEPpfRVN2e9vK8+nSwHlmNiiTnwTeAj6f+XmzK86tndXjGejN8oc2AHf/MvB94PfA5sDKZjbBzPYwswPMrFOTnucB9ipx+8rTieaaPTPIH29m6zZzX4BhuY1RRGA528yWMLMV611hFlB2B/YA1gPuBY40s3ObkN9iG8uY2Wb5fD0zG0X8s32aCDKfcPfnLboUjm/C9laA904oqxFNaG+Z2Y+BLYB98wS8ewbsLmdmw4AjgW2BO4kT1ayOTvClgsXSwPq5jr8DA4Dz8iQ1tIlZXQf4JDCUKDCd6O7vmtlyzVh5Nm0eARxAFJAeBH7ZjHW32s4SRHA9hJiBcHXg81kTfl9QKQKymW0FnOvulxLf9cczv5jZ/ma2YRWasXP/PkH8775OfJfXNDtgmdn6wJeISscvgbVzW8X7xbnVzWwscB7wB+BUMzsT+F1+bnXgSx3kz9z930TtehMzO9/d/xf4GDDYzL6X23q3xwOzu+tRx4Psj8/nhwC75/MvEM2kNwP/Bfw38DNgZCfWvRrRnAPwQ+DV0nsHAPd3Zn1trH8osEo+350onF1IFAB+UVpuIvHPaXVsY4vczkCi3+zuTN82v5+JTfodPgCcA1xL/MOOIGrKvyWa/ZcCRhM19V0b/c2JYH8+cChRUh8AnEXM3/6hXO7I3N6wbjgO1yMKVBcAZwP3AGvmezsAK3bw+V2IQPkp4FFgFvCBfG9P4Bigf4N5HAucnHn8FXA7sEa+txdwYhO2sRPRLP4VojZ+N7Buvnco0WfYjO97bP6Pnws8nNsZlu+NAz4LLJGvRwHrlz73LBG8i3WtTzRlX04U7j7Y1cdLDfu3VR4TPwa+AfwGGJXv7QFs3eD6i3FMI4AVgGPzPHNf6ZjYqrT8Yvn4AdG1NpYo3K9WWmbH4nte2DaL58CqwJ+Br5TyMh34SU9//+6uoNzwFxgH1aPFgZtpJwL/CyxfHFgdrKN80HyWqOn9N/DJTJtB9I3+mAjIH24gvwZsBNxF9LvOJJrGN8gT5hdyuQlEkF6njm2snHndLF/vAVyZz/fO99Zs8HsfRQZ2ogb8L2LO9OL9o4gCza+IAD2+9Xfdye2tXfyOwAtEK8ay+Xo7omBwD/A94PGFnSSaeOyNIfqPP0IE5D8Cm5fy9ASwwUI+vwkRELYiCjfXA6fle5vmfoxrMI/rEt0uw4EhxHiFr+d72+ax3lDAzP24F/gg8GWitrV6vrcRUUDasgnf9zrEjXLWIgLFr4FL873tc192ztdrAF8DliwdJ9cRQW7x0jpH5GdX7erjpYb9W584v6xAFNL+Xvw2wNZEIBvThO3smMfqHsAduc2iYLM9cU4qfr+i8vD1/N/6NS2FrcOA/TrYVvncegIR3D9T+t85Nd9bjehW+UCP/w49nYHe+iCC2weIkm5xkCxRev984C/AEkC/Gte5E9HftCGwX54wj8n3tiZKsKs3kOcNgR3y+SXAm8Be+XoQUdK/k2gSup8GAgvR5H5XnpQ+RATIqfmPvVYTvv8PEDXiAcCyRCHiJ8BZpWVGETX1kcVvVufvvAxwKS3NrucCjwGXl5YbCGxJlOTr/o06ka8NMg/75+ud83j5CVFAeALYo53P9iP6CucDv8u0/sD+eVz8gWga3KvBPK5KtBLdRksBdaPM2xVE68LuDW5jrdzn8m9xBVGD/QFR8x/f4DYWA1YhAv/NwMqZ/mEiSPwiv7OitWxEHiOfJlqMvk3WgvN/4HoabBnoguNpNFHgOD9fL0u0bvwl9+XR9o6nTm5n3Twets3Xx+a5ZgIRLB8jgvViwGBgNrAZcW76D7Bdfm4TotC4fY3b/TRxPhoB/I04P+9JFA7OLv4Hevp3cFdQ7uwBZa1eLw78Tx4gi5XSN8i/C206LC3fjwgg7wLfy7TliRP8JLL20oT8fzxPLsOA8USN/k8s2FzUn2jyHVzH+sdQqlkRJ/j98vl6ROBYuwn70a/0/b9MBuI8AV5L1JZGEy0ByzTjN8/vZUvgVFq6Fv5ISwvAHmTLQDcdi0OJPtPflNI2JJqDjyZrhrRqumu1jo8QtaETS2mL5Ylr5bY+U+v3VXp9CNFa8XFaAvMKRGvKak34HtbI3/kO4GOl9LF5PGxcz360sy97Ea0he1MqaOe+fKD8OaJL4FwisP2Y6OIomoFvIO+I113HSw37uiJRgLqZrJ1m+s5EhWBMvd9jaV39iUGEfyYGXxbph+X/7EVExcRK/3cTgUvy+ReAh/L7fIAaC41EgfmHxHnvs/ndX5Xr2YcoFNR0ru6W36KnM9BbHq1ObqsCw/P5JUR/7NL5+gCiGWRgHds4hCgNFifUZYiT/beBlRrIe7nA8GFilG4RLI8mSsMb5PML6vxOBuVJ6Cai5jKS6N/7alf8DrQ0Ja9FdBWcnq/H5EnvWWC3Jv7mS+a2fg2ckWmLE7W+24hS+6hGtlfjfq9GSz/l0Py+p3Ti81sDZ+SJcEWiSfZl4IQm5nEHYkTrsUQB7+PAT4mgNqhJ2xiT+7Ix0Rp1FjEQaLsmf9/bEc3QE/Ok/jGiCXr34n++nc8dSRRGbs3v4kdEF0MRmK8ERkfPzXsAAB2/SURBVHTV8dKJ/duY6EZYJ4/nK4ng2JRm3NJ2lgeWyucfJyobx7TzmWJsxmLEIK6raGne3piowHyovP4a8rEkUQi9s/gc8A+i62u5nvod2sxrT2egtz2IJpb780Q8mSj1/5xokrqS6A/ZsBPr24cIXnsQJcl9gNeAbfL9Zcg+qTrzWw7IRxGjD08kAvM+mX400W99D/CRGtdbDlir0VILWpIIyucSzeDv0oRmr1bb3pYo8e5Y2v48SgUAGmwib7V/x9HS1z4qT7Zfy9f98iSzWjcce3sTNYR7iJL/vkRf7bXA1TV8fmfgGaK2f0WuYzTRpPgW8Jkm5HFnogXhlDzGHs1jeD+iT3VvOhhjUcM2xhIFyW8S8wEcQYw4P4MYcb9tk77vXYj+6K/kth4kCma7EM3V7XUPHELU6EYT/aBfI0YZX0Z0TzXcfdOk/dudlprnr4Cv5jnop0Rlo1mBeS+iO+H3ZMEEOCi/j+NLy/XLx73EufXzeT45B/hZE/Ixihhf8mHifHttd/zfdjqfPZ2Bqj9anZy3yoN4GFGqnJYnNiNK7rt05kcmAstDxCCGKcTgrsF5AnsX2KKJ+7EdMbPVwHx9TP7z7Z2vh1BDkzWlpqV8fRIxmvZeFgyK6+TJ8o/kqMom7ce2RD/TecArxIX/EDXz18g+sSZu7xiiELZaKW040Tf4LbL03w3H4VCiv/+DeeI8Jre/PtG/fgsLGQCYv9tpxCVixfd1JNmMCHwUGNuEfF4EfKrV61vy+WfoRIG1nX0YQNQ+i/7b9fN4OJgoIJ9NjvFowr6cARxSen0UMDWfH0E73RVErf2L+XwJohB8ExHcLwaGdMcx08G+LcOCfbvDiIL5kURz7zSaMBqc6LZ6gBhLsCrRinV6bv9Q4vw5IpddIf/2JwZ8fZcogB6U69i4wbwsSXQnzCBattbr6d+hzXz2dAaq/GDB4LMxUUqexIK1z3uAg+tZNxGIi8tX1iVqMJ/P14c14+RClDzXIppqrmPBkZ9HE6O6a67JUhoMkSepu/L5pcQ1jd9otXzdtfw2tr0OUcMrTshjiZrMhHy9KrBTk7a1WJ6cphPNsYOIJszLiBrGcKIPru5uhU7m5wNE7axouh5AtMwUo6WXqGEdZxODkoo+8fWI5vhyH2LdfYb5+XOBU0qvl8nfbPFG1ttqGxeTfY/5emfgpi443r4DTCq9XoUoyC60a4poDbiJ0kDJDCqnUpG+S6Jb4ReUWsaIcSYX5fOm/F5ErfRGWpquVyTGsRxEDCYrmqV3JQZinc2CtecjiQL4GzRn5PfiRIF0eE//Bu09NHlIG0qTLhSTKxxOTAyyOlFT2bi0+K+JUcwdrXMJMxuSz3fJ5EFEYMTdnyT6J7fKGWx+mmmN5B93f8djxrEDiAFpO5feu5yo8T1Y43pXAmYXE2gAzwGHmdlniZL2xsCnzOyi0mxQ/6pnH1pttzhOtyWmNN3JzJbzmNbw88CZZnaUu/+vu99R76xIrb63d939NeLEdRHRJL8O0Wy6h7vPBQ5y95fr3rFOcPcXiNrwHma2hrv/k/jtlsuZpGqZrvEyYiapk/P1W0St5L2ZqDzPXA2YSkx9uH++3oiozQ5t4mxVrxP/NwPy9dvw3qQXDR9vJecAHzWzs/L1SOL/f6X2PwJEn/PjwMFmtpOZ7UG04kxx9781MX9185infxYxy96QTO4HrGVmy9C8KWn/Q/wmo81s2dz/7xNB/3V3n2cxnecFxLwOA4DjzOzCzOdkooVnpLvPbDQz7v6Wuz+f/7/V1NOlgio+KPX5EJfd3ENLDeV4otR7EtEM8yg1XMtLjAS9g7ggfxZx8G1KHKDH5TL7Es07dQ88YMHa/cHEwX4sETR3IAZA1X3tKXEZwZO0NDUNyjx/NF9/n2ju7fTo7fb2pdhWPv84USufQI6sJroNtmnGtvL5QUStZmciqGxG1ojzO50BLE2Dtco68rhDHj+35PH3HJ1ocqalWfBK4pKnh4CP15GPNpvsaRl8tz0RlCYRl7jUfdkTC45yLv9G/0OM5bgk96Ohy7fa2y5REP9jbu9xamxVImrVJxCF9ttooNm+wf2w8t82np9LNP+fSoyKbuTc0OZocqI//WqiAH1obq+4NHME0V33QaLl64H8+2va6Irq7v+5HvnNejoDVXsQ12/eA3wzX+9LNJF+r7TM+PyHu5AO+l1a/QN8n6hVj8vXQ4gg93tiUNRjzfrnJa7Lm0n0W3+TaIZdOw/4v9NAMy/R1PQ0LYH5QuK6v5Pp5OxlNW7rLqLfvSi8HEw0YU6kdMlTPf+wpZNWEVA+TQSsw4hBUYeXli1mvWp3Qo5uOD5XJ1o9vkgHI40X9n0Qtf5OX79NjHm4sL1tl77HkXnCXbeObXyAHEhXXmc+LwfpsURXwhb1/v41HhtL5f6s0dntEE20PTK6l7hU65NkAbm9fOc5bnfqnK0rf+eigNxeIepgok99ClmQzN/vkjyml8tzx6b53pX5f9/js5x1++/W0xmo0qN0QlmTCMyfy9fjiFL/iQ2s+zhi+r/ziCA/pvTeUpSuDa1z/e9N6Zevvw1slM8HE819F+fr/WjwemFaAvMAYpTpmUSzXdMCFjE47XGiWfy7RF9UMep5AjE5REN9Q5QGexCDqX5Ay2QkM4gmPcuT8jH00OCQhQUCWtWGWMi12Y0GLuK64NOI1oqtat0GtU+gY8T11tcR828X6Yu19byRfSt9XxvR/qCt922rve1X7UG0Kk0mCq/F1RHtXrdez/7l73U+UcMtZi7r1966WHA8w4/IggAxfmMqca7dkqhEdNklhlV+9HgGqvggLku6jLj+9aRM24Oo6Z5Sx/qOIQbpFNc2f4Xox101/2G+3mB+iyn9lqKl9vpTSnO5EqNrf0YTRwsDuxE1x0H5+n3XbdaxzvLcuG01a/2GlsFNqzSyHaI59yngp6X0c3Ibt5bSjiNG13fZZA+l/d6cGNyyEaVm+1bLtjvzEFFYuo4Ymd3mIDRammb717NPRIvLF4irBdoLzMU2lmjv5N/BNoqbFJxZSmt9gu/XVnont7MX0Ty9Zav099XOc18amoymux9ES9kkYlDmcuVjrcnf4+XEiO331Zjb2M6atFyxUR6wN5G4NGsmeZVAX3xooFcrOajrfKKZ5XRgXzM72d1/SfQJDzWzwZ1Y39LECeZ04m5CxxAnwxWIJtgjiWBZb35HELXgF4kT+almth5xnejipTsyrUqURpt2S0F3n07Umu7MwVhvdPCRWtZZ3BHmFOKfcw7xz3q8x8CuucBYMxvl7v/XwKYWc/e33X0UsIWZXZTpjxMjry8AMLODiK6KV72B+2J3JPd7d6L2sBIxYnl868FRFvfnftvMBpvZAa3e25S41vQqYnDV6XnnLGv1+XfyGP4Z0YrSoVaD4GYTzYtPA4fn3Y9a5/GdvEXeD4jxDDWzuPH8F4lulh3M7ILc7nt38CltY3nitn813WnKzAYWgxDNbG3i+B3v7veY2ZoWt37EW+7sVN6Xy4lJMHqF3JdPEP/7E4BDzGz5PNaKQazl7/Gkztyxq7SOnYjfam3g2hzQ9U7etatYttjOlkQF4tfEpDWb03LP5klEn/Mu7n59EwcG9i49XSqo2oMYFHVUPu9H1DD/RMt1h53uHyKCykNESfKbuY2ziH69NmtDnVh3W1P6nU4c7B8man1TiTva1H0jiw7y0LQ+M7q5WSvX+x3g37TM+/sVYhDRdGJQXpf3IRMD5n5MDBDaJn+vofle0eRX1DSWJyZB2KH0+dWIAXfFlKPLEAHxYiJAGy3dM4OIwUc71Ji3oiYzlhhoVsxuNZgYxPN9Wq53LefxTmqYYYvoAin6PZfLzxV9i5vm91LuY+5f2o/fUGNfKNEtMan0va6cx9aZuV/TiBasL7axL3dQ4zzLPfWgdDkYUbC7s/ifz3PEpcT11UWNufgelyfGUXS6T5nouvo/YnDfDkQL422Uasyl7/FAIng/Rgz8Oo0IzifTQKvXovbo8Qz06M633fd1OBGEi9uvFVPP3UudAZRoVv4oLU3Lh+Q/TEPNvaWTZesp/YrLCNbL91ekCaOhu+H36NZmLaIW8TRRONqeaMouAvMgoi+77n7+OvJzFlFDvo+crIToNtmg9F0Myu9o61afXYeWyRaKO0Utleu7rHQiHpwnzU6NVs98zCIGmU0lrj1dkyg0nUZMAlEekX9XLSd5IiB/P4/hFfL/7V6yWZwoXHyWuFzw/NLniu+hs/sxOPN9RG579/y/2S3f25MMyrn88kTgb2h0fzccO8sSBYriBiUDiILbnqVlvkl0Nx1Hy/ltEBEY6x3ktTHw/XzeP4+H2/I7LQ/CHEUE5EPy9QlEYeiUPGZPo4Zr7fvCo8czUIUH0fz7NeKygEFE8/W9RHPMEUSpruFZeIhm0aNo4gheFj6l30XA6J7+fjvIfxFsPkLUVk4lrg3+ClmjyfdXIideoI4+yna2/XFKN/sgBnq9VJxkumm/h9AygcKniMC3W77ejLj8rDwX+kNETbr4/AbE9efFrRFPJmpExSVqS9FSW7I8lmuqIZfyugIxSnZNog/2fmLA4i/JKVZpmQRncaLloeYgRtTiflw6YReFsOLGLuPy2C4GLi5JTJG4fWe/73y+W37Ph7RaZltK990manmX0uA9hLvrQRQy/wLsm6+PI65aKG4msR1RoCpGxC9NTHJS87SkpeOu+DuKqCnvXlrmdGJazWK7yxEF6kdpKWwtThTkfkbMeNZtN3Op+qPHM9DTD6IUfnv+Qz5Iy42vLwSuIUr8Nc0HXcO2liGC/IeamP+OpvTrlhmnGtyHPfN7/gNd1KxF260ixUC18i03v0NcCjW0rc80eb/3Ipqp7yYmTjBi1Py1RL/w4yxY01maBUfYjyNq+j/MPO9KFM5OoXQ/61bbrGmgX6sgthhxmdIHiQF3axEB+lHymu1Wn6317mjlwVQH5z4fmus+nrgO+wxiXMFOpWUH04nL7koBZE1aavMfzWNuAlGoGEXUiPdq9dmGbqDRHQ8WvKvSPuTNWIhLjb6Wv9F3iIA9tvS5paljHm5iXoCf5m81iLhJx7NEa8euxCWeHyrlbXNivMtJ+b+9QWk9txBdCk2b8a23P3o8A92+wy39asVB/C2i1HYS0Ye4BAtOJdnUuY2bfaKnF0zp10H+hxL9WcX9ZpverNUqwBxHBL5D84TxDaJpdDuiQHMV3TA3cQaBqRkcPkjU0I/P99YjmlU3LPLP+0ceL0cUXIq+3P2IZsPN8zv9Kq1aY2o99kr/G1sQBabinturkSPV871Ly9vozLFd2sZIWvocxxJdRQdnwNgh92vberbRaju7EN1SxXz162eguJ0oKC9PS1/z+77vqj5K+zeQlibpvYlC2s5Eq8LWxPX3W5c+V9eVBPmd/Sb/R39ItJisndu4nihQ7tvqM8U5dwRRc7+FuMrhSWLMwDSaVPFZFB49noEe2/G4jGgZom9sev4tBtQcS5Q4Kz97DFFSPScfOxF9f3dQ4bldW+V/MBF8u7xZi+g3vocI+JcSrSGLEbWy7xL3ku3ymZeI0bDXE0G5uLZzFDGy/MwaPr8T0VR9GVEjKoLa54Cb83lDg++IWvijRD/kb4FrMv23xOxWL9Dg3b9yG/cS/d5XEQOvdiRqYUcAA5r0fW+R69yIKABNIJreVyFqeb+lFw40oiUgjyda9a6nZYDcHkTNuJljMD5EDNIq7i73USI4n09L98UClZ421jEwf/eTiYGomxFdBkOblc/e/ujxDHTbjsbI3QPz+WeIvrlv54n4BXK6QaJ/6wkqcnu1GvetElP6NZD/Lm/WImboepAskRPXHX+TuPSpGPnbZQNNWp+kiJr6dKJWU2x/XeBvRM2jdc24GCm7aZ4YtyNqHWfQMjPXlkSzdaO3RlyMVjWeDJ6nETWvLUvfY10FV6Ip+S9E//g6xDiI3xM11v2IIN1woMz83gT8byltJWK8xeH5utsG83XBcTWO6K9dhShoPEJc4kUeW88TXQ8NVzCIsQW/A+4ppW1E1JYvyN+uM60lOxCDGlVLLj2KktYiL68BvYQo5a9FnGDWIpqx9iJK0LcQpbcJ7v6nHspq3cxsWeKf4v/1dF46I6+1PoYIlA8SJ+XDiCbY09z9j3Ws07x0cJvZSOKE9VN3/2ymbUIUwv4DfBl4x7vgH6LIi5ntQJzE/kXc4GIPopZzPfBbd3/VzJZx93+VPrs28KK7/zP34VrgNnc/08xWJQoWrxM3l9gCOMPdb2ogj9sTtfBtiVr3r/L9DwEnu/sn6/sWFtjWMCIwHufunzazxTyuQb4EuNfdrzSz4V7nTQPa+O1XJQLWfe4+MdO+RrQmnFRcQ9vofnWX8v6Z2USiRaMY5DeduILkNHe/zsyGuPv8RrZjZmsQAfcRomXuYqKwfEAutwnwmrs/1cn1DyMKwn+tJ3+Lqv4dL7JocPebzexNonb8R3d/2szmECXJYURT5j1EU2BdB3FPc/fXezoP9XD3OWb2LbIGRgTlZYiBKi90dn2tTlonECOUHyUGoUw3s7nufr67zzKzd4C57v52c/bm/fLEtjNRm7ia2MfjiaY7iFpzPzP7BVFAKBsKrGxm9xLN2zOJO3Pd5O4P5/6NJmpKU9z93tZBqRN53JMYOHgscXOCH5jZVhkchwOrmdlA4J+dXX/pBL8h0b/5DDE5ygPu/uNc7JXcD4gRvZ1W2s6ORBfV/3P3a81sN+AqM7uNKJzvRowSpjcGZDMbD+zn7odZ3OXpq8Ro8udyMo/DzezORs5luZ29ie/pdWIw183ExC7nm9lUdx/v7rPqXP+8evO2SOvpqnp3P4iayavAAaW0qcQB3uP506N5zVrEyf8uYoDJK8QEK/sQwe2sLt6H1s3VFwBHl15fBNySzz/DQrociGtOn6Glmfs0okm2ad0UxMCxGylNN0k0jT9GFFifoIG7PeX6ilH29xF9vN8hCsWnEjdFeJgGJuigpYl/N2JQ13iiVeLUTB9BtMQ8QssgunanLK3qg7gEbiotE+wsRvQpf56WgVObN2E7Q4iBcMVI6qPyOB5NNGXfSMUvueyNjz43zaa7TyWaRr9hZmdmSXBNoo9ZquHPRKGp083WhazRbUzMIrQvMSJ9daLJ+ERiysEVu2IqPzNbiugWwczWMbPVieblFUuLfRWYb2aLu/v33P2R9tbnce/k/wLuyekQzyYC2wVm9uEmZduJk/BymW9z968RVyf8GDjUo7Wp3ntVDyWaV49x982J/L9GTGdbXGt9mrv/po51r5HTR75tZsOJmtx+xCxtTxEtCxe4+xwiUM8mWirwLmwh6Qp5bI0nCq5FTbM/0QIzhijsXO7u9zVjc8TxUEy9eRVxDO/v7q8Qg8gebsJ2pKynSwU99SAGQbxDlDjX7On86NElv/GSRFPxnfnagH8Ql0U1ZWRvO9v9EHH9+yXEYKZBxEjVl2mZcWkrYgKLEdR+qdJuRJBZPvflNGCTJub7M8Ro2qJmtAUxzqLhkbG0P8r+RkqtVLV+F63W/TGi9atoSRiRv/vMfL0+8C7wpXy9GjEl6Qd6+hitcf/eu4Vk/l2ZGHl/Ay0TzyxFTHbS6dtLtrGdocDAfP5loiWjmHBkb6KVR9cVd9Gjz9WUCx6DYXYkbs/4TE/nR5rP3d8gmi/7Z41yd2KmqOketc+u2u4TROA8FrjJ3f/u7g8QU1SeYWb/TYwsP93d53ie7WpY73QicP6ZOGl+3evsz2vHz4mm0Elm9g1iUOQl7v5ioyt291eJILKjmW3g7m8RA9yWAPa0uHELtX4XrdZ9O3AQMMvMBnvUiAcSfaAQhbPriRHkeAwsOsDdOz1eoSe4v9fff0kOhluTaPp/AviWmY1w9/+4+zvu/mzxmTq3sxdxHNxhZtsQE/osDVxsZl8hxuTclr+fdIE+M/pa+iYzW5Jorv4YMYjoE95FI+tLg3BWy6T9iBri88AN7v6ymX2QGDSzjLs/Wc+grLyS4HWvo6m3hnUvS9TqhwLPufsfmrjupo+yb7X+XYnrzzchmuO/QzTtbgkc4e531fN99zSLu3BdQjRbX0e0vhxNXOr0GaLmf4i7v1nn+ovjdimiifp04hg4kBhP8DTR+rM2MMvdf9vYHsnCKCjLIs/MFidOYO96nZfZ1LCN4rKe3Ykgc6S7P2FmhxGzbP2BaGLdBDjP3VuPsq5nm70xwAykZZT9dGKU/eXAzs2okWdg/i5x6dlyRDfB39z9rkbX3VPM7Hii6+MlYga6Az1GWQ8g9nGguz/Z4DZ2IS4R3crdD8m0w4m59S9397pvLyudo6As0oDydcV5vebVRG38j9kk+x/iOvjtiZHfn/MYbNjnWVy3/Q1i8FdDteRW692VuP3nBh4DknqVNq6z3pMYmLYCcWz91cwOJgoep3idl3SVasgbEzXkaUSX3u/c/cRc5kjiWv5PNKPQJB1TUBapk5mtQDSNz3L3qXkt7MeJ0dH7E0H4XWIO4jeJgUXP98YablfoyskjssXiX+5+Z7PX3R2yP3c4cVOOR4n++NuJgXErEIWOU939lw1uZ1Ni7MOv3f1/zGw00ST+qrt/IZdZxd3rum5cOq/PDvQSaYLFiRH8W2St73biZhI/Ipqq9wT+l2iafcvdn4f6BuEsitx9XlcE5Fz3ze5+Z1dc8tbVzOyjxGCrDYkgvBMROFcjmua/DnzV3X/ZhP0r7hu+kZktQVzDfTEwwswuzmV6xYC4RYVqyiJ1sJyaMZsWDyVG+H6VuN3i4u7+ppmtRwzMOczddR28tKvUlLwKcT39AHe/1cy2Je4vPsHdb8oukQHu/lKdgwSL7awKvOTu/zGzzYmbSvwIuMrjeu+NiGln271+XrqGasoidciAPJaYjP9O4rKRicT9at/MaR5/QTQxKiBLu0qBclfiWLoY2M/MVnL3u4kJb35uZhPd/d/u/hJ0vsUlByMWlz1dCXzPzD5HzKT2ZeLuWUeYWX93f0gBuWcoKIt0koX+RF/xd9z9B8QUhC8Ts0dtQ0yUcYC7T+uNTajSfTJQbkZctvcpoon6dWBfM1shL0Hajuhf7rS81Im8OmBLYvrUTxDjHI4gLoH6IzHv+QTicjjpIWq+FqmTmX2WOFke6+7zs0nwduL2maflhBkiC5WFtueA591960w7jOjrfRa40t3/VizbmRpyDqbbHfiZu/89a8lzicB7FtFs/SliQpozANz9703aNamDasoiNShqu2b2UTM7xOJWhjOJWZUOzOtv+wF/BX6ggCwLUzqeNiPuFnYysLGZfR7A3X9K3AxkHWDZ4nOdDMgrEvO+Pwi4mX3E3afl6/HEhCrXE5PbDCLuK62A3MNUUxapUQ7q+gbwM6L2cSFxo4ltiEkqlqDO+xlL32Nx+8XTgRnE7WOfJ2Y8u8jdv5HL1HVf6Qz6hwJbA/fn35eBazxuWXoNcbx+E/gecW/rmY3vlTRKQVmkBlkzPp5o8tuA6Pfb2t3/YTGV5xrAm+7+jK5Dlo6Y2SDiphLHEGMTTnf3j1hMw/oI8DV3P6cJ2zmJuPvXS0St+0Vigps5xA1BBhMtOzc2ui1pDgVlkXaURsVuCfw3cDdxN571gINyqsPdgL+4++yezKv0LhZzjF9E3F5yDHHJ09Nmti4RPP/tcaONRraxC3GHp8WA+cRUr+sQAfkGd3/E4paX/1BBsjrUpyzSjtKo2K8DXyIuVynu+/ucmW1B3DVnxYWsRuR93P11YqausUSt+Gkz246YD/wpd7+9kVH7ZrYycWvP49x9G+AOYABRC18TOMDMBrj7PzI/CsgV0b+nMyBSccsT81bfCEwm5gb+VM49vDlwkjfxTkrSp1xP3CjlS1mr3QP4rLv/GRoOlG8R5/eV8vUk4k5TmxMB+mbvwtuXSv3UfC3SATPbmxgQcwIxKGcMMBJ41t0fUtOf1CubsccQfbtz3f2BZh1POZJ7OeDn7v5YBv7jgRNd95CvLAVlkRqY2R7EIK8L3P2qns6PSEcs7l99LLAp8ABx/+rjG+2rlq6loCxSo7yE5RvEzEsvuPu7PZwlkYWyuOfyFsQVA7O8F99Xuq9QUBbpBDMb4u7zezofIrJoUlAWERGpCF0SJSIiUhEKyiIiIhWhoCwiIlIRCsoiIiIVoaAsIiJSEQrKIiIiFfH/AR5+AjVd2oEcAAAAAElFTkSuQmCC\\n\",\n            \"text/plain\": [\n              \"<Figure size 432x288 with 1 Axes>\"\n            ]\n          },\n          \"metadata\": {\n            \"tags\": [],\n            \"needs_background\": \"light\"\n          }\n        }\n      ]\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"q2IkKpXZzRiP\"\n      },\n      \"source\": [\n        \"## Exiting the bot\\n\",\n        \"\\n\",\n        \"Once you're done, you can call `bot.quit()` or `bot.end()` to disconnect and stop the bot.\"\n      ]\n    },\n    {\n      \"cell_type\": \"code\",\n      \"metadata\": {\n        \"id\": \"1-NxvPk1YuGw\"\n      },\n      \"source\": [\n        \"bot.quit()\"\n      ],\n      \"execution_count\": null,\n      \"outputs\": []\n    },\n    {\n      \"cell_type\": \"markdown\",\n      \"metadata\": {\n        \"id\": \"SpwlmlCBc90Q\"\n      },\n      \"source\": [\n        \"## Read more\\n\",\n        \"\\n\",\n        \"* **API** - https://github.com/PrismarineJS/mineflayer/blob/master/docs/api.md\\n\",\n        \"* **Type Definitions** - https://github.com/PrismarineJS/mineflayer/blob/master/index.d.ts\\n\",\n        \"* FAQ - https://github.com/PrismarineJS/mineflayer/blob/master/docs/FAQ.md\\n\",\n        \"* JS tutorial - https://github.com/PrismarineJS/mineflayer/blob/master/docs/tutorial.md\\n\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "docs/ru/CONTRIBUTING_RU.md",
    "content": "# Вклад в проект\n\nИзначально Mineflayer создал [andrewrk](http://github.com/andrewrk), но с тех пор проект был улучшен и исправлен многими [помощниками](https://github.com/andrewrk/mineflayer/graphs/contributors).\nЭто то, почему важно знать, как внести свой вклад в mineflayer.\n\n## Организация проблем\n\nУ нас есть метки трёх стадий для организаций проблем:\n\n* Стадия 1: созданы каким-либо новичком, мы не знаем, нуждается ли это в реализации или исправлении\n* Стадия 2: многообещающая идея, но требует дополнительного обдумывания перед реализацией\n* Стадия 3: идея точно задана, осталось только сделать код\n\nСсылки по типу https://github.com/PrismarineJS/mineflayer/issues?q=is%3Aopen+is%3Aissue+-label%3AStage1 могут использоваться для показа только с меток первой стадии, если вы хотите развить какую-либо тему.\n\n## Создание тестов\nMineflayer имеет 2 вида тестов :\n\n * [Внутренние тесты](../../test/internalTest.js) : Тесты, которые выполняются на простом сервере, созданном с помощью node-minecraft-protocol.\n * [Внешние тесты](../../test/externalTests/) : Тесты, который выполняются на ванильном сервере.\n \nЦель этих тестов - автоматически определить, что работает, а что нет в mineflayer, чтобы было проще заставить mineflayer работать.\n\n## Запуск тестов\nВы можете запустить тесты для разных версий Minecraft, используя флаг `-g` в npm run mocha_test. Например:\n\n```bash\n# Запуск всех тестов для всех поддерживаемых версий\nnpm run test\n\n# Запуск определённого теста для Minecraft 1.20.4\nnpm run mocha_test -- -g \"mineflayer_external 1.20.4v.*exampleBee\"\n\n# Запуск всех тестов только для версии 1.20.4\nnpm run mocha_test -- -g \"mineflayer_external 1.20.4v\"\n```\n\n### Создание внешних тестов\n\nДля внешних тестов вам просто нужно создать файл в [test/externalTests](../../test/externalTests)\n\nНапример : [test/externalTests/digAndBuild.js](https://github.com/PrismarineJS/mineflayer/blob/master/test/externalTests/digAndBuild.js)\n\nЭтот файл должен экспортировать функцию, возвращающую функцию или массив функций, принимающих в качестве параметра объект бота и выполненный обратный вызов,  \nон должен содержать утверждения для проверки, если тестируемая функциональность не сработала.\n\n\n## Создание стороннего плагина\nMineflayer поддерживает плагины; любой желающий может создать плагин, который добавляет API еще более высокого уровня поверх Mineflayer.\n\nНесколько сторонних плагинов, которые уже были сделаны вы можете найти [здесь](https://github.com/andrewrk/mineflayer#third-party-plugins).\n\nДля того чтобы создать новый плагин, вам необходимо :\n\n1. Создать новый репозиторий\n2. В вашем файле index.js, экспортировать функцию init, которая будет принимать mineflayer в качестве аргумента. ([Пример](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L18))\n3. Эта функция возвращает функцию inject, которая принимает объект бота. ([Пример](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L23))\n4. С помощью этой inject функции можно добавить функционал объекту бота. ([Пример](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L32))\n\nПоскольку объект mineflayer передается в параметре, этот новый пакет не должен зависеть от mineflayer (в package.json не должно быть зависимости mineflayer)\n\nСмотрите [полный пример здесь](https://github.com/andrewrk/mineflayer-navigate/tree/e24cb6a868ce64ae43bea2d035832c15ed01d301).\n\n## Сообщения об ошибках\nMineflayer хорошо работает в большинстве случаев, но иногда в нем все еще есть ошибки.\n\nПри обнаружении ошибки лучше всего сообщить о проблеме, предоставив следующую информацию :\n\n* что вы хотите сделать (цель на английском языке)\n* что вы делаете (ваш код)\n* что происходит\n* что вы ожидали увидеть\n\n## Код Mineflayer\nНекоторые вещи, о которых следует подумать при отправке Pull Request или commit :\n\n### Обработка ошибок\nВ большинстве случаев mineflayer не должен выводить бота из строя. Даже если что-то не сработает, бот может воспользоваться альтернативным маршрутом, чтобы добраться до своей цели.\n\nЭто означает, что мы не должны использовать `throw(new Error(\"error\"))`, а вместо этого использовать соглашение node.js о передаче ошибки в обратном вызове.\n+\nПример : \n\n```js\nfunction myfunction (param1, callback) {\n  // что-то делаем\n  let toDo = 1\n  toDo = 2\n  if (toDo === 2) { // всё работает\n    callback()\n  } else {\n    callback(new Error('что-то не так'))\n  }\n}\n```\n\nВы можете посмотреть другие примеры в [коде mineflayer](https://github.com/andrewrk/mineflayer/blob/a8736c4ea473cf1a609c5a29046c0cdad006d429/lib/plugins/bed.js#L10)\n\n### Обновление документации\nСписок содержимого документации docs/api.md is made with doctoc. After updating that file, you should run doctoc docs/api.md to update the table of content.\n"
  },
  {
    "path": "docs/ru/FAQ_RU.md",
    "content": "## FAQ\n\nЭто документ с часто задаваемыми вопросами, предназначен для помощи людям в самых распространенных вещах.\n\n### Выдаёт ошибку (например, protocol/data) когда бот пытается подключиться к серверу Minecraft.\n\nУбедитесь, что версия сервера Minecraft поддерживается (см. README), иначе попробуйте ещё раз, используя [тестовые версии mineflayer](../../lib/version.js).\n\n### Выдаёт ошибку при попытке войти в систему через аккаунт Microsoft.\n\nУбедитесь, что адрес электронной почты, который вы ввели в поле username в createBot, можно использовать для входа на `minecraft.net` используя кнопку «Войти с помощью Microsoft».\nУбедитесь, что у вас прописана опция `auth: 'microsoft'` в настройках вашего createBot.\n\nКогда вы получите сообщение об ошибке, в котором говорится что-то о недопустимых учетных данных или «Владеет ли эта учетная запись Minecraft?», попробуйте удалить поле пароля в параметрах `createBot` и повторите попытку.\n\n### Как скрыть ошибки?\n\nИспользуйте `hideErrors: true` в параметрах createBot. \nВы также можете добавить эти слушатели:\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n### Я не получаю событие чата на сервере, как я могу это решить?\n\nСервера Spigot, в частности некоторые плагины, используют разные форматы чата, вам необходимо проанализировать его с помощью регулярного выражения/парсера.\nПосмотрите и измените скрипт [chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js), чтобы он работал для вашего плагина на чат, также прочтите http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat\n\n### Как я могу собрать информацию из плагина в чате?\n\nБольшинство майнкрафт серверов поддерживают плагины, и многие из этих плагинов выводят что-то в чат, когда что-то происходит. Если это всего лишь одно сообщение, лучше использовать решение, описанное выше, но когда эти сообщения разбиты на множество небольших сообщений, другим вариантом является использование события `\"messagestr\"`, поскольку оно позволяет легко анализировать многострочные сообщения.\n\n**Пример:**\n\nСообщение в чате выглядит следующим образом:\n```\n(!) U9G выйграл в /jackpot и получил\n$26,418,402,450! Он купил 2,350,000 (76.32%) билета(ов) из\n3,079,185 проданных билета(ов)!\n```\n```js\nconst regex = {\n  first: /\\(!\\) (.+) выйграл в \\/jackpot и получил +/,\n  second: /\\$(.+)! Он купил (.+) \\((.+)%\\) билета\\(ов\\) из /,\n  third: /(.+) проданных билета\\(ов\\)!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n### Как я могу отправлять команды?\n\nИспользуйте `bot.chat()`.\n\nПример:\n\n```js\nbot.chat('/give @p diamond')\n```\n\n### Можно ли войти в несколько учетных записей с помощью bot = mineflayer.createbot, контролируя их все по отдельности?\n\nСоздавайте разные экземпляры ботов, вызывая createBot, затем выполняйте разные действия для каждого. [Пример](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple.js).\n\n### Как заставить бота выбросить все вещи их инвентаря?\n\n`bot.inventory.items()` возвращает массив предметов в инвентаре бота. Вы можете использовать рекурсивную функцию, чтобы перебрать их и выбросить каждый элемент используя `bot.toss()`. Нажмите [здесь](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9), чтобы посмотреть пример\n\n### Как проверить отправленные/полученные пакеты?\n\nВключите отладку https://github.com/PrismarineJS/mineflayer#debug\n\n### Я хочу избежать отключения бота от сервера даже в случае задержки сервера, как мне этого добиться?\n\nОдин из способов - увеличить параметр [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) (передаваемый в createBot) к более высокому значению (Например `300*1000`, что составляет 5 минут вместо обычных 30 сек.). Если вы всё ещё сталкиваетесь с данной проблемой, вы можете автоматически переподключиться, используя что-то вроде этого примера https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js\n\n### Как получить описание/текст предмета?\n\nВы можете использовать свойство `item.nbt`. Также рекомендуем использовать библиотеку `prismarine-nbt`. Метод `nbt.simplify()` может быть полезен.\n\n**Пример:**\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### Как я могу отправить сообщение из консоли на сервер?\n\nВы можете использовать библиотеку, такую как `repl`, чтобы прочитать ввод консоли и использовать `bot.chat()` для его отправки. Вы можете найти пример [здесь](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js).\n\n### Как я могу использовать другой плагин в качестве зависимости при создании своего плагина?\n\nВ функции `inject()` вашего плагина вы можете безопасно вызвать `bot.loadPlugin(anotherPlugin)`, чтобы убедиться, что плагин загружен. Если плагин уже был загружен ранее, ничего не произойдет.\n\nОбратите внимание, что порядок в котором загружаются плагины является динамическим, поэтому вы никогда не должны вызывать другой плагин в своей функции `inject()`.\n\n### Как я могу использовать прокси socks5?\n\nВ объекте с настройками для `mineflayer.createBot(options)` удалите опцию `host`, объявите переменные `PROXY_IP, PROXY_PORT, PROXY_USERNAME, PROXY_PASSWORD, MC_SERVER_ADDRESS, MC_SERVER_PORT`, затем добавьте это в свой объект с настройками:\n```js\nconnect: (client) => {\n    socks.createConnection({\n      proxy: {\n        host: PROXY_IP,\n        port: PROXY_PORT,\n        type: 5,\n        userId: PROXY_USERNAME,\n        password: PROXY_PASSWORD\n      },\n      command: 'connect',\n      destination: {\n        host: MC_SERVER_ADDRESS,\n        port: MC_SERVER_PORT\n      }\n    }, (err, info) => {\n      if (err) {\n        console.log(err)\n        return\n      }\n      client.setSocket(info.socket)\n      client.emit('connect')\n    })\n  }\n  ```\n  `socks` объявляется с помощью `const socks = require('socks').SocksClient` и использует [эту](https://www.npmjs.com/package/socks) библиотеку.\n  Некоторые серверы могут отклонить соединение. Если это произойдет, попробуйте добавить `fakeHost: MC_SERVER_ADDRESS` в настройки.\n  \n# Частые ошибки\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\nЭта ошибка означает, что вы ввели неправильную версию сервера, либо mineflayer обнаруживает её неправильно.\n\n### `TypeError: Cannot read property '?' of undefined`\n\nВозможно, вы пытаетесь использовать что-то в объекте бота, чего еще нет, попробуйте вызвать инструкцию после события `spawn`\n\n### `SyntaxError: Unexpected token '?'`\n\nОбновите node.js\n\n### Бот не может ломать/ставить блоки или открывать сундуки\n\nУбедитесь, что защита спавна не мешает боту\n\n"
  },
  {
    "path": "docs/ru/README_RU.md",
    "content": "# Mineflayer\n\n[![Версия NPM](https://img.shields.io/npm/v/mineflayer.svg?color=success&label=npm%20package&logo=npm)](https://www.npmjs.com/package/mineflayer)\n[![Последние изменения](https://img.shields.io/github/actions/workflow/status/PrismarineJS/mineflayer/ci.yml.svg?label=CI&logo=github&logoColor=lightgrey)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Попробуйте на gitpod](https://img.shields.io/static/v1.svg?label=try&message=on%20gitpod&color=brightgreen&logo=gitpod)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n[![Открыть в Colab](https://img.shields.io/static/v1.svg?label=open&message=on%20colab&color=blue&logo=google-colab)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)\n[![Спонсоры GitHub](https://img.shields.io/github/sponsors/PrismarineJS)](https://github.com/sponsors/PrismarineJS)\n\n[![Официальный дискорд](https://img.shields.io/static/v1.svg?label=OFFICIAL&message=DISCORD&color=blue&logo=discord&style=for-the-badge)](https://discord.gg/GsEFRM8)\n\n| <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) | <sub>BR</sub> [Portuguese](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|\n\nСоздавайте ботов Minecraft с помощью мощного, стабильного и высокоуровневого JavaScript [API](api_ru.md), также можете использовать Python.\n\nПервый раз используете Node.js? Начните с [этого](tutorial_ru.md). Знаете Python? Посмотрите [примеры на Python](https://github.com/PrismarineJS/mineflayer/tree/master/examples/python) и попробуйте [Mineflayer в Google Colab](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb).\n\n## Возможности\n\n * Поддержка с Minecraft 1.8 до 1.21.8 (1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.20, 1.21.8)\n * Поддержка энтити и их отслеживание.\n * Вы можете полностью взаимодействовать с миром. Миллисекунды на поиск любого блока.\n * Физика и управление.\n * Атака энтити и использование транспортных средств.\n * Взаимодействие с инвентарем.\n * Взаимодействие с крафтом, сундуками, раздатчиками и чаровальными столами.\n * Вы можете копать и строить.\n * Мелкие функции, такие как отслеживание здоровья и погоды.\n * Активация блоков и использование предметов.\n * Взаимодействие с чатом.\n\n### Наши цели\n\nУзнайте про наши текущие [задачи](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects). \n \n## Установка\n\nСначала установите Node.js >= 18 из [nodejs.org](https://nodejs.org/), затем выполните:\n\n`npm install mineflayer`\n\nЧтобы обновить пакет mineflayer (или любой Node.js) и его зависимости, используйте\n```bash\nnpm update\n```\n\n## Документация\n\n| Ссылка                                                                     | Описание                              |\n| -------------------------------------------------------------------------- | ------------------------------------- |\n| [Обучение](tutorial_ru.md)                                                 | Знакомство с Node.js и Mineflayer     |\n| [ЧАВО](FAQ_RU.md)                                                          | Появился вопрос? Найдите ответ здесь. |\n| **[api_ru.md](api_ru.md)** <br/>[unstable_api.md](unstable_api_ru.md)      | Полное описание API                   |\n| [Обновления](../history.md)                                                | Список изменений в обновлениях        |\n| [Примеры](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Примеры использования Mineflayer      |\n\n\n## Сделать вклад в развитие Mineflayer\n\nПрочитайте [CONTRIBUTING_RU.md](CONTRIBUTING_RU.md) и [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute)\n\n## Использование\n\n**Видео**\n\nОбучающее видео, объясняющее базовый процесс настройки бота, можно найти [здесь](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n\nЕсли Вы хотите узнать больше, посмотрите другие видео [здесь](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV), а также посмотреть [исходный код ботов](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials)\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Перед запуском**\n\nЕсли версия не указана, она будет выбрана автоматически, исходя из поддерживаемых сервером версии.\nБез указания `auth` будет выбран вход через mojang.\n\n### Простой пример\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // айпи майнкрафт сервера\n  username: 'email@example.com', // ник бота\n  auth: 'microsoft' // для пираток нужно заменить на 'offline'\n  // port: 25565,                // прописывайте, если порт не 25565\n  // version: false,             // прописывайте, если нужна конкретная версия или снапшот (например: \"1.8.9\" или \"1.16.5\"), иначе версия будет выбрана автоматически\n  // password: '12345678'        // прописывайте, если хотите использовать аутентификацию через пароль (может быть ненадёжно)\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// Логирование ошибок и причин отключения от сервера:\nbot.on('kicked', console.log)\nbot.on('error', console.log)\n```\n\nЕсли в `auth` установлен `microsoft`, вам предложит войти в microsoft.com с кодом в вашем браузере. После входа через браузер \nбот автоматически получит и сохранит в кэш токен аутентификации (для вашего ника), чтобы потом вам опять не пришлось входить.\n\nЧтобы сменить аккаунт, обновите `username`. По умолчанию кэшированые токены храняться в вашей папке .minecraft или в `profilesFolder`, если это указано.\nДля большей информации о настройках бота смотрите [API документацию](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) по node-minecraft-protocol.\n\n#### Подключение к Realm\n\nЧтобы зайти в Realm, куда ваш аккаунт был приглашён, вы можете вписать объект `realms` с функцией, как показано ниже.\n\n```js\nconst client = mineflayer.createBot({\n  username: 'email@example.com', // майнкрафт ник\n  realms: {\n    // Эта функция вызывается с массивом доступных для аккаунта Realm'ов. Оно должно возвращать то, куда оно хочет зайти.\n    pickRealm: (realms) => realms[0]\n  },\n  auth: 'microsoft'\n})\n```\n\n### Смотрите, что делает бот\n\nСпасибо репозиторию [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer), с помощью которого можно через браузер увидеть, что делает бот.\nУстановите его через `npm install prismarine-viewer` и добавьте это в код:\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // port - это порт сервера майнкрафт, если значение firstPerson: false, вы получите вид с высоты птичьего полета\n})\n```\nПосле запуска, вы в прямом эфире сможете наблюдать за происходящим:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### Больше примеров\n\n| Пример                                                                                                      | Описание                                                                                  |\n| ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |\n| [viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer)                            | Отобразить через браузер вид от лица бота                                                 |\n| [pathfinder](https://github.com/PrismarineJS/mineflayer/tree/master/examples/pathfinder)                    | Передвижение бота по координатам и не только                                              |\n| [chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js)                           | Использование сундуков, печек, раздатчиков и чаровальных столов                           |\n| [digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js)                         | Пример для создания бота-шахтёра                                                          |\n| [discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js)                       | Создайте Discord бота                                                                     |\n| [jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js)                         | Научите бота передвигатся, прыгать, использовать средства пережвижения, а также атаковать |\n| [ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js)                             | Отобразите чат вашего бота со всеми цветами, отображаемыми в вашем терминале              |\n| [guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js)                           | Заставьте бота охранять определенную область от мобов                                     |\n| [multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Добавьте текстовый файл с аккаунтами для запуска нескольких ботов                         |\n\nМножество других примеров в [данной папке](https://github.com/PrismarineJS/mineflayer/tree/master/examples)\n\n### Модули\n\nБольшая часть разработки происходит внутри небольших пакетов npm, которые используются mineflayer.\n\n#### The Node Way&trade;\n\n> \"Когда приложения сделаны правильно, они представляют собой лишь ту самую специфичную, \"солоноватую\" прослойку логики, которую нельзя так просто абстрагировать. Все изящные, переиспользуемые компоненты возносятся на github и npm, где все могут совместно работать на общее благо.\" — substack из [\"как я пишу модули\"](https://gist.github.com/substack/5075355)\n\n#### Модули\n\nЗдесь основная часть пакетов, которые используются в mineflayer:\n\n| Модуль                                                                        | Описание                                                                                |\n| ----------------------------------------------------------------------------- |---------------------------------------------------------------------------------------- |\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Парсинг пакетов Minecraft, аутентификация и шифрование                                  |\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data)              | Независимый от языка модуль, предоставляющий данные Minecraft для клиента и сервера     |\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics)      | Взаимодействие с физикой                                                                |\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk)          | Хранение чанков Minecraft                                                               |\n| [node-vec3](https://github.com/PrismarineJS/node-vec3)                        | Векторная обработка координат                                                           |\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block)          | Взаимодействие с блоками и их данными                                                   |\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat)            | Парсер чата Minecraft (вырезано из Mineflayer)                                          |\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil)              | Библиотека для взаимодействия с системой аутентификации Mojang, известная как Yggdrasil |\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world)          | Реализация миров для prismarine                                                         |\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows)      | Взаимодействие с GUI                                                                    |\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item)            | Взаимодействие с предметами и их данными                                                |\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt)              | Парсер NBT для node-minecraft-protocol                                                  |\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)        | Взаимодействие с рецептами крафта                                                       |\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome)          | Взаимодействие с биомами                                                                |\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)        | Взаимодействие с сущностями                                                             |\n\n\n### Дебаг\n\nВы можете отлавливать ошибки с помощью переменной окружения `DEBUG`:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nВ Windows:\n```\nset DEBUG=minecraft-protocol\nnode your_script.js\n```\n\n## Cторонние плагины:\n\nMineflayer поддерживает сторонние плагины. Любой желающий может создать плагин, который добавляет API ещё более высокого уровня поверх Mineflayer.\n\nНаиболее обновлённые и полезные:\n\n * [minecraft-mcp-server](https://github.com/yuniko-software/minecraft-mcp-server) Сервер MCP для mineflayer, позволяющий использовать mineflayer из LLM\n * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - Продвинутый A* поиск пути с множеством настраиваемых функций\n * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - Простой web клиент для просмотра чанков\n * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - Веб клиент для взаимодействия с инвентарём\n * [statemachine](https://github.com/PrismarineJS/mineflayer-statemachine) - API для более сложного поведения бота\n * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - Автоматическое взаимодействие с бронёй\n * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - Панель управления для бота\n * [PVP](https://github.com/PrismarineJS/mineflayer-pvp) - Простой API для базовых PVP и PVE сражений\n * [Auto Eat](https://github.com/link-discord/mineflayer-auto-eat) - Автоматическое поедание пищи\n * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - Автоматическое размещение и взрыв кристалов края\n * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - Утилита для автоматического выбора инструмента/оружия с высокоуровневым API\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - Утилита для использования автоматического прицеливания из луков\n * [GUI](https://github.com/firejoust/mineflayer-GUI) - Взаимодействие с окнами по типу инвентаря, используя async/await\n * [Projectile](https://github.com/firejoust/mineflayer-projectile) - Получение необходимого угола запуска снарядов\n * [Movement](https://github.com/firejoust/mineflayer-movement) - Плавные и реалистичные движения игрока, лучше всего подходящие для PvP\n * [Collect Block](https://github.com/PrismarineJS/mineflayer-collectblock) - API для простого способа для подбора блоков\n\n\nВы также можете изучить:\n\n * [radar](https://github.com/andrewrk/mineflayer-radar/) - Веб радар, созданный с помощью\n * [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - Аутентификация на пиратских серверах\n * [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - Отслеживание получаемого урона в пределах видимости\n * [tps](https://github.com/SiebeDW/mineflayer-tps) - Получение TPS сервера\n * [panorama](https://github.com/IceTank/mineflayer-panorama) - Создание панорамных снимков вашего мира\n * [player-death-event](https://github.com/tuanzisama/mineflayer-death-event) - Создание события смерти игрока в Mineflayer.\n\n## Проекты, созданные с помощью Mineflayer\n\n * [Voyager](https://github.com/MineDojo/Voyager) - Открытый агент с большими языковыми моделями\n * [mindcraft](https://github.com/kolbytn/mindcraft) - Библиотека для использования mineflayer с LLM\n * [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - постройка спиральной лестницы](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - дублирование постройки](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n * [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - Визуализация от первого лица бота, созданная с помощью voxel.js\n * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) - Логирование активности игрока в онлайн-API\n * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (последняя версия с открытым исходным кодом, созданная AlexKvazos) - Веб чат майнкрафт сервера\n * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - Плагин с чистым GUI. Создан с помощью Node-Webkit. http://bot.ezcha.net/\n * [Chaoscraft](https://github.com/schematical/chaoscraft) - Бот Minecraft, использующий генетические алгоритмы, посмотрите [эти видео](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) - Мост между Minecraft и Telegram, созданный при помощи Mineflayer & Telegraf\n * [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - Строит схемы в режиме выживания, сохраняя направление\n * [SilkePilon/OpenDeliveryBot](https://github.com/SilkePilon/OpenDeliveryBot) - Minecraft бот на Python для переноса вещей с места на место.\n * [и многие другие](https://github.com/PrismarineJS/mineflayer/network/dependents) - Все проекты, обнаруженные GitHub, в которых используется Mineflayer\n\n\n## Тестирование\n\n### Тестирование всего\n\nПросто запустите:\n\n```bash\nnpm test\n```\n\n### Тестирование определённой версии\nЗапустите\n\n```bash\nnpm run mocha_test -- -g <version>\n```\n\nгде `<version>` означает версию, таких как `1.12`, `1.15.2`...\n\n### Тестирование определённой функции\n\nЗапустите\n\n```bash\nnpm run mocha_test -- -g <test_name>\n```\n\nгде `<test_name>` означает название проверки, таких как `bed`, `useChests`, `rayTrace`...\n\n### Пример\n\n```bash\nnpm run mocha_test -- -g \"1.18.1.*BlockFinder\"\n```\n\nзапустит тест BlockFinder на версии 1.18.1\n\n## Лицензия\n\n[MIT](../../LICENSE)\n"
  },
  {
    "path": "docs/ru/_sidebar.md",
    "content": "- Первые шаги\n  - [Вступление](ru/README_RU.md)\n  - [API](ru/api_ru.md)\n  - [ЧаВо](ru/FAQ_RU.md)\n  - [Примеры](ru/demos_ru.md)\n  - [Туториал](ru/tutorial_ru.md)\n  - [Нестабильное API](ru/unstable_api_ru.md)\n  - [Помочь](ru/CONTRIBUTING_RU.md)\n  - [История](history.md)\n"
  },
  {
    "path": "docs/ru/api_ru.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Содержание**  *сгенерировано с помощью [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API](#api)\n  - [Enums](#enums)\n    - [minecraft-data](#minecraft-data)\n    - [mcdata.blocks](#mcdatablocks)\n    - [mcdata.items](#mcdataitems)\n    - [mcdata.materials](#mcdatamaterials)\n    - [mcdata.recipes](#mcdatarecipes)\n    - [mcdata.instruments](#mcdatainstruments)\n    - [mcdata.biomes](#mcdatabiomes)\n    - [mcdata.entities](#mcdataentities)\n  - [Classes](#classes)\n    - [vec3](#vec3)\n    - [mineflayer.Location](#mineflayerlocation)\n    - [Entity](#entity)\n      - [Player Skin Data](#player-skin-data)\n    - [Block](#block)\n    - [Biome](#biome)\n    - [Item](#item)\n    - [windows.Window (base class)](#windowswindow-base-class)\n      - [window.deposit(itemType, metadata, count, nbt)](#windowdeposititemtype-metadata-count-nbt)\n      - [window.withdraw(itemType, metadata, count, nbt)](#windowwithdrawitemtype-metadata-count-nbt)\n      - [window.close()](#windowclose)\n    - [Recipe](#recipe)\n    - [mineflayer.Container](#mineflayercontainer)\n    - [mineflayer.Furnace](#mineflayerfurnace)\n      - [furnace \"update\"](#furnace-update)\n      - [furnace.takeInput()](#furnacetakeinput)\n      - [furnace.takeFuel()](#furnacetakefuel)\n      - [furnace.takeOutput()](#furnacetakeoutput)\n      - [furnace.putInput(itemType, metadata, count)](#furnaceputinputitemtype-metadata-count)\n      - [furnace.putFuel(itemType, metadata, count)](#furnaceputfuelitemtype-metadata-count)\n      - [furnace.inputItem()](#furnaceinputitem)\n      - [furnace.fuelItem()](#furnacefuelitem)\n      - [furnace.outputItem()](#furnaceoutputitem)\n      - [furnace.fuel](#furnacefuel)\n      - [furnace.progress](#furnaceprogress)\n    - [mineflayer.EnchantmentTable](#mineflayerenchantmenttable)\n      - [enchantmentTable \"ready\"](#enchantmenttable-ready)\n      - [enchantmentTable.targetItem()](#enchantmenttabletargetitem)\n      - [enchantmentTable.xpseed](#enchantmenttablexpseed)\n      - [enchantmentTable.enchantments](#enchantmenttableenchantments)\n      - [enchantmentTable.enchant(choice)](#enchantmenttableenchantchoice)\n      - [enchantmentTable.takeTargetItem()](#enchantmenttabletaketargetitem)\n      - [enchantmentTable.putTargetItem(item)](#enchantmenttableputtargetitemitem)\n      - [enchantmentTable.putLapis(item)](#enchantmenttableputlapisitem)\n    - [mineflayer.anvil](#mineflayeranvil)\n      - [anvil.combine(itemOne, itemTwo[, name])](#anvilcombineitemone-itemtwo-name)\n      - [anvil.combine(item[, name])](#anvilcombineitem-name)\n      - [villager \"ready\"](#villager-ready)\n      - [villager.trades](#villagertrades)\n      - [villager.trade(tradeIndex, [times])](#villagertradetradeindex-times)\n    - [mineflayer.ScoreBoard](#mineflayerscoreboard)\n      - [ScoreBoard.name](#scoreboardname)\n      - [ScoreBoard.title](#scoreboardtitle)\n      - [ScoreBoard.itemsMap](#scoreboarditemsmap)\n      - [ScoreBoard.items](#scoreboarditems)\n    - [mineflayer.Team](#mineflayerteam)\n      - [Team.name](#teamname)\n      - [Team.friendlyFire](#teamfriendlyfire)\n      - [Team.nameTagVisibility](#teamnametagvisibility)\n      - [Team.collisionRule](#teamcollisionrule)\n      - [Team.color](#teamcolor)\n      - [Team.prefix](#teamprefix)\n      - [Team.suffix](#teamsuffix)\n      - [Team.members](#teammembers)\n    - [mineflayer.BossBar](#mineflayerbossbar)\n      - [BossBar.title](#bossbartitle)\n      - [BossBar.health](#bossbarhealth)\n      - [BossBar.dividers](#bossbardividers)\n      - [BossBar.entityUUID](#bossbarentityuuid)\n      - [BossBar.shouldDarkenSky](#bossbarshoulddarkensky)\n      - [BossBar.isDragonBar](#bossbarisdragonbar)\n      - [BossBar.createFog](#bossbarcreatefog)\n      - [BossBar.color](#bossbarcolor)\n    - [mineflayer.Particle](#mineflayerparticle)\n      - [Particle.id](#particleid)\n      - [Particle.name](#particlename)\n      - [Particle.position](#particleposition)\n      - [Particle.offset](#particleoffset)\n      - [Particle.longDistanceRender](#particlelongdistancerender)\n      - [Particle.count](#particlecount)\n      - [Particle.movementSpeed](#particlemovementspeed)\n  - [Bot](#bot)\n    - [mineflayer.createBot(options)](#mineflayercreatebotoptions)\n    - [Properties](#properties)\n      - [bot.registry](#botregistry)\n      - [bot.world](#botworld)\n        - [world \"blockUpdate\" (oldBlock, newBlock)](#world-blockupdate-oldblock-newblock)\n        - [world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#world-blockupdatex-y-z-oldblock-newblock)\n      - [bot.entity](#botentity)\n      - [bot.entities](#botentities)\n      - [bot.username](#botusername)\n      - [bot.spawnPoint](#botspawnpoint)\n      - [bot.heldItem](#bothelditem)\n      - [bot.usingHeldItem](#botusinghelditem)\n      - [bot.game.levelType](#botgameleveltype)\n      - [bot.game.dimension](#botgamedimension)\n      - [bot.game.difficulty](#botgamedifficulty)\n      - [bot.game.gameMode](#botgamegamemode)\n      - [bot.game.hardcore](#botgamehardcore)\n      - [bot.game.maxPlayers](#botgamemaxplayers)\n      - [bot.game.serverBrand](#botgameserverbrand)\n      - [bot.game.minY](#botgameminy)\n      - [bot.game.height](#botgameheight)\n      - [bot.physicsEnabled](#botphysicsenabled)\n      - [bot.player](#botplayer)\n      - [bot.players](#botplayers)\n      - [bot.tablist](#bottablist)\n      - [bot.isRaining](#botisraining)\n      - [bot.rainState](#botrainstate)\n      - [bot.thunderState](#botthunderstate)\n      - [bot.chatPatterns](#botchatpatterns)\n      - [bot.settings.chat](#botsettingschat)\n      - [bot.settings.colorsEnabled](#botsettingscolorsenabled)\n      - [bot.settings.viewDistance](#botsettingsviewdistance)\n      - [bot.settings.difficulty](#botsettingsdifficulty)\n      - [bot.settings.skinParts](#botsettingsskinparts)\n        - [bot.settings.skinParts.showCape - boolean](#botsettingsskinpartsshowcape---boolean)\n        - [bot.settings.skinParts.showJacket - boolean](#botsettingsskinpartsshowjacket---boolean)\n        - [bot.settings.skinParts.showLeftSleeve - boolean](#botsettingsskinpartsshowleftsleeve---boolean)\n        - [bot.settings.skinParts.showRightSleeve - boolean](#botsettingsskinpartsshowrightsleeve---boolean)\n        - [bot.settings.skinParts.showLeftPants - boolean](#botsettingsskinpartsshowleftpants---boolean)\n        - [bot.settings.skinParts.showRightPants - boolean](#botsettingsskinpartsshowrightpants---boolean)\n        - [bot.settings.skinParts.showHat - boolean](#botsettingsskinpartsshowhat---boolean)\n      - [bot.settings.enableTextFiltering - boolean](#botsettingsenabletextfiltering---boolean)\n      - [bot.settings.enableServerListing - boolean](#botsettingsenableserverlisting---boolean)\n      - [bot.experience.level](#botexperiencelevel)\n      - [bot.experience.points](#botexperiencepoints)\n      - [bot.experience.progress](#botexperienceprogress)\n      - [bot.health](#bothealth)\n      - [bot.food](#botfood)\n      - [bot.foodSaturation](#botfoodsaturation)\n      - [bot.oxygenLevel](#botoxygenlevel)\n      - [bot.physics](#botphysics)\n      - [bot.fireworkRocketDuration](#botfireworkrocketduration)\n      - [bot.simpleClick.leftMouse (slot)](#botsimpleclickleftmouse-slot)\n      - [bot.simpleClick.rightMouse (slot)](#botsimpleclickrightmouse-slot)\n      - [bot.time.doDaylightCycle](#bottimedodaylightcycle)\n      - [bot.time.bigTime](#bottimebigtime)\n      - [bot.time.time](#bottimetime)\n      - [bot.time.timeOfDay](#bottimetimeofday)\n      - [bot.time.day](#bottimeday)\n      - [bot.time.isDay](#bottimeisday)\n      - [bot.time.moonPhase](#bottimemoonphase)\n      - [bot.time.bigAge](#bottimebigage)\n      - [bot.time.age](#bottimeage)\n      - [bot.quickBarSlot](#botquickbarslot)\n      - [bot.inventory](#botinventory)\n      - [bot.targetDigBlock](#bottargetdigblock)\n      - [bot.isSleeping](#botissleeping)\n      - [bot.scoreboards](#botscoreboards)\n      - [bot.scoreboard](#botscoreboard)\n      - [bot.teams](#botteams)\n      - [bot.teamMap](#botteammap)\n      - [bot.controlState](#botcontrolstate)\n    - [Events](#events)\n      - [\"chat\" (username, message, translate, jsonMsg, matches)](#chat-username-message-translate-jsonmsg-matches)\n      - [\"whisper\" (username, message, translate, jsonMsg, matches)](#whisper-username-message-translate-jsonmsg-matches)\n      - [\"actionBar\" (jsonMsg, verified)](#actionbar-jsonmsg-verified)\n      - [\"message\" (jsonMsg, position, sender, verified)](#message-jsonmsg-position-sender-verified)\n      - [\"messagestr\" (message, messagePosition, jsonMsg, sender, verified)](#messagestr-message-messageposition-jsonmsg-sender-verified)\n      - [\"inject_allowed\"](#inject_allowed)\n      - [\"login\"](#login)\n      - [\"spawn\"](#spawn)\n      - [\"respawn\"](#respawn)\n      - [\"game\"](#game)\n      - [\"resourcePack\" (url, hash)](#resourcepack-url-hash)\n      - [\"title\" (title, type)](#title-title-type)\n      - [\"title_times\" (fadeIn, stay, fadeOut)](#title_times-fadein-stay-fadeout)\n      - [\"title_clear\"](#title_clear)\n      - [\"rain\"](#rain)\n      - [\"weatherUpdate\"](#weatherupdate)\n      - [\"time\"](#time)\n      - [\"kicked\" (reason, loggedIn)](#kicked-reason-loggedin)\n      - [\"end\" (reason)](#end-reason)\n      - [\"error\" (err)](#error-err)\n      - [\"spawnReset\"](#spawnreset)\n      - [\"death\"](#death)\n      - [\"health\"](#health)\n      - [\"breath\"](#breath)\n      - [\"entityAttributes\" (entity)](#entityattributes-entity)\n      - [\"entitySwingArm\" (entity)](#entityswingarm-entity)\n      - [\"entityHurt\" (entity)](#entityhurt-entity)\n      - [\"entityDead\" (entity)](#entitydead-entity)\n      - [\"entityTaming\" (entity)](#entitytaming-entity)\n      - [\"entityTamed\" (entity)](#entitytamed-entity)\n      - [\"entityShakingOffWater\" (entity)](#entityshakingoffwater-entity)\n      - [\"entityEatingGrass\" (entity)](#entityeatinggrass-entity)\n      - [\"entityHandSwap\" (entity)](#entityhandswap-entity)\n      - [\"entityWake\" (entity)](#entitywake-entity)\n      - [\"entityEat\" (entity)](#entityeat-entity)\n      - [\"entityCriticalEffect\" (entity)](#entitycriticaleffect-entity)\n      - [\"entityMagicCriticalEffect\" (entity)](#entitymagiccriticaleffect-entity)\n      - [\"entityCrouch\" (entity)](#entitycrouch-entity)\n      - [\"entityUncrouch\" (entity)](#entityuncrouch-entity)\n      - [\"entityEquip\" (entity)](#entityequip-entity)\n      - [\"entitySleep\" (entity)](#entitysleep-entity)\n      - [\"entitySpawn\" (entity)](#entityspawn-entity)\n      - [\"entityElytraFlew\" (entity)](#entityelytraflew-entity)\n      - [\"itemDrop\" (entity)](#itemdrop-entity)\n      - [\"playerCollect\" (collector, collected)](#playercollect-collector-collected)\n      - [\"entityGone\" (entity)](#entitygone-entity)\n      - [\"entityMoved\" (entity)](#entitymoved-entity)\n      - [\"entityDetach\" (entity, vehicle)](#entitydetach-entity-vehicle)\n      - [\"entityAttach\" (entity, vehicle)](#entityattach-entity-vehicle)\n      - [\"entityUpdate\" (entity)](#entityupdate-entity)\n      - [\"entityEffect\" (entity, effect)](#entityeffect-entity-effect)\n      - [\"entityEffectEnd\" (entity, effect)](#entityeffectend-entity-effect)\n      - [\"playerJoined\" (player)](#playerjoined-player)\n      - [\"playerUpdated\" (player)](#playerupdated-player)\n      - [\"playerLeft\" (player)](#playerleft-player)\n      - [\"blockUpdate\" (oldBlock, newBlock)](#blockupdate-oldblock-newblock)\n      - [\"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#blockupdatex-y-z-oldblock-newblock)\n      - [\"blockPlaced\" (oldBlock, newBlock)](#blockplaced-oldblock-newblock)\n      - [\"chunkColumnLoad\" (point)](#chunkcolumnload-point)\n      - [\"chunkColumnUnload\" (point)](#chunkcolumnunload-point)\n      - [\"soundEffectHeard\" (soundName, position, volume, pitch)](#soundeffectheard-soundname-position-volume-pitch)\n      - [\"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)](#hardcodedsoundeffectheard-soundid-soundcategory-position-volume-pitch)\n      - [\"noteHeard\" (block, instrument, pitch)](#noteheard-block-instrument-pitch)\n      - [\"pistonMove\" (block, isPulling, direction)](#pistonmove-block-ispulling-direction)\n      - [\"chestLidMove\" (block, isOpen, block2)](#chestlidmove-block-isopen-block2)\n      - [\"blockBreakProgressObserved\" (block, destroyStage, entity)](#blockbreakprogressobserved-block-destroystage-entity)\n      - [\"blockBreakProgressEnd\" (block, entity)](#blockbreakprogressend-block-entity)\n      - [\"diggingCompleted\" (block)](#diggingcompleted-block)\n      - [\"diggingAborted\" (block)](#diggingaborted-block)\n      - [\"usedFirework\" (fireworkEntityId)](#usedfirework-fireworkentityid)\n      - [\"move\"](#move)\n      - [\"forcedMove\"](#forcedmove)\n      - [\"mount\"](#mount)\n      - [\"dismount\" (vehicle)](#dismount-vehicle)\n      - [\"windowOpen\" (window)](#windowopen-window)\n      - [\"windowClose\" (window)](#windowclose-window)\n      - [\"sleep\"](#sleep)\n      - [\"wake\"](#wake)\n      - [\"experience\"](#experience)\n      - [\"scoreboardCreated\" (scoreboard)](#scoreboardcreated-scoreboard)\n      - [\"scoreboardDeleted\" (scoreboard)](#scoreboarddeleted-scoreboard)\n      - [\"scoreboardTitleChanged\" (scoreboard)](#scoreboardtitlechanged-scoreboard)\n      - [\"scoreUpdated\" (scoreboard, item)](#scoreupdated-scoreboard-item)\n      - [\"scoreRemoved\" (scoreboard, item)](#scoreremoved-scoreboard-item)\n      - [\"scoreboardPosition\" (position, scoreboard)](#scoreboardposition-position-scoreboard)\n      - [\"teamCreated\" (team)](#teamcreated-team)\n      - [\"teamRemoved\" (team)](#teamremoved-team)\n      - [\"teamUpdated\" (team)](#teamupdated-team)\n      - [\"teamMemberAdded\" (team)](#teammemberadded-team)\n      - [\"teamMemberRemoved\" (team)](#teammemberremoved-team)\n      - [\"bossBarCreated\" (bossBar)](#bossbarcreated-bossbar)\n      - [\"bossBarDeleted\" (bossBar)](#bossbardeleted-bossbar)\n      - [\"bossBarUpdated\" (bossBar)](#bossbarupdated-bossbar)\n      - [\"heldItemChanged\" (heldItem)](#helditemchanged-helditem)\n      - [\"physicsTick\" ()](#physicstick-)\n      - [\"chat:name\" (matches)](#chatname-matches)\n      - [\"particle\"](#particle)\n    - [Functions](#functions)\n      - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)\n      - [bot.waitForChunksToLoad()](#botwaitforchunkstoload)\n      - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)\n      - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)\n      - [bot.entityAtCursor(maxDistance=3.5)](#botentityatcursormaxdistance35)\n      - [bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)](#botblockatentitycursorentitybotentity-maxdistance256)\n      - [bot.canSeeBlock(block)](#botcanseeblockblock)\n      - [bot.findBlocks(options)](#botfindblocksoptions)\n      - [bot.findBlock(options)](#botfindblockoptions)\n      - [bot.canDigBlock(block)](#botcandigblockblock)\n      - [bot.recipesFor(itemType, metadata, minResultCount, craftingTable)](#botrecipesforitemtype-metadata-minresultcount-craftingtable)\n      - [bot.recipesAll(itemType, metadata, craftingTable)](#botrecipesallitemtype-metadata-craftingtable)\n      - [bot.nearestEntity(match = (entity) => { return true })](#botnearestentitymatch--entity---return-true-)\n    - [Methods](#methods)\n      - [bot.end(reason)](#botendreason)\n      - [bot.quit(reason)](#botquitreason)\n      - [bot.tabComplete(str, [assumeCommand], [sendBlockInSight], [timeout])](#bottabcompletestr-assumecommand-sendblockinsight-timeout)\n      - [bot.chat(message)](#botchatmessage)\n      - [bot.whisper(username, message)](#botwhisperusername-message)\n      - [bot.chatAddPattern(pattern, chatType, description)](#botchataddpatternpattern-chattype-description)\n      - [bot.addChatPattern(name, pattern, chatPatternOptions)](#botaddchatpatternname-pattern-chatpatternoptions)\n      - [bot.addChatPatternSet(name, patterns, chatPatternOptions)](#botaddchatpatternsetname-patterns-chatpatternoptions)\n      - [bot.removeChatPattern(name)](#botremovechatpatternname)\n      - [bot.awaitMessage(...args)](#botawaitmessageargs)\n      - [bot.setSettings(options)](#botsetsettingsoptions)\n      - [bot.loadPlugin(plugin)](#botloadpluginplugin)\n      - [bot.loadPlugins(plugins)](#botloadpluginsplugins)\n      - [bot.hasPlugin(plugin)](#bothaspluginplugin)\n      - [bot.sleep(bedBlock)](#botsleepbedblock)\n      - [bot.isABed(bedBlock)](#botisabedbedblock)\n      - [bot.wake()](#botwake)\n      - [bot.setControlState(control, state)](#botsetcontrolstatecontrol-state)\n      - [bot.getControlState(control)](#botgetcontrolstatecontrol)\n      - [bot.clearControlStates()](#botclearcontrolstates)\n      - [bot.getExplosionDamages(entity, position, radius, [rawDamages])](#botgetexplosiondamagesentity-position-radius-rawdamages)\n      - [bot.lookAt(point, [force])](#botlookatpoint-force)\n      - [bot.look(yaw, pitch, [force])](#botlookyaw-pitch-force)\n      - [bot.updateSign(block, text, back = false)](#botupdatesignblock-text-back--false)\n      - [bot.equip(item, destination)](#botequipitem-destination)\n      - [bot.unequip(destination)](#botunequipdestination)\n      - [bot.tossStack(item)](#bottossstackitem)\n      - [bot.toss(itemType, metadata, count)](#bottossitemtype-metadata-count)\n      - [bot.elytraFly()](#botelytrafly)\n      - [bot.dig(block, [forceLook = true], [digFace])](#botdigblock-forcelook--true-digface)\n      - [bot.stopDigging()](#botstopdigging)\n      - [bot.digTime(block)](#botdigtimeblock)\n      - [bot.acceptResourcePack()](#botacceptresourcepack)\n      - [bot.denyResourcePack()](#botdenyresourcepack)\n      - [bot.placeBlock(referenceBlock, faceVector)](#botplaceblockreferenceblock-facevector)\n      - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)\n      - [bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botactivateblockblock-direction-vec3-cursorpos-vec3)\n      - [bot.activateEntity(entity)](#botactivateentityentity)\n      - [bot.activateEntityAt(entity, position)](#botactivateentityatentity-position)\n      - [bot.consume()](#botconsume)\n      - [bot.fish()](#botfish)\n      - [bot.activateItem(offHand=false)](#botactivateitemoffhandfalse)\n      - [bot.deactivateItem()](#botdeactivateitem)\n      - [bot.useOn(targetEntity)](#botuseontargetentity)\n      - [bot.attack(entity, swing = true)](#botattackentity-swing--true)\n      - [bot.swingArm([hand], showHand)](#botswingarmhand-showhand)\n      - [bot.mount(entity)](#botmountentity)\n      - [bot.dismount()](#botdismount)\n      - [bot.moveVehicle(left,forward)](#botmovevehicleleftforward)\n      - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)\n      - [bot.craft(recipe, count, craftingTable)](#botcraftrecipe-count-craftingtable)\n      - [bot.writeBook(slot, pages)](#botwritebookslot-pages)\n      - [bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)](#botopencontainercontainerblock-or-containerentity-direction-cursorpos)\n      - [bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)](#botopenchestchestblock-or-minecartchestentity-direction-cursorpos)\n      - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)\n      - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)\n      - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)\n      - [bot.openAnvil(anvilBlock)](#botopenanvilanvilblock)\n      - [bot.openVillager(villagerEntity)](#botopenvillagervillagerentity)\n      - [bot.trade(villagerInstance, tradeIndex, [times])](#bottradevillagerinstance-tradeindex-times)\n      - [bot.setCommandBlock(pos, command, [options])](#botsetcommandblockpos-command-options)\n      - [bot.supportFeature(name)](#botsupportfeaturename)\n      - [bot.waitForTicks(ticks)](#botwaitforticksticks)\n      - [bot.respawn()](#botrespawn)\n    - [Lower level inventory methods](#lower-level-inventory-methods)\n      - [bot.clickWindow(slot, mouseButton, mode)](#botclickwindowslot-mousebutton-mode)\n      - [bot.putSelectedItemRange(start, end, window, slot)](#botputselecteditemrangestart-end-window-slot)\n      - [bot.putAway(slot)](#botputawayslot)\n      - [bot.closeWindow(window)](#botclosewindowwindow)\n      - [bot.transfer(options)](#bottransferoptions)\n      - [bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)](#botopenblockblock-direction-vec3-cursorpos-vec3)\n      - [bot.openEntity(entity)](#botopenentityentity)\n      - [bot.moveSlotItem(sourceSlot, destSlot)](#botmoveslotitemsourceslot-destslot)\n      - [bot.updateHeldItem()](#botupdatehelditem)\n      - [bot.getEquipmentDestSlot(destination)](#botgetequipmentdestslotdestination)\n    - [bot.creative](#botcreative)\n      - [bot.creative.setInventorySlot(slot, item)](#botcreativesetinventoryslotslot-item)\n      - [bot.creative.clearSlot(slot)](#botcreativeclearslotslot)\n      - [bot.creative.clearInventory()](#botcreativeclearinventory)\n      - [bot.creative.flyTo(destination)](#botcreativeflytodestination)\n      - [bot.creative.startFlying()](#botcreativestartflying)\n      - [bot.creative.stopFlying()](#botcreativestopflying)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API\n\n## Enums\n\nЭти данные хранятся независимо от проекта [minecraft-data](https://github.com/PrismarineJS/minecraft-data),\n и доступны через [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\n### minecraft-data\n\nДанные доступны в модуле [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\nИспользуйте `require('minecraft-data')(bot.version)`.\n\n### mcdata.blocks\n\nИдентификация блоков по ID.\n\n### mcdata.items\n\nИдентификация предметов по ID.\n\n### mcdata.materials\n\nНазвание материала и объект, который содержит информацию об инструментах и их эффективности разрушения..\n\n### mcdata.recipes\n\nИдентификация крафтов по ID.\n\n### mcdata.instruments\n\nИдентификация инструментов по ID.\n\n### mcdata.biomes\n\nИдентификация биомов по ID.\n\n### mcdata.entities\n\nИдентификация существ по ID.\n\n## Classes\n\n### vec3\n\nСмотрите [andrewrk/node-vec3](https://github.com/andrewrk/node-vec3).\n\nВсе координаты библиотеки Mineflayer используют данный класс.\n\n * `x` - Юг.\n * `y` - Вверх.\n * `z` - Запад.\n\nФункции и методы, требующие точного аргумента позиции, как правило, используют `Vec3`,\nа также массив с тремя значениями и объект с `x`, `y`, `z`.\n\n### mineflayer.Location\n\n### Entity\n\nЭнтити (существо) - это игроки, мобы и объекты. Вы также можете получить доступ\nк своему существу, используя `bot.entity`.\nСмотрите [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity).\n\n#### Player Skin Data\n\nДанные скина хранятся в свойстве `skinData` объекта игрока, если имеются.\n\n```js\n// player.skinData\n{\n  url: 'http://textures.minecraft.net/texture/...',\n  model: 'slim' // или 'classic'\n}\n```\n\n### Block\n\nСмотрите [prismarine-block](https://github.com/PrismarineJS/prismarine-block).\n\n`block.blockEntity` является дополнительным полем с данными блок-существ в виде `Object`.\n```js\n// sign.blockEntity\n{\n  x: -53,\n  y: 88,\n  z: 66,\n  id: 'minecraft:sign', // 'Sign' в 1.10\n  Text1: { toString: Function }, // ChatMessage object\n  Text2: { toString: Function }, // ChatMessage object\n  Text3: { toString: Function }, // ChatMessage object\n  Text4: { toString: Function } // ChatMessage object\n}\n```\n\n### Biome\n\nСмотрите [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome).\n\n### Item\n\nСмотрите [prismarine-item](https://github.com/PrismarineJS/prismarine-item).\n\n### windows.Window (base class)\n\nСмотрите [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows).\n\n#### window.deposit(itemType, metadata, count, nbt)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\n * `itemType` - Числовой ID предмета.\n * `metadata` - Числовое значение мета-данных. `null` означает любой вид.\n * `count` - Сколько предметов класть. `null` будет равно `1`.\n * `nbt` - Совпадение по нбт. `null` отключает это.\n\n#### window.withdraw(itemType, metadata, count, nbt)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении. Выдаёт ошибку, если нет места в инвентаре.\n\n * `itemType` - Числовой ID предмета.\n * `metadata` - Числовое значение мета-данных. `null` означает любой вид.\n * `count` - Сколько предметов брать. `null` будет равно `1`.\n * `nbt` - Совпадение по нбт. `null` отключает это.\n\n#### window.close()\n\nЗакрывает окно.\n\n### Recipe\n\nСмотрите [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe).\n\n### mineflayer.Container\n\nДополнение к `windows.Window` для сундуков, раздатчиков и прочих.\nСмотрите `bot.openContainer(chestBlock или minecartchestEntity)`.\n\n### mineflayer.Furnace\n\nДополнение к `windows.Window` для печки, плавильни и прочих.\nСмотрите `bot.openFurnace(furnaceBlock)`.\n\n#### furnace \"update\"\n\nСрабатывает при обновлении `furnace.fuel` и/или `furnace.progress`.\n\n#### furnace \"updateSlot\" (oldItem, newItem)\n\nСрабатывает, когда в печи обновляется слот для плавки.\n\n#### furnace.takeInput()\n\nЭта функция возвращает `Promise` с `item` в качестве аргумента при завершении.\n\n\n#### furnace.takeFuel()\n\nЭта функция возвращает `Promise` с `item` в качестве аргумента при завершении.\n\n\n#### furnace.takeOutput()\n\nЭта функция возвращает `Promise` с `item` в качестве аргумента при завершении.\n\n\n#### furnace.putInput(itemType, metadata, count)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\n#### furnace.putFuel(itemType, metadata, count)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\n#### furnace.inputItem()\n\nВозвращает предмет, который плавится, в виде `Item`.\n\n#### furnace.fuelItem()\n\nВозвращает топливо в виде `Item`.\n\n#### furnace.outputItem()\n\nВозвращает результат плавки в виде `Item`.\n\n#### furnace.fuel\n\nВозвращает количество оставшегося топлива от `0` до `1`.\n\n#### furnace.progress\n\nВозвращает прогресс плавки предмета от `0` до `1`.\n\n### mineflayer.EnchantmentTable\n\nДополнение к `windows.Window` для стола зачарований.\nСмотрите `bot.openEnchantmentTable(enchantmentTableBlock)`.\n\n#### enchantmentTable \"ready\"\n\nСрабатывает, когда `enchantmentTable.enchantments` полностью заполнен, и вы\nможете сделать выбор, вызвав `enchantmentTable.enchant(choice)`.\n\n#### enchantmentTable.targetItem()\n\nВозвращает текущий предмет в столе зачарования. Этот метод может использоваться, чтобы положить или забрать предмет.\n\n#### enchantmentTable.xpseed\n\n16-битный xpseed, отправленный сервером.\n\n#### enchantmentTable.enchantments\n\nВозвращает массив из трёх зачарований, доступных для выбора.\n`level` может быть `-1`, если сервер ещё не отправил данные.\n\nПример:\n\n```js\n[\n  {\n    level: 3\n  },\n  {\n    level: 4\n  },\n  {\n    level: 9\n  }\n]\n```\n\n#### enchantmentTable.enchant(choice)\n\nВозращает `Promise` с `item` в качестве аргумента после зачарования.\n\n * `choice` - [0-2], индекс зачарования, которое вы выбираете.\n\n#### enchantmentTable.takeTargetItem()\n\nВозращает `Promise` с `item` в качестве аргумента при завершении.\n\n\n#### enchantmentTable.putTargetItem(item)\n\nВозращает `Promise` с `void` в качестве аргумента при завершении.\n\n\n#### enchantmentTable.putLapis(item)\n\nВозращает `Promise` с `void` в качестве аргумента при завершении.\n\n\n### mineflayer.anvil\n\nДополнение к `windows.Window` для наковальни.\nСмотрите `bot.openAnvil(anvilBlock)`.\n\n#### anvil.combine(itemOne, itemTwo[, name])\n\nВозращает `Promise` с `void` в качестве аргумента при завершении.\n\n#### anvil.combine(item[, name])\n\nВозращает `Promise` с `void` в качестве аргумента при завершении.\n\n\n#### villager \"ready\"\n\nСрабатывает, когда `villager.trades` был загружен.\n\n#### villager.trades\n\nМассив с вариантами торговли.\n\nПример:\n\n```js\n[\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: true,\n    secondaryInput: Item,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  }\n]\n```\n\n#### villager.trade(tradeIndex, [times])\nПодобно [bot.trade(villagerInstance, tradeIndex, [times])](#bottradevillagerinstance-tradeindex-times)\n\n### mineflayer.ScoreBoard\n\n#### ScoreBoard.name\n\nИмя скорборда.\n\n#### ScoreBoard.title\n\nЗаголовок скорборда (может не совпадать с именем).\n\n#### ScoreBoard.itemsMap\n\nОбъект со всеми элементами скорборда.\n\nПример:\n\n```js\n{\n  wvffle: { name: 'wvffle', value: 3 },\n  dzikoysk: { name: 'dzikoysk', value: 6 }\n}\n```\n\n#### ScoreBoard.items\n\nМассив со всеми отсортированными элементами скорборда.\n\nПример:\n\n```js\n[\n  { name: 'dzikoysk', value: 6 },\n  { name: 'wvffle', value: 3 }\n]\n```\n\n### mineflayer.Team\n\n#### Team.name\n\nНазвание команды.\n\n#### Team.friendlyFire\n\nОпределяет, включен ли огонь по своим.\n\n#### Team.nameTagVisibility\n\nМожет быть `always`, `hideForOtherTeams`, `hideForOwnTeam`.\n\n#### Team.collisionRule\n\nМожет быть `always`, `pushOtherTeams`, `pushOwnTeam`.\n\n#### Team.color\n\nЦвет (или форматирование) названия команды, например `dark_green`, `red`, `underlined`.\n\n#### Team.prefix\n\nКомпонент чата, содержащий префикс команды.\n\n#### Team.suffix\n\nКомпонент чата, содержащий суффикс команды.\n\n#### Team.members\n\nМассив с участниками команды. Ники игроков и UUID существ.\n\n### mineflayer.BossBar\n\n#### BossBar.title\n\nНазвание боссбара, передается в `ChatMessage`.\n\n#### BossBar.health\n\nКоличество здоровья от `0` до `1`.\n\n#### BossBar.dividers\n\nКоличество ячеек, может быть `0`, `6`, `10`, `12`, `20`.\n\n#### BossBar.entityUUID\n\nUUID существа, который определяется боссом.\n\n#### BossBar.shouldDarkenSky\n\nОпределяет, стоит ли затемнять небо.\n\n#### BossBar.isDragonBar\n\nОпределяет, является ли боссбар - боссбаром Дракона Края.\n\n#### BossBar.createFog\n\nОпределяет, стоит ли создават туман.\n\n#### BossBar.color\n\nОпределяет цвет боссбара. Может быть `pink`, `blue`, `red`, `green`, `yellow`, `purple`, `white`.\n\n### mineflayer.Particle\n\n#### Particle.id\n\nИдентификатор частицы, который прописан в [протоколе](https://minecraft.wiki/w/Protocol#Particle).\n\n#### Particle.name\n\nНазвание частицы, которое прописано в [протоколе](https://minecraft.wiki/w/Protocol#Particle).\n\n#### Particle.position\n\nРасположение частицы в Vec3.\n\n#### Particle.offset\n\nСмещение частицы в Vec3.\n\n#### Particle.longDistanceRender\n\nОпределяет, следует ли принудительно отображать частицу, несмотря на настройки частиц клиента, и увеличивает максимальную дальность прорисовки с 256 до 65536.\n\n#### Particle.count\n\nКоличество созданных частиц.\n\n#### Particle.movementSpeed\n\nСкорость частиц в случайном направлении.\n\n## Bot\n\n### mineflayer.createBot(options)\n\nСоздаёт и возвращает экземпляр класса бота.\n`options` - это объект, который содержит в себе :\n * `username` : Ник игрока, по умолчанию `\"Player\"`.\n * `port` : Порт сервера, по умолчанию `25565`.\n * `password` : Пароль может быть пропущен, если подключение осуществляется к пиратскому серверу.\n * `host` : Айпи сервера, по умолчанию `\"localhost\"`.\n * `version` : По умолчанию версия сервера определяется автоматически. Пример использования : `\"1.12.2\"`.\n * `auth` : Вид аутентификации, по умолчанию `\"mojang\"`, может быть `\"microsoft\"`.\n * `clientToken` : Генерируется, если задан пароль.\n * `accessToken` : Генерируется, если задан пароль.\n * `logErrors` : По умолчанию включено, используется для отлова и логирования ошибок.\n * `hideErrors` : По умолчанию включено, не логирует ошибки (даже если включен `logErrors`).\n * `keepAlive` : Отправка пакета активности, по умолчанию включено.\n * `checkTimeoutInterval` : По умолчанию `30*1000` (30 сек.), проверяет, получен ли пакет активности, иначе отключается.\n * `loadInternalPlugins` : Загрузка плагинов, по умолчанию включено.\n * `storageBuilder` : Необязательная функция, принимающая в качестве аргумента версию и название мира (`worldName`) и возвращающая экземпляр чего-либо с тем же API, что и `prismarine-provider-anvil`. Будет использовано для сохранения мира.\n * `client` : Экземпляр `node-minecraft-protocol`, если не указан, mineflayer создает свой собственный клиент. Это может быть нужно для использования mineflayer через прокси многих клиентов или ванильного клиента и mineflayer клиента.\n * `brand` : Название версии, которое будет использовать клиент. По умолчанию `vanilla`. Может использоваться для имитации пользовательских клиентов для серверов, которым это требуется.\n * `respawn` : Отвечает за автоматическое возрождение бота, по умолчанию включено.\n * `plugins` : Объект : По умолчанию `{}`\n   - `pluginName` : `false` : Не загружать плагин с заданным именем `pluginName`.\n   - `pluginName` : `true` : Загрузить плагин с заданным именем `pluginName`, даже если `loadInternalplugins` отключен.\n   - `pluginName` : Функция ввода внешнего плагина : загружает сторонний плагин, переопределяет внутренний плагин с заданным именем `pluginName`.\n * `physicsEnabled` : По умолчанию включено. Должна ли физика влиять на бота? Можно изменить с помощью `bot.physicsEnabled`.\n * [chat](#bot.settings.chat)\n * [colorsEnabled](#bot.settings.colorsEnabled)\n * [viewDistance](#bot.settings.viewDistance)\n * [difficulty](#bot.settings.difficulty)\n * [skinParts](#bot.settings.skinParts)\n * [enableTextFiltering](#bot.settings.enableTextFiltering)\n * [enableServerListing](#bot.settings.enableServerListing)\n * `chatLengthLimit` : Максимальное количество символов, отправляемое в чат. Если не установлено, будет установлено следующее: 100 в < 1.11 и 256 в >= 1.11.\n * `defaultChatPatterns`: По умолчанию включено, добавляет шаблоны, такие как общий чат и личные сообщения.\n\n### Properties\n\n#### bot.registry\n\nЭкземпляр `minecraft-data` используемый ботом. Передайте это конструкторам, которые ожидают `minecraft-data`, таким как `prismarine-block`.\n\n#### bot.world\n\nСинхронное представление мира. Смотрите [prismarine-world](http://github.com/PrismarineJS/prismarine-world).\n\n##### world \"blockUpdate\" (oldBlock, newBlock)\n\nСрабатывает при обновлении блока. `oldBlock` и `newBlock` предоставляются для сравнения.\n`oldBlock` может быть `null` при обычном обновлении блока.\n\n##### world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\nСрабатывает в определенной точке. `oldBlock` и `newBlock` предоставляются для сравнения. Все слушатели получают `null` для `oldBlock` и `newBlock` и автоматически удаляются при выгрузке мира.\n`oldBlock` может быть `null` при обычном обновлении блока.\n\n#### bot.entity\n\nВаше собственное существо. Смотрите `Entity`.\n\n#### bot.entities\n\nВсе близлежащие существа. Этот объект представляет собой сопоставление `entityId` с `entity`.\n\n#### bot.username\n\nИспользуйте это, чтобы узнать имя бота.\n\n#### bot.spawnPoint\n\nПоказывает координаты спавна бота, на которые указывает компас.\n\n#### bot.heldItem\n\nПредмет, который держит бот. Представляет экземпляр [prismarine-item](https://github.com/PrismarineJS/prismarine-item), основанный на мета-данных, нбт-данных и т.д.\n\n#### bot.usingHeldItem\n\nИспользует ли бот предмет, который он держит в руках, например, ест пищу или использует щит.\n\n#### bot.game.levelType\n\nТип генерации.\n\n#### bot.game.dimension\n\nТекущее измерение бота, может быть `overworld`, `the_end` или `the_nether`.\n\n#### bot.game.difficulty\n\nСложность на сервере.\n\n#### bot.game.gameMode\n\nИгровой режим.\n\n#### bot.game.hardcore\n\nВключен ли режим хардкода.\n\n#### bot.game.maxPlayers\n\n#### bot.game.serverBrand\n\nЯдро сервера.\n\n#### bot.game.minY\n\nМинимальная высота Y в мире.\n\n#### bot.game.height\n\nМаксимальная высота мира.\n\n#### bot.physicsEnabled\n\nВключает физику бота, по умолчанию `true`.\n\n### bot.player\n\nОбъект игрока.\n\nПример:\n```js\n{\n  username: 'player',\n  displayName: { toString: Function }, // Объект ChatMessage.\n  gamemode: 0,\n  ping: 28,\n  entity: entity // null, если Вы находитесь слишком далеко\n}\n```\n\nПинг игрока изначально равен `0`, нужно подождать, пока сервер отправит его пинг.\n\n#### bot.players\n\nПоказывает всех игроков, которые находятся на сервере.\n\n#### bot.tablist\n\nОбъект таблиста бота, содержит `header` и `footer`.\n\nПример:\n```js\n{\n  header: { toString: Function }, // Объект ChatMessage.\n  footer: { toString: Function } // Объект ChatMessage.\n}\n```\n\n#### bot.isRaining\n\nОпределяет, идёт ли дождь.\n\n#### bot.rainState\n\nЧисло, указывающее текущий уровень дождя. Когда дождя нет, значение будет равно 0. Когда начнется дождь, значение будет постепенно увеличиваться до 1. Когда дождь прекращается, значение постепенно возвращается к 0.\n\nКаждый раз, когда изменяется `bot.rainState`, срабатывает событие `\"weatherUpdate\"`.\n\n#### bot.thunderState\n\nЧисло, указывающее текущий уровень грозы. Когда грозы нет, значение будет равно 0. Когда начнется гроза, значение будет постепенно увеличиваться до 1. Когда гроза прекращается, значение постепенно возвращается к 0.\n\nКаждый раз, когда изменяется `bot.thunderState`, срабатывает событие `\"weatherUpdate\"`.\n\nЭто то же самое, что и `bot.rainState`, но для грозы.\nВо время грозы изменяются значения `bot.rainState` и `bot.thunderState`.\n\n#### bot.chatPatterns\n\nМассив шаблонов следующего формата: [/regex/, \"chattype\", \"description\"]\n\n * `/regex/` - Шаблон регулярного выражения, который должен иметь как минимум две группы.\n * `'chattype'` - Тип чата, который может является \"chat\" или \"whisper\".\n * `'description'` - Описание шаблона, необязательно.\n\n#### bot.settings.chat\n\nВыбор:\n\n * `enabled` - Включен (по умолчанию).\n * `commandsOnly` - Только команды.\n * `disabled` - Выключен.\n\n#### bot.settings.colorsEnabled\n\nПо умолчанию активно, используется для отображения цветов в чате.\n\n#### bot.settings.viewDistance\n\nВыбор прорисовки:\n * `far` - Дальняя (по умолчанию).\n * `normal` - Нормальная.\n * `short` - Малая.\n * `tiny` - Минимальная.\n\n#### bot.settings.difficulty\n\nСложность. Вернет то же, что и в `server.properties`.\n\n#### bot.settings.skinParts\n\nДолжны ли отображаться дополнительные детали скинов игроков.\n\n#### bot.settings.skinParts.showCape - boolean\n\nОтображение плаща.\n\n##### bot.settings.skinParts.showJacket - boolean\n\nОтображение куртки.\n\n##### bot.settings.skinParts.showLeftSleeve - boolean\n\nОтображение левого рукава.\n\n##### bot.settings.skinParts.showRightSleeve - boolean\n\nОтображение правого рукава.\n\n##### bot.settings.skinParts.showLeftPants - boolean\n\nОтображение левой штанины.\n\n##### bot.settings.skinParts.showRightPants - boolean\n\nОтображение правой штанины.\n\n##### bot.settings.skinParts.showHat - boolean\n\nОтображение головного убора.\n\n#### bot.settings.enableTextFiltering - boolean\n\nНе используется. По умолчанию выключен в ванильном клиенте.\n\n#### bot.settings.enableServerListing - boolean\n\nЭтот параметр отправляется на сервер, чтобы определить, должен ли игрок отображаться в списке серверов.\n\n#### bot.experience.level\n\nУровень опыта.\n\n#### bot.experience.points\n\nОбщее количество очков опыта.\n\n#### bot.experience.progress\n\nЗначение от `0` до `1` - число для перехода на следующий уровень.\n\n#### bot.health\n\nЧисло от `0` до `20`. Каждое число является половиной ячейки здоровья в игре.\n\n#### bot.food\n\nЧисло от `0` до `20`. Каждое число является половиной ячейки голода в игре.\n\n#### bot.foodSaturation\n\nПоказывает насыщенность. Голод не уменьшается, если насыщенность больше нуля. Игроки, зашедшие на сервер, автоматически получают насыщенность `5,0`. Еда увеличивает как насыщенность, так и голод.\n\n#### bot.oxygenLevel\n\nЧисло от `0` до `20`. Каждое число отображает количество значков воды, известных как уровень кислорода.\n\n#### bot.physics\n\nИзменение значений скорости, отдачи, скорости прыжка и т.д.\nИзменяйте на свой страх и риск!\n\n#### bot.fireworkRocketDuration\n\nСколько физических тиков осталось до окончания ускорения от фейерверка.\n\n#### bot.simpleClick.leftMouse (slot)\n\nТо же, что и `bot.clickWindow(slot, 0, 0)`.\n\n#### bot.simpleClick.rightMouse (slot)\n\nТо же, что и `bot.clickWindow(slot, 1, 0)`.\n\n#### bot.time.doDaylightCycle\n\nОтображает включено ли игровое правило `doDaylightCycle`.\n\n#### bot.time.bigTime\n\nКоличество тиков с нулевого дня в мире.\n\nЭто значение имеет тип `BigInt` и является точным даже при очень больших значениях (более 2^51 - 1 тиков).\n\n#### bot.time.time\n\nКоличество тиков с нулевого дня в мире.\n\nПоскольку ограничение `Number` в Javascript составляет 2^51 - 1, значение `bot.time.time` становится неточным при превышении этого ограничения, рекомендуется использовать `bot.time.bigTime`.\nВероятно вам никогда не понадобится `bot.time.bigTime`, так как 2^51 - 1 тиков это примерно 14280821 настоящих лет.\n\n#### bot.time.timeOfDay\n\nВремя суток в тиках.\n\nВремя основано на тиках, где каждую секунду происходит 20 тиков. 24000 тиков - 1 игровой день, или же 20 реальных минут.\n\nВремя суток основано на тиках. `0` - восход, `6000` - полдень, `12000` - закат, а `18000` - полночь.\n\n#### bot.time.day\n\nОтображает, какой день в мире.\n\n#### bot.time.isDay\n\nОпределяет, сейчас день (`true`) или ночь (`false`).\n\nОсновано на времени между `0` и `13000` тиками (день + закат).\n\n#### bot.time.moonPhase\n\nФаза луны.\n\nЗначение от `0` до `7`, где `0` - полнолуние.\n\n#### bot.time.bigAge\n\nВозраст мира в тиках.\n\nЭто значение имеет тип `BigInt` и является точным даже при очень больших значениях. (более 2^51 - 1 тиков)\n\n#### bot.time.age\n\nВозраст мира в тиках.\n\nПоскольку ограничение `Number` в Javascript составляет 2^51 - 1, значение `bot.time.age` становится неточным при превышении этого ограничения, рекомендуется использовать `bot.time.bigAge`.\nВероятно вам никогда не понадобится `bot.time.bigAge`, так как 2^51 - 1 тиков это примерно 14280821 настоящих лет.\n\n#### bot.quickBarSlot\n\nПоказывает, какой слот сейчас выбран (0-8).\n\n#### bot.inventory\n\nЭкземпляр [`Window`](https://github.com/PrismarineJS/prismarine-windows#windowswindow-base-class), который представляет ваш инвентарь.\n\n#### bot.targetDigBlock\n\nПоказывает блок, который вы сейчас копаете, или же `null`.\n\n#### bot.isSleeping\n\nВозвращает `true` или `false`, в зависимости от того,\nлежите вы в кровати или нет.\n\n#### bot.scoreboards\n\nПоказывает все скорборды в виде объекта: `name -> scoreboard`.\n\n#### bot.scoreboard\n\nПоказывает все скорборды в виде объекта: `scoreboard displaySlot -> scoreboard`.\n\n * `belowName` - Cкорборд размещен снизу никнейма.\n * `sidebar` - Cкорборд размещен на боковой панели.\n * `list` - Cкорборд помещен в список игроков.\n * `0-18` - Cлоты, определённые в [протоколе](https://minecraft.wiki/w/Protocol#Display_Scoreboard).\n\n#### bot.teams\n\nВсе команды (Подобно `/team list`).\n\n#### bot.teamMap\n\nСписок участников команды. Использует никнеймы для игроков и UUID для существ.\n\n#### bot.controlState\n\nОбъект, состоящий из основных элементов управления: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'].\n\nУстановка значения для этого объекта вызовет [bot.setControlState](#botsetcontrolstatecontrol-state).\n\n### Events\n\n#### \"chat\" (username, message, translate, jsonMsg, matches)\n\nПри получении сообщения в чате от игрока.\n\n * `username` - Имя отправителя (сравните с `bot.username`, если вы не хотите видеть собственные сообщения).\n * `message` - Сообщение, очищенное от всех цветовых кодов.\n * `translate` - Тип сообщения. В большинстве случаев является `null`.\n * `jsonMsg` - Сообщение в формате JSON.\n * `matches` - Массив совпадений в регулярных выражениях. Может являться `null`.\n\n#### \"whisper\" (username, message, translate, jsonMsg, matches)\n\nПри получении сообщения в личных сообщениях от игрока.\n\n * `username` - И отправителя.\n * `message` - Сообщение, очищенное от всех цветовых кодов.\n * `translate` - Тип сообщения. В большинстве является `null`.\n * `jsonMsg` - Сообщение в формате JSON.\n * `matches` - Массив совпадений в регулярных выражениях. Может являться `null`.\n\n#### \"actionBar\" (jsonMsg, verified)\n\nПри появлении сообщения от сервера над хотбаром.\n\n * `jsonMsg` - Сообщение в формате JSON.\n * `verified` - Если не подтверждено - `null`, если подтверждено и правильно - `true`, если подтверждено, но не правильно - `false`.\n\n#### \"message\" (jsonMsg, position, sender, verified)\n\nПри появлении любого серверного сообщения, включая чаты.\n\n * `jsonMsg` - Объект [ChatMessage](https://github.com/PrismarineJS/prismarine-chat) содержащий форматированное сообщение. Дополнительно может обладать следующими свойствами:\n   * unsigned - Неподтверждённый объект `ChatMessage`. Только для версий 1.19.2+, когда сервер разрешает \"небезопасный\" чат или сервер изменяет сообщения без подписи игрока.\n * `position` - (> = 1.8.1): Положение сообщения в чате может быть\n   * `chat`\n   * `system`\n   * `game_info`\n * `sender` - UUID отправителя, если известно (1.16+), иначе `null`.\n * `verified` - Если не подтверждено - `null`, если подтверждено и правильно - `true`, если подтверждено, но не правильно - `false`.\n\n#### \"messagestr\" (message, messagePosition, jsonMsg, sender, verified)\n\nТо же самое, что и `\"message\"`, но вызывает `.toString()` в объекте `prismarine-message`, чтобы сразу получить сообщение.\n\n * `sender` - UUID отправителя, если известно (1.16+), иначе `null`.\n * `verified` - Если не подтверждено - `null`, если подтверждено и правильно - `true`, если подтверждено, но не правильно - `false`.\n\n#### \"inject_allowed\"\n\nСрабатывает, когда главный файл загружен, здесь вы можете загрузить `mcData` и плагины, но лучше подождать событие `\"spawn\"`.\n\n#### \"login\"\n\nСрабатывает при успешном подключении к серверу.\nВозможно, вам потребуется дождаться события `\"spawn\"`, прежде чем что-либо делать на сервере.\n\n#### \"spawn\"\n\nСрабатывает один раз после того, как вы вошли на сервер и появились в мире, а также срабатывает при респавне после смерти.\n\nВ большинстве случаев это событие, которое вы хотите прослушать, прежде чем что-либо делать на сервере.\n\n\n#### \"respawn\"\n\nСрабатывает при смене миров и после появления в мире.\nВ большинстве случаев вам нужно сначала дождаться события `\"spawn\"` вместо этого.\n\n#### \"game\"\n\nСрабатывает, если сервер меняет свойства в `server.properties`.\n\n#### \"resourcePack\" (url, hash)\n\nСрабатывает, когда сервер отправляет ресурспак.\n\n#### \"title\" (title, type)\n\nСрабатывает, когда сервер отправляет текст по центру экрана.\n\n * `title` - Текст на экране.\n * `type` - Тип текста \"subtitle\" или \"title\"\n\n#### \"title_times\" (fadeIn, stay, fadeOut)\n\nСрабатывает, когда сервер отправляет пакет с временем для текста по центру экрана (например, когда устанавливается или обновляется время для появления, отображения и исчезновения надписи).\n\n * `fadeIn` - время появления в тиках (число)\n * `stay` - время отображения в тиках (число)\n * `fadeOut` - время исчезновения в тиках (число)\n\nПример:\n\n```js\nbot.on('title_times', (fadeIn, stay, fadeOut) => {\n  console.log(`Время для надписей: fadeIn=${fadeIn}, stay=${stay}, fadeOut=${fadeOut}`)\n})\n```\n\n#### \"title_clear\"\n\nСрабатывает, когда сервер очищает все надписи по центру экрана.\n\n#### \"rain\"\n\nСрабатывает, когда начинается или прекращается дождь. Если вы присоединитесь к\nсерверу, на котором уже идет дождь, это событие также сработает.\n\n#### \"weatherUpdate\"\n\nСрабатывает, когда `bot.thunderState` или `bot.rainState` изменяются.\nЕсли вы присоединитесь к серверу, на котором уже идет дождь, это событие также сработает.\n\n#### \"time\"\n\nСрабатывает, когда сервер отправляет время. Смотрите `bot.time`.\n\n#### \"kicked\" (reason, loggedIn)\n\nСрабатывает при кике с сервера.\n\n * `reason` - Причина отключения.\n * `loggedIn` - `true`, если вы были кикнуты после успешного входа на сервер, или `false`, если отключение произошло во время подключения.\n\n#### \"end\" (reason)\n\nСрабатывает, когда вы отключены от сервера.\n\n * `reason` - причина отключения. (обычно `'socketClosed'`)\n\n#### \"error\" (err)\n\nСрабатывает, когда происходит какая-либо ошибка.\n\n#### \"spawnReset\"\n\nСрабатывает, когда вы не можете заспавниться у своей кровати, и ваша точка появления сбрасывается.\n\n#### \"death\"\n\nСрабатывает, когда вы умираете.\n\n#### \"health\"\n\nСрабатывает, когда значения здоровья или голода изменяются.\n\n#### \"breath\"\n\nСрабатывает, когда значение запаса воздуха изменяется.\n\n#### \"entityAttributes\" (entity)\n\nСрабатывает при изменении атрибутов (свойств) существа.\n\n\n#### \"entitySwingArm\" (entity)\n#### \"entityHurt\" (entity)\n#### \"entityDead\" (entity)\n#### \"entityTaming\" (entity)\n#### \"entityTamed\" (entity)\n#### \"entityShakingOffWater\" (entity)\n#### \"entityEatingGrass\" (entity)\n#### \"entityHandSwap\" (entity)\n#### \"entityWake\" (entity)\n#### \"entityEat\" (entity)\n#### \"entityCriticalEffect\" (entity)\n#### \"entityMagicCriticalEffect\" (entity)\n#### \"entityCrouch\" (entity)\n#### \"entityUncrouch\" (entity)\n#### \"entityEquip\" (entity)\n#### \"entitySleep\" (entity)\n#### \"entitySpawn\" (entity)\n#### \"entityElytraFlew\" (entity)\n\nЕсли существо начало летать на элитрах.\n\n#### \"itemDrop\" (entity)\n#### \"playerCollect\" (collector, collected)\n\nЕсли существо подняло предмет.\n\n * `collector` - Существо, поднявшее предмет.\n * `collected` - Существо, которое являлось поднятым предметом.\n\n#### \"entityGone\" (entity)\n#### \"entityMoved\" (entity)\n#### \"entityDetach\" (entity, vehicle)\n#### \"entityAttach\" (entity, vehicle)\n\nЕсли существо сидит в транспортном средстве, таком как лодка или вагонетка.\n\n * `entity` - Существо, которое сидит в транспортном средстве.\n * `vehicle` - Существо, которое является транспортным средством.\n\n#### \"entityUpdate\" (entity)\n#### \"entityEffect\" (entity, effect)\n#### \"entityEffectEnd\" (entity, effect)\n#### \"playerJoined\" (player)\n#### \"playerUpdated\" (player)\n#### \"playerLeft\" (player)\n\n#### \"blockUpdate\" (oldBlock, newBlock)\n\n(Лучше использовать это событие от `bot.world`, чем напрямую от бота)\nСрабатывает при обновлении блока. `oldBlock` и `newBlock` можно сравнить.\n\nСтоит заметить, что `oldBlock` может быть `null`.\n\n#### \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\n(Лучше использовать это событие от `bot.world`, чем напрямую от бота)\nСрабатывает при обновлении блока в определенном месте. `oldBlock` и `newBlock` можно сравнить.\n\nСтоит заметить, что `oldBlock` может быть `null`.\n\n#### \"blockPlaced\" (oldBlock, newBlock)\n\nСрабатывает при установке блока. `oldBlock` и `newBlock` можно сравнить.\n\nСтоит заметить, что `oldBlock` может быть `null`.\n\n#### \"chunkColumnLoad\" (point)\n#### \"chunkColumnUnload\" (point)\n\nСрабатывает при обновлении чанка. `point` является координатами угла чанка с наименьшими значениями `x`, `y`, и `z`.\n\n#### \"soundEffectHeard\" (soundName, position, volume, pitch)\n\nСрабатывает, когда вы слышите звуковой эффект.\n\n * `soundName` - Имя звукового эффекта.\n * `position` - Координаты в виде `Vec3`, где был проигран звук.\n * `volume` - Уровень звука в виде `float`, `1.0` является 100%.\n * `pitch` - Искажение звука в виде `integer`, `63` является 100%.\n\n#### \"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)\n\nСрабатывает, когда вы слышите нестандартный звуковой эффект.\n\n * `soundId` - ID звукового эффекта.\n * `soundCategory` - Категория звукового эффекта.\n * `position` - Координаты в виде `Vec3`, где был проигран звук.\n * `volume` - Уровень звука в виде `float`, `1.0` является 100%.\n * `pitch` - Искажение звука в виде `integer`, `63` является 100%.\n\n#### \"noteHeard\" (block, instrument, pitch)\n\nСрабатывает, когда был проигран звук нотного блока.\n\n * `block` - Блок, который проиграл звук.\n * `instrument`: Объект\n   - `id` : ID в виде `integer`.\n   - `name` : Один из видов звука.\n * `pitch` - Высота ноты (от 0 до 24 включительно, где 0 - это самая низкая, а 24 - самая высокая). Больше информации об этом можно найти на [оффициальной Minecraft википедии](http://minecraft.wiki/w/Note_Block).\n\n#### \"pistonMove\" (block, isPulling, direction)\n\n#### \"chestLidMove\" (block, isOpen, block2)\n* `block` - Блок, который был открыт. Если это двойной сундук - то отмечается правый блок.\n* `isOpen` - Число игроков, открывших сундук. 0, если он закрыт.\n* `block2`: Второй блок, который является частью двойного сундук. `null`, если это не двойной сундук.\n\n#### \"blockBreakProgressObserved\" (block, destroyStage, entity)\n\nСрабатывает, когда вы наблюдаете процесс разрушения блока\n\n * `block` - Блок, который ломают.\n * `destroyStage` - Уровень прогресса (0-9).\n * `entity` - Существо, которое ломает блок.\n\n#### \"blockBreakProgressEnd\" (block, entity)\n\nСрабатывает, когда процесс разрушения блока прекращен.\nПроисходит при прекращении разрушения блока или после его полного разрушения.\n\n * `block` - Блок, который перестали ломать.\n * `entity` - Существо, которое перестало ломать блок.\n\n#### \"diggingCompleted\" (block)\n\n * `block` - Блок, который был разрушен.\n\n#### \"diggingAborted\" (block)\n\n * `block` - Блок, который не был разрушен.\n\n#### \"usedFirework\" (fireworkEntityId)\n\nСрабатывает при использовании фейерверка во время полёта на элитрах.\n\n * `fireworkEntityId` - айди существа фейерверка.\n\n#### \"move\"\n\nСрабатывает при движении бота. Если вы хотите узнать текущее положение, используйте `bot.entity.position`, если вы хотите узнать предыдущее положение, используйте `bot.entity.position.minus(bot.entity.velocity)`.\n\n#### \"forcedMove\"\n\nСрабатывает при принудительном перемещении бота сервером (телепорт, спавн и т.д.). Если вы хотите узнать текущее положение, используйте `bot.entity.position`.\n\n#### \"mount\"\n\nСрабатывает, если вы поставили существо, например вагонетку. Чтобы получить доступ к ней,\nиспользуйте `bot.vehicle`.\n\nЧтобы сесть в неё, используйте `mount`.\n\n#### \"dismount\" (vehicle)\n\nСрабатывает, если вы слезли с существа.\n\n#### \"windowOpen\" (window)\n\nСрабатывает, если вы открываете верстак, сундук и т.д.\n\n#### \"windowClose\" (window)\n\nСрабатывает, если вы закрыли верстак, сундук и т.д.\n\n#### \"sleep\"\n\nСрабатывает, если вы легли спать.\n\n#### \"wake\"\n\nСрабатывает, если вы проснулись.\n\n#### \"experience\"\n\nСрабатывает, если значение `bot.experience.*` было обновлено.\n\n#### \"scoreboardCreated\" (scoreboard)\n\nСрабатывает, если скорборд был создан.\n\n#### \"scoreboardDeleted\" (scoreboard)\n\nСрабатывает, если скорборд был удален.\n\n#### \"scoreboardTitleChanged\" (scoreboard)\n\nСрабатывает, если название скорборда было обновлено.\n\n#### \"scoreUpdated\" (scoreboard, item)\n\nСрабатывает, если значение в скорборде было обновлено.\n\n#### \"scoreRemoved\" (scoreboard, item)\n\nСрабатывает, если значение в скорборде было удалено.\n\n#### \"scoreboardPosition\" (position, scoreboard)\n\nСрабатывает, если позиция скорборда была обновлена.\n\n#### \"teamCreated\" (team)\n\nСрабатывает, если команда была создана.\n\n#### \"teamRemoved\" (team)\n\nСрабатывает, если команда была удалена.\n\n#### \"teamUpdated\" (team)\n\nСрабатывает, если команда была обновлена.\n\n#### \"teamMemberAdded\" (team)\n\nСрабатывает, если участник(и) были добавлены в команду.\n\n#### \"teamMemberRemoved\" (team)\n\nСрабатывает, если участник(и) были удалены из команды.\n\n#### \"bossBarCreated\" (bossBar)\n\nСрабатывает, если боссбар был создан.\n\n#### \"bossBarDeleted\" (bossBar)\n\nСрабатывает, если боссбар был удален.\n\n#### \"bossBarUpdated\" (bossBar)\n\nСрабатывает, если боссбар был обновлен.\n\n#### \"heldItemChanged\" (heldItem)\n\nСрабатывает, если предмет в руке был изменён.\n\n#### \"physicsTick\" ()\n\nСрабатывает каждый тик, если `bot.physicsEnabled` включен.\n\n#### \"chat:name\" (matches)\n\nСрабатывает, если все регулярные выражения шаблона чата совпадают.\n\n#### \"particle\"\n\nСрабатывает, если появилась частица.\n\n### Functions\n\n#### bot.blockAt(point, extraInfos=true)\n\nВозвращает блок в `point` или `null`, если эта точка не загружена. Если значение `extraInfos` равно `true`, возращает информацию о табличках, картинах, сундуках, шалкерах и т.д. (медленнее).\nСмотрите `Block`.\n\n#### bot.waitForChunksToLoad()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда все чанки были загружены.\n\n#### bot.blockInSight(maxSteps, vectorLength)\n\nНеподдерживается, используйте `blockAtCursor`.\n\nВозвращает блок, на который смотрит бот, либо `null`.\n\n * `maxSteps` - Количество блоков, по умолчанию 256.\n * `vectorLength` - Длина вектора, по умолчанию `5/16`.\n\n#### bot.blockAtCursor(maxDistance=256)\n\nВозвращает блок, на который смотрит бот, либо `null`.\n * `maxDistance` - Максимальное расстояние от глаз до блока, по умолчанию 256.\n\n#### bot.entityAtCursor(maxDistance=3.5)\n\nВозвращает существо, на которое смотрит бот, либо `null`.\n * `maxDistance` - Максимальное расстояние от глаз до существа, по умолчанию 3,5.\n\n#### bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)\n\nВозвращает блок, на который смотрит существо, либо `null`.\n * `entity` - Существо в виде `Object`.\n * `maxDistance` - Максимальное расстояние от глаз до блока, по умолчанию 256.\n\n#### bot.canSeeBlock(block)\n\nВозвращает `true` или `false`, в зависимости от того,\nвидит ли бот указанный блок, или нет.\n\n#### bot.findBlocks(options)\n\nНаходит ближайшие блоки от заданной точки.\n\n * `options` - Параметры для поиска:\n   - `point` - Начальная позиция поиска (центр). По умолчанию позиция бота.\n   - `matching` - Функция, которая возращает `true`, если данный блок совпадает. Также поддерживает значение в виде ID блока или массива с ID нескольких блоков.\n   - `useExtraInfo` - Для сохранения обратной совместимости может привести к двум вариантам поведения в зависимости от типа\n      - **boolean** - Предсталяет функции `matching` больше информации - медленнее.\n      - **function** - Создаёт двойную функцию проверки, если блок проходит через функцию `matching`, то далее проходит через `useExtraInfo` с дополнительной информацией.\n   - `maxDistance` - Самое дальнее расстояние для поиска, по умолчанию 16.\n   - `count` - Количество блоков, которые нужно найти. По умолчанию 1. Может вернуть меньше, если будет найдено недостаточно блоков.\n\nВозвращает массив (может быть пустым) с координатами найденных блоков (не сами блоки). Массив отсортирован (от ближайших до дальних блоков).\n\n#### bot.findBlock(options)\n\nТо же самое, что и `bot.blockAt(bot.findBlocks(options)[0])`. Возращает один блок, либо `null`.\n\n#### bot.canDigBlock(block)\n\nВозвращает, можно ли сломать блок и находится ли в пределах диапозона бота.\n\n#### bot.recipesFor(itemType, metadata, minResultCount, craftingTable)\n\nВозвращает список рецептов(`Recipe`), которые вы можете использовать для крафта \nпредмета(`itemType`) с мета-данными(`metadata`).\n\n * `itemType` - Числовой ID предмета, который вы хотите создать.\n * `metadata` - Числовое значение мета-данных создаваемого предмета, `null` соответствует любым мета-данным\n * `minResultCount` - Количество создаваемых предметов, на основе ресурсов из вашего инвентаря, `null` эквивалентно 1 предмету.\n * `craftingTable` - Верстак (или подобный блок) в виде экземпляра `Block`. Если `null`, то будут работать только те рецепты, которые можно выполнить в окне инвентаря.\n\n#### bot.recipesAll(itemType, metadata, craftingTable)\n\nТо же, что и `bot.recipesFor`, но без проверки количества материала, требуемого для изготовления предмета.\n\n#### bot.nearestEntity(match = (entity) => { return true })\n\nВозвращает ближайшее к боту существо, подходящий по функции (по умолчанию находит любое существо). Возвращает `null`, если существо не найдено.\n\nПример:\n```js\nconst cow = bot.nearestEntity(entity => entity.name.toLowerCase() === 'cow') // используем .toLowercase(), потому что в 1.8 \"cow\" пишется с большой буквы, что может вызвать несовместимость с новыми версиями\n```\n\n### Methods\n\n#### bot.end(reason)\n\nЗакрывает соединение с сервером.\n* `reason` - Необязательная строка, в которой указывается причина отключения.\n\n#### bot.quit(reason)\n\nПринудительно завершает соединение по собственной причине (по умолчанию `'disconnect.quitting'`).\n\n#### bot.tabComplete(str, [assumeCommand], [sendBlockInSight], [timeout])\n\nЭта функция возвращает `Promise` с `matches` в качестве аргумента при завершении.\n\nЗапрашивает подсказки к командам/аргументам в чате от сервера.\n\n * `str` - Строка для завершения через подсказки.\n * `assumeCommand` - Поле отправляемое серверу, по умолчанию `false`.\n * `sendBlockInSight` - Поле отправляемое серверу, по умолчанию `true`. Установите для этого параметра значение `false`, если вы хотите повысить производительность.\n * `timeout` - Время в миллисекундах, после которого функция вернёт пустой массив, по умолчанию 5000.\n\n#### bot.chat(message)\n\nОтправляет сообщение в чат. При необходимости разбивает большое сообщение на несколько маленьких.\n\n#### bot.whisper(username, message)\n\nАналог \"/tell <никнейм>\". Все разделенные сообщения будут отправлятся пользователю.\n\n#### bot.chatAddPattern(pattern, chatType, description)\n\nНеподдерживается, используйте `addChatPattern`.\n\nДобавляет шаблон чата с помощью регулярных выражений. Полезно, если формат чата сильно меняется за счёт плагинов.\n\n * `pattern` - Регулярное выражение для совпадения с сообщением.\n * `chatType` - Вид сообщения. Является названием события, который будет срабатывать при совпадении с шаблоном. Например: \"chat\" или \"whisper\".\n * `description` - Необязательно, описание шаблона.\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\n** то же самое, что и `bot.addChatPatternSet(name, [pattern], chatPatternOptions)`\n\nСоздаёт событие, который вызывается каждый раз, когда сообщение совпадает с шаблоном.\nСобытие будет называться `\"chat:name\"`, где название - это значение `name`\n\n* `name` - Название, используемое для прослушивания события.\n* `pattern` - Регулярное выражение для совпадения с сообщением.\n* `chatPatternOptions` - Объект:\n  * `repeat` - По умолчанию `true`. Нужно ли прослушивать событие после первого совпадения.\n  * `parse` - Вместо самого сообщения, которое совпало с шаблоном, возвращает группы из регулярного выражения.\n  * `deprecated` - (**нестабильно**) используется методом `bot.chatAddPattern` для сохранения совместимости, вероятно, будет удален.\n\nВозвращает число, которое используется методом `bot.removeChatPattern()` лишь для того, чтобы можно было удалить этот шаблон.\n\n - :eyes: см. [examples/chat_parsing](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js#L17-L36)\n\n#### bot.addChatPatternSet(name, patterns, chatPatternOptions)\n\nСоздаёт событие, который вызывается каждый раз, когда сообщения совпадают с шаблонами.\nСобытие будет называться `\"chat:name\"`, где название - это значение `name`.\n* `name` - Название, используемое для прослушивания события.\n* `patterns` - Массив с регулярными выражениями для совпадения с сообщениями.\n* `chatPatternOptions` - Объект:\n  * `repeat` - По умолчанию `true`. Нужно ли прослушивать событие после первого совпадения.\n  * `parse` - Вместо самого сообщения, которое совпало с шаблоном, возвращает группы из регулярного выражения.\n\nВозвращает число, которое используется методом `bot.removeChatPattern()` лишь для того, чтобы можно было удалить этот шаблон.\n\n - :eyes: см. [examples/chat_parsing](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js#L17-L36)\n\n#### bot.removeChatPattern(name)\n\nУдаляет шаблон(ы) чата.\n* `name` - Строка или число.\n\nЕсли `name` - строка, все шаблоны с этим названием будут удалены.\nЕсли `name` - число, удаляет только определённый шаблон.\n\n#### bot.awaitMessage(...args)\n\nПромис, который срабатывает, когда сообщение совпадает с переданными аргументами.\n\nПример:\n\n```js\nasync function wait () {\n  await bot.awaitMessage('<flatbot> hello world') // срабатывает на \"hello world\" в чате от flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world']) // срабатывает на \"hello\" или \"world\" в чате от flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world'], ['<flatbot> im', '<flatbot> batman']) // срабатывает на \"hello\" или \"world\" или \"im\" или \"batman\" в чате от flatbot\n  await bot.awaitMessage('<flatbot> hello', '<flatbot> world') // срабатывает на \"hello\" или \"world\" в чате от flatbot\n  await bot.awaitMessage(/<flatbot> (.+)/) // срабатывает на первое сообщение подходящее по шаблону\n}\n```\n\n#### bot.setSettings(options)\n\nУстанавливает значения для `bot.settings`.\n\n#### bot.loadPlugin(plugin)\n\nЗагружает плагин. Ничего не делает, если плагин уже был загружен.\n\n * `plugin` - Функция.\n\n```js\nfunction somePlugin (bot, options) {\n  function someFunction () {\n    bot.chat('Yay!')\n  }\n  bot.someFunction = someFunction\n}\n\nconst bot = mineflayer.createBot({})\nbot.loadPlugin(somePlugin)\nbot.once('login', () => {\n  bot.someFunction() // Yay!\n})\n```\n\n#### bot.loadPlugins(plugins)\n\nО загрузке плагинов смотрите в `bot.loadPlugin`.\n * `plugins` - Массив функций.\n\n#### bot.hasPlugin(plugin)\n\nПроверяет, загружен ли плагин (или планирует загружаться) для данного бота.\n\n#### bot.sleep(bedBlock)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nОтправляет бота спать. `bedBlock` должен быть экземпляром `Block`, который является кроватью.\n\n#### bot.isABed(bedBlock)\n\nВозвращает `true`, если `bedBlock` является кроватью.\n\n#### bot.wake()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nПоднимает бота с кровати.\n\n#### bot.setControlState(control, state)\n\nЭто основной способ управлять ботом. Работает как нажатия кнопок в майнкрафте.\nНапример, `forward` со значением `true` будет перемещать бота вперёд. `forward` со значением `false` остановит бота от движения вперёд.\nВы можете использовать `bot.lookAt` вместе с этой функцией. jumper.js показывает на примере, как это можно использовать.\n\n * `control` - Одно из ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'].\n * `state` - `true` или `false`.\n\n#### bot.getControlState(control)\n\nВозращает `true`, если определённый элемент управления включен.\n\n* `control` - Одно из ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'].\n\n#### bot.clearControlStates()\n\nОтключает элементы управления.\n\n#### bot.getExplosionDamages(entity, position, radius, [rawDamages])\n\nВозвращает, какой урон будет нанесен существу в радиусе вокруг места взрыва.\nБудет возвращать `null`, если у существа нет брони и `rawDamages` является `true`, потому что функция не может рассчитать урон с броней без самой брони.\n\n* `entity` - Экземпляр существа.\n* `position` - Экземпляр [Vec3](https://github.com/andrewrk/node-vec3).\n* `radius` - Радиус взрыва в виде числа.\n* `rawDamages` - Необязательно, если `true`, то при рассчётах не считает броню.\n\n#### bot.lookAt(point, [force])\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда вы смотрите в указанную точку.\n\n * `point` - Экземпляр [Vec3](https://github.com/andrewrk/node-vec3). Поворачивает голову к указанной точке.\n * `force` - Смотрите `force` в `bot.look`.\n\n#### bot.look(yaw, pitch, [force])\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда вы смотрите с указанным `yaw` и `pitch`.\n\nУстанавливает направление головы.\n\n * `yaw` - Количество радианов по горизонтальной оси, начиная с востока по часовой стрелке.\n * `pitch` - Количество радианов для поворота вверх или вниз. `0`  - строго вперед. `pi / 2` - смотреть вверх. `-pi / 2` - смотреть вниз.\n * `force` - Если установлен `true`, плавного поворота не будет. Укажите значение `true`,\n если хотите передать серверу куда вы целитесь, например при бросании предметов или выстреле с лука. Это не требуется для вычислений на стороне клиента, таких как направление ходьбы.\n\n#### bot.updateSign(block, text, back = false)\n\nИзменяет текст на табличке. В Майнкрафте 1.20 и выше будет пытаться изменить текст с обратной стороны, если табличка не прикреплена к стене (Значение `back`).\n\n#### bot.equip(item, destination)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда вы надели предмет или когда узнаёте, что вам не удалось надеть предмет.\n\nНадевает предмет из вашего инвентаря. Если аргумент `item` является экземпляром `Item`, то функция будет пытаться надеть указанный предмет из слота окна. Если аргумент `item` является числом, то функция будет пытаться надеть первый попавшийся предмет в инвентаре с этим ID. (Проверка хотбара идёт последней. Слоты брони, крафта, результата крафта и второй руки не проверяются).\n\n * `item` - Экземпляр `Item` или число с ID предмета. Смотрите `window.items()`.\n * `destination`\n   - `\"hand\"` - (ведущая рука) `null` альтернатива к этому.\n   - `\"head\"` - (шлем)\n   - `\"torso\"` - (нагрудник)\n   - `\"legs\"` - (поножи)\n   - `\"feet\"` - (ботинки)\n   - `\"off-hand\"` - (вторая рука) Если доступно.\n\n#### bot.unequip(destination)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nСнимает предмет.\n\n#### bot.tossStack(item)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при выбрасывании.\n\n * `item` - Cтак предметов, которые вы хотите выбросить.\n\n#### bot.toss(itemType, metadata, count)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при одном выбрасывании.\n\n * `itemType` - Числовой ID предмета, который вы хотите выбросить.\n * `metadata` - Мета-данные предмета. Используйте `null`, чтобы выбрать любые мета-данные.\n * `count` - Количество предметов, которые вы хотите выбросить. `null` равно `1`.\n\n#### bot.elytraFly()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении полёта на элитрах.\nВ случае сбоя выдаёт сообщение об ошибке.\n\n#### bot.dig(block, [forceLook = true], [digFace])\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда блок был сломан или разрушение было прервано.\n\nНачинает ломать блок предметом, который находится в руке.\nСмотрите также события `\"diggingCompleted\"` и `\"diggingAborted\"`.\n\nОбратите внимание, что вы не сможете ломать другие блоки, пока выбранный блок не будет сломан, либо не будет вызвана функция `bot.stopDigging()`.\n\n * `block` - Блок, который нужно сломать.\n * `forceLook` - (необязательно) если `true`, сразу смотрит на блок и начинает ломать. Если `true`, бот плавно поворачивается к блоку, который нужно сломать. Кроме того, можно присвоить значение `'ignore'`, чтобы бот вообще не двигал головой. Также можно присвоить значение `'raycast'` для поворота головы бота до места, куда бот смотрит.\n * `digFace` - (необязательно) По умолчанию `'auto'`, смотрит на центр блока и ломает верхнюю грань. Также может быть вектором vec3 для направления бота при разрушении блока. Например: ```vec3(0, 1, 0)```, когда копаешь сверху. Кроме того, может быть `'raycast'`, оно проверяет, видна ли сторона для бота и копает с этим направлением. Полезно для серверов с анти-читом.\n\n#### bot.stopDigging()\n\nОстанавливает разрушение блока.\n\n#### bot.digTime(block)\n\nПокажет время, которое нужно потратить, чтобы сломать блок в миллисекундах.\n\n#### bot.acceptResourcePack()\n\nПодтверждает загрузку ресурс-пака.\n\n#### bot.denyResourcePack()\n\nОтклоняет загрузку ресурс-пака.\n\n#### bot.placeBlock(referenceBlock, faceVector)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда сервер подтверждает, что блок поставлен.\n\n * `referenceBlock` - Блок, на котором вы хотите разместить свой блок.\n * `faceVector` - Одно из шести направлений (Например: `new Vec3(0, 1, 0)` для верхней грани), указывающее, на какую грань `referenceBlock` будет установлен новый блок.\n\nНовый блок будет размещен на `referenceBlock.position.plus(faceVector)`.\n\n#### bot.placeEntity(referenceBlock, faceVector)\n\nЭта функция возвращает `Promise` с `Entity` в качестве аргумента при завершении.\n\n * `referenceBlock` - Блок, на котором вы хотите разместить существо.\n * `faceVector` - Одно из шести направлений (Например: `new Vec3(0, 1, 0)` для верхней грани), указывающее, на какую грань `referenceBlock` будет установлено существо.\n\nНовое существо будет размещено на `referenceBlock.position.plus(faceVector)`.\n\n#### bot.activateBlock(block, direction?: Vec3, cursorPos?: Vec3)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nУдаряет нотный блок, открывает дверь и т.д.\n\n * `block` - Блок для активации.\n * `direction` - (необязательно) По умолчанию `new Vec3(0, 1, 0)` (сверху). Вектор, отвечающий с какой стороны будет активироваться блок. Ничего не делает, когда целью является существо-хранилище.\n * `cursorPos` - (необязательно) По умолчанию `new Vec3(0.5, 0.5, 0.5)` (центр блока). Является точкой, куда будет смотреть бот при активации блока. Отправляется с пакетом активации блока. Ничего не делает, когда целью является существо-хранилище.\n\n#### bot.activateEntity(entity)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nНажимает на существо, например житель, или NPC.\n\n * `entity` - Существо для активации.\n\n#### bot.activateEntityAt(entity, position)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nНажимает на существо с указанной позицией, полезно при взаимодействии с стойками для брони.\n\n * `entity` - Существо для активации.\n * `position` - Позиция для клика.\n\n#### bot.consume()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении употребления.\n\nСъедает/выпивает предмет, который находится в руке.\n\n#### bot.fish()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении рыбалки.\n\nИспользует удочку.\n\n#### bot.activateItem(offHand=false)\n\nАктивирует предмет, который находится в руке. Используется для выстрела из лука, бросания яиц, использования фейерверков и т.д.\n\n * `offHand` - Во второй ли руке находится предмет для активации.\n\n#### bot.deactivateItem()\n\nДеактивирует предмет, который находится в руке. Например для прекращения натягивания тетевы лука и т.д.\n\n#### bot.useOn(targetEntity)\n\nИспользует предмет, который находится в руке, на существе. Например, одеть седло или использовать ножницы.\n\n#### bot.attack(entity, swing = true)\n\nАтакует игрока или моба.\n\n * `entity` - Тип существа. Чтобы получить конкретное существо, используйте [bot.nearestEntity()](#botnearestentitymatch--entity---return-true-) или [bot.entities](#botentities).\n * `swing` - По умолчанию `true`. Если `false` анимация руки при ударе не будет отображаться.\n\n#### bot.swingArm([hand], showHand)\n\nПроигрывает анимацию руки при ударе.\n\n * `hand` - Может быть `left` или `right`, в зависимости от того, какую руку нужно анимировать. По умолчанию: `right`.\n * `showHand` - Нужно ли добавлять руку в пакет. По умолчанию: `true`.\n\n#### bot.mount(entity)\n\nСесть в транспортное средство. Чтобы слезть, используйте `bot.dismount`.\n\n#### bot.dismount()\n\nВылезти из транспортного средства.\n\n#### bot.moveVehicle(left,forward)\n\nДвигаться в транспортном средстве:\n\n * `left` - Может быть -1 или 1 : -1 означает вправо, 1 означает влево.\n * `forward` - Может быть -1 или 1 : -1 означает назад, 1 означает вперед.\n\nНаправление относительно того, куда смотрит бот.\n\n#### bot.setQuickBarSlot(slot)\n\nВыбирает слот в хотбаре.\n\n * `slot` - Слот в хотбаре (0-8).\n\n#### bot.craft(recipe, count, craftingTable)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении крафта и обновлении инвентаря.\n\n * `recipe` - Рецепт крафта (экземпляр `Recipe`). Смотрите `bot.recipesFor`.\n * `count` - Количество операций для крафта. Например: Если вы хотите скрафтить 8 палок из досок, вы должны установить `count` на `2`. `null` является `1`.\n * `craftingTable` - Блок верстака (экземпляр `Block`), Вы можете использовать `null`, если рецепт можно использовать в инвентаре.\n\n#### bot.writeBook(slot, pages)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда написание было выполнено успешно или произошла ошибка.\n\n * `slot` - Слот в инвентаре (например, 36 - первый слот в хотбаре).\n * `pages` - Массив со страницами.\n\n#### bot.openContainer(containerBlock or containerEntity, direction?, cursorPos?)\n\nОткрывает хранилище блока или существа.\n\n * `containerBlock` или `containerEntity` - Экземпляр блока или существа для открытия.\n * `direction` - (необязательно) По умолчанию `new Vec3(0, 1, 0)` (сверху). Вектор, отвечающий с какой стороны будет активироваться блок. Ничего не делает, когда целью является существо-хранилище.\n * `cursorPos` - (необязательно) По умолчанию `new Vec3(0.5, 0.5, 0.5)` (центр блока). Является точкой, куда будет смотреть бот при активации блока. Отправляется с пакетом активации блока. Ничего не делает, когда целью является существо-хранилище.\n\nВовзращает `Promise` с экземпляром `Container`, которое представляет хранилище, которое вы открываете.\n\n#### bot.openChest(chestBlock or minecartchestEntity, direction?, cursorPos?)\n\nУстарело. То же самое, что `openContainer`.\n\n#### bot.openFurnace(furnaceBlock)\n\nВозвращает `Promise` с экземпляром `Furnace`, представляющий печь, которую вы открываете.\n\n#### bot.openDispenser(dispenserBlock)\n\nУстарело. То же самое, что `openContainer`.\n\n#### bot.openEnchantmentTable(enchantmentTableBlock)\n\nВозвращает `Promise` с экземпляром `EnchantmentTable`, представляющий стол зачарований, который вы открываете.\n\n#### bot.openAnvil(anvilBlock)\n\nВозвращает `Promise` с экземпляром `anvil`, представляющий наковальню, которую вы открываете.\n\n#### bot.openVillager(villagerEntity)\n\nВозвращает `Promise` с экземпляром `Villager`, представляющий жителя, с которым вы торгуете.\nВы можете прослушивать события `ready` для этого `Villager`, чтобы знать, когда он готов торговаться.\n\n#### bot.trade(villagerInstance, tradeIndex, [times])\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\n * `villagerInstance` - Житель, с которым вы торгуете.\n * `tradeIndex` - Номер предложения.\n * `times` - Сколько раз произвести торговлю.\n\n#### bot.setCommandBlock(pos, command, [options])\n\nУстанавливает настройки командного блока в позиции `pos`.\nПример аргумента `options`:\n\n```js\n{\n  mode: 2,\n  trackOutput: true,\n  conditional: false,\n  alwaysActive: true\n}\n```\n\n`options.mode` может иметь 3 значения: 0 (Цепной), 1 (Цикличный), 2 (Импульсный)\nВсе дополнительные настройки по умолчанию `false`, кроме `mode`, который равен 2 (для повторения командного блока по умолчанию в Майнкрафте).\n\n#### bot.supportFeature(name)\n\nМожет использоваться для проверки особой для текущей версии Майнкрафт возможности. Обычно это требуется только для обработки функций, зависящих от версии.\n\nСписок возможностей можно найти в файле [./lib/features.json](https://github.com/PrismarineJS/mineflayer/blob/master/lib/features.json).\n\n#### bot.waitForTicks(ticks)\n\nЭто функция основана на промисе. Она ожидает определённое количество игровых тиков перед продолжением. Может быть полезно для быстрых таймеров, который требуют особых задержек, независимо от заданной физической скорости тиканья бота. Это похоже на стандартную функцию Javascript `setTimeout`, но выполняется специально по физическому таймеру бота.\n\n#### bot.respawn()\n\nКогда выключена настройка `respawn`, вы можете вызвать этот метод для ручного возрождения.\n\n### Методы инвентаря низкого уровня\n\nЭти методы могут быть иногда полезны, но мы рекомендуем использовать методы, описанные выше.\n\n#### bot.clickWindow(slot, mouseButton, mode)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n  \nПоддержка mode:\n  - стабильно:\n    - клик мышью (0)\n\n  - экспериментально:\n    - клик с шифтом (1)\n    - клик цифрой (2)\n    - клик колёсиком (3)\n    - выкидывающий клик (4)\n\n  - не реализовано:\n    - драг клик (5)\n    - двойной клик (6)\n\nНажимает на текущее окно. Подробнее - https://minecraft.wiki/w/Protocol#Click_Container\n\nРекомендуется использовать `bot.simpleClick.*`\n\n#### bot.putSelectedItemRange(start, end, window, slot)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nПомещает предмет в слот в указаном диапазоне.\n\n#### bot.putAway(slot)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nПомещает предмет в слот инвентаря.\n\n#### bot.closeWindow(window)\n\nЗакрывает окно.\n\n#### bot.transfer(options)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nПеремещает предмет с одного диапазона в другой. `options` это объект, содержащий :\n\n * `window` : (необязательно) Окно, куда требуется положить предмет.\n * `itemType` : Тип предмета.\n * `metadata` : (необязательно) Мета-данные предмета.\n * `sourceStart` и `sourceEnd` : Старый диапозон. `sourceEnd` необязателен и будет по умолчанию равен `sourceStart` + 1.\n * `destStart` и `destEnd` : Новый диапозон. `destEnd` необязателен и будет по умолчанию равен `destStart` + 1.\n * `count` : Количество предметов. По умолчанию: `1`.\n * `nbt` : Нбт-данные предмета. По умолчанию: `nullish` (игнорирует нбт).\n\n#### bot.openBlock(block, direction?: Vec3, cursorPos?: Vec3)\n\nОткрывает блок, например сундук. Возвращает `Promise` с открытым окном (`Window`).\n\n * `block` - Блок, который нужно открыть боту.\n * `direction` - (необязательно) По умолчанию `new Vec3(0, 1, 0)` (сверху). Вектор, отвечающий с какой стороны будет активироваться блок. Ничего не делает, когда целью является существо-хранилище.\n * `cursorPos` - (необязательно) По умолчанию `new Vec3(0.5, 0.5, 0.5)` (центр блока). Является точкой, куда будет смотреть бот при активации блока. Отправляется с пакетом активации блока. Ничего не делает, когда целью является существо-хранилище.\n\n#### bot.openEntity(entity)\n\nОткрывает GUI существа, например жителя. Возвращает `Promise` с открытым окном (`Window`).\n\n * `entity` - Существо, GUI которого нужно открыть.\n\n#### bot.moveSlotItem(sourceSlot, destSlot)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента при завершении.\n\nПомещает предмет со слота `sourceSlot` в слот `destSlot` в открытом окне.\n\n#### bot.updateHeldItem()\n\nОбновляет `bot.heldItem`.\n\n#### bot.getEquipmentDestSlot(destination)\n\nПолучает ID слота экипировки по названию.\n\nДоступны:\n * head (шлем)\n * torso (нагрудник)\n * legs (поножи)\n * feet (ботинки)\n * hand (главная рука)\n * off-hand (вторая рука)\n\n### bot.creative\n\nЭта коллекция API полезна в творческом режиме.\nОбнаружение и изменение игровых режимов здесь не реализовано, но предполагается и часто требуется, чтобы бот находился в творческом режиме для работы этих функций.\n\n#### bot.creative.setInventorySlot(slot, item)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда сервер выдаёт предмет в слот.\n\nВыдёт боту указанный предмет в слоте инвентаря.\n\n * `slot` - Номер слота (например: 36 - первый слот в хотбаре).\n * `item` - Экземпляр [prismarine-item](https://github.com/PrismarineJS/prismarine-item), содержащий мета-данные, нбт-данные и т.д.\n    Если `item` равен `null`, предмет в указанном слоте удаляется.\n\nЕсли этот метод что-либо изменит, вы можете узнать об этом через `bot.inventory.on(\"updateSlot\")`.\n\n#### bot.creative.clearSlot(slot)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда сервер очищает слот.\n\nУстанавливает значение `null` для предмета в заданном слоте.\n\n * `slot` - Номер слота (например: 36 - первый слот в хотбаре).\n\n#### bot.creative.clearInventory()\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда сервер очищает слоты.\n\n#### bot.creative.flyTo(destination)\n\nЭта функция возвращает `Promise` с `void` в качестве аргумента, когда бот достигает точки назначения.\n\nВызывает `startFlying()` и движется к месту назначения по прямой.\n`destination` - это `Vec3`. Координаты `x` и `z` обычно заканчиваются на `.5`.\nФункция не будет работать, если на пути присутствуют препятствия.\nРекомендуется отправлять на небольшие расстояния.\n\nЭтот метод не пытается найти путь до точки.\nОжидается, что реализация поиска пути будет использовать этот метод для перемещения на <2 блоков одновременно.\n\nЧтобы остановить полет, используйте `stopFlying()`.\n\n#### bot.creative.startFlying()\n\nУстанавливает `bot.physics.gravity` на `0`.\nЧтобы остановить полет, используйте `stopFlying()`.\n\nЭтот метод полезен, если вы хотите летать, копая землю под собой.\nНет необходимости вызывать эту функцию перед вызовом `flyTo()`.\n\nОбратите внимание, что во время полета `bot.entity.velocity` не будет точным.\n\n#### bot.creative.stopFlying()\n\nВосстанавливает `bot.physics.gravity` к исходному значению.\n"
  },
  {
    "path": "docs/ru/demos_ru.md",
    "content": "## mineflayer-navigate\n\n[navigate](https://github.com/andrewrk/mineflayer-navigate/) - Лёгкое передвижение с помощью поиска путей уровня A*.\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/O6lQdmRz8eE\" frameborder=\"0\"></iframe>\n\n## rbot\n\n[rom1504/rbot](https://github.com/rom1504/rbot) - Умный бот, созданный на основе mineflayer.\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/0cQxg9uDnzA\" frameborder=\"0\"></iframe>\n\n## chaoscraft\n\n[Chaoscraft](https://github.com/schematical/chaoscraft) - Майнкрафт бот, использующий генетические алгоритмы.\n\n\n​<iframe width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/videoseries?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/ru/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Mineflayer - создавайте Майнкрафт ботов с помощью стабильного и высокоуровневого API</title>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n  <meta name=\"description\" content=\"Создавайте Майнкрафт ботов с помощью стабильного и высокоуровневого API\">\n  <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n  <link rel=\"stylesheet\" href=\"//unpkg.com/docsify/lib/themes/vue.css\">\n    <style>\n        .markdown-section {\n            max-width:1400px;\n        }\n    </style>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-128628977-3\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'UA-128628977-3');\n    </script>\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script>\n    window.$docsify = {\n      name: 'mineflayer',\n      repo: 'https://github.com/PrismarineJS/mineflayer',\n      loadSidebar: true,\n      subMaxLevel: 2,\n      auto2top: true\n    }\n  </script>\n  <script src=\"//unpkg.com/docsify/lib/docsify.min.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/ru/tutorial_ru.md",
    "content": "# Туториал\n\n**Содержание**\n\n- [Вступление](#вступление)\n- [Основы](#основы)\n  - [Основы Javascript](#основы-javascript)\n    - [Установка Node](#установка-node)\n    - [Переменные в Javascript](#переменные-в-javascript)\n    - [Получение ответа](#получение-ответа)\n    - [Функции в Javascript](#функции-javascript)\n    - [Типы данных в Javascript](#типы-данных-в-javascript)\n    - [Условные конструкции](#условные-конструкции)\n    - [Циклы](#циклы)\n    - [Node Package Manager](#node-package-manager)\n  - [Создание бота](#создание-бота)\n    - [Объекты в Javascript](#объекты-в-javascript)\n    - [Присоединение](#присоединение)\n    - [Аргументы командной строки](#аргументы-командной-строки)\n  - [Передача функций](#передача-функций)\n  - [Прослушивание событий](#прослушивание-событий)\n  - [Промисы](#промисы)\n    - [Правильный и неправильный подход](#правильный-и-неправильный-подход)\n- [Продвинутым](#продвинутым)\n  - [Цикл для объекта](#цикл-для-объекта)\n  - [Создание события для чата](#создание-события-для-чата)\n    - [Приветствующий бот](#приветствующий-бот)\n    - [Нестандартный формат чата](#нестандартный-формат-чата)\n- [ЧаВо](#чаво)\n  - [Как запустить бота на Android](#как-запустить-бота-на-android)\n    - [Установка Termux](#установка-termux)\n    - [Настройка](#настройка)\n    - [Запуск вашего бота](#запуск-вашего-бота)\n\n## Вступление\n\nЭтот туториал поможет вам начать работать с Mineflayer, даже если вы ничего не знаете о программировании.  \nЕсли вы уже знаете что-то о Node и NPM, вы можете сразу переходить к разделу [Создание бота](#создание-бота).\n\n## Основы\n\nСледующие разделы посвящены основным понятиям, которые вам необходимо знать, чтобы начать использовать Mineflayer.\n\n### Основы Javascript\n\n#### Установка Node\n\nВ этом разделе вы научитесь основам Javascript, Node и NPM.\n\nJavascript (сокращённо JS) - это язык программирования, созданный для Интернета. Это то, что делает возможным максимальный уровень взаимодействия в Интернете.  \nNode.js, часто просто Node, позволяет использовать Javascript вне веб-браузеров.\n\nДля начала, вам нужно установить Node. Вы можете это сделать [здесь](https://nodejs.org/ru/download/).  \nПосле установки откройте командную строку (также известную как терминал) и затем введите `node -v`  \nЕсли вы всё сделали правильно, то вам напишет версию Node. Если вам написало о том, что команда не найдена, попробуйте установить ещё раз.\n\nТеперь у вас есть Node, вы можете начать писать код, но вам нужно кое-что ещё.  \nJavascript был написан в примитивном текстовом редакторе, но легче использовать [Интегрированную среду разработки](https://ru.wikipedia.org/wiki/Интегрированная_среда_разработки)(IDE)  \nIDE поможет вам в написании кода, потому что будет давать вам подсказки или указывать на ошибки в коде. Примером хорошей IDE является [Visual Studio Code](https://code.visualstudio.com/)(VSCode)  \nПосле того как вы установили VSCode, создайте новый текстовый файл и сохраните его где-нибудь, а затем переименуйте его так, чтобы в конце была приписка `.js`. Например: `bot.js`  \nЭто сообщит VSCode о том, что вы работаете с Javascript, чтобы программа выдавала правильные подсказки.\n\n#### Переменные в Javascript\n\nНачните с этого:\n\n```js\nconst test = 5\n```\n\nЭто создаст переменную с названием `test` и выдаст ей значение `5`  \nПеременные используются для хранения данных и использования их в коде.\n\nСохраните файл, теперь вы можете запустить этот код. Откройте терминал (или новый терминал в VSCode), затем выберите папку с вашим файлом. Для этого можно использовать команду `cd`. Например: `cd Documents\\javascript`  \nТеперь ваш терминал находится в той же папке, где и ваш файл, вы можете запустить его с помощью `node filename.js`  \nЕсли вы всё сделали правильно, то вы ничего не будете видеть.  \nВ следующей главе мы покажем вам, как вы можете выводить данные в терминале.\n\nВ общем, использование `const` вместо `let` является нормальным при определении переменной. Переменная, определённая с помощью `const` не может быть изменена, так как является константой.  \nJavascript сможет заставить ваш код работать более эффективно, потому что он знает, что ему не нужно учитывать изменения значения этой переменной.  \nЕсли вы хотите изменяемую переменную, вы можете использовать `let`.\n\n```js\nconst test = 5\n// eslint-disable-next-line\ntest = 10 // Эта строчка неправильная\n```\n\nВторая строчка неправильная, так как вы не можете перезаписать переменную `test`.\n\nЕсли вы хотите помочь себе и другим людям в понимании вашего кода, то вы можете использовать комментарии.  \nЧтобы написать комментарий вам нужно использовать `//`, всё после этого будет игнорироваться Javascript'ом.\n\n#### Получение ответа\n\nДовольно часто для того чтобы убедиться, что ваша программа работает правильно, вам нужно выводить значения переменных.  \nВы можете сделать это отображая переменные в терминале.  \nВ Javascript вы можете это сделать с помощью функции `console.log()`.  \n\n```js\nconst test = 5\n\nconsole.log(test)\n```\n\nТеперь когда вы сохраните и запустите этот код, то наконец увидите:\n\n```txt\n5\n```\n\n#### Функции в Javascript\n\nДалее вы узнаете о функциях. Функции - это часть кода, которая может быть использована несколько раз в вашем коде.\nЭто может быть полезно, потому что вам не нужно будет писать что-либо много раз.\n\n```js\nconst addition = (a, b) => {\n  return a + b\n}\n\nconst test1 = addition(5, 10)\nconst test2 = addition(1, 0)\n\nconsole.log(test1)\nconsole.log(test2)\n```\n\n`=>` используется для определения функции, и называется стрелочным оператором.\nПеред стрелочным оператором находится список параметров, всё, что находится в круглых скобках `()` - это параметры, разделённые запятыми.  \nПараметры - это переменные, которые вы можете передать вашей функции, чтобы функция могла с ними работать.  \nЗатем после оператора идёт тело функции, это всё, что находится в фигурных скобках `{}`  \nЭто то место, где вы можете поместить свой код функции.  \nТеперь, когда функция готова, вы присваиваем её к переменной, чтобы дать имя. В нашем случае - `addition`  \n\nКак вы можете видеть, код берёт в качестве параметров переменные `a` и `b`, а затем складывает их.  \nЗатем функция возвращает результат.  \nКогда функция определена, код в теле функции не выполняется. Чтобы запустить функцию вам нужно вызвать её.\nВы можете вызвать функцию, используя её имя, за которыми идут круглые скобки. В нашем случае - `addition()`  \nОднако для функции `addition` требуется 2 параметра. Их можно передать, добавив их в круглые скобки через запятую. В нашем случае - `addition(1, 2)`  \nКогда функция готова, вы можете Wпредставить, что вызов функции заменяется тем, что функция вернула. Таким образом, в этом случае `let test1 = addition(5, 10)` станет `let test1 = result` (На самом вы этого не увидите, но это может помочь вам понять концепцию).\n\nИногда вы столкнётесь со следующим: `function addition() {}` Это означает то же самое, но предпочтительнее использовать `() => {}`. (Если вы действительно хотите знать почему, загуглите 'javascript function vs arrow function')\n\nПриведённый код выше должен вывести следующее:\n\n```txt\n15\n1\n```\n\n#### Типы данных в Javascript\n\nДо этого мы работали только с числами, но Javascript имеет множество других типов данных:\n\n- Строка - это текст, который содержит множество символов. Строки объявляются с помощью `''`\n\n```js\nconst string = 'This is a string' // string type\n```\n\n- Массив - это тип, который может хранить несколько других переменных. Массивы объявляются с помощью `[]`\n\n```js\nconst array = [1, 2, 3] // array type\n```\n- Объекты - это обычно продвинутые массивы, позже вы узнаете больше об этом типе в туториале. Они объявляются с помощью `{}`\n\n```js\nconst object = {} // object type\n```\n\n- У функций есть свой собственный тип\n\n```js\nconst adder = (a, b) => { return a + b } // function type\n```\n\n- Логический тип может быть `true` или `false`\n\n```js\nconst boolean = true // boolean type\n```\n\n- Когда что-либо ещё не объявлено, оно имеет тип `undefined`\n\n```js\nlet nothing // undefined type\nconst notDefined = undefined // undefined type\n```\n\n#### Условные конструкции\n\nИногда вам придётся делать разные вещи, основываясь на определенном условии.  \nЭто можно реализовать с помощью условных конструкций.\n\n```js\nconst name = 'Боб'\n\nif (name === 'Боб') {\n  console.log('Меня зовут Боб')\n} else if (name === 'Алиса') {\n  console.log('Меня зовут Алиса')\n} else {\n  console.log('Меня не зовут Боб или Алиса')\n}\n```\n\nУсловные конструкции создаются с помощью `if`. После этого идёт условие с круглых скобках `()`, код находится в фигурных скобках `{}`  \nВ условии должно быть что-то, что возвращает логический тип данных.  \nВ нашем случае используется `===`, которое возвращает `true`, если значение значение слева равняется значению справа. Иначе будет `false`\nЕсли значение равно `true`, то код, соответствующий этому условию будет выполнен.  \nВы можете продолжать цепочку условных конструкций используя `else if` и `else`.  \nВы можете иметь столько условных конструкций с `else if`, сколько вы захотите, но можно использовать только только 1 `if` и `else`.  \nЕсли у вас присутствует `else`, то он будет вызываться только тогда, когда все остальные условия вернули `false`\n\n#### Циклы\n\nЦиклы используются для повторения определенного кода до тех пор, пока не будет выполнено определенное условие.\n\n```js\nlet countDown = 5\n\nwhile (countDown > 0) {\n  console.log(countDown)\n  countDown = countDown - 1 // Понижаем значение countDown на 1\n}\n\nconsole.log('Конец!')\n```\n\nКод выше будет выводить следующее:\n\n```txt\n5\n4\n3\n2\n1\nКонец!\n```\n\nЦикл `while` имеет условие `()` и тело `{}`  \nКогда код доходит до цикла, он проверяет условие. Если условие равно `true`, то код в теле циклы будет выполнен.  \nКогда код в теле выполнен, условие проверяется ещё раз, и если оно равно `true`, код выполняется заново.  \nЭто будет происходить до тех пор, пока условие равно `true`  \nКаждый цикл код выводит число `countDown`, а затем отнимает от него 1.  \nПосле 5 срабатывания, когда условие равно `0 > 0`, будет `false`, и тогда код будет продолжаться дальше.\n\nЦикл `for` также часто используется и немного отличается от `while`.  \n\n```js\nfor (let countDown = 5; countDown > 0; countDown = countDown - 1) {\n  console.log(countDown)\n}\n```\n\nВместо одного условия, цикл содержит 3 разных части.  \nЭти части разделены точкой с запятой.  \nПервая часть - `let countDown = 5`, срабатывает только 1 раз, при запуске цикла.  \nВторая часть - `countDown > 0`, условие, которое одинаково при каждом срабатывании цикла.  \nТретья часть -  `countDown = countDown - 1`, срабатывает при каждом срабатывании цикла.\n\nЕсли вы хотите что-то сделать с каждым элементом массива, вы можете использовать цикл `for of`.  \n\n```js\nconst array = [1, 2, 3]\n\nfor (const item of array) {\n  console.log(item)\n}\n```\n\nЦикл `for of` требует переменную перед `of`, это требуется для доступа к каждому элементу этой переменной.  \nПеременная после `of` нужна, чтобы хранить переменную. В основном это массивы, но также могут быть объектами.  \nЦикл будет выполняться для каждого элемента в `array`, и каждый раз переменная `item` будет являться элементом `array`.\n\n#### Node Package Manager\n\nТеперь вы узнаете как пользоваться [Node Package Manager](https://www.npmjs.com/)(NPM).  \nNPM автоматически устанавливается, когда вы устанавливаете Node.  \nNPM используется для получения библиотек, которые другие люди создали для удобства.  \nВы можете посмотреть библиотеки на [сайте](https://www.npmjs.com/) и затем установить их, используя команду `npm install` в вашем терминале.  \nНапример, чтобы скачать библиотеку Mineflayer, вам нужно прописать `npm install mineflayer`  \n\nТеперь Node может получить доступ к установленной библиотеке с помощью функции `require()`.\n\n```js\nconst mineflayer = require('mineflayer')\n```\n\nПосле этого будет доступна переменная `mineflayer`, представляющая все функции Mineflayer.\n\n### Создание бота\n\nТеперь, когда вы знаете основы Javascript, Node и NPM, вы готовы к созданию вашего первого бота!  \nЕсли вы не знаете слов выше, то вернитесь к [предыдущему](#основы-javascript)\n\nСнизу представлены начальные действия для создания бота.\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot()\n```\n\nЕсли вы запустите этот код, вы заметите, что программа не останавливатся. Если вы хотите остановить работающую программу, нажмите `Ctrl` + `c`  \nОднако этот бот не совсем полезен, так как по умолчанию он подключается к серверу Minecraft, работающему на вашем компьютере, с портом 25565.  \nЕсли вы хотите выбрать сервер, на который будет заходить бот, вам нужно прописать некоторые настройки.\n\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst options = {\n  host: 'localhost', // Измените это на айпи сервера, который вам нужен.\n  port: 25565 // Измените это на порт сервера, который вам нужен.\n}\n\nconst bot = mineflayer.createBot(options)\n```\n\n#### Объекты в Javascript\n\nФигурные скобки `{}` используются для созданий объектов.  \nОбъекты содержат значения в виде пар `ключ-значение`  \nЭти пары разделены с помощью `:`, где ключ перед двоеточием, а значение после двоеточия.  \nКлючи можно использовать для получения их значения.  \nВы можете иметь несколько таких пар, разделённых запятыми.\n\n```js\nconst object = {\n  number: 10,\n  another: 5\n}\n\nconsole.log(object.number) // Выведет число 10\n```\n\nЭта концепция часто используется для создания так называемых 'именованных параметров'  \nПреимущество этого заключается в том, что вам не нужно использовать все доступные опции, и их расположение не имеет значения.  \nЗначением может быть что угодно, даже другой объект. Если значение является функцией, то эта функция часто вызывается методом для этого объекта.  \nВы также можете создать объект одной строкой.\n\n```js\nconst bot = mineflayer.createBot({ host: 'localhost', port: 25565 })\n```\n\n#### Присоединение\n\nБез каких либо параметров у бота будет ник `Player` и он сможет подключаться только к пиратским серверам(или LAN-сервера).  \nЕсли вы дополните `createBot` опцией `username`, то бот будет использовать указанный вами ник. (Всё ещё для пиратских серверов)  \nЧтобы зайти на конкретный лицензионный аккаунт, вы должны использовать `username` вместе с `password`\n\n```js\nconst bot = mineflayer.createBot({\n  host: 'localhost',\n  port: 25565,\n  username: 'Player',\n  password: 'password'\n})\n```\n\n#### Аргументы командной строки\n\nЧто если кому-то понравится ваш бот и он захочет использовать его на другом сервере или с другим аккаунтом?  \nЭто означает, что все смогут изменить айпи сервера и настройки входа как они захотят. (А также плохая идея передавать свой пароль)  \nПоэтому многие используют аргументы командной строки.\n\n```js\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4],\n  password: process.argv[5]\n})\n```\n\nКак вы видите, теперь ваши данные не используются в коде! Но как его запустить?  \nТеперь вместо того, чтобы запускать код через `node filename.js`, вы должны запускать его с помощью `node filename.js host port username password`  \nNode автоматически разделит агрументы через пробел в массив.  \nЭтот массив - `process.argv`  \nДанные можно получить с помощью индексов. Индексы всегда начинаются с 0, поэтому первый аргумент с номером `[0]` будет со значением `node` и т.д.\n\n| | Первый аргумент | Второй аргумент | Третий аргумент | Четвёртый аргумент | Пятый аргумент | Шестой аргумент |\n| --- | :---: | :---: | :---: | :---: | :---: | :---: |\n| Значение | `node` | `filename.js` | `host` | `port` | `username` | `password` |\n| Индекс | `[0]` | `[1]` | `[2]` | `[3]` | `[4]` | `[5]`\n\n### Передача функций\n\nПередаваться в качестве аргумента могут не только основные переменные, но и функции.\nФункции передаются точно так же.\n\n```js\nconst welcome = () => {\n  bot.chat('Привет!')\n}\n\nbot.once('spawn', welcome)\n```\n\nКак вы можете видеть, метод `bot.once()` имеет 2 параметра.  \nПервый параметр - название события, второй - функция, которая вызывается, когда срабатывает событие.  \nЗапомните, когда передаёте функцию в качестве аргумента, используйте только имя функции, без `()`\n\n`bot.chat()` - это метод отправки сообщений в чат.\n\nВы можете упростить код, используя анонимные функции.  \nУ анонимных функций нет названий, они создаются на месте имени функции.  \nОни так же могут иметь параметры в `()` и тело функции в `{}`, даже если они не используются.\n\n```js\nbot.once('spawn', () => {\n  bot.chat('Привет!')\n})\n```\n\n### Прослушивание событий\n\nОбъект бота имеет множество полезных [событий](http://prismarinejs.github.io/mineflayer/#/api_ru?id=events).\nВы можете прослушивать события используя методы `bot.on()` или `bot.once()` для объекта бота, они принимают имя события и функцию.  \nЧтобы удалить какой-либо прослушиватель событий, используйте метод `bot.removeListener()`.\n\n- `bot.on(eventName, listener)`\n  Вызывает функцию `listener` каждый раз, когда срабатывает событие `eventName`.\n- `bot.once(eventName, listener)`\n  Вызывает функцию `listener` только один раз, когда впервые срабатывает событие `eventName`.\n- `bot.removeListener(eventName, listener)`\n  Удаляет `listener` для события `eventName`. Чтобы это использовать, вам нужно либо определить вашу функцию с помощью `function myNamedFunc() {}`, либо поместить вашу функцию в переменную с помощью `const myNamedFunc = () => {}`. Затем вы можете использовать `myNamedFunc` в аргументе слушателя.\n\nСобытия имеет не только объект бота, например у [`Сундуков`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=mineflayerchest), [`Печек`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=mineflayerfurnace), [`Раздатчиков`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=mineflayerdispenser), [`Столов зачарования`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=mineflayerenchantmenttable), [`Жителей`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=mineflayervillager) также есть свои события.\n\n### Промисы\n[Промисы](https://nodejs.dev/learn/understanding-javascript-promises) - это функции, которые вы можете использовать с помощью переменной `await` для ожидания, пока какая-либо функция не завершится (вы также можете прервать await, чтобы не ожидать результата).\n\n```js\nasync function consume (bot) {\n  try {\n    await bot.consume()\n    console.log('Съел')\n  } catch (err) {\n    console.log(error)\n  }\n}\n```\n\nКод выше попытается употребить то, что сейчас бот держит в руке.  \nКогда употребление заканчивается, вызывается переданная функция.\nПосле этого вы сможете делать любые другие вещи.  \nФункция также может быть вызвана при возникновении ошибки.\n\n#### Правильный и неправильный подход\n\nСнизу пример бота, который создаёт дубовые доски, а затем палки.\n\nНеправильно ❌:\n\n```js\nfunction craft (bot) {\n  const mcData = require('minecraft-data')(bot.version)\n  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0] // Получение рецепта для дубовых досок\n  bot.craft(plankRecipe, 1) // ❌ Начинает создавать дубовые доски\n\n  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0] // Получение рецепта для палок\n  bot.craft(stickRecipe, 1) // ❌ Начинает создавать палки\n}\n```\n\nПравильно с промисами ✔️:\n\n```js\nasync function craft (bot) {\n  const mcData = require('minecraft-data')(bot.version)\n  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0]\n  await bot.craft(plankRecipe, 1, null)\n  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0]\n  await bot.craft(stickRecipe, 1, null)\n  bot.chat('Скрафтил палки')\n}\n```\n\nПричина почему первый код неправильный в том, что когда вызывается `bot.craft()`, код продолжает что-то делать, пока бот крафтит.  \nК тому времени как код уже выполняет второй `bot.craft()`, первый ещё возможно даже не закончился, а значит ресурсов для палок ещё нет.  \nИспользование промисов может исправить это, потому что будет известно, когда закончится выполнение `bot.craft()`.\n\nБольше о методе `bot.craft()` [здесь](https://github.com/PrismarineJS/mineflayer/blob/master/docs/api_ru.md#botcraftrecipe-count-craftingtable).\n\n## Продвинутым\n\nСледующие концепции необязательны для создания бота на Mineflayer, но могут быть полезны для понимая и создания усовершенствованных ботов.  \nМы предполагаем, что вы поняли [Основы](#основы).\n\n### Цикл для объекта\n\nЦикл `for of` описанный в [разделе о циклах](#циклы) также может использоваться и для объектов.\n\nЕсли у нас есть следующий объект:\n\n```js\nconst obj = {\n  a: 1,\n  b: 2,\n  c: 3\n}\n```\n\nМы можем создать цикл, перебирающий все значения объекта.\n\n```js\nfor (const value of Object.values(obj)) {\n  console.log(value)\n}\n```\n\n```txt\n1\n2\n3\n```\n\nЭто цикл, перебирающий все ключи объекта.\n\n```js\nfor (const key of Object.keys(obj)) {\n  console.log(key)\n}\n```\n\n```txt\na\nb\nc\n```\n\nВы также можете одновременно использовать ключи и значения одновременно. Сначала вам придется деструктурировать переменные, объяснение вы можете найти [здесь.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)\n\n```js\nfor (const [key, value] of Object.entries(obj)) {\n  console.log(key + ', ' + value)\n}\n```\n\n```txt\na, 1\nb, 2\nc, 3\n```\n\nЭти циклы возможны благодаря `Object.values(obj)` и `Object.keys(obj)`, который возвращают массивы с значениями и ключами объектов соотвественно.  \n`Object.entries(obj)` возвращает массив, состоящий из двух элементов: ключа и его значения.  \nВажно знать, что в отличии от функций `Object.values()` и `Object.keys()`, функция `Object.entries()` порядок элементов останется таким же, каким он был в объекте.\n\nТакже существует цикл `for in`. Однако, вам чаще придётся использовать `for of` вместо `for in`, потому что есть различия в ключах.  \nЦикл `for in` работает на основе ключей вместо значений. (Индекс в этом случае, если это массив)  \nОднако он зацикливается не только на своих собственных ключах, но и на ключах из другого объекта, от которого он \"наследуется\", что нежелательно и может сбивать с толку. Подробнее об этом [здесь.](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/for...in)  \nВ общем, вам понадобится `for of` вместо `for in`, поэтому убедитесь, что вы не путаете эти два понятия.\n\n### Создание события для чата\n\nВы можете создать свои собственные события для чата, используя метод [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=#botchataddpatternpattern-chattype-description). Полезно для серверов с плагинами, который меняют формат чата на сервере.\nМетод [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api_ru?id=botchataddpatternpattern-chattype-description) принимает три аргумента :\n\n- `pattern` - Регулярное выражение для совпадения с сообщением.\n- `chatType` - Вид сообщения. Является названием события, который будет срабатывать при совпадении с шаблоном. Например: \"chat\" или \"whisper\".\n- `description` - Необязательно, описание шаблона.\n\nВы можете добавить [группы](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges) в `pattern`, чтобы затем слушатель последовательно распределил группы по аргументам вашего обратного вызова.\n\nОзнакомиться с регулярными выражениями вы можете [здесь](https://ru.wikipedia.org/wiki/Регулярные_выражения).\n\nПримеры :\n\n#### Приветствующий бот\n\nЗдесь мы создаём бота, который отвечает на 'привет' другого игрока.\n\n```js\nbot.chatAddPattern(\n  /(прив|привет|Привет)/,\n  'hello',\n  'Кто-то приветствуется'\n)\n\nconst hi = () => {\n  bot.chat('Здарова!')\n}\n\nbot.on('hello', hi)\n```\n\n#### Нестандартный формат чата\n\nСоздание события основанного на изменённом формате сообщений.  \nПример:\n\n```txt\n[Игрок] Player1 > Привет\n[Админ] Alex > прив\n[Игрок] Player2 > Помогите, я застрял\n[Модератор] Jim > Сейчас\n```\n\n```js\nbot.chatAddPattern(\n  /^\\[(.+)\\] (\\S+) > (.+)$/,\n  'my_chat_event',\n  'Собственное событие чата'\n)\n\nconst logger = (rank, username, message) => {\n  console.log(`${username} сказал ${message}`)\n}\n\nbot.on('my_chat_event', logger)\n```\n\nОбъяснение этого `^\\[(.+)\\] (\\S+) > (.+)$` вы можете найти [здесь](https://regex101.com/r/VDUrDC/2).\n\n## ЧаВо\n\n### Как запустить бота на Android\n\nВы можете запускать ботов на Android при помощи [Termux](https://termux.com/).\n\n#### Установка Termux\n\nУстановите [Termux](https://termux.com/) и запустите его.\n\n#### Настройка\n\nУстановите `Node.js`:\n\n```bash\npkg update -y\npkg install nodejs -y\n```\n\n❗️ Выдайте Termux права на доступ к файлам в настройках приложения.\nСоздайте папку во внутреннем хранилище :\n\n```bash\ncd /sdcard\nmkdir my_scripts\ncd my_scripts\n```\n\nУстановите `mineflayer`:\n\n```bash\nnpm install mineflayer\n```\n\nТеперь вы можете скопировать и хранить все свои скрипты в папке `my_scripts` во внутреннем хранилище.\n\n#### Запуск вашего бота\n\nЧтобы запустить бота, запустите Node с именем вашего скрипта.\n\n```bash\nnode script_name.js\n```\n\n❗️ Каждый раз, когда вы открываете Termux, вы должны изменять директорию на `/sdcard/my_scripts`, перед тем как запускать бота:\n\n```bash\ncd /sdcard/my_scripts\n```\n"
  },
  {
    "path": "docs/ru/unstable_api_ru.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Содержание**  *сгенерировано с помощью [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [unstable API : bot._](#unstable-api--bot_)\n  - [bot._client](#bot_client)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# unstable API : bot._\n\nЭти методы и классы могут быть полезны в особых случаях, но являются нестабильными и могут изменятся в любой момент.\n\n## bot._client\n\n`bot._client` создан при помощи [node-minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol).\nОн обрабатывает запись и чтение пакетов.\nРабота данного метода постоянно меняется, так как версии Minecraft постоянно обновляются.\nРекомендуем использовать стандартные методы Mineflayer, если это возможно\n"
  },
  {
    "path": "docs/tr/README_TR.md",
    "content": "# Mineflayer\n\n[![NPM version](https://badge.fury.io/js/mineflayer.svg)](http://badge.fury.io/js/mineflayer)\n[![Build Status](https://github.com/PrismarineJS/mineflayer/workflows/CI/badge.svg)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)\n[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)\n[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)\n[![Issue Hunt](https://github.com/BoostIO/issuehunt-materials/blob/master/v1/issuehunt-shield-v1.svg)](https://issuehunt.io/r/PrismarineJS/mineflayer)\n\n[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n\n| <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) | <sub>BR</sub> [Portuguese](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|\n\nJavaScript ile güçlü, stabil ve üst seviye Minecraft botları oluşturabileceğiniz bir [API](api.md).\n\nİlk defa mı Node.js kullanıyorsun? [Öğretici](tutorial.md) ile başlayabilirsin.\n\n## Özellikler\n\n * Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 ve 1.20 sürümlerini destekler.\n * Varlık bilgisi ve takibi.\n * Blok bilgisi. Etrafını inceleyebilirsin. Bir bloğu bulmak milisaniyeler sürer.\n * Fizik ve hareket - bütün hayali kutucukları ele alabilirsin\n * Canlılara saldırma ve taşıtları kullanma.\n * Envanter düzenleme.\n * Çalışma masaları, sandıklar, fırlatıcılar, büyü masaları.\n * Blok kazma ve koyma.\n * Can sayını ve yağmur yağıp yapmadığını öğrenmek gibi ekstra özellikler.\n * Eşyaları kullanma ve blokları aktifleştirme.\n * Sohbet.\n\n### Yol Haritası\n\nBu sayfayı ziyaret ederek [projelerin](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects) durumlarını öğrenebilirsin. \n \n## Kurulum\n\nNode.js 14 veya üstü bir sürümü [nodejs.org](https://nodejs.org/) adresinden indirip kurduktan sonra mineflayer'ı  `npm install mineflayer` ile kurabilirsin.\n\n## Belgeler / Wiki\n\n| link | açıklama |\n|---|---|\n| [Öğretici](tutorial.md) | Node.js ve mineflayer öğren |\n| [FAQ.md](FAQ.md) | Aklına bir şey mi takıldı? Buraya bak. |\n| [api.md](api.md) [unstable_api.md](unstable_api.md) | API hakkında her şey |\n| [history.md](history.md) | Değişikliklerin listesi |\n| [examples/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | Tüm mineflayer örnekleri |\n\n\n## Katkıda bulun\n\nKatkıda bulunmadan önce lütfen [CONTRIBUTING.md](CONTRIBUTING.md) ve [prismarine-contribute](https://github.com/PrismarineJS/prismarine-contribute) dosyalarını oku.\n\n## Kullanım\n\n**Videolar**\n\nBir botun temel kurulum sürecini açıklayan bir öğretici videoyu [burada](https://www.youtube.com/watch?v=ltWosy4Z0Kw) bulabilirsin.\n\nDaha fazlasını öğrenmek istersen [burada](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) öğretici videolar bulabilirsin. Videolarda kullanılan botların kaynak kodlarını da [şurada](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials) bulabilirsin.\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**Başlangıç**\n\nEğer sürüm belirtilmezse otomatik olarak ayarlanacaktır. Kimlik doğrulama türü belirtilmez ise de Mojang'ınki kullanılacaktır.\n\n### Papağan Örneği (bot dediklerinizi taklit eder)\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // sunucu IP adresi\n  username: 'email@example.com', // Minecraft kullanıcı adı / e-posta adresi\n  password: '12345678' // Minecraft şifresi, korsan sunucular için boş bırakabilirsin\n  // port: 25565,                // sadece port 25565 olmadığında kullan\n  // version: false,             // özellikle bir sürüm belirteceğin zaman burayı değiştirebilirsin\n  // auth: 'mojang'              // Microsoft kullanıyorsan 'microsoft' olarak değiştirebilirsin\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// Hataları ve sunucudan atılma sebeplerini konsola yansıt:\nbot.on('kicked', console.log)\nbot.on('error', console.log)\n```\n\n### Botunun ne yaptığını gör\n\n[prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) projesi sayesinde tarayıcı sekmende botunun ne yaptığını izleyebilirsin. Sadece `npm install prismarine-viewer` komutunu çalıştır ve şu kodu botuna ekle:\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // port: yayın yapılacak port, firstPerson: true yaparsan botun gözünden, false yaparsan kuş bakışı görüntü elde edersin.\n})\n```\nve şuna benzeyen *canlı* bir görüntü elde edeceksin:\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### Daha fazla örnek\n\n| Örnek | Açıklama |\n|---|---|\n|[viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | Botunu tarayıcında izle |\n|[pathfinder](https://github.com/PrismarineJS/mineflayer/tree/master/examples/pathfinder) | Botunun belirli bir yere gitmesini sağla |\n|[chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | Sandıkları, fırınları, fırlatıcıları ve büyü masalarını kullan |\n|[digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | Blok kazabilen bir botun nasıl yapılacağını öğren |\n|[discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | Discord ile bir mineflayer botunu bağla |\n|[jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | Nasıl hareket edebileceğini, zıplayabileceğini, taşıt kullanabileceğini, yakındaki canlılara saldırabileceğini öğren |\n|[ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | Sohbet mesajlarını bütün renkleri görecek şekilde konsoldan izle |\n|[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | Çevreyi etraftaki yaratıklardan koruyan bir bot yap |\n|[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | Birçok hesabın bulunduğu bir dosya kullanarak o hesaplarla botlar yap |\n\ndaha da fazlası [burada](https://github.com/PrismarineJS/mineflayer/tree/master/examples)\n\n### Modüller\n\nAktif geliştirmenin bir çoğu mineflayer tarafından kullanılan küçük npm paketlerinin içinde gerçekleşiyor.\n\n#### The Node Way&trade;\n\n> \"When applications are done well, they are just the really application-specific, brackish residue that can't be so easily abstracted away. All the nice, reusable components sublimate away onto github and npm where everybody can collaborate to advance the commons.\" — substack from [\"how I write modules\"](https://gist.github.com/substack/5075355)\n\n#### Modüller\n\nmineflayer'ın yapı taşları olarak kullanılan bazı modüller:\n\n| Modül | Açıklama |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | Minecraft packetlerini incelemeyi sağlayan bir modül\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | Minecraft hakkında bir veritabanı\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) | Minecraft canlılarının fizik motoru\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | Chunk bilgisini tutan bir modül\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | Güçlü birim testleri ile 3D vektör matematiği\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | Minecraft bloğunu verisi ile tanımlamaya yarayan modül\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | Minecraft sohbet ayrıştırıcı (mineflayer'dan alındı)\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Mojang'ın üyelik sistemiyle etkileşime geçebilmek için bir Node.js kütüphanesi\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | Prismarine dünyaların ana kütüphanesi\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | Minecraft pencereleri için bir yönetim kütüphanesi\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | Bir Minecraft eşyasını verileri ile tanımlamaya yarayan modül\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | node-minecraft-protocol için bir NBT ayrıştırıcı\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | Minecraft tarif kütüphanesi\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | Bir Minecraft biyomunu verileri ile tanımlamaya yarayan modül\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) | Bir Minecraft canlısını tanımlamaya yarayan modül\n\n\n### Hata ayıklama\n\nHata ayıklama çıktısı almak için `DEBUG` değişkenini kullanabilirsin:\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\nWindows:\n```\nset DEBUG=minecraft-protocol\nnode your_script.js\n```\n\n## 3. Parti Eklentiler\n\nmineflayer eklenti desteği sağlar; isteyen herkes mineflayer'ın üstüne daha da üst seviye bir API ekleyen bir eklenti yazabilir.\n\nEn çok güncellenen ve en kullanışlı olan bazıları:\n\n * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - konfigüre edilebilen tonlarca özellik ile gelişmiş A* yön bulma\n * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - basit tarayıcı chunk gösterici\n * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web bazlı envanter gösterici\n * [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - daha kompleks bot eventleri için bir API\n * [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - otomatik zırh düzenleyici\n * [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - basit ve hızlı bir blok toplama API'ı\n * [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - mineflayer botları için kontrol paneli\n * [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - PVP ve PVE için basit bir API\n * [auto-eat](https://github.com/LINKdiscordd/mineflayer-auto-eat) - otomatik yemek yeme\n * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - otomatik eşya seçimi için üst seviye bir API\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - yaylarla otomatik eğim için bir API\n\n\n Şunlara da göz at:\n\n * [radar](https://github.com/andrewrk/mineflayer-radar/) - canvas ve socket.io kullanan tarayıcı bazlı bir radar arayüzü. [YouTube Demo](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n * [blockfinder](https://github.com/Darthfett/mineflayer-blockFinder) - 3 boyutlu dünyada blok bulun\n * [scaffold](https://github.com/andrewrk/mineflayer-scaffold) - bir hedefe blok koyarak\n veya kırarak ulaşın [YouTube Demo](http://youtu.be/jkg6psMUSE0)\n * [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - sohbet-bazlı bot giriş sistemi\n * [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - başka bir varlığa gelen hasardan kimin ve neyin sorumlu olduğu hakkında bilgi alın\n * [tps](https://github.com/SiebeDW/mineflayer-tps) - tps değerini elde edin\n + [panorama](https://github.com/IceTank/mineflayer-panorama) - dünyanın panorama fotoğraflarını çekin\n\n## Mineflayer Kullanan Projeler\n\n * [rom1504/rbot](https://github.com/rom1504/rbot)\n   - [YouTube - spiral bir merdiven inşa etme](https://www.youtube.com/watch?v=UM1ZV5200S0)\n   - [YouTube - bir yapıyı taklit etme](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n * [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot)\n * [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - voxel.js ile \n botun ne yaptığını gör\n * [JonnyD/Skynet](https://github.com/JonnyD/Skynet) - bot aktivitesini online bir API'a gönder\n * [MinecraftChat](https://github.com/rom1504/MinecraftChat) (son açık kaynak sürümü, AlexKvazos tarafından yapıldı) - Minecraft internet tabanlı sohbet <https://minecraftchat.net/>\n * [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) - node-webkit ile yapılan eklenti bazlı, temiz bir arayüze sahip bir bot\n * [Chaoscraft](https://github.com/schematical/chaoscraft) - genetik algoritmalar kullanan bir Minecraft botu, [videoları burada](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n * [hexatester/minetelegram](https://github.com/hexatester/minetelegram) -  mineflayer & telegraf üstüne kurulu Minecraft - Telegram köprüsü\n * [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - Minecraft şemalarını hayatta kalma modunda inşa eden bir proje\n * [ve daha niceleri](https://github.com/PrismarineJS/mineflayer/network/dependents) - mineflayer kullanıyor olup GitHub tarafından tespit edilen tüm projeler.\n\n\n## Test etme\n\n### Her şeyi test etme\n\nBasitçe\n```bash\nnpm test\n```\n\nkomutunu çalıştırın\n\n### Özel bir sürümü test etme\n\n```bash\nnpm test -- -g <version>\n```\n\nkomutunu çalıştırın, `<version>` bir Minecraft sürümü olmalı (`1.12`, `1.15.2` gibi).\n\n### Özel bir şeyi test etme\n\n```bash\nnpm test -- -g <test_name>\n```\n\nkomutunu çalıştırın, `<test_name>` kısmının olduğu bölüm bir test adı olmalı (`bed`, `useChests`, `rayTrace` gibi).\n\n## Lisans\n[MIT](../../LICENSE)\n"
  },
  {
    "path": "docs/tutorial.md",
    "content": "# Tutorial\n\n**Table of Contents**\n\n- [Basics](#basics)\n  - [Javascript basics](#javascript-basics)\n    - [Installing Node](#installing-node)\n    - [Javascript variables](#javascript-variables)\n    - [Show output](#show-output)\n    - [Javascript functions](#javascript-functions)\n    - [Javascript types](#javascript-types)\n    - [If-statements](#if-statements)\n    - [Loops](#loops)\n    - [Node Package manager](#node-package-manager)\n  - [Creating a bot](#creating-a-bot)\n    - [Javascript objects](#javascript-objects)\n    - [Logging in](#logging-in)\n  - [Passing along functions](#passing-along-functions)\n  - [Listening for an event](#listening-for-an-event)\n  - [Promises](#promises)\n    - [Correct and incorrect approach](#correct-and-incorrect-approach)\n- [Advanced](#advanced)\n  - [Asynchronousy](#asynchronousy)\n  - [Loop over an object](#loop-over-an-object)\n  - [Creating an event from chat](#creating-an-event-from-chat)\n    - [Answer Hello Bot](#answer-hello-bot)\n    - [Custom Chat](#custom-chat)\n- [FAQ](#faq)\n  - [How to run a bot on android](#how-to-run-a-bot-on-android)\n    - [Install Termux](#install-termux)\n    - [Setup](#setup)\n    - [Start your bot](#start-your-bot)\n\n## Introduction\n\nThis tutorial will help you get started with Mineflayer, even if you know nothing about coding.  \nIf you already know some things about Node and NPM, you can go to the [Create a bot](#creating-a-bot) section, otherwise start here.\n\n## Basics\n\nThe following sections are about basics concepts you need to know to get started using Mineflayer.\n\n### Javascript basics\n\n#### Installing Node\n\nIn this section you will learn the basics about Javascript, Node and NPM.\n\nJavascript, often abbreviated to JS, is a programming language designed for the web. It is what makes most interactivity on the web possible.  \nNode.js, often just Node, makes it possible to use Javascript outside of web browsers.\n\nSo the first thing you have to do to get started is to install Node. You can get it [here](https://nodejs.org/en/download/).  \nAfter it is installed, open a command prompt (also known as a terminal) and then type `node -v`  \nIf you have installed Node correctly, it should return a version number. If it says it can't find the command, try installing it again.\n\nNow you have Node, you could start writing code, but we need to do 1 more thing.  \nJavascript can be written in any basic text editor, but it is much easier if you use what is called an [Integrated development environment](https://en.wikipedia.org/wiki/Integrated_development_environment)(IDE)  \nAn IDE will help you write code because it can give you suggestions, or tell you if your code has potential problems. A good IDE to start with is [Visual Studio Code](https://code.visualstudio.com/)(VSCode)  \nOnce you have installed and set-up VSCode, create a new file and then save it somewhere with a name ending with `.js`, e.g. `bot.js`  \nThis will let VSCode know we are working with Javascript, and give you the correct suggestions.\n\n#### Javascript variables\n\nStart by typing the following:\n\n```js\nconst test = 5\n```\n\nThis will create a new variable named `test` and assign it the value `5`  \nVariable are used to save data and use it later in the code.\n\nNow save the file so we can run the code. Open a terminal again (or a new terminal in VSCode) and navigate to the same folder the file is saved in. This can be done using the `cd` command, for example: `cd Documents\\javascript`  \nOnce your terminal is in the same folder as your Javascript file, you can run `node filename.js`  \nIf you have done everything correctly, you should see nothing.  \nIn the next chapter we will show you how you can 'print' things to the terminal.\n\nIn general, it is good practice to use the `const` keyword instead of the `let` keyword when defining a variable. A variable defined with `const` can't be modified later and thus is a constant.  \nJavascript is then able to make your code run more efficiently because it knows it doesn't have to account for value changes for that variable.  \nIf you want a modifiable variable, you will still have to use `let` of course.\n\n```js\nconst test = 5\n// eslint-disable-next-line\ntest = 10 // This line is invalid.\n```\n\nThe second line is invallid because you can't reassign the `test` variable.\n\nIf you want to help yourself and other people understand your code better, you can use comments.  \nComments can be created using `//` and everything after that is completely ignored by Javascript.\n\n#### Show output\n\nA lot of times you want to see the current value of a variable, to make sure your program is running correctly.  \nYou do this by printing the variables to the terminal.  \nIn Javascript, we can do this using the `console.log()` function.  \n\n```js\nconst test = 5\n\nconsole.log(test)\n```\n\nNow when you save and run this code, you should finally see something:\n\n```txt\n5\n```\n\n#### Javascript functions\n\nNext you will learn about functions. Functions are a piece of code that can be used multiple times throughout your code.  \nThese can be useful because you don't have to type something multiple times.\n\n```js\nconst addition = (a, b) => {\n  return a + b\n}\n\nconst test1 = addition(5, 10)\nconst test2 = addition(1, 0)\n\nconsole.log(test1)\nconsole.log(test2)\n```\n\nThe `=>` is used to define a function, called the arrow operator.  \nBefore the arrow operator is the parameter list, everything between the round brackets `()` are parameters, separated by a comma.  \nParameters are variables you can give to your function so that your function can work with them.  \nThen after the arrow operator comes the function body, this is everything between the curly brackets `{}`  \nThis is where you put the code of the function.  \nNow that the function is complete, we assign it to a variable to give it a name, in this case `addition`  \n\nAs you can see, this code takes the parameters `a` and `b` and adds them together.  \nThen the function will return the result.  \nWhen a function is defined, the code in the function body is not yet executed. To run a function you have to call it.  \nYou can call a function by using the name of a function followed by round brackets. In this case `addition()`  \nHowever, the `addition` function requires 2 parameters. These can be passed along by putting them inside the round brackets, comma separated: `addition(1, 2)`  \nWhen the function is done, you can imagine that the function call is replaced by whatever the function has returned. So in this case `let test1 = addition(5, 10)` will become `let test1 = result` (You will not actually see this, but this can help you understand the concept)\n\nSometimes you will come across the following: `function addition() {}` This means the same thing, although `() => {}` is preferred. (If you really want to know why, look up 'javascript function vs arrow function')\n\nThe above should output the following:\n\n```txt\n15\n1\n```\n\n#### Javascript types\n\nSo far we have only worked with numbers, but Javascript can work with more variable types:\n\n- A string is a piece of text that can contain multiple characters. Strings are defined by using the quotes `''`\n\n```js\nconst string = 'This is a string' // string type\n```\n\n- An array is a type that can hold multiple variables inside itself. Arrays are defined by using the square brackets `[]`\n\n```js\nconst array = [1, 2, 3] // array type\n```\n- Object are basically advanced arrays, you will learn more about it later in this tutorial. Their defined by curly brackets `{}`\n\n```js\nconst object = {} // object type\n```\n\n- Functions are also their own type.\n\n```js\nconst adder = (a, b) => { return a + b } // function type\n```\n\n- A boolean is a type that can only be `true` or `false`\n\n```js\nconst boolean = true // boolean type\n```\n\n- When something is not (yet) defined, its type is `undefined`\n\n```js\nlet nothing // undefined type\nconst notDefined = undefined // undefined type\n```\n\n#### If-statements\n\nSometimes you want to do different things based on a certain condition.  \nThis can be achieved using if-statements.\n\n```js\nconst name = 'Bob'\n\nif (name === 'Bob') {\n  console.log('Your name is Bob')\n} else if (name === 'Alice') {\n  console.log('Your name is Alice')\n} else {\n  console.log('Your name is not Bob or Alice')\n}\n```\n\nAn if-statement is created using the `if` keyword. After that you have a condition between the round brackets `()` followed by the body between the curly brackets `{}`\nA condition has to be something that computes to a boolean.  \nIn this case it uses an equal operator `===` which will be `true` if the value in front is the same as the value after. Otherwise it will be `false`\nIf the condition is `true` the code in the body will be executed.  \nYou can chain an if-statement with an else-if-statement or an else-statement.  \nYou can have as many else-if-statements as you want, but only 1 if and else statement.  \nIf you have an else-statement, it will be called only if all the chained statements before it are `false`\n\n#### Loops\n\nLoops are used to repeat certain code until a certain conditional is met.\n\n```js\nlet countDown = 5\n\nwhile (countDown > 0) {\n  console.log(countDown)\n  countDown = countDown - 1 // Decrement countDown by 1\n}\n\nconsole.log('Finished!')\n```\n\nThe above code will print the following\n\n```txt\n5\n4\n3\n2\n1\nFinished!\n```\n\nThe `while` loop has a condition `()` and a body `{}`  \nWhen the code reaches the loop, it will check the condition. If the condition is `true`, the code in the body will be executed.  \nAfter the end of the body is reached, the condition is checked again, and if `true`, the body executed again.  \nThis will happen for as long as the condition check is still `true`  \nEach loop, this code prints the current `countDown` number, and then decrements it by 1.  \nAfter the 5th loop, the condition `0 > 0` will be `false`, and thus the code will move on.\n\nA `for` loop is also often used, and differs slightly from a `while` loop.  \n\n```js\nfor (let countDown = 5; countDown > 0; countDown = countDown - 1) {\n  console.log(countDown)\n}\n```\n\nInstead of only a condition, the for loops has 3 different parts  \nThese parts are separated by a semi-column.  \nThe first parts `let countDown = 5` is only executed once, at the start of the loop.  \nThe second part `countDown > 0` is the condition, this is the same as the while loop.  \nThe third part `countDown = countDown - 1` is executed after each loop.:\n\nIf you want to do something for every item in an array, a `for of` loop can be useful.  \n\n```js\nconst array = [1, 2, 3]\n\nfor (const item of array) {\n  console.log(item)\n}\n```\n\nA `for of` loop needs to have a variable before the `of`, this is the variable that can be used to access the current item.  \nThe variable after the `of` needs to be something that contains other variable. These are mostly arrays, but also some objects.  \nThe loop will execute the body for each item in the `array` and each loop the `item` variable will be the current item of the `array`\n\n#### Node Package manager\n\nThe last thing you need to know is how to use the [Node Package Manager](https://www.npmjs.com/).  \nNPM is automatically installed when you install Node.  \nNPM is used to get useful packages that other people created that can do useful things for you.  \nYou can search for packages on [their website](https://www.npmjs.com/), and then install them using the `npm install` command in your terminal.  \nTo install Mineflayer for example, run `npm install mineflayer`  \n\nThen, Node can access installed modules by using the `require()` function.\n\n```js\nconst mineflayer = require('mineflayer')\n```\n\nAfter this, the `mineflayer` variable can be used to access all the features of Mineflayer.\n\n### Creating a bot\n\nNow that you know the basics of Javascript, Node and NPM, you're ready to start creating your first bot!  \nIf you don't know any of the terms above, you should go back to the [previous section](#javascript-basics)\n\nBelow is the absolute minimum necessary to create a Mineflayer bot.\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot()\n```\n\nIf you run this example, you'll notice that your program will not stop. If you want to stop your currently running program, press `Ctrl` + `c`  \nHowever, this bot isn't quite useful, as by default this will connect to a Minecraft server running on your machine with the port 25565.  \nIf you want to choose which server you want your bot to connect to, you have to pass along a few options.\n\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst options = {\n  host: 'localhost', // Change this to the ip you want.\n  port: 25565 // Change this to the port you want.\n}\n\nconst bot = mineflayer.createBot(options)\n```\n\n#### Javascript objects\n\nThe curly brackets `{}` are used to create an object.  \nObjects contain what is called a key-value pair.  \nA key-value pair consist of a colon `:` and a key before the colon, and the value of that key after the colon.  \nThe keys can then be used to retrieve their value.  \nYou can have multiple key-value pairs by separating them by commas.\n\n```js\nconst object = {\n  number: 10,\n  another: 5\n}\n\nconsole.log(object.number) // This will print the value 10\n```\n\nThis concept is often used to create what is named 'named parameters'  \nThe advantage of this is that you don't have to use all the options available, and their position does not matter.  \nThe value can be anything, even other object. If the value is a function, that function is often called a method for that object.  \nYou can also create the object in-line.\n\n```js\nconst bot = mineflayer.createBot({ host: 'localhost', port: 25565 })\n```\n\n#### Logging in\n\nWithout any parameters, the bot will have the name `Player` and can only log into offline servers. (Cracked & open-to-lan)  \nIf you supply the `createBot` with an `username` option, it will log in with that username. (Still only in offline server)  \nTo log into a specific account, you have to supply both the `username` and the `password`\n\n```js\nconst bot = mineflayer.createBot({\n  host: 'localhost',\n  port: 25565,\n  username: 'Player',\n  password: 'password'\n})\n```\n\n#### Command line arguments\n\nWhat if somebody else likes your bot and wants to use it, but uses it on a different server and with a different account?  \nThis means that everyone has to change the server address and login settings to their preference. (And it's of course also a bad idea to share your password)  \nTo counter this, a lot of people use command line arguments.\n\n```js\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4],\n  password: process.argv[5]\n})\n```\n\nAs you can see, no more sensitive data in your code! But now, how do you run it?  \nNow, instead of starting your program with just `node filename.js` you start it with `node filename.js host port username password`  \nNode will automatically split the whole command line into an array, separated by spaces.  \nThis array is `process.argv`  \nThe data in an array can be accessed using the index of each item. The index always start at 0, so the first item can be accessed with `[0]` and in this case will be `node` etc.\n\n| | First item | Second item | Third Item | Fourth item | Fifth item | Sixth item |\n| --- | :---: | :---: | :---: | :---: | :---: | :---: |\n| Value | `node` | `filename.js` | `host` | `port` | `username` | `password` |\n| Index | `[0]` | `[1]` | `[2]` | `[3]` | `[4]` | `[5]`\n\n### Passing along functions\n\nNot only basics variables like numbers and strings can be given as an argument.  \nFunctions can also be passed as a variable.\n\n```js\nconst welcome = () => {\n  bot.chat('hi!')\n}\n\nbot.once('spawn', welcome)\n```\n\nAs you can see, the `bot.once()` method takes 2 parameters.  \nThe first parameter is an event name, the second parameter is the function to call when that event happens.  \nRemember, when passing along a function, only use the name and not the round brackets `()`\n\n`bot.chat()` is the method for sending message to the chat.\n\nYou can also simplify this code by using a anonymous function.  \nAn anonymous function doesn't have a name, and is created at the position where the function name used to go.  \nThey still have to have a parameter list `()` and a function body `{}`, even if it isn't used.\n\n```js\nbot.once('spawn', () => {\n  bot.chat('hi!')\n})\n```\n\n### Listening for an event\n\nThe bot object has many useful [events](http://prismarinejs.github.io/mineflayer/#/api?id=events).\nYou can listen for an event by using either `bot.on()` method or `bot.once()` method of the bot object, which takes the name of an event and a function.\nTo remove specific listener you can use `bot.removeListener()` method.\n\n- `bot.on(eventName, listener)`\n  Execute the `listener` function for each time the event named `eventName` triggered.\n- `bot.once(eventName, listener)`\n  Execute the `listener` function, only once, the first time the event named `eventName` triggered.\n- `bot.removeListener(eventName, listener)`\n  Removes the specified `listener` for the event named `eventName`. In order to use this you either need to define your function with `function myNamedFunc() {}` or put your function in a variable with `const myNamedFunc = () => {}`. You can then use `myNamedFunc` in the listener argument.\n\nNot only bot object, [`Chest`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerchest), [`Furnace`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerfurnace), [`Dispenser`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerenchantmenttable), [`Villager`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayervillager) object also have their own events!\n\n### Promises\nA [promise](https://nodejs.dev/learn/understanding-javascript-promises) is a function that you can use the `await` variable to wait on until it's job is complete. (you can omit the await to not wait for results)\n\n```js\nasync function consume (bot) {\n  try {\n    await bot.consume()\n    console.log('Finished consuming')\n  } catch (err) {\n    console.log(error)\n  }\n}\n```\n\nThe above code will try to consume what the bot is currently holding.  \nWhen the consuming ends, the function that is passed along is called.  \nWe can then do other things that we want to do after.  \nThe function could also be called when an error occurs.\n\n#### Correct and incorrect approach\n\nBelow is an example of a bot that will craft oak logs into oak planks and then into sticks.\n\nIncorrect approach ❌:\n\n```js\nfunction craft (bot) {\n  const mcData = require('minecraft-data')(bot.version)\n  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0] // Get the first recipe for oak planks\n  bot.craft(plankRecipe, 1) // ❌ start crafting oak planks.\n\n  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0] // Get the first recipe for sticks\n  bot.craft(stickRecipe, 1) // ❌ start crafting sticks.\n}\n```\n\nCorrect approach with promises ✔️:\n\n```js\nasync function craft (bot) {\n  const mcData = require('minecraft-data')(bot.version)\n  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0]\n  await bot.craft(plankRecipe, 1, null)\n  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0]\n  await bot.craft(stickRecipe, 1, null)\n  bot.chat('Crafting Sticks finished')\n}\n```\n\nThe reason the incorrect approach is wrong is because when `bot.craft()` is called, the code will continue below while the bot is crafting.  \nBy the time the code reaches the second `bot.craft()`, the first probably hasn't finished yet, which means the wanted resource is not available yet.  \nUsing promises can fix this because they will only be called after the `bot.craft()` is finished.\n\nMore on the [bot.craft()](https://github.com/PrismarineJS/mineflayer/blob/master/docs/api.md#botcraftrecipe-count-craftingtable) method.\n\n## Advanced\n\nThe following concepts aren't necessary to create a Mineflayer bot, but they can be useful to understand and create more advanced bots.  \nWe assume you have understood the [Basics](#basics) tutorial.\n\n### Loop over an object\n\nThe `for of` loop described in the [loops](#loops) chapter can also be used to loop over an object.\n\nIf we have the following object:\n\n```js\nconst obj = {\n  a: 1,\n  b: 2,\n  c: 3\n}\n```\n\nThe following will loop over all the values of the object.\n\n```js\nfor (const value of Object.values(obj)) {\n  console.log(value)\n}\n```\n\n```txt\n1\n2\n3\n```\n\nThis will loop over all the keys of the object.\n\n```js\nfor (const key of Object.keys(obj)) {\n  console.log(key)\n}\n```\n\n```txt\na\nb\nc\n```\n\nYou can also loop over the keys and values at the same time. You will have to destructure the variables first, explained [here.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)\n\n```js\nfor (const [key, value] of Object.entries(obj)) {\n  console.log(key + ', ' + value)\n}\n```\n\n```txt\na, 1\nb, 2\nc, 3\n```\n\nThese loops are possible because `Object.values(obj)` and `Object.keys(obj)` both return an array of the objects values and keys respectively.  \n`Object.entries(obj)` returns an array where each item is an array with 2 items: a key and its corresponding value.  \nIt's important to know that, unlike the `Object.values()` and `Object.keys()` functions, the `Object.entries()` function does not guarantee that the order is the same as the order when the object was defined.\n\nThere is also a `for in` loop. However, you will most often want to use `for of` instead of `for in` because there are key differences.  \nThe `for in` loop loops over the keys of an object instead of the values. (The index in case it is an array)\nHowever, it doesn't loop only over its own keys, but also keys from other object it 'inherits' from, which can be confusing or unwanted. More on this [here.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in)\nIn general, you'll want to use `for of` instead of `for in` so make sure you don't confuse the two.\n\n### Creating an event from chat\n\nYou can create your own event from chat using [`bot.addChatPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botaddchatpatternname-pattern-chatpatternoptions) method. Useful for Bukkit servers where the chat format changes a lot.\n[`bot.addChatPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botaddchatpatternname-pattern-chatpatternoptions) method takes three arguments :\n\n- `pattern` - regular expression (regex) to match chat\n- `chatType` - the event the bot emits when the pattern matches. e.g. \"chat\" or \"whisper\"\n- `description` - Optional, describes what the pattern is for\n\nYou can add [Groups and Range](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges) into the `pattern`, then the listener will spread the captured groups into arguments of your callback sequentially.\n\nRead more about [regular expression](https://en.wikipedia.org/wiki/Regular_expression).\n\nExamples :\n\n#### Answer Hello Bot\n\nHere we're creating a bot that answer 'hello' from the other player.\n\n```js\nbot.addChatPattern(\n  'hello',\n  /(helo|hello|Hello)/,\n  'Someone says hello'\n)\n\nconst hi = () => {\n  bot.chat('Hi!')\n}\n\nbot.on('chat:hello', hi)\n```\n\n#### Custom chat\n\nCreating an event based on custom chat format.  \nCustom chat example:\n\n```txt\n[Player] Player1 > Hello\n[Admin] Alex > Hi\n[Player] Player2 > Help me, im stuck\n[Mod] Jim > On my way\n```\n\n```js\nbot.addChatPattern(\n  /^\\[(.+)\\] (\\S+) > (.+)$/,\n  'my_chat_event',\n  'Custom chat event'\n)\n\nconst logger = (rank, username, message) => {\n  console.log(`${username} said ${message}`)\n}\n\nbot.on('my_chat_event', logger)\n```\n\nExplanation on the regex `^\\[(.+)\\] (\\S+) > (.+)$` can be found [here](https://regex101.com/r/VDUrDC/2).\n\n## FAQ\n\n### How to run a bot on android\n\nHere is a quick setup for running a bot on an android device using [Termux](https://termux.com/).\n\n#### Install Termux\n\nInstall [Termux](https://termux.com/) and start it.\n\n#### Setup\n\nInstall `Node.js`:\n\n```bash\npkg update -y\npkg install nodejs -y\n```\n\n❗️ Allow Storage permission for Termux on app settings.\nCreate new folder on internal storage :\n\n```bash\ncd /sdcard\nmkdir my_scripts\ncd my_scripts\n```\n\nInstall `mineflayer`:\n\n```bash\nnpm install mineflayer\n```\n\nNow you can copy / store all of your scripts into `my_scripts` folder inside Internal Storage.\n\n#### Start your bot\n\nTo start the bot, run Node with the name of your script.\n\n```bash\nnode script_name.js\n```\n\n❗️ For each time opening Termux you must change the cwd into `/sdcard/my_scripts`, before starting the bot:\n\n```bash\ncd /sdcard/my_scripts\n```\n"
  },
  {
    "path": "docs/unstable_api.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [unstable API : bot._](#unstable-api--bot_)\n  - [bot._client](#bot_client)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# unstable API : bot._\n\nThese methods and classes are useful in some special cases but are not stable and can change at any moment.\n\n## bot._client\n\n`bot._client` is created using [node-minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol).\nIt handles writing and reading packet.\nIts behaviour can change (for example at each new minecraft version) so it's better to use mineflayer methods if possible."
  },
  {
    "path": "docs/update_to_1_21_5.md",
    "content": "# Mineflayer 1.21.5 Support Plan\n\n## 🚩 Latest Progress (July 2025)\n\n- ✅ **Chunk loading/parsing is now fixed** in both `node_modules` and the local `prismarine-chunk` repo. The fix was applied to `PaletteChunkSection.js` and `BitArrayNoSpan.js`.\n- 🔗 **Local development uses `npm link` to the local prismarine-chunk repo** for immediate testing of fixes.\n- 🛠️ **BitArrayNoSpan.js** now validates the buffer size and logs a warning if it is invalid (e.g., Infinity), preventing crashes.\n- 🤖 **The bot can now spawn and interact with the world** in 1.21.5. Chunk parsing errors are resolved.\n- ✅ **12 tests pass** for 1.21.5, confirming core protocol and chunk logic is working.\n- ❌ **4 tests fail**, but these are due to higher-level Mineflayer/game logic (timeouts, creative set slot, etc.), not chunk/protocol errors.\n- 🚧 **Current blockers:**\n  - Creative set slot protocol changes (UntrustedSlot)\n  - declare_commands packet parsing (PartialReadError)\n\n---\n\n## Current Status\n\nAs of July 2025, Mineflayer has partial 1.21.5 support with several critical issues remaining. The version is already listed in `testedVersions` but tests are failing due to protocol changes in 1.21.5.\n\n## Key Issues Identified\n\nBased on the analysis of pull requests and issues, the main problems for 1.21.5 support are:\n\n### 1. Chunk Protocol Changes (✅ FIXED)\n- **Issue**: Network has small changes to chunk format where size is now auto-computed to save a byte\n- **Status**: **RESOLVED** - Fixed size computation formula in prismarine-chunk\n- **Fix Applied**: Changed from `Math.ceil(constants.BLOCK_SECTION_VOLUME * bitsPerValue / 64)` to `Math.ceil(constants.BLOCK_SECTION_VOLUME / Math.floor(64 / bitsPerValue))`\n- **Impact**: Chunk loading now works correctly for 1.21.5\n- **Files Modified**: \n  - `prismarine-chunk/src/pc/common/PaletteContainer.js` (both DirectPaletteContainer and IndirectPaletteContainer)\n- **Dependencies**: Updated package.json to point to fixed prismarine-chunk branch\n\n### 2. Creative Set Slot Packet Behavior\n- **Issue**: Creative set slot packet behavior is the main breaking change (not working right now)\n- **Status**: Critical issue affecting creative mode functionality\n- **Impact**: `bot.creative.setInventorySlot()` fails\n- **Location**: `lib/plugins/creative.js`\n\n### 3. Item Format Changes\n- **Issue**: New concepts of hashed items and unsecure items (related to components)\n- **Status**: Protocol changes need investigation\n- **Impact**: Item handling and inventory management\n- **Dependencies**: minecraft-data and minecraft-protocol updates needed\n\n### 4. Entity Metadata Changes\n- **Issue**: Entity metadata may have changed\n- **Status**: Could cause issues with various listeners in mineflayer\n- **Impact**: Entity tracking and interaction\n- **Location**: `lib/plugins/entities.js`\n\n## Detailed Action Plan\n\n### Phase 1: Dependency Updates and Investigation\n\n#### 1.1 Investigate Chunk Protocol Issues\n- **Task**: Manually dump and decode chunk packets to understand the new format\n- **Tools**: Use packet analyzers or debug tools\n- **Expected Outcome**: Identify exact changes in chunk size computation\n- **Files to Modify**: `lib/plugins/blocks.js` (chunk handling)\n\n#### 1.2 Analyze Creative Set Slot Issues\n- **Task**: Debug creative set slot packet failures\n- **Method**: Compare packet structure between 1.21.4 and 1.21.5\n- **Files to Modify**: `lib/plugins/creative.js`\n- **Test**: `test/externalTests/creative.js`\n\n### Phase 2: Protocol Implementation\n\n#### 2.1 Fix Chunk Loading\n```javascript\n// In lib/plugins/blocks.js\n// Update chunk loading logic to handle auto-computed size\nbot._client.on('map_chunk', (packet) => {\n  // Handle new chunk format with auto-computed size\n  // May need to adjust data parsing based on new format\n})\n```\n\n#### 2.2 Fix Creative Set Slot\n```javascript\n// In lib/plugins/creative.js\n// Update setInventorySlot to handle new packet format\nasync function setInventorySlot (slot, item, waitTimeout = 400) {\n  // Investigate and fix packet structure changes\n  // May need new packet format or different handling\n}\n```\n\n#### 2.3 Update Item Handling\n```javascript\n// In lib/plugins/inventory.js\n// Handle new hashed items and unsecure items concepts\n// Update Item.fromNotch and Item.toNotch methods\n```\n\n#### 2.4 Fix Entity Metadata\n```javascript\n// In lib/plugins/entities.js\n// Update entity metadata parsing for 1.21.5 changes\nbot._client.on('entity_metadata', (packet) => {\n  // Handle new metadata format\n})\n```\n\n### Phase 3: Testing and Validation\n\n#### 3.1 Create 1.21.5 Specific Tests\n```javascript\n// Add to test/externalTests/\n// Create tests that specifically validate 1.21.5 functionality\n```\n\n#### 3.2 Update Existing Tests\n- **Task**: Fix failing tests for 1.21.5\n- **Focus**: Creative mode, chunk loading, entity handling\n- **Method**: Run `npm run mocha_test -- -g \"mineflayer_external 1.21.5v\"`\n\n#### 3.3 Manual Testing\n- **Task**: Test core functionality manually\n- **Areas**: World loading, inventory management, entity interaction\n- **Tools**: Use examples in `examples/` directory\n\n### Phase 4: Documentation and Cleanup\n\n#### 4.1 Update Documentation\n- **Task**: Update README and API docs for 1.21.5\n- **Files**: `docs/README.md`, `docs/api.md`\n- **Content**: Document any new features or breaking changes\n\n#### 4.2 Update Version Support\n- **Task**: Ensure 1.21.5 is properly listed as supported\n- **Files**: `lib/version.js`, `package.json`\n\n## Analysis of Current Fix Status\n\n### ✅ **Good News: Fix Already Implemented**\nThe [prismarine-chunk PR #289](https://github.com/PrismarineJS/prismarine-chunk/pull/289/files) has already implemented the 1.21.5 chunk protocol fix:\n\n**Key Changes in PR #289:**\n1. **Added `noSizePrefix` detection**: Uses `mcData.version['>=']('1.21.5')` to detect 1.21.5+\n2. **Modified chunk reading**: All palette containers now handle the `noSizePrefix` option\n3. **Dynamic size computation**: When `noSizePrefix` is true, size is computed as `Math.ceil(constants.BLOCK_SECTION_VOLUME * bitsPerValue / 64)`\n\n### 🔍 **Current Status Check**\nMineflayer is already using the experimental branches:\n- `prismarine-chunk`: `extremeheat/prismarine-chunk#pc1.21.5` ✅\n- `minecraft-protocol`: `extremeheat/node-minecraft-protocol#pcp1.21.5` ✅\n\n### ✅ **Chunk Loading Issue RESOLVED**\n**FIXED**: The chunk loading issue has been resolved by correcting the size computation formula.\n\n**Root Cause Analysis:**\n1. ✅ **Fix is implemented**: `noSizePrefix` detection and logic is present in the code\n2. ✅ **Version detection works**: `mcData.version['>=']('1.21.5')` returns `true` correctly\n3. ✅ **Size computation fixed**: Changed from `Math.ceil(constants.BLOCK_SECTION_VOLUME * bitsPerValue / 64)` to `Math.ceil(constants.BLOCK_SECTION_VOLUME / Math.floor(64 / bitsPerValue))`\n4. ✅ **Buffer reading works**: No more \"Target offset is beyond the bounds of the internal SmartBuffer data\" errors\n\n**The Solution:**\nThe issue was in the `readBuffer` method in `PaletteContainer.js`. The formula needed to calculate the number of longs based on the actual BitArray logic used in the constructor.\n\n## Current Test Status\n\n### ✅ **Chunk Loading Fixed**\n- **Status**: Chunk loading now works correctly for 1.21.5\n- **Evidence**: No more \"Target offset is beyond the bounds of the internal SmartBuffer data\" errors\n- **Next**: Focus on remaining test failures\n\n### 🚨 **New Test Failures Identified**\nAfter fixing chunk loading, new issues emerged:\n\n1. **Test Setup Timeout**: \"Event message did not fire within timeout of 5000ms\" in \"before each\" hook for \"bed\"\n2. **Server Shutdown Issues**: \"Server shutdown took too long. Killing process.\"\n3. **Potential Protocol Changes**: Other 1.21.5 protocol changes may be affecting test functionality\n\n## Next Priority Issues\n\n### 1. **Investigate Test Setup Failures** (High Priority)\n- **Issue**: Tests are timing out during setup phase\n- **Location**: `test/externalTests/plugins/testCommon.js:127:21` - `clearInventory` function\n- **Possible Causes**: \n  - Creative set slot packet changes\n  - Inventory protocol changes\n  - Entity metadata changes\n\n### 2. **Debug Creative Set Slot** (High Priority - PROTOCOL CHANGE IDENTIFIED)\n- **Issue**: Creative mode functionality broken due to protocol change\n- **Location**: `lib/plugins/creative.js`\n- **Test**: `test/externalTests/creative.js`\n- **Root Cause**: `set_creative_slot` packet changed from `Slot` to `UntrustedSlot` type\n- **Key Changes**:\n  - **1.21.4**: `packet_set_creative_slot.item` type: `Slot`\n  - **1.21.5**: `packet_set_creative_slot.item` type: `UntrustedSlot`\n  - `UntrustedSlot` has `present` boolean field first\n  - Uses `UntrustedSlotComponent` instead of `SlotComponent`\n  - New component system with `addedComponentCount` and `removedComponentCount`\n- **Files to Modify**: `lib/plugins/creative.js` (creative set slot handling)\n\n### 3. **Check Item Format Changes** (Medium Priority - PROTOCOL CHANGES IDENTIFIED)\n- **Issue**: New hashed items and unsecure items concepts\n- **Location**: `lib/plugins/inventory.js`\n- **Impact**: Item handling and inventory management\n- **Protocol Changes Found**:\n  - **New `vec3i` type**: Added for 3D integer vectors\n  - **Item component system**: New component-based item system\n  - **Component reordering**: Item component IDs have been reordered (e.g., `hide_additional_tooltip` → `tooltip_display`)\n  - **New components**: Added `blocks_attacks`, `weapon` components\n  - **Entity metadata**: `item_stack` type still uses `Slot` but may have component changes\n\n### 4. **Entity Metadata Changes** (Medium Priority - MINIMAL CHANGES)\n- **Issue**: Entity metadata format changes\n- **Location**: `lib/plugins/entities.js`\n- **Impact**: Entity tracking and interaction\n- **Protocol Analysis**: \n  - **Good news**: `entity_metadata` packet structure unchanged\n  - **Good news**: `item_stack` type in metadata still uses `Slot` (not `UntrustedSlot`)\n  - **Minimal impact**: Entity metadata changes appear to be minimal for 1.21.5\n\n## Protocol Analysis Summary\n\nBased on the [minecraft-data PR #1029](https://github.com/PrismarineJS/minecraft-data/pull/1029/files) analysis, here are the key protocol changes for 1.21.5:\n\n### 🔥 **Critical Changes (Blocking Issues)**\n\n1. **Creative Set Slot Packet**:\n   - **Change**: `packet_set_creative_slot.item` type changed from `Slot` to `UntrustedSlot`\n   - **Impact**: Creative mode inventory management completely broken\n   - **Fix Required**: Update `lib/plugins/creative.js` to handle `UntrustedSlot` format\n\n2. **New Packet Types**:\n   - **Added**: `set_test_block` (0x39) and `test_instance_block_action` (0x3c)\n   - **Impact**: May affect block interaction tests\n\n### 📦 **Item System Changes**\n\n1. **Component System**:\n   - **New**: `UntrustedSlot` with component-based system\n   - **Components**: `addedComponentCount`, `removedComponentCount`, `UntrustedSlotComponent`\n   - **Impact**: Item serialization/deserialization needs updates\n\n2. **Component Reordering**:\n   - **Changed**: Component IDs reordered (e.g., `hide_additional_tooltip` → `tooltip_display`)\n   - **Added**: New components like `blocks_attacks`, `weapon`\n\n### 🎯 **Minimal Impact Changes**\n\n1. **Entity Metadata**: \n   - **Status**: Unchanged - still uses `Slot` for `item_stack`\n   - **Impact**: Minimal - no changes needed\n\n2. **New Types**:\n   - **Added**: `vec3i` type for 3D integer vectors\n   - **Impact**: May be used in new packets but not critical\n\n## Implementation Steps\n```bash\ncd /media/documents/Documents/programmation/interlangage/minecraft/mineflayer\nnpm install\n```\n\n### Step 2: Run Current Tests\n```bash\n# Test current 1.21.5 status\nnpm run mocha_test -- -g \"mineflayer_external 1.21.5v\"\n```\n\n### Step 3: Investigate Specific Issues\n```bash\n# Debug chunk loading\nDEBUG=\"minecraft-protocol\" npm run mocha_test -- -g \"mineflayer_external 1.21.5v.*blocks\"\n\n# Debug creative mode\nnpm run mocha_test -- -g \"mineflayer_external 1.21.5v.*creative\"\n```\n\n### Step 4: Implement Fixes\n1. Start with chunk protocol fixes\n2. Fix creative set slot issues\n3. Update item handling\n4. Fix entity metadata\n\n### Step 5: Validate Fixes\n```bash\n# Run all 1.21.5 tests\nnpm run mocha_test -- -g \"mineflayer_external 1.21.5v\"\n\n# Run specific functionality tests\nnpm run mocha_test -- -g \"mineflayer_external 1.21.5v.*inventory\"\nnpm run mocha_test -- -g \"mineflayer_external 1.21.5v.*entities\"\n```\n\n## Success Criteria\n\n1. All 1.21.5 tests pass\n2. Core functionality works (world loading, inventory, entities)\n3. Creative mode functions properly\n4. No regressions in other versions\n5. Documentation is updated\n\n## Risk Mitigation\n\n1. **Backward Compatibility**: Ensure fixes don't break older versions\n2. **Incremental Testing**: Test each fix individually\n3. **Fallback Mechanisms**: Implement fallbacks for protocol changes\n4. **Version Detection**: Use `bot.supportFeature()` for version-specific code\n\n## Resources Needed\n\n1. **Minecraft 1.21.5 Server**: For testing\n2. **Packet Analyzer**: For debugging protocol changes\n3. **Documentation**: Minecraft 1.21.5 protocol changes\n4. **Time**: 1-2 weeks of focused development\n\n## Contributing Guidelines\n\nFor anyone wanting to contribute to 1.21.5 support:\n\n1. **Read the Documentation**: `docs/llm_contribute.md` and `docs/README.md`\n2. **Understand the Test System**: `test/externalTests/`\n3. **Focus on One Issue**: Pick one specific problem to solve\n4. **Test Thoroughly**: Run tests for multiple versions\n5. **Document Changes**: Update relevant documentation\n\n## Updated Timeline\n\n- **Phase 1**: ✅ COMPLETED (chunk protocol fix)\n- **Phase 2**: 2-3 days (investigate and fix test setup failures)\n- **Phase 3**: 2-3 days (fix creative set slot and other protocol issues)\n- **Phase 4**: 1-2 days (testing and validation)\n- **Phase 5**: 1 day (documentation and cleanup)\n\n**Total Estimated Time**: 6-9 days remaining\n\n**Note**: Chunk loading is now fixed! Focus is on remaining protocol changes and test failures.\n\n## References\n\n- [PrismarineJS/prismarine-chunk#289](https://github.com/PrismarineJS/prismarine-chunk/pull/289)\n- [PrismarineJS/mineflayer#3691](https://github.com/PrismarineJS/mineflayer/pull/3691)\n- [PrismarineJS/mineflayer#3641](https://github.com/PrismarineJS/mineflayer/issues/3641)\n- [PrismarineJS/minecraft-data#1029](https://github.com/PrismarineJS/minecraft-data/pull/1029)\n- [PrismarineJS/node-minecraft-protocol#1408](https://github.com/PrismarineJS/node-minecraft-protocol/pull/1408) "
  },
  {
    "path": "docs/zh/CONTRIBUTING.md",
    "content": "# 贡献\n\nMineflayer 最初主要是由 [andrewrk](http://github.com/andrewrk) 制作的\n但自那以后，许多[贡献者](https://github.com/andrewrk/mineflayer/graphs/contributors)对其进行了改进和修复 \n所以知道如何为mineflayer做出贡献的最佳方式很重要\n\n## Issue organization\n\n我们有3个阶段标签来尝试组织Issue:\n\n* Stage 1: 只是由项目新手创建的，我们还不知道它是否值得实现/修复\n* Stage 2: 有希望的想法，但在实施前需要更多思考\n* Stage 3: 想法被精确地指定了，就剩写代码了\n\n链接如 https://github.com/PrismarineJS/mineflayer/issues?q=is%3Aopen+is%3Aissue+-label%3AStage1 can be used to filter out stage 1 if you're looking for things that are ready for contribution\n\n## 创建测试\nMineflayer 有两种测试 :\n\n * [internal tests](test/internalTest.js) : 针对使用node-minecraft-protocol创建的简单服务器进行的测试\n * [external tests](test/externalTests/) : 针对原版服务器进行的测试\n\nThe objective of these tests is to know automatically what works and what doesn't in mineflayer, so it's easier to make mineflayer work.\n\n### 创建外部测试\n\nIn order to add an external test now you only need to create a file in [test/externalTests](test/externalTests)\n\n一个例子 : [test/externalTests/digAndBuild.js](https://github.com/PrismarineJS/mineflayer/blob/master/test/externalTests/digAndBuild.js)\n\nThat file needs to export a function returning a function or an array of function taking as parameter the bot object and a done callback,\n it should contain asserts to test if the tested functionality failed.\n\n\n## 创建第三方插件\nMineflayer 是可扩展的插件化的； 任何人都可以创建一个插件，在 Mineflayer 之上添加更高级别的 API。\n\n已经开发了几个这样的第三方插件 [查看](https://github.com/andrewrk/mineflayer#third-party-plugins)\n\n为了创建一个新的，您需要 :\n\n1. 创建一个新的 repo\n2. 在你的 index.js 文件中, 导出一个接受参数 mineflayer 的 init 函数 ([查看例子](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L18))\n3. that function returns a inject function taking in argument the bot object ([example](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L23))\n4. that inject function add functionalities to the bot object ([example](https://github.com/andrewrk/mineflayer-navigate/blob/e24cb6a868ce64ae43bea2d035832c15ed01d301/index.js#L32))\n\nSince the mineflayer object is passed in parameter, that new package doesn't need to depend on mineflayer (no mineflayer dependency in the package.json)\n\n参考 [全部示例](https://github.com/andrewrk/mineflayer-navigate/tree/e24cb6a868ce64ae43bea2d035832c15ed01d301) \n\n## 反馈Bug\nMineflayer 在大多数情况下都能很好地工作，但有时仍然存在bug.\n\n找到一个问题时，最好报告一个提供这些信息的问题 :\n\n* 你想做什么 (英语目标)\n* 你尝试过什么 (代码)\n* 发生了什么事\n* 你期望会发生什么\n\n## Mineflayer 代码\n提交请求或提交提交时需要考虑的一些事情 :\n\n### 错误处理\n在大多数情况下，mineflayer不会让机器人崩溃。即使有些东西失败了，机器人也可以选择另一条路线来达到它的目标。\n\n这意味着我们不应该使用 `throw(new Error(\"error\"))` 而是使用node.js约定在回调中传递错误。\n\n例如 : \n\n```js\nfunction myfunction (param1, callback) {\n  // do stuff\n  let toDo = 1\n  toDo = 2\n  if (toDo === 2) { // 一切正常\n    callback()\n  } else {\n    callback(new Error('什么东西出错了'))\n  }\n}\n```\n\n请参考另一个例子 [mineflayer code](https://github.com/andrewrk/mineflayer/blob/a8736c4ea473cf1a609c5a29046c0cdad006d429/lib/plugins/bed.js#L10)\n\n### 更新文档\ndocs/api.md 的内容是用doctoc制作的。更新该文件后，应运行 `doctoc docs/api.md` 以更新目录。\n\n没有doctoc命令使用下面的命令安装\n\n```bash\nnpm install -g doctoc\n```\n"
  },
  {
    "path": "docs/zh/FAQ.md",
    "content": "## FAQ\n\n本文档旨在帮助人们解决常见问题\n\n### 如何隐藏报错 ?\n\n在createBot选项中使用`hideErrors:true`\n您也可以选择添加这些监听事件:\n\n```js\nclient.on('error', () => {})\nclient.on('end', () => {})\n```\n\n### 我无法在自定义服务器上获取聊天事件，如何解决?\n\nSpigot 服务器, 特别是一些插件, 使用的是自定义聊天格式,您需要使用自定义正则表达式/解析器对其进行解析。\n阅读并改编[chat_parsing.js](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chat_parsing.js)使其适用于您的特定聊天插件. 或者阅读 http://prismarinejs.github.io/mineflayer/#/tutorial?id=custom-chat\n\n### 如何用自定义插件在聊天中收集信息 ?\n\n大多数定制的Minecraft服务器都有插件支持，很多插件会在聊天中说一些事情. 如果只是一条信息, 最好使用上述解决方案中讨论的解决方案, 但是当这些消息被分成许多小消息时, 另一个选择是使用 `\"messagestr\"` 事件 因为它允许轻松解析多行消息.\n\n**例子:**\n\n聊天栏中的信息看起来像:\n```\n(!) U9G has won the /jackpot and received\n$26,418,402,450! They purchased 2,350,000 (76.32%) ticket(s) out of the\n3,079,185 ticket(s) sold!\n```\n```js\nconst regex = {\n  first: /\\(!\\) (.+) has won the \\/jackpot and received +/,\n  second: /\\$(.+)! They purchased (.+) \\((.+)%\\) ticket\\(s\\) out of the /,\n  third: /(.+) ticket\\(s\\) sold!/\n}\n\nlet jackpot = {}\nbot.on('messagestr', msg => {\n  if (regex.first.test(msg)) {\n    const username = msg.match(regex.first)[1]\n    jackpot.username = username\n  } else if (regex.second.test(msg)) {\n    const [, moneyWon, boughtTickets, winPercent] = msg.match(regex.second)\n    jackpot.moneyWon = parseInt(moneyWon.replace(/,/g, ''))\n    jackpot.boughtTickets = parseInt(boughtTickets.replace(/,/g, ''))\n    jackpot.winPercent = parseFloat(winPercent)\n  } else if (regex.third.test(msg)) {\n    const totalTickets = msg.match(regex.third)[1]\n    jackpot.totalTickets = parseInt(totalTickets.replace(/,/g, ''))\n    onDone(jackpot)\n    jackpot = {}\n  }\n})\n```\n### 如何发送命令 ?\n\n使用  `bot.chat()`.\n\n**例子:**\n\n```js\nbot.chat('/give @p minecraft:diamond_sword')\n```\n\n### 是否可以使用bot = mineflayer.createbot登录多个帐户  同时分别控制它们 ?\n\n通过调用createBot创建不同的bot实例，然后为每个实例执行不同的操作，请参考 multiple.js\n\n### 如何让机器人丢出它的全部背包物品?\n\nbot.inventory.items() 返回机器人的物品数组. 您可以使用递归函数循环遍历它们，并使用 `bot.toss()`.  [点这里](https://gist.github.com/dada513/3d88f772be4224b40f9e5d1787bd63e9) 查看例子\n\n### 如何检查发送/接收的数据包 ?\n\n启用调试模式 https://github.com/PrismarineJS/mineflayer#debug\n\n### 我希望即使在服务器有延迟的情况下也能避免断开连接，如何实现这一点 ?\n\n一种方法是增加 [checkTimeoutInterval](https://github.com/PrismarineJS/node-minecraft-protocol/blob/master/docs/API.md#mccreateclientoptions) 选项的值(在createBot中设置)  (例如 `300*1000` 这是5分钟，而不是默认的30秒). 如果仍然断开连接，可以使用类似于此示例的方法自动重新连接 https://github.com/PrismarineJS/mineflayer/blob/master/examples/reconnector.js\n\n### 如何获取物品的 lore / text?\n\n你可以使用 `item.nbt` 属性. 此外建议使用 `prismarine-nbt` 库.   `nbt.simplify()` 方法可能有用\n\n**例子:**\n\n```js\nfunction getLore (item) {\n  let message = ''\n  if (item.nbt == null) return message\n\n  const nbt = require('prismarine-nbt')\n  const ChatMessage = require('prismarine-chat')(bot.version)\n\n  const data = nbt.simplify(item.nbt)\n  const display = data.display\n  if (display == null) return message\n\n  const lore = display.Lore\n  if (lore == null) return message\n  for (const line of lore) {\n    message += new ChatMessage(line).toString()\n    message += '\\n'\n  }\n\n  return message\n}\n```\n\n### 如何从控制台发送消息到服务器?\n\n您可以使用类似`repl`的库来读取控制台输入的内容并用`bot.chat()`发送它。 你可以在这查看例子 [点这里](https://github.com/PrismarineJS/mineflayer/blob/master/examples/repl.js)\n\n### 创建插件时，如何将另一个插件指定为依赖项？\n\n在插件的`inject()`函数中，您可以安全地调用`bot.loadPlugin(anotherPlugin)`确保已加载该插件。如果插件之前已经加载，则不会发生任何事情。\n\n请注意，加载插件的顺序是动态的, 因此，永远不要在`inject()`函数中调用其他插件.\n\n### 如何使用socks5代理？\n\n在对象的选项中 `mineflayer.createBot(options)`,从选项对象中删除你的 `host` 选项,声明以下变量 `PROXY_IP, PROXY_PORT, PROXY_USERNAME, PROXY_PASSWORD, MC_SERVER_IP, MC_SERVER_PORT` 并将其添加到选项对象中:\n```js\nconnect: (client) => {\n  socks.createConnection({\n    proxy: {\n      host: PROXY_IP,\n      port: PROXY_PORT,\n      type: 5,\n      userId: PROXY_USERNAME,\n      password: PROXY_PASSWORD\n    },\n    command: 'connect',\n    destination: {\n      host: MC_SERVER_IP,\n      port: MC_SERVER_PORT\n    }\n  }, (err, info) => {\n    if (err) {\n      console.log(err)\n      return\n    }\n    client.setSocket(info.socket)\n    client.emit('connect')\n  })\n}\n```\n  `socks` 用 `const socks = require('socks').SocksClient` 声明 使用的是[这个](https://www.npmjs.com/package/socks) 包.\n\n# 常见错误\n\n### `UnhandledPromiseRejectionWarning: Error: Failed to read asymmetric key`\n\n当你给 mineflayer 设定了错误的服务器版本，或者 mineflayer 检测到错误的服务器版本时会发生这种情况\n\n### `TypeError: Cannot read property '?' of undefined`\n\n您可能正在尝试在 bot 对象上使用尚不存在的内容，请尝试在 `spawn` 事件之后调用该语句\n\n### `SyntaxError: Unexpected token '?'`\n\n更新node版本\n\n### The bot can't break/place blocks or open chests\n\n检查出生点保护是否阻止了机器人的操作\n\n"
  },
  {
    "path": "docs/zh/README_ZH_CN.md",
    "content": "# Mineflayer\n\n[![NPM version](https://badge.fury.io/js/mineflayer.svg)](http://badge.fury.io/js/mineflayer)\n[![Build Status](https://github.com/PrismarineJS/mineflayer/workflows/CI/badge.svg)](https://github.com/PrismarineJS/mineflayer/actions?query=workflow%3A%22CI%22)\n[![Discord](https://img.shields.io/badge/chat-on%20discord-brightgreen.svg)](https://discord.gg/GsEFRM8)\n[![Gitter](https://img.shields.io/badge/chat-on%20gitter-brightgreen.svg)](https://gitter.im/PrismarineJS/general)\n[![Irc](https://img.shields.io/badge/chat-on%20irc-brightgreen.svg)](https://irc.gitter.im/)\n[![Issue Hunt](https://github.com/BoostIO/issuehunt-materials/blob/master/v1/issuehunt-shield-v1.svg)](https://issuehunt.io/r/PrismarineJS/mineflayer)\n\n[![Try it on gitpod](https://img.shields.io/badge/try-on%20gitpod-brightgreen.svg)](https://gitpod.io/#https://github.com/PrismarineJS/mineflayer)\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)\n\n| <sub>EN</sub> [English](../README.md) | <sub>RU</sub> [русский](../ru/README_RU.md) | <sub>ES</sub> [Español](../es/README_ES.md) | <sub>FR</sub> [Français](../fr/README_FR.md) | <sub>TR</sub> [Türkçe](../tr/README_TR.md) | <sub>ZH</sub> [中文](../zh/README_ZH_CN.md) | <sub>BR</sub> [Portuguese](../br/README_BR.md) |\n|-------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|----------------------------|\n\n使用强大、稳定、高级的 JavaScript [API](../api.md) 来开发 Minecraft 机器人，同时支持 Python。\n\n第一次使用 node.js ？你可以先看看 [使用教程](../tutorial.md) 。了解过 Python？这里有一些 [Python 实例](https://github.com/PrismarineJS/mineflayer/tree/master/examples/python)，同时你也可以[在谷歌 Colab 中运行 Mineflayer](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb) 来体验一下。\n\n## 特点\n\n * 支持版本：Minecraft 1.8, 1.9, 1.10, 1.11, 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19 和 1.20 \n * 实体感知与追踪\n * 方块感知，你可以在几毫秒内查找到bot周围的任何方块\n * 物理和运动引擎 - 支持所有的碰撞箱\n * 攻击实体，使用交通工具\n * 背包管理\n * 使用工作台、箱子、酿造台、附魔台\n * 挖掘和建造\n * 各种各样的的信息接口，比如查看你的血量或是否下雨\n * 激活方块和使用物品\n * 进行聊天\n\n### 路线图\n\n [点这里](https://github.com/PrismarineJS/mineflayer/wiki/Big-Prismarine-projects) 看看目前我们有哪些实用的项目\n\n## 安装\n\n首先，从 [nodejs.org](https://nodejs.org/) 安装 nodejs（版本要求 >= 18），\n\n然后在你创建的bot项目目录中，使用命令行运行：\n\n`npm install mineflayer`\n\n## 文档\n\n| 链接 | 描述 |\n|---|---|\n| [使用教程](../tutorial.md) | node.js 和 mineflayer 入门 |\n| [FAQ](../FAQ.md) | 使用中出现问题？先看看这个文档吧 |\n| [api](../api.md)、[不稳定的api](../unstable_api.md) | 完整的接口参考文档 |\n| [更新日志](../history.md) | mineflayer 的更新日志 |\n| [示例/](https://github.com/PrismarineJS/mineflayer/tree/master/examples) | 我们为你准备的 mineflayer 使用实例 |\n\n## 参与贡献\n\n请参阅 [为本项目贡献](../CONTRIBUTING.md)，以及[为 Prismarine 贡献](https://github.com/PrismarineJS/prismarine-contribute)\n\n## 如何使用\n\n**视频**（Youtube）\n\n[这里](https://www.youtube.com/watch?v=ltWosy4Z0Kw) 是一个解释bot基本设置过程的教程视频。\n\n如果你想了解更多，更多的视频教程可以在 [这里](https://www.youtube.com/playlist?list=PLh_alXmxHmzGy3FKbo95AkPp5D8849PEV) 找到，视频的相应的源码在 [这里](https://github.com/TheDudeFromCI/Mineflayer-Youtube-Tutorials) 。\n\n[<img src=\"https://img.youtube.com/vi/ltWosy4Z0Kw/0.jpg\" alt=\"tutorial 1\" width=\"200\">](https://www.youtube.com/watch?v=ltWosy4Z0Kw)\n[<img src=\"https://img.youtube.com/vi/UWGSf08wQSc/0.jpg\" alt=\"tutorial 2\" width=\"200\">](https://www.youtube.com/watch?v=UWGSf08wQSc)\n[<img src=\"https://img.youtube.com/vi/ssWE0kXDGJE/0.jpg\" alt=\"tutorial 3\" width=\"200\">](https://www.youtube.com/watch?v=ssWE0kXDGJE)\n[<img src=\"https://img.youtube.com/vi/walbRk20KYU/0.jpg\" alt=\"tutorial 4\" width=\"200\">](https://www.youtube.com/watch?v=walbRk20KYU)\n\n**开始使用**\n\n如果没有指定特定版本，使用的服务器版本将自动判断并使用。  \n如果没有指定登录类型，默认使用 mojang 账户认证登录。\n\n### 例子：复读机\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot({\n  host: 'localhost', // minecraft 服务器的 IP 地址\n  username: 'email@example.com', // minecraft 用户名\n  password: '12345678' // minecraft 密码, 如果你玩的是不需要正版验证的服务器，请注释掉。\n  // port: 25565,                // 默认使用 25565，如果你的服务器端口不是这个请取消注释并填写。\n  // version: false,             // 如果需要指定使用一个版本或快照时，请取消注释并手动填写（如：\"1.8.9\" 或 \"1.16.5\"），否则会自动设置。\n  // auth: 'mojang'              // 如果需要使用微软账号登录时，请取消注释，然后将值设置为 'microsoft'，否则会自动设置为 'mojang'。\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\n// 记录错误和被踢出服务器的原因:\nbot.on('kicked', console.log)\nbot.on('error', console.log)\n```\n\n### 看看你的 bot 在做什么\n\n感谢 [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer)项目，它可以在浏览器窗口显示你的机器人正在做什么。  \n只需要运行 `npm install prismarine-viewer` 并将其添加到你的 bot 代码中。\n\n```js\nconst { mineflayer: mineflayerViewer } = require('prismarine-viewer')\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: true }) // port 是本地网页运行的端口 ，如果 firstPerson: false，那么将会显示鸟瞰图。\n})\n```\n\n然后你会得到一个看起来像这样的*实时视图*：\n\n[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"500\">](https://prismarinejs.github.io/prismarine-viewer/)\n\n#### 更多示例\n\n| 例子 | 描述 |\n|---|---|\n|[viewer](https://github.com/PrismarineJS/mineflayer/tree/master/examples/viewer) | 在浏览器中显示 bot 的视角 |\n|[pathfinder](https://github.com/PrismarineJS/mineflayer/tree/master/examples/pathfinder) | 让你的 bot 自动前往任何地点  |\n|[chest](https://github.com/PrismarineJS/mineflayer/blob/master/examples/chest.js) | 使用箱子、熔炉、酿造台、附魔台 |\n|[digger](https://github.com/PrismarineJS/mineflayer/blob/master/examples/digger.js) | 学习如何创建一个能够挖掘方块的简单bot |\n|[discord](https://github.com/PrismarineJS/mineflayer/blob/master/examples/discord.js) | 将 discord bot 与 mineflayer bot 进行消息互通 |\n|[jumper](https://github.com/PrismarineJS/mineflayer/blob/master/examples/jumper.js) | 学习如何移动、跳跃、骑乘载具、攻击附近的实体 |\n|[ansi](https://github.com/PrismarineJS/mineflayer/blob/master/examples/ansi.js) | 使用全彩色在命令行中显示 bot 的聊天记录 |\n|[guard](https://github.com/PrismarineJS/mineflayer/blob/master/examples/guard.js) | 让bot守卫一个指定的区域，不让附近的生物进入。 |\n|[multiple-from-file](https://github.com/PrismarineJS/mineflayer/blob/master/examples/multiple_from_file.js) | 创建一个包含账户信息的文本文件，让它们全部同时登录 |\n\n还有更多的例子在 [examples](https://github.com/PrismarineJS/mineflayer/tree/master/examples) 文件夹中\n\n### 模块\n\n很多活跃的开发都发生在 mineflayer 所使用的小型 npm 包内\n\n#### The Node Way & trade;\n\n> \"当你很好的编写了一个应用程序，此时它的价值仅限于这些特定的需求。你要知道，真正好的、可重复使用的优秀组件都会升华到github和npm上，在那里，每个人都可以合作来推进公共事业。\" — [《 how I write modules 》 - substack](https://gist.github.com/substack/5075355)\n\n#### 子模块\n\n这些是 构成 mineflayer 的主要模块：\n\n| 模块 | 描述 |\n|---|---|\n| [minecraft-protocol](https://github.com/PrismarineJS/node-minecraft-protocol) | 解析和序列化 minecraft 数据包，以及身份验证和加密。\n| [minecraft-data](https://github.com/PrismarineJS/minecraft-data) | 为 minecraft 客户端、服务器和库提供 minecraft 数据的语言独立模块。\n| [prismarine-physics](https://github.com/PrismarineJS/prismarine-physics) |  为 minecraft 实体提供物理引擎\n| [prismarine-chunk](https://github.com/PrismarineJS/prismarine-chunk) | 一个为 Minecraft 保存区块数据的类\n| [node-vec3](https://github.com/PrismarineJS/node-vec3) | 具有强大单元测试的 3d 矢量数学\n| [prismarine-block](https://github.com/PrismarineJS/prismarine-block) | 用相关数据表示一个 minecraft 方块\n| [prismarine-chat](https://github.com/PrismarineJS/prismarine-chat) | minecraft 聊天消息解析器（从 mineflayer 中提取）\n| [node-yggdrasil](https://github.com/PrismarineJS/node-yggdrasil) | Node.js 库与 Mojang 的身份验证系统交互\n| [prismarine-world](https://github.com/PrismarineJS/prismarine-world) | prismarine 世界的核心实现\n| [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows) | 表示 minecraft 窗口\n| [prismarine-item](https://github.com/PrismarineJS/prismarine-item) | 用相关数据表示一个 minecraft 物品\n| [prismarine-nbt](https://github.com/PrismarineJS/prismarine-nbt) | node-minecraft-protocol 的 NBT 解析器\n| [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe) | 展示我的世界合成表\n| [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome) | 用相关数据表示 minecraft 生物群落\n| [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity) |  表示一个 minecraft 实体\n\n### 调试\n\n您可以使用 `DEBUG` 环境变量启用某些协议调试输出：\n\n```bash\nDEBUG=\"minecraft-protocol\" node [...]\n```\n\n在 windows 上:\n\n```powershell\nset DEBUG=minecraft-protocol\nnode your_script.js\n```\n\n## 第三方插件\n\nmineflayer 支持插件；任何人都可以创建一个插件，在 mineflayer 之上添加更高级别的 API。\n\n最新和最有用的有：\n\n* [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - 具有许多可配置功能的高级 A* 寻路\n* [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - 简单的在线区块查看器\n* [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - 在线背包查看器\n* [statemachine](https://github.com/TheDudeFromCI/mineflayer-statemachine) - 用于更复杂机器人行为的状态机 API\n* [Armor Manager](https://github.com/G07cha/MineflayerArmorManager) - 自动护甲管理\n* [Collect Block](https://github.com/TheDudeFromCI/mineflayer-collectblock) - 快速简单的块收集 API\n* [Dashboard](https://github.com/wvffle/mineflayer-dashboard) - mineflayer bot 的前端仪表板\n* [PVP](https://github.com/TheDudeFromCI/mineflayer-pvp) - 用于基本 PVP 和 PVE 的简单 API\n* [auto-eat](https://github.com/LINKdiscordd/mineflayer-auto-eat) - 自动进食\n * [Auto Crystal](https://github.com/link-discord/mineflayer-autocrystal) - 自动放置和破碎结\n * [Tool](https://github.com/TheDudeFromCI/mineflayer-tool) - 一个具有高级API的工具/武器自动选择工具的工具\n * [Hawkeye](https://github.com/sefirosweb/minecraftHawkEye) - 一个使用自动瞄准弓的工具\n * [GUI](https://github.com/firejoust/mineflayer-GUI) - 简化了嵌套箱子GUI窗口的导航和管理\n * [Projectile](https://github.com/firejoust/mineflayer-projectile) - 以投射物为基础的战斗的可配置插件\n\n\n 也可以看看这些 :\n\n* [radar](https://github.com/andrewrk/mineflayer-radar/) - 使用 canvas 和 socket.io 的基于 Web 的雷达界面 [YouTube 演示](https://www.youtube.com/watch?v=FjDmAfcVulQ)\n* [blockfinder](https://github.com/Darthfett/mineflayer-blockFinder) - 在 3D 世界中寻找方块\n* [scaffold](https://github.com/andrewrk/mineflayer-scaffold) - 到达目标目的地，即使您必须建造或破坏块才能这样做 [YouTube 演示](http://youtu.be/jkg6psMUSE0)\n* [auto-auth](https://github.com/G07cha/MineflayerAutoAuth) - 基于聊天的bot身份验证\n* [Bloodhound](https://github.com/Nixes/mineflayer-bloodhound) - 确定谁和什么对另一个实体的损害负责\n* [tps](https://github.com/SiebeDW/mineflayer-tps) - 获取当前的 tps（已处理的 tps）\n* [panorama](https://github.com/IceTank/mineflayer-panorama) - 拍摄您的世界的全景图像\n * [player-death-event](https://github.com/tuanzisama/mineflayer-death-event) - 在 Mineflayer 里监听玩家死亡事件\n\n## 正在使用 mineflayer 的项目\n\n* [rom1504/rbot](https://github.com/rom1504/rbot)\n  * [YouTube - 建造旋转楼梯](https://www.youtube.com/watch?v=UM1ZV5200S0)\n  * [YouTube - 复制一个建筑](https://www.youtube.com/watch?v=0cQxg9uDnzA)\n* [Darthfett/Helperbot](https://github.com/Darthfett/Helperbot) - 完成一些简单指令\n* [vogonistic/voxel](https://github.com/vogonistic/mineflayer-voxel) - 使用 voxel.js 可视化机器人正在做什么\n* [JonnyD/Skynet](https://github.com/JonnyD/Skynet) -  将玩家活动记录到在线 API 上\n* [MinecraftChat](https://github.com/rom1504/MinecraftChat) （最后一个开源版本，由 AlexKvazos 构建）——基于 Minecraft 网络的聊天客户端 <https://minecraftchat.net/>\n* [Cheese Bot](https://github.com/Minecheesecraft/Cheese-Bot) -  基于插件的机器人，具有干净的 GUI。使用 Node-Webkit 制作。\n* [Chaoscraft](https://github.com/schematical/chaoscraft) - 使用遗传算法的 Minecraft 机器人，请参阅 [Youtube](https://www.youtube.com/playlist?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH)\n* [hexatester/minetelegram](https://github.com/hexatester/minetelegram) -  Minecraft - Telegram 消息互通，基于 mineflayer & telegraf.\n* [PrismarineJS/mineflayer-builder](https://github.com/PrismarineJS/mineflayer-builder) - 在生存中打印我的世界示意图，保持方向\n* [以及数千个](https://github.com/PrismarineJS/mineflayer/network/dependents) - github 检测到的在使用 mineflayer 的项目\n\n## 测试\n\n### 完整测试\n\n运行\n```bash\nnpm test\n````\n\n### 测试指定版本\n\n运行 \n\n```bash\nnpm mocha_test -- -g <version>\n```\n\n其中 `<version>` 表示 minecraft 版本号 如 `1.12`, `1.15.2`...\n\n### 测试指定测试脚本\n\n运行 \n\n```bash\nnpm mocha_test -- -g <test_name>\n```\n\n其中 `<test_name>` 是测试名称，例如 `bed`, `useChests`, `rayTrace`...\n\n### 示例\n\n```bash\nnpm run mocha_test -- -g \"1.18.1.*BlockFinder\"\n```\n\n进行 1.18.1 寻路测试\n\n## 许可证\n\n[MIT](../../LICENSE)\n"
  },
  {
    "path": "docs/zh/_sidebar.md",
    "content": "- 入门手册\n  - [介绍](zh/README_ZH_CN.md)\n  - [API](zh/api.md)\n  - [FAQ](zh/FAQ.md)\n  - [演示](zh/demos.md)\n  - [教程](zh/tutorial.md)\n  - [不稳定的API](unstable_api.md)\n  - [贡献](zh/CONTRIBUTING.md)\n  - [更新历史](history.md)\n"
  },
  {
    "path": "docs/zh/api.md",
    "content": "<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [API](#api)\n  - [Enums](#enums)\n    - [minecraft-data](#minecraft-data)\n    - [mcdata.blocks](#mcdatablocks)\n    - [mcdata.items](#mcdataitems)\n    - [mcdata.materials](#mcdatamaterials)\n    - [mcdata.recipes](#mcdatarecipes)\n    - [mcdata.instruments](#mcdatainstruments)\n    - [mcdata.biomes](#mcdatabiomes)\n    - [mcdata.entities](#mcdataentities)\n  - [Classes](#classes)\n    - [vec3](#vec3)\n    - [mineflayer.Location](#mineflayerlocation)\n    - [Entity](#entity)\n    - [Block](#block)\n    - [Biome](#biome)\n    - [Item](#item)\n    - [windows.Window (base class)](#windowswindow-base-class)\n      - [window.deposit(itemType, metadata, count, [callback])](#windowdeposititemtype-metadata-count-callback)\n      - [window.withdraw(itemType, metadata, count, [callback])](#windowwithdrawitemtype-metadata-count-callback)\n      - [window.close()](#windowclose)\n    - [Recipe](#recipe)\n    - [mineflayer.Container](#mineflayercontainer)\n    - [mineflayer.Furnace](#mineflayerfurnace)\n      - [furnace \"update\"](#furnace-update)\n      - [furnace.takeInput([callback])](#furnacetakeinputcallback)\n      - [furnace.takeFuel([callback])](#furnacetakefuelcallback)\n      - [furnace.takeOutput([callback])](#furnacetakeoutputcallback)\n      - [furnace.putInput(itemType, metadata, count, [cb])](#furnaceputinputitemtype-metadata-count-cb)\n      - [furnace.putFuel(itemType, metadata, count, [cb])](#furnaceputfuelitemtype-metadata-count-cb)\n      - [furnace.inputItem()](#furnaceinputitem)\n      - [furnace.fuelItem()](#furnacefuelitem)\n      - [furnace.outputItem()](#furnaceoutputitem)\n      - [furnace.fuel](#furnacefuel)\n      - [furnace.progress](#furnaceprogress)\n    - [mineflayer.EnchantmentTable](#mineflayerenchantmenttable)\n      - [enchantmentTable \"ready\"](#enchantmenttable-ready)\n      - [enchantmentTable.targetItem()](#enchantmenttabletargetitem)\n      - [enchantmentTable.xpseed](#enchantmenttablexpseed)\n      - [enchantmentTable.enchantments](#enchantmenttableenchantments)\n      - [enchantmentTable.enchant(choice, [callback])](#enchantmenttableenchantchoice-callback)\n      - [enchantmentTable.takeTargetItem([callback])](#enchantmenttabletaketargetitemcallback)\n      - [enchantmentTable.putTargetItem(item, [callback])](#enchantmenttableputtargetitemitem-callback)\n      - [enchantmentTable.putLapis(item, [callback])](#enchantmenttableputlapisitem-callback)\n    - [mineflayer.anvil](#mineflayeranvil)\n      - [anvil.combine(itemOne, itemTwo[, name, callback])](#anvilcombineitemone-itemtwo-name-callback)\n      - [anvil.combine(item[, name, callback])](#anvilcombineitem-name-callback)\n      - [villager \"ready\"](#villager-ready)\n      - [villager.trades](#villagertrades)\n      - [villager.trade(tradeIndex, [times], [cb])](#villagertradetradeindex-times-cb)\n    - [mineflayer.ScoreBoard](#mineflayerscoreboard)\n      - [ScoreBoard.name](#scoreboardname)\n      - [ScoreBoard.title](#scoreboardtitle)\n      - [ScoreBoard.itemsMap](#scoreboarditemsmap)\n      - [ScoreBoard.items](#scoreboarditems)\n    - [mineflayer.Team](#mineflayerteam)\n      - [Team.name](#teamname)\n      - [Team.friendlyFire](#teamfriendlyfire)\n      - [Team.nameTagVisibility](#teamnametagvisibility)\n      - [Team.collisionRule](#teamcollisionrule)\n      - [Team.color](#teamcolor)\n      - [Team.prefix](#teamprefix)\n      - [Team.suffix](#teamsuffix)\n      - [Team.members](#teammembers)\n    - [mineflayer.BossBar](#mineflayerbossbar)\n      - [BossBar.title](#bossbartitle)\n      - [BossBar.health](#bossbarhealth)\n      - [BossBar.dividers](#bossbardividers)\n      - [BossBar.entityUUID](#bossbarentityuuid)\n      - [BossBar.shouldDarkenSky](#bossbarshoulddarkensky)\n      - [BossBar.isDragonBar](#bossbarisdragonbar)\n      - [BossBar.createFog](#bossbarcreatefog)\n      - [BossBar.color](#bossbarcolor)\n  - [Bot](#bot)\n    - [mineflayer.createBot(options)](#mineflayercreatebotoptions)\n    - [Properties](#properties)\n      - [bot.world](#botworld)\n        - [world \"blockUpdate\" (oldBlock, newBlock)](#world-blockupdate-oldblock-newblock)\n        - [world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#world-blockupdatex-y-z-oldblock-newblock)\n      - [bot.entity](#botentity)\n      - [bot.entities](#botentities)\n      - [bot.username](#botusername)\n      - [bot.spawnPoint](#botspawnpoint)\n      - [bot.heldItem](#bothelditem)\n      - [bot.usingHeldItem](#botusinghelditem)\n      - [bot.game.levelType](#botgameleveltype)\n      - [bot.game.dimension](#botgamedimension)\n      - [bot.game.difficulty](#botgamedifficulty)\n      - [bot.game.gameMode](#botgamegamemode)\n      - [bot.game.hardcore](#botgamehardcore)\n      - [bot.game.maxPlayers](#botgamemaxplayers)\n      - [bot.game.serverBrand](#botgameserverbrand)\n    - [bot.physicsEnabled](#botphysicsenabled)\n    - [bot.player](#botplayer)\n      - [bot.players](#botplayers)\n      - [bot.isRaining](#botisraining)\n      - [bot.rainState](#botrainstate)\n      - [bot.thunderState](#botthunderstate)\n      - [bot.chatPatterns](#botchatpatterns)\n      - [bot.settings.chat](#botsettingschat)\n      - [bot.settings.colorsEnabled](#botsettingscolorsenabled)\n      - [bot.settings.viewDistance](#botsettingsviewdistance)\n      - [bot.settings.difficulty](#botsettingsdifficulty)\n      - [bot.settings.skinParts](#botsettingsskinparts)\n        - [bot.settings.skinParts.showCape - boolean](#botsettingsskinpartsshowcape---boolean)\n        - [bot.settings.skinParts.showJacket - boolean](#botsettingsskinpartsshowjacket---boolean)\n        - [bot.settings.skinParts.showLeftSleeve - boolean](#botsettingsskinpartsshowleftsleeve---boolean)\n        - [bot.settings.skinParts.showRightSleeve - boolean](#botsettingsskinpartsshowrightsleeve---boolean)\n        - [bot.settings.skinParts.showLeftPants - boolean](#botsettingsskinpartsshowleftpants---boolean)\n        - [bot.settings.skinParts.showRightPants - boolean](#botsettingsskinpartsshowrightpants---boolean)\n        - [bot.settings.skinParts.showHat - boolean](#botsettingsskinpartsshowhat---boolean)\n      - [bot.experience.level](#botexperiencelevel)\n      - [bot.experience.points](#botexperiencepoints)\n      - [bot.experience.progress](#botexperienceprogress)\n      - [bot.health](#bothealth)\n      - [bot.food](#botfood)\n      - [bot.foodSaturation](#botfoodsaturation)\n      - [bot.oxygenLevel](#botoxygenlevel)\n      - [bot.physics](#botphysics)\n      - [bot.simpleClick.leftMouse (slot)](#botsimpleclickleftmouse-slot)\n      - [bot.simpleClick.rightMouse (slot)](#botsimpleclickrightmouse-slot)\n      - [bot.time.doDaylightCycle](#bottimedodaylightcycle)\n      - [bot.time.bigTime](#bottimebigtime)\n      - [bot.time.time](#bottimetime)\n      - [bot.time.timeOfDay](#bottimetimeofday)\n      - [bot.time.day](#bottimeday)\n      - [bot.time.isDay](#bottimeisday)\n      - [bot.time.moonPhase](#bottimemoonphase)\n      - [bot.time.bigAge](#bottimebigage)\n      - [bot.time.age](#bottimeage)\n      - [bot.quickBarSlot](#botquickbarslot)\n      - [bot.inventory](#botinventory)\n      - [bot.targetDigBlock](#bottargetdigblock)\n      - [bot.isSleeping](#botissleeping)\n      - [bot.scoreboards](#botscoreboards)\n      - [bot.scoreboard](#botscoreboard)\n      - [bot.teams](#botteams)\n      - [bot.teamMap](#botteammap)\n      - [bot.controlState](#botcontrolstate)\n    - [Events](#events)\n      - [\"chat\" (username, message, translate, jsonMsg, matches)](#chat-username-message-translate-jsonmsg-matches)\n      - [\"whisper\" (username, message, translate, jsonMsg, matches)](#whisper-username-message-translate-jsonmsg-matches)\n      - [\"actionBar\" (jsonMsg)](#actionbar-jsonmsg)\n      - [\"message\" (jsonMsg, position)](#message-jsonmsg-position)\n      - [\"messagestr\" (message, messagePosition, jsonMsg)](#messagestr-message-messageposition-jsonmsg)\n      - [\"inject_allowed\"](#inject_allowed)\n      - [\"login\"](#login)\n      - [\"spawn\"](#spawn)\n      - [\"respawn\"](#respawn)\n      - [\"game\"](#game)\n      - [\"resourcePack\" (url, hash)](#resourcepack-url-hash)\n      - [\"title\" (title, type)](#title-title-type)\n      - [\"rain\"](#rain)\n      - [\"weatherUpdate\"](#weatherupdate)\n      - [\"time\"](#time)\n      - [\"kicked\" (reason, loggedIn)](#kicked-reason-loggedin)\n      - [\"end\" (reason)](#end-reason)\n      - [\"error\" (err)](#error-err)\n      - [\"spawnReset\"](#spawnreset)\n      - [\"death\"](#death)\n      - [\"health\"](#health)\n      - [\"breath\"](#breath)\n      - [\"entityAttributes\" (entity)](#entityattributes-entity)\n      - [\"entitySwingArm\" (entity)](#entityswingarm-entity)\n      - [\"entityHurt\" (entity)](#entityhurt-entity)\n      - [\"entityDead\" (entity)](#entitydead-entity)\n      - [\"entityTaming\" (entity)](#entitytaming-entity)\n      - [\"entityTamed\" (entity)](#entitytamed-entity)\n      - [\"entityShakingOffWater\" (entity)](#entityshakingoffwater-entity)\n      - [\"entityEatingGrass\" (entity)](#entityeatinggrass-entity)\n      - [\"entityWake\" (entity)](#entitywake-entity)\n      - [\"entityEat\" (entity)](#entityeat-entity)\n      - [\"entityCriticalEffect\" (entity)](#entitycriticaleffect-entity)\n      - [\"entityMagicCriticalEffect\" (entity)](#entitymagiccriticaleffect-entity)\n      - [\"entityCrouch\" (entity)](#entitycrouch-entity)\n      - [\"entityUncrouch\" (entity)](#entityuncrouch-entity)\n      - [\"entityEquip\" (entity)](#entityequip-entity)\n      - [\"entitySleep\" (entity)](#entitysleep-entity)\n      - [\"entitySpawn\" (entity)](#entityspawn-entity)\n      - [\"itemDrop\" (entity)](#itemdrop-entity)\n      - [\"playerCollect\" (collector, collected)](#playercollect-collector-collected)\n      - [\"entityGone\" (entity)](#entitygone-entity)\n      - [\"entityMoved\" (entity)](#entitymoved-entity)\n      - [\"entityDetach\" (entity, vehicle)](#entitydetach-entity-vehicle)\n      - [\"entityAttach\" (entity, vehicle)](#entityattach-entity-vehicle)\n      - [\"entityUpdate\" (entity)](#entityupdate-entity)\n      - [\"entityEffect\" (entity, effect)](#entityeffect-entity-effect)\n      - [\"entityEffectEnd\" (entity, effect)](#entityeffectend-entity-effect)\n      - [\"playerJoined\" (player)](#playerjoined-player)\n      - [\"playerUpdated\" (player)](#playerupdated-player)\n      - [\"playerLeft\" (player)](#playerleft-player)\n      - [\"blockUpdate\" (oldBlock, newBlock)](#blockupdate-oldblock-newblock)\n      - [\"blockUpdate:(x, y, z)\" (oldBlock, newBlock)](#blockupdatex-y-z-oldblock-newblock)\n      - [\"blockPlaced\" (oldBlock, newBlock)](#blockplaced-oldblock-newblock)\n      - [\"chunkColumnLoad\" (point)](#chunkcolumnload-point)\n      - [\"chunkColumnUnload\" (point)](#chunkcolumnunload-point)\n      - [\"soundEffectHeard\" (soundName, position, volume, pitch)](#soundeffectheard-soundname-position-volume-pitch)\n      - [\"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)](#hardcodedsoundeffectheard-soundid-soundcategory-position-volume-pitch)\n      - [\"noteHeard\" (block, instrument, pitch)](#noteheard-block-instrument-pitch)\n      - [\"pistonMove\" (block, isPulling, direction)](#pistonmove-block-ispulling-direction)\n      - [\"chestLidMove\" (block, isOpen, block2)](#chestlidmove-block-isopen-block2)\n      - [\"blockBreakProgressObserved\" (block, destroyStage)](#blockbreakprogressobserved-block-destroystage)\n      - [\"blockBreakProgressEnd\" (block)](#blockbreakprogressend-block)\n      - [\"diggingCompleted\" (block)](#diggingcompleted-block)\n      - [\"diggingAborted\" (block)](#diggingaborted-block)\n      - [\"move\"](#move)\n      - [\"forcedMove\"](#forcedmove)\n      - [\"mount\"](#mount)\n      - [\"dismount\" (vehicle)](#dismount-vehicle)\n      - [\"windowOpen\" (window)](#windowopen-window)\n      - [\"windowClose\" (window)](#windowclose-window)\n      - [\"sleep\"](#sleep)\n      - [\"wake\"](#wake)\n      - [\"experience\"](#experience)\n      - [\"scoreboardCreated\" (scoreboard)](#scoreboardcreated-scoreboard)\n      - [\"scoreboardDeleted\" (scoreboard)](#scoreboarddeleted-scoreboard)\n      - [\"scoreboardTitleChanged\" (scoreboard)](#scoreboardtitlechanged-scoreboard)\n      - [\"scoreUpdated\" (scoreboard, item)](#scoreupdated-scoreboard-item)\n      - [\"scoreRemoved\" (scoreboard, item)](#scoreremoved-scoreboard-item)\n      - [\"scoreboardPosition\" (position, scoreboard)](#scoreboardposition-position-scoreboard)\n      - [\"teamCreated\" (team)](#teamcreated-team)\n      - [\"teamRemoved\" (team)](#teamremoved-team)\n      - [\"teamUpdated\" (team)](#teamupdated-team)\n      - [\"teamMemberAdded\" (team)](#teammemberadded-team)\n      - [\"teamMemberRemoved\" (team)](#teammemberremoved-team)\n      - [\"bossBarCreated\" (bossBar)](#bossbarcreated-bossbar)\n      - [\"bossBarDeleted\" (bossBar)](#bossbardeleted-bossbar)\n      - [\"bossBarUpdated\" (bossBar)](#bossbarupdated-bossbar)\n      - [\"heldItemChanged\" (heldItem)](#helditemchanged-helditem)\n      - [\"physicsTick\" ()](#physicstick-)\n      - [\"chat:name\" (matches)](#chatname-matches)\n    - [Functions](#functions)\n      - [bot.blockAt(point, extraInfos=true)](#botblockatpoint-extrainfostrue)\n      - [bot.waitForChunksToLoad(cb)](#botwaitforchunkstoloadcb)\n      - [bot.blockInSight(maxSteps, vectorLength)](#botblockinsightmaxsteps-vectorlength)\n      - [bot.blockAtCursor(maxDistance=256)](#botblockatcursormaxdistance256)\n      - [bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)](#botblockatentitycursorentitybotentity-maxdistance256)\n      - [bot.canSeeBlock(block)](#botcanseeblockblock)\n      - [bot.findBlocks(options)](#botfindblocksoptions)\n      - [bot.findBlock(options)](#botfindblockoptions)\n      - [bot.canDigBlock(block)](#botcandigblockblock)\n      - [bot.recipesFor(itemType, metadata, minResultCount, craftingTable)](#botrecipesforitemtype-metadata-minresultcount-craftingtable)\n      - [bot.recipesAll(itemType, metadata, craftingTable)](#botrecipesallitemtype-metadata-craftingtable)\n      - [bot.nearestEntity(match = (entity) => { return true })](#botnearestentitymatch--entity---return-true-)\n    - [Methods](#methods)\n      - [bot.end(reason)](#botendreason)\n      - [bot.quit(reason)](#botquitreason)\n      - [bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])](#bottabcompletestr-cb-assumecommand-sendblockinsight)\n      - [bot.chat(message)](#botchatmessage)\n      - [bot.whisper(username, message)](#botwhisperusername-message)\n      - [bot.chatAddPattern(pattern, chatType, description)](#botchataddpatternpattern-chattype-description)\n      - [bot.addChatPattern(name, pattern, chatPatternOptions)](#botaddchatpatternname-pattern-chatpatternoptions)\n      - [bot.addChatPatternSet(name, patterns, chatPatternOptions)](#botaddchatpatternsetname-patterns-chatpatternoptions)\n      - [bot.removeChatPattern(name)](#botremovechatpatternname)\n      - [bot.awaitMessage(...args)](#botawaitmessageargs)\n      - [bot.setSettings(options)](#botsetsettingsoptions)\n      - [bot.loadPlugin(plugin)](#botloadpluginplugin)\n      - [bot.loadPlugins(plugins)](#botloadpluginsplugins)\n      - [bot.hasPlugin(plugin)](#bothaspluginplugin)\n      - [bot.sleep(bedBlock, [cb])](#botsleepbedblock-cb)\n      - [bot.isABed(bedBlock)](#botisabedbedblock)\n      - [bot.wake([cb])](#botwakecb)\n      - [bot.setControlState(control, state)](#botsetcontrolstatecontrol-state)\n      - [bot.getControlState(control)](#botgetcontrolstatecontrol)\n      - [bot.clearControlStates()](#botclearcontrolstates)\n      - [bot.getExplosionDamages(entity, position, radius, [rawDamages])](#botgetexplosiondamagesentity-position-radius-rawdamages)\n      - [bot.lookAt(point, [force], [callback])](#botlookatpoint-force-callback)\n      - [bot.look(yaw, pitch, [force], [callback])](#botlookyaw-pitch-force-callback)\n      - [bot.updateSign(block, text)](#botupdatesignblock-text)\n      - [bot.equip(item, destination, [callback])](#botequipitem-destination-callback)\n      - [bot.unequip(destination, [callback])](#botunequipdestination-callback)\n      - [bot.tossStack(item, [callback])](#bottossstackitem-callback)\n      - [bot.toss(itemType, metadata, count, [callback])](#bottossitemtype-metadata-count-callback)\n      - [bot.dig(block, [forceLook = true], [digFace], [callback])](#botdigblock-forcelook--true-digface-callback)\n      - [bot.stopDigging()](#botstopdigging)\n      - [bot.digTime(block)](#botdigtimeblock)\n      - [bot.acceptResourcePack()](#botacceptresourcepack)\n      - [bot.denyResourcePack()](#botdenyresourcepack)\n      - [bot.placeBlock(referenceBlock, faceVector, cb)](#botplaceblockreferenceblock-facevector-cb)\n      - [bot.placeEntity(referenceBlock, faceVector)](#botplaceentityreferenceblock-facevector)\n      - [bot.activateBlock(block, [callback])](#botactivateblockblock-callback)\n      - [bot.activateEntity(entity, [callback])](#botactivateentityentity-callback)\n      - [bot.activateEntityAt(entity, position, [callback])](#botactivateentityatentity-position-callback)\n      - [bot.consume(callback)](#botconsumecallback)\n      - [bot.fish(callback)](#botfishcallback)\n      - [bot.activateItem(offHand=false)](#botactivateitemoffhandfalse)\n      - [bot.deactivateItem()](#botdeactivateitem)\n      - [bot.useOn(targetEntity)](#botuseontargetentity)\n      - [bot.attack(entity, swing = true)](#botattackentity-swing--true)\n      - [bot.swingArm([hand], showHand)](#botswingarmhand-showhand)\n      - [bot.mount(entity)](#botmountentity)\n      - [bot.dismount()](#botdismount)\n      - [bot.moveVehicle(left,forward)](#botmovevehicleleftforward)\n      - [bot.setQuickBarSlot(slot)](#botsetquickbarslotslot)\n      - [bot.craft(recipe, count, craftingTable, [callback])](#botcraftrecipe-count-craftingtable-callback)\n      - [bot.writeBook(slot, pages, [callback])](#botwritebookslot-pages-callback)\n      - [bot.openContainer(containerBlock or containerEntity)](#botopencontainercontainerblock-or-containerentity)\n      - [bot.openChest(chestBlock or minecartchestEntity)](#botopenchestchestblock-or-minecartchestentity)\n      - [bot.openFurnace(furnaceBlock)](#botopenfurnacefurnaceblock)\n      - [bot.openDispenser(dispenserBlock)](#botopendispenserdispenserblock)\n      - [bot.openEnchantmentTable(enchantmentTableBlock)](#botopenenchantmenttableenchantmenttableblock)\n      - [bot.openAnvil(anvilBlock)](#botopenanvilanvilblock)\n      - [bot.openVillager(villagerEntity)](#botopenvillagervillagerentity)\n      - [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n      - [bot.setCommandBlock(pos, command, [options])](#botsetcommandblockpos-command-options)\n      - [bot.supportFeature(name)](#botsupportfeaturename)\n      - [bot.waitForTicks(ticks)](#botwaitforticksticks)\n    - [Lower level inventory methods](#lower-level-inventory-methods)\n      - [bot.clickWindow(slot, mouseButton, mode, cb)](#botclickwindowslot-mousebutton-mode-cb)\n      - [bot.putSelectedItemRange(start, end, window, slot)](#botputselecteditemrangestart-end-window-slot)\n      - [bot.putAway(slot)](#botputawayslot)\n      - [bot.closeWindow(window)](#botclosewindowwindow)\n      - [bot.transfer(options, cb)](#bottransferoptions-cb)\n      - [bot.openBlock(block)](#botopenblockblock)\n      - [bot.openEntity(entity)](#botopenentityentity)\n      - [bot.moveSlotItem(sourceSlot, destSlot, cb)](#botmoveslotitemsourceslot-destslot-cb)\n      - [bot.updateHeldItem()](#botupdatehelditem)\n      - [bot.getEquipmentDestSlot(destination)](#botgetequipmentdestslotdestination)\n    - [bot.creative](#botcreative)\n      - [bot.creative.setInventorySlot(slot, item, [callback])](#botcreativesetinventoryslotslot-item-callback)\n      - [bot.creative.flyTo(destination, [cb])](#botcreativeflytodestination-cb)\n      - [bot.creative.startFlying()](#botcreativestartflying)\n      - [bot.creative.stopFlying()](#botcreativestopflying)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n# API\n\n## Enums\n\nThese enums are stored in the language independent [minecraft-data](https://github.com/PrismarineJS/minecraft-data) project,\n and accessed through [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data).\n\n### minecraft-data\nThe data is available in [node-minecraft-data](https://github.com/PrismarineJS/node-minecraft-data) module\n\n`require('minecraft-data')(bot.version)` gives you access to it.\n\n### mcdata.blocks\nblocks indexed by id\n\n### mcdata.items\nitems indexed by id\n\n### mcdata.materials\n\nThe key is the material. The value is an object with the key as the item id\nof the tool and the value as the efficiency multiplier.\n\n### mcdata.recipes\nrecipes indexed by id\n\n### mcdata.instruments\ninstruments indexed by id\n\n### mcdata.biomes\nbiomes indexed by id\n\n### mcdata.entities\nentities indexed by id\n\n## Classes\n\n### vec3\n\nSee [andrewrk/node-vec3](https://github.com/andrewrk/node-vec3)\n\nAll points in mineflayer are supplied as instances of this class.\n\n * x - south\n * y - up\n * z - west\n\nFunctions and methods which require a point argument accept `Vec3` instances\nas well as an array with 3 values, and an object with `x`, `y`, and `z`\nproperties.\n\n### mineflayer.Location\n\n### Entity\n\n实体表示玩家、怪物和对象.\n\n它们在许多事件中被触发, 您可以使用 `bot.entity`.访问自己的实体\n见 [prismarine-entity](https://github.com/PrismarineJS/prismarine-entity)\n\n### Block\n\nSee [prismarine-block](https://github.com/PrismarineJS/prismarine-block)\n\nAlso `block.blockEntity` is additional field with block entity data as `Object`\n```js\n// sign.blockEntity\n{\n  x: -53,\n  y: 88,\n  z: 66,\n  id: 'minecraft:sign', // 'Sign' in 1.10\n  Text1: { toString: Function }, // ChatMessage object\n  Text2: { toString: Function }, // ChatMessage object\n  Text3: { toString: Function }, // ChatMessage object\n  Text4: { toString: Function } // ChatMessage object\n}\n```\n\n### Biome\n\nSee [prismarine-biome](https://github.com/PrismarineJS/prismarine-biome)\n\n### Item\n\nSee [prismarine-item](https://github.com/PrismarineJS/prismarine-item)\n\n### windows.Window (base class)\n\nSee [prismarine-windows](https://github.com/PrismarineJS/prismarine-windows)\n\n#### window.deposit(itemType, metadata, count, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `itemType` - numerical item id\n * `metadata` - numerical value. `null` means match anything.\n * `count` - how many to deposit. `null` is an alias to 1.\n * `callback(err)` - (optional) - called when done depositing\n\n#### window.withdraw(itemType, metadata, count, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `itemType` - numerical item id\n * `metadata` - numerical value. `null` means match anything.\n * `count` - how many to withdraw. `null` is an alias to 1.\n * `callback(err)` - (optional) - called when done withdrawing\n\n#### window.close()\n\n### Recipe\n\nSee [prismarine-recipe](https://github.com/PrismarineJS/prismarine-recipe)\n\n### mineflayer.Container\n\nExtends windows.Window for chests, dispensers, etc...\nSee `bot.openContainer(chestBlock or minecartchestEntity)`.\n\n### mineflayer.Furnace\n\nExtends windows.Window for furnace, smelter, etc...\nSee `bot.openFurnace(furnaceBlock)`.\n\n#### furnace \"update\"\n\nFires when `furnace.fuel` and/or `furnace.progress` update.\n\n#### furnace.takeInput([callback])\n\nThis function also returns a `Promise`, with `item` as its argument upon completion.\n\n * `callback(err, item)`\n\n#### furnace.takeFuel([callback])\n\nThis function also returns a `Promise`, with `item` as its argument upon completion.\n\n * `callback(err, item)`\n\n#### furnace.takeOutput([callback])\n\nThis function also returns a `Promise`, with `item` as its argument upon completion.\n\n * `callback(err, item)`\n\n#### furnace.putInput(itemType, metadata, count, [cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n#### furnace.putFuel(itemType, metadata, count, [cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n#### furnace.inputItem()\n\nReturns `Item` instance which is the input.\n\n#### furnace.fuelItem()\n\nReturns `Item` instance which is the fuel.\n\n#### furnace.outputItem()\n\nReturns `Item` instance which is the output.\n\n#### furnace.fuel\n\nHow much fuel is left between 0 and 1.\n\n#### furnace.progress\n\nHow much cooked the input is between 0 and 1.\n\n### mineflayer.EnchantmentTable\n\nExtends windows.Window for enchantment tables\nSee `bot.openEnchantmentTable(enchantmentTableBlock)`.\n\n#### enchantmentTable \"ready\"\n\nFires when `enchantmentTable.enchantments` is fully populated and you\nmay make a selection by calling `enchantmentTable.enchant(choice)`.\n\n#### enchantmentTable.targetItem()\n\nGets the target item. This is both the input and the output of the\nenchantment table.\n\n#### enchantmentTable.xpseed\n\nThe 16 bits xpseed sent by the server.\n\n#### enchantmentTable.enchantments\n\nArray of length 3 which are the 3 enchantments to choose from.\n`level` can be `-1` if the server has not sent the data yet.\n\nLooks like:\n\n```js\n[\n  {\n    level: 3\n  },\n  {\n    level: 4\n  },\n  {\n    level: 9\n  }\n]\n```\n\n#### enchantmentTable.enchant(choice, [callback])\n\nThis function also returns a `Promise`, with `item` as its argument upon completion.\n\n * `choice` - [0-2], the index of the enchantment you want to pick.\n * `callback(err, item)` - (optional) called when the item has been enchanted\n\n#### enchantmentTable.takeTargetItem([callback])\n\nThis function also returns a `Promise`, with `item` as its argument upon completion.\n\n * `callback(err, item)`\n\n#### enchantmentTable.putTargetItem(item, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `callback(err)`\n\n#### enchantmentTable.putLapis(item, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `callback(err)`\n\n### mineflayer.anvil\n\nExtends windows.Window for anvils\nSee `bot.openAnvil(anvilBlock)`.\n\n#### anvil.combine(itemOne, itemTwo[, name, callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `callback(err)` - in order to use callback, pass an empty string ('') for name\n\n#### anvil.combine(item[, name, callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `callback(err)`\n\n#### villager \"ready\"\n\nFires when `villager.trades` is loaded.\n\n#### villager.trades\n\nArray of trades.\n\nLooks like:\n\n```js\n[\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: false,\n    secondaryInput: null,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  },\n  {\n    firstInput: Item,\n    output: Item,\n    hasSecondItem: true,\n    secondaryInput: Item,\n    disabled: false,\n    tooluses: 0,\n    maxTradeuses: 7\n  }\n]\n```\n\n#### villager.trade(tradeIndex, [times], [cb])\nIs the same as [bot.trade(villagerInstance, tradeIndex, [times], [cb])](#bottradevillagerinstance-tradeindex-times-cb)\n\n### mineflayer.ScoreBoard\n\n#### ScoreBoard.name\n\n记分牌的名称\n\n#### ScoreBoard.title\n\n记分牌的标题 (does not always equal the name)\n\n#### ScoreBoard.itemsMap\n\n记分板中包含所有项目的对象\n```js\n{\n  wvffle: { name: 'wvffle', value: 3 },\n  dzikoysk: { name: 'dzikoysk', value: 6 }\n}\n```\n\n#### ScoreBoard.items\n\n记分板中包含所有已排序项的数组\n```js\n[\n  { name: 'dzikoysk', value: 6 },\n  { name: 'wvffle', value: 3 }\n]\n```\n\n### mineflayer.Team\n\n#### Team.name\n\n队伍名称\n\n#### Team.friendlyFire\n\n#### Team.nameTagVisibility\n\n`always`, `hideForOtherTeams`, `hideForOwnTeam` 其中一个\n\n#### Team.collisionRule\n\n `always`, `pushOtherTeams`, `pushOwnTeam ` 其中一个\n\n#### Team.color\n\nColor (or formatting) name of team, 如 `dark_green`, `red`, `underlined`\n\n#### Team.prefix\n\n一个聊天组件，包含队伍前缀\n\n#### Team.suffix\n\n一个聊天组件，包含队伍后缀\n\n#### Team.members\n\nArray of team members. Usernames for players and UUIDs for other entities.\n\n### mineflayer.BossBar\n\n#### BossBar.title\n\nboss 栏标题,  ChatMessage 有例子\n\n#### BossBar.health\n\nboss 生命百分比, 从`0` 到`1`\n\n#### BossBar.dividers\n\nNumber of boss bar dividers, one of `0`, `6`, `10`, `12`, `20`\n\n#### BossBar.entityUUID\n\nBoss 栏实体 uuid\n\n#### BossBar.shouldDarkenSky\n\nDetermines whether or not to darken the sky\n\n#### BossBar.isDragonBar\n\nDetermines whether or not boss bar is dragon bar\n\n#### BossBar.createFog\n\nDetermines whether or not boss bar creates fog\n\n#### BossBar.color\n\nDetermines what color the boss bar color is,  `pink`, `blue`, `red`, `green`, `yellow`, `purple`, `white `之中的一个\n\n## Bot\n\n### mineflayer.createBot(options)\n\n创建并返回bot类的实例。\n`options` 是包含可选属性的对象 :\n\n * username : 用户名，默认为 'Player'\n * port : 端口，默认为 25565\n * password : 可以省略 (如果token也被省略，那么它将尝试以离线模式连接)\n * host : 默认为 localhost\n * version : 默认为自动猜测服务器的版本。值示例：\"1.12.2\"\n * auth : 默认为\"mojang\"，也可以是\"microsoft\"\n * clientToken : 如果给定密码，则生成\n * accessToken : 如果给定密码，则生成\n * logErrors : 默认情况下为true，捕获错误并记录它们\n * hideErrors : 默认情况下为true，不记录错误（即使logErrors为true）\n * keepAlive : 发送保持活动的数据包：默认为true\n * checkTimeoutInterval : 默认 `30*1000` (30s), 检查是否在此期间收到keepalive，否则断开连接。\n * loadInternalPlugins : 默认为true\n * storageBuilder : 可选功能,将version和worldName作为参数，并返回与prismarine-provider-anvil具有相同API的某个对象的实例 ，将被用来保存世界\n * client : node-minecraft-protocol 实例, 如果未指定，mineflayer将创建自己的客户端.这可用于通过许多客户端的代理或普通客户端和mineflayer客户端来启用mineflayer\n * plugins : object : 默认为{}\n   - pluginName : false : don't load internal plugin with given name ie. `pluginName`\n   - pluginName : true : load internal plugin with given name ie. `pluginName` 即使loadInternalplugins设置为false\n   - pluginName : 外部插件注入函数: 加载外部插件, overrides internal plugin with given name ie. `pluginName`\n * physicsEnabled : 默认为true, 机器人应该受到物理的影响吗？ 以后可以通过 bot.physicsEnabled 修改\n * [chat](#bot.settings.chat)\n * [colorsEnabled](#bot.settings.colorsEnabled)\n * [viewDistance](#bot.settings.viewDistance)\n * [difficulty](#bot.settings.difficulty)\n * [skinParts](#bot.settings.skinParts)\n * chatLengthLimit : 单个消息中可以发送的最大字符数. 如果没有设置， 那么游戏版本在 < 1.11 为100  在 >= 1.11 为256\n * defaultChatPatterns: 默认为true, 设置为false不添加聊天和私信等模式\n\n### Properties\n\n#### bot.world\n\nA sync representation of the world. 查看以下位置的文档： http://github.com/PrismarineJS/prismarine-world\n\n##### world \"blockUpdate\" (oldBlock, newBlock)\n\n当方块更新时触发. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\n注意 `oldBlock` 可能是 `null`.\n\n##### world \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\nFires for a specific point. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\n注意:  `oldBlock` 可能为 `null`\n\n\n#### bot.entity\n\nBot自己的实体. 见 `Entity`.\n\n#### bot.entities\n\n所有附近的实体。 This object is a map of entityId to entity.\n\n#### bot.username\n\n机器人自己的名字\n\n#### bot.spawnPoint\n\n到主出生点的坐标, 所有指南针指向的地方。\n\n#### bot.heldItem\n\n机器人手中的物品, represented as a [prismarine-item](https://github.com/PrismarineJS/prismarine-item) instance specified with arbitrary metadata, nbtdata, etc.\n\n#### bot.usingHeldItem\n\n机器人是否正在使用其持有的物品，例如吃食物或使用盾牌。\n\n#### bot.game.levelType\n\n#### bot.game.dimension\n\n#### bot.game.difficulty\n\n#### bot.game.gameMode\n\n#### bot.game.hardcore\n\n#### bot.game.maxPlayers\n\n#### bot.game.serverBrand\n\n### bot.physicsEnabled\n\n启用物理，默认为true。\n\n### bot.player\n\n机器人的玩家对象\n```js\n{\n  username: 'player',\n  displayName: { toString: Function }, // ChatMessage object.\n  gamemode: 0,\n  ping: 28,\n  entity: entity // 如果距离太远，则为空\n}\n```\n\n一个玩家的ping值从0开始,您可能需要等待服务器发送实际的ping\n\n#### bot.players\n\nMap of username to people playing the game.\n\n#### bot.isRaining\n\n#### bot.rainState\n\n指示当前降雨量的数字。不下雨的时候，这个\n将等于0。 当开始下雨时，该值将增加\n逐渐上升到1。当雨停时，该值逐渐减小回0。\n\nEach time `bot.rainState` is changed, the \"weatherUpdate\" event is emitted.\n\n#### bot.thunderState\n\nA number indicating the current thunder level. When there isn't a thunderstorm, this\nwill be equal to 0. When a thunderstorm starts, this value will increase\ngradually up to 1. When the thunderstorm stops, this value gradually decreases back to 0.\n\nEach time `bot.thunderState` is changed, the \"weatherUpdate\" event is emitted.\n\nThis is the same as `bot.rainState`, but for thunderstorms.\nFor thunderstorms, both `bot.rainState` and `bot.thunderState` will change.\n\n#### bot.chatPatterns\n\nThis is an array of pattern objects, of the following format:\n{ /regex/, \"chattype\", \"description\")\n * /regex/ - a regular expression pattern, that should have at least two capture groups\n * 'chattype' - the type of chat the pattern matches, ex \"chat\" or \"whisper\", but can be anything.\n * 'description' - description of what the pattern is for, optional.\n\n#### bot.settings.chat\n\n选项:\n\n * `enabled` (默认)\n * `commandsOnly`\n * `disabled`\n\n#### bot.settings.colorsEnabled\n\n默认为true，无论您是否从服务器接收聊天中的颜色代码。\n\n#### bot.settings.viewDistance\n\n选项:\n * `far` (默认)\n * `normal`\n * `short`\n * `tiny`\n\n#### bot.settings.difficulty\n\nSame as from server.properties.\n\n#### bot.settings.skinParts\n\n这些boolean设置控制玩家皮肤上的额外皮肤细节是否可见\n\n##### bot.settings.skinParts.showCape - boolean\n\n如果您有披风，可以将其设置为false来关闭它\n\n##### bot.settings.skinParts.showJacket - boolean\n\n##### bot.settings.skinParts.showLeftSleeve - boolean\n\n##### bot.settings.skinParts.showRightSleeve - boolean\n\n##### bot.settings.skinParts.showLeftPants - boolean\n\n##### bot.settings.skinParts.showRightPants - boolean\n\n##### bot.settings.skinParts.showHat - boolean\n\n\n#### bot.experience.level\n\n#### bot.experience.points\n\n总经验点数\n\n#### bot.experience.progress\n\nBetween 0 and 1 - amount to get to the next level.\n\n#### bot.health\n\n[0,20]范围内的数字，表示半颗心的数量。\n\n#### bot.food\n\n [0, 20] 范围内的数字，表示半个鸡腿的数量。\n\n#### bot.foodSaturation\n\nFood saturation acts as a food \"overcharge\". Food values will not decrease\nwhile the saturation is over zero. Players logging in automatically get a\nsaturation of 5.0. Eating food increases the saturation as well as the food bar.\n\n#### bot.oxygenLevel\n\nNumber in the range [0, 20] respresenting the number of water-icons known as oxygen level.\n\n#### bot.physics\n\n编辑这些数字以调整重力、跳跃速度、终点速度等。\n这样做的风险由你自己承担。\n\n#### bot.simpleClick.leftMouse (slot)\n\nabstraction over `bot.clickWindow(slot, 0, 0)`\n\n#### bot.simpleClick.rightMouse (slot)\n\nabstraction over `bot.clickWindow(slot, 1, 0)`\n\n#### bot.time.doDaylightCycle\n\nWhether or not the gamerule doDaylightCycle is true or false.\n\n#### bot.time.bigTime\n\nThe total number of ticks since day 0.\n\nThis value is of type BigInt and is accurate even at very large values. (more than 2^51 - 1 ticks)\n\n#### bot.time.time\n\nThe total numbers of ticks since day 0.\n\nBecause the Number limit of Javascript is at 2^51 - 1 bot.time.time becomes inaccurate higher than this limit and the use of bot.time.bigTime is recommended.\nRealistically though you'll probably never need to use bot.time.bigTime as it will only reach 2^51 - 1 ticks naturally after ~14280821 real years.\n\n#### bot.time.timeOfDay\n\n一天中的时间，单位为Tick\n\nTime is based on ticks, where 20 ticks happen every second. There are 24000\nticks in a day, making Minecraft days exactly 20 minutes long.\n\nThe time of day is based on the timestamp modulo 24000. 0 is sunrise, 6000\nis noon, 12000 is sunset, and 18000 is midnight.\n\n#### bot.time.day\n\n世界中的一天\n\n#### bot.time.isDay\n\nWhether it is day or not.\n\nBased on whether the current time of day is between 13000 and 23000 ticks.\n\n#### bot.time.moonPhase\n\n月相\n\n0-7，其中0表示满月\n\n#### bot.time.bigAge\n\n世界的年龄以tick为单位\n\n此值为BigInt类型，即使在非常大的值下也准确。 (more than 2^51 - 1 ticks)\n\n#### bot.time.age\n\nAge of the world, in ticks.\n\nBecause the Number limit of Javascript is at 2^51 - 1 bot.time.age becomes inaccurate higher than this limit and the use of bot.time.bigAge is recommended.\nRealistically though you'll probably never need to use bot.time.bigAge as it will only reach 2^51 - 1 ticks naturally after ~14280821 real years.\n\n#### bot.quickBarSlot\n\n选择了哪个物品栏位 (0 - 8)\n\n#### bot.inventory\n\nA [`Window`](https://github.com/PrismarineJS/prismarine-windows#windowswindow-base-class) instance representing your inventory.\n\n#### bot.targetDigBlock\n\nThe `block` that you are currently digging, or `null`.\n\n#### bot.isSleeping\n\nBoolean, whether or not you are in bed.\n\n#### bot.scoreboards\n\nAll scoreboards known to the bot in an object scoreboard name -> scoreboard.\n\n#### bot.scoreboard\n\nAll scoreboards known to the bot in an object scoreboard displaySlot -> scoreboard.\n\n * `belowName` - scoreboard placed in belowName\n * `sidebar` - scoreboard placed in sidebar\n * `list` - scoreboard placed in list\n * `0-18` - slots defined in [protocol](https://minecraft.wiki/w/Protocol#Display_Scoreboard)\n\n#### bot.teams\n\n机器人已知的所有队伍\n\n#### bot.teamMap\n\nMapping of member to team. Uses usernames for players and UUIDs for entities.\n\n#### bot.controlState\n\nAn object whose keys are the main control states: ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak'].\n\nSetting values for this object internally calls [bot.setControlState](#botsetcontrolstatecontrol-state).\n\n### Events\n\n#### \"chat\" (username, message, translate, jsonMsg, matches)\n\n仅在玩家公开聊天时触发\n\n * `username` - who said the message (compare with `bot.username` to ignore your own chat)\n * `message` - stripped of all color and control characters\n * `translate` - chat message type. Null for most bukkit chat messages\n * `jsonMsg` - unmodified JSON message from the server\n * `matches` - array of returned matches from regular expressions. May be null\n\n#### \"whisper\" (username, message, translate, jsonMsg, matches)\n\n仅当玩家私下与您聊天时触发\n\n * `username` - 谁发的消息\n * `message` - 去除所有颜色和控制字符\n * `translate` - 聊天信息类型. 大多数bukkit聊天信息为空\n * `jsonMsg` - 来自服务器的未修改的JSON消息\n * `matches` - 返回从正则表达式的匹配项数组。可能为空\n\n#### \"actionBar\" (jsonMsg)\n\nEmitted for every server message which appears on the Action Bar.\n\n * `jsonMsg` - 来自服务器的未修改的JSON消息\n\n#### \"message\" (jsonMsg, position)\n\nEmitted for every server message, including chats.\n\n * `jsonMsg` - unmodified JSON message from the server\n\n * `position` - (>= 1.8.1): 聊天信息的position可以是\n   * chat\n   * system\n   * game_info\n\n#### \"messagestr\" (message, messagePosition, jsonMsg)\n\n`message`事件的别名，但它调用消息对象上的toString()，以在发出前获取消息的字符串。\n\n#### \"inject_allowed\"\n加载索引文件后触发，您可以在此处加载mcData和插件，但最好等待`spawn`事件。\n\n#### \"login\"\n\n成功登录到服务器后触发。\n在做任何事情之前 您可能要等待\"spawn\"事件。\n\n#### \"spawn\"\n\n在您首次登录和出生后触发一次然后在你死后重生时触发。\n\n这通常是您想要监听的事件在服务器上执行任何操作之前.\n\n#### \"respawn\"\n\n在改变维度时和出生之前触发。\n一般忽略此事件并等待\"spawn\"事件。\n\n#### \"game\"\n\n服务器更改任何游戏属性时触发。\n\n#### \"resourcePack\" (url, hash)\n\n当服务器发送资源包时触发\n\n#### \"title\" (title, type)\n\n当服务器发送标题时触发\n\n * `title` - 标题文本\n * `type` - 标题类型 \"subtitle\" 或 \"title\"\n\n#### \"rain\"\n\n开始或停止下雨时触发. 如果你加入已在下雨的服务器上，将触发此事件。\n\n#### \"weatherUpdate\"\n\nEmitted when either `bot.thunderState` or `bot.rainState` changes.\nIf you join a server where it is already raining, this event will fire.\n\n#### \"time\"\n\n当服务器发送时间更新时触发. 见 `bot.time`\n\n#### \"kicked\" (reason, loggedIn)\n\n当bot从服务器被踢出时触发\n\n `reason`是一条解释你被踢的原因的聊天信息.\n\n`loggedIn`\n 如果客户端在成功登录后被踢出则为`true`\n如果kick发生在登录阶段则为 `false`\n\n#### \"end\" (reason)\n\n当您不再连接到服务器时触发\n`reason` 是一个字符串，用于解释客户端断开连接的原因。 (默认为 'socketClosed')\n\n#### \"error\" (err)\n\n发生错误时触发\n\n#### \"spawnReset\"\n\n当你不能在床上出生并且出生点重置时触发\n\n#### \"death\"\n\n当你死亡时触发\n\n#### \"health\"\n\n当你的血量或饥饿发生变化时触发\n\n#### \"breath\"\n\n当你的氧气水平改变时触发\n\n#### \"entityAttributes\" (entity)\n\n当实体的属性更改时触发\n\n#### \"entitySwingArm\" (entity)\n#### \"entityHurt\" (entity)\n\n实体被攻击（指被攻击不是受到伤害\n\n#### \"entityDead\" (entity)\n#### \"entityTaming\" (entity)\n#### \"entityTamed\" (entity)\n#### \"entityShakingOffWater\" (entity)\n#### \"entityEatingGrass\" (entity)\n\n实体吃草\n\n#### \"entityWake\" (entity)\n\n实体睡醒\n\n#### \"entityEat\" (entity)\n\n实体进食\n\n#### \"entityCriticalEffect\" (entity)\n\n实体暴击效果\n\n#### \"entityMagicCriticalEffect\" (entity)\n#### \"entityCrouch\" (entity)\n#### \"entityUncrouch\" (entity)\n#### \"entityEquip\" (entity)\n#### \"entitySleep\" (entity)\n#### \"entitySpawn\" (entity)\n#### \"itemDrop\" (entity)\n#### \"playerCollect\" (collector, collected)\n\n某实体拾取一个物品\n\n * `collector` - 拾取物品的实体\n * `collected` - 地面上的物品所在的实体\n\n#### \"entityGone\" (entity)\n#### \"entityMoved\" (entity)\n\n已移动的实体\n\n#### \"entityDetach\" (entity, vehicle)\n#### \"entityAttach\" (entity, vehicle)\n\n实体乘骑在交通工具上, 例如矿车和船\n\n * `entity` - 搭便车的实体\n * `vehicle` - 作为车辆的实体\n\n#### \"entityUpdate\" (entity)\n#### \"entityEffect\" (entity, effect)\n\n实体获得buff效果\n\n#### \"entityEffectEnd\" (entity, effect)\n#### \"playerJoined\" (player)\n\n玩家加入游戏后触发\n\n#### \"playerUpdated\" (player)\n#### \"playerLeft\" (player)\n\n玩家离开游戏触发\n\n#### \"blockUpdate\" (oldBlock, newBlock)\n\n(It is better to use this event from bot.world instead of bot directly) Fires when a block updates. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\n注意:  `oldBlock` 可能为 `null`\n\n#### \"blockUpdate:(x, y, z)\" (oldBlock, newBlock)\n\n(It is better to use this event from bot.world instead of bot directly) Fires for a specific point. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\n注意:  `oldBlock` 可能为 `null`\n\n#### \"blockPlaced\" (oldBlock, newBlock)\n\n当机器人放置方块时触发. Both `oldBlock` and `newBlock` provided for\ncomparison.\n\n注意:  `oldBlock` 可能为 `null`\n\n#### \"chunkColumnLoad\" (point)\n#### \"chunkColumnUnload\" (point)\n\n当区块已更新时触发. `point` is the coordinates to the corner of the chunk with the smallest x, y, and z values.\n\n#### \"soundEffectHeard\" (soundName, position, volume, pitch)\n\n当客户端听到指定的音效时触发\n\n * `soundName`: 音效名称\n * `position`:  Vec3 实例，声音从哪里发出（译者注：vec3即 x,y,z坐标\n * `volume`: 浮点数音量, 1.0 为100%\n * `pitch`: 整数音高，63为100%\n\n#### \"hardcodedSoundEffectHeard\" (soundId, soundCategory, position, volume, pitch)\n\n  Fires when the client hears a hardcoded sound effect.\n\n   * `soundId`: id of the sound effect\n   * `soundCategory`: category of the sound effect\n   * `position`: a Vec3 instance where the sound originates\n   * `volume`: floating point volume, 1.0 is 100%\n   * `pitch`: integer pitch, 63 is 100%\n\n#### \"noteHeard\" (block, instrument, pitch)\n\n当一个音符块在某处响起时触发\n\n * `block`: a Block instance, the block that emitted the noise\n * `instrument`:\n   - `id`: integer id\n   - `name`: one of [`harp`, `doubleBass`, `snareDrum`, `sticks`, `bassDrum`].\n * `pitch`: The pitch of the note (between 0-24 inclusive where 0 is the\n   lowest and 24 is the highest). More information about how the pitch values\n   correspond to notes in real life are available on the\n   [official Minecraft wiki](http://minecraft.wiki/w/Note_Block).\n\n#### \"pistonMove\" (block, isPulling, direction)\n\n#### \"chestLidMove\" (block, isOpen, block2)\n* `block`: a Block instance, the block whose lid opened. The right block if it's a double chest\n* `isOpen`: number of players that have the chest open. 0 if it's closed\n* `block2`: a Block instance, the other half of the block whose lid opened. null if it's not a double chest\n\n#### \"blockBreakProgressObserved\" (block, destroyStage)\n\nFires when the client observes a block in the process of being broken.\n\n * `block`: a Block instance, the block being broken\n * `destroyStage`: integer corresponding to the destroy progress (0-9)\n\n#### \"blockBreakProgressEnd\" (block)\n\nFires when the client observes a block stops being broken.\nThis occurs whether the process was completed or aborted.\n\n * `block`: a Block instance, the block no longer being broken\n\n#### \"diggingCompleted\" (block)\n\n * `block` - 方块不再存在\n\n#### \"diggingAborted\" (block)\n\n * `block` - 方块仍然存在\n\n#### \"usedFirework\" (fireworkEntityId)\n\n在机器人在鞘翅飞行时使用烟花火箭时触发\n\n * `fireworkEntityId` - 烟花火箭的实体编号\n\n#### \"move\"\n\n当机器人移动时触发. 如果需要当前位置，请使用\n`bot.entity.position` 对于正常移动，如果您想要上一个位置，请使用\n`bot.entity.position.minus(bot.entity.velocity)`.\n\n#### \"forcedMove\"\n\nFires when the bot is force moved by the server (teleport, spawning, ...). If you want the current position, use\n`bot.entity.position`.\n\n#### \"mount\"\n\n乘骑实体（如矿车）时触发\n\n要访问实体，请使用 `bot.vehicle`.\n\n要乘骑实体, 请使用 `mount`.\n\n#### \"dismount\" (vehicle)\n\n实体从坐骑上下马时触发\n\n#### \"windowOpen\" (window)\n\nFires when you begin using a workbench, chest, brewing stand, etc.\n\n#### \"windowClose\" (window)\n\nFires when you may no longer work with a workbench, chest, etc.\n\n#### \"sleep\"\n\n睡觉时触发\n\n#### \"wake\"\n\n当你醒来的时候触发\n\n#### \"experience\"\n\n当 `bot.experience.*` 经验点数变化时触发\n\n#### \"scoreboardCreated\" (scoreboard)\n\n记分牌被添加时触发\n\n#### \"scoreboardDeleted\" (scoreboard)\n\n记分板被删除时触发\n\n#### \"scoreboardTitleChanged\" (scoreboard)\n\n当记分牌标题更新时触发\n\n#### \"scoreUpdated\" (scoreboard, item)\n\nFires when the score of a item in a scoreboard is updated.\n\n#### \"scoreRemoved\" (scoreboard, item)\n\nFires when the score of a item in a scoreboard is removed.\n\n#### \"scoreboardPosition\" (position, scoreboard)\n\nFires when the position of a scoreboard is updated.\n\n#### \"teamCreated\" (team)\n\n添加队伍时触发\n\n#### \"teamRemoved\" (team)\n\n队伍被移除触发\n\n#### \"teamUpdated\" (team)\n\n更新队伍触发\n\n#### \"teamMemberAdded\" (team)\n\nFires when a team member or multiple members are added to a team.\n\n#### \"teamMemberRemoved\" (team)\n\nFires when a team member or multiple members are removed from a team.\n\n#### \"bossBarCreated\" (bossBar)\n\n新boss栏创建时触发\n\n#### \"bossBarDeleted\" (bossBar)\n\n新boss栏删除时激发。\n\n#### \"bossBarUpdated\" (bossBar)\n\n更新新boss栏时触发\n\n#### \"heldItemChanged\" (heldItem)\n\n手持物品变动时触发\n\n#### \"physicsTick\" ()\n\n如果 bot.physicsEnabled 设为true则每tick触发一次\n\n#### \"chat:name\" (matches)\n\nFires when the all of a chat pattern's regexs have matches\n\n### Functions\n\n#### bot.blockAt(point, extraInfos=true)\n\nReturns the block at `point` or `null` if that point is not loaded. If `extraInfos` set to true, also returns informations about signs, paintings and block entities (slower).\nSee `Block`.\n\n#### bot.waitForChunksToLoad(cb)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nThe cb gets called when many chunks have loaded.\n\n#### bot.blockInSight(maxSteps, vectorLength)\n\nDeprecated, use `blockAtCursor` instead.\n\nReturns the block at which bot is looking at or `null`\n * `maxSteps` - Number of steps to raytrace, defaults to 256.\n * `vectorLength` - Length of raytracing vector, defaults to `5/16`.\n\n#### bot.blockAtCursor(maxDistance=256)\n\nReturns the block at which bot is looking at or `null`\n * `maxDistance` - The maximum distance the block can be from the eye, defaults to 256.\n\n#### bot.blockAtEntityCursor(entity=bot.entity, maxDistance=256)\n\nReturns the block at which specific entity is looking at or `null`\n * `entity` - Entity data as `Object`\n * `maxDistance` - The maximum distance the block can be from the eye, defaults to 256.\n\n#### bot.canSeeBlock(block)\n\nReturns true or false depending on whether the bot can see the specified `block`.\n\n#### bot.findBlocks(options)\n\nFinds the closest blocks from the given point.\n * `options` - Options for the search:\n   - `point` - The start position of the search (center). Default is the bot position.\n   - `matching` - A function that returns true if the given block is a match. Also supports this value being a block id or array of block ids.\n   - `useExtraInfo` - To preserve backward compatibility can result in two behavior depending on the type\n      - **boolean** - Provide your `matching` function more data - noticeably slower aproach\n      - **function** - Creates two stage maching, if block passes `matching` function it is passed further to `useExtraInfo` with additional info\n   - `maxDistance` - The furthest distance for the search, defaults to 16.\n   - `count` - Number of blocks to find before returning the search. Default to 1. Can return less if not enough blocks are found exploring the whole area.\n\nReturns an array (possibly empty) with the found block coordinates (not the blocks). The array is sorted (closest first)\n\n#### bot.findBlock(options)\n\nAlias for `bot.blockAt(bot.findBlocks(options)[0])`. Return a single block or `null`.\n\n#### bot.canDigBlock(block)\n\nReturns whether `block` is diggable and within range.\n\n#### bot.recipesFor(itemType, metadata, minResultCount, craftingTable)\n\nReturns a list of `Recipe` instances that you could use to craft `itemType`\nwith `metadata`.\n\n * `itemType` - numerical item id of the thing you want to craft\n * `metadata` - the numerical metadata value of the item you want to craft\n   `null` matches any metadata.\n * `minResultCount` - based on your current inventory, any recipe from the\n   returned list will be able to produce this many items. `null` is an\n   alias for `1`.\n * `craftingTable` - a `Block` instance. If `null`, only recipes that can\n   be performed in your inventory window will be included in the list.\n\n#### bot.recipesAll(itemType, metadata, craftingTable)\n\nThe same as bot.recipesFor except that it does not check wether the bot has enough materials for the recipe.\n\n#### bot.nearestEntity(match = (entity) => { return true })\n\nReturn the nearest entity to the bot, matching the function (default to all entities). Return null if no entity is found.\n\n示例:\n```js\nconst cow = bot.nearestEntity(entity => entity.name.toLowerCase() === 'cow') // 我们使用 .toLowercase() 因为在1.8版本中，cow是大写的，这样可以适用于新版本\n```\n\n### Methods\n\n#### bot.end(reason)\n\nEnd the connection with the server.\n* `reason` - Optional string that states the reason of the end.\n\n#### bot.quit(reason)\n\nGracefully disconnect from the server with the given reason (defaults to 'disconnect.quitting').\n\n#### bot.tabComplete(str, cb, [assumeCommand], [sendBlockInSight])\n\nThis function also returns a `Promise`, with `matches` as its argument upon completion.\n\nRequests chat completion from the server.\n * `str` - String to complete.\n * `callback(matches)`\n   - `matches` - Array of matching strings.\n * `assumeCommand` - Field sent to server, defaults to false.\n * `sendBlockInSight` - Field sent to server, defaults to true. Set this option to false if you want more performance.\n\n#### bot.chat(message)\n\nSends a publicly broadcast chat message. Breaks up big messages into multiple chat messages as necessary.\n\n#### bot.whisper(username, message)\n\nShortcut for \"/tell <username>\". All split messages will be whispered to username.\n\n#### bot.chatAddPattern(pattern, chatType, description)\n\nDeprecated, use `addChatPattern` instead.\n\nAdds a regex pattern to the bot's chat matching. Useful for bukkit servers where the chat format changes a lot.\n * `pattern` - regular expression to match chat\n * `chatType` - the event the bot emits when the pattern matches. Eg: \"chat\" or \"whisper\"\n * 'description ' - Optional, describes what the pattern is for\n\n#### bot.addChatPattern(name, pattern, chatPatternOptions)\n\n** this is an alias of `bot.addChatPatternSet(name, [pattern], chatPatternOptions)`\n\nmake an event that is called every time the pattern is matched to a message,\nthe event will be called `\"chat:name\"`, with name being the name passed\n* `name` - the name used to listen for the event\n* `pattern` - regular expression to match to messages recieved\n* `chatPatternOptions` - object\n  * `repeat` - defaults to true, whether to listen for this event after the first match\n  * `parse` - instead of returning the actual message that was matched, return the capture groups from the regex\n  * `deprecated` - (**unstable**) used by bot.chatAddPattern to keep compatability, likely to be removed\n\nreturns a number which can be used with bot.removeChatPattern() to only delete this pattern\n\n#### bot.addChatPatternSet(name, patterns, chatPatternOptions)\n\nmake an event that is called every time all patterns havee been matched to messages,\nthe event will be called `\"chat:name\"`, with name being the name passed\n* `name` - the name used to listen for the event\n* `patterns` - array of regular expression to match to messages recieved\n* `chatPatternOptions` - object\n  * `repeat` - defaults to true, whether to listen for this event after the first match\n  * `parse` - instead of returning the actual message that was matched, return the capture groups from the regex\n\nreturns a number which can be used with bot.removeChatPattern() to only delete this patternset\n\n#### bot.removeChatPattern(name)\n\nremoves a chat pattern(s)\n* `name` : string or number\n\nif name is a string, all patterns that have that name will be removed\nelse if name is a number, only that exact pattern will be removed\n\n#### bot.awaitMessage(...args)\n\npromise that is resolved when one of the messages passed as an arg is resolved\n\nExample:\n\n```js\nasync function wait () {\n  await bot.awaitMessage('<flatbot> hello world') // resolves on \"hello world\" in chat by flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world']) // resolves on \"hello\" or \"world\" in chat by flatbot\n  await bot.awaitMessage(['<flatbot> hello', '<flatbot> world'], ['<flatbot> im', '<flatbot> batman']) // resolves on \"hello\" or \"world\" or \"im\" or \"batman\" in chat by flatbot\n  await bot.awaitMessage('<flatbot> hello', '<flatbot> world') // resolves on \"hello\" or \"world\" in chat by flatbot\n  await bot.awaitMessage(/<flatbot> (.+)/) // resolves on first message matching the regex\n}\n```\n\n#### bot.setSettings(options)\n\nSee the `bot.settings` property.\n\n#### bot.loadPlugin(plugin)\n\nInjects a Plugin. Does nothing if the plugin is already loaded.\n\n * `plugin` - function\n\n```js\nfunction somePlugin (bot, options) {\n  function someFunction () {\n    bot.chat('Yay!')\n  }\n\n  bot.myPlugin = {} // Good practice to namespace plugin API\n  bot.myPlugin.someFunction = someFunction\n}\n\nconst bot = mineflayer.createBot({})\nbot.loadPlugin(somePlugin)\nbot.once('login', function () {\n  bot.myPlugin.someFunction() // Yay!\n})\n```\n\n#### bot.loadPlugins(plugins)\n\nInjects plugins see `bot.loadPlugin`.\n * `plugins` - array of functions\n\n#### bot.hasPlugin(plugin)\n\nChecks if the given plugin is loaded (or scheduled to be loaded) on this bot.\n\n#### bot.sleep(bedBlock, [cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nSleep in a bed. `bedBlock` should be a `Block` instance which is a bed. `cb` can have an err parameter if the bot cannot sleep.\n\n#### bot.isABed(bedBlock)\n\nReturn true if `bedBlock` is a bed\n\n#### bot.wake([cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nGet out of bed. `cb` can have an err parameter if the bot cannot wake up.\n\n#### bot.setControlState(control, state)\n\nThis is the main method controlling the bot movements. It works similarly to pressing keys in minecraft.\nFor example forward with state true will make the bot move forward. Forward with state false will make the bot stop moving forward.\nYou may use bot.lookAt in conjunction with this to control movement. The jumper.js example shows how to use this.\n\n * `control` - one of ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n * `state` - `true` or `false`\n\n#### bot.getControlState(control)\n\nReturns true if a control state is toggled.\n\n* `control` - one of ['forward', 'back', 'left', 'right', 'jump', 'sprint', 'sneak']\n\n#### bot.clearControlStates()\n\nSets all controls to off.\n\n#### bot.getExplosionDamages(entity, position, radius, [rawDamages])\n\nReturns how much damage will be done to the entity in a radius around the position of the explosion.\nIt will return `null` if the entity has no armor and rawDamages is not set to true, since the function can't calculate the damage with armor if there is no armor.\n\n* `entity` - Entity instance\n* `position` - [Vec3](https://github.com/andrewrk/node-vec3) instance\n* `radius` - the explosion radius as a number\n* `rawDamages` - optional, if true it ignores armor in the calculation\n\n#### bot.lookAt(point, [force], [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `point` [Vec3](https://github.com/andrewrk/node-vec3) instance - tilts your head so that it is directly facing this point.\n * `force` - See `force` in `bot.look`\n * `callback()` optional, called when you are looking at `point`\n\n#### bot.look(yaw, pitch, [force], [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nSet the direction your head is facing.\n\n * `yaw` - The number of radians to rotate around the vertical axis, starting\n   from due east. Counter clockwise.\n * `pitch` - Number of radians to point up or down. 0 means straight forward.\n   pi / 2 means straight up. -pi / 2 means straight down.\n * `force` - If present and true, skips the smooth server-side transition.\n   Specify this to true if you need the server to know exactly where you\n   are looking, such as for dropping items or shooting arrows. This is not\n   needed for client-side calculation such as walking direction.\n * `callback()` optional, called when you are looking at `yaw` and `pitch`\n\n#### bot.updateSign(block, text)\n\nChanges the text on the sign.\n\n#### bot.equip(item, destination, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nEquips an item from your inventory. If the argument `item` is of Instance `Item` equip will equip this specific item from its window slot. If the argument `item` is of type `number` equip will equip the first item found with that id searched by rising slot id (Hotbar is searched last. Armor, crafting, crafting result and off-hand slots are excluded).\n\n * `item` - `Item` instance or `number` for item id. See `window.items()`.\n * `destination`\n   - `\"hand\"` - `null` aliases to this\n   - `\"head\"`\n   - `\"torso\"`\n   - `\"legs\"`\n   - `\"feet\"`\n   - `\"off-hand\"` - when available\n * `callback(error)` - optional. called when you have successfully equipped\n   the item or when you learn that you have failed to equip the item.\n\n#### bot.unequip(destination, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nRemove an article of equipment.\n\n#### bot.tossStack(item, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `item` - the stack of items you wish to toss\n * `callback(error)` - optional, called when tossing is done. if error is\n   truthy, you were not able to complete the toss.\n\n#### bot.toss(itemType, metadata, count, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `itemType` - numerical id of the item you wish to toss\n * `metadata` - metadata of the item you wish to toss. Use `null`\n   to match any metadata\n * `count` - how many you want to toss. `null` is an alias for `1`.\n * `callback(err)` - (optional) called once tossing is complete\n\n#### bot.dig(block, [forceLook = true], [digFace], [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nBegin digging into `block` with the currently equipped item.\nSee also \"diggingCompleted\" and \"diggingAborted\" events.\n\nNote that once you begin digging into a block, you may not\ndig any other blocks until the block has been broken, or you call\n`bot.stopDigging()`.\n\n * `block` - the block to start digging into\n * `forceLook` - (optional) if true, look at the block and start mining instantly. If false, the bot will slowly turn to the block to mine. Additionally, this can be assigned to 'ignore' to prevent the bot from moving it's head at all. Also, this can be assigned to 'raycast' to raycast from the bots head to place where the bot is looking.\n * `digFace` - (optional) Default is 'auto' looks at the center of the block and mines the top face. Can also be a vec3 vector\n of the face the bot should be looking at when digging the block. For example: ```vec3(0, 1, 0)``` when mining the top. Can also be 'raycast' raycast checks if there is a face visible by the bot and mines that face. Useful for servers with anti cheat.\n * `callback(err)` - (optional) called when the block is broken or you\n   are interrupted.\n\nIf you call bot.dig twice before the first dig is finished, you will get a fatal 'diggingAborted' error.\n\n#### bot.stopDigging()\n\n#### bot.digTime(block)\n\nTells you how long it will take to dig the block, in milliseconds.\n\n#### bot.acceptResourcePack()\n\nAccepts resource pack.\n\n#### bot.denyResourcePack()\n\nDenies resource pack.\n\n#### bot.placeBlock(referenceBlock, faceVector, cb)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `referenceBlock` - the block you want to place a new block next to\n * `faceVector` - one of the six cardinal directions, such as `new Vec3(0, 1, 0)` for the top face,\n   indicating which face of the `referenceBlock` to place the block against.\n * `cb` will be called when the server confirms that the block has indeed been placed\n\nThe new block will be placed at `referenceBlock.position.plus(faceVector)`.\n\n#### bot.placeEntity(referenceBlock, faceVector)\n\nThis function also returns a `Promise`, with `Entity` as its argument upon completion.\n\n * `referenceBlock` - the block you want to place the entity next to\n * `faceVector` - one of the six cardinal directions, such as `new Vec3(0, 1, 0)` for the top face,\n   indicating which face of the `referenceBlock` to place the block against.\n\nThe new block will be placed at `referenceBlock.position.plus(faceVector)`.\n\n#### bot.activateBlock(block, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nPunch a note block, open a door, etc.\n\n * `block` - the block to activate\n * `callback(err)` - (optional) called when the block has been activated\n\n#### bot.activateEntity(entity, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nActivate an entity, useful for villager for example.\n\n * `entity` - the entity to activate\n * `callback(err)` - (optional) called when the entity has been activated\n\n#### bot.activateEntityAt(entity, position, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nActivate an entity at the given position, useful for armor stands.\n\n * `entity` - the entity to activate\n * `position` - the world position to click at\n * `callback(err)` - (optional) called when the entity has been activated\n\n#### bot.consume(callback)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nEat / drink currently held item\n\n * `callback(error)` - called when consume ends\n\n#### bot.fish(callback)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nUse fishing rod\n\n * `callback(error)` - called when fishing ends\n\n#### bot.activateItem(offHand=false)\n\nActivates the currently held item. This is how you eat, shoot bows, throw an egg, etc.\nOptional parameter is `false` for main hand and `true` for off hand.\n\n#### bot.deactivateItem()\n\nDeactivates the currently held item. This is how you release an arrow, stop eating, etc.\n\n#### bot.useOn(targetEntity)\n\nUse the currently held item on an `Entity` instance. This is how you apply a saddle and\nuse shears.\n\n#### bot.attack(entity, swing = true)\n\nAttack a player or a mob.\n\n * `entity` is a type of entity. To get a specific entity use [bot.nearestEntity()](#botnearestentitymatch--entity---return-true-) or [bot.entities](#botentities).\n * `swing` Default `true`. If false the bot does not swing is arm when attacking.\n\n#### bot.swingArm([hand], showHand)\n\nPlay an arm swing animation.\n\n * `hand` can take `left` or `right` which is arm that is animated. Default: `right`\n * `showHand` is a boolean whether to add the hand to the packet, Default: `true`\n\n#### bot.mount(entity)\n\nMount a vehicle. To get back out, use `bot.dismount`.\n\n#### bot.dismount()\n\nDismounts from the vehicle you are in.\n\n#### bot.moveVehicle(left,forward)\n\nMoves the vehicle :\n\n * left can take -1 or 1 : -1 means right, 1 means left\n * forward can take -1 or 1 : -1 means backward, 1 means forward\n\nAll the direction are relative to where the bot is looking at\n\n#### bot.setQuickBarSlot(slot)\n\n * `slot` - 0-8 the quick bar slot to select.\n\n#### bot.craft(recipe, count, craftingTable, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `recipe` - A `Recipe` instance. See `bot.recipesFor`.\n * `count` - How many times you wish to perform the operation.\n   If you want to craft planks into `8` sticks, you would set\n   `count` to `2`. `null` is an alias for `1`.\n * `craftingTable` - A `Block` instance, the crafting table you wish to\n   use. If the recipe does not require a crafting table, you may use\n   `null` for this argument.\n * `callback` - (optional) Called when the crafting is complete and your\n   inventory is updated.\n\n#### bot.writeBook(slot, pages, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\n * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).\n * `pages` is an array of strings represents the pages.\n * `callback(error)` - optional. called when the writing was successfully or an error occurred.\n\n#### bot.openContainer(containerBlock or containerEntity)\n\nReturns a promise on a `Container` instance which represents the container you are opening.\n\n#### bot.openChest(chestBlock or minecartchestEntity)\n\nDeprecated. Same as `openContainer`\n\n#### bot.openFurnace(furnaceBlock)\n\nReturns a promise on a `Furnace` instance which represents the furnace you are opening.\n\n#### bot.openDispenser(dispenserBlock)\n\nDeprecated. Same as `openContainer`\n\n#### bot.openEnchantmentTable(enchantmentTableBlock)\n\nReturns a promise on an `EnchantmentTable` instance which represents the enchantment table\nyou are opening.\n\n#### bot.openAnvil(anvilBlock)\n\nReturns a promise on an `anvil` instance which represents the anvil you are opening.\n\n#### bot.openVillager(villagerEntity)\n\nReturns a promise on a `Villager` instance which represents the trading window you are opening.\nYou can listen to the `ready` event on this `Villager` to know when it's ready\n\n#### bot.trade(villagerInstance, tradeIndex, [times], [cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nUses the open `villagerInstance` to trade.\n\n#### bot.setCommandBlock(pos, command, [options])\n\nSet a command block's properties at `pos`.\nExample `options` argument:\n\n```js\n{\n  mode: 2,\n  trackOutput: true,\n  conditional: false,\n  alwaysActive: true\n}\n```\noptions.mode can have 3 values: 0 (SEQUENCE), 1 (AUTO), 2 (REDSTONE)\nAll options attributes are false by default, except mode which is 2 (as to replicate the default command block in Minecraft).\n\n#### bot.supportFeature(name)\n\nThis can be used to check is a specific feature is available in the current Minecraft version. This is usually only required for handling version-specific functionality.\n\nThe list of available features can be found inside the [./lib/features.json](https://github.com/PrismarineJS/mineflayer/blob/master/lib/features.json) file.\n\n#### bot.waitForTicks(ticks)\n\nThis is a promise-based function that waits for a given number of in-game ticks to pass before continuing. This is useful for quick timers that need to function with specific timing, regardless of the given physics tick speed of the bot. This is similar to the standard Javascript setTimeout function, but runs on the physics timer of the bot specifically.\n\n### Lower level inventory methods\n\nThese are lower level methods for the inventory, they can be useful sometimes but prefer the inventory methods presented above if you can.\n\n#### bot.clickWindow(slot, mouseButton, mode, cb)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nClick on the current window. See details at https://minecraft.wiki/w/Protocol#Click_Window\n\n#### bot.putSelectedItemRange(start, end, window, slot)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nPut the item at `slot` in the specified range.\n\n#### bot.putAway(slot)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nPut the item at `slot` in the inventory.\n\n#### bot.closeWindow(window)\n\nClose the `window`.\n\n#### bot.transfer(options, cb)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nTransfer some kind of item from one range to an other. `options` is an object containing :\n\n * `window` : the window where the item will be moved\n * `itemType` : the type of the moved items\n * `metadata` : the metadata of the moved items\n * `sourceStart` and `sourceEnd` : the source range\n * `destStart` and `destEnd` : the dest Range\n * `count` : the amount of items to transfer. Default: `1`\n * `nbt` : nbt data of the item to transfer. Default: `nullish` (ignores nbt)\n\n#### bot.openBlock(block)\n\nOpen a block, for example a chest, returns a promise on the opening `Window`.\n\n * `block` is the block the bot will open\n\n#### bot.openEntity(entity)\n\nOpen an entity with an inventory, for example a villager, returns a promise on the opening `Window`.\n\n * `entity` is the entity the bot will open\n\n#### bot.moveSlotItem(sourceSlot, destSlot, cb)\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nMove an item from `sourceSlot` to `destSlot` in the current window.\n\n#### bot.updateHeldItem()\n\nUpdate `bot.heldItem`.\n\n#### bot.getEquipmentDestSlot(destination)\n\nGets the inventory equipment slot id for the given equipment destination name.\n\nAvailable destinations are:\n* head\n* torso\n* legs\n* feet\n* hand\n* off-hand\n\n### bot.creative\n\nThis collection of apis is useful in creative mode.\nDetecting and changing gamemodes is not implemented here,\nbut it is assumed and often required that the bot be in creative mode for these features to work.\n\n#### bot.creative.setInventorySlot(slot, item, [callback])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nGives the bot the specified item in the specified inventory slot.\nIf called twice on the same slot before first callback exceeds, first callback will have an error parameter\n\n * `slot` is in inventory window coordinates (where 36 is the first quickbar slot, etc.).\n * `item` is a [prismarine-item](https://github.com/PrismarineJS/prismarine-item) instance specified with arbitrary metadata, nbtdata, etc.\n    If `item` is `null`, the item at the specified slot is deleted.\n * `callback(err)` (optional) is a callback which gets fired when the servers sets the slot\n\nIf this method changes anything, you can be notified via `bot.inventory.on(\"updateSlot\")`.\n\n#### bot.creative.flyTo(destination, [cb])\n\nThis function also returns a `Promise`, with `void` as its argument upon completion.\n\nCalls `startFlying()` and moves at a constant speed through 3d space in a straight line to the destination.\n`destination` is a `Vec3`, and often the `x` and `z` coordinates will end with `.5`.\nThis operation will not work if there is an obstacle in the way,\nso it is advised to fly very short distances at a time.\n\nWhen the bot arrives at the destination, `cb` is called.\n\nThis method does not attempt any path finding.\nIt is expected that a path finding implementation will use this method to move < 2 blocks at a time.\n\nTo resume normal physics, call `stopFlying()`.\n\n#### bot.creative.startFlying()\n\nSets `bot.physics.gravity` to `0`.\nTo resume normal physics, call `stopFlying()`.\n\nThis method is useful if you want to hover while digging the ground below you.\nIt is not necessary to call this function before calling `flyTo()`.\n\nNote that while flying, `bot.entity.velocity` will not be accurate.\n\n#### bot.creative.stopFlying()\n\nRestores `bot.physics.gravity` to it's original value.\n"
  },
  {
    "path": "docs/zh/demos.md",
    "content": "## mineflayer-navigate\n\n[navigate](https://github.com/andrewrk/mineflayer-navigate/) -  轻松使用A*寻路\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/O6lQdmRz8eE\" frameborder=\"0\"></iframe>\n\n## rbot\n\n[rom1504/rbot](https://github.com/rom1504/rbot) 基于mineflayer的智能机器人\n\n<iframe type=\"text/html\" width=\"640\" height=\"360\" src=\"http://www.youtube.com/embed/0cQxg9uDnzA\" frameborder=\"0\"></iframe>\n\n## chaoscraft\n\n[Chaoscraft](https://github.com/schematical/chaoscraft) 基于genetic算法的Minecraft机器人\n\n\n<iframe width=\"640\" height=\"360\" src=\"https://www.youtube.com/embed/videoseries?list=PLLkpLgU9B5xJ7Qy4kOyBJl5J6zsDIMceH\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen></iframe>"
  },
  {
    "path": "docs/zh/history.md",
    "content": "## 3.14.0\n\n* Make prismarine-entity versioned (@u9g)\n* fix(typings): Added OpenContainer (@SaubereSache)\n\n## 3.13.1\n\n* Fix bug with force lastSentPitch in bot.look (@KadaverBrutalo10)\n* Fix typo harming type safety (@Eagle-Anne)\n\n## 3.13.0\n\n* 动态计算记分板显示名称displayName  (@U9G)\n* 修复 SkinsRestorer(@U5B)\n* 修复机器人放置方块时不摆臂 (@IceTank)\n\n## 3.12.0\n\n* Bypass anticheats that detect sensitivity (@mat-1)\n* 修复了一次从tab列表中删除多个玩家的问题 (@mat-1)\n* Added blockAtEntityCursor function (@DatArnoGuy)\n* add option to disable default chat patterns (@U5B)\n* Fixed wrong arm swinging (@IceTank)\n* Add pitch speed to look (@IceTank)\n* 修复控制台垃圾信息 (@IceTank)\n* Update openVillager function to return a promise (@amoraschi)\n* Send arm_animation before use_entity (@aesthetic0001)\n* Add reason for the end of a mineflayer bot (@U5B)\n* added rejection of invalid transaction packets (anticheat fix) (@U5B)\n\n## 3.11.2\n* Remove unnecessary and buggy inventory check in place block (@Karang)\n* Make all events allow async cb typings (@u9g)\n\n## 3.11.1\n* Get rid of nowaiting (@nickelpro)\n* 更新readme文件 (@inthmafr)\n* 修复打字相关(@link-discord, @IceTank, @u9g)\n\n## 3.11.0\n* 优化聊天, 装备和消耗错误 (@u9g)\n* 增加 bot.usingHeldItem (@mat1)\n* 支持 1.17.1 (主要工作是 @nickelpro 和 @u9g 完成的, 还有 @Archengius @extremeheat @imharvol @willocn @rom1504)\n\n## 3.10.0\n* 添加中文翻译 (@Nyaasu66)\n* Fix bot.equip failing with off-hand (@IceTank)\n* window.withdraw no longer will drop items if it takes too many items (@Zn10plays)\n* No longer have to await ready for enchanting (@u9g)\n* Remove polling, recursive calling, rechecks for bot.waitForChunksToLoad (@u9g)\n* Add crystal placing example (@u9g)\n* Fixes physicsEnabled check for knockback (@u9g)\n* Default swingArm to left hand (@u9g)\n* Add support for teams (@builder-247)\n* Add missing bot.transfer documentation (@IceTank)\n\n## 3.9.0\n* Fix crash on blocks without registered blockId (@Furry)\n* Move when hit by an explsion (@u9g)\n* Add getExplosionDamages() function (@Karang)\n* doc of get explosion (@link-discord)\n\n## 3.8.0\n* 改进 index.d.ts (@DrMoraschi)\n* 增加资源包支持 (@kaffinpx)\n* 修复 bot.dig 错误(@MoneyMakingTornado)\n* Added timeout to #consume (@SeanmcCord)\n* 增加资源包示例 (@u9g)\n* 改进工作流程 (@u9g)\n* Linted JS in md files (@u9g)\n* Added bot oxygen Level management (@kaffinpx)\n* Improved links (@satyamedh)\n* Improved links (@AwesomestCode)\n* Improved typing (@u9g)\n* Refactored chat.js (@u9g)\n* Expanded placeBlockWith Options to offhand (@aestetic)\n* Added anvil test (@u9g)\n* Added placeEntity() (@u9g)\n* Improved oxygen typings (@DrMoraschi)\n* Improved socket snippet (@iceTank)\n* Improved placeEntity (@u9g)\n* Renamed bot.quit to end (@u9g)\n* Updated Spanish readme (@DrMoraschi)\n* Added French Translations (@creeper09)\n* Corrected java version in gitpod (@rom)\n* Improved readme lint (@rom)\n* Added container and dropper to allowWindowTypes (@IceTank)\n\n\n## 3.7.0\n* Add bot.removeChatPattern() (@BlueBurgersTDD)\n* Add events to typings (@DrMoraschi)\n* Add TR translation (@KaffinPX)\n* Create plugin example (@Zn10plays)\n* Revise readme (@IceTank)\n* Revise chat_parsing example comments (@U5B)\n* Revise raycast example (@IceTank)\n* allow passing nmpclient as an option in createbot (@u9g)\n* Add bot.awaitMessage() (@u9g)\n* Add modular example (@u9g)\n* Fix bug with chat patterns (@u9g)\n* Fix bug with game event (@u9g)\n\n## 3.6.0\n* add bot.addChatPattern() & bot.addChatPatternSet() & deprecate bot.chatAddPattern() (@U9G)\n\n## 3.5.0\n* Add common errors to FAQ (@U9G)\n* Move mosts of index.js to lib/loader.js (@U9G)\n* Improve packet_info handling (@Karang)\n* Add getControlState function (@Camezza)\n\n## 3.4.0\n* fix once leak in placeBlock (@Karang)\n* allow sleeping during rain/thunderstorms (@qrvd)\n* Change transaction apology packet to match vanilla client (@FeldrinH)\n\n## 3.3.3\n* fix world switch leak\n\n## 3.3.2\n* 修复实体名称\n\n## 3.3.1\n* 修复停止挖掘 (@Karang)\n\n## 3.3.0\n* 修复交易相关 (@validgem)\n* 修复附魔相关 (@goncharovchik)\n* fix newListener and removeListener stacking on world change (@U5B)\n* 增加 'messagestr' 事件(@U9G)\n* Add an option forceLook for place block similar to the digging one (@CyberPatrick)\n* Can see block add intersect match (@sefirosweb)\n* Add ability to use an anvil fully (@U9G)\n\n## 3.2.0\n* Fix position in getBlock()\n\n## 3.1.0\n* Fix typings of findBlock and findBlocks (@csorfab)\n* place block improvements (@Karang)\n* add face option to dig (@IceTank)\n* trading fixes (@validgem)\n* world events exposed by pworld (@u9g)\n* fix wait for ticks and expose physicsEnabled (@Karang)\n\n## 3.0.0\n* added null or undefined check in inventory (@u9g)\n* Removed broken use of \"this\" in physics.js (@TheDudeFromCI)\n* Promisify testCommon (@ArcticZeroo)\n* Fixed Bot not skipping end credits (@IceTank)\n* BREAKING: Simplify windows API and promisify tests (@Karang) : several methods and events from window API were changed:\n  * Removed Chest, EnchantmentTable, Furnace, Dispenser and Villager classes (they all are Windows now)\n  * Dispensers are now handled by the same code as other containers, hopper too (they were missing)\n  * There is now only 2 events signaling a slot update (\"updateSlot\" and \"updateSlot:slotId\" of the Window class) (before there was: \"setSlot\", \"setSlot:windowId\", \"windowUpdate\", \"updateSlot\", on 3 different eventEmitter (and not all of them were working properly))\n  * All windows (present and future) now have a withdraw and deposit function\n\n## 2.41.0\n* Fix Time type definition (@hivivo)\n* Add face for block in sight result (@Karang)\n* Fix skin restorer bug (@TheDudeFromCI)\n* Improve enchantment table info (@Karang)\n* 支持 1.16.5 (@rom1504)\n\n## 2.40.1\n* Fix for not handling negative numbers in time plugin (@Naomi)\n* Fix typescript Bot definition (@rom1504)\n\n## 2.40.0\n* fix for dig ignore (@TheDudeFromCI)\n* better calculation of digging range (@goncharovchik)\n* emit death once (@extremeheat)\n* add waitForTicks function (@TheDudeFromCI)\n* add null check for sign text (@u9g)\n\n## 2.39.2\n* explicit node 14 support\n\n## 2.39.1\n* add null check in bot.dig (@rom1504)\n* Fix deprecation warning for block in sight (@Karang)\n\n## 2.39.0\n* Add number support to bot.chat (@BlueBurgersTDD)\n* Fixed && Improved blockFind function with useExtraInfo = true (@magicaltoast)\n* Added option to allow the bot to keep it's head in place when mining. (@TheDudeFromCI)\n\n## 2.38.0\n* Add bot.game.serverBrand property (@Karang)\n* set extraInfos to false in blockIsNotEmpty (@mat-1)\n* make the ChatMessage.toAnsi:lang argument optional (@Antonio32A)\n* Fixed message types (@TheDudeFromCI)\n* by default hideErrors is now true (@rom1504)\n\n## 2.37.1\n* Optimize lookAt promise behavior (@ph0t0shop)\n\n## 2.37.0\n* Promisify villager & Trader (thanks @ph0t0shop)\n* protect against action id going over 32767 (@rom1504)\n* fix incorrect handling of username definition (@rom1504)\n\n## 2.36.0\n* all async method now both return promises and take a callback (thanks @ph0t0shop for this great improvement)\n\n## 2.35.0\n* Extra position packet after TP\n* Add blockAtCursor\n* Deprecate blockInSight\n* TS typing fixes\n\n## 2.34.0\n* 支持 1.16.4\n\n## 2.33.0\n* block_actions fix (thanks @SpikeThatMike)\n* typescript fixes (thanks @TheDudeFromCI and @NotSugden)\n* add uuid by objectUUID handling (thanks @Rob9315)\n* fix bed packet (thanks @imharvol)\n* better plugin handling (thanks @TheDudeFromCI)\n\n## 2.32.0\n* 支持 1.16.3 (感谢@GroobleDierne 和 @TheDudeFromCI)\n* fix bug with entity width (thanks @TheDudeFromCI)\n* Add ability to call openChest on shulker boxes (thanks @efunneko)\n\n## 2.31.0\n* Fix furnace and add tests (thanks @ImHarvol)\n* Add offhand param to d.ts (thanks @TheDudeFromCI)\n* Add hasAttackCooldown feature (thanks @TheDudeFromCI)\n* Add type validation for bot.chat (thanks @BlueBurgersTDD)\n* Add chat position to message event (thanks @larspapen)\n\n## 2.30.0\n* Add support for Barrel (#1344) (thanks @ImHarvol)\n* Fix attack cooldown bug (thanks @TheDudeFromCI)\n* Exposed getDestSlot (thanks @TheDudeFromCI)\n* Simplify setCommandBlock arguments (thanks @ImHarvol)\n* hide unknown transaction warning if hideErrors option is enabled\n\n## 2.29.1\n* fix findblock typescript def (thanks @TheDudeFromCI)\n* fix setCommandBlock for recent versions (thanks @ImHarvol)\n\n## 2.29.0\n* Add hand parameter to activateItem (thanks @Karang)\n* remove _chunkColumn from the api (bot.world should now be used)\n* Handle MC|AdvCmd misspelling (thanks @ImHarvol)\n\n## 2.28.1\n* 修复 findBlocks (感谢 @Karang)\n\n## 2.28.0\n* 增加 nearestEntity function (感谢 @Karang)\n\n## 2.27.0\n* add heldItemChanged\n\n## 2.26.0\n* use and expose prismarine-world as bot.world\n* add itemDrop event (thanks @ImHarvol)\n* fix bot.fish callback (thanks @GroobleDierne)\n* parse entity metadata for crouching (thanks @IdanHo)\n* fix bot.time.day (thanks @Naomi-alt)\n* improve find blocks options (thanks @Karang)\n\n## 2.25.0\n* emit chestLidMove (thanks @imharvol)\n* add options for main hand selection (thanks @Colten-Covington)\n* fix respawning columns issues (thanks @Karang)\n\n## 2.24.0\n* Fix getBlockAt when outside bounds\n* Improve documentation and examples\n* Add ability to change the skin parts of a bot (thanks @Naomi-alt)\n\n## 2.23.0\n* 1.16 support\n* fix noteheard (thanks @Naomi-alt)\n\n## 2.22.1\n* better typedef (thanks @Konstantin)\n* fix off by 1 error in findBlocks (thanks @Karang)\n* physics.js look fix (thanks @thesourceoferror)\n* fix chat message bracketing (thanks @Nurutomo)\n* use prismarine-physics\n\n## 2.22.0\n* Improve digTime computation (thanks @Karang)\n* expose blockEntity.raw (thanks @SiebeDW)\n* improve typedef for find block options (thanks @TheDudeFromCI)\n\n## 2.21.0\n* don't log errors if hideErrors is true\n\n## 2.20.0\n* add extra infos option in find block\n\n## 2.19.2\n* fix ground up for 1.13->1.15\n\n## 2.19.1\n* 修复 find block (感谢 @Karang)\n* improve sign parsing (thanks @cookiedragon234)\n\n## 2.19.0\n* much faster findBlock (thanks @Karang)\n\n## 2.18.0\n* fix bugs in lookAt and setQuickBarSlot\n* add auto_totem example (thanks @AlexProgrammerDE)\n* improve blockAt speed\n\n## 2.17.0\n* physics engine refactor (thanks @Karang)\n* mcdata update for better 1.14 and 1.15 support\n\n## 2.16.0\n* use protodef compiler (thanks @Karang)\n* off-hand support (thanks @Karang)\n* fix type definitions (thanks @dada513)\n\n## 2.15.0\n* fix transfer bugs (thanks @Karang)\n* add typescript definitions (thanks @IdanHo)\n\n## 2.14.1\n* fix openVillager\n\n## 2.14.0\n* 1.15 support\n* russian translation (thanks @shketov)\n\n## 2.13.0\n* 1.14 support : more tests, refactored pwindows, feature flags (thanks @Karang)\n* Look at the center of the face when placing block\n* improve bot.sleep : don't sleep if mob are present (thanks @ImHarvol)\n\n## 2.12.0\n* 1.13 support (thanks @Karang, @hornta, @SiebeDW)\n* better fishing support (thanks @hutu13879513663)\n\n## 2.11.0\n* Expose columns & blockEntities (thanks @SiebeDW)\n* Create discord.js (thanks @SiebeDW)\n* change amount of slots based on version (thanks @IdanHo)\n* Fix 'respawn' event (thanks @ImHarvol)\n* Add callback to creative set block (thanks @wvffle)\n\n## 2.10.0\nLot of fixes from @wvffle in this release :\n* more checks when digging\n* expose a bot.swingArgm() function\n* better toString to chat message\n* fix handling of empty signs\n* correct handling of entity metadata change\nAnd some others :\n* new tps plugin by @SiebeDW\n* correct handling of chunk unloading by @IdanHo\n\n## 2.9.6\n* fix logErrors option\n\n## 2.9.5\n* fix logErrors\n\n## 2.9.4\n* enable catching and logging of errors by default\n\n## 2.9.3\n* fix typo in variable name actionId\n\n## 2.9.2\n* improve pushback (thanks @Vap0r1ze)\n* more robust handling of tablist (thanks @wvffle)\n* ignore (with a warning) transaction without previous click\n\n## 2.9.1\n* improve boss bar\n* add checks in scoreboard implementation\n\n## 2.9.0\n\n* add universal chat patterns to support more chat plugins\n\n## 2.8.1\n\n* fix error on scoreboard removal\n\n## 2.8.0\n\nlot of new features from @wvffle :\n\n* support for block entities\n* improved block bars support\n* add block in sight\n* fix scoreboard support\n* add eating support\n* add tab complete support\n* add fishing support\n* better sign text support\n* repl example\n\n## 2.7.5\n\n* improve basic find block a bit\n\n## 2.7.4\n\n* start the bot alive in all cases\n* correct run speed and use it to limit the speed properly (thanks @CheezBarger)\n* emit error instead of throwing when loading a chunk (thanks @ArcticZeroo)\n\n## 2.7.3\n\n* use docsify for docs\n\n## 2.7.2\n\n* don't do anything if transaction.action < 0 (fix for some non-vanilla plugins)\n\n## 2.7.1\n\n* include fixes from pchunk, protodef and mcdata\n\n## 2.7.0\n\n* fix cannot jump repeatedly\n* fix spaces in chatmessage (thanks @Gjum)\n* add bot.getControlStates (thanks @ArcticZeroo)\n* Support end dimension (thanks @iRath96)\n* Added sneaking option to controll states (thanks @Meldiron)\n* add title event (thanks @yario-o)\n* Update sound.js to include hardcoded sound effects (thanks @jeresuikkila)\n* Support for the new launcher_profiles.json format  (thanks @Amezylst)\n* update api about checkTimeoutInterval\n\n## 2.6.1\n\n* fix chatmessage\n* add plugins to bot options to be able to disable an internal plugin\n\n## 2.6.0\n\n* improve ChatMessage translation functionality (thanks @plexigras)\n* added eslint\n* es6\n* fix autoversion in online mode\n\n## 2.5.0\n\n* don't swing arm when activating an entity\n* new plugin loading api\n\n## 2.4.1\n\n* better 1.12 support\n\n## 2.4.0\n\n* auto version detection (thanks @plexigras)\n\n## 2.3.0\n\n* support version 1.12 (thanks @jonathanperret)\n* add example to use minecraft session file for auth (thanks @plexigras)\n\n## 2.2.0\n\n* added book writing plugin (thanks @plexigras)\n* Make sure bot.time.day is between 0 and 24000 (thanks @roblabla)\n* Pass skyLightSent to Chunk.load (thanks @iRath96)\n\n## 2.1.1\n\n* use protodef aliases to properly define channels\n\n## 2.1.0\n\n* add bot.canSeeBlock (thanks @Nixes)\n* handle unknown entities and entities sent with their internal id\n* add bloodhound to plugin list\n* fix chat hoverEvent for 1.9\n\n## 2.0.0\n\n* added support for minecraft chests (thanks @plexigras)\n* cross version support : 1.8, 1.9, 1.10 and 1.11 now supported\n* [BREAKING] prismarine classes (Block, Entity, Recipe, ...) are now available only by requiring them, not in mineflayer.X. It was required to make cross version possible. minecraft-data is also to be required directly and not available as mineflayer.blocks. The code depending on this should be updated, hence the major version.\n\n## 1.8.0\n\n* add actionBar event (thanks @ArcticZeroo)\n* added support for villager trading (thanks @plexigras)\n\n## 1.7.5\n\n* bump dependencies\n\n## 1.7.4\n\n* update minecraft-data\n\n## 1.7.3\n\n* add callback to activateBlock\n\n## 1.7.2\n\n* update dependencies\n\n## 1.7.1\n\n * update minecraft-protocol, minecraft-data and protodef\n\n## 1.7.0\n\n * listen for disconnect in login phase (thanks @deathcap)\n * fix multi_block_change (thanks @Corgano)\n * remove chat filter : fix utf8 in chat\n * add extra tolerance for malformed sign packets (thanks @G07cha)\n * adapt to new minecraft data entities format\n * update minecraft-protocol to 0.17.2\n\n\n## 1.6.0\n\n * add functionalities to use scoreboard (thanks @jakibaki)\n * update to minecraft-data 0.16.3\n * 50 -> 20 tps for physics\n * Remove requireindex, for browserify support\n * add bot.setCommandBlock\n\n## 1.5.3\n\n * fix entity_status\n\n## 1.5.2\n\n * use prismarine-recipe and prismarine-windows\n * use require-self to be able to do require('mineflayer') in the examples\n * fix viewDistance sending\n\n## 1.5.1\n\n * add checkTimeoutInterval to createBot\n\n## 1.5.0\n\n * fix achievements parsing in toString()\n * update to nmp 0.16\n * use prismarine-item\n * add example to run multiple bots\n * uuid is now a dashed string\n * remove digging interruption : this doesn't happen in 1.8 servers (and caused problem in some spigot servers)\n\n## 1.4.0\n\n * improve placeBlock : now use lookAt before placing and has a callback\n * fix soulsand speed\n * use new multi-version version of (node-)minecraft-data\n\n## 1.3.0\n\n * swing arm on placing a block, look at center of block when activating a block (thanks gipsy-king)\n * refactor examples (thanks Pietro210)\n * add clickWindow support to ContainerWindow (thanks Gnomesley)\n * fix skylight in the nether\n * update node-mojangson to display unparsed text in case of error\n\n## 1.2.1\n\n * Prevent crash when an unknown entity is spawned\n * add createBot to api.md\n\n## 1.2.0\n\n * update minecraft-protocol to 0.14.0 : several fixes (error are now catchable, packets are in-order, packets fixes, etc.)\n * add ContainerWindow to support non-Vanilla plugins and add /invsee example (thanks Pietro210)\n * add a callback to bot.look and bot.lookAt\n * when receiving a remove effect packet : if the corresponding effect doesn't exist yet, emit an event with just the id of the effect (thanks Pietro210)\n * swing arm immediately when digging (thanks gipsy-king)\n * now updates bot.entity.heldItem when bot.heldItem is updated\n * fix cli args in examples\n * add forcedMove event\n * fix equipment api\n * new minecraft data version : better metadata handling\n\n## 1.1.2\n\n * a small fix in chat.js\n * add a licence file\n\n## 1.1.1\n\n * bot.transfer is faster\n * fix arm_animation\n * using mojangson parser for chat hoverevent\n * add chat patterns for unidentified chat messages\n * fix player leaving\n\n## 1.1.0\n\nLot of fixes and improvements in this version in order to support mineflayer 1.8.3, including :\n\n * minecraft 1.8.3 support\n * update minecraft protocol to 0.13.4\n * move enums data to minecraft-data\n * add automatic testing with a vanilla minecraft server on circle ci\n * add argv arguments to examples\n * refactor inventory.js\n * use new recipe format handling metadata better\n * fix lot of things to support 1.8.3 including :\n  * block format change\n  * position change : y is now always at the feet of the bot\n\n## 1.0.0\n\n * updated minecraft protocol to 0.11 (Minecraft 1.6.2 support).\n * small changes in the arguments of some events: `chat`, `whisper` and `message`. See [doc/api.md](https://github.com/andrewrk/mineflayer/blob/master/doc/api.md).\n\n## 0.1.1\n\n * updated minecraft protocol to 0.10 (Minecraft 1.5.2 support).\n\n## 0.1.0\n\nHuge thanks to [zuazo](https://github.com/zuazo) for debugging and\neliminating the problems with 1.5.1 protocol update and node 0.10 update!\n\n * update minecraft-protocol to 0.9.0 - includes many fixes\n * blocks: fix buffer length assertion error (thanks zuazo)\n * physics: fix assertion error (thanks zuazo)\n\n## 0.0.35\n\n * inventory: window clicking waits a bit if you have just dug\n   fixes a rejected transaction race condition.\n\n## 0.0.34\n\n * inventory: equipping makes the quick bar a basic LRU cache.\n   This can alleviate some race conditions when trying to equip a\n   different tool immediately after digging.\n\n## 0.0.33\n\n * crafting: fix shapeless recipe support\n * inventory: fix several instances which could cause transaction rejected\n * add missing recipes (thanks rom1504)\n * `recipe.delta` data structure changed.\n\n## 0.0.32\n\n * digging: fix crash when not holding a tool\n\n## 0.0.31\n\n * only stationary water has a negative effect on digging\n * digging: if you dig while already digging, instead of crashing,\n   mineflayer will cancel the in progress dig and start the new one.\n * digging: in creative mode dig time is 0\n * digging interruption error has a code so you can check for it\n\n## 0.0.30\n\n * expose the materials enum as `mineflayer.materials`\n\n## 0.0.29\n\n * digging is faster and has less bugs\n * you can stop digging with `bot.stopDigging()`.\n * `bot.dig(block, [timeout], [callback])` changed to `bot.dig(block, [callback])`.\n * add `bot.digTime(block)`\n * add `block.material`\n * add `block.harvestTools`\n * add `window.emptySlotCount()`\n * block and item enums are cleaned up. Every block and item has an\n   unambiguous `name` and `displayName`.\n\n## 0.0.28\n\n * add missing recipe for wooden planks\n * fix various crafting and inventory bugs\n * unequip works with hand as a destination\n\n## 0.0.27\n\n * add `mineflayer.Location` which can help you locate chunk boundaries\n * `entity.metadata` is formatted as an object instead of an array for\n   easier access\n * `canDigBlock` returns `false` if `block` is `null` instead of crashing.\n\n## 0.0.26\n\n * fix `bot.heldItem` being wrong sometimes\n * water and lava are not solid\n\n## 0.0.25\n\n * `bot.equip` - wait at least a tick before calling callback\n\n## 0.0.24\n\n * fix digging leaves not calling callback.\n\n## 0.0.23\n\n * add enchantment table support. See `examples/chest.js` for an example.\n * rename `bot.tell` to `bot.whisper` to be consistent with 'whisper' event.\n   (thanks Darthfett)\n\n## 0.0.22\n\n * update vec3 to 0.1.3\n * add \"whisper\" chat event\n\n## 0.0.21\n\nThis release is feature-complete with the old\n[C++/Qt based version of mineflayer](https://github.com/andrewrk/mineflayer/blob/cpp-qt-end).\n\n * add `bot.activateItem()`\n * add `bot.deactivateItem()`\n * add `bot.useOn(targetEntity)`\n\n## 0.0.20\n\n * add dispenser support\n   - add `mineflayer.Dispenser`\n   - add `bot.openDispenser(dispenserBlock)`\n\n## 0.0.19\n\n * add furnace support\n   - add `mineflayer.Furnace`\n   - add `bot.openFurnace(furnaceBlock)`\n * `mineflayer.Chest`: \"update\" event renamed to \"updateSlot\"\n * `bot.equip(itemType, destination, [callback])` changed to\n   `bot.equip(item, destination, [callback])`. Use `bot.inventory.items()`\n   to get a list of what items you can choose from to equip.\n * fix `bot.openChest` not working for ender chests\n * fix incorrectly scaled fuel percentage\n * upgrade to minecraft-protocol 0.7.0\n   - `mineflayer.createBot` no longer takes a `email` argument.\n   - The `username` and `password` arguments are used to authenticate with the\n     official minecraft servers and determine the case-correct username. If\n     you have migrated your user account to a mojang login, `username` looks\n     like an email address.\n   - If you leave out the `password` argument, `username` is used to connect\n     directly to the server. In this case you will get kicked if the server is\n     in online mode.\n\n## 0.0.18\n\n * fix crash for some block updates\n\n## 0.0.17\n\nrecalled\n\n## 0.0.16\n\n * add chest support\n   - add `mineflayer.Chest`\n   - add `bot.openChest(chestBlock)`\n * `block.meta` renamed to `block.metadata`\n * `item.meta` renamed to `item.metadata`\n * fix crash when player causes entityGone message\n * update to minecraft-protocol 0.6.6\n\n## 0.0.15\n\n * fix `bot.sleep` not working at all\n * add `bot.isSleeping`\n * add \"sleep\" event\n * add \"wake\" event\n * `bot.sleep(bedPoint)` changed to `bot.sleep(bedBlock)`\n * fix `mineflayer.Recipe` not exposed\n\n## 0.0.14\n\n * add crafting support\n   - add `mineflayer.windows`\n   - add `mineflayer.Recipe`\n   - `bot.inventory` is now an instance of `InventoryWindow`\n   - `bot.inventory.count` is no longer a map of id to count.\n     `Window` instances have a `count(itemType, [metadata])` method.\n   - `bot.inventory.quickBarSlot` moved to `bot.quickBarSlot`.\n   - add `'windowOpen' (window)` event\n   - add `'windowClose' (window)` event\n   - add `bot.craft(recipe, count, craftingTable, [callback])`\n   - add `bot.recipesFor(itemType, metadata, minResultCount, craftingTable)`\n * `block.pos` renamed to `block.position`.\n * `'blockUpdate' (point)` event signature changed to\n   `'blockUpdate' (oldBlock, newBlock)`\n * `'blockUpdate:(x, y, z)'` event signature changed to\n   `'blockUpdate:(x, y, z)' (oldBlock, newBlock)`\n * add `'diggingAborted' (block)` event\n * add `bot.unequip(destination, [callback])`\n * add `bot.toss(itemType, metadata, count, [callback])`\n * `bot.startDigging(block)` changed to `bot.dig(block, [timeout], [callback])`.\n * add `bot.activateBlock(block)`\n\n## 0.0.13\n\n * fix `bot.equip` when already equipping the item\n * fix some incorrect block physics\n * add `mineflayer.recipes` enum\n * fix crash when digging at a high elevation\n\n## 0.0.12\n\n * add inventory support\n   - add `Item` class which is exposed on `mineflayer`\n   - add `bot.inventory` (see docs for more details)\n   - add `bot.equip(itemType, destination, [callback])`\n   - add `bot.tossStack(item, [callback])`\n * add digging support\n   - add `bot.startDigging(block)`\n   - add `bot.canDigBlock(block)`\n * blocks: add `blockUpdate:(x, y, z)` event.\n * add building support\n   - add `bot.placeBlock(referenceBlock, faceVector)`\n * add `block.painting`\n * add `Painting` class which is exposed on `mineflayer`\n * add experience orb support\n   - `entity.type` can be `orb` now\n   - `entity.count` is how much experience you get for collecting it\n\n## 0.0.11\n\n * physics: skip frames instead of glitching out\n * default bot name to Player - `createBot` can take no arguments now.\n\n## 0.0.10\n\n * physics: fix bug: walking too slowly on Z axis\n\n## 0.0.9\n\n * ability to sprint (thanks ruan942)\n * fix color code stripping (thanks rom1504)\n * event \"onNonSpokenChat\" deleted\n * new event \"message\" which fires for all messages\n * `bot.chat` no longer checks for \"/tell\" at the beginning\n * add `bot.tell(username, message)` method\n * fix crash when an entity effect occurs\n\n## 0.0.8\n\n * chat: no longer suppress \"chat\" events for your own chat (thanks Darthfett).\n * ability to mount / dismount vehicles and attack\n * physics: fix tall grass and dead bushes treated as solid\n * fix \"respawn\" event firing twice sometimes\n * remove `bot.spawn()` and `autoSpawn` option. auto spawn is now mandatory.\n * fix sending spawn packet twice on init\n * fix bots spawning with their heads on backwards\n * fix bots jumping when they get hit\n * update player heights when they crouch\n * add support for signs: `block.signText` and `bot.updateSign(block, text)`\n\n## 0.0.7\n\n * add `bot.time.day` and `bot.time.age` and \"time\" event\n * add `bot.entities` which is a map of the entities around you\n * add `bot.look(yaw, pitch, force)` and `bot.lookAt(point, force)`\n\n## 0.0.6\n\n * add a physics engine which understands gravity\n * add jumper example, jumps whenever you chat\n * add `respawn` event which fires when you die or change dimensions\n * Block instances have a `boundingBox` property, which is currently either\n   `solid` or `empty`.\n * fix `game` event to fire correctly\n * `bot.game.spawnPoint` moved to `bot.spawnPoint`.\n * `bot.game.players` moved to `bot.players`.\n * `bot.quit` has a default reason of \"disconnect.quitting\" (thanks Darthfett)\n\n## 0.0.5\n\n * unload chunks when changing dimensions\n * blocks: handle all forms of block changing so that `blockAt` is always\n   accurate.\n\n## 0.0.4\n\n * expose Block, Biome, and Entity\n\n## 0.0.3\n\n * add `bot.blockAt(point)` which returns a `Block`\n * add `mineflayer.blocks`, `mineflayer.biomes`, and `mineflayer.items`\n * 添加机器人 `chunk` 事件\n * 修复`spawn` 事件和 `settings.showCape`\n * added chatterbox example\n * changed `entityDetach` event to have a vehicle argument\n * changed `entityEffectEnd` event to have an effect argument\n   instead of `effectId`\n * fix prefixes in pseudos in chat. (thanks rom1504)\n * update vec3 to 0.1.0 which uses euclidean modulus\n\n## 0.0.2\n\n * 增加 bot.game.spawnPoint\n * 增加 spawn 支持\n * 增加 rain 支持\n * 增加 support for getting kicked\n * 增加 settings 支持\n * 增加experience support\n * 增加 bed 支持\n * health status knowledge\n * 增加实体跟踪API\n"
  },
  {
    "path": "docs/zh/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-cmn-Hans\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Mineflayer - 使用稳定的高级API创建Minecraft机器人</title>\n  <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />\n  <meta name=\"description\" content=\"使用稳定的高级API创建Minecraft机器人\">\n  <meta name=\"viewport\" content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n  <link rel=\"stylesheet\" href=\"//unpkg.com/docsify/lib/themes/vue.css\">\n    <style>\n        .markdown-section {\n            max-width:1400px;\n        }\n    </style>\n    <!-- Global site tag (gtag.js) - Google Analytics -->\n    <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-128628977-3\"></script>\n    <script>\n      window.dataLayer = window.dataLayer || [];\n      function gtag(){dataLayer.push(arguments);}\n      gtag('js', new Date());\n\n      gtag('config', 'UA-128628977-3');\n    </script>\n</head>\n<body>\n  <div id=\"app\"></div>\n  <script>\n    window.$docsify = {\n      name: 'mineflayer',\n      repo: 'https://github.com/PrismarineJS/mineflayer',\n      loadSidebar: true,\n      subMaxLevel: 2,\n      auto2top: true\n    }\n  </script>\n  <script src=\"//unpkg.com/docsify/lib/docsify.min.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "docs/zh/tutorial.md",
    "content": "# 使用教程\n\n**目录**\n\n- [基础](#基础)\n  - [Javascript 基础](#Javascript 基础知识)\n    - [Installing Node](#installing-node)\n    - [Javascript variables](#javascript-variables)\n    - [Show output](#show-output)\n    - [Javascript functions](#javascript-functions)\n    - [Javascript 数据类型](#Javascript 数据类型)\n    - [If-statements](#if-statements)\n    - [Loops](#loops)\n    - [Node 包管理器](#Node 包管理器)\n  - [Creating a bot](#creating-a-bot)\n    - [Javascript objects](#javascript-objects)\n    - [Logging in](#logging-in)\n  - [Passing along functions](#passing-along-functions)\n  - [Listening for an event](#listening-for-an-event)\n  - [Callbacks](#callbacks)\n    - [Correct and incorrect approach](#correct-and-incorrect-approach)\n- [高级](#高级)\n  - [Asynchronousy](#asynchronousy)\n  - [Loop over an object](#loop-over-an-object)\n  - [Creating an event from chat](#creating-an-event-from-chat)\n    - [Answer Hello Bot](#answer-hello-bot)\n    - [Custom Chat](#custom-chat)\n- [FAQ](#faq)\n  - [How to run a bot on android](#how-to-run-a-bot-on-android)\n    - [Install Termux](#install-termux)\n    - [Setup](#setup)\n    - [Start your bot](#start-your-bot)\n\n## 介绍\n\nThis tutorial will help you get started with Mineflayer, even if you know nothing about coding.  \nIf you already know some things about Node and NPM, you can go to the [Create a bot](#creating-a-bot) section, otherwise start here.\n\n## 基础\n\n以下几节是关于开始使用Mineflayer需要知道的基本概念。\n\n### Javascript 基础知识\n\n#### Installing Node\n\nIn this section you will learn the basics about Javascript, Node and NPM.\n\nJavascript, often abbreviated to JS, is a programming language designed for the web. It is what makes most interactivity on the web possible.  \nNode.js, often just Node, makes it possible to use Javascript outside of web browsers.\n\nSo the first thing you have to do to get started is to install Node. You can get it [here](https://nodejs.org/en/download/).  \nAfter it is installed, open a command prompt (also known as a terminal) and then type `node -v`  \nIf you have installed Node correctly, it should return a version number. If it says it can't find the command, try installing it again.\n\nNow you have Node, you could start writing code, but we need to do 1 more thing.  \nJavascript can be written in any basic text editor, but it is much easier if you use what is called an [Integrated development environment](https://en.wikipedia.org/wiki/Integrated_development_environment)(IDE)  \nAn IDE will help you write code because it can give you suggestions, or tell you if your code has potential problems. A good IDE to start with is [Visual Studio Code](https://code.visualstudio.com/)(VSCode)  \nOnce you have installed and set-up VSCode, create a new file and then save it somewhere with a name ending with `.js`, e.g. `bot.js`  \nThis will let VSCode know we are working with Javascript, and give you the correct suggestions.\n\n#### Javascript variables\n\n首先输入以下内容：\n\n```js\nconst test = 5\n```\n\nThis will create a new variable named `test` and assign it the value `5`  \nVariable are used to save data and use it later in the code.\n\nNow save the file so we can run the code. Open a terminal again (or a new terminal in VSCode) and navigate to the same folder the file is saved in. This can be done using the `cd` command, for example: `cd Documents\\javascript`  \nOnce your terminal is in the same folder as your Javascript file, you can run `node filename.js`  \nIf you have done everything correctly, you should see nothing.  \nIn the next chapter we will show you how you can 'print' things to the terminal.\n\nIn general, it is good practice to use the `const` keyword instead of the `let` keyword when defining a variable. A variable defined with `const` can't be modified later and thus is a constant.  \nJavascript is then able to make your code run more efficiently because it knows it doesn't have to account for value changes for that variable.  \nIf you want a modifiable variable, you will still have to use `let` of course.\n\n```js\nconst test = 5\n// eslint-disable-next-line\ntest = 10 // This line is invalid.\n```\n\nThe second line is invallid because you can't reassign the `test` variable.\n\nIf you want to help yourself and other people understand your code better, you can use comments.  \nComments can be created using `//` and everything after that is completely ignored by Javascript.\n\n#### 显示输出\n\nA lot of times you want to see the current value of a variable, to make sure your program is running correctly.  \n您可以通过将变量打印到终端来实现这一点.  \n在Javascript中，我们可以使用 `console.log()` 函数  \n\n```js\nconst test = 5\n\nconsole.log(test)\n```\n\n现在，当您保存并运行此代码时，您最终应该会看到：\n\n```txt\n5\n```\n\n#### Javascript functions\n\nNext you will learn about functions. Functions are a piece of code that can be used multiple times throughout your code.  \nThese can be useful because you don't have to type something multiple times.\n\n```js\nconst addition = (a, b) => {\n  return a + b\n}\n\nconst test1 = addition(5, 10)\nconst test2 = addition(1, 0)\n\nconsole.log(test1)\nconsole.log(test2)\n```\n\nThe `=>` is used to define a function, called the arrow operator.  \nBefore the arrow operator is the parameter list, everything between the round brackets `()` are parameters, separated by a comma.  \nParameters are variables you can give to your function so that your function can work with them.  \nThen after the arrow operator comes the function body, this is everything between the curly brackets `{}`  \nThis is where you put the code of the function.  \nNow that the function is complete, we assign it to a variable to give it a name, in this case `addition`  \n\nAs you can see, this code takes the parameters `a` and `b` and adds them together.  \nThen the function will return the result.  \nWhen a function is defined, the code in the function body is not yet executed. To run a function you have to call it.  \nYou can call a function by using the name of a function followed by round brackets. In this case `addition()`  \nHowever, the `addition` function requires 2 parameters. These can be passed along by putting them inside the round brackets, comma separated: `addition(1, 2)`  \nWhen the function is done, you can imagine that the function call is replaced by whatever the function has returned. So in this case `let test1 = addition(5, 10)` will become `let test1 = result` (You will not actually see this, but this can help you understand the concept)\n\nSometimes you will come across the following: `function addition() {}` This means the same thing, although `() => {}` is preferred. (If you really want to know why, look up 'javascript function vs arrow function')\n\nThe above should output the following:\n\n```txt\n15\n1\n```\n\n#### Javascript 数据类型\n\nSo far we have only worked with numbers, but Javascript can work with more variable types:\n\n- A string is a piece of text that can contain multiple characters. Strings are defined by using the quotes `''`\n\n```js\nconst string = 'This is a string' // string type\n```\n\n- An array is a type that can hold multiple variables inside itself. Arrays are defined by using the square brackets `[]`\n\n```js\nconst array = [1, 2, 3] // array type\n```\n- Object are basically advanced arrays, you will learn more about it later in this tutorial. Their defined by curly brackets `{}`\n\n```js\nconst object = {} // object type\n```\n\n- Functions are also their own type.\n\n```js\nconst adder = (a, b) => { return a + b } // function type\n```\n\n- A boolean is a type that can only be `true` or `false`\n\n```js\nconst boolean = true // boolean type\n```\n\n- When something is not (yet) defined, its type is `undefined`\n\n```js\nlet nothing // undefined type\nconst notDefined = undefined // undefined type\n```\n\n#### If-statements\n\nSometimes you want to do different things based on a certain condition.  \nThis can be achieved using if-statements.\n\n```js\nconst name = 'Bob'\n\nif (name === 'Bob') {\n  console.log('你的名字是 Bob')\n} else if (name === 'Alice') {\n  console.log('你的名字是 Alice')\n} else {\n  console.log('你的名字不是Bob或Alice')\n}\n```\n\nAn if-statement is created using the `if` keyword. After that you have a condition between the round brackets `()` followed by the body between the curly brackets `{}`\nA condition has to be something that computes to a boolean.  \nIn this case it uses an equal operator `===` which will be `true` if the value in front is the same as the value after. Otherwise it will be `false`\nIf the condition is `true` the code in the body will be executed.  \nYou can chain an if-statement with an else-if-statement or an else-statement.  \nYou can have as many else-if-statements as you want, but only 1 if and else statement.  \nIf you have an else-statement, it will be called only if all the chained statements before it are `false`\n\n#### Loops\n\nLoops are used to repeat certain code until a certain conditional is met.\n\n```js\nlet countDown = 5\n\nwhile (countDown > 0) {\n  console.log(countDown)\n  countDown = countDown - 1 // 从1递减\n}\n\nconsole.log('已完成!')\n```\n\n上述代码将打印以下内容\n\n```txt\n5\n4\n3\n2\n1\n已完成!\n```\n\nThe `while` loop has a condition `()` and a body `{}`  \nWhen the code reaches the loop, it will check the condition. If the condition is `true`, the code in the body will be executed.  \nAfter the end of the body is reached, the condition is checked again, and if `true`, the body executed again.  \nThis will happen for as long as the condition check is still `true`  \nEach loop, this code prints the current `countDown` number, and then decrements it by 1.  \nAfter the 5th loop, the condition `0 > 0` will be `false`, and thus the code will move on.\n\nA `for` loop is also often used, and differs slightly from a `while` loop.  \n\n```js\nfor (let countDown = 5; countDown > 0; countDown = countDown - 1) {\n  console.log(countDown)\n}\n```\n\nInstead of only a condition, the for loops has 3 different parts  \nThese parts are separated by a semi-column.  \nThe first parts `let countDown = 5` is only executed once, at the start of the loop.  \nThe second part `countDown > 0` is the condition, this is the same as the while loop.  \nThe third part `countDown = countDown - 1` is executed after each loop.:\n\nIf you want to do something for every item in an array, a `for of` loop can be useful.  \n\n```js\nconst array = [1, 2, 3]\n\nfor (const item of array) {\n  console.log(item)\n}\n```\n\nA `for of` loop needs to have a variable before the `of`, this is the variable that can be used to access the current item.  \nThe variable after the `of` needs to be something that contains other variable. These are mostly arrays, but also some objects.  \nThe loop will execute the body for each item in the `array` and each loop the `item` variable will be the current item of the `array`\n\n#### Node 包管理器\n\nThe last thing you need to know is how to use the [Node Package Manager](https://www.npmjs.com/).  \nNPM is automatically installed when you install Node.  \nNPM is used to get useful packages that other people created that can do useful things for you.  \nYou can search for packages on [their website](https://www.npmjs.com/), and then install them using the `npm install` command in your terminal.  \nTo install Mineflayer for example, run `npm install mineflayer`  \n\nThen, Node can access installed modules by using the `require()` function.\n\n```js\nconst mineflayer = require('mineflayer')\n```\n\nAfter this, the `mineflayer` variable can be used to access all the features of Mineflayer.\n\n### 创建机器人\n\nNow that you know the basics of Javascript, Node and NPM, you're ready to start creating your first bot!  \nIf you don't know any of the terms above, you should go back to the [previous section](#javascript-basics)\n\n下面是创建Mineflayer机器人所需的绝对最少代码\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst bot = mineflayer.createBot()\n```\n\nIf you run this example, you'll notice that your program will not stop. If you want to stop your currently running program, press `Ctrl` + `c`  \nHowever, this bot isn't quite useful, as by default this will connect to a Minecraft server running on your machine with the port 25565.  \nIf you want to choose which server you want your bot to connect to, you have to pass along a few options.\n\n\n```js\nconst mineflayer = require('mineflayer')\n\nconst options = {\n  host: 'localhost', // 将此项更改为所需的ip\n  port: 25565 // 将此项更改为所需的端口\n}\n\nconst bot = mineflayer.createBot(options)\n```\n\n#### Javascript objects\n\nThe curly brackets `{}` are used to create an object.  \nObjects contain what is called a key-value pair.  \nA key-value pair consist of a colon `:` and a key before the colon, and the value of that key after the colon.  \nThe keys can then be used to retrieve their value.  \nYou can have multiple key-value pairs by separating them by commas.\n\n```js\nconst object = {\n  number: 10,\n  another: 5\n}\n\nconsole.log(object.number) // 这将打印值10\n```\n\nThis concept is often used to create what is named 'named parameters'  \nThe advantage of this is that you don't have to use all the options available, and their position does not matter.  \nThe value can be anything, even other object. If the value is a function, that function is often called a method for that object.  \nYou can also create the object in-line.\n\n```js\nconst bot = mineflayer.createBot({ host: 'localhost', port: 25565 })\n```\n\n#### 登录\n\nWithout any parameters, the bot will have the name `Player` and can only log into offline servers. (Cracked & open-to-lan)  \nIf you supply the `createBot` with an `username` option, it will log in with that username. (Still only in offline server)  \nTo log into a specific account, you have to supply both the `username` and the `password`\n\n```js\nconst bot = mineflayer.createBot({\n  host: 'localhost',\n  port: 25565,\n  username: 'Player',\n  password: 'password'\n})\n```\n\n#### Command line arguments\n\nWhat if somebody else likes your bot and wants to use it, but uses it on a different server and with a different account?  \nThis means that everyone has to change the server address and login settings to their preference. (And it's of course also a bad idea to share your password)  \nTo counter this, a lot of people use command line arguments.\n\n```js\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4],\n  password: process.argv[5]\n})\n```\n\nAs you can see, no more sensitive data in your code! But now, how do you run it?  \nNow, instead of starting your program with just `node filename.js` you start it with `node filename.js host port username password`  \nNode will automatically split the whole command line into an array, separated by spaces.  \nThis array is `process.argv`  \nThe data in an array can be accessed using the index of each item. The index always start at 0, so the first item can be accessed with `[0]` and in this case will be `node` etc.\n\n| | First item | Second item | Third Item | Fourth item | Fifth item | Sixth item |\n| --- | :---: | :---: | :---: | :---: | :---: | :---: |\n| Value | `node` | `filename.js` | `host` | `port` | `username` | `password` |\n| Index | `[0]` | `[1]` | `[2]` | `[3]` | `[4]` | `[5]`\n\n### Passing along functions\n\nNot only basics variables like numbers and strings can be given as an argument.  \nFunctions can also be passed as a variable.\n\n```js\nconst welcome = () => {\n  bot.chat('你好!')\n}\n\nbot.once('spawn', welcome)\n```\n\nAs you can see, the `bot.once()` method takes 2 parameters.  \nThe first parameter is an event name, the second parameter is the function to call when that event happens.  \nRemember, when passing along a function, only use the name and not the round brackets `()`\n\n`bot.chat()` is the method for sending message to the chat.\n\nYou can also simplify this code by using a anonymous function.  \nAn anonymous function doesn't have a name, and is created at the position where the function name used to go.  \nThey still have to have a parameter list `()` and a function body `{}`, even if it isn't used.\n\n```js\nbot.once('spawn', () => {\n  bot.chat('你好!')\n})\n```\n\n### Listening for an event\n\nThe bot object has many useful [events](http://prismarinejs.github.io/mineflayer/#/api?id=events).\nYou can listen for an event by using either `bot.on()` method or `bot.once()` method of the bot object, which takes the name of an event and a function.\nTo remove specific listener you can use `bot.removeListener()` method.\n\n- `bot.on(eventName, listener)`\n  Execute the `listener` function for each time the event named `eventName` triggered.\n- `bot.once(eventName, listener)`\n  Execute the `listener` function, only once, the first time the event named `eventName` triggered.\n- `bot.removeListener(eventName, listener)`\n  Removes the specified `listener` for the event named `eventName`. In order to use this you either need to define your function with `function myNamedFunc() {}` or put your function in a variable with `const myNamedFunc = () => {}`. You can then use `myNamedFunc` in the listener argument.\n\nNot only bot object, [`Chest`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerchest), [`Furnace`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerfurnace), [`Dispenser`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerdispenser), [`EnchantmentTable`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayerenchantmenttable), [`Villager`](http://prismarinejs.github.io/mineflayer/#/api?id=mineflayervillager) object also have their own events!\n\n### Callbacks\nA [callback](https://en.wikipedia.org/wiki/Callback_(computer_programming)) is a function that you can give to another function, that is expected to be *called back*, generally when that function ends.  \nIn Mineflayer, callbacks are often used to handle errors.\n\n```js\nbot.consume((error) => {\n  if (error) { // 这将检查是否发生错误\n    console.log(error)\n  } else {\n    console.log('Finished consuming')\n  }\n})\n```\n\nThe above code will try to consume what the bot is currently holding.  \nWhen the consuming ends, the function that is passed along is called.  \nWe can then do other things that we want to do after.  \nThe function could also be called when an error occurs.\n\n#### Correct and incorrect approach\n\nBelow is an example of a bot that will craft oak logs into oak planks and then into sticks.\n\nIncorect approach ❌:\n\n```js\nconst plankRecipe = bot.recipesFor(5)[0] // Get the first recipe for item id 5, which is oak planks.\nbot.craft(plankRecipe, 1) // ❌ start crafting oak planks.\n\nconst stickRecipe = bot.recipesFor(280)[0] // Get the first recipe for item id 5, which is sticks.\nbot.craft(stickRecipe, 1) // ❌ start crafting sticks.\n```\n\n回调的正确方法 ✔️:\n\n```js\nconst plankRecipe = bot.recipesFor(5)[0]\n\nbot.craft(plankRecipe, 1, null, (error) => {\n  // After bot.craft(plankRecipe, ...) is finished, this callback is called and we continue. ✔️\n  if (error) { // 检查是否发生了错误\n    console.log(error)\n  } else {\n    const stickRecipe = bot.recipesFor(280)[0]\n\n    bot.craft(stickRecipe, 1, null, (error) => {\n      // After bot.craft(stickRecipe, ...) is finished, this callback is called and we continue. ✔️\n      if (error) { // Check if an error happened.\n        console.log(error)\n      } else {\n        bot.chat('Crafting Sticks finished')\n      }\n    })\n  }\n})\n```\n\nThe reason the incorrect approach is wrong is because when `bot.craft()` is called, the code will continue below while the bot is crafting.  \nBy the time the code reaches the second `bot.craft()`, the first probably hasn't finished yet, which means the wanted resource is not available yet.  \nUsing callbacks can fix this because they will only be called after the `bot.craft()` is finished.\n\nMore on the [bot.craft()](https://prismarinejs.github.io/mineflayer/#/api?id=botcraftrecipe-count-craftingtable-callback) method.\n\n## 高级\n\nThe following concepts aren't necessary to create a Mineflayer bot, but they can be useful to understand and create more advanced bots.  \nWe assume you have understood the [Basics](#basics) tutorial.\n\n### Asynchronousy\nIn Javascript, asynchronousy is an important concept.  \nBy default, Javascript will run everything line by line, and only go to the next line if the current line is done. This is called blocking.  \nHowever, sometimes you have to do something that takes a relatively long time, and you don't want your whole program to block and wait for it to finish.  \n\nInteracting with the filesystem is often done using asynchronousy, because reading and writing large files can take a long time.  \n\n```js\nconst myPromise = new Promise((resolve, reject) => {\n  setTimeout(() => {\n    resolve('Success!') // 耶！一切都很顺利！\n  }, 1000)\n})\n\nmyPromise.then((successMessage) => {\n  console.log(successMessage)\n})\n\nmyPromise.catch((error) => {\n  console.log(error)\n})\n```\n\nThe above codes uses what is called a Promise. A promise promises it will eventually complete.  \nThe function given you a promise always has 2 parameters, a `resolve` function and a `reject` function.  \nIf the promise is successful, it will call the `resolve` function, otherwise it will call the `reject` function.  \nThe above code uses a `setTimeout`, which calls the given function after the set amount of milliseconds, 1000 in this case.  \nYou can then tell the promise what it should do when it succeeds with `.then(function)` or when it fails with `.catch(function)`\n\nThe `.then` and `.catch` function can also be chained together with the promise to simplify the code.\n\n```js\nconst myPromise = new Promise((resolve, reject) => {\n  setTimeout(() => {\n    resolve('Success!') // Yay! Everything went well!\n  }, 1000)\n}).then((successMessage) => {\n  console.log(successMessage)\n}).catch((error) => {\n  console.log(error)\n})\n```\n\n### Loop over an object\n\nThe `for of` loop described in the [loops](#loops) chapter can also be used to loop over an object.\n\nIf we have the following object:\n\n```js\nconst obj = {\n  a: 1,\n  b: 2,\n  c: 3\n}\n```\n\nThe following will loop over all the values of the object.\n\n```js\nfor (const value of Object.values(obj)) {\n  console.log(value)\n}\n```\n\n```txt\n1\n2\n3\n```\n\nThis will loop over all the keys of the object.\n\n```js\nfor (const key of Object.keys(obj)) {\n  console.log(key)\n}\n```\n\n```txt\na\nb\nc\n```\n\nYou can also loop over the keys and values at the same time. You will have to destructure the variables first, explained [here.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)\n\n```js\nfor (const [key, value] of Object.entries(obj)) {\n  console.log(key + ', ' + value)\n}\n```\n\n```txt\na, 1\nb, 2\nc, 3\n```\n\nThese loops are possible because `Object.values(obj)` and `Object.keys(obj)` both return an array of the objects values and keys respectively.  \n`Object.entries(obj)` returns an array where each item is an array with 2 items: a key and its corresponding value.  \nIt's important to know that, unlike the `Object.values()` and `Object.keys()` functions, the `Object.entries()` function does not guarantee that the order is the same as the order when the object was defined.\n\nThere is also a `for in` loop. However, you will most often want to use `for of` instead of `for in` because there are key differences.  \nThe `for in` loop loops over the keys of an object instead of the values. (The index in case it is an array)\nHowever, it doesn't loop only over its own keys, but also keys from other object it 'inherits' from, which can be confusing or unwanted. More on this [here.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in)\nIn general, you'll want to use `for of` instead of `for in` so make sure you don't confuse the two.\n\n### 从聊天中创建事件\n\nYou can create your own event from chat using [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method. Useful for Bukkit servers where the chat format changes a lot.\n[`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) method takes three arguments :\n\n- `pattern` - regular expression (regex) to match chat\n- `chatType` - the event the bot emits when the pattern matches. e.g. \"chat\" or \"whisper\"\n- `description` - Optional, describes what the pattern is for\n\nYou can add [Groups and Range](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Groups_and_Ranges) into the `pattern`, then the listener will spread the captured groups into arguments of your callback sequentially.\n\n阅读有关[正则表达式](https://en.wikipedia.org/wiki/Regular_expression)的更多信息\n\n例子 :\n\n#### 回答你好 机器人\n\n在这里，我们创建一个机器人，从另一个玩家那里回答“你好”。\n\n```js\nbot.chatAddPattern(\n  /(helo|hello|Hello)/,\n  'hello',\n  'Someone says hello'\n)\n\nconst hi = () => {\n  bot.chat('Hi!')\n}\n\nbot.on('hello', hi)\n```\n\n#### 自定义聊天\n\n基于自定义聊天格式创建事件  \n自定义聊天示例:\n\n```txt\n[Player] 路人甲 > 你好\n[Admin] 李四 > Hi\n[Player] 法外狂徒张三 > 焯!我卡住了\n[Mod] Jim > 我马上到\n```\n\n```js\nbot.chatAddPattern(\n  /^\\[(.+)\\] (\\S+) > (.+)$/,\n  'my_chat_event',\n  'Custom chat event'\n)\n\nconst logger = (rank, username, message) => {\n  console.log(`${username} 说 ${message}`)\n}\n\nbot.on('my_chat_event', logger)\n```\n\n关于 `^\\[(.+)\\] (\\S+) > (.+)$` 正则表达式的解释可在[此处](https://regex101.com/r/VDUrDC/2)找到\n\n## FAQ\n\n### 如何在Android上运行机器人\n\n下面是在Android设备上用 [Termux](https://termux.com/)运行bot的快速设置教程\n\n#### 安装Termux\n\n安装[Termux](https://termux.com/) 并启动\n\n#### Setup\n\n安装 `Node.js`:\n\n```bash\npkg update -y\npkg install nodejs -y\n```\n\n❗️ 允许应用程序设置上Termux的存储权限.\n在内部存储上创建新文件夹：\n\n```bash\ncd /sdcard\nmkdir my_scripts\ncd my_scripts\n```\n\n安装 `mineflayer`:\n\n```bash\nnpm install mineflayer\n```\n\n现在，您可以将所有脚本复制/存储到内部存储器中的`my_scripts`文件夹中。\n\n#### 启动你的机器人\n\n要启动机器人，请使用Node运行脚本名称\n\n```bash\nnode script_name.js\n```\n\n❗️ 每次打开 Termux 时，您都必须在启动机器人之前将 cwd 更改为 `/sdcard/my_scripts`:\n\n```bash\ncd /sdcard/my_scripts\n```\n"
  },
  {
    "path": "examples/advanced/README.md",
    "content": "# Advanced examples\n\nThese are examples that have a very specific use-case, and most people won't need.\n"
  },
  {
    "path": "examples/advanced/chest_confirm.md",
    "content": "# Manual Chest Confirm\n\nThis code snippet will tell the bot not to wait for chest confirmations that some spigot plugins will not send\n\n```js\nbot.on('windowOpen', async (window) => {\n  window.requiresConfirmation = false // fix\n  await bot.clickWindow(13, 0, 0)\n  console.log(bot._events) // without the fix this code is unreachable, the promise never resolve\n})\nbot.on('windowClose', () => {\n  console.log(bot._events) // without the fix there is a confirmTransaction1 listener that is never removed\n})\n```\n"
  },
  {
    "path": "examples/ansi.js",
    "content": "/*\n *\n * A simple bot that logs everything that is said to the console.\n *\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node ansi.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'ansi',\n  password: process.argv[5]\n})\n\nbot.on('message', (message) => {\n  console.log(message.toAnsi())\n})\n"
  },
  {
    "path": "examples/anvil.js",
    "content": "/**\n * This example demonstrates how to use anvils w/ mineflayer\n *  the options are: (<Option> are required, [<Option>] are optional)\n * 1. \"anvil combine <itemName1> <itemName2> [<name>]\"\n * 2. \"anvil rename <itemName> <name>\"\n *\n * to use this:\n * /op anvilman\n * /gamemode anvilman creative\n * /xp set anvilman 999 levels\n *\n * Put an anvil near the bot\n * Give him a sword and an enchanted book\n * say list\n * say xp\n * say anvil combine diamond_sword enchanted_book\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node anvil.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'anvilman',\n  password: process.argv[5]\n})\n\nbot.on('chat', async (username, message) => {\n  const command = message.split(' ')\n\n  switch (true) {\n    case /^list$/.test(message):\n      sayItems()\n      break\n    case /^toss \\w+$/.test(message):\n      // toss name\n      // ex: toss diamond\n      tossItem(command[1])\n      break\n    case /^xp$/.test(message):\n      bot.chat(bot.experience.level)\n      break\n    case /^gamemode$/.test(message):\n      bot.chat(bot.game.gameMode)\n      break\n    case /^anvil combine \\w+ \\w+$/.test(message): // anvil firstSlot secondSlot\n      combine(bot, command[2], command[3])\n      break\n    case /^anvil combine \\w+ \\w+ (.+)$/.test(message): // anvil firstSlot secondSlot name\n      combine(bot, command[2], command[3], command.slice(4).join(' '))\n      break\n    case /^anvil rename \\w+ (.+)/.test((message)):\n      rename(bot, command[2], command.slice(3).join(' '))\n      break\n  }\n})\n\nasync function tossItem (name, amount) {\n  amount = parseInt(amount, 10)\n  const item = itemByName(name)\n  if (!item) {\n    bot.chat(`I have no ${name}`)\n  } else {\n    try {\n      if (amount) {\n        await bot.toss(item.type, null, amount)\n        bot.chat(`tossed ${amount} x ${name}`)\n      } else {\n        await bot.tossStack(item)\n        bot.chat(`tossed ${name}`)\n      }\n    } catch (err) {\n      bot.chat(`unable to toss: ${err.message}`)\n    }\n  }\n}\n\nfunction itemByName (name) {\n  return bot.inventory.items().filter(item => item.name === name)[0]\n}\n\nfunction itemToString (item) {\n  if (item) {\n    return `${item.name} x ${item.count}`\n  } else {\n    return '(nothing)'\n  }\n}\n\nfunction sayItems (items = bot.inventory.items()) {\n  const output = items.map(itemToString).join(', ')\n  if (output) {\n    bot.chat(output)\n  } else {\n    bot.chat('empty')\n  }\n}\n\nfunction getAnvilIds () {\n  const matchingBlocks = [bot.registry.blocksByName.anvil.id]\n  if (bot.registry.blocksByName?.chipped_anvil) {\n    matchingBlocks.push(bot.registry.blocksByName.chipped_anvil.id)\n    matchingBlocks.push(bot.registry.blocksByName.damaged_anvil.id)\n  }\n  return matchingBlocks\n}\n\nasync function rename (bot, itemName, name) {\n  const anvilBlock = bot.findBlock({\n    matching: getAnvilIds()\n  })\n  const anvil = await bot.openAnvil(anvilBlock)\n  try {\n    await anvil.rename(itemByName(itemName), name)\n    bot.chat('Anvil used successfully.')\n  } catch (err) {\n    bot.chat(err.message)\n  }\n  anvil.close()\n}\n\nasync function combine (bot, itemName1, itemName2, name) {\n  const anvilBlock = bot.findBlock({\n    matching: getAnvilIds()\n  })\n  const anvil = await bot.openAnvil(anvilBlock)\n  try {\n    bot.chat('Using the anvil...')\n    await anvil.combine(itemByName(itemName1), itemByName(itemName2), name)\n    bot.chat('Anvil used successfully.')\n  } catch (err) {\n    bot.chat(err.message)\n  }\n  anvil.close()\n}\n\nbot.on('error', console.log)\n"
  },
  {
    "path": "examples/anvil_saver/.npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "examples/anvil_saver/package.json",
    "content": "{\n  \"name\": \"mineflayer-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"prismarine-provider-anvil\": \"^2.3.0\"\n  },\n  \"description\": \"A mineflayer example\"\n}\n"
  },
  {
    "path": "examples/anvil_saver/saver.js",
    "content": "/*\n * This example demonstrates how to save a world with mineflayer and\n * https://github.com/PrismarineJS/prismarine-provider-anvil\n */\n\nconst mineflayer = require('mineflayer')\nconst fs = require('fs')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node saver.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'saver',\n  password: process.argv[5],\n  storageBuilder: ({ version, worldName }) => {\n    const Anvil = require('prismarine-provider-anvil').Anvil(version)\n    worldName = worldName.replace(/:/g, '_')\n    fs.mkdirSync(worldName)\n    return new Anvil(worldName)\n  }\n})\n\nbot.on('spawn', () => {\n  bot.waitForChunksToLoad(() => {\n    console.log('World saved!')\n  })\n})\n"
  },
  {
    "path": "examples/armor_stand.js",
    "content": "/*\n * This script will apply armor onto an armor stand within 4 blocks of the bot\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node armor_stand.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'armorStand',\n  password: process.argv[5]\n})\n\nconst armorTypes = {\n  helmet: [0, 1.8, 0],\n  chestplate: [0, 1.2, 0],\n  leggings: [0, 0.75, 0],\n  boots: [0, 0.1, 0]\n}\n\nbot.on('chat', async (username, message) => {\n  const [mainCommand, subCommand] = message.split(' ')\n  if (mainCommand !== 'equip' && mainCommand !== 'unequip') return\n\n  const armorStand = bot.nearestEntity(e => e.displayName === 'Armor Stand' && bot.entity.position.distanceTo(e.position) < 4)\n  if (!armorStand) {\n    bot.chat('No armor stands nearby!')\n    return\n  }\n\n  if (mainCommand === 'equip') {\n    let armor = null\n    // parse chat\n    Object.keys(armorTypes).forEach(armorType => {\n      if (subCommand !== armorType) return\n      armor = bot.inventory.items().find(item => item.name.includes(armorType))\n    })\n\n    if (armor === null) {\n      bot.chat('I have no armor items in my inventory!')\n      return\n    }\n\n    await bot.equip(armor, 'hand')\n    bot.activateEntityAt(armorStand, armorStand.position)\n  } else if (mainCommand === 'unequip') {\n    await bot.unequip('hand')\n\n    const offset = armorTypes[subCommand]\n    if (!offset) return\n\n    bot.activateEntityAt(armorStand, armorStand.position.offset(...offset))\n  }\n})\n"
  },
  {
    "path": "examples/attack.js",
    "content": "/*\n *\n * A bot that attacks the player that sends a message or the nearest entity (excluding players)\n *\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node attack.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'attack',\n  password: process.argv[5]\n})\n\nbot.on('spawn', () => {\n  bot.on('chat', (username, message) => {\n    if (message === 'attack me') attackPlayer(username)\n    else if (message === 'attack') attackEntity()\n  })\n})\n\nfunction attackPlayer (username) {\n  const player = bot.players[username]\n  if (!player || !player.entity) {\n    bot.chat('I can\\'t see you')\n  } else {\n    bot.chat(`Attacking ${player.username}`)\n    bot.attack(player.entity)\n  }\n}\n\nfunction attackEntity () {\n  const entity = bot.nearestEntity()\n  if (!entity) {\n    bot.chat('No nearby entities')\n  } else {\n    bot.chat(`Attacking ${entity.name ?? entity.username}`)\n    bot.attack(entity)\n  }\n}\n"
  },
  {
    "path": "examples/auto-eat.js",
    "content": "const mineflayer = require('mineflayer')\nconst autoeat = require('mineflayer-auto-eat')\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: process.argv[3],\n  username: process.argv[4],\n  password: process.argv[5]\n})\n\n// Load the plugin\nbot.loadPlugin(autoeat)\n\nbot.once('spawn', () => {\n  bot.autoEat.options = {\n    priority: 'foodPoints',\n    startAt: 14,\n    bannedFood: []\n  }\n})\n// The bot eats food automatically and emits these events when it starts eating and stops eating.\n\nbot.on('autoeat_started', () => {\n  console.log('Auto Eat started!')\n})\n\nbot.on('autoeat_stopped', () => {\n  console.log('Auto Eat stopped!')\n})\n\nbot.on('health', () => {\n  if (bot.food === 20) bot.autoEat.disable()\n  // Disable the plugin if the bot is at 20 food points\n  else bot.autoEat.enable() // Else enable the plugin again\n})\n"
  },
  {
    "path": "examples/auto_totem.js",
    "content": "/*\n * This script will automatically set if a totem is in the inventory or the off-hand.\n * It checks for a totem every tick.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node auto_totem.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'totem',\n  password: process.argv[5]\n})\n\nbot.on('spawn', () => {\n  const totemId = bot.registry.itemsByName.totem_of_undying.id // Get the correct id\n  if (bot.registry.itemsByName.totem_of_undying) {\n    setInterval(() => {\n      const totem = bot.inventory.findInventoryItem(totemId, null)\n      if (totem) {\n        bot.equip(totem, 'off-hand')\n      }\n    }, 50)\n  }\n})\n"
  },
  {
    "path": "examples/bee.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node bee.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'bee',\n  password: process.argv[5],\n  verbose: true\n})\n\n// /gamemode creative bee\n\nasync function loop (n) {\n  for (let i = 0; i <= n; i++) {\n    const { position } = bot.entity\n    await bot.creative.flyTo(position.offset(Math.sin(i) * 2, 0.5, Math.cos(i) * 2))\n  }\n  bot.chat('My flight was amazing !')\n}\n\nbot.on('chat', async (username, message) => {\n  if (username === bot.username) return\n  switch (message) {\n    case 'loaded':\n      await bot.waitForChunksToLoad()\n      bot.chat('Ready!')\n      break\n    case 'fly':\n      bot.creative.startFlying()\n      loop(10)\n      break\n  }\n})\n"
  },
  {
    "path": "examples/block_entity.js",
    "content": "/*\n * This example demonstrates how easy it is to create a bot\n * that fetches monster spawners mob type\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node block_entity.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'block_entity',\n  password: process.argv[5]\n})\n\nbot.on('message', (cm) => {\n  if (cm.toString().includes('spawner')) {\n    spawner()\n  }\n})\n\nfunction spawner () {\n  let blockName\n  if (bot.supportFeature('mobSpawner')) {\n    blockName = bot.registry.blocksByName.mob_spawner.id\n  } else if (bot.supportFeature('spawner')) {\n    blockName = bot.registry.blocksByName.spawner.id\n  }\n  const block = bot.findBlock({\n    matching: blockName,\n    point: bot.entity.position\n  })\n\n  if (!block) {\n    return bot.chat('Monster spawner not found')\n  }\n\n  bot.chat(`Entity type: ${block.blockEntity.SpawnData.id}`)\n  bot.chat(`Delay: ${block.blockEntity.Delay}`)\n  console.log(block.blockEntity)\n}\n"
  },
  {
    "path": "examples/blockfinder.js",
    "content": "/*\n * This simple bot will help you find any block\n */\nconst mineflayer = require('mineflayer')\n\nconst { performance } = require('perf_hooks')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node blockfinder.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'finder',\n  password: process.argv[5]\n})\n\nbot.on('chat', async (username, message) => {\n  if (username === bot.username) return\n\n  if (message === 'loaded') {\n    console.log(bot.entity.position)\n    await bot.waitForChunksToLoad()\n    bot.chat('Ready!')\n  }\n\n  if (message.startsWith('find')) {\n    const name = message.split(' ')[1]\n    if (bot.registry.blocksByName[name] === undefined) {\n      bot.chat(`${name} is not a block name`)\n      return\n    }\n    const ids = [bot.registry.blocksByName[name].id]\n\n    const startTime = performance.now()\n    const blocks = bot.findBlocks({ matching: ids, maxDistance: 128, count: 10 })\n    const time = (performance.now() - startTime).toFixed(2)\n\n    bot.chat(`I found ${blocks.length} ${name} blocks in ${time} ms`)\n  }\n})\n"
  },
  {
    "path": "examples/book.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node book.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'book',\n  password: process.argv[5]\n})\n\nconst pages = [\n  'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n  'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',\n  'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',\n  'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'\n].map(page => page\n  .split(' ')\n  .map((word, i) => `§${(i % 13 + 1).toString(16)}${i % 2 ? '§l' : ''}${word}`)\n  .join(' '))\n\nbot.once('login', () => console.log('logged in'))\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  switch (message) {\n    case 'print':\n      print()\n      break\n    case 'write':\n      write()\n      break\n    case 'toss':\n      toss()\n      break\n  }\n})\n\nfunction toss () {\n  const [book] = bot.inventory.items().filter(({ name }) => name === 'writable_book')\n  bot.tossStack(book)\n}\n\nasync function write () {\n  const [book] = bot.inventory.items().filter(({ name }) => name === 'writable_book')\n  if (!book) {\n    bot.chat(\"I don't have a book.\")\n    return\n  }\n  await bot.writeBook(book.slot, pages)\n  print()\n}\n\nfunction print () {\n  const [book] = bot.inventory.items().filter(({ name }) => name === 'writable_book')\n  book.nbt.value.pages.value.value.forEach((page, i) => bot.chat(`Page ${i + 1}: ${page.replace(/§[a-z0-9]/g, '')}`))\n}\n"
  },
  {
    "path": "examples/bossbar.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node bossbar.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'bossbar_bot',\n  password: process.argv[5]\n})\n\n// Wait for spawn\nbot.once('spawn', () => {\n  console.log('Bot spawned!')\n\n  // Create a boss bar\n  bot.chat('/bossbar add test:bar \"Test Boss Bar\"')\n  bot.chat('/bossbar set test:bar players ' + bot.username)\n  bot.chat('/bossbar set test:bar color red')\n  bot.chat('/bossbar set test:bar style notched_6')\n  bot.chat('/bossbar set test:bar value 50')\n})\n\n// Listen for boss bar events\nbot.on('bossBarCreated', (bossBar) => {\n  console.log('Boss bar created:', bossBar.title.toString())\n})\n\nbot.on('bossBarUpdated', (bossBar) => {\n  console.log('Boss bar updated:', {\n    title: bossBar.title.toString(),\n    health: bossBar.health,\n    color: bossBar.color,\n    dividers: bossBar.dividers\n  })\n})\n\nbot.on('bossBarDeleted', (bossBar) => {\n  console.log('Boss bar deleted:', bossBar.title.toString())\n})\n\n// After 5 seconds, update the boss bar\nsetTimeout(() => {\n  bot.chat('/bossbar set test:bar color blue')\n  bot.chat('/bossbar set test:bar style notched_10')\n  bot.chat('/bossbar set test:bar value 75')\n}, 5000)\n\n// After 10 seconds, remove the boss bar\nsetTimeout(() => {\n  bot.chat('/bossbar remove test:bar')\n}, 10000)\n"
  },
  {
    "path": "examples/chat_parsing.js",
    "content": "/*\nthis example is to show the different ways to parse chat messages\n\nExpected output in console:\n\nbot has just joined!\nbot has just left!\nbot has just rejoined!\nbot has just left!\n*/\nconst mineflayer = require('mineflayer')\nconst bot = mineflayer.createBot({\n  host: 'localhost',\n  username: 'bot'\n})\n\nbot.once('spawn', () => {\n  bot.addChatPattern('bot_left_the_game', /bot. left the game/)\n  bot.addChatPatternSet('bot_rejoins_the_game', [/bot. left the game/, /bot. joined the game/])\n  bot.addChatPattern('who_just_joined', /(.+) joined the game/, { parse: true, repeat: false })\n  makeChatMessages()\n})\n\nbot.on('chat:bot_left_the_game', matches => {\n  // => ['bot left the game']\n  console.log('bot has just left!')\n})\n\nbot.on('chat:bot_rejoins_the_game', matches => {\n  // => ['bot left the game', 'bot joined the game']\n  console.log('bot has just rejoined!')\n})\n\nbot.on('chat:who_just_joined', matches => {\n  console.log(`${matches[0]} has just joined!`) // should only run once\n})\n\nasync function makeChatMessages () {\n  let bot1 = mineflayer.createBot({\n    host: 'localhost',\n    username: 'bot1'\n  })\n  let bot2\n  setTimeout(() => bot1.quit(), 1500)\n  setTimeout(() => {\n    bot1 = mineflayer.createBot({\n      host: 'localhost',\n      username: 'bot1'\n    })\n  }, 1750)\n  setTimeout(() => {\n    bot2 = mineflayer.createBot({\n      host: 'localhost',\n      username: 'bot2'\n    }, 2000)\n  })\n  setTimeout(() => bot2.quit(), 2500)\n}\n\nbot.on('error', console.log)\n"
  },
  {
    "path": "examples/chatterbox.js",
    "content": "/*\n * This example demonstrates how easy it is to create a bot\n * that sends chat messages whenever something interesting happens\n * on the server you are connected to.\n *\n * Below you can find a wide range of different events you can watch\n * but remember to check out the API documentation to find even more!\n *\n * Some events may be commented out because they are very frequent and\n * may flood the chat, feel free to check them out for other purposes though.\n *\n * This bot also replies to some specific chat messages so you can ask him\n * a few information while you are in game.\n */\nconst mineflayer = require('mineflayer')\nconst { Vec3 } = require('vec3')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node chatterbot.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'chatterbox',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  const result = /canSee (-?[0-9]+),(-?[0-9]+),(-?[0-9]+)/.exec(message)\n  if (result) {\n    canSee(new Vec3(result[1], result[2], result[3]))\n    return\n  }\n  switch (message) {\n    case 'pos':\n      sayPosition(username)\n      break\n    case 'wearing':\n      sayEquipment()\n      break\n    case 'nick':\n      sayNick()\n      break\n    case 'spawn':\n      saySpawnPoint()\n      break\n    case 'block':\n      sayBlockUnder(username)\n      break\n    case 'quit':\n      quit(username)\n      break\n    default:\n      bot.chat(\"That's nice\")\n  }\n\n  function canSee (pos) {\n    const block = bot.blockAt(pos)\n    const r = bot.canSeeBlock(block)\n    if (r) {\n      bot.chat(`I can see the block of ${block.displayName} at ${pos}`)\n    } else {\n      bot.chat(`I cannot see the block of ${block.displayName} at ${pos}`)\n    }\n  }\n\n  function sayPosition (username) {\n    bot.chat(`I am at ${bot.entity.position}`)\n    bot.chat(`You are at ${bot.players[username].entity.position}`)\n  }\n\n  function sayEquipment () {\n    const eq = bot.players[username].entity.equipment\n    const eqText = []\n    if (eq[0]) eqText.push(`holding a ${eq[0].displayName}`)\n    if (eq[1]) eqText.push(`wearing a ${eq[1].displayName} on your feet`)\n    if (eq[2]) eqText.push(`wearing a ${eq[2].displayName} on your legs`)\n    if (eq[3]) eqText.push(`wearing a ${eq[3].displayName} on your torso`)\n    if (eq[4]) eqText.push(`wearing a ${eq[4].displayName} on your head`)\n    if (eqText.length) {\n      bot.chat(`You are ${eqText.join(', ')}.`)\n    } else {\n      bot.chat('You are naked!')\n    }\n  }\n\n  function saySpawnPoint () {\n    bot.chat(`Spawn is at ${bot.spawnPoint}`)\n  }\n\n  function sayBlockUnder () {\n    const block = bot.blockAt(bot.players[username].entity.position.offset(0, -1, 0))\n    bot.chat(`Block under you is ${block.displayName} in the ${block.biome.name} biome`)\n    console.log(block)\n  }\n\n  function quit (username) {\n    bot.quit(`${username} told me to`)\n  }\n\n  function sayNick () {\n    bot.chat(`My name is ${bot.player.displayName}`)\n  }\n})\n\nbot.on('whisper', (username, message, rawMessage) => {\n  console.log(`I received a message from ${username}: ${message}`)\n  bot.whisper(username, 'I can tell secrets too.')\n})\nbot.on('nonSpokenChat', (message) => {\n  console.log(`Non spoken chat: ${message}`)\n})\n\nbot.on('login', () => {\n  bot.chat('Hi everyone!')\n})\nbot.on('spawn', () => {\n  bot.chat('I spawned, watch out!')\n})\nbot.on('spawnReset', (message) => {\n  bot.chat('Oh noez! My bed is broken.')\n})\nbot.on('forcedMove', () => {\n  bot.chat(`I have been forced to move to ${bot.entity.position}`)\n})\nbot.on('health', () => {\n  bot.chat(`I have ${bot.health} health and ${bot.food} food`)\n})\nbot.on('death', () => {\n  bot.chat('I died x.x')\n})\nbot.on('kicked', (reason) => {\n  console.log(`I got kicked for ${reason}`)\n})\n\nbot.on('time', () => {\n  bot.chat('Current time: ' + bot.time.timeOfDay)\n})\nbot.on('rain', () => {\n  if (bot.isRaining) {\n    bot.chat('It started raining.')\n  } else {\n    bot.chat('It stopped raining.')\n  }\n})\nbot.on('noteHeard', (block, instrument, pitch) => {\n  bot.chat(`Music for my ears! I just heard a ${instrument.name}`)\n})\nbot.on('chestLidMove', (block, isOpen) => {\n  const action = isOpen ? 'open' : 'close'\n  bot.chat(`Hey, did someone just ${action} a chest?`)\n})\nbot.on('pistonMove', (block, isPulling, direction) => {\n  const action = isPulling ? 'pulling' : 'pushing'\n  bot.chat(`A piston is ${action} near me, i can hear it.`)\n})\n\nbot.on('playerJoined', (player) => {\n  if (player.username !== bot.username) {\n    bot.chat(`Hello, ${player.username}! Welcome to the server.`)\n  }\n})\nbot.on('playerLeft', (player) => {\n  if (player.username === bot.username) return\n  bot.chat(`Bye ${player.username}`)\n})\nbot.on('playerCollect', (collector, collected) => {\n  if (collector.type === 'player') {\n    const item = collected.getDroppedItem()\n    bot.chat(`${collector.username !== bot.username ? (\"I'm so jealous. \" + collector.username) : 'I '} collected ${item.count} ${item.displayName}`)\n  }\n})\n\nbot.on('entitySpawn', (entity) => {\n  if (entity.type === 'mob') {\n    console.log(`Look out! A ${entity.displayName} spawned at ${entity.position}`)\n  } else if (entity.type === 'player') {\n    bot.chat(`Look who decided to show up: ${entity.username}`)\n  } else if (entity.type === 'object') {\n    console.log(`There's a ${entity.displayName} at ${entity.position}`)\n  } else if (entity.type === 'global') {\n    bot.chat('Ooh lightning!')\n  } else if (entity.type === 'orb') {\n    bot.chat('Gimme dat exp orb!')\n  }\n})\nbot.on('entityHurt', (entity) => {\n  if (entity.type === 'mob') {\n    bot.chat(`Haha! The ${entity.displayName} got hurt!`)\n  } else if (entity.type === 'player') {\n    bot.chat(`Aww, poor ${entity.username} got hurt. Maybe you shouldn't have a ping of ${bot.players[entity.username].ping}`)\n  }\n})\nbot.on('entitySwingArm', (entity) => {\n  bot.chat(`${entity.username}, I see that your arm is working fine.`)\n})\nbot.on('entityCrouch', (entity) => {\n  bot.chat(`${entity.username}: you so sneaky.`)\n})\nbot.on('entityUncrouch', (entity) => {\n  bot.chat(`${entity.username}: welcome back from the land of hunchbacks.`)\n})\nbot.on('entitySleep', (entity) => {\n  bot.chat(`Good night, ${entity.username}`)\n})\nbot.on('entityWake', (entity) => {\n  bot.chat(`Top of the morning, ${entity.username}`)\n})\nbot.on('entityEat', (entity) => {\n  bot.chat(`${entity.username}: OM NOM NOM NOMONOM. That's what you sound like.`)\n})\nbot.on('entityAttach', (entity, vehicle) => {\n  if (entity.type === 'player' && vehicle.type === 'object') {\n    bot.chat(`Sweet, ${entity.username} is riding that ${vehicle.displayName}`)\n  }\n})\nbot.on('entityDetach', (entity, vehicle) => {\n  if (entity.type === 'player' && vehicle.type === 'object') {\n    bot.chat(`Lame, ${entity.username} stopped riding the ${vehicle.displayName}`)\n  }\n})\nbot.on('entityEquipmentChange', (entity) => {\n  console.log('entityEquipmentChange', entity)\n})\nbot.on('entityEffect', (entity, effect) => {\n  console.log('entityEffect', entity, effect)\n})\nbot.on('entityEffectEnd', (entity, effect) => {\n  console.log('entityEffectEnd', entity, effect)\n})\n"
  },
  {
    "path": "examples/chest.js",
    "content": "/*\n * Watch out, this is a big one!\n *\n * This is a demonstration to show you how you can interact with:\n * - Chests\n * - Furnaces\n * - Dispensers\n * - Enchantment Tables\n *\n * and of course with your own inventory.\n *\n * Each of the main commands makes the bot interact with the block and open\n * its window. From there you can send another set of commands to actually\n * interact with the window and make awesome stuff.\n *\n * There's also a bonus example which shows you how to use the /invsee command\n * to see what items another user has in his inventory and what items he has\n * equipped.\n * This last one is usually reserved to Server Ops so make sure you have the\n * appropriate permission to do it or it won't work.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node chest.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'chest',\n  password: process.argv[5]\n})\n\nbot.on('experience', () => {\n  bot.chat(`I am level ${bot.experience.level}`)\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  switch (true) {\n    case /^list$/.test(message):\n      sayItems()\n      break\n    case /^chest$/.test(message):\n      watchChest(false, ['chest', 'ender_chest', 'trapped_chest'])\n      break\n    case /^furnace$/.test(message):\n      watchFurnace()\n      break\n    case /^dispenser$/.test(message):\n      watchChest(false, ['dispenser'])\n      break\n    case /^enchant$/.test(message):\n      watchEnchantmentTable()\n      break\n    case /^chestminecart$/.test(message):\n      watchChest(true)\n      break\n    case /^invsee \\w+( \\d)?$/.test(message): {\n      // invsee Herobrine [or]\n      // invsee Herobrine 1\n      const command = message.split(' ')\n      useInvsee(command[0], command[1])\n      break\n    }\n  }\n})\n\nfunction sayItems (items = bot.inventory.items()) {\n  const output = items.map(itemToString).join(', ')\n  if (output) {\n    bot.chat(output)\n  } else {\n    bot.chat('empty')\n  }\n}\n\nasync function watchChest (minecart, blocks = []) {\n  let chestToOpen\n  if (minecart) {\n    chestToOpen = Object.keys(bot.entities)\n      .map(id => bot.entities[id]).find(e => e.entityType === bot.registry.entitiesByName.chest_minecart &&\n      e.objectData.intField === 1 &&\n      bot.entity.position.distanceTo(e.position) < 3)\n    if (!chestToOpen) {\n      bot.chat('no chest minecart found')\n      return\n    }\n  } else {\n    chestToOpen = bot.findBlock({\n      matching: blocks.map(name => bot.registry.blocksByName[name].id),\n      maxDistance: 6\n    })\n    if (!chestToOpen) {\n      bot.chat('no chest found')\n      return\n    }\n  }\n  const chest = await bot.openContainer(chestToOpen)\n  sayItems(chest.containerItems())\n  chest.on('updateSlot', (slot, oldItem, newItem) => {\n    bot.chat(`chest update: ${itemToString(oldItem)} -> ${itemToString(newItem)} (slot: ${slot})`)\n  })\n  chest.on('close', () => {\n    bot.chat('chest closed')\n  })\n\n  bot.on('chat', onChat)\n\n  function onChat (username, message) {\n    if (username === bot.username) return\n    const command = message.split(' ')\n    switch (true) {\n      case /^close$/.test(message):\n        closeChest()\n        break\n      case /^withdraw \\d+ \\w+$/.test(message):\n        // withdraw amount name\n        // ex: withdraw 16 stick\n        withdrawItem(command[2], command[1])\n        break\n      case /^deposit \\d+ \\w+$/.test(message):\n        // deposit amount name\n        // ex: deposit 16 stick\n        depositItem(command[2], command[1])\n        break\n    }\n  }\n\n  function closeChest () {\n    chest.close()\n    bot.removeListener('chat', onChat)\n  }\n\n  async function withdrawItem (name, amount) {\n    const item = itemByName(chest.containerItems(), name)\n    if (item) {\n      try {\n        await chest.withdraw(item.type, null, amount)\n        bot.chat(`withdrew ${amount} ${item.name}`)\n      } catch (err) {\n        bot.chat(`unable to withdraw ${amount} ${item.name}`)\n      }\n    } else {\n      bot.chat(`unknown item ${name}`)\n    }\n  }\n\n  async function depositItem (name, amount) {\n    const item = itemByName(chest.items(), name)\n    if (item) {\n      try {\n        await chest.deposit(item.type, null, amount)\n        bot.chat(`deposited ${amount} ${item.name}`)\n      } catch (err) {\n        bot.chat(`unable to deposit ${amount} ${item.name}`)\n      }\n    } else {\n      bot.chat(`unknown item ${name}`)\n    }\n  }\n}\n\nasync function watchFurnace () {\n  const furnaceBlock = bot.findBlock({\n    matching: ['furnace', 'lit_furnace'].filter(name => bot.registry.blocksByName[name] !== undefined).map(name => bot.registry.blocksByName[name].id),\n    maxDistance: 6\n  })\n  if (!furnaceBlock) {\n    bot.chat('no furnace found')\n    return\n  }\n  const furnace = await bot.openFurnace(furnaceBlock)\n  let output = ''\n  output += `input: ${itemToString(furnace.inputItem())}, `\n  output += `fuel: ${itemToString(furnace.fuelItem())}, `\n  output += `output: ${itemToString(furnace.outputItem())}`\n  bot.chat(output)\n\n  furnace.on('updateSlot', (slot, oldItem, newItem) => {\n    bot.chat(`furnace update: ${itemToString(oldItem)} -> ${itemToString(newItem)} (slot: ${slot})`)\n  })\n  furnace.on('close', () => {\n    bot.chat('furnace closed')\n  })\n  furnace.on('update', () => {\n    console.log(`fuel: ${Math.round(furnace.fuel * 100)}% progress: ${Math.round(furnace.progress * 100)}%`)\n  })\n\n  bot.on('chat', onChat)\n\n  function onChat (username, message) {\n    if (username === bot.username) return\n    const command = message.split(' ')\n    switch (true) {\n      case /^close$/.test(message):\n        closeFurnace()\n        break\n      case /^(input|fuel) \\d+ \\w+$/.test(message):\n        // input amount name\n        // ex: input 32 coal\n        putInFurnace(command[0], command[2], command[1])\n        break\n      case /^take (input|fuel|output)$/.test(message):\n        // take what\n        // ex: take output\n        takeFromFurnace(command[0])\n        break\n    }\n\n    function closeFurnace () {\n      furnace.close()\n      bot.removeListener('chat', onChat)\n    }\n\n    async function putInFurnace (where, name, amount) {\n      const item = itemByName(furnace.items(), name)\n      if (item) {\n        const fn = {\n          input: furnace.putInput,\n          fuel: furnace.putFuel\n        }[where]\n        try {\n          await fn.call(furnace, item.type, null, amount)\n          bot.chat(`put ${amount} ${item.name}`)\n        } catch (err) {\n          bot.chat(`unable to put ${amount} ${item.name}`)\n        }\n      } else {\n        bot.chat(`unknown item ${name}`)\n      }\n    }\n\n    async function takeFromFurnace (what) {\n      const fn = {\n        input: furnace.takeInput,\n        fuel: furnace.takeFuel,\n        output: furnace.takeOutput\n      }[what]\n      try {\n        const item = await fn.call(furnace)\n        bot.chat(`took ${item.name}`)\n      } catch (err) {\n        bot.chat('unable to take')\n      }\n    }\n  }\n}\n\nasync function watchEnchantmentTable () {\n  const enchantTableBlock = bot.findBlock({\n    matching: ['enchanting_table'].map(name => bot.registry.blocksByName[name].id),\n    maxDistance: 6\n  })\n  if (!enchantTableBlock) {\n    bot.chat('no enchantment table found')\n    return\n  }\n  const table = await bot.openEnchantmentTable(enchantTableBlock)\n  bot.chat(itemToString(table.targetItem()))\n\n  table.on('updateSlot', (slot, oldItem, newItem) => {\n    bot.chat(`enchantment table update: ${itemToString(oldItem)} -> ${itemToString(newItem)} (slot: ${slot})`)\n  })\n  table.on('close', () => {\n    bot.chat('enchantment table closed')\n  })\n  table.on('ready', () => {\n    bot.chat(`ready to enchant. choices are ${table.enchantments.map(o => o.level).join(', ')}`)\n  })\n\n  bot.on('chat', onChat)\n\n  function onChat (username, message) {\n    if (username === bot.username) return\n    const command = message.split(' ')\n    switch (true) {\n      case /^close$/.test(message):\n        closeEnchantmentTable()\n        break\n      case /^put \\w+$/.test(message):\n        // put name\n        // ex: put diamondsword\n        putItem(command[1])\n        break\n      case /^add lapis$/.test(message):\n        addLapis()\n        break\n      case /^enchant \\d+$/.test(message):\n        // enchant choice\n        // ex: enchant 2\n        enchantItem(command[1])\n        break\n      case /^take$/.test(message):\n        takeEnchantedItem()\n        break\n    }\n\n    function closeEnchantmentTable () {\n      table.close()\n    }\n\n    async function putItem (name) {\n      const item = itemByName(table.window.items(), name)\n      if (item) {\n        try {\n          await table.putTargetItem(item)\n          bot.chat(`I put ${itemToString(item)}`)\n        } catch (err) {\n          bot.chat(`error putting ${itemToString(item)}`)\n        }\n      } else {\n        bot.chat(`unknown item ${name}`)\n      }\n    }\n\n    async function addLapis () {\n      const item = itemByType(table.window.items(), ['dye', 'purple_dye', 'lapis_lazuli'].filter(name => bot.registry.itemByName[name] !== undefined)\n        .map(name => bot.registry.itemByName[name].id))\n      if (item) {\n        try {\n          await table.putLapis(item)\n          bot.chat(`I put ${itemToString(item)}`)\n        } catch (err) {\n          bot.chat(`error putting ${itemToString(item)}`)\n        }\n      } else {\n        bot.chat(\"I don't have any lapis\")\n      }\n    }\n\n    async function enchantItem (choice) {\n      choice = parseInt(choice, 10)\n      try {\n        const item = await table.enchant(choice)\n        bot.chat(`enchanted ${itemToString(item)}`)\n      } catch (err) {\n        bot.chat('error enchanting')\n      }\n    }\n\n    async function takeEnchantedItem () {\n      try {\n        const item = await table.takeTargetItem()\n        bot.chat(`got ${itemToString(item)}`)\n      } catch (err) {\n        bot.chat('error getting item')\n      }\n    }\n  }\n}\n\nfunction useInvsee (username, showEquipment) {\n  bot.once('windowOpen', (window) => {\n    const count = window.containerItems().length\n    const what = showEquipment ? 'equipment' : 'inventory items'\n    if (count) {\n      bot.chat(`${username}'s ${what}:`)\n      sayItems(window.containerItems())\n    } else {\n      bot.chat(`${username} has no ${what}`)\n    }\n  })\n  if (showEquipment) {\n    // any extra parameter triggers the easter egg\n    // and shows the other player's equipment\n    bot.chat(`/invsee ${username} 1`)\n  } else {\n    bot.chat(`/invsee ${username}`)\n  }\n}\n\nfunction itemToString (item) {\n  if (item) {\n    return `${item.name} x ${item.count}`\n  } else {\n    return '(nothing)'\n  }\n}\n\nfunction itemByType (items, type) {\n  let item\n  let i\n  for (i = 0; i < items.length; ++i) {\n    item = items[i]\n    if (item && item.type === type) return item\n  }\n  return null\n}\n\nfunction itemByName (items, name) {\n  let item\n  let i\n  for (i = 0; i < items.length; ++i) {\n    item = items[i]\n    if (item && item.name === name) return item\n  }\n  return null\n}\n"
  },
  {
    "path": "examples/cli/readline.js",
    "content": "/*\n * This example is an easy way to connect mineflayer to the node:readline module\n * See: https://nodejs.org/api/readline.html\n * Using this, we can make a simple terminal-to-ingame-chat interface\n *\n * Made by Jovan04 01/24/2023\n*/\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node readline.js <host> <port> [<name>] [<auth>]')\n  process.exit(1)\n}\n\nconst mineflayer = require('mineflayer') // load mineflayer library\nconst readline = require('node:readline') // load the node.js readline module\n\n// bot options\nconst options = {\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] || 'readline',\n  auth: process.argv[5] || 'offline'\n}\n\nconst bot = mineflayer.createBot(options) // join the minecraft server\n\nconst rl = readline.createInterface({ // creates our readline interface with our console as input and output\n  input: process.stdin,\n  output: process.stdout\n})\n\nbot.once('spawn', () => {\n  console.log(`Bot joined the game with username ${bot.username}.`)\n  rl.setPrompt('> '); rl.prompt() // gives us a little arrow at the bottom for the input line\n})\n\nbot.on('message', (message) => {\n  readline.moveCursor(process.stdout, -2, 0) // we move the cursor to the left two places because our cursor is already two positions in (because of the input arrow)\n  console.log(message.toAnsi()) // convert our message to ansi to preserve chat formatting\n  rl.prompt() // regenerate our little arrow on the input line\n})\n\nrl.on('line', (line) => {\n  readline.moveCursor(process.stdout, 0, -1) // move cursor up one line\n  readline.clearScreenDown(process.stdout) // clear all the lines below the cursor (i.e. the last line we entered)\n  bot.chat(line.toString()) // sends the line we entered to ingame chat\n})\n\nbot.on('kicked', console.log)\nbot.on('error', console.log)\n"
  },
  {
    "path": "examples/collectblock.js",
    "content": "/**\n * A quick and easy implementation of the collect block plugin. (Requires mineflayer-pathfinder and mineflayer-collectblock)\n */\nconst mineflayer = require('mineflayer')\nconst pathfinder = require('mineflayer-pathfinder').pathfinder\nconst collectBlock = require('mineflayer-collectblock').plugin\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node collectblock.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'collector',\n  password: process.argv[5]\n})\n\n// Load pathfinder and collect block plugins\nbot.loadPlugin(pathfinder)\nbot.loadPlugin(collectBlock)\n\n// Listen for when a player says \"collect [something]\" in chat\nbot.on('chat', (username, message) => {\n  const args = message.split(' ')\n  if (args[0] !== 'collect') return\n\n  // Get the correct block type\n  const blockType = bot.registry.blocksByName[args[1]]\n  if (!blockType) {\n    bot.chat(\"I don't know any blocks with that name.\")\n    return\n  }\n\n  bot.chat('Collecting the nearest ' + blockType.name)\n\n  // Try and find that block type in the world\n  const block = bot.findBlock({\n    matching: blockType.id,\n    maxDistance: 64\n  })\n\n  if (!block) {\n    bot.chat(\"I don't see that block nearby.\")\n    return\n  }\n\n  // Collect the block if we found one\n  bot.collectBlock.collect(block, err => {\n    if (err) bot.chat(err.message)\n  })\n})\n"
  },
  {
    "path": "examples/command_block.js",
    "content": "/*\n * An example on how to set and read command blocks\n */\n\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node command_block.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'command_block',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  const command = message.split(' ')\n  switch (true) {\n    case /^setCommandBlock (.+)$/.test(message): {\n      const commandBlock = bot.findBlock({\n        matching: bot.registry.blocksByName.command_block.id\n      })\n      bot.setCommandBlock(commandBlock.position, command[1], false)\n      break\n    }\n  }\n})\n"
  },
  {
    "path": "examples/crossbower.js",
    "content": "// This example will shoot the player that said \"fire\" in chat, when it is said in chat.\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node crossbower.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'crossbower',\n  password: process.argv[5]\n})\n\nbot.on('spawn', function () {\n  bot.chat(`/give ${bot.username} crossbow{Enchantments:[{id:quick_charge,lvl:3},{id:unbreaking,lvl:3}]} 1`) // Test with fast charge\n  // bot.chat(`/give ${bot.username} crossbow 1`) // Test with slow charge\n  bot.chat(`/give ${bot.username} minecraft:arrow 64`)\n})\n\nbot.on('chat', async (username, message) => {\n  if (message === 'fire') {\n    // Check if weapon is equipped\n    const slotID = bot.getEquipmentDestSlot('hand')\n    if (bot.inventory.slots[slotID] === null || bot.inventory.slots[slotID].name !== 'crossbow') {\n      const weaponFound = bot.inventory.items().find(item => item.name === 'crossbow')\n      if (weaponFound) {\n        await bot.equip(weaponFound, 'hand')\n      } else {\n        console.log('No weapon in inventory')\n        return\n      }\n    }\n\n    const isEnchanted = bot.heldItem.nbt.value.Enchantments ? bot.heldItem.nbt.value.Enchantments.value.value.find(enchant => enchant.id.value === 'quick_charge') : undefined\n\n    const timeForCharge = 1250 - ((isEnchanted ? isEnchanted.lvl.value : 0) * 250)\n\n    bot.activateItem() // charge\n    await sleep(timeForCharge) // wait for crossbow to charge\n    bot.deactivateItem() // raise weapon\n\n    try {\n      bot.lookAt(bot.players[username].entity.position, true)\n      await bot.waitForTicks(5) // wait for lookat to finish\n      bot.activateItem() // fire\n      bot.deactivateItem()\n    } catch (err) {\n      bot.chat('Player disappeared, crossbow is charged now.')\n    }\n  }\n})\n\nfunction sleep (ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n"
  },
  {
    "path": "examples/crystal.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node crystal.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'crystal',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (message === 'compute') {\n    const target = bot.players[username]?.entity\n    if (!target) {\n      bot.chat('I don\\'t know where you are')\n      return\n    }\n    const crystal = bot.nearestEntity(entity => entity.name.includes('crystal'))\n    if (!crystal) {\n      bot.chat('No crystal nearby')\n      return\n    }\n\n    const damages = bot.getExplosionDamages(target, crystal.position, 6)\n\n    bot.chat(`You'll take ${damages} damages.`)\n  }\n})\n"
  },
  {
    "path": "examples/digger.js",
    "content": "/*\n * Never spend hours mining from ground to bedrock again!\n *\n * Learn how to create a simple bot that is capable of digging the block\n * below his feet and then going back up by creating a dirt column to the top.\n *\n * As always, you can send the bot commands using chat messages, and monitor\n * his inventory at any time.\n *\n * Remember that in survival mode he might not have enough dirt to get back up,\n * so be sure to teach him a few more tricks before leaving him alone at night.\n */\nconst mineflayer = require('mineflayer')\nconst vec3 = require('vec3')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node digger.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'digger',\n  password: process.argv[5]\n})\n\nbot.on('chat', async (username, message) => {\n  if (username === bot.username) return\n  switch (message) {\n    case 'loaded':\n      await bot.waitForChunksToLoad()\n      bot.chat('Ready!')\n      break\n    case 'list':\n      sayItems()\n      break\n    case 'dig':\n      dig()\n      break\n    case 'build':\n      build()\n      break\n    case 'equip dirt':\n      equipDirt()\n      break\n  }\n})\n\nfunction sayItems (items = bot.inventory.items()) {\n  const output = items.map(itemToString).join(', ')\n  if (output) {\n    bot.chat(output)\n  } else {\n    bot.chat('empty')\n  }\n}\n\nasync function dig () {\n  let target\n  if (bot.targetDigBlock) {\n    bot.chat(`already digging ${bot.targetDigBlock.name}`)\n  } else {\n    target = bot.blockAt(bot.entity.position.offset(0, -1, 0))\n    if (target && bot.canDigBlock(target)) {\n      bot.chat(`starting to dig ${target.name}`)\n      try {\n        await bot.dig(target)\n        bot.chat(`finished digging ${target.name}`)\n      } catch (err) {\n        console.log(err.stack)\n      }\n    } else {\n      bot.chat('cannot dig')\n    }\n  }\n}\n\nfunction build () {\n  const referenceBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0))\n  const jumpY = Math.floor(bot.entity.position.y) + 1.0\n  bot.setControlState('jump', true)\n  bot.on('move', placeIfHighEnough)\n\n  let tryCount = 0\n\n  async function placeIfHighEnough () {\n    if (bot.entity.position.y > jumpY) {\n      try {\n        await bot.placeBlock(referenceBlock, vec3(0, 1, 0))\n        bot.setControlState('jump', false)\n        bot.removeListener('move', placeIfHighEnough)\n        bot.chat('Placing a block was successful')\n      } catch (err) {\n        tryCount++\n        if (tryCount > 10) {\n          bot.chat(err.message)\n          bot.setControlState('jump', false)\n          bot.removeListener('move', placeIfHighEnough)\n        }\n      }\n    }\n  }\n}\n\nasync function equipDirt () {\n  let itemsByName\n  if (bot.supportFeature('itemsAreNotBlocks')) {\n    itemsByName = 'itemsByName'\n  } else if (bot.supportFeature('itemsAreAlsoBlocks')) {\n    itemsByName = 'blocksByName'\n  }\n  try {\n    await bot.equip(bot.registry[itemsByName].dirt.id, 'hand')\n    bot.chat('equipped dirt')\n  } catch (err) {\n    bot.chat(`unable to equip dirt: ${err.message}`)\n  }\n}\n\nfunction itemToString (item) {\n  if (item) {\n    return `${item.name} x ${item.count}`\n  } else {\n    return '(nothing)'\n  }\n}\n"
  },
  {
    "path": "examples/discord.js",
    "content": "/*\n * This example is a very simple way how to connect a discord bot with a mineflayer bot.\n * For this example you will need discord.js installed. You can install with: npm install discord.js\n * This example uses discord.js v14\n * You need to do this before running this example:\n * - You need to get a discord bot token\n * - You need to get the id of the channel you want to use\n *\n * Original credit to U9G, updated by Jovan04 12/19/2022\n*/\n\nif (process.argv.length < 6 || process.argv.length > 8) {\n  console.log('Usage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<auth>]')\n  process.exit(1)\n}\n\n// load discord.js\nconst { Client, GatewayIntentBits } = require('discord.js')\nconst { MessageContent, GuildMessages, Guilds } = GatewayIntentBits\n\nlet channel = process.argv[3]\nconst token = process.argv[2]\n\n// create new discord client that can see what servers the bot is in, as well as the messages in those servers\nconst client = new Client({ intents: [Guilds, GuildMessages, MessageContent] })\nclient.login(token)\n\n// load mineflayer\nconst mineflayer = require('mineflayer')\n\n// bot options\nconst options = {\n  host: process.argv[4],\n  port: parseInt(process.argv[5]),\n  username: process.argv[6] || 'discord',\n  auth: process.argv[7] || 'offline'\n}\n\n// join server\nconst bot = mineflayer.createBot(options)\nbot.on('spawn', () => {\n  console.log(`Mineflayer bot logged in as ${bot.username}`)\n})\n\n// when discord client is ready, send login message\nclient.once('ready', (c) => {\n  console.log(`Discord bot logged in as ${c.user.tag}`)\n  channel = client.channels.cache.get(channel)\n  if (!channel) {\n    console.log(`I could not find the channel (${process.argv[3]})!`)\n    console.log('Usage : node discord.js <discord bot token> <channel id> <host> <port> [<name>] [<auth>]')\n    process.exit(1)\n  }\n})\n\nclient.on('messageCreate', (message) => {\n  // Only handle messages in specified channel\n  if (message.channel.id !== channel.id) return\n  // Ignore messages from the bot itself\n  if (message.author.id === client.user.id) return\n  // console.log(message)\n  bot.chat(`${message.author.username}: ${message.content}`)\n})\n\n// Redirect in-game messages to Discord channel\nbot.on('chat', (username, message) => {\n  // Ignore messages from the bot itself\n  if (username === bot.username) return\n\n  channel.send(`${username}: ${message}`)\n})\n"
  },
  {
    "path": "examples/echo.js",
    "content": "/*\n * This is one of the simplest examples.\n *\n * We created a simple bot that echoes back everything that is said on chat.\n *\n * It's not very useful yet, but you can use this as a starting point\n * to create your own bot.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node echo.js <host> <port> [<name>] [online?]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'echo',\n  auth: process.argv[5] ? 'microsoft' : 'offline'\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  bot.chat(message)\n})\n\nbot.on('kicked', (reason) => {\n  console.log('I was kicked from the server: ' + reason)\n})\n"
  },
  {
    "path": "examples/elytra.js",
    "content": "// This example will shoot the player that said \"fire\" in chat, when it is said in chat.\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node elytra.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'elytraer',\n  password: process.argv[5]\n})\n\nbot.on('error', err => {\n  console.log(err)\n})\n\nbot.on('kicked', err => {\n  console.log(err)\n})\n\nbot.on('spawn', async function () {\n  bot.chat(`/give ${bot.username} minecraft:elytra`)\n  bot.chat(`/give ${bot.username} minecraft:firework_rocket 64`)\n\n  await sleep(1000)\n  const elytraItem = bot.inventory.slots.find(item => item?.name === 'elytra')\n  if (elytraItem == null) {\n    console.log('no elytra')\n    return\n  }\n  await bot.equip(elytraItem, 'torso')\n  const fireworkItem = bot.inventory.slots.find(item => item?.name === 'firework_rocket')\n  if (fireworkItem == null) {\n    console.log('no fireworks')\n    return\n  }\n  await bot.equip(fireworkItem, 'hand')\n})\n\nbot.on('chat', async (username, message) => {\n  if (message === 'fly') {\n    await bot.look(bot.entity.yaw, 50 * Math.PI / 180)\n    bot.setControlState('jump', true)\n    bot.setControlState('jump', false)\n    await sleep(50)\n\n    // try to fly\n    try {\n      await bot.elytraFly()\n    } catch (err) {\n      bot.chat(`Failed to fly: ${err}`)\n      return\n    }\n    await sleep(50)\n\n    // use rocket\n    bot.activateItem()\n  }\n})\n\nfunction sleep (ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n"
  },
  {
    "path": "examples/farmer.js",
    "content": "const { Vec3 } = require('vec3')\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node farmer.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'farmer',\n  password: process.argv[5]\n})\n\n// To fish we have to give bot the seeds\n// /give farmer wheat_seeds 64\n\nfunction blockToSow () {\n  return bot.findBlock({\n    point: bot.entity.position,\n    matching: bot.registry.blocksByName.farmland.id,\n    maxDistance: 6,\n    useExtraInfo: (block) => {\n      const blockAbove = bot.blockAt(block.position.offset(0, 1, 0))\n      return !blockAbove || blockAbove.type === 0\n    }\n  })\n}\n\nfunction blockToHarvest () {\n  return bot.findBlock({\n    point: bot.entity.position,\n    maxDistance: 6,\n    matching: (block) => {\n      return block && block.type === bot.registry.blocksByName.wheat.id && block.metadata === 7\n    }\n  })\n}\n\nasync function loop () {\n  try {\n    while (1) {\n      const toHarvest = blockToHarvest()\n      if (toHarvest) {\n        await bot.dig(toHarvest)\n      } else {\n        break\n      }\n    }\n    while (1) {\n      const toSow = blockToSow()\n      if (toSow) {\n        await bot.equip(bot.registry.itemsByName.wheat_seeds.id, 'hand')\n        await bot.placeBlock(toSow, new Vec3(0, 1, 0))\n      } else {\n        break\n      }\n    }\n  } catch (e) {\n    console.log(e)\n  }\n\n  // No block to harvest or sow. Postpone next loop a bit\n  setTimeout(loop, 1000)\n}\n\nbot.once('login', loop)\n"
  },
  {
    "path": "examples/fisherman.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node fisherman.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'fisherman',\n  password: process.argv[5]\n})\n\n// To fish we have to give bot the fishing rod and teleport bot to the water\n// /give fisherman fishing_rod 1\n// /teleport fisherman ~ ~ ~\n\n// To eat we have to apply hunger first\n// /effect fisherman minecraft:hunger 1 255\n\nbot.on('message', (cm) => {\n  if (cm.toString().includes('start')) {\n    startFishing()\n  }\n\n  if (cm.toString().includes('stop')) {\n    stopFishing()\n  }\n\n  if (cm.toString().includes('eat')) {\n    eat()\n  }\n})\n\nlet nowFishing = false\n\nfunction onCollect (player, entity) {\n  if (entity.kind === 'Drops' && player === bot.entity) {\n    bot.removeListener('playerCollect', onCollect)\n    startFishing()\n  }\n}\n\nasync function startFishing () {\n  bot.chat('Fishing')\n  try {\n    await bot.equip(bot.registry.itemsByName.fishing_rod.id, 'hand')\n  } catch (err) {\n    return bot.chat(err.message)\n  }\n\n  nowFishing = true\n  bot.on('playerCollect', onCollect)\n\n  try {\n    await bot.fish()\n  } catch (err) {\n    bot.chat(err.message)\n  }\n  nowFishing = false\n}\n\nfunction stopFishing () {\n  bot.removeListener('playerCollect', onCollect)\n\n  if (nowFishing) {\n    bot.activateItem()\n  }\n}\n\nasync function eat () {\n  stopFishing()\n\n  try {\n    await bot.equip(bot.registry.itemsByName.fish.id, 'hand')\n  } catch (err) {\n    return bot.chat(err.message)\n  }\n\n  try {\n    await bot.consume()\n  } catch (err) {\n    return bot.chat(err.message)\n  }\n}\n"
  },
  {
    "path": "examples/graffiti.js",
    "content": "/*\n * What's better than a bot that knows how to read and understands art?\n *\n * Learn how easy it is to interact with signs and paintings in this example.\n *\n * You can send commands to this bot using chat messages, the bot will\n * reply by telling you the name of the nearest painting or the text written on\n * the nearest sign, and you can also update signs with custom messages!\n *\n * To update a sign simply send a message in this format: write [your message]\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node graffiti.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'graffiti',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  switch (true) {\n    case /^watch$/.test(message):\n      watchPaintingOrSign()\n      break\n    case /^write .+$/.test(message):\n      // write message\n      // ex: write I love diamonds\n      updateSign(message)\n      break\n  }\n})\n\nfunction watchPaintingOrSign () {\n  const paintingBlock = bot.findBlock({\n    matching (block) {\n      return !!block.painting\n    }\n  })\n  const signBlock = bot.findBlock({\n    matching: ['painting', 'sign'].map(name => bot.registry.blocksByName[name].id)\n  })\n  if (signBlock) {\n    bot.chat(`The sign says: ${signBlock.signText}`)\n  } else if (paintingBlock) {\n    bot.chat(`The painting is: ${paintingBlock.painting.name}`)\n  } else {\n    bot.chat('There are no signs or paintings near me')\n  }\n}\n\nfunction updateSign (message) {\n  const signBlock = bot.findBlock({\n    matching: ['painting', 'sign'].map(name => bot.registry.blocksByName[name].id)\n  })\n  if (signBlock) {\n    bot.updateSign(signBlock, message.split(' ').slice(1).join(' '))\n    bot.chat('Sign updated')\n  } else {\n    bot.chat('There are no signs near me')\n  }\n}\n"
  },
  {
    "path": "examples/guard.js",
    "content": "/**\n * This bot example shows the basic usage of the mineflayer-pvp plugin for guarding a defined area from nearby mobs.\n */\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node guard.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst mineflayer = require('mineflayer')\nconst { pathfinder, Movements, goals } = require('mineflayer-pathfinder')\nconst pvp = require('mineflayer-pvp').plugin\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'Guard',\n  password: process.argv[5]\n})\n\nbot.loadPlugin(pathfinder)\nbot.loadPlugin(pvp)\n\nlet guardPos = null\n\n// Assign the given location to be guarded\nfunction guardArea (pos) {\n  guardPos = pos\n\n  // We we are not currently in combat, move to the guard pos\n  if (!bot.pvp.target) {\n    moveToGuardPos()\n  }\n}\n\n// Cancel all pathfinder and combat\nfunction stopGuarding () {\n  guardPos = null\n  bot.pvp.stop()\n  bot.pathfinder.setGoal(null)\n}\n\n// Pathfinder to the guard position\nfunction moveToGuardPos () {\n  bot.pathfinder.setMovements(new Movements(bot))\n  bot.pathfinder.setGoal(new goals.GoalBlock(guardPos.x, guardPos.y, guardPos.z))\n}\n\n// Called when the bot has killed it's target.\nbot.on('stoppedAttacking', () => {\n  if (guardPos) {\n    moveToGuardPos()\n  }\n})\n\n// Check for new enemies to attack\nbot.on('physicsTick', () => {\n  if (!guardPos) return // Do nothing if bot is not guarding anything\n\n  // Only look for mobs within 16 blocks\n  const filter = e => e.type === 'mob' && e.position.distanceTo(bot.entity.position) < 16 &&\n                    e.displayName !== 'Armor Stand' // Mojang classifies armor stands as mobs for some reason?\n\n  const entity = bot.nearestEntity(filter)\n  if (entity) {\n    // Start attacking\n    bot.pvp.attack(entity)\n  }\n})\n\n// Listen for player commands\nbot.on('chat', (username, message) => {\n  // Guard the location the player is standing\n  if (message === 'guard') {\n    const player = bot.players[username]\n\n    if (!player) {\n      bot.chat(\"I can't see you.\")\n      return\n    }\n\n    bot.chat('I will guard that location.')\n    guardArea(player.entity.position)\n  }\n\n  // Stop guarding\n  if (message === 'stop') {\n    bot.chat('I will no longer guard this area.')\n    stopGuarding()\n  }\n})\n"
  },
  {
    "path": "examples/inventory.js",
    "content": "/*\n * Using the inventory is one of the first things you learn in Minecraft,\n * now it's time to teach your bot the same skill.\n *\n * Command your bot with chat messages and make him toss, equip, use items\n * and even craft new items using the built-in recipe book.\n *\n * To learn more about the recipe system and how crafting works\n * remember to read the API documentation!\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node inventory.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'inventory',\n  password: process.argv[5]\n})\n\nbot.on('chat', async (username, message) => {\n  if (username === bot.username) return\n  const command = message.split(' ')\n  switch (true) {\n    case message === 'loaded':\n      await bot.waitForChunksToLoad()\n      bot.chat('Ready!')\n      break\n    case /^list$/.test(message):\n      sayItems()\n      break\n    case /^toss \\d+ \\w+$/.test(message):\n      // toss amount name\n      // ex: toss 64 diamond\n      tossItem(command[2], command[1])\n      break\n    case /^toss \\w+$/.test(message):\n      // toss name\n      // ex: toss diamond\n      tossItem(command[1])\n      break\n    case /^equip [\\w-]+ \\w+$/.test(message):\n      // equip destination name\n      // ex: equip hand diamond\n      equipItem(command[2], command[1])\n      break\n    case /^unequip \\w+$/.test(message):\n      // unequip testination\n      // ex: unequip hand\n      unequipItem(command[1])\n      break\n    case /^use$/.test(message):\n      useEquippedItem()\n      break\n    case /^craft \\d+ \\w+$/.test(message):\n      // craft amount item\n      // ex: craft 64 stick\n      craftItem(command[2], command[1])\n      break\n  }\n})\n\nfunction sayItems (items = null) {\n  if (!items) {\n    items = bot.inventory.items()\n    if (bot.registry.isNewerOrEqualTo('1.9') && bot.inventory.slots[45]) items.push(bot.inventory.slots[45])\n  }\n  const output = items.map(itemToString).join(', ')\n  if (output) {\n    bot.chat(output)\n  } else {\n    bot.chat('empty')\n  }\n}\n\nasync function tossItem (name, amount) {\n  amount = parseInt(amount, 10)\n  const item = itemByName(name)\n  if (!item) {\n    bot.chat(`I have no ${name}`)\n  } else {\n    try {\n      if (amount) {\n        await bot.toss(item.type, null, amount)\n        bot.chat(`tossed ${amount} x ${name}`)\n      } else {\n        await bot.tossStack(item)\n        bot.chat(`tossed ${name}`)\n      }\n    } catch (err) {\n      bot.chat(`unable to toss: ${err.message}`)\n    }\n  }\n}\n\nasync function equipItem (name, destination) {\n  const item = itemByName(name)\n  if (item) {\n    try {\n      await bot.equip(item, destination)\n      bot.chat(`equipped ${name}`)\n    } catch (err) {\n      bot.chat(`cannot equip ${name}: ${err.message}`)\n    }\n  } else {\n    bot.chat(`I have no ${name}`)\n  }\n}\n\nasync function unequipItem (destination) {\n  try {\n    await bot.unequip(destination)\n    bot.chat('unequipped')\n  } catch (err) {\n    bot.chat(`cannot unequip: ${err.message}`)\n  }\n}\n\nfunction useEquippedItem () {\n  bot.chat('activating item')\n  bot.activateItem()\n}\n\nasync function craftItem (name, amount) {\n  amount = parseInt(amount, 10)\n  const item = bot.registry.itemsByName[name]\n  const craftingTableID = bot.registry.blocksByName.crafting_table.id\n\n  const craftingTable = bot.findBlock({\n    matching: craftingTableID\n  })\n\n  if (item) {\n    const recipe = bot.recipesFor(item.id, null, 1, craftingTable)[0]\n    if (recipe) {\n      bot.chat(`I can make ${name}`)\n      try {\n        await bot.craft(recipe, amount, craftingTable)\n        bot.chat(`did the recipe for ${name} ${amount} times`)\n      } catch (err) {\n        bot.chat(`error making ${name}`)\n      }\n    } else {\n      bot.chat(`I cannot make ${name}`)\n    }\n  } else {\n    bot.chat(`unknown item: ${name}`)\n  }\n}\n\nfunction itemToString (item) {\n  if (item) {\n    return `${item.name} x ${item.count}`\n  } else {\n    return '(nothing)'\n  }\n}\n\nfunction itemByName (name) {\n  const items = bot.inventory.items()\n  if (bot.registry.isNewerOrEqualTo('1.9') && bot.inventory.slots[45]) items.push(bot.inventory.slots[45])\n  return items.filter(item => item.name === name)[0]\n}\n"
  },
  {
    "path": "examples/jumper.js",
    "content": "/*\n * Jumping is fun. Riding pigs is even funnier!\n *\n * Learn how to make your bot interactive with this example.\n *\n * This bot can move, jump, ride vehicles, attack nearby entities and much more.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node jumper.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'jumper',\n  password: process.argv[5]\n})\n\nlet target = null\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  target = bot.players[username].entity\n  let entity\n  switch (message) {\n    case 'forward':\n      bot.setControlState('forward', true)\n      break\n    case 'back':\n      bot.setControlState('back', true)\n      break\n    case 'left':\n      bot.setControlState('left', true)\n      break\n    case 'right':\n      bot.setControlState('right', true)\n      break\n    case 'sprint':\n      bot.setControlState('sprint', true)\n      break\n    case 'stop':\n      bot.clearControlStates()\n      break\n    case 'jump':\n      bot.setControlState('jump', true)\n      bot.setControlState('jump', false)\n      break\n    case 'jump a lot':\n      bot.setControlState('jump', true)\n      break\n    case 'stop jumping':\n      bot.setControlState('jump', false)\n      break\n    case 'attack':\n      entity = bot.nearestEntity()\n      if (entity) {\n        bot.attack(entity, true)\n      } else {\n        bot.chat('no nearby entities')\n      }\n      break\n    case 'mount':\n      entity = bot.nearestEntity((entity) => { return entity.name === 'minecart' })\n      if (entity) {\n        bot.mount(entity)\n      } else {\n        bot.chat('no nearby objects')\n      }\n      break\n    case 'dismount':\n      bot.dismount()\n      break\n    case 'move vehicle forward':\n      bot.moveVehicle(0.0, 1.0)\n      break\n    case 'move vehicle backward':\n      bot.moveVehicle(0.0, -1.0)\n      break\n    case 'move vehicle left':\n      bot.moveVehicle(1.0, 0.0)\n      break\n    case 'move vehicle right':\n      bot.moveVehicle(-1.0, 0.0)\n      break\n    case 'tp':\n      bot.entity.position.y += 10\n      break\n    case 'pos':\n      bot.chat(bot.entity.position.toString())\n      break\n    case 'yp':\n      bot.chat(`Yaw ${bot.entity.yaw}, pitch: ${bot.entity.pitch}`)\n      break\n  }\n})\n\nbot.once('spawn', () => {\n  // keep your eyes on the target, so creepy!\n  setInterval(watchTarget, 50)\n\n  function watchTarget () {\n    if (!target) return\n    bot.lookAt(target.position.offset(0, target.height, 0))\n  }\n})\n\nbot.on('mount', () => {\n  bot.chat(`mounted ${bot.vehicle.displayName}`)\n})\n\nbot.on('dismount', (vehicle) => {\n  bot.chat(`dismounted ${vehicle.displayName}`)\n})\n"
  },
  {
    "path": "examples/looker.js",
    "content": "/*\n * This script will automatically look at the closest entity.\n * It checks for a near entity every tick.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node looker.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'looker',\n  password: process.argv[5]\n})\n\nbot.once('spawn', function () {\n  setInterval(() => {\n    const entity = bot.nearestEntity()\n    if (entity !== null) {\n      if (entity.type === 'player') {\n        bot.lookAt(entity.position.offset(0, 1.6, 0))\n      } else if (entity.type === 'mob') {\n        bot.lookAt(entity.position)\n      }\n    }\n  }, 50)\n})\n"
  },
  {
    "path": "examples/modular_mineflayer/index.js",
    "content": "const fs = require('fs')\nconst path = require('path')\nconst mineflayer = require('mineflayer')\n\nconst OPTIONS = {\n  username: 'i_am_u9g',\n  host: 'localhost'\n}\n\nfunction injectModules (bot) {\n  const MODULES_DIRECTORY = path.join(__dirname, 'modules')\n  const modules = fs\n    .readdirSync(MODULES_DIRECTORY) // find the plugins\n    .filter(x => x.endsWith('.js')) // only use .js files\n    .map(pluginName => require(path.join(MODULES_DIRECTORY, pluginName)))\n\n  bot.loadPlugins(modules)\n}\n\nfunction initBot () {\n  const bot = mineflayer.createBot(OPTIONS)\n  injectModules(bot)\n\n  bot.on('end', initBot) // auto restart\n}\n\ninitBot() // start the bot\n"
  },
  {
    "path": "examples/modular_mineflayer/modules/hello.js",
    "content": "const mineflayer = require('mineflayer') // eslint-disable-line\n\n/**\n * @param {mineflayer.Bot} bot // to enable intellisense\n */\n\nmodule.exports = bot => {\n  bot.addChatPattern('hello', /<(.+)> (?:Hello|hello)/, { parse: true })\n\n  bot.on('chat:hello', ([[playerIgn]]) => {\n    bot.chat(`Hi, ${playerIgn}`)\n  })\n}\n"
  },
  {
    "path": "examples/multiple.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 3 || process.argv.length > 5) {\n  console.log('Usage : node multiple.js <host> <port>')\n  process.exit(1)\n}\n\nlet i = 0\nfunction next () {\n  if (i < 10) {\n    i++\n    setTimeout(() => {\n      createBot(`mineflayer-bot${i}`)\n      next()\n    }, 100)\n  }\n}\nnext()\n\nfunction createBot (name) {\n  mineflayer.createBot({\n    host: process.argv[2],\n    port: parseInt(process.argv[3]),\n    username: name\n  })\n}\n"
  },
  {
    "path": "examples/multiple_from_file.js",
    "content": "/*\n* This example is for people with multiple (mojang) minecraft accounts,\n* in a file in the format \"username:password\" on each line,\n* change the file property of config to set your .txt file location\n*/\n\nconst fs = require('fs')\nconst util = require('util')\nconst mineflayer = require('mineflayer')\nconst readFile = (fileName) => util.promisify(fs.readFile)(fileName, 'utf8')\n\nconst config = {\n  host: 'localhost',\n  port: 25565,\n  file: './accounts.txt',\n  interval: 500 // cooldown between joining server too prevent joining too quickly\n}\n\nfunction makeBot ([_u, _p], ix) {\n  return new Promise((resolve, reject) => {\n    setTimeout(() => {\n      const bot = mineflayer.createBot({\n        username: _u,\n        password: _p,\n        host: config.host,\n        port: config.port\n      })\n      bot.on('spawn', () => resolve(bot))\n      bot.on('error', (err) => reject(err))\n      setTimeout(() => reject(Error('Took too long to spawn.')), 5000) // 5 sec\n    }, config.interval * ix)\n  })\n}\n\nasync function main () {\n  // convert accounts.txt => array\n  const file = await readFile(config.file)\n  const accounts = file.split(/\\r?\\n/).map(login => login.split(':'))\n  const botProms = accounts.map(makeBot)\n  // const bots = await Promise.allSettled(botProms)\n  const bots = (await Promise.allSettled(botProms)).map(({ value, reason }) => value || reason).filter(value => !(value instanceof Error))\n  console.log(`Bots (${bots.length} / ${accounts.length}) successfully logged in.`)\n}\n\nmain()\n"
  },
  {
    "path": "examples/pathfinder/.npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "examples/pathfinder/gps.js",
    "content": "// This is an example that uses mineflayer-pathfinder to showcase how simple it is to walk to goals\n\nconst mineflayer = require('mineflayer')\nconst { pathfinder, Movements, goals: { GoalNear } } = require('mineflayer-pathfinder')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node gps.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'gps',\n  password: process.argv[5]\n})\n\nconst RANGE_GOAL = 1 // get within this radius of the player\n\nbot.loadPlugin(pathfinder)\n\nbot.once('spawn', () => {\n  const defaultMove = new Movements(bot)\n\n  bot.on('chat', (username, message) => {\n    if (username === bot.username) return\n    if (message !== 'come') return\n    const target = bot.players[username]?.entity\n    if (!target) {\n      bot.chat(\"I don't see you !\")\n      return\n    }\n    const { x: playerX, y: playerY, z: playerZ } = target.position\n\n    bot.pathfinder.setMovements(defaultMove)\n    bot.pathfinder.setGoal(new GoalNear(playerX, playerY, playerZ, RANGE_GOAL))\n  })\n})\n"
  },
  {
    "path": "examples/pathfinder/package.json",
    "content": "{\n  \"name\": \"mineflayer-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"mineflayer-pathfinder\": \"^2.4.5\",\n    \"mineflayer\": \"file:../../\"\n  },\n  \"description\": \"A mineflayer example\"\n}\n"
  },
  {
    "path": "examples/perfectShotBow.js",
    "content": "const mineflayer = require('mineflayer')\nconst minecraftHawkEye = require('minecrafthawkeye')\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'Archer',\n  password: process.argv[5]\n})\nbot.loadPlugin(minecraftHawkEye)\n\nbot.on('spawn', function () {\n  bot.chat(`/give ${bot.username} bow{Enchantments:[{id:unbreaking,lvl:100}]} 1`)\n  bot.chat(`/give ${bot.username} crossbow{Enchantments:[{id:quick_charge,lvl:3},{id:unbreaking,lvl:100}]} 1`)\n  bot.chat(`/give ${bot.username} minecraft:arrow 300`)\n  bot.chat('/time set day')\n  bot.chat('/kill @e[type=minecraft:arrow]')\n\n  bot.chat('Ready!')\n\n  // Get target for block position, use whatever you need\n  const target = bot.hawkEye.getPlayer()\n\n  if (!target) {\n    return false\n  }\n\n  // const validWeapons = ['bow', 'crossbow', 'snowball', 'ender_pearl', 'egg', 'splash_potion']\n  const weapon = 'crossbow'\n\n  // Auto attack every 1,2 secs with bow\n  // With crossbow attack when crossbow is charget (enchant 3 = 0.5s)\n  // ['snowball', 'ender_pearl', 'egg', 'splash_potion'] auto attack every 0,1 sec, no recommended use autoAttack for these items, instead use \"bot.hawkEye.oneShot(target, weapon)\"\n\n  bot.hawkEye.autoAttack(target, weapon)\n  // If you force stop attack use:\n  // hawkEye.stop();\n\n  // Use one shot time with calc:\n  // bot.hawkEye.oneShot(target, weapon);\n\n  // If you want to shot in XYZ position:\n  /*\n            const blockPosition = {\n                    position: {\n                        x: 244.5,\n                        y: 75.5,\n                        z: -220\n                    },\n                    isValid: true // Fake to is \"alive\"\n                }\n            // bot.hawkEye.oneShot(blockPosition, weapon);\n            // bot.hawkEye.autoAttack(blockPosition);\n  */\n})\n\nbot.on('die', () => {\n  bot.hawkEye.stop()\n})\n"
  },
  {
    "path": "examples/place_end_crystal/.npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "examples/place_end_crystal/index.js",
    "content": "// This example shows how to tell the bot to place an end crystal\n// Example commands:\n// \"place crystal near bot\" - find a block near the bot that has a block empty above it, then place a crystal on it\n// \"place crystal near ExplodeMe\" - find a block near the player with username \"ExplodeMe\" that has an empty block above it, then place a crystal on it\n\nconst mineflayer = require('mineflayer')\nconst pathfinder = require('mineflayer-pathfinder')\nconst { Vec3 } = require('vec3')\nconst AABB = require('prismarine-physics/lib/aabb')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node ansi.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'crystal_bot',\n  password: process.argv[5],\n  plugins: [pathfinder.pathfinder]\n})\n\nconst MAX_DIST_FROM_BLOCK_TO_PLACE = 4\n\nbot.on('chat', async (ign, msg) => {\n  // solve where the bot will place the crystal near\n  let findBlocksNearPoint = null\n  if (msg === 'place crystal near bot') {\n    findBlocksNearPoint = bot.entity.position\n  } else if (msg.startsWith('place crystal near ')) {\n    const playerUsername = msg.split(' ').pop()\n    const player = bot.players[playerUsername]\n    if (!player) return bot.chat(`Couldn't find player with the username: \"${playerUsername}\"`)\n    findBlocksNearPoint = player.entity.position\n  } else {\n    return // don't do anything\n  }\n\n  // find end crystal(s) in inventory\n  const item = bot.inventory.findInventoryItem(bot.registry.itemsByName.end_crystal.id)\n  if (!item) bot.chat(\"I don't have any ender crystals\")\n\n  // find the crystal\n  const block = bot.findBlock({\n    point: findBlocksNearPoint,\n    matching: ['bedrock', 'obsidian'].map(blockName => bot.registry.blocksByName[blockName].id),\n    useExtraInfo: block => {\n      const hasAirAbove = bot.blockAt(block.position.offset(0, 1, 0)).name === 'air'\n      const botNotStandingOnBlock = block.position.xzDistanceTo(bot.entity.position) > 2\n      // do no intersecting entity check\n      const { x: aboveX, y: aboveY, z: aboveZ } = block.position.offset(0, 1, 0)\n      const blockBoundingBox = new AABB(aboveX, aboveY, aboveZ, aboveX + 1, aboveY + 2, aboveZ + 1)\n      const entityAABBs = Object.values(bot.entities).map(entity => {\n        // taken from https://github.com/PrismarineJS/prismarine-physics/blob/d145e54a4bb8604300258badd7563f59f2101922/index.js#L92\n        const w = entity.height / 2\n        const { x, y, z } = entity.position\n        return new AABB(-w, 0, -w, w, entity.height, w).offset(x, y, z)\n      })\n      const hasIntersectingEntities = entityAABBs.filter(aabb => aabb.intersects(blockBoundingBox)).length === 0\n      return hasAirAbove && botNotStandingOnBlock && !hasIntersectingEntities\n    }\n  })\n  if (!block) return bot.chat(\"Couldn't find bedrock or obsidian block that has air above it near myself.\")\n\n  // get to the crystal\n  if (block.position.xzDistanceTo(bot.entity.position) > MAX_DIST_FROM_BLOCK_TO_PLACE) await bot.pathfinder.goto(new pathfinder.goals.GoalNear(block.position.x, block.position.y, block.position.z, MAX_DIST_FROM_BLOCK_TO_PLACE))\n  // get ready to place crystal\n  await bot.equip(item, 'hand')\n  await bot.lookAt(block.position, true)\n  // place crystal\n  await bot.placeEntity(block, new Vec3(0, 1, 0))\n  bot.chat('I placed an end crystal!')\n})\n"
  },
  {
    "path": "examples/place_end_crystal/package.json",
    "content": "{\n  \"name\": \"mineflayer-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"mineflayer-pathfinder\": \"^1.7.0\"\n  },\n  \"description\": \"A mineflayer example\"\n}\n"
  },
  {
    "path": "examples/place_entity.js",
    "content": "const mineflayer = require('mineflayer')\nconst { Vec3 } = require('vec3')\nconst bot = mineflayer.createBot()\n\nbot.on('chat', async (_, msg) => {\n  if (msg === 'go_endcrystal') {\n    const crystal = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, 1)), new Vec3(0, 1, 0))\n    console.log(crystal)\n  } else if (msg === 'go_boat') {\n    const boat = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, -2, -2)), new Vec3(0, 1, 0))\n    console.log(boat)\n  } else if (msg === 'go_spawnegg') {\n    const mob = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, -2)), new Vec3(0, 1, 0))\n    console.log(mob)\n  } else if (msg === 'go_armorstand') {\n    const armorstand = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, -2)), new Vec3(0, 1, 0))\n    console.log(armorstand)\n  }\n})\n"
  },
  {
    "path": "examples/plugins/afk.js",
    "content": "/*\r\n  Make a function that is exported, this will be the \"inject function\", which is called when loading the plugin into mineflayer.\r\n  You can load this plugin into mineflayer in three ways:\r\n\r\n  1.\r\n  ```\r\n  bot.createBot({\r\n    plugins: [require('./plugin')]\r\n  })\r\n  ```\r\n\r\n  2.\r\n  ```\r\n  bot.createBot({\r\n    plugins: {\r\n      afk: require('./plugin')\r\n    }\r\n  })\r\n  ```\r\n\r\n  3.\r\n  ```\r\n  const bot = bot.createBot()\r\n  bot.loadPlugin(require('./plugin'))\r\n  ```\r\n*/\r\nmodule.exports = bot => {\r\n  /*\r\n    Inside the scope of this function, you should do anything you need to with the bot object, like add properties to it, like `bot.afk`,\r\n    this function will be called when this plugin is called during the login process\r\n  */\r\n  let rotater\r\n  let rotated = false\r\n  bot.afk = {}\r\n\r\n  bot.afk.start = () => {\r\n    if (rotater) return\r\n    rotater = setInterval(rotate, 3000)\r\n  }\r\n\r\n  bot.afk.stop = () => {\r\n    if (!rotater) return\r\n    clearInterval(rotater)\r\n  }\r\n\r\n  function rotate () {\r\n    bot.look(rotated ? 0 : Math.PI, 0)\r\n    rotated = !rotated\r\n  }\r\n}\r\n"
  },
  {
    "path": "examples/plugins/hello_world.js",
    "content": "module.exports = (bot, { version }) => {\n  bot.once('spawn', () => console.log('hello world!'))\n}\n"
  },
  {
    "path": "examples/python/README.md",
    "content": "# Using mineflayer in Python\n\n* Checkout the tutorial on Google Colab 👉 [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/PrismarineJS/mineflayer/blob/master/docs/mineflayer.ipynb)\n\nThanks to [JSPyBridge](https://github.com/extremeheat/JSPyBridge), it is possible to use mineflayer in python!\n\n\n### Install\n\nMake sure you have Python 3.8 or newer installed and also Node.js 14 or newer. You can get them from https://www.python.org/downloads/ and https://nodejs.org/.\n\nYou can access mineflayer in Python in addition to any other JavaScript package by first installing the javascript pip package:\n\n```sh\npip install javascript\n```\n\n\nOnce you have the package installed, you can put this at the top of your Python:\n\n```py\nfrom javascript import require\nmineflayer = require('mineflayer')\n```\n\n... and you're good to go, with full API access. You interact with the API very similarly to JavaScript. \n\n### Examples\n\n* [gps](https://github.com/PrismarineJS/mineflayer/blob/master/examples/python/basic.py) (based on [js version](https://github.com/PrismarineJS/mineflayer/blob/master/examples/pathfinder/gps.js))\n* [chatterbot](https://github.com/PrismarineJS/mineflayer/blob/master/examples/python/chatterbox.py)  (based on [js version](https://github.com/PrismarineJS/mineflayer/blob/py/examples/chatterbox.js))\n\n### See also\n* [javascript pip package docs](https://github.com/extremeheat/JSPyBridge/blob/master/docs/python.md)\n"
  },
  {
    "path": "examples/python/basic.py",
    "content": "from javascript import require, On\nmineflayer = require('mineflayer')\npathfinder = require('mineflayer-pathfinder')\n\nRANGE_GOAL = 1\nBOT_USERNAME = 'python'\n\nbot = mineflayer.createBot({\n  'host': '127.0.0.1',\n  'port': 25565,\n  'username': BOT_USERNAME\n})\n\nbot.loadPlugin(pathfinder.pathfinder)\nprint(\"Started mineflayer\")\n\n@On(bot, 'spawn')\ndef handle(*args):\n  print(\"I spawned 👋\")\n  movements = pathfinder.Movements(bot)\n\n  @On(bot, 'chat')\n  def handleMsg(this, sender, message, *args):\n    print(\"Got message\", sender, message)\n    if sender and (sender != BOT_USERNAME):\n      bot.chat('Hi, you said ' + message)\n      if 'come' in message:\n        player = bot.players[sender]\n        print(\"Target\", player)\n        target = player.entity\n        if not target:\n          bot.chat(\"I don't see you !\")\n          return\n\n        pos = target.position\n        bot.pathfinder.setMovements(movements)\n        bot.pathfinder.setGoal(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z, RANGE_GOAL))\n\n@On(bot, \"end\")\ndef handle(*args):\n  print(\"Bot ended!\", args)\n"
  },
  {
    "path": "examples/python/chatterbox.py",
    "content": "# ==========================================================================\n# This example demonstrates how easy it is to create a bot\n# that sends chat messages whenever something interesting happens\n# on the server you are connected to.\n#\n# Below you can find a wide range of different events you can watch\n# but remember to check out the API documentation to find even more!\n#\n# Some events may be commented out because they are very frequent and\n# may flood the chat, feel free to check them out for other purposes though.\n#\n# This bot also replies to some specific chat messages so you can ask him\n# a few information while you are in game.\n# ===========================================================================\nimport sys, re\nfrom javascript import require, On, Once, console\n\nmineflayer = require(\"mineflayer\", \"latest\")\nVec3 = require(\"vec3\").Vec3\n\nprint(sys.argv)\nif len(sys.argv) < 3 or len(sys.argv) > 6:\n    print(\"Usage : node chatterbot.js <host> <port> [<name>]\")\n    exit(1)\n\nhost = sys.argv[1]\nport = sys.argv[2]\nusername = sys.argv[3] if len(sys.argv) > 3 else \"boat\"\n\nbot = mineflayer.createBot({\n    \"host\": host,\n    \"port\": port,\n    \"username\": username\n})\n\nItem = require(\"prismarine-item\")(bot.registry)\n\n\n@On(bot, \"chat\")\ndef handle(this, username, message, *args):\n    if username == bot.username:\n        return\n\n    if message.startswith(\"can see\"):\n        # Extract x, y and z\n        # e.g. \"can see 327 60 -120\" or \"can see 327, -23, -120\"\n        try:\n            x, y, z = map(lambda v: int(v), message.split(\"see\")[1].replace(\",\", \" \").split())\n        except Exception:\n            bot.chat(\"Bad syntax\")\n    elif message.startswith(\"pos\"):\n        say_position(username)\n    elif message.startswith(\"wearing\"):\n        say_equipment(username)\n    elif message.startswith(\"block\"):\n        say_block_under()\n    elif message.startswith(\"spawn\"):\n        say_spawn()\n    elif message.startswith(\"quit\"):\n        quit_game(username)\n    else:\n        bot.chat(\"That's nice\")\n\n\ndef can_see(pos):\n    block = bot.blockAt(pos)\n    canSee = bot.canSeeBlock(block)\n\n    if canSee:\n        bot.chat(f\"I can see the block of {block.displayName} at {pos}\")\n    else:\n        bot.chat(f\"I can't see the block of {block.displayName} at {pos}\")\n\n\ndef say_position(username):\n    p = bot.entity.position\n    bot.chat(f\"I am at {p.toString()}\")\n    if username in bot.players:\n        p = bot.players[username].entity.position\n        bot.chat(f\"You are at {p.toString()}\")\n\n\ndef say_equipment(username):\n    eq = bot.players[username].entity.equipment\n    eqText = []\n    if eq[0]:\n        eqText.append(f\"holding a {eq[0].displayName}\")\n    if eq[1]:\n        eqText.append(f\"wearing a {eq[1].displayName} on your feet\")\n    if eq[2]:\n        eqText.append(f\"wearing a {eq[2].displayName} on your legs\")\n    if eq[3]:\n        eqText.append(f\"wearing a {eq[3].displayName} on your torso\")\n    if eq[4]:\n        eqText.append(f\"wearing a {eq[4].displayName} on your head\")\n    if len(eqText):\n        bot.chat(f\"You are {', '.join(eqText)}.\")\n    else:\n        bot.chat(\"You are naked!\")\n\n\ndef say_spawn():\n    bot.chat(f\"Spawn is at {bot.spawnPoint.toString()}\")\n\n\ndef say_block_under():\n    block = bot.blockAt(bot.players[username].entity.position.offset(0, -1, 0))\n    bot.chat(f\"Block under you is {block.displayName} in the {block.biome.name} biome\")\n    print(block)\n\n\ndef quit_game(username):\n    bot.quit(f\"{username} told me to\")\n\n\ndef say_nick():\n    bot.chat(f\"My name is {bot.player.displayName}\")\n\n\n@On(bot, \"whisper\")\ndef whisper(this, username, message, rawMessage, *a):\n    console.log(f\"I received a message from {username}: {message}\")\n    bot.whisper(username, \"I can tell secrets too.\")\n\n\n@On(bot, \"nonSpokenChat\")\ndef nonSpokenChat(this, message):\n    console.log(f\"Non spoken chat: {message}\")\n\n\n@On(bot, \"login\")\ndef login(this):\n    bot.chat(\"Hi everyone!\")\n\n\n@On(bot, \"spawn\")\ndef spawn(this):\n    bot.chat(\"I spawned, watch out!\")\n\n\n@On(bot, \"spawnReset\")\ndef spawnReset(this, message):\n    bot.chat(\"Oh noez! My bed is broken.\")\n\n\n@On(bot, \"forcedMove\")\ndef forcedMove(this):\n    p = bot.entity.position\n    bot.chat(f\"I have been forced to move to {p.toString()}\")\n\n\n@On(bot, \"health\")\ndef health(this):\n    bot.chat(f\"I have {bot.health} health and {bot.food} food\")\n\n\n@On(bot, \"death\")\ndef death(this):\n    bot.chat(\"I died x.x\")\n\n\n@On(bot, \"kicked\")\ndef kicked(this, reason, *a):\n    print(\"I was kicked\", reason, a)\n    console.log(f\"I got kicked for {reason}\")\n\n\n@On(bot, \"time\")\ndef time(this):\n    bot.chat(f\"Current time: \" + str(bot.time.timeOfDay))\n\n\n@On(bot, \"rain\")\ndef rain(this):\n    if bot.isRaining:\n        bot.chat(\"It started raining\")\n    else:\n        bot.chat(\"It stopped raining\")\n\n\n@On(bot, \"noteHeard\")\ndef noteHeard(this, block, instrument, pitch):\n    bot.chat(f\"Music for my ears! I just heard a {instrument.name}\")\n\n\n@On(bot, \"chestLidMove\")\ndef chestLidMove(this, block, isOpen, *a):\n    action = \"open\" if isOpen else \"close\"\n    bot.chat(f\"Hey, did someone just {action} a chest?\")\n\n\n@On(bot, \"pistonMove\")\ndef pistonMove(this, block, isPulling, direction):\n    action = \"pulling\" if isPulling else \"pushing\"\n    bot.chat(f\"A piston is {action} near me, i can hear it.\")\n\n\n@On(bot, \"playerJoined\")\ndef playerJoined(this, player):\n    print(\"joined\", player)\n    if player[\"username\"] != bot.username:\n        bot.chat(f\"Hello, {player['username']}! Welcome to the server.\")\n\n\n@On(bot, \"playerLeft\")\ndef playerLeft(this, player):\n    if player[\"username\"] == bot.username:\n        return\n    bot.chat(f\"Bye ${player.username}\")\n\n\n@On(bot, \"playerCollect\")\ndef playerCollect(this, collector, collected):\n    if collector.type == \"player\" and collected.type == \"object\":\n        raw_item = collected.metadata[10]\n        item = Item.fromNotch(raw_item)\n        header = (\"I'm so jealous. \" + collector.username) if (\n            collector.username != bot.username) else \"I \"\n        bot.chat(f\"{header} collected {item.count} {item.displayName}\")\n\n\n@On(bot, \"entitySpawn\")\ndef entitySpawn(this, entity):\n    if entity.type == \"mob\":\n        p = entity.position\n        console.log(f\"Look out! A {entity.displayName} spawned at {p.toString()}\")\n    elif entity.type == \"player\":\n        bot.chat(f\"Look who decided to show up: {entity.username}\")\n    elif entity.type == \"object\":\n        p = entity.position\n        console.log(f\"There's a {entity.displayName} at {p.toString()}\")\n    elif entity.type == \"global\":\n        bot.chat(\"Ooh lightning!\")\n    elif entity.type == \"orb\":\n        bot.chat(\"Gimme dat exp orb!\")\n\n\n@On(bot, \"entityHurt\")\ndef entityHurt(this, entity):\n    if entity.type == \"mob\":\n        bot.chat(f\"Haha! The ${entity.displayName} got hurt!\")\n    elif entity.type == \"player\":\n        if entity.username in bot.players:\n            ping = bot.players[entity.username].ping\n            bot.chat(f\"Aww, poor {entity.username} got hurt. Maybe you shouldn't have a ping of {ping}\")\n\n\n@On(bot, \"entitySwingArm\")\ndef entitySwingArm(this, entity):\n    bot.chat(f\"{entity.username}, I see that your arm is working fine.\")\n\n\n@On(bot, \"entityCrouch\")\ndef entityCrouch(this, entity):\n    bot.chat(f\"${entity.username}: you so sneaky.\")\n\n\n@On(bot, \"entityUncrouch\")\ndef entityUncrouch(this, entity):\n    bot.chat(f\"{entity.username}: welcome back from the land of hunchbacks.\")\n\n\n@On(bot, \"entitySleep\")\ndef entitySleep(this, entity):\n    bot.chat(f\"Good night, {entity.username}\")\n\n\n@On(bot, \"entityWake\")\ndef entityWake(this, entity):\n    bot.chat(f\"Top of the morning, {entity.username}\")\n\n\n@On(bot, \"entityEat\")\ndef entityEat(this, entity):\n    bot.chat(f\"{entity.username}: OM NOM NOM NOMONOM. That's what you sound like.\")\n\n\n@On(bot, \"entityAttach\")\ndef entityAttach(this, entity, vehicle):\n    if entity.type == \"player\" and vehicle.type == \"object\":\n        print(f\"Sweet, {entity.username} is riding that {vehicle.displayName}\")\n\n\n@On(bot, \"entityDetach\")\ndef entityDetach(this, entity, vehicle):\n    if entity.type == \"player\" and vehicle.type == \"object\":\n        print(f\"Lame, {entity.username} stopped riding the {vehicle.displayName}\")\n\n\n@On(bot, \"entityEquipmentChange\")\ndef entityEquipmentChange(this, entity):\n    print(\"entityEquipmentChange\", entity)\n\n\n@On(bot, \"entityEffect\")\ndef entityEffect(this, entity, effect):\n    print(\"entityEffect\", entity, effect)\n\n\n@On(bot, \"entityEffectEnd\")\ndef entityEffectEnd(this, entity, effect):\n    print(\"entityEffectEnd\", entity, effect)\n"
  },
  {
    "path": "examples/quitter.js",
    "content": "/*\n * This is one of the simplest examples.\n *\n * We created a simple bot that connects to a server and immediately quits.\n *\n * It's not very useful yet, but you can use this as a starting point\n * to create your own bot.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node quitter.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'emobot',\n  password: process.argv[5]\n})\n\nbot.once('spawn', () => {\n  bot.chat('Goodbye, cruel world!')\n  bot.quit()\n})\n"
  },
  {
    "path": "examples/raycast.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node raycast.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'raycast',\n  password: process.argv[5]\n})\n\nbot.on('message', (cm) => {\n  if (cm.toString().includes('block')) {\n    block()\n  }\n})\n\nfunction block () {\n  const block = bot.blockAtCursor()\n\n  if (!block) {\n    return bot.chat('Looking at Air')\n  }\n\n  bot.chat(`Looking at ${block.displayName}`)\n}\n"
  },
  {
    "path": "examples/reconnector.js",
    "content": "/*\n * This example will automatically reconnect when it gets disconnected from the server.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node reconnector.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nfunction createBot () {\n  const bot = mineflayer.createBot({\n    host: process.argv[2],\n    port: parseInt(process.argv[3]),\n    username: process.argv[4] ? process.argv[4] : 'reconnector',\n    password: process.argv[5]\n  })\n\n  bot.on('error', (err) => console.log(err))\n  bot.on('end', createBot)\n}\n\ncreateBot()\n"
  },
  {
    "path": "examples/repl.js",
    "content": "const mineflayer = require('mineflayer')\nconst repl = require('repl')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node repl.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'repl',\n  password: process.argv[5]\n})\n\nbot.on('login', () => {\n  const r = repl.start('> ')\n  r.context.bot = bot\n\n  r.on('exit', () => {\n    bot.end()\n  })\n})\n"
  },
  {
    "path": "examples/resourcepack.js",
    "content": "/*\n *\n * A simple bot that accepts a resource pack sent by a server\n *\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node resourcepack.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'packbot',\n  password: process.argv[5]\n})\n\nbot.once('resourcePack', () => { // resource pack sent by server\n  bot.acceptResourcePack()\n})\n"
  },
  {
    "path": "examples/scoreboard.js",
    "content": "/*\n * A simple example to show the display board functionality\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node scoreboard.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'scoreboard',\n  password: process.argv[5]\n})\n\n// /scoreboard objectives add Kills totalKillCount\n// /scoreboard objectives setDisplay sidebar Kills\nbot.on('scoreboardCreated', (scoreboard) => {\n  bot.chat(`New scoreboard: ${scoreboard.name}, ${scoreboard.title}`)\n  console.log(scoreboard)\n})\n\n// kill a mob for this to be displayed\nbot.on('scoreboardScoreUpdated', (scoreboard, updated) => {\n  bot.chat(`Scoreboard score : ${scoreboard.title}, ${updated.name}, ${updated.value}`)\n  console.log(scoreboard)\n})\n"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/.dockerignore",
    "content": "screenshots\nnode_modules"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/.npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/Dockerfile",
    "content": "FROM node:14\n\nRUN apt-get update -y\nRUN apt-get install -y xserver-xorg-dev libxi-dev xserver-xorg-dev libxext-dev xvfb\n\nWORKDIR /usr/src/app\n\nCOPY package.json ./\n\nRUN npm install\n\nCOPY screenshot.js ./\n\nRUN mkdir screenshots\n\n# Start the container with the BrowserCubeMap example script\nCMD xvfb-run --auto-servernum --server-num=1 --server-args='-ac -screen 0 1280x1024x24' node screenshot.js $HOST $PORT $USERNAME $PASSWORD\n"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/README.md",
    "content": "### node-canvas-webgl example\n\n#### screenshot.js\nGenerates Screenshots of the bot world\n\n### Starting\n\nLinux:\n\n`\nxvfb-run -s \"-ac -screen 0 1280x1024x24\" node <your script> [...args]\n`\n\nMac High Sierra:\n\n`node <your script> [...args]`\n\n### Installation:\nInstallation on a none unix based systems is none trivial. \nI suggest you install it on something like Ubuntu. Or a Virtual Machine running Ubuntu.\nMac OS X may work too, but I have only tested it on 10.13 High Sierra.\n\nDo `npm install` to install all required node packages.\n\n#### Troubleshooting (Linux):\nIf npm fails while installing try installing the following and try again:\n```bash\nsudo apt-get update -y\nsudo apt-get install -y xserver-xorg-dev libxi-dev xserver-xorg-dev libxext-dev xvfb\n```\n\n### Docker\nIf you want to run the screenshot example on windows without a vm you can install it in a Docker Container.\n\nBuilding the Docker image:\n```bash\ncd screenshot-with-node-canvas\ndocker build . -t screenshot-bot\n```\n\nRunning the image and saving the screenshot to the current directory:\n```bash\ndocker run -v $(pwd):/usr/src/app/screenshots -e HOST='<server ip address>' -e PORT=<port> screenshot-bot\n```\n`-e USERNAME=User1` and `-e PASSWORD=<Your password>` can be added if the server is not running in offline mode.\n\n\n"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/package.json",
    "content": "{\n  \"name\": \"mineflayer-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"prismarine-viewer\": \"^1.19.2\",\n    \"node-canvas-webgl\": \"^0.2.6\",\n    \"three\": \"^0.126.1\",\n    \"mineflayer\": \"^3.6.0\"\n  },\n  \"description\": \"A mineflayer example\"\n}\n"
  },
  {
    "path": "examples/screenshot-with-node-canvas-webgl/screenshot.js",
    "content": "/*\n *\n * A simple a simple Screenshot demo for https://github.com/PrismarineJS/prismarine-viewer\n *\n */\n\nconst mineflayer = require('mineflayer')\nconst { Viewer, WorldView, getBufferFromStream } = require('prismarine-viewer').viewer\nglobal.Worker = require('worker_threads').Worker\n\nconst THREE = require('three')\nconst { createCanvas } = require('node-canvas-webgl/lib')\nconst fs = require('fs').promises\nconst { Vec3 } = require('vec3')\nconst { EventEmitter } = require('events')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node screenshot.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'screenshot',\n  password: process.argv[5]\n})\n\nbot.on('spawn', async () => {\n  await bot.waitForChunksToLoad()\n  const camera = new Camera(bot)\n  camera.on('ready', async () => {\n    await camera.takePicture(new Vec3(1, -0.2, 0), 'screenshot1')\n  })\n})\n\nbot.on('error', (err) => {\n  console.error(err)\n})\n\nclass Camera extends EventEmitter {\n  constructor (bot) {\n    super()\n    this.bot = bot\n    this.viewDistance = 4\n    this.width = 512\n    this.height = 512\n    this.canvas = createCanvas(this.width, this.height)\n    this.renderer = new THREE.WebGLRenderer({ canvas: this.canvas })\n    this.viewer = new Viewer(this.renderer)\n    this._init().then(() => {\n      this.emit('ready')\n    })\n  }\n\n  async _init () {\n    const botPos = this.bot.entity.position\n    const center = new Vec3(botPos.x, botPos.y + 10, botPos.z)\n    this.viewer.setVersion(this.bot.version)\n\n    // Load world\n    const worldView = new WorldView(this.bot.world, this.viewDistance, center)\n    this.viewer.listen(worldView)\n\n    this.viewer.camera.position.set(center.x, center.y, center.z)\n\n    await worldView.init(center)\n  }\n\n  async takePicture (direction, name) {\n    const cameraPos = new Vec3(this.viewer.camera.position.x, this.viewer.camera.position.y, this.viewer.camera.position.z)\n    const point = cameraPos.add(direction)\n    this.viewer.camera.lookAt(point.x, point.y, point.z)\n    console.info('Waiting for world to load')\n    await new Promise(resolve => setTimeout(resolve, 5000))\n    this.renderer.render(this.viewer.scene, this.viewer.camera)\n\n    const imageStream = this.canvas.createJPEGStream({\n      bufsize: 4096,\n      quality: 100,\n      progressive: false\n    })\n    const buf = await getBufferFromStream(imageStream)\n    let stats\n    try {\n      stats = await fs.stat('./screenshots')\n    } catch (e) {\n      if (!stats?.isDirectory()) {\n        await fs.mkdir('./screenshots')\n      }\n    }\n    await fs.writeFile(`screenshots/${name}.jpg`, buf)\n    console.log('saved', name)\n  }\n}\n"
  },
  {
    "path": "examples/session.js",
    "content": "// This example describes how to login using a launcher_profiles folder instead of a usual minecraft username & password\n\nconst mineflayer = require('mineflayer')\nconst path = require('path')\n\nif (process.argv.length !== 5) {\n  console.log('Usage : node session.js <host> <port> <pathToLauncherProfiles>')\n  process.exit(1)\n}\n\nconst profile = require(path.resolve(process.argv[4], 'launcher_profiles.json'))\nconst auth = profile.authenticationDatabase[profile.selectedUser.account]\nconst profileID = profile.selectedUser.profile\n\nconst session = {\n  accessToken: auth.accessToken,\n  clientToken: profile.clientToken,\n  selectedProfile: {\n    id: profileID,\n    name: auth.profiles[profileID].displayName\n  }\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  session\n})\n\nbot.once('login', () => {\n  console.log('logged in')\n  bot.quit()\n})\n"
  },
  {
    "path": "examples/skin_blinker.js",
    "content": "/*\n * Since 1.8 the players skin can have a second layer over their whole skin.\n *\n * This example will toggle that layer every half second, making your skin 'blick'\n * (If your bots skin has a second layer)\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node skin_blinker.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'skin_blinker',\n  password: process.argv[5]\n})\n\nlet show = true\n\nfunction toggleSkin () {\n  show = !show\n  bot.setSettings({\n    skinParts: {\n      showJacket: show,\n      showHat: show,\n      showRightPants: show,\n      showLeftPants: show,\n      showLeftSleeve: show,\n      showRightSleeve: show\n    }\n  })\n}\n\nbot.on('spawn', () => {\n  setInterval(toggleSkin, 500)\n})\n"
  },
  {
    "path": "examples/skin_data.js",
    "content": "/*\n * This script will automatically set if a totem is in the inventory or the off-hand.\n * It checks for a totem every tick.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node skin_data.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'skin_data',\n  password: process.argv[5]\n})\n\nsetTimeout(() => {\n  bot.quit()\n  console.log('Skin data:')\n  console.log(Object.entries(bot.players).map(([name, player]) => ({\n    name,\n    skinData: player.skinData\n  })))\n}, 10000)\n"
  },
  {
    "path": "examples/sleeper.js",
    "content": "/*\n * Even bots need to rest sometimes.\n *\n * That's why we created an example that demonstrates how easy it is\n * to find and use a bed properly.\n *\n * You can ask the bot to sleep or wake up by sending a chat message.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node sleeper.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'sleeper',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  switch (message) {\n    case 'sleep':\n      goToSleep()\n      break\n    case 'wakeup':\n      wakeUp()\n      break\n  }\n})\n\nbot.on('sleep', () => {\n  bot.chat('Good night!')\n})\nbot.on('wake', () => {\n  bot.chat('Good morning!')\n})\n\nasync function goToSleep () {\n  const bed = bot.findBlock({\n    matching: block => bot.isABed(block)\n  })\n  if (bed) {\n    try {\n      await bot.sleep(bed)\n      bot.chat(\"I'm sleeping\")\n    } catch (err) {\n      bot.chat(`I can't sleep: ${err.message}`)\n    }\n  } else {\n    bot.chat('No nearby bed')\n  }\n}\n\nasync function wakeUp () {\n  try {\n    await bot.wake()\n  } catch (err) {\n    bot.chat(`I can't wake up: ${err.message}`)\n  }\n}\n"
  },
  {
    "path": "examples/sound.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node sound.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'sound_bot',\n  password: process.argv[5]\n})\n\n// Listen for any sound effect\nbot.on('soundEffectHeard', (soundName, position, volume, pitch) => {\n  const { x, y, z } = position\n  console.log(`Heard sound: ${soundName} at ${x}, ${y}, ${z}`)\n})\n\n// Listen for note block sounds\nbot.on('noteHeard', (block, instrument, pitch) => {\n  console.log(`Heard note block: ${instrument.name} at pitch ${pitch}`)\n})\n\n// Listen for hardcoded sound effects (like mob sounds)\nbot.on('hardcodedSoundEffectHeard', (soundId, soundCategory, position, volume, pitch) => {\n  const { x, y, z } = position\n  console.log(`Heard hardcoded sound: ${soundId} (${soundCategory}) at ${x}, ${y}, ${z}`)\n})\n\nbot.on('spawn', () => {\n  console.log('Bot spawned!')\n})\n"
  },
  {
    "path": "examples/tab_complete.js",
    "content": "const mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node tab_complete.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'tabComplete',\n  password: process.argv[5]\n})\n\nbot.on('message', (cm) => {\n  if (cm.toString().includes('complete')) {\n    const message = cm.toString()\n    const str = cm.toString().slice(message.indexOf('complete') + 9)\n    complete(str)\n  }\n})\n\nasync function complete (str) {\n  try {\n    const matches = await bot.tabComplete(str)\n    console.log(str, matches)\n    bot.chat(`Matches for \"${str}\": ${matches.join(', ')}`)\n  } catch (err) {\n    bot.chat(err.message)\n  }\n}\n"
  },
  {
    "path": "examples/telegram.js",
    "content": "/*\n* This example is a very simple way of connecting to a telegram group\n* For this example you'll need Telegraf installed. This can be done with `npm install telegraf`\n* You need to do this before running this example:\n* - You need to get a telegram bot token from @botfather\n* - You need to get the id of the group you want to use\n*/\n\nif (process.argv.length < 6 || process.argv.length > 8) {\n  console.log('Usage : node telegram.js <telegram bot token> <group id> <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\n// Load Telegraf\nconst { Telegraf } = require('telegraf')\nconst telegram = new Telegraf(process.argv[2])\n\n// Load mineflayer\nconst mineflayer = require('mineflayer')\nconst bot = mineflayer.createBot({\n  host: process.argv[4],\n  port: parseInt(process.argv[5]),\n  username: process.argv[6] || 'telegram',\n  password: process.argv[7]\n})\n\ntelegram.on('text', async (ctx) => {\n  // check if message was reveived from chosen group\n  if (ctx.update.message.chat.id.toString() === process.argv[3]) {\n    // send message to mc server\n    bot.chat(`${ctx.update.message.from.first_name} ${ctx.update.message.from.last_name}: ${ctx.update.message.text}`)\n  }\n})\n\n// Redirect in-game messages to telegram group\nbot.on('chat', (username, message) => {\n  // Ignore messages from the bot itself\n  if (username === bot.username) return\n  telegram.telegram.sendMessage(process.argv[3], username + ': ' + message)\n})\n\n// Login telegram bot\ntelegram.launch()\n"
  },
  {
    "path": "examples/titles.js",
    "content": "/*\n * An example of how to handle title events from the server.\n * Demonstrates title, subtitle, timing, and clearing functionality.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node titles.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'titles',\n  password: process.argv[5]\n})\n\n// This event is triggered when the server sends a title or subtitle\nbot.on('title', (text, type) => {\n  // type is either \"title\" or \"subtitle\"\n  console.log(`Received ${type}: ${text}`)\n})\n\n// This event is triggered when the server sets title display times\nbot.on('title_times', (fadeIn, stay, fadeOut) => {\n  console.log(`Title timing: fadeIn=${fadeIn}ms, stay=${stay}ms, fadeOut=${fadeOut}ms`)\n})\n\n// This event is triggered when the server clears all titles\nbot.on('title_clear', () => {\n  console.log('All titles cleared')\n})\n\nbot.on('spawn', () => {\n  console.log('Bot spawned! Try these commands:')\n  console.log('/title @a title {\"text\":\"Hello World\"}')\n  console.log('/title @a subtitle {\"text\":\"Welcome!\"}')\n  console.log('/title @a times 10 20 30')\n  console.log('/title @a clear')\n})\n"
  },
  {
    "path": "examples/trader.js",
    "content": "/*\n * Even bots want to trade sometimes.\n *\n * That's why we created an example that demonstrates how easy it is\n * to find a villager and trade.\n *\n * You can ask the bot to trade with a villager, display the villagers in range\n * and show what trades a villager has by sending a chat message.\n */\nconst mineflayer = require('mineflayer')\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node trader.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\nconsole.log('Commands :\\n' +\n  '  show villagers\\n' +\n  '  show inventory\\n' +\n  '  show trades <id>\\n' +\n  '  trade <id> <trade> [<times>]')\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'trader',\n  password: process.argv[5]\n})\n\nbot.on('chat', (username, message) => {\n  if (username === bot.username) return\n  const command = message.split(' ')\n  switch (true) {\n    case message === 'show villagers':\n      showVillagers()\n      break\n    case message === 'show inventory':\n      showInventory()\n      break\n    case /^show trades [0-9]+$/.test(message):\n      showTrades(command[2])\n      break\n    case /^trade [0-9]+ [0-9]+( [0-9]+)?$/.test(message):\n      trade(command[1], command[2], command[3])\n      break\n  }\n})\n\nfunction showVillagers () {\n  const villagers = Object.keys(bot.entities).map(id => bot.entities[id]).filter(e => e.entityType === bot.registry.entitiesByName.villager.id)\n  const closeVillagersId = villagers.filter(e => bot.entity.position.distanceTo(e.position) < 3).map(e => e.id)\n  bot.chat(`found ${villagers.length} villagers`)\n  bot.chat(`villager(s) you can trade with: ${closeVillagersId.join(', ')}`)\n}\n\nfunction showInventory () {\n  bot.inventory.slots\n    .filter(item => item).forEach((item) => {\n      bot.chat(stringifyItem(item))\n    })\n}\n\nasync function showTrades (id) {\n  const e = bot.entities[id]\n  switch (true) {\n    case !e:\n      bot.chat(`cant find entity with id ${id}`)\n      break\n    case e.entityType !== bot.registry.entitiesByName.villager.id:\n      bot.chat('entity is not a villager')\n      break\n    case bot.entity.position.distanceTo(e.position) > 3:\n      bot.chat('villager out of reach')\n      break\n    default: {\n      const villager = await bot.openVillager(e)\n      villager.close()\n      stringifyTrades(villager.trades).forEach((trade, i) => {\n        bot.chat(`${i + 1}: ${trade}`)\n      })\n    }\n  }\n}\n\nasync function trade (id, index, count) {\n  const e = bot.entities[id]\n  switch (true) {\n    case !e:\n      bot.chat(`cant find entity with id ${id}`)\n      break\n    case e.entityType !== bot.registry.entitiesByName.villager.id:\n      bot.chat('entity is not a villager')\n      break\n    case bot.entity.position.distanceTo(e.position) > 3:\n      bot.chat('villager out of reach')\n      break\n    default: {\n      const villager = await bot.openVillager(e)\n      const trade = villager.trades[index - 1]\n      count = count || trade.maximumNbTradeUses - trade.nbTradeUses\n      switch (true) {\n        case !trade:\n          villager.close()\n          bot.chat('trade not found')\n          break\n        case trade.disabled:\n          villager.close()\n          bot.chat('trade is disabled')\n          break\n        case trade.maximumNbTradeUses - trade.nbTradeUses < count:\n          villager.close()\n          bot.chat('cant trade that often')\n          break\n        case !hasResources(villager.slots, trade, count):\n          villager.close()\n          bot.chat('dont have the resources to do that trade')\n          break\n        default:\n          bot.chat('starting to trade')\n          try {\n            await bot.trade(villager, index - 1, count)\n            bot.chat(`traded ${count} times`)\n          } catch (err) {\n            bot.chat('an error occurred while trying to trade')\n            console.log(err)\n          }\n          villager.close()\n      }\n    }\n  }\n\n  function hasResources (window, trade, count) {\n    const first = enough(trade.inputItem1, count)\n    const second = !trade.inputItem2 || enough(trade.inputItem2, count)\n    return first && second\n\n    function enough (item, count) {\n      let c = 0\n      window.forEach((element) => {\n        if (element && element.type === item.type && element.metadata === item.metadata) {\n          c += element.count\n        }\n      })\n      return c >= item.count * count\n    }\n  }\n}\n\nfunction stringifyTrades (trades) {\n  return trades.map((trade) => {\n    let text = stringifyItem(trade.inputItem1)\n    if (trade.inputItem2) text += ` & ${stringifyItem(trade.inputItem2)}`\n    if (trade.disabled) text += ' x '; else text += ' » '\n    text += stringifyItem(trade.outputItem)\n    return `(${trade.nbTradeUses}/${trade.maximumNbTradeUses}) ${text}`\n  })\n}\n\nfunction stringifyItem (item) {\n  if (!item) return 'nothing'\n  let text = `${item.count} ${item.displayName}`\n  if (item.nbt && item.nbt.value) {\n    const ench = item.nbt.value.ench\n    const StoredEnchantments = item.nbt.value.StoredEnchantments\n    const Potion = item.nbt.value.Potion\n    const display = item.nbt.value.display\n\n    if (Potion) text += ` of ${Potion.value.replace(/_/g, ' ').split(':')[1] || 'unknown type'}`\n    if (display) text += ` named ${display.value.Name.value}`\n    if (ench || StoredEnchantments) {\n      text += ` enchanted with ${(ench || StoredEnchantments).value.value.map((e) => {\n        const lvl = e.lvl.value\n        const id = e.id.value\n        return bot.registry.enchantments[id].displayName + ' ' + lvl\n      }).join(' ')}`\n    }\n  }\n  return text\n}\n"
  },
  {
    "path": "examples/viewer/.npmrc",
    "content": "engine-strict=true\npackage-lock=false\n"
  },
  {
    "path": "examples/viewer/README.md",
    "content": "[<img src=\"https://prismarinejs.github.io/prismarine-viewer/test_1.16.1.png\" alt=\"viewer\" width=\"800\">](https://prismarinejs.github.io/prismarine-viewer/)\n"
  },
  {
    "path": "examples/viewer/package.json",
    "content": "{\n  \"name\": \"mineflayer-example\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"prismarine-viewer\": \"^1.0.3\",\n    \"mineflayer\": \"file:../../\"\n  },\n  \"description\": \"A mineflayer example\"\n}"
  },
  {
    "path": "examples/viewer/viewer.js",
    "content": "/*\n *\n * A simple bot demo https://github.com/PrismarineJS/prismarine-viewer\n * Start it then open your browser to http://localhost:3007 and enjoy the view\n *\n */\n\nconst mineflayer = require('mineflayer')\nconst mineflayerViewer = require('prismarine-viewer').mineflayer\n\nif (process.argv.length < 4 || process.argv.length > 6) {\n  console.log('Usage : node viewer.js <host> <port> [<name>] [<password>]')\n  process.exit(1)\n}\n\nconst bot = mineflayer.createBot({\n  host: process.argv[2],\n  port: parseInt(process.argv[3]),\n  username: process.argv[4] ? process.argv[4] : 'viewer',\n  password: process.argv[5]\n})\n\nbot.once('spawn', () => {\n  mineflayerViewer(bot, { port: 3007, firstPerson: false })\n})\n"
  },
  {
    "path": "index.d.ts",
    "content": "import { EventEmitter } from 'events'\nimport TypedEmitter from 'typed-emitter'\nimport { Client, ClientOptions } from 'minecraft-protocol'\nimport { Vec3 } from 'vec3'\nimport { Item } from 'prismarine-item'\nimport { Window } from 'prismarine-windows'\nimport { Recipe } from 'prismarine-recipe'\nimport { Block } from 'prismarine-block'\nimport { Entity } from 'prismarine-entity'\nimport { ChatMessage } from 'prismarine-chat'\nimport { world } from 'prismarine-world'\nimport { Registry } from 'prismarine-registry'\nimport { IndexedData } from 'minecraft-data'\n\nexport function createBot (options: { client: Client } & Partial<BotOptions>): Bot\nexport function createBot (options: BotOptions): Bot\n\nexport interface BotOptions extends ClientOptions {\n  logErrors?: boolean\n  hideErrors?: boolean\n  loadInternalPlugins?: boolean\n  plugins?: PluginOptions\n  chat?: ChatLevel\n  colorsEnabled?: boolean\n  viewDistance?: ViewDistance\n  mainHand?: MainHands\n  difficulty?: number\n  chatLengthLimit?: number\n  physicsEnabled?: boolean\n  /** @default 4 */\n  maxCatchupTicks?: number\n  client?: Client\n  brand?: string\n  defaultChatPatterns?: boolean\n  respawn?: boolean\n}\n\nexport type ChatLevel = 'enabled' | 'commandsOnly' | 'disabled'\nexport type ViewDistance = 'far' | 'normal' | 'short' | 'tiny' | number\nexport type MainHands = 'left' | 'right'\n\nexport interface PluginOptions {\n  [plugin: string]: boolean | Plugin\n}\n\nexport type Plugin = (bot: Bot, options: BotOptions) => void\n\nexport interface BotEvents {\n  chat: (\n    username: string,\n    message: string,\n    translate: string | null,\n    jsonMsg: ChatMessage,\n    matches: string[] | null\n  ) => Promise<void> | void\n  whisper: (\n    username: string,\n    message: string,\n    translate: string | null,\n    jsonMsg: ChatMessage,\n    matches: string[] | null\n  ) => Promise<void> | void\n  actionBar: (jsonMsg: ChatMessage) => Promise<void> | void\n  error: (err: Error) => Promise<void> | void\n  message: (jsonMsg: ChatMessage, position: string) => Promise<void> | void\n  messagestr: (message: string, position: string, jsonMsg: ChatMessage) => Promise<void> | void\n  unmatchedMessage: (stringMsg: string, jsonMsg: ChatMessage) => Promise<void> | void\n  inject_allowed: () => Promise<void> | void\n  login: () => Promise<void> | void\n  /** When `respawn` option is disabled, you can call this method manually to respawn. */\n  spawn: () => Promise<void> | void\n  respawn: () => Promise<void> | void\n  game: () => Promise<void> | void\n  title: (text: string, type: \"subtitle\" | \"title\") => Promise<void> | void\n  rain: () => Promise<void> | void\n  time: () => Promise<void> | void\n  kicked: (reason: string, loggedIn: boolean) => Promise<void> | void\n  end: (reason: string) => Promise<void> | void\n  spawnReset: () => Promise<void> | void\n  death: () => Promise<void> | void\n  health: () => Promise<void> | void\n  breath: () => Promise<void> | void\n  entitySwingArm: (entity: Entity) => Promise<void> | void\n  entityHurt: (entity: Entity, source: Entity) => Promise<void> | void\n  entityDead: (entity: Entity) => Promise<void> | void\n  entityTaming: (entity: Entity) => Promise<void> | void\n  entityTamed: (entity: Entity) => Promise<void> | void\n  entityShakingOffWater: (entity: Entity) => Promise<void> | void\n  entityEatingGrass: (entity: Entity) => Promise<void> | void\n  entityHandSwap: (entity: Entity) => Promise<void> | void\n  entityWake: (entity: Entity) => Promise<void> | void\n  entityEat: (entity: Entity) => Promise<void> | void\n  entityCriticalEffect: (entity: Entity) => Promise<void> | void\n  entityMagicCriticalEffect: (entity: Entity) => Promise<void> | void\n  entityCrouch: (entity: Entity) => Promise<void> | void\n  entityUncrouch: (entity: Entity) => Promise<void> | void\n  entityEquip: (entity: Entity) => Promise<void> | void\n  entitySleep: (entity: Entity) => Promise<void> | void\n  entitySpawn: (entity: Entity) => Promise<void> | void\n  entityElytraFlew: (entity: Entity) => Promise<void> | void\n  usedFirework: () => Promise<void> | void\n  itemDrop: (entity: Entity) => Promise<void> | void\n  playerCollect: (collector: Entity, collected: Entity) => Promise<void> | void\n  entityAttributes: (entity: Entity) => Promise<void> | void\n  entityGone: (entity: Entity) => Promise<void> | void\n  entityMoved: (entity: Entity) => Promise<void> | void\n  entityDetach: (entity: Entity, vehicle: Entity) => Promise<void> | void\n  entityAttach: (entity: Entity, vehicle: Entity) => Promise<void> | void\n  entityUpdate: (entity: Entity) => Promise<void> | void\n  entityEffect: (entity: Entity, effect: Effect) => Promise<void> | void\n  entityEffectEnd: (entity: Entity, effect: Effect) => Promise<void> | void\n  playerJoined: (player: Player) => Promise<void> | void\n  playerUpdated: (player: Player) => Promise<void> | void\n  playerLeft: (entity: Player) => Promise<void> | void\n  blockUpdate: (oldBlock: Block | null, newBlock: Block) => Promise<void> | void\n  'blockUpdate:(x, y, z)': (oldBlock: Block | null, newBlock: Block | null) => Promise<void> | void\n  chunkColumnLoad: (entity: Vec3) => Promise<void> | void\n  chunkColumnUnload: (entity: Vec3) => Promise<void> | void\n  soundEffectHeard: (\n    soundName: string,\n    position: Vec3,\n    volume: number,\n    pitch: number\n  ) => Promise<void> | void\n  hardcodedSoundEffectHeard: (\n    soundId: number,\n    soundCategory: number,\n    position: Vec3,\n    volume: number,\n    pitch: number\n  ) => Promise<void> | void\n  noteHeard: (block: Block, instrument: Instrument, pitch: number) => Promise<void> | void\n  pistonMove: (block: Block, isPulling: number, direction: number) => Promise<void> | void\n  chestLidMove: (block: Block, isOpen: number, block2: Block | null) => Promise<void> | void\n  blockBreakProgressObserved: (block: Block, destroyStage: number) => Promise<void> | void\n  blockBreakProgressEnd: (block: Block) => Promise<void> | void\n  diggingCompleted: (block: Block) => Promise<void> | void\n  diggingAborted: (block: Block) => Promise<void> | void\n  move: (position: Vec3) => Promise<void> | void\n  forcedMove: () => Promise<void> | void\n  mount: () => Promise<void> | void\n  dismount: (vehicle: Entity) => Promise<void> | void\n  windowOpen: (window: Window) => Promise<void> | void\n  windowClose: (window: Window) => Promise<void> | void\n  sleep: () => Promise<void> | void\n  wake: () => Promise<void> | void\n  experience: () => Promise<void> | void\n  physicsTick: () => Promise<void> | void\n  physicTick: () => Promise<void> | void\n  scoreboardCreated: (scoreboard: ScoreBoard) => Promise<void> | void\n  scoreboardDeleted: (scoreboard: ScoreBoard) => Promise<void> | void\n  scoreboardTitleChanged: (scoreboard: ScoreBoard) => Promise<void> | void\n  scoreUpdated: (scoreboard: ScoreBoard, item: number) => Promise<void> | void\n  scoreRemoved: (scoreboard: ScoreBoard, item: number) => Promise<void> | void\n  scoreboardPosition: (position: DisplaySlot, scoreboard: ScoreBoard) => Promise<void> | void\n  teamCreated: (team: Team) => Promise<void> | void\n  teamRemoved: (team: Team) => Promise<void> | void\n  teamUpdated: (team: Team) => Promise<void> | void\n  teamMemberAdded: (team: Team) => Promise<void> | void\n  teamMemberRemoved: (team: Team) => Promise<void> | void\n  bossBarCreated: (bossBar: BossBar) => Promise<void> | void\n  bossBarDeleted: (bossBar: BossBar) => Promise<void> | void\n  bossBarUpdated: (bossBar: BossBar) => Promise<void> | void\n  resourcePack: (url: string, hash?: string, uuid?: string) => Promise<void> | void\n  particle: (particle: Particle) => Promise<void> | void\n}\n\nexport interface CommandBlockOptions {\n  mode: number,\n  trackOutput: boolean,\n  conditional: boolean,\n  alwaysActive: boolean\n}\n\nexport interface Bot extends TypedEmitter<BotEvents> {\n  username: string\n  protocolVersion: string\n  majorVersion: string\n  version: string\n  entity: Entity\n  entities: { [id: string]: Entity }\n  fireworkRocketDuration: number\n  spawnPoint: Vec3\n  game: GameState\n  player: Player\n  players: { [username: string]: Player }\n  isRaining: boolean\n  thunderState: number\n  chatPatterns: ChatPattern[]\n  settings: GameSettings\n  experience: Experience\n  health: number\n  food: number\n  foodSaturation: number\n  oxygenLevel: number\n  physics: PhysicsOptions\n  physicsEnabled: boolean\n  time: Time\n  quickBarSlot: number\n  inventory: Window<StorageEvents>\n  targetDigBlock: Block\n  isSleeping: boolean\n  scoreboards: { [name: string]: ScoreBoard }\n  scoreboard: { [slot in DisplaySlot]: ScoreBoard }\n  teams: { [name: string]: Team }\n  teamMap: { [name: string]: Team }\n  controlState: ControlStateStatus\n  creative: creativeMethods\n  world: world.WorldSync\n  _client: Client\n  heldItem: Item | null\n  usingHeldItem: boolean\n  currentWindow: Window | null\n  simpleClick: simpleClick\n  tablist: Tablist\n  registry: Registry\n\n  connect: (options: BotOptions) => void\n\n  supportFeature: IndexedData['supportFeature']\n\n  end: (reason?: string) => void\n\n  blockAt: (point: Vec3, extraInfos?: boolean) => Block | null\n\n  blockInSight: (maxSteps: number, vectorLength: number) => Block | null\n\n  blockAtCursor: (maxDistance?: number, matcher?: Function) => Block | null\n  blockAtEntityCursor: (entity?: Entity, maxDistance?: number, matcher?: Function) => Block | null\n\n  canSeeBlock: (block: Block) => boolean\n\n  findBlock: (options: FindBlockOptions) => Block | null\n\n  findBlocks: (options: FindBlockOptions) => Vec3[]\n\n  canDigBlock: (block: Block) => boolean\n\n  recipesFor: (\n    itemType: number,\n    metadata: number | null,\n    minResultCount: number | null,\n    craftingTable: Block | boolean | null\n  ) => Recipe[]\n\n  recipesAll: (\n    itemType: number,\n    metadata: number | null,\n    craftingTable: Block | boolean | null\n  ) => Recipe[]\n\n  quit: (reason?: string) => void\n\n  tabComplete: (\n    str: string,\n    assumeCommand?: boolean,\n    sendBlockInSight?: boolean,\n    timeout?: number\n  ) => Promise<string[]>\n\n  chat: (message: string) => void\n\n  whisper: (username: string, message: string) => void\n\n  chatAddPattern: (pattern: RegExp, chatType: string, description?: string) => number\n\n  setSettings: (options: Partial<GameSettings>) => void\n\n  loadPlugin: (plugin: Plugin) => void\n\n  loadPlugins: (plugins: Plugin[]) => void\n\n  hasPlugin: (plugin: Plugin) => boolean\n\n  sleep: (bedBlock: Block) => Promise<void>\n\n  isABed: (bedBlock: Block) => boolean\n\n  wake: () => Promise<void>\n\n  elytraFly: () => Promise<void>\n\n  setControlState: (control: ControlState, state: boolean) => void\n\n  getControlState: (control: ControlState) => boolean\n\n  clearControlStates: () => void\n\n  getExplosionDamages: (targetEntity: Entity, position: Vec3, radius: number, rawDamages?: boolean) => number | null\n\n  lookAt: (point: Vec3, force?: boolean) => Promise<void>\n\n  look: (\n    yaw: number,\n    pitch: number,\n    force?: boolean\n  ) => Promise<void>\n\n  updateSign: (block: Block, text: string, back?: boolean) => void\n\n  equip: (\n    item: Item | number,\n    destination: EquipmentDestination | null\n  ) => Promise<void>\n\n  unequip: (\n    destination: EquipmentDestination | null\n  ) => Promise<void>\n\n  tossStack: (item: Item) => Promise<void>\n\n  toss: (\n    itemType: number,\n    metadata: number | null,\n    count: number | null\n  ) => Promise<void>\n\n  dig: ((block: Block, forceLook?: boolean | 'ignore') => Promise<void>) & ((block: Block, forceLook: boolean | 'ignore', digFace: 'auto' | Vec3 | 'raycast') => Promise<void>)\n\n  stopDigging: () => void\n\n  digTime: (block: Block) => number\n\n  placeBlock: (referenceBlock: Block, faceVector: Vec3) => Promise<void>\n\n  placeEntity: (referenceBlock: Block, faceVector: Vec3) => Promise<Entity>\n\n  activateBlock: (block: Block, direction?: Vec3, cursorPos?: Vec3) => Promise<void>\n\n  activateEntity: (entity: Entity) => Promise<void>\n\n  activateEntityAt: (entity: Entity, position: Vec3) => Promise<void>\n\n  consume: () => Promise<void>\n\n  fish: () => Promise<void>\n\n  activateItem: (offhand?: boolean) => void\n\n  deactivateItem: () => void\n\n  useOn: (targetEntity: Entity) => void\n\n  attack: (entity: Entity) => void\n\n  swingArm: (hand: 'left' | 'right' | undefined, showHand?: boolean) => void\n\n  mount: (entity: Entity) => void\n\n  dismount: () => void\n\n  moveVehicle: (left: number, forward: number) => void\n\n  setQuickBarSlot: (slot: number) => void\n\n  craft: (\n    recipe: Recipe,\n    count?: number,\n    craftingTable?: Block\n  ) => Promise<void>\n\n  writeBook: (\n    slot: number,\n    pages: string[]\n  ) => Promise<void>\n\n  openContainer: (chest: Block | Entity, direction?: Vec3, cursorPos?: Vec3) => Promise<Chest | Dispenser>\n\n  openChest: (chest: Block | Entity, direction?: number, cursorPos?: Vec3) => Promise<Chest>\n\n  openFurnace: (furnace: Block) => Promise<Furnace>\n\n  openDispenser: (dispenser: Block) => Promise<Dispenser>\n\n  openEnchantmentTable: (enchantmentTable: Block) => Promise<EnchantmentTable>\n\n  openAnvil: (anvil: Block) => Promise<Anvil>\n\n  openVillager: (\n    villager: Entity\n  ) => Promise<Villager>\n\n  trade: (\n    villagerInstance: Villager,\n    tradeIndex: string | number,\n    times?: number\n  ) => Promise<void>\n\n  \n  \n  setCommandBlock: (pos: Vec3, command: string, options: CommandBlockOptions) => void\n\n  clickWindow: (\n    slot: number,\n    mouseButton: number,\n    mode: number\n  ) => Promise<void>\n\n  putSelectedItemRange: (\n    start: number,\n    end: number,\n    window: Window,\n    slot: any\n  ) => Promise<void>\n\n  putAway: (slot: number) => Promise<void>\n\n  closeWindow: (window: Window) => void\n\n  transfer: (options: TransferOptions) => Promise<void>\n\n  openBlock: (block: Block, direction?: Vec3, cursorPos?: Vec3) => Promise<Window>\n\n  openEntity: (block: Entity, Class: new () => EventEmitter) => Promise<Window>\n\n  moveSlotItem: (\n    sourceSlot: number,\n    destSlot: number\n  ) => Promise<void>\n\n  updateHeldItem: () => void\n\n  getEquipmentDestSlot: (destination: string) => number\n\n  waitForChunksToLoad: () => Promise<void>\n\n  entityAtCursor: (maxDistance?: number) => Entity | null\n  nearestEntity: (filter?: (entity: Entity) => boolean) => Entity | null\n\n  waitForTicks: (ticks: number) => Promise<void>\n\n  addChatPattern: (name: string, pattern: RegExp, options?: chatPatternOptions) => number\n\n  addChatPatternSet: (name: string, patterns: RegExp[], options?: chatPatternOptions) => number\n\n  removeChatPattern: (name: string | number) => void\n\n  awaitMessage: (...args: string[] | RegExp[]) => Promise<string>\n\n  acceptResourcePack: () => void\n\n  denyResourcePack: () => void\n\n  respawn: () => void\n}\n\nexport interface simpleClick {\n  leftMouse: (slot: number) => Promise<void>\n  rightMouse: (slot: number) => Promise<void>\n}\n\nexport interface Tablist {\n  header: ChatMessage\n  footer: ChatMessage\n}\n\nexport interface chatPatternOptions {\n  repeat: boolean\n  parse: boolean\n}\n\nexport interface GameState {\n  levelType: LevelType\n  gameMode: GameMode\n  hardcore: boolean\n  dimension: Dimension\n  difficulty: Difficulty\n  maxPlayers: number\n  serverBrand: string\n}\n\nexport type LevelType =\n  | 'default'\n  | 'flat'\n  | 'largeBiomes'\n  | 'amplified'\n  | 'customized'\n  | 'buffet'\n  | 'default_1_1'\nexport type GameMode = 'survival' | 'creative' | 'adventure' | 'spectator'\nexport type Dimension = 'the_nether' | 'overworld' | 'the_end'\nexport type Difficulty = 'peaceful' | 'easy' | 'normal' | 'hard'\n\nexport interface Player {\n  uuid: string\n  username: string\n  displayName: ChatMessage\n  gamemode: number\n  ping: number\n  entity: Entity\n  skinData: SkinData | undefined\n  profileKeys?: {\n    publicKey: Buffer\n    signature: Buffer\n  }\n}\n\nexport interface SkinData {\n  url: string\n  model: string | null\n}\n\nexport interface ChatPattern {\n  pattern: RegExp\n  type: string\n  description: string\n}\n\nexport interface SkinParts {\n  showCape: boolean\n  showJacket: boolean\n  showLeftSleeve: boolean\n  showRightSleeve: boolean\n  showLeftPants: boolean\n  showRightPants: boolean\n  showHat: boolean\n}\n\nexport interface GameSettings {\n  chat: ChatLevel\n  colorsEnabled: boolean\n  viewDistance: ViewDistance\n  difficulty: number\n  skinParts: SkinParts\n  mainHand: MainHands\n}\n\nexport interface Experience {\n  level: number\n  points: number\n  progress: number\n}\n\nexport interface PhysicsOptions {\n  maxGroundSpeed: number\n  terminalVelocity: number\n  walkingAcceleration: number\n  gravity: number\n  groundFriction: number\n  playerApothem: number\n  playerHeight: number\n  jumpSpeed: number\n  yawSpeed: number\n  pitchSpeed: number\n  sprintSpeed: number\n  maxGroundSpeedSoulSand: number\n  maxGroundSpeedWater: number\n}\n\nexport interface Time {\n  doDaylightCycle: boolean\n  bigTime: BigInt\n  time: number\n  timeOfDay: number\n  day: number\n  isDay: boolean\n  moonPhase: number\n  bigAge: BigInt\n  age: number\n}\n\nexport interface ControlStateStatus {\n  forward: boolean\n  back: boolean\n  left: boolean\n  right: boolean\n  jump: boolean\n  sprint: boolean\n  sneak: boolean\n}\n\nexport type ControlState =\n  | 'forward'\n  | 'back'\n  | 'left'\n  | 'right'\n  | 'jump'\n  | 'sprint'\n  | 'sneak'\n\nexport interface Effect {\n  id: number\n  amplifier: number\n  duration: number\n}\n\nexport interface Instrument {\n  id: number\n  name: 'harp' | 'doubleBass' | 'snareDrum' | 'sticks' | 'bassDrum'\n}\n\nexport interface FindBlockOptions {\n  point?: Vec3\n  matching: number | number[] | ((block: Block) => boolean)\n  maxDistance?: number\n  count?: number\n  useExtraInfo?: boolean | ((block: Block) => boolean)\n}\n\nexport type EquipmentDestination = 'hand' | 'head' | 'torso' | 'legs' | 'feet' | 'off-hand'\n\nexport interface TransferOptions {\n  window: Window\n  itemType: number\n  metadata: number | null\n  count?: number,\n  sourceStart: number\n  sourceEnd: number\n  destStart: number\n  destEnd: number\n}\n\nexport interface creativeMethods {\n  setInventorySlot: (\n    slot: number,\n    item: Item | null\n  ) => Promise<void>\n\n  clearSlot: (slot: number) => Promise<void>\n\n  clearInventory: () => Promise<void>\n\n  flyTo: (destination: Vec3) => Promise<void>\n\n  startFlying: () => void\n\n  stopFlying: () => void\n}\n\nexport class Location {\n  floored: Vec3\n  blockPoint: Vec3\n  chunkCorner: Vec3\n  blockIndex: number\n  biomeBlockIndex: number\n  chunkYIndex: number\n\n  constructor (absoluteVector: Vec3);\n}\n\nexport class Painting {\n  id: number\n  position: Vec3\n  name: string\n  direction: Vec3\n\n  constructor (id: number, position: Vec3, name: string, direction: Vec3);\n}\n\ninterface StorageEvents {\n  open: () => void\n  close: () => void\n  updateSlot: (slot: number, oldItem: Item | null, newItem: Item | null) => void\n}\n\ninterface FurnaceEvents extends StorageEvents {\n  update: () => void\n}\n\ninterface ConditionalStorageEvents extends StorageEvents {\n  ready: () => void\n}\n\nexport class Chest extends Window<StorageEvents> {\n  constructor ();\n\n  close (): void;\n\n  deposit (\n    itemType: number,\n    metadata: number | null,\n    count: number | null\n  ): Promise<void>;\n\n  withdraw (\n    itemType: number,\n    metadata: number | null,\n    count: number | null\n  ): Promise<void>;\n}\n\nexport class Furnace extends Window<FurnaceEvents> {\n  fuel: number\n  progress: number\n\n  constructor ();\n\n  close (): void;\n\n  takeInput (): Promise<Item>;\n\n  takeFuel (): Promise<Item>;\n\n  takeOutput (): Promise<Item>;\n\n  putInput (\n    itemType: number,\n    metadata: number | null,\n    count: number\n  ): Promise<void>;\n\n  putFuel (\n    itemType: number,\n    metadata: number | null,\n    count: number\n  ): Promise<void>;\n\n  inputItem (): Item;\n\n  fuelItem (): Item;\n\n  outputItem (): Item;\n}\n\nexport class Dispenser extends Window<StorageEvents> {\n  constructor ();\n\n  close (): void;\n\n  deposit (\n    itemType: number,\n    metadata: number | null,\n    count: number | null\n  ): Promise<void>;\n\n  withdraw (\n    itemType: number,\n    metadata: number | null,\n    count: number | null\n  ): Promise<void>;\n}\n\nexport class EnchantmentTable extends Window<ConditionalStorageEvents> {\n  enchantments: Enchantment[]\n\n  constructor ();\n\n  close (): void;\n\n  targetItem (): Item;\n\n  enchant (\n    choice: string | number\n  ): Promise<Item>;\n\n  takeTargetItem (): Promise<Item>;\n\n  putTargetItem (item: Item): Promise<Item>;\n\n  putLapis (item: Item): Promise<Item>;\n}\n\nexport class Anvil {\n  combine (itemOne: Item, itemTwo: Item, name?: string): Promise<void>\n  rename (item: Item, name?: string): Promise<void>\n}\n\nexport interface Enchantment {\n  level: number\n  expected: { enchant: number, level: number }\n}\n\nexport class Villager extends Window<ConditionalStorageEvents> {\n  trades: VillagerTrade[]\n\n  constructor ();\n\n  close (): void;\n}\n\nexport interface VillagerTrade {\n  inputItem1: Item\n  outputItem: Item\n  inputItem2: Item | null\n  hasItem2: boolean\n  tradeDisabled: boolean\n  nbTradeUses: number\n  maximumNbTradeUses: number\n  xp?: number\n  specialPrice?: number\n  priceMultiplier?: number\n  demand?: number\n  realPrice?: number\n}\n\nexport class ScoreBoard {\n  name: string\n  title: string\n  itemsMap: { [name: string]: ScoreBoardItem }\n  items: ScoreBoardItem[]\n\n  constructor (packet: object);\n\n  setTitle (title: string): void;\n\n  add(name: string, value: number): ScoreBoardItem;\n\n  remove (name: string): ScoreBoardItem;\n}\n\nexport interface ScoreBoardItem {\n  name: string\n  displayName: ChatMessage\n  value: number\n}\n\nexport class Team {\n  team: string\n  name: ChatMessage\n  friendlyFire: number\n  nameTagVisibility: string\n  collisionRule: string\n  color: string\n  prefix: ChatMessage\n  suffix: ChatMessage\n  memberMap: { [name: string]: '' }\n  members: string[]\n\n  constructor(team: string, name: string, friendlyFire: boolean, nameTagVisibility: string, collisionRule: string, formatting: number, prefix: string, suffix: string);\n\n  parseMessage (value: string): ChatMessage;\n\n  add (name: string, value: number): void;\n\n  remove (name: string): void;\n\n  update (name: string, friendlyFire: boolean, nameTagVisibility: string, collisionRule: string, formatting: number, prefix: string, suffix: string): void;\n\n  displayName (member: string): ChatMessage;\n}\n\nexport type DisplaySlot =\n  | 'list'\n  | 'sidebar'\n  | 'belowName'\n  | 3\n  | 4\n  | 5\n  | 6\n  | 7\n  | 8\n  | 9\n  | 10\n  | 11\n  | 12\n  | 13\n  | 14\n  | 15\n  | 16\n  | 17\n  | 18\n\nexport class BossBar {\n  entityUUID: string\n  title: ChatMessage\n  health: number\n  dividers: number\n  color: 'pink' | 'blue' | 'red' | 'green' | 'yellow' | 'purple' | 'white'\n  shouldDarkenSky: boolean\n  isDragonBar: boolean\n  createFog: boolean\n  shouldCreateFog: boolean\n\n  constructor (\n    uuid: string,\n    title: string,\n    health: number,\n    dividers: number,\n    color: number,\n    flags: number\n  );\n}\n\nexport class Particle {\n  id: number\n  position: Vec3\n  offset: Vec3\n  count: number\n  movementSpeed: number\n  longDistanceRender: boolean\n  static fromNetwork(packet: Object): Particle\n\n  constructor(\n    id: number,\n    position: Vec3,\n    offset: Vec3,\n    count?: number,\n    movementSpeed?: number,\n    longDistanceRender?: boolean\n  );\n}\n\nexport let testedVersions: string[]\nexport let latestSupportedVersion: string\nexport let oldestSupportedVersion: string\n\nexport function supportFeature (feature: string, version: string): boolean\n"
  },
  {
    "path": "index.js",
    "content": "if (typeof process !== 'undefined' && !process.browser && process.platform !== 'browser' && parseInt(process.versions.node.split('.')[0]) < 18) {\n  console.error('Your node version is currently', process.versions.node)\n  console.error('Please update it to a version >= 22.x.x from https://nodejs.org/')\n  process.exit(1)\n}\n\nmodule.exports = require('./lib/loader.js')\n"
  },
  {
    "path": "lib/bossbar.js",
    "content": "const colors = ['pink', 'blue', 'red', 'green', 'yellow', 'purple', 'white']\nconst divisions = [0, 6, 10, 12, 20]\n\nfunction loader (registry) {\n  const ChatMessage = require('prismarine-chat')(registry)\n  return class BossBar {\n    constructor (uuid, title, health, dividers, color, flags) {\n      this._entityUUID = uuid\n      this.title = title\n      this._health = health\n      this._dividers = divisions[dividers]\n      this._color = colors[color]\n      this._shouldDarkenSky = flags & 0x1\n      this._isDragonBar = flags & 0x2\n      this._createFog = flags & 0x4\n    }\n\n    set entityUUID (uuid) {\n      this._entityUUID = uuid\n    }\n\n    set title (title) {\n      if (title && typeof title === 'object' && title.type === 'string' && 'value' in title) {\n        this._title = title.value\n      } else {\n        const chatMsg = ChatMessage.fromNotch(title)\n        if (chatMsg !== undefined && chatMsg !== null) {\n          this._title = chatMsg\n        } else if (typeof title === 'string') {\n          this._title = title\n        } else {\n          this._title = ''\n        }\n      }\n    }\n\n    set health (health) {\n      this._health = health\n    }\n\n    set dividers (dividers) {\n      this._dividers = divisions[dividers]\n    }\n\n    set color (color) {\n      this._color = colors[color]\n    }\n\n    set flags (flags) {\n      this._shouldDarkenSky = flags & 0x1\n      this._isDragonBar = flags & 0x2\n      this._createFog = flags & 0x4\n    }\n\n    get flags () {\n      return (this._shouldDarkenSky) | (this._isDragonBar << 1) | (this._createFog << 2)\n    }\n\n    set shouldDarkenSky (darkenSky) {\n      this._shouldDarkenSky = darkenSky\n    }\n\n    set isDragonBar (dragonBar) {\n      this._isDragonBar = dragonBar\n    }\n\n    get createFog () {\n      return this._createFog\n    }\n\n    set createFog (createFog) {\n      this._createFog = createFog\n    }\n\n    get entityUUID () {\n      return this._entityUUID\n    }\n\n    get title () {\n      return this._title\n    }\n\n    get health () {\n      return this._health\n    }\n\n    get dividers () {\n      return this._dividers\n    }\n\n    get color () {\n      return this._color\n    }\n\n    get shouldDarkenSky () {\n      return this._shouldDarkenSky\n    }\n\n    get isDragonBar () {\n      return this._isDragonBar\n    }\n\n    get shouldCreateFog () {\n      return this._createFog\n    }\n  }\n}\n\nmodule.exports = loader\n"
  },
  {
    "path": "lib/conversions.js",
    "content": "const { Vec3 } = require('vec3')\nconst math = require('./math')\nconst euclideanMod = math.euclideanMod\nconst PI = Math.PI\nconst PI_2 = Math.PI * 2\nconst TO_RAD = PI / 180\nconst TO_DEG = 1 / TO_RAD\nconst FROM_NOTCH_BYTE = 360 / 256\n// From minecraft.wiki: Velocity is believed to be in units of 1/8000 of a block per server tick (50ms)\nconst FROM_NOTCH_VEL = 1 / 8000\n\nexports.toRadians = toRadians\nexports.toDegrees = toDegrees\nexports.fromNotchianYaw = fromNotchianYaw\nexports.fromNotchianPitch = fromNotchianPitch\nexports.fromNotchVelocity = fromNotchVelocity\nexports.toNotchianYaw = yaw => toDegrees(PI - yaw)\nexports.toNotchianPitch = pitch => toDegrees(-pitch)\nexports.fromNotchianYawByte = yaw => fromNotchianYaw(yaw * FROM_NOTCH_BYTE)\nexports.fromNotchianPitchByte = pitch => fromNotchianPitch(pitch * FROM_NOTCH_BYTE)\n\nfunction toRadians (degrees) {\n  return TO_RAD * degrees\n}\n\nfunction toDegrees (radians) {\n  return TO_DEG * radians\n}\n\nfunction fromNotchianYaw (yaw) {\n  return euclideanMod(PI - toRadians(yaw), PI_2)\n}\n\nfunction fromNotchianPitch (pitch) {\n  return euclideanMod(toRadians(-pitch) + PI, PI_2) - PI\n}\n\nfunction fromNotchVelocity (vel) {\n  return new Vec3(vel.x * FROM_NOTCH_VEL, vel.y * FROM_NOTCH_VEL, vel.z * FROM_NOTCH_VEL)\n}\n"
  },
  {
    "path": "lib/loader.js",
    "content": "const mc = require('minecraft-protocol')\nconst { EventEmitter } = require('events')\nconst pluginLoader = require('./plugin_loader')\nconst plugins = {\n  bed: require('./plugins/bed'),\n  title: require('./plugins/title'),\n  block_actions: require('./plugins/block_actions'),\n  blocks: require('./plugins/blocks'),\n  book: require('./plugins/book'),\n  boss_bar: require('./plugins/boss_bar'),\n  breath: require('./plugins/breath'),\n  chat: require('./plugins/chat'),\n  chest: require('./plugins/chest'),\n  command_block: require('./plugins/command_block'),\n  craft: require('./plugins/craft'),\n  creative: require('./plugins/creative'),\n  digging: require('./plugins/digging'),\n  enchantment_table: require('./plugins/enchantment_table'),\n  entities: require('./plugins/entities'),\n  experience: require('./plugins/experience'),\n  explosion: require('./plugins/explosion'),\n  fishing: require('./plugins/fishing'),\n  furnace: require('./plugins/furnace'),\n  game: require('./plugins/game'),\n  health: require('./plugins/health'),\n  inventory: require('./plugins/inventory'),\n  kick: require('./plugins/kick'),\n  physics: require('./plugins/physics'),\n  place_block: require('./plugins/place_block'),\n  rain: require('./plugins/rain'),\n  ray_trace: require('./plugins/ray_trace'),\n  resource_pack: require('./plugins/resource_pack'),\n  scoreboard: require('./plugins/scoreboard'),\n  team: require('./plugins/team'),\n  settings: require('./plugins/settings'),\n  simple_inventory: require('./plugins/simple_inventory'),\n  sound: require('./plugins/sound'),\n  spawn_point: require('./plugins/spawn_point'),\n  tablist: require('./plugins/tablist'),\n  time: require('./plugins/time'),\n  villager: require('./plugins/villager'),\n  anvil: require('./plugins/anvil'),\n  place_entity: require('./plugins/place_entity'),\n  generic_place: require('./plugins/generic_place'),\n  particle: require('./plugins/particle')\n}\n\nconst minecraftData = require('minecraft-data')\nconst { testedVersions, latestSupportedVersion, oldestSupportedVersion } = require('./version')\nconst latestSupportedProtocolVersion = minecraftData.versionsByMinecraftVersion.pc[latestSupportedVersion].version\nif (!latestSupportedProtocolVersion) throw new Error(`Version '${latestSupportedVersion}' not supported by minecraft-data - is it up to date?`)\n\nmodule.exports = {\n  createBot,\n  Location: require('./location'),\n  Painting: require('./painting'),\n  ScoreBoard: require('./scoreboard'),\n  BossBar: require('./bossbar'),\n  Particle: require('./particle'),\n  latestSupportedVersion,\n  oldestSupportedVersion,\n  testedVersions,\n  supportFeature: (feature, version) => minecraftData(version).supportFeature(feature)\n}\n\nfunction createBot (options = {}) {\n  options.username = options.username ?? 'Player'\n  options.version = options.version ?? false\n  options.plugins = options.plugins ?? {}\n  options.hideErrors = options.hideErrors ?? false\n  options.logErrors = options.logErrors ?? true\n  options.loadInternalPlugins = options.loadInternalPlugins ?? true\n  options.client = options.client ?? null\n  options.brand = options.brand ?? 'vanilla'\n  options.respawn = options.respawn ?? true\n  const bot = new EventEmitter()\n  bot._client = options.client\n  bot.end = (reason) => bot._client.end(reason)\n  bot._warn = function (...message) {\n    if (options.hideErrors) return\n    console.warn('[mineflayer]', ...message)\n  }\n  if (options.logErrors) {\n    bot.on('error', err => {\n      if (!options.hideErrors) {\n        console.log(err)\n      }\n    })\n  }\n\n  pluginLoader(bot, options)\n  const internalPlugins = Object.keys(plugins)\n    .filter(key => {\n      if (typeof options.plugins[key] === 'function') return false\n      if (options.plugins[key] === false) return false\n      return options.plugins[key] || options.loadInternalPlugins\n    }).map(key => plugins[key])\n  const externalPlugins = Object.keys(options.plugins)\n    .filter(key => {\n      return typeof options.plugins[key] === 'function'\n    }).map(key => options.plugins[key])\n  bot.loadPlugins([...internalPlugins, ...externalPlugins])\n\n  options.validateChannelProtocol = false\n  bot._client = bot._client ?? mc.createClient(options)\n  bot._client.on('connect', () => {\n    bot.emit('connect')\n  })\n  bot._client.on('error', (err) => {\n    bot.emit('error', err)\n  })\n  bot._client.on('end', (reason) => {\n    bot.emit('end', reason)\n  })\n  if (!bot._client.wait_connect) next()\n  else bot._client.once('connect_allowed', next)\n  function next () {\n    const serverPingVersion = bot._client.version\n    bot.registry = require('prismarine-registry')(serverPingVersion)\n    if (!bot.registry?.version) throw new Error(`Server version '${serverPingVersion}' is not supported, no data for version`)\n\n    const versionData = bot.registry.version\n    if (versionData['>'](latestSupportedVersion) && (versionData.version !== latestSupportedProtocolVersion)) {\n      throw new Error(`Server version '${serverPingVersion}' is not supported. Latest supported version is '${latestSupportedVersion}'.`)\n    } else if (versionData['<'](oldestSupportedVersion)) {\n      throw new Error(`Server version '${serverPingVersion}' is not supported. Oldest supported version is '${oldestSupportedVersion}'.`)\n    }\n\n    bot.protocolVersion = versionData.version\n    bot.majorVersion = versionData.majorVersion\n    bot.version = versionData.minecraftVersion\n    options.version = versionData.minecraftVersion\n    bot.supportFeature = bot.registry.supportFeature\n    setTimeout(() => bot.emit('inject_allowed'), 0)\n  }\n  return bot\n}\n"
  },
  {
    "path": "lib/location.js",
    "content": "const { Vec3 } = require('vec3')\nconst CHUNK_SIZE = new Vec3(16, 16, 16)\n\nclass Location {\n  constructor (absoluteVector) {\n    this.floored = absoluteVector.floored()\n    this.blockPoint = this.floored.modulus(CHUNK_SIZE)\n    this.chunkCorner = this.floored.minus(this.blockPoint)\n    this.blockIndex = this.blockPoint.x + CHUNK_SIZE.x * this.blockPoint.z + CHUNK_SIZE.x * CHUNK_SIZE.z * this.blockPoint.y\n    this.biomeBlockIndex = this.blockPoint.x + CHUNK_SIZE.x * this.blockPoint.z\n    this.chunkYIndex = Math.floor(absoluteVector.y / 16)\n  }\n}\nmodule.exports = Location\n"
  },
  {
    "path": "lib/math.js",
    "content": "exports.clamp = function clamp (min, x, max) {\n  return Math.max(min, Math.min(x, max))\n}\n\nexports.euclideanMod = function euclideanMod (numerator, denominator) {\n  const result = numerator % denominator\n  return result < 0 ? result + denominator : result\n}\n"
  },
  {
    "path": "lib/painting.js",
    "content": "function Painting (id, pos, name, direction) {\n  this.id = id\n  this.position = pos\n  this.name = name\n  this.direction = direction\n}\nmodule.exports = Painting\n"
  },
  {
    "path": "lib/particle.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = loader\n\nfunction loader (registry) {\n  class Particle {\n    constructor (id, position, offset, count = 1, movementSpeed = 0, longDistanceRender = false) {\n      this.id = id\n      Object.assign(this, registry.particles[id] || registry.particlesByName[id])\n      this.position = position\n      this.offset = offset\n      this.count = count\n      this.movementSpeed = movementSpeed\n      this.longDistanceRender = longDistanceRender\n    }\n\n    static fromNetwork (packet) {\n      if (registry.supportFeature('updatedParticlesPacket')) {\n        // TODO: We add extra data that's inside packet.particle.data that varies by the particle's .type\n        return new Particle(\n          packet.particle.type,\n          new Vec3(packet.x, packet.y, packet.z),\n          new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),\n          packet.amount,\n          packet.velocityOffset,\n          packet.longDistance\n        )\n      } else {\n        return new Particle(\n          packet.particleId,\n          new Vec3(packet.x, packet.y, packet.z),\n          new Vec3(packet.offsetX, packet.offsetY, packet.offsetZ),\n          packet.particles,\n          packet.particleData,\n          packet.longDistance\n        )\n      }\n    }\n  }\n\n  return Particle\n}\n"
  },
  {
    "path": "lib/plugin_loader.js",
    "content": "const assert = require('assert')\n\nmodule.exports = inject\n\nfunction inject (bot, options) {\n  let loaded = false\n  const pluginList = []\n  bot.once('inject_allowed', onInjectAllowed)\n\n  function onInjectAllowed () {\n    loaded = true\n    injectPlugins()\n  }\n\n  function loadPlugin (plugin) {\n    assert.ok(typeof plugin === 'function', 'plugin needs to be a function')\n\n    if (hasPlugin(plugin)) {\n      return\n    }\n\n    pluginList.push(plugin)\n\n    if (loaded) {\n      plugin(bot, options)\n    }\n  }\n\n  function loadPlugins (plugins) {\n    // While type checking if already done in the other function, it's useful to do\n    // it here to prevent situations where only half the plugin list is loaded.\n    assert.ok(plugins.filter(plugin => typeof plugin === 'function').length === plugins.length, 'plugins need to be an array of functions')\n\n    plugins.forEach((plugin) => {\n      loadPlugin(plugin)\n    })\n  }\n\n  function injectPlugins () {\n    pluginList.forEach((plugin) => {\n      plugin(bot, options)\n    })\n  }\n\n  function hasPlugin (plugin) {\n    return pluginList.indexOf(plugin) >= 0\n  }\n\n  bot.loadPlugin = loadPlugin\n  bot.loadPlugins = loadPlugins\n  bot.hasPlugin = hasPlugin\n}\n"
  },
  {
    "path": "lib/plugins/anvil.js",
    "content": "const assert = require('assert')\nconst { sleep } = require('../promise_utils')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n\n  const matchWindowType = window => /minecraft:(?:chipped_|damaged_)?anvil/.test(window.type)\n\n  async function openAnvil (anvilBlock) {\n    const anvil = await bot.openBlock(anvilBlock)\n    if (!matchWindowType(anvil)) {\n      throw new Error('Not a anvil-like window: ' + JSON.stringify(anvil))\n    }\n\n    function err (name) {\n      anvil.close()\n      throw new Error(name)\n    }\n\n    function sendItemName (name) {\n      if (bot.supportFeature('useMCItemName')) {\n        bot._client.writeChannel('MC|ItemName', name)\n      } else {\n        bot._client.write('name_item', { name })\n      }\n    }\n\n    async function addCustomName (name) {\n      if (!name) return\n      for (let i = 1; i < name.length + 1; i++) {\n        sendItemName(name.substring(0, i))\n        await sleep(50)\n      }\n    }\n    async function putInAnvil (itemOne, itemTwo) {\n      await putSomething(0, itemOne.type, itemOne.metadata, itemOne.count, itemOne.nbt)\n      sendItemName('') // sent like this by vnailla\n      if (!bot.supportFeature('useMCItemName')) sendItemName('')\n      await putSomething(1, itemTwo.type, itemTwo.metadata, itemTwo.count, itemTwo.nbt)\n    }\n\n    async function combine (itemOne, itemTwo, name) {\n      if (name?.length > 35) err('Name is too long.')\n      if (bot.supportFeature('useMCItemName')) {\n        bot._client.registerChannel('MC|ItemName', 'string')\n      }\n\n      assert.ok(itemOne && itemTwo)\n      const { xpCost: normalCost } = Item.anvil(itemOne, itemTwo, bot.game.gameMode === 'creative', name)\n      const { xpCost: inverseCost } = Item.anvil(itemTwo, itemOne, bot.game.gameMode === 'creative', name)\n      if (normalCost === 0 && inverseCost === 0) err('Not anvil-able (in either direction), cancelling.')\n\n      const smallest = (normalCost < inverseCost ? normalCost : inverseCost) === 0 ? inverseCost : 0\n      if (bot.game.gameMode !== 'creative' && bot.experience.level < smallest) {\n        err('Player does not have enough xp to do action, cancelling.')\n      }\n\n      const xpPromise = bot.game.gameMode === 'creative' ? Promise.resolve() : once(bot, 'experience')\n      if (normalCost === 0) await putInAnvil(itemTwo, itemOne)\n      else if (inverseCost === 0) await putInAnvil(itemOne, itemTwo)\n      else if (normalCost < inverseCost) await putInAnvil(itemOne, itemTwo)\n      else await putInAnvil(itemTwo, itemOne)\n\n      await addCustomName(name)\n      await bot.putAway(2)\n      await xpPromise\n    }\n\n    async function rename (item, name) {\n      if (name?.length > 35) err('Name is too long.')\n      if (bot.supportFeature('useMCItemName')) {\n        bot._client.registerChannel('MC|ItemName', 'string')\n      }\n      assert.ok(item)\n      const { xpCost: normalCost } = Item.anvil(item, null, bot.game.gameMode === 'creative', name)\n      if (normalCost === 0) err('Not valid rename, cancelling.')\n\n      if (bot.game.gameMode !== 'creative' && bot.experience.level < normalCost) {\n        err('Player does not have enough xp to do action, cancelling.')\n      }\n      const xpPromise = once(bot, 'experience')\n      await putSomething(0, item.type, item.metadata, item.count, item.nbt)\n      sendItemName('') // sent like this by vnailla\n      if (!bot.supportFeature('useMCItemName')) sendItemName('')\n      await addCustomName(name)\n      await bot.putAway(2)\n      await xpPromise\n    }\n\n    async function putSomething (destSlot, itemId, metadata, count, nbt) {\n      const options = {\n        window: anvil,\n        itemType: itemId,\n        metadata,\n        count,\n        nbt,\n        sourceStart: anvil.inventoryStart,\n        sourceEnd: anvil.inventoryEnd,\n        destStart: destSlot,\n        destEnd: destSlot + 1\n      }\n      await bot.transfer(options)\n    }\n\n    anvil.combine = combine\n    anvil.rename = rename\n\n    return anvil\n  }\n\n  bot.openAnvil = openAnvil\n}\n"
  },
  {
    "path": "lib/plugins/bed.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nconst CARDINAL_DIRECTIONS = ['south', 'west', 'north', 'east']\n\nfunction inject (bot) {\n  bot.isSleeping = false\n\n  const beds = new Set(['white_bed', 'orange_bed', 'magenta_bed', 'light_blue_bed', 'yellow_bed', 'lime_bed', 'pink_bed', 'gray_bed',\n    'light_gray_bed', 'cyan_bed', 'purple_bed', 'blue_bed', 'brown_bed', 'green_bed', 'red_bed', 'black_bed', 'bed'])\n\n  function isABed (block) {\n    return beds.has(block.name)\n  }\n\n  function parseBedMetadata (bedBlock) {\n    const metadata = {\n      part: false, // true: head, false: foot\n      occupied: 0,\n      facing: 0, // 0: south, 1: west, 2: north, 3 east\n      headOffset: new Vec3(0, 0, 1)\n    }\n\n    if (bot.supportFeature('blockStateId')) {\n      const state = bedBlock.stateId - bot.registry.blocksByStateId[bedBlock.stateId].minStateId\n      const bitMetadata = state.toString(2).padStart(4, '0') // FACING (first 2 bits), PART (3rd bit), OCCUPIED (4th bit)\n      metadata.part = bitMetadata[3] === '0'\n      metadata.occupied = bitMetadata[2] === '0'\n\n      switch (bitMetadata.slice(0, 2)) {\n        case '00':\n          metadata.facing = 2\n          metadata.headOffset.set(0, 0, -1)\n          break\n        case '10':\n          metadata.facing = 1\n          metadata.headOffset.set(-1, 0, 0)\n          break\n        case '11':\n          metadata.facing = 3\n          metadata.headOffset.set(1, 0, 0)\n      }\n    } else if (bot.supportFeature('blockMetadata')) {\n      const bitMetadata = bedBlock.metadata.toString(2).padStart(4, '0') // PART (1st bit), OCCUPIED (2nd bit), FACING (last 2 bits)\n      metadata.part = bitMetadata[0] === '1'\n      metadata.occupied = bitMetadata[1] === '1'\n\n      switch (bitMetadata.slice(2, 4)) {\n        case '01':\n          metadata.facing = 1\n          metadata.headOffset.set(-1, 0, 0)\n          break\n        case '10':\n          metadata.facing = 2\n          metadata.headOffset.set(0, 0, -1)\n          break\n        case '11':\n          metadata.facing = 3\n          metadata.headOffset.set(1, 0, 0)\n      }\n    }\n\n    return metadata\n  }\n\n  async function wake () {\n    if (!bot.isSleeping) {\n      throw new Error('already awake')\n    } else {\n      bot._client.write('entity_action', {\n        entityId: bot.entity.id,\n        actionId: 2,\n        jumpBoost: 0\n      })\n    }\n  }\n\n  async function sleep (bedBlock) {\n    const thunderstorm = bot.isRaining && (bot.thunderState > 0)\n    if (!thunderstorm && !(bot.time.timeOfDay >= 12541 && bot.time.timeOfDay <= 23458)) {\n      throw new Error(\"it's not night and it's not a thunderstorm\")\n    } else if (bot.isSleeping) {\n      throw new Error('already sleeping')\n    } else if (!isABed(bedBlock)) {\n      throw new Error('wrong block : not a bed block')\n    } else {\n      const botPos = bot.entity.position.floored()\n      const metadata = parseBedMetadata(bedBlock)\n      let headPoint = bedBlock.position\n\n      if (metadata.occupied) {\n        throw new Error('the bed is occupied')\n      }\n\n      if (!metadata.part) { // Is foot\n        const upperBlock = bot.blockAt(bedBlock.position.plus(metadata.headOffset))\n\n        if (isABed(upperBlock)) {\n          headPoint = upperBlock.position\n        } else {\n          const lowerBlock = bot.blockAt(bedBlock.position.plus(metadata.headOffset.scaled(-1)))\n\n          if (isABed(lowerBlock)) {\n            // If there are 2 foot parts, minecraft only lets you sleep if you click on the lower one\n            headPoint = bedBlock.position\n            bedBlock = lowerBlock\n          } else {\n            throw new Error(\"there's only half bed\")\n          }\n        }\n      }\n\n      if (!bot.canDigBlock(bedBlock)) {\n        throw new Error('cant click the bed')\n      }\n\n      const clickRange = [2, -3, -3, 2] // [south, west, north, east]\n      const monsterRange = [7, -8, -8, 7]\n      const oppositeCardinal = (metadata.facing + 2) % CARDINAL_DIRECTIONS.length\n\n      if (clickRange[oppositeCardinal] < 0) {\n        clickRange[oppositeCardinal]--\n      } else {\n        clickRange[oppositeCardinal]++\n      }\n\n      const nwClickCorner = headPoint.offset(clickRange[1], -2, clickRange[2]) // North-West lower corner\n      const seClickCorner = headPoint.offset(clickRange[3], 2, clickRange[0]) // South-East upper corner\n      if (botPos.x > seClickCorner.x || botPos.x < nwClickCorner.x || botPos.y > seClickCorner.y || botPos.y < nwClickCorner.y || botPos.z > seClickCorner.z || botPos.z < nwClickCorner.z) {\n        throw new Error('the bed is too far')\n      }\n\n      if (bot.game.gameMode !== 'creative' || bot.supportFeature('creativeSleepNearMobs')) { // If in creative mode the bot should be able to sleep even if there are monster nearby (starting in 1.13)\n        const nwMonsterCorner = headPoint.offset(monsterRange[1], -6, monsterRange[2]) // North-West lower corner\n        const seMonsterCorner = headPoint.offset(monsterRange[3], 4, monsterRange[0]) // South-East upper corner\n\n        for (const key of Object.keys(bot.entities)) {\n          const entity = bot.entities[key]\n          if (entity.kind === 'Hostile mobs') {\n            const entityPos = entity.position.floored()\n            if (entityPos.x <= seMonsterCorner.x && entityPos.x >= nwMonsterCorner.x && entityPos.y <= seMonsterCorner.y && entityPos.y >= nwMonsterCorner.y && entityPos.z <= seMonsterCorner.z && entityPos.z >= nwMonsterCorner.z) {\n              throw new Error('there are monsters nearby')\n            }\n          }\n        }\n      }\n\n      // We need to register the listener before actually going to sleep to avoid race conditions\n      const waitingPromise = waitUntilSleep()\n      bot.activateBlock(bedBlock)\n      await waitingPromise\n    }\n  }\n\n  async function waitUntilSleep () {\n    return new Promise((resolve, reject) => {\n      const timeoutForSleep = setTimeout(() => {\n        reject(new Error('bot is not sleeping'))\n      }, 3000)\n\n      bot.once('sleep', () => {\n        clearTimeout(timeoutForSleep)\n        resolve()\n      })\n    })\n  }\n\n  bot._client.on('game_state_change', (packet) => {\n    if (packet.reason === 0 || packet.reason === 'no_respawn_block_available') {\n      // occurs when you can't spawn in your bed and your spawn point gets reset\n      bot.emit('spawnReset')\n    }\n  })\n\n  bot.on('entitySleep', (entity) => {\n    if (entity === bot.entity) {\n      bot.isSleeping = true\n      bot.emit('sleep')\n    }\n  })\n\n  bot.on('entityWake', (entity) => {\n    if (entity === bot.entity) {\n      bot.isSleeping = false\n      bot.emit('wake')\n    }\n  })\n\n  bot.parseBedMetadata = parseBedMetadata\n  bot.wake = wake\n  bot.sleep = sleep\n  bot.isABed = isABed\n}\n"
  },
  {
    "path": "lib/plugins/block_actions.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nconst CARDINALS = {\n  north: new Vec3(0, 0, -1),\n  south: new Vec3(0, 0, 1),\n  west: new Vec3(-1, 0, 0),\n  east: new Vec3(1, 0, 0)\n}\n\nconst FACING_MAP = {\n  north: { west: 'right', east: 'left' },\n  south: { west: 'left', east: 'right' },\n  west: { north: 'left', south: 'right' },\n  east: { north: 'right', south: 'left' }\n}\n\nfunction inject (bot) {\n  const { instruments, blocks } = bot.registry\n\n  // Stores how many players have currently open a container at a certain position\n  const openCountByPos = {}\n\n  function parseChestMetadata (chestBlock) {\n    const chestTypes = ['single', 'right', 'left']\n\n    return bot.supportFeature('doesntHaveChestType')\n      ? { facing: Object.keys(CARDINALS)[chestBlock.metadata - 2] }\n      : {\n          waterlogged: !(chestBlock.metadata & 1),\n          type: chestTypes[(chestBlock.metadata >> 1) % 3],\n          facing: Object.keys(CARDINALS)[Math.floor(chestBlock.metadata / 6)]\n        }\n  }\n\n  function getChestType (chestBlock) { // Returns 'single', 'right' or 'left'\n    if (bot.supportFeature('doesntHaveChestType')) {\n      const facing = parseChestMetadata(chestBlock).facing\n\n      if (!facing) return 'single'\n\n      // We have to check if the adjacent blocks in the perpendicular cardinals are the same type\n      const perpendicularCardinals = Object.keys(FACING_MAP[facing])\n      for (const cardinal of perpendicularCardinals) {\n        const cardinalOffset = CARDINALS[cardinal]\n        if (bot.blockAt(chestBlock.position.plus(cardinalOffset))?.type === chestBlock.type) {\n          return FACING_MAP[cardinal][facing]\n        }\n      }\n\n      return 'single'\n    } else {\n      return parseChestMetadata(chestBlock).type\n    }\n  }\n\n  bot._client.on('block_action', (packet) => {\n    const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)\n    const block = bot.blockAt(pt)\n\n    // Ignore on non-vanilla blocks\n    if (block === null || !blocks[packet.blockId]) { return }\n\n    const blockName = blocks[packet.blockId].name\n\n    if (blockName === 'noteblock') { // Pre 1.13\n      bot.emit('noteHeard', block, instruments[packet.byte1], packet.byte2)\n    } else if (blockName === 'note_block') { // 1.13 onward\n      bot.emit('noteHeard', block, instruments[Math.floor(block.metadata / 50)], Math.floor((block.metadata % 50) / 2))\n    } else if (blockName === 'sticky_piston' || blockName === 'piston') {\n      bot.emit('pistonMove', block, packet.byte1, packet.byte2)\n    } else {\n      let block2 = null\n\n      if (blockName === 'chest' || blockName === 'trapped_chest') {\n        const chestType = getChestType(block)\n        if (chestType === 'right') {\n          const index = Object.values(FACING_MAP[parseChestMetadata(block).facing]).indexOf('left')\n          const cardinalBlock2 = Object.keys(FACING_MAP[parseChestMetadata(block).facing])[index]\n          const block2Position = block.position.plus(CARDINALS[cardinalBlock2])\n          block2 = bot.blockAt(block2Position)\n        } else if (chestType === 'left') return // Omit left part of the chest so 'chestLidMove' doesn't emit twice when it's a double chest\n      }\n\n      // Emit 'chestLidMove' only if the number of players with the lid open changes\n      if (openCountByPos[block.position] !== packet.byte2) {\n        bot.emit('chestLidMove', block, packet.byte2, block2)\n\n        if (packet.byte2 > 0) {\n          openCountByPos[block.position] = packet.byte2\n        } else {\n          delete openCountByPos[block.position]\n        }\n      }\n    }\n  })\n\n  bot._client.on('block_break_animation', (packet) => {\n    const destroyStage = packet.destroyStage\n    const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)\n    const block = bot.blockAt(pt)\n    const entity = bot.entities[packet.entityId]\n\n    if (destroyStage < 0 || destroyStage > 9) {\n      // http://minecraft.wiki/w/Protocol#Block_Break_Progress\n      // \"0-9 to set it, any other value to remove it\"\n      bot.emit('blockBreakProgressEnd', block, entity)\n    } else {\n      bot.emit('blockBreakProgressObserved', block, destroyStage, entity)\n    }\n  })\n}\n"
  },
  {
    "path": "lib/plugins/blocks.js",
    "content": "const { Vec3 } = require('vec3')\nconst assert = require('assert')\nconst Painting = require('../painting')\nconst { onceWithCleanup } = require('../promise_utils')\n\nconst { OctahedronIterator } = require('prismarine-world').iterators\n\nmodule.exports = inject\n\nconst paintingFaceToVec = [\n  new Vec3(0, 0, -1),\n  new Vec3(-1, 0, 0),\n  new Vec3(0, 0, 1),\n  new Vec3(1, 0, 0)\n]\n\nconst dimensionNames = {\n  '-1': 'minecraft:nether',\n  0: 'minecraft:overworld',\n  1: 'minecraft:end'\n}\n\nfunction inject (bot, { version, storageBuilder, hideErrors }) {\n  const Block = require('prismarine-block')(bot.registry)\n  const Chunk = require('prismarine-chunk')(bot.registry)\n  const World = require('prismarine-world')(bot.registry)\n  const paintingsByPos = {}\n  const paintingsById = {}\n\n  function addPainting (painting) {\n    paintingsById[painting.id] = painting\n    paintingsByPos[painting.position] = painting\n  }\n\n  function deletePainting (painting) {\n    delete paintingsById[painting.id]\n    delete paintingsByPos[painting.position]\n  }\n\n  function delColumn (chunkX, chunkZ) {\n    bot.world.unloadColumn(chunkX, chunkZ)\n  }\n\n  function addColumn (args) {\n    if (!args.bitMap && args.groundUp) {\n      // stop storing the chunk column\n      delColumn(args.x, args.z)\n      return\n    }\n    let column = bot.world.getColumn(args.x, args.z)\n    if (!column) {\n      // Allocates new chunk object while taking world's custom min/max height into account\n      column = new Chunk({ minY: bot.game.minY, worldHeight: bot.game.height })\n    }\n\n    try {\n      column.load(args.data, args.bitMap, args.skyLightSent, args.groundUp)\n      if (args.biomes !== undefined) {\n        column.loadBiomes(args.biomes)\n      }\n      if (args.skyLight !== undefined) {\n        column.loadParsedLight(args.skyLight, args.blockLight, args.skyLightMask, args.blockLightMask, args.emptySkyLightMask, args.emptyBlockLightMask)\n      }\n      bot.world.setColumn(args.x, args.z, column)\n    } catch (e) {\n      bot.emit('error', e)\n    }\n  }\n\n  async function waitForChunksToLoad () {\n    const dist = 2\n    // This makes sure that the bot's real position has been already sent\n    if (!bot.entity.height) await onceWithCleanup(bot, 'chunkColumnLoad', { timeout: 10000 })\n    const pos = bot.entity.position\n    const center = new Vec3(pos.x >> 4 << 4, 0, pos.z >> 4 << 4)\n    // get corner coords of 5x5 chunks around us\n    const chunkPosToCheck = new Set()\n    for (let x = -dist; x <= dist; x++) {\n      for (let y = -dist; y <= dist; y++) {\n        // ignore any chunks which are already loaded\n        const pos = center.plus(new Vec3(x, 0, y).scaled(16))\n        if (!bot.world.getColumnAt(pos)) chunkPosToCheck.add(pos.toString())\n      }\n    }\n\n    if (chunkPosToCheck.size) {\n      return new Promise((resolve, reject) => {\n        const timeout = setTimeout(() => {\n          bot.world.off('chunkColumnLoad', waitForLoadEvents)\n          reject(new Error(`Timeout waiting for ${chunkPosToCheck.size} chunks to load after 10000ms`))\n        }, 10000)\n\n        function waitForLoadEvents (columnCorner) {\n          chunkPosToCheck.delete(columnCorner.toString())\n          if (chunkPosToCheck.size === 0) { // no chunks left to find\n            clearTimeout(timeout)\n            bot.world.off('chunkColumnLoad', waitForLoadEvents) // remove this listener instance\n            resolve()\n          }\n        }\n\n        // begin listening for remaining chunks to load\n        bot.world.on('chunkColumnLoad', waitForLoadEvents)\n      })\n    }\n  }\n\n  function getMatchingFunction (matching) {\n    if (typeof (matching) !== 'function') {\n      if (!Array.isArray(matching)) {\n        matching = [matching]\n      }\n      return isMatchingType\n    }\n    return matching\n\n    function isMatchingType (block) {\n      return block === null ? false : matching.indexOf(block.type) >= 0\n    }\n  }\n\n  function isBlockInSection (section, matcher) {\n    if (!section) return false // section is empty, skip it (yay!)\n    // If the chunk use a palette we can speed up the search by first\n    // checking the palette which usually contains less than 20 ids\n    // vs checking the 4096 block of the section. If we don't have a\n    // match in the palette, we can skip this section.\n    if (section.palette) {\n      for (const stateId of section.palette) {\n        if (matcher(Block.fromStateId(stateId, 0))) {\n          return true // the block is in the palette\n        }\n      }\n      return false // skip\n    }\n    return true // global palette, the block might be in there\n  }\n\n  function getFullMatchingFunction (matcher, useExtraInfo) {\n    if (typeof (useExtraInfo) === 'boolean') {\n      return fullSearchMatcher\n    }\n\n    return nonFullSearchMatcher\n\n    function nonFullSearchMatcher (point) {\n      const block = blockAt(point, true)\n      return matcher(block) && useExtraInfo(block)\n    }\n\n    function fullSearchMatcher (point) {\n      return matcher(bot.blockAt(point, useExtraInfo))\n    }\n  }\n\n  bot.findBlocks = (options) => {\n    const matcher = getMatchingFunction(options.matching)\n    const point = (options.point || bot.entity.position).floored()\n    const maxDistance = options.maxDistance || 16\n    const count = options.count || 1\n    const useExtraInfo = options.useExtraInfo || false\n    const fullMatcher = getFullMatchingFunction(matcher, useExtraInfo)\n    const start = new Vec3(Math.floor(point.x / 16), Math.floor(point.y / 16), Math.floor(point.z / 16))\n    const it = new OctahedronIterator(start, Math.ceil((maxDistance + 8) / 16))\n    // the octahedron iterator can sometime go through the same section again\n    // we use a set to keep track of visited sections\n    const visitedSections = new Set()\n\n    let blocks = []\n    let startedLayer = 0\n    let next = start\n    while (next) {\n      const column = bot.world.getColumn(next.x, next.z)\n      const sectionY = next.y + Math.abs(bot.game.minY >> 4)\n      const totalSections = bot.game.height >> 4\n      if (sectionY >= 0 && sectionY < totalSections && column && !visitedSections.has(next.toString())) {\n        const section = column.sections[sectionY]\n        if (useExtraInfo === true || isBlockInSection(section, matcher)) {\n          const begin = new Vec3(next.x * 16, sectionY * 16 + bot.game.minY, next.z * 16)\n          const cursor = begin.clone()\n          const end = cursor.offset(16, 16, 16)\n          for (cursor.x = begin.x; cursor.x < end.x; cursor.x++) {\n            for (cursor.y = begin.y; cursor.y < end.y; cursor.y++) {\n              for (cursor.z = begin.z; cursor.z < end.z; cursor.z++) {\n                if (fullMatcher(cursor) && cursor.distanceTo(point) <= maxDistance) blocks.push(cursor.clone())\n              }\n            }\n          }\n        }\n        visitedSections.add(next.toString())\n      }\n      // If we started a layer, we have to finish it otherwise we might miss closer blocks\n      if (startedLayer !== it.apothem && blocks.length >= count) {\n        break\n      }\n      startedLayer = it.apothem\n      next = it.next()\n    }\n    blocks.sort((a, b) => {\n      return a.distanceTo(point) - b.distanceTo(point)\n    })\n    // We found more blocks than needed, shorten the array to not confuse people\n    if (blocks.length > count) {\n      blocks = blocks.slice(0, count)\n    }\n    return blocks\n  }\n\n  function findBlock (options) {\n    const blocks = bot.findBlocks(options)\n    if (blocks.length === 0) return null\n    return bot.blockAt(blocks[0])\n  }\n\n  function blockAt (absolutePoint, extraInfos = true) {\n    const block = bot.world.getBlock(absolutePoint)\n    // null block means chunk not loaded\n    if (!block) return null\n\n    if (extraInfos) {\n      block.painting = paintingsByPos[block.position]\n    }\n\n    return block\n  }\n\n  // if passed in block is within line of sight to the bot, returns true\n  // also works on anything with a position value\n  function canSeeBlock (block) {\n    const headPos = bot.entity.position.offset(0, bot.entity.eyeHeight, 0)\n    const range = headPos.distanceTo(block.position)\n    const dir = block.position.offset(0.5, 0.5, 0.5).minus(headPos)\n    const match = (inputBlock, iter) => {\n      const intersect = iter.intersect(inputBlock.shapes, inputBlock.position)\n      if (intersect) { return true }\n      return block.position.equals(inputBlock.position)\n    }\n    const blockAtCursor = bot.world.raycast(headPos, dir.normalize(), range, match)\n    return blockAtCursor && blockAtCursor.position.equals(block.position)\n  }\n\n  bot._client.on('unload_chunk', (packet) => {\n    delColumn(packet.chunkX, packet.chunkZ)\n  })\n\n  function updateBlockState (point, stateId) {\n    const oldBlock = blockAt(point)\n    bot.world.setBlockStateId(point, stateId)\n\n    const newBlock = blockAt(point)\n    // sometimes minecraft server sends us block updates before it sends\n    // us the column that the block is in. ignore this.\n    if (newBlock === null) {\n      return\n    }\n    if (oldBlock.type !== newBlock.type) {\n      const pos = point.floored()\n      const painting = paintingsByPos[pos]\n      if (painting) deletePainting(painting)\n    }\n  }\n\n  bot._client.on('update_light', (packet) => {\n    let column = bot.world.getColumn(packet.chunkX, packet.chunkZ)\n    if (!column) {\n      column = new Chunk({ minY: bot.game.minY, worldHeight: bot.game.height })\n      bot.world.setColumn(packet.chunkX, packet.chunkZ, column)\n    }\n\n    if (bot.supportFeature('newLightingDataFormat')) {\n      column.loadParsedLight(packet.skyLight, packet.blockLight, packet.skyLightMask, packet.blockLightMask, packet.emptySkyLightMask, packet.emptyBlockLightMask)\n    } else {\n      column.loadLight(packet.data, packet.skyLightMask, packet.blockLightMask, packet.emptySkyLightMask, packet.emptyBlockLightMask)\n    }\n  })\n\n  // Chunk batches are used by the server to throttle the chunks per tick for players based on their connection speed.\n  let chunkBatchStartTime = 0\n  // The Vanilla client uses nano seconds with its weighted average starting at 2000000 converted to milliseconds that is 2\n  let weightedAverage = 2\n  // This is used for keeping track of the weight of the old average when updating it.\n  let oldSampleWeight = 1\n\n  bot._client.on('chunk_batch_start', (packet) => {\n    // Get the time the chunk batch is starting.\n    chunkBatchStartTime = Date.now()\n  })\n\n  bot._client.on('chunk_batch_finished', (packet) => {\n    const milliPerChunk = (Date.now() - chunkBatchStartTime) / packet.batchSize\n    // Prevents the MilliPerChunk from being hugely different then the average, Vanilla uses 3 as a constant here.\n    const clampedMilliPerChunk = Math.min(Math.max(milliPerChunk, weightedAverage / 3.0), weightedAverage * 3.0)\n    weightedAverage = ((weightedAverage * oldSampleWeight) + clampedMilliPerChunk) / (oldSampleWeight + 1)\n    // 49 is used in Vanilla client to limit it to 50 samples\n    oldSampleWeight = Math.min(49, oldSampleWeight + 1)\n    bot._client.write('chunk_batch_received', {\n      // Vanilla uses 7000000 as a constant here, since we are using milliseconds that is now 7. Not sure why they pick this constant to convert from nano seconds per chunk to chunks per tick.\n      chunksPerTick: 7 / weightedAverage\n    })\n  })\n  bot._client.on('map_chunk', (packet) => {\n    addColumn({\n      x: packet.x,\n      z: packet.z,\n      bitMap: packet.bitMap,\n      heightmaps: packet.heightmaps,\n      biomes: packet.biomes,\n      skyLightSent: bot.game.dimension === 'overworld',\n      groundUp: packet.groundUp,\n      data: packet.chunkData,\n      trustEdges: packet.trustEdges,\n      skyLightMask: packet.skyLightMask,\n      blockLightMask: packet.blockLightMask,\n      emptySkyLightMask: packet.emptySkyLightMask,\n      emptyBlockLightMask: packet.emptyBlockLightMask,\n      skyLight: packet.skyLight,\n      blockLight: packet.blockLight\n    })\n\n    if (typeof packet.blockEntities !== 'undefined') {\n      const column = bot.world.getColumn(packet.x, packet.z)\n      if (!column) {\n        if (!hideErrors) console.warn('Ignoring block entities as chunk failed to load at', packet.x, packet.z)\n        return\n      }\n      for (const blockEntity of packet.blockEntities) {\n        if (blockEntity.x !== undefined) { // 1.17+\n          column.setBlockEntity(blockEntity, blockEntity.nbtData)\n        } else {\n          const pos = new Vec3(blockEntity.value.x.value & 0xf, blockEntity.value.y.value, blockEntity.value.z.value & 0xf)\n          column.setBlockEntity(pos, blockEntity)\n        }\n      }\n    }\n  })\n\n  bot._client.on('map_chunk_bulk', (packet) => {\n    let offset = 0\n    let meta\n    let i\n    let size\n    for (i = 0; i < packet.meta.length; ++i) {\n      meta = packet.meta[i]\n      size = (8192 + (packet.skyLightSent ? 2048 : 0)) *\n        onesInShort(meta.bitMap) + // block ids\n        2048 * onesInShort(meta.bitMap) + // (two bytes per block id)\n        256 // biomes\n      addColumn({\n        x: meta.x,\n        z: meta.z,\n        bitMap: meta.bitMap,\n        heightmaps: packet.heightmaps,\n        skyLightSent: packet.skyLightSent,\n        groundUp: true,\n        data: packet.data.slice(offset, offset + size)\n      })\n      offset += size\n    }\n\n    assert.strictEqual(offset, packet.data.length)\n  })\n\n  bot._client.on('multi_block_change', (packet) => {\n    // multi block change\n    for (let i = 0; i < packet.records.length; ++i) {\n      const record = packet.records[i]\n\n      let blockX, blockY, blockZ\n      if (bot.supportFeature('usesMultiblockSingleLong')) {\n        blockZ = (record >> 4) & 0x0f\n        blockX = (record >> 8) & 0x0f\n        blockY = record & 0x0f\n      } else {\n        blockZ = record.horizontalPos & 0x0f\n        blockX = (record.horizontalPos >> 4) & 0x0f\n        blockY = record.y\n      }\n\n      let pt\n      if (bot.supportFeature('usesMultiblock3DChunkCoords')) {\n        pt = new Vec3(packet.chunkCoordinates.x, packet.chunkCoordinates.y, packet.chunkCoordinates.z)\n      } else {\n        pt = new Vec3(packet.chunkX, 0, packet.chunkZ)\n      }\n\n      pt = pt.scale(16).offset(blockX, blockY, blockZ)\n\n      if (bot.supportFeature('usesMultiblockSingleLong')) {\n        updateBlockState(pt, record >> 12)\n      } else {\n        updateBlockState(pt, record.blockId)\n      }\n    }\n  })\n\n  bot._client.on('block_change', (packet) => {\n    const pt = new Vec3(packet.location.x, packet.location.y, packet.location.z)\n    updateBlockState(pt, packet.type)\n  })\n\n  bot._client.on('explosion', (packet) => {\n    // explosion\n    const p = new Vec3(packet.x, packet.y, packet.z)\n    if (packet.affectedBlockOffsets) {\n      // TODO: server no longer sends in 1.21.3. Is client supposed to compute this or is it sent via normal block updates?\n      packet.affectedBlockOffsets.forEach((offset) => {\n        const pt = p.offset(offset.x, offset.y, offset.z)\n        updateBlockState(pt, 0)\n      })\n    }\n  })\n\n  bot._client.on('spawn_entity_painting', (packet) => {\n    const pos = new Vec3(packet.location.x, packet.location.y, packet.location.z)\n    const painting = new Painting(packet.entityId,\n      pos, packet.title, paintingFaceToVec[packet.direction])\n    addPainting(painting)\n  })\n\n  bot._client.on('entity_destroy', (packet) => {\n    // destroy entity\n    packet.entityIds.forEach((id) => {\n      const painting = paintingsById[id]\n      if (painting) deletePainting(painting)\n    })\n  })\n\n  bot._client.on('update_sign', (packet) => {\n    const pos = new Vec3(packet.location.x & 0xf, packet.location.y, packet.location.z & 0xf)\n\n    // TODO: warn if out of loaded world?\n    const column = bot.world.getColumn(packet.location.x >> 4, packet.location.z >> 4)\n    if (!column) {\n      return\n    }\n\n    const blockAt = column.getBlock(pos)\n\n    blockAt.signText = [packet.text1, packet.text2, packet.text3, packet.text4].map(text => {\n      if (text === 'null' || text === '') return ''\n      return JSON.parse(text)\n    })\n    column.setBlock(pos, blockAt)\n  })\n\n  bot._client.on('tile_entity_data', (packet) => {\n    if (packet.location !== undefined) {\n      const column = bot.world.getColumn(packet.location.x >> 4, packet.location.z >> 4)\n      if (!column) return\n      const pos = new Vec3(packet.location.x & 0xf, packet.location.y, packet.location.z & 0xf)\n      column.setBlockEntity(pos, packet.nbtData)\n    } else {\n      const tag = packet.nbtData\n      const column = bot.world.getColumn(tag.value.x.value >> 4, tag.value.z.value >> 4)\n      if (!column) return\n      const pos = new Vec3(tag.value.x.value & 0xf, tag.value.y.value, tag.value.z.value & 0xf)\n      column.setBlockEntity(pos, tag)\n    }\n  })\n\n  bot.updateSign = (block, text, back = false) => {\n    const lines = text.split('\\n')\n    if (lines.length > 4) {\n      bot.emit('error', new Error('too many lines for sign text'))\n      return\n    }\n\n    for (let i = 0; i < lines.length; ++i) {\n      if (lines[i].length > 45) {\n        bot.emit('error', new Error('Signs have a maximum of 45 characters per line'))\n        return\n      }\n    }\n\n    let signData\n    if (bot.supportFeature('sendStringifiedSignText')) {\n      signData = {\n        text1: lines[0] ? JSON.stringify(lines[0]) : '\"\"',\n        text2: lines[1] ? JSON.stringify(lines[1]) : '\"\"',\n        text3: lines[2] ? JSON.stringify(lines[2]) : '\"\"',\n        text4: lines[3] ? JSON.stringify(lines[3]) : '\"\"'\n      }\n    } else {\n      signData = {\n        text1: lines[0] ?? '',\n        text2: lines[1] ?? '',\n        text3: lines[2] ?? '',\n        text4: lines[3] ?? ''\n      }\n    }\n\n    bot._client.write('update_sign', {\n      location: block.position,\n      isFrontText: !back,\n      ...signData\n    })\n  }\n\n  // if we get a respawn packet and the dimension is changed,\n  // unload all chunks from memory.\n  let dimension\n  let worldName\n  function dimensionToFolderName (dimension) {\n    if (bot.supportFeature('dimensionIsAnInt')) {\n      return dimensionNames[dimension]\n    } else if (bot.supportFeature('dimensionIsAString') || bot.supportFeature('dimensionIsAWorld')) {\n      return worldName\n    }\n  }\n  // only exposed for testing\n  bot._getDimensionName = () => worldName\n\n  async function switchWorld () {\n    if (bot.world) {\n      if (storageBuilder) {\n        await bot.world.async.waitSaving()\n      }\n\n      for (const [name, listener] of Object.entries(bot._events)) {\n        if (name.startsWith('blockUpdate:') && typeof listener === 'function') {\n          bot.emit(name, null, null)\n          bot.off(name, listener)\n        }\n      }\n\n      for (const [x, z] of Object.keys(bot.world.async.columns).map(key => key.split(',').map(x => parseInt(x, 10)))) {\n        bot.world.unloadColumn(x, z)\n      }\n\n      if (storageBuilder) {\n        bot.world.async.storageProvider = storageBuilder({ version: bot.version, worldName: dimensionToFolderName(dimension) })\n      }\n    } else {\n      bot.world = new World(null, storageBuilder ? storageBuilder({ version: bot.version, worldName: dimensionToFolderName(dimension) }) : null).sync\n      startListenerProxy()\n    }\n  }\n\n  bot._client.on('login', (packet) => {\n    if (bot.supportFeature('dimensionIsAnInt')) {\n      dimension = packet.dimension\n      worldName = dimensionToFolderName(dimension)\n    } else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+\n      dimension = packet.worldState.dimension\n      worldName = packet.worldState.name\n    } else {\n      dimension = packet.dimension\n      worldName = /^minecraft:.+/.test(packet.worldName) ? packet.worldName : `minecraft:${packet.worldName}`\n    }\n    switchWorld()\n  })\n\n  bot._client.on('respawn', (packet) => {\n    if (bot.supportFeature('dimensionIsAnInt')) { // <=1.15.2\n      if (dimension === packet.dimension) return\n      dimension = packet.dimension\n    } else if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5+\n      if (dimension === packet.worldState.dimension) return\n      if (worldName === packet.worldState.name && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true\n      dimension = packet.worldState.dimension\n      worldName = packet.worldState.name\n    } else { // >= 1.15.2\n      if (dimension === packet.dimension) return\n      if (worldName === packet.worldName && packet.copyMetadata === true) return // don't unload chunks if in same world and metaData is true\n      // Metadata is true when switching dimensions however, then the world name is different\n      dimension = packet.dimension\n      worldName = packet.worldName\n    }\n    switchWorld()\n  })\n\n  let listener\n  let listenerRemove\n  function startListenerProxy () {\n    if (listener) {\n      // custom forwarder for custom events\n      bot.off('newListener', listener)\n      bot.off('removeListener', listenerRemove)\n    }\n    // standardized forwarding\n    const forwardedEvents = ['blockUpdate', 'chunkColumnLoad', 'chunkColumnUnload']\n    for (const event of forwardedEvents) {\n      bot.world.on(event, (...args) => bot.emit(event, ...args))\n    }\n    const blockUpdateRegex = /blockUpdate:\\(-?\\d+, -?\\d+, -?\\d+\\)/\n    listener = (event, listener) => {\n      if (blockUpdateRegex.test(event)) {\n        bot.world.on(event, listener)\n      }\n    }\n    listenerRemove = (event, listener) => {\n      if (blockUpdateRegex.test(event)) {\n        bot.world.off(event, listener)\n      }\n    }\n    bot.on('newListener', listener)\n    bot.on('removeListener', listenerRemove)\n  }\n\n  bot.findBlock = findBlock\n  bot.canSeeBlock = canSeeBlock\n  bot.blockAt = blockAt\n  bot._updateBlockState = updateBlockState\n  bot.waitForChunksToLoad = waitForChunksToLoad\n}\n\nfunction onesInShort (n) {\n  n = n & 0xffff\n  let count = 0\n  for (let i = 0; i < 16; ++i) {\n    count = ((1 << i) & n) ? count + 1 : count\n  }\n  return count\n}\n"
  },
  {
    "path": "lib/plugins/book.js",
    "content": "const assert = require('assert')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n\n  let editBook\n  if (bot.supportFeature('editBookIsPluginChannel')) {\n    bot._client.registerChannel('MC|BEdit', 'slot')\n    bot._client.registerChannel('MC|BSign', 'slot')\n    editBook = (book, pages, title, slot, signing = false) => {\n      if (signing) bot._client.writeChannel('MC|BSign', Item.toNotch(book))\n      else bot._client.writeChannel('MC|BEdit', Item.toNotch(book))\n    }\n  } else if (bot.supportFeature('hasEditBookPacket')) {\n    if (bot.supportFeature('editBookPacketUsesNbt')) { // 1.13 - 1.17\n      editBook = (book, pages, title, slot, signing = false, hand = 0) => {\n        bot._client.write('edit_book', {\n          hand: slot,\n          pages,\n          title\n        })\n      }\n    } else { // 1.18+\n      editBook = (book, pages, title, slot, signing = false, hand = 0) => {\n        bot._client.write('edit_book', {\n          new_book: Item.toNotch(book),\n          signing,\n          hand\n        })\n      }\n    }\n  }\n\n  async function write (slot, pages, author, title, signing) {\n    assert.ok(slot >= 0 && slot <= 44, 'slot out of inventory range')\n    const book = bot.inventory.slots[slot]\n    assert.ok(book && book.type === bot.registry.itemsByName.writable_book.id, `no book found in slot ${slot}`)\n    const quickBarSlot = bot.quickBarSlot\n    const moveToQuickBar = slot < 36\n\n    if (moveToQuickBar) {\n      await bot.moveSlotItem(slot, 36)\n    }\n\n    bot.setQuickBarSlot(moveToQuickBar ? 0 : slot - 36)\n\n    const modifiedBook = await modifyBook(moveToQuickBar ? 36 : slot, pages, author, title, signing)\n    editBook(modifiedBook, pages, title, moveToQuickBar ? 0 : slot - 36, signing)\n    await once(bot.inventory, `updateSlot:${moveToQuickBar ? 36 : slot}`)\n\n    bot.setQuickBarSlot(quickBarSlot)\n\n    if (moveToQuickBar) {\n      await bot.moveSlotItem(36, slot)\n    }\n  }\n\n  function modifyBook (slot, pages, author, title, signing) {\n    const book = Object.assign({}, bot.inventory.slots[slot])\n    if (!book.nbt || book.nbt.type !== 'compound') {\n      book.nbt = {\n        type: 'compound',\n        name: '',\n        value: {}\n      }\n    }\n    if (signing) {\n      if (bot.supportFeature('clientUpdateBookIdWhenSign')) {\n        book.type = bot.registry.itemsByName.written_book.id\n      }\n      book.nbt.value.author = {\n        type: 'string',\n        value: author\n      }\n      book.nbt.value.title = {\n        type: 'string',\n        value: title\n      }\n    }\n    book.nbt.value.pages = {\n      type: 'list',\n      value: {\n        type: 'string',\n        value: pages\n      }\n    }\n    bot.inventory.updateSlot(slot, book)\n    return book\n  }\n\n  bot.writeBook = async (slot, pages) => {\n    await write(slot, pages, null, null, false)\n  }\n\n  bot.signBook = async (slot, pages, author, title) => {\n    await write(slot, pages, author, title, true)\n  }\n}\n"
  },
  {
    "path": "lib/plugins/boss_bar.js",
    "content": "module.exports = inject\n\nfunction inject (bot, { version }) {\n  const BossBar = require('../bossbar')(bot.registry)\n  const bars = {}\n\n  function extractTitle (title) {\n    if (!title) return ''\n    if (typeof title === 'string') return title\n    // Return the original object for BossBar to handle\n    return title\n  }\n\n  function handleBossBarPacket (packet) {\n    if (packet.action === 0) {\n      bars[packet.entityUUID] = new BossBar(\n        packet.entityUUID,\n        extractTitle(packet.title),\n        packet.health,\n        packet.dividers,\n        packet.color,\n        packet.flags\n      )\n      bot.emit('bossBarCreated', bars[packet.entityUUID])\n    } else if (packet.action === 1) {\n      bot.emit('bossBarDeleted', bars[packet.entityUUID])\n      delete bars[packet.entityUUID]\n    } else {\n      if (!(packet.entityUUID in bars)) {\n        return\n      }\n      if (packet.action === 2 && packet.health !== undefined) {\n        bars[packet.entityUUID].health = packet.health\n      }\n      if (packet.action === 3 && packet.title !== undefined) {\n        bars[packet.entityUUID].title = extractTitle(packet.title)\n      }\n      if (packet.action === 4) {\n        if (packet.dividers !== undefined) {\n          bars[packet.entityUUID].dividers = packet.dividers\n        }\n        if (packet.color !== undefined) {\n          bars[packet.entityUUID].color = packet.color\n        }\n      }\n      if (packet.action === 5 && packet.flags !== undefined) {\n        bars[packet.entityUUID].flags = packet.flags\n      }\n      bot.emit('bossBarUpdated', bars[packet.entityUUID])\n    }\n  }\n\n  // Handle all possible packet names\n  bot._client.on('boss_bar', handleBossBarPacket)\n  bot._client.on('bossbar', handleBossBarPacket)\n  bot._client.on('boss_bar_update', handleBossBarPacket)\n\n  Object.defineProperty(bot, 'bossBars', {\n    get () {\n      return Object.values(bars)\n    }\n  })\n}\n"
  },
  {
    "path": "lib/plugins/breath.js",
    "content": "module.exports = inject\r\n\r\nfunction inject (bot) {\r\n  if (bot.supportFeature('mcDataHasEntityMetadata')) {\r\n    // this is handled inside entities.js. We don't yet have entity metadataKeys for all versions but once we do\r\n    // we can delete the numerical checks here and in entities.js https://github.com/extremeheat/mineflayer/blob/eb9982aa04973b0086aac68a2847005d77f01a3d/lib/plugins/entities.js#L469\r\n    return\r\n  }\r\n  bot._client.on('entity_metadata', (packet) => {\r\n    if (!bot.entity) return\r\n    if (bot.entity.id !== packet.entityId) return\r\n    for (const metadata of packet.metadata) {\r\n      if (metadata.key === 1) {\r\n        bot.oxygenLevel = Math.round(metadata.value / 15)\r\n        bot.emit('breath')\r\n      }\r\n    }\r\n  })\r\n}\r\n"
  },
  {
    "path": "lib/plugins/chat.js",
    "content": "const { onceWithCleanup } = require('../promise_utils')\n\nconst USERNAME_REGEX = '(?:\\\\(.{1,15}\\\\)|\\\\[.{1,15}\\\\]|.){0,5}?(\\\\w+)'\nconst LEGACY_VANILLA_CHAT_REGEX = new RegExp(`^${USERNAME_REGEX}\\\\s?[>:\\\\-»\\\\]\\\\)~]+\\\\s(.*)$`)\n\nmodule.exports = inject\n\nfunction inject (bot, options) {\n  const CHAT_LENGTH_LIMIT = options.chatLengthLimit ?? (bot.supportFeature('lessCharsInChat') ? 100 : 256)\n  const defaultChatPatterns = options.defaultChatPatterns ?? true\n\n  const ChatMessage = require('prismarine-chat')(bot.registry)\n  // chat.pattern.type will emit an event for bot.on() of the same type, eg chatType = whisper will trigger bot.on('whisper')\n  const _patterns = {}\n  let _length = 0\n  // deprecated\n  bot.chatAddPattern = (patternValue, typeValue) => {\n    return bot.addChatPattern(typeValue, patternValue, { deprecated: true })\n  }\n\n  bot.addChatPatternSet = (name, patterns, opts = {}) => {\n    if (!patterns.every(p => p instanceof RegExp)) throw new Error('Pattern parameter should be of type RegExp')\n    const { repeat = true, parse = false } = opts\n    _patterns[_length++] = {\n      name,\n      patterns,\n      position: 0,\n      matches: [],\n      messages: [],\n      repeat,\n      parse\n    }\n    return _length\n  }\n\n  bot.addChatPattern = (name, pattern, opts = {}) => {\n    if (!(pattern instanceof RegExp)) throw new Error('Pattern parameter should be of type RegExp')\n    const { repeat = true, deprecated = false, parse = false } = opts\n    _patterns[_length] = {\n      name,\n      patterns: [pattern],\n      position: 0,\n      matches: [],\n      messages: [],\n      deprecated,\n      repeat,\n      parse\n    }\n    return _length++ // increment length after we give it back to the user\n  }\n\n  bot.removeChatPattern = name => {\n    if (typeof name === 'number') {\n      _patterns[name] = undefined\n    } else {\n      const matchingPatterns = Object.entries(_patterns).filter(pattern => pattern[1]?.name === name)\n      matchingPatterns.forEach(([indexString]) => {\n        _patterns[+indexString] = undefined\n      })\n    }\n  }\n\n  function findMatchingPatterns (msg) {\n    const found = []\n    for (const [indexString, pattern] of Object.entries(_patterns)) {\n      if (!pattern) continue\n      const { position, patterns } = pattern\n      if (patterns[position].test(msg)) {\n        found.push(+indexString)\n      }\n    }\n    return found\n  }\n\n  bot.on('messagestr', (msg, _, originalMsg) => {\n    const foundPatterns = findMatchingPatterns(msg)\n\n    for (const ix of foundPatterns) {\n      _patterns[ix].matches.push(msg)\n      _patterns[ix].messages.push(originalMsg)\n      _patterns[ix].position++\n\n      if (_patterns[ix].deprecated) {\n        const [, ...matches] = _patterns[ix].matches[0].match(_patterns[ix].patterns[0])\n        bot.emit(_patterns[ix].name, ...matches, _patterns[ix].messages[0].translate, ..._patterns[ix].messages)\n        _patterns[ix].messages = [] // clear out old messages\n      } else { // regular parsing\n        if (_patterns[ix].patterns.length > _patterns[ix].matches.length) return // we have all the matches, so we can emit the done event\n        if (_patterns[ix].parse) {\n          const matches = _patterns[ix].patterns.map((pattern, i) => {\n            const [, ...matches] = _patterns[ix].matches[i].match(pattern) // delete full message match\n            return matches\n          })\n          bot.emit(`chat:${_patterns[ix].name}`, matches)\n        } else {\n          bot.emit(`chat:${_patterns[ix].name}`, _patterns[ix].matches)\n        }\n        // these are possibly null-ish if the user deletes them as soon as the event for the match is emitted\n      }\n      if (_patterns[ix]?.repeat) {\n        _patterns[ix].position = 0\n        _patterns[ix].matches = []\n      } else {\n        _patterns[ix] = undefined\n      }\n    }\n  })\n\n  addDefaultPatterns()\n\n  bot._client.on('playerChat', (data) => {\n    const message = data.formattedMessage\n    const verified = data.verified\n    let msg\n    if (bot.supportFeature('clientsideChatFormatting')) {\n      const parameters = {\n        sender: data.senderName ? JSON.parse(data.senderName) : undefined,\n        target: data.targetName ? JSON.parse(data.targetName) : undefined,\n        content: message ? JSON.parse(message) : { text: data.plainMessage }\n      }\n      const registryIndex = data.type.chatType != null ? data.type.chatType : data.type\n      msg = ChatMessage.fromNetwork(registryIndex, parameters)\n\n      if (data.unsignedContent) {\n        msg.unsigned = ChatMessage.fromNetwork(registryIndex, { sender: parameters.sender, target: parameters.target, content: JSON.parse(data.unsignedContent) })\n      }\n    } else {\n      msg = ChatMessage.fromNotch(message)\n    }\n    bot.emit('message', msg, 'chat', data.sender, verified)\n    bot.emit('messagestr', msg.toString(), 'chat', msg, data.sender, verified)\n  })\n\n  bot._client.on('systemChat', (data) => {\n    const msg = ChatMessage.fromNotch(data.formattedMessage)\n    const chatPositions = {\n      1: 'system',\n      2: 'game_info'\n    }\n    bot.emit('message', msg, chatPositions[data.positionId], null)\n    bot.emit('messagestr', msg.toString(), chatPositions[data.positionId], msg, null)\n    if (data.positionId === 2) bot.emit('actionBar', msg, null)\n  })\n\n  function chatWithHeader (header, message) {\n    if (typeof message === 'number') message = message.toString()\n    if (typeof message !== 'string') {\n      throw new Error('Chat message type must be a string or number: ' + typeof message)\n    }\n\n    if (!header && message.startsWith('/')) {\n      // Do not try and split a command without a header\n      bot._client.chat(message)\n      return\n    }\n\n    const lengthLimit = CHAT_LENGTH_LIMIT - header.length\n    message.split('\\n').forEach((subMessage) => {\n      if (!subMessage) return\n      let i\n      let smallMsg\n      for (i = 0; i < subMessage.length; i += lengthLimit) {\n        smallMsg = header + subMessage.substring(i, i + lengthLimit)\n        bot._client.chat(smallMsg)\n      }\n    })\n  }\n\n  async function tabComplete (text, assumeCommand = false, sendBlockInSight = true, timeout = 5000) {\n    let position\n\n    if (sendBlockInSight) {\n      const block = bot.blockAtCursor()\n\n      if (block) {\n        position = block.position\n      }\n    }\n\n    bot._client.write('tab_complete', {\n      text,\n      assumeCommand,\n      lookedAtBlock: position\n    })\n\n    const [packet] = await onceWithCleanup(bot._client, 'tab_complete', { timeout })\n    return packet.matches\n  }\n\n  bot.whisper = (username, message) => {\n    chatWithHeader(`/tell ${username} `, message)\n  }\n  bot.chat = (message) => {\n    chatWithHeader('', message)\n  }\n\n  bot.tabComplete = tabComplete\n\n  function addDefaultPatterns () {\n    // 1.19 changes the chat format to move <sender> prefix from message contents to a separate field.\n    // TODO: new chat lister to handle this\n    if (!defaultChatPatterns) return\n    bot.addChatPattern('whisper', new RegExp(`^${USERNAME_REGEX} whispers(?: to you)?:? (.*)$`), { deprecated: true })\n    bot.addChatPattern('whisper', new RegExp(`^\\\\[${USERNAME_REGEX} -> \\\\w+\\\\s?\\\\] (.*)$`), { deprecated: true })\n    bot.addChatPattern('chat', LEGACY_VANILLA_CHAT_REGEX, { deprecated: true })\n  }\n\n  function awaitMessage (...args) {\n    const timeout = typeof args[args.length - 1] === 'number' ? args.pop() : 20000\n    return new Promise((resolve, reject) => {\n      const resolveMessages = args.flatMap(x => x)\n      const timeoutHandle = setTimeout(() => {\n        bot.off('messagestr', messageListener)\n        reject(new Error(`Timeout waiting for message after ${timeout}ms`))\n      }, timeout)\n\n      function messageListener (msg) {\n        if (resolveMessages.some(x => x instanceof RegExp ? x.test(msg) : msg === x)) {\n          clearTimeout(timeoutHandle)\n          resolve(msg)\n          bot.off('messagestr', messageListener)\n        }\n      }\n      bot.on('messagestr', messageListener)\n    })\n  }\n  bot.awaitMessage = awaitMessage\n}\n"
  },
  {
    "path": "lib/plugins/chest.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const allowedWindowTypes = ['minecraft:generic', 'minecraft:chest', 'minecraft:dispenser', 'minecraft:ender_chest', 'minecraft:shulker_box', 'minecraft:hopper', 'minecraft:container', 'minecraft:dropper', 'minecraft:trapped_chest', 'minecraft:barrel', 'minecraft:white_shulker_box', 'minecraft:orange_shulker_box', 'minecraft:magenta_shulker_box', 'minecraft:light_blue_shulker_box', 'minecraft:yellow_shulker_box', 'minecraft:lime_shulker_box', 'minecraft:pink_shulker_box', 'minecraft:gray_shulker_box', 'minecraft:light_gray_shulker_box', 'minecraft:cyan_shulker_box', 'minecraft:purple_shulker_box', 'minecraft:blue_shulker_box', 'minecraft:brown_shulker_box', 'minecraft:green_shulker_box', 'minecraft:red_shulker_box', 'minecraft:black_shulker_box']\n  function matchWindowType (window) {\n    for (const type of allowedWindowTypes) {\n      if (window.type.startsWith(type)) return true\n    }\n    return false\n  }\n\n  async function openContainer (containerToOpen, direction, cursorPos) {\n    direction = direction ?? new Vec3(0, 1, 0)\n    cursorPos = cursorPos ?? new Vec3(0.5, 0.5, 0.5)\n    let chest\n    if (containerToOpen.constructor.name === 'Block' && allowedWindowTypes.map(name => name.replace('minecraft:', '')).includes(containerToOpen.name)) {\n      chest = await bot.openBlock(containerToOpen, direction, cursorPos)\n    } else if (containerToOpen.constructor.name === 'Entity') {\n      chest = await bot.openEntity(containerToOpen)\n    } else {\n      throw new Error('containerToOpen is neither a block nor an entity')\n    }\n\n    if (!matchWindowType(chest)) { throw new Error('Non-container window used as a container: ' + JSON.stringify(chest)) }\n    return chest\n  }\n\n  bot.openContainer = openContainer\n  bot.openChest = openContainer\n  bot.openDispenser = openContainer\n}\n"
  },
  {
    "path": "lib/plugins/command_block.js",
    "content": "const assert = require('assert')\nconst { ProtoDef } = require('protodef')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  function setCommandBlock (pos, command, options = {}) {\n    assert.strictEqual(bot.player.gamemode, 1, new Error('The bot has to be in creative mode to open the command block window'))\n    assert.notStrictEqual(pos, null)\n    assert.notStrictEqual(command, null)\n    assert.strictEqual(bot.blockAt(pos).name.includes('command_block'), true, new Error(\"The block isn't a command block\"))\n\n    // Default values when a command block is placed in vanilla minecraft\n    options.trackOutput = options.trackOutput ?? false\n    options.conditional = options.conditional ?? false\n    options.alwaysActive = options.alwaysActive ?? false\n    options.mode = options.mode ?? 2 // Possible values: 0: SEQUENCE, 1: AUTO and 2: REDSTONE\n\n    let flags = 0\n    flags |= +options.trackOutput << 0 // 0x01\n    flags |= +options.conditional << 1 // 0x02\n    flags |= +options.alwaysActive << 2 // 0x04\n\n    if (bot.supportFeature('usesAdvCmd') || bot.supportFeature('usesAdvCdm')) {\n      const pluginChannelName = bot.supportFeature('usesAdvCdm') ? 'MC|AdvCdm' : 'MC|AdvCmd'\n\n      const proto = new ProtoDef()\n\n      proto.addType('string', [\n        'pstring',\n        {\n          countType: 'varint'\n        }])\n\n      proto.addType(pluginChannelName, [\n        'container',\n        [\n          {\n            name: 'mode',\n            type: 'i8'\n          },\n          {\n            name: 'x',\n            type: [\n              'switch',\n              {\n                compareTo: 'mode',\n                fields: {\n                  0: 'i32'\n                },\n                default: 'void'\n              }\n            ]\n          },\n          {\n            name: 'y',\n            type: [\n              'switch',\n              {\n                compareTo: 'mode',\n                fields: {\n                  0: 'i32'\n                },\n                default: 'void'\n              }\n            ]\n          },\n          {\n            name: 'z',\n            type: [\n              'switch',\n              {\n                compareTo: 'mode',\n                fields: {\n                  0: 'i32'\n                },\n                default: 'void'\n              }\n            ]\n          },\n          {\n            name: 'eid',\n            type: [\n              'switch',\n              {\n                compareTo: 'mode',\n                fields: {\n                  1: 'i32'\n                },\n                default: 'void'\n              }\n            ]\n          },\n          {\n            name: 'command',\n            type: 'string'\n          },\n          {\n            name: 'trackOutput',\n            type: 'bool'\n          }\n        ]\n      ])\n\n      const buffer = proto.createPacketBuffer(pluginChannelName, {\n        mode: 0,\n        x: pos.x,\n        y: pos.y,\n        z: pos.z,\n        command,\n        trackOutput: options.trackOutput\n      })\n      bot._client.write('custom_payload', {\n        channel: pluginChannelName,\n        data: buffer\n      })\n    } else {\n      bot._client.write('update_command_block', {\n        location: pos,\n        command,\n        mode: options.mode,\n        flags\n      })\n    }\n  }\n\n  bot.setCommandBlock = setCommandBlock\n}\n"
  },
  {
    "path": "lib/plugins/craft.js",
    "content": "const assert = require('assert')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n  const Recipe = require('prismarine-recipe')(bot.registry).Recipe\n  let windowCraftingTable\n\n  async function craft (recipe, count, craftingTable) {\n    assert.ok(recipe)\n    count = parseInt(count ?? 1, 10)\n    if (recipe.requiresTable && !craftingTable) {\n      throw new Error('Recipe requires craftingTable, but one was not supplied: ' + JSON.stringify(recipe))\n    }\n\n    try {\n      for (let i = 0; i < count; i++) {\n        await craftOnce(recipe, craftingTable)\n      }\n\n      if (windowCraftingTable) {\n        bot.closeWindow(windowCraftingTable)\n        windowCraftingTable = undefined\n      }\n    } catch (err) {\n      if (windowCraftingTable) {\n        bot.closeWindow(windowCraftingTable)\n        windowCraftingTable = undefined\n      }\n      throw new Error(err)\n    }\n  }\n\n  async function craftOnce (recipe, craftingTable) {\n    if (craftingTable) {\n      if (!windowCraftingTable) {\n        bot.activateBlock(craftingTable)\n        const [window] = await once(bot, 'windowOpen')\n        windowCraftingTable = window\n      }\n      if (!windowCraftingTable.type.startsWith('minecraft:crafting')) {\n        throw new Error('crafting: non craftingTable used as craftingTable: ' + windowCraftingTable.type)\n      }\n      await startClicking(windowCraftingTable, 3, 3)\n    } else {\n      await startClicking(bot.inventory, 2, 2)\n    }\n\n    async function startClicking (window, w, h) {\n      const extraSlots = unusedRecipeSlots()\n      let ingredientIndex = 0\n      let originalSourceSlot = null\n      let it\n      if (recipe.inShape) {\n        it = {\n          x: 0,\n          y: 0,\n          row: recipe.inShape[0]\n        }\n        await clickShape()\n      } else {\n        await nextIngredientsClick()\n      }\n\n      function incrementShapeIterator () {\n        it.x += 1\n        if (it.x >= it.row.length) {\n          it.y += 1\n          if (it.y >= recipe.inShape.length) return null\n          it.x = 0\n          it.row = recipe.inShape[it.y]\n        }\n        return it\n      }\n\n      async function nextShapeClick () {\n        if (incrementShapeIterator()) {\n          await clickShape()\n        } else if (!recipe.ingredients) {\n          await putMaterialsAway()\n        } else {\n          await nextIngredientsClick()\n        }\n      }\n\n      async function clickShape () {\n        const destSlot = slot(it.x, it.y)\n        const ingredient = it.row[it.x]\n        if (ingredient.id === -1) return nextShapeClick()\n        if (!window.selectedItem || window.selectedItem.type !== ingredient.id ||\n          (ingredient.metadata != null &&\n            window.selectedItem.metadata !== ingredient.metadata)) {\n          // we are not holding the item we need. click it.\n          const sourceItem = window.findInventoryItem(ingredient.id, ingredient.metadata)\n          if (!sourceItem) throw new Error('missing ingredient')\n          if (originalSourceSlot == null) originalSourceSlot = sourceItem.slot\n          await bot.clickWindow(sourceItem.slot, 0, 0)\n        }\n        await bot.clickWindow(destSlot, 1, 0)\n        await nextShapeClick()\n      }\n\n      async function nextIngredientsClick () {\n        const ingredient = recipe.ingredients[ingredientIndex]\n        const destSlot = extraSlots.pop()\n        if (!window.selectedItem || window.selectedItem.type !== ingredient.id ||\n          (ingredient.metadata != null &&\n            window.selectedItem.metadata !== ingredient.metadata)) {\n          // we are not holding the item we need. click it.\n          const sourceItem = window.findInventoryItem(ingredient.id, ingredient.metadata)\n          if (!sourceItem) throw new Error('missing ingredient')\n          if (originalSourceSlot == null) originalSourceSlot = sourceItem.slot\n          await bot.clickWindow(sourceItem.slot, 0, 0)\n        }\n        await bot.clickWindow(destSlot, 1, 0)\n        if (++ingredientIndex < recipe.ingredients.length) {\n          await nextIngredientsClick()\n        } else {\n          await putMaterialsAway()\n        }\n      }\n\n      async function putMaterialsAway () {\n        const start = window.inventoryStart\n        const end = window.inventoryEnd\n        await bot.putSelectedItemRange(start, end, window, originalSourceSlot)\n        await grabResult()\n      }\n\n      async function grabResult () {\n        assert.strictEqual(window.selectedItem, null)\n        // Causes a double-emit on 1.12+ --nickelpro\n        // put the recipe result in the output\n        const item = new Item(recipe.result.id, recipe.result.count, recipe.result.metadata)\n        window.updateSlot(0, item)\n        await bot.putAway(0)\n        await updateOutShape()\n      }\n\n      async function updateOutShape () {\n        if (!recipe.outShape) {\n          for (let i = 1; i <= w * h; i++) {\n            window.updateSlot(i, null)\n          }\n          return\n        }\n        const slotsToClick = []\n        for (let y = 0; y < recipe.outShape.length; ++y) {\n          const row = recipe.outShape[y]\n          for (let x = 0; x < row.length; ++x) {\n            const _slot = slot(x, y)\n            let item = null\n            if (row[x].id !== -1) {\n              item = new Item(row[x].id, row[x].count, row[x].metadata || null)\n              slotsToClick.push(_slot)\n            }\n            window.updateSlot(_slot, item)\n          }\n        }\n        for (const _slot of slotsToClick) {\n          await bot.putAway(_slot)\n        }\n      }\n\n      function slot (x, y) {\n        return 1 + x + w * y\n      }\n\n      function unusedRecipeSlots () {\n        const result = []\n        let x\n        let y\n        let row\n        if (recipe.inShape) {\n          for (y = 0; y < recipe.inShape.length; ++y) {\n            row = recipe.inShape[y]\n            for (x = 0; x < row.length; ++x) {\n              if (row[x].id === -1) result.push(slot(x, y))\n            }\n            for (; x < w; ++x) {\n              result.push(slot(x, y))\n            }\n          }\n          for (; y < h; ++y) {\n            for (x = 0; x < w; ++x) {\n              result.push(slot(x, y))\n            }\n          }\n        } else {\n          for (y = 0; y < h; ++y) {\n            for (x = 0; x < w; ++x) {\n              result.push(slot(x, y))\n            }\n          }\n        }\n        return result\n      }\n    }\n  }\n\n  function recipesFor (itemType, metadata, minResultCount, craftingTable) {\n    minResultCount = minResultCount ?? 1\n    const results = []\n    Recipe.find(itemType, metadata).forEach((recipe) => {\n      if (requirementsMetForRecipe(recipe, minResultCount, craftingTable)) {\n        results.push(recipe)\n      }\n    })\n    return results\n  }\n\n  function recipesAll (itemType, metadata, craftingTable) {\n    const results = []\n    Recipe.find(itemType, metadata).forEach((recipe) => {\n      if (!recipe.requiresTable || craftingTable) {\n        results.push(recipe)\n      }\n    })\n    return results\n  }\n\n  function requirementsMetForRecipe (recipe, minResultCount, craftingTable) {\n    if (recipe.requiresTable && !craftingTable) return false\n\n    // how many times we have to perform the craft to achieve minResultCount\n    const craftCount = Math.ceil(minResultCount / recipe.result.count)\n\n    // false if not enough inventory to make all the ones that we want\n    for (let i = 0; i < recipe.delta.length; ++i) {\n      const d = recipe.delta[i]\n      if (bot.inventory.count(d.id, d.metadata) + d.count * craftCount < 0) return false\n    }\n\n    // otherwise true\n    return true\n  }\n\n  bot.craft = craft\n  bot.recipesFor = recipesFor\n  bot.recipesAll = recipesAll\n}\n"
  },
  {
    "path": "lib/plugins/creative.js",
    "content": "const assert = require('assert')\nconst { Vec3 } = require('vec3')\nconst { sleep, onceWithCleanup } = require('../promise_utils')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n\n  // these features only work when you are in creative mode.\n  bot.creative = {\n    setInventorySlot,\n    flyTo,\n    startFlying,\n    stopFlying,\n    clearSlot: slotNum => setInventorySlot(slotNum, null),\n    clearInventory\n  }\n\n  const creativeSlotsUpdates = []\n\n  // WARN: This method should not be called twice on the same slot before first promise succeeds\n  async function setInventorySlot (slot, item, waitTimeout = 400) {\n    assert(slot >= 0 && slot <= 44)\n\n    if (Item.equal(bot.inventory.slots[slot], item, true)) return\n    if (creativeSlotsUpdates[slot]) {\n      throw new Error(`Setting slot ${slot} cancelled due to calling bot.creative.setInventorySlot(${slot}, ...) again`)\n    }\n    creativeSlotsUpdates[slot] = true\n    bot._client.write('set_creative_slot', {\n      slot,\n      item: Item.toNotch(item)\n    })\n\n    if (bot.supportFeature('noAckOnCreateSetSlotPacket')) {\n      // No ack\n      bot._setSlot(slot, item)\n      if (waitTimeout === 0) return // no wait\n      // allow some time to see if server rejects\n      return new Promise((resolve, reject) => {\n        function updateSlot (oldItem, newItem) {\n          if (newItem.itemId !== item.itemId) {\n            creativeSlotsUpdates[slot] = false\n            reject(Error('Server rejected'))\n          }\n        }\n        bot.inventory.once(`updateSlot:${slot}`, updateSlot)\n        setTimeout(() => {\n          bot.inventory.off(`updateSlot:${slot}`, updateSlot)\n          creativeSlotsUpdates[slot] = false\n          resolve()\n        }, waitTimeout)\n      })\n    }\n\n    await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, {\n      timeout: 5000,\n      checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata\n    })\n    creativeSlotsUpdates[slot] = false\n  }\n\n  async function clearInventory () {\n    return Promise.all(bot.inventory.slots.filter(item => item).map(item => setInventorySlot(item.slot, null)))\n  }\n\n  let normalGravity = null\n  const flyingSpeedPerUpdate = 0.5\n\n  // straight line, so make sure there's a clear path.\n  async function flyTo (destination) {\n    // TODO: consider sending 0x13\n    startFlying()\n\n    let vector = destination.minus(bot.entity.position)\n    let magnitude = vecMagnitude(vector)\n\n    while (magnitude > flyingSpeedPerUpdate) {\n      bot.physics.gravity = 0\n      bot.entity.velocity = new Vec3(0, 0, 0)\n\n      // small steps\n      const normalizedVector = vector.scaled(1 / magnitude)\n      bot.entity.position.add(normalizedVector.scaled(flyingSpeedPerUpdate))\n\n      await sleep(50)\n\n      vector = destination.minus(bot.entity.position)\n      magnitude = vecMagnitude(vector)\n    }\n\n    // last step\n    bot.entity.position = destination\n    await once(bot, 'move', /* no timeout */ 0)\n  }\n\n  function startFlying () {\n    if (normalGravity == null) normalGravity = bot.physics.gravity\n    bot.physics.gravity = 0\n  }\n\n  function stopFlying () {\n    bot.physics.gravity = normalGravity\n  }\n}\n\n// this should be in the vector library\nfunction vecMagnitude (vec) {\n  return Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z)\n}\n"
  },
  {
    "path": "lib/plugins/digging.js",
    "content": "const { performance } = require('perf_hooks')\nconst { createDoneTask, createTask } = require('../promise_utils')\nconst BlockFaces = require('prismarine-world').iterators.BlockFace\nconst { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  let swingInterval = null\n  let waitTimeout = null\n\n  let diggingTask = createDoneTask()\n\n  bot.targetDigBlock = null\n  bot.targetDigFace = null\n  bot.lastDigTime = null\n\n  async function dig (block, forceLook, digFace) {\n    if (block === null || block === undefined) {\n      throw new Error('dig was called with an undefined or null block')\n    }\n\n    if (!digFace || typeof digFace === 'function') {\n      digFace = 'auto'\n    }\n\n    const waitTime = bot.digTime(block)\n    if (waitTime === Infinity) {\n      throw new Error(`dig time for ${block?.name ?? block} is Infinity`)\n    }\n\n    bot.targetDigFace = 1 // Default (top)\n\n    if (forceLook !== 'ignore') {\n      if (digFace?.x || digFace?.y || digFace?.z) {\n        // Determine the block face the bot should mine\n        if (digFace.x) {\n          bot.targetDigFace = digFace.x > 0 ? BlockFaces.EAST : BlockFaces.WEST\n        } else if (digFace.y) {\n          bot.targetDigFace = digFace.y > 0 ? BlockFaces.TOP : BlockFaces.BOTTOM\n        } else if (digFace.z) {\n          bot.targetDigFace = digFace.z > 0 ? BlockFaces.SOUTH : BlockFaces.NORTH\n        }\n        await bot.lookAt(\n          block.position.offset(0.5, 0.5, 0.5).offset(digFace.x * 0.5, digFace.y * 0.5, digFace.z * 0.5),\n          forceLook\n        )\n      } else if (digFace === 'raycast') {\n        // Check faces that could be seen from the current position. If the delta is smaller then 0.5 that means the\n        // bot can most likely not see the face as the block is 1 block thick\n        // this could be false for blocks that have a smaller bounding box than 1x1x1\n        const dx = bot.entity.position.x - (block.position.x + 0.5)\n        const dy = bot.entity.position.y + bot.entity.eyeHeight - (block.position.y + 0.5)\n        const dz = bot.entity.position.z - (block.position.z + 0.5)\n        // Check y first then x and z\n        const visibleFaces = {\n          y: Math.sign(Math.abs(dy) > 0.5 ? dy : 0),\n          x: Math.sign(Math.abs(dx) > 0.5 ? dx : 0),\n          z: Math.sign(Math.abs(dz) > 0.5 ? dz : 0)\n        }\n        const validFaces = []\n        const closerBlocks = []\n        for (const i in visibleFaces) {\n          if (!visibleFaces[i]) continue // skip as this face is not visible\n          // target position on the target block face. -> 0.5 + (current face) * 0.5\n          const targetPos = block.position.offset(\n            0.5 + (i === 'x' ? visibleFaces[i] * 0.5 : 0),\n            0.5 + (i === 'y' ? visibleFaces[i] * 0.5 : 0),\n            0.5 + (i === 'z' ? visibleFaces[i] * 0.5 : 0)\n          )\n          const startPos = bot.entity.position.offset(0, bot.entity.eyeHeight, 0)\n          const rayBlock = bot.world.raycast(startPos, targetPos.clone().subtract(startPos).normalize(), 5)\n          if (rayBlock) {\n            if (startPos.distanceTo(rayBlock.intersect) < startPos.distanceTo(targetPos)) {\n              // Block is closer then the raycasted block\n              closerBlocks.push(rayBlock)\n              // continue since if distance is ever less, then we did not intersect the block we wanted,\n              // meaning that the position of the intersected block is not what we want.\n              continue\n            }\n            const rayPos = rayBlock.position\n            if (\n              rayPos.x === block.position.x &&\n              rayPos.y === block.position.y &&\n              rayPos.z === block.position.z\n            ) {\n              validFaces.push({\n                face: rayBlock.face,\n                targetPos: rayBlock.intersect\n              })\n            }\n          }\n        }\n\n        if (validFaces.length > 0) {\n          // Chose closest valid face\n          let closest\n          let distSqrt = 999\n          for (const i in validFaces) {\n            const tPos = validFaces[i].targetPos\n            const cDist = new Vec3(tPos.x, tPos.y, tPos.z).distanceSquared(\n              bot.entity.position.offset(0, bot.entity.eyeHeight, 0)\n            )\n            if (distSqrt > cDist) {\n              closest = validFaces[i]\n              distSqrt = cDist\n            }\n          }\n          await bot.lookAt(closest.targetPos, forceLook)\n          bot.targetDigFace = closest.face\n        } else if (closerBlocks.length === 0 && block.shapes.length === 0) {\n          // no other blocks were detected and the block has no shapes.\n          // The block in question is replaceable (like tall grass) so we can just dig it\n          // TODO: do AABB + ray intercept check to this position for digFace.\n          await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), forceLook)\n        } else {\n          // Block is obstructed return error?\n          throw new Error('Block not in view')\n        }\n      } else {\n        await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), forceLook)\n      }\n    }\n\n    // In vanilla the client will cancel digging the current block once the other block is at the crosshair.\n    // Todo: don't wait until lookAt is at middle of the block, but at the edge of it.\n    if (bot.targetDigBlock) bot.stopDigging()\n\n    diggingTask = createTask()\n    bot._client.write('block_dig', {\n      status: 0, // start digging\n      location: block.position,\n      face: bot.targetDigFace // default face is 1 (top)\n    })\n    waitTimeout = setTimeout(finishDigging, waitTime)\n    bot.targetDigBlock = block\n    bot.swingArm()\n\n    swingInterval = setInterval(() => {\n      bot.swingArm()\n    }, 350)\n\n    function finishDigging () {\n      clearInterval(swingInterval)\n      clearTimeout(waitTimeout)\n      swingInterval = null\n      waitTimeout = null\n      if (bot.targetDigBlock) {\n        bot._client.write('block_dig', {\n          status: 2, // finish digging\n          location: bot.targetDigBlock.position,\n          face: bot.targetDigFace // always the same as the start face\n        })\n      }\n      bot.targetDigBlock = null\n      bot.targetDigFace = null\n      bot.lastDigTime = performance.now()\n      bot._updateBlockState(block.position, 0)\n    }\n\n    const eventName = `blockUpdate:${block.position}`\n    bot.on(eventName, onBlockUpdate)\n\n    const currentBlock = block\n    bot.stopDigging = () => {\n      if (!bot.targetDigBlock) return\n\n      // Replicate the odd vanilla cancellation face value.\n      // When the cancellation is because of a new dig request on another block it's the same as the new dig start face. In all other cases it's 0.\n      const stoppedBecauseOfNewDigRequest = !currentBlock.position.equals(bot.targetDigBlock.position)\n      const cancellationDiggingFace = !stoppedBecauseOfNewDigRequest ? bot.targetDigFace : 0\n\n      bot.removeListener(eventName, onBlockUpdate)\n      clearInterval(swingInterval)\n      clearTimeout(waitTimeout)\n      swingInterval = null\n      waitTimeout = null\n      bot._client.write('block_dig', {\n        status: 1, // cancel digging\n        location: bot.targetDigBlock.position,\n        face: cancellationDiggingFace\n      })\n      const block = bot.targetDigBlock\n      bot.targetDigBlock = null\n      bot.targetDigFace = null\n      bot.lastDigTime = performance.now()\n      bot.emit('diggingAborted', block)\n      bot.stopDigging = noop\n      diggingTask.cancel(new Error('Digging aborted'))\n    }\n\n    function onBlockUpdate (oldBlock, newBlock) {\n      // vanilla server never actually interrupt digging, but some server send block update when you start digging\n      // so ignore block update if not air\n      // All block update listeners receive (null, null) when the world is unloaded. So newBlock can be null.\n      if (newBlock?.type !== 0) return\n      bot.removeListener(eventName, onBlockUpdate)\n      clearInterval(swingInterval)\n      clearTimeout(waitTimeout)\n      swingInterval = null\n      waitTimeout = null\n      bot.targetDigBlock = null\n      bot.targetDigFace = null\n      bot.lastDigTime = performance.now()\n      bot.emit('diggingCompleted', newBlock)\n      diggingTask.finish()\n    }\n\n    await diggingTask.promise\n  }\n\n  bot.on('death', () => {\n    bot.removeAllListeners('diggingAborted')\n    bot.removeAllListeners('diggingCompleted')\n    bot.stopDigging()\n  })\n\n  function canDigBlock (block) {\n    return (\n      block &&\n      block.diggable &&\n      block.position.offset(0.5, 0.5, 0.5).distanceTo(bot.entity.position.offset(0, 1.65, 0)) <= 5.1\n    )\n  }\n\n  function digTime (block) {\n    let type = null\n    let enchantments = []\n\n    // Retrieve currently held item ID and active enchantments from heldItem\n    const currentlyHeldItem = bot.heldItem\n    if (currentlyHeldItem) {\n      type = currentlyHeldItem.type\n      enchantments = currentlyHeldItem.enchants\n    }\n\n    // Append helmet enchantments (because Aqua Affinity actually affects dig speed)\n    const headEquipmentSlot = bot.getEquipmentDestSlot('head')\n    const headEquippedItem = bot.inventory.slots[headEquipmentSlot]\n    if (headEquippedItem) {\n      const helmetEnchantments = headEquippedItem.enchants\n      enchantments = enchantments.concat(helmetEnchantments)\n    }\n\n    const creative = bot.game.gameMode === 'creative'\n    return block.digTime(\n      type,\n      creative,\n      bot.entity.isInWater,\n      !bot.entity.onGround,\n      enchantments,\n      bot.entity.effects\n    )\n  }\n\n  bot.dig = dig\n  bot.stopDigging = noop\n  bot.canDigBlock = canDigBlock\n  bot.digTime = digTime\n}\n\nfunction noop (err) {\n  if (err) throw err\n}\n"
  },
  {
    "path": "lib/plugins/enchantment_table.js",
    "content": "const assert = require('assert')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  async function openEnchantmentTable (enchantmentTableBlock) {\n    assert.strictEqual(enchantmentTableBlock.name, 'enchanting_table')\n    let ready = false\n    const enchantmentTable = await bot.openBlock(enchantmentTableBlock)\n    if (!enchantmentTable.type.startsWith('minecraft:enchant')) {\n      throw new Error('Expected minecraft:enchant when opening table but got ' + enchantmentTable.type)\n    }\n\n    resetEnchantmentOptions()\n\n    enchantmentTable.enchant = enchant\n    enchantmentTable.takeTargetItem = takeTargetItem\n    enchantmentTable.putTargetItem = putTargetItem\n    enchantmentTable.putLapis = putLapis\n    enchantmentTable.targetItem = function () { return this.slots[0] }\n\n    bot._client.on('craft_progress_bar', onUpdateWindowProperty)\n    enchantmentTable.once('close', () => {\n      bot._client.removeListener('craft_progress_bar', onUpdateWindowProperty)\n    })\n\n    return enchantmentTable\n\n    function onUpdateWindowProperty (packet) {\n      if (packet.windowId !== enchantmentTable.id) return\n      assert.ok(packet.property >= 0)\n\n      const slots = enchantmentTable.enchantments\n\n      if (packet.property < 3) {\n        const slot = slots[packet.property]\n        slot.level = packet.value\n      } else if (packet.property === 3) {\n        enchantmentTable.xpseed = packet.value\n      } else if (packet.property < 7) {\n        const slot = slots[packet.property - 4]\n        slot.expected.enchant = packet.value\n      } else if (packet.property < 10) {\n        const slot = slots[packet.property - 7]\n        slot.expected.level = packet.value\n      }\n\n      if (slots[0].level >= 0 && slots[1].level >= 0 && slots[2].level >= 0) {\n        if (!ready) {\n          ready = true\n          enchantmentTable.emit('ready')\n        }\n      } else {\n        ready = false\n      }\n    }\n\n    function resetEnchantmentOptions () {\n      enchantmentTable.xpseed = -1\n      enchantmentTable.enchantments = []\n      for (let slot = 0; slot < 3; slot++) {\n        enchantmentTable.enchantments.push({\n          level: -1,\n          expected: {\n            enchant: -1,\n            level: -1\n          }\n        })\n      }\n      ready = false\n    }\n\n    async function enchant (choice) {\n      if (!ready) await once(enchantmentTable, 'ready')\n      choice = parseInt(choice, 10) // allow string argument\n      assert.notStrictEqual(enchantmentTable.enchantments[choice].level, -1)\n      bot._client.write('enchant_item', {\n        windowId: enchantmentTable.id,\n        enchantment: choice\n      })\n      const [, newItem] = await once(enchantmentTable, 'updateSlot:0')\n      return newItem\n    }\n\n    async function takeTargetItem () {\n      const item = enchantmentTable.targetItem()\n      assert.ok(item)\n      await bot.putAway(item.slot)\n      return item\n    }\n\n    async function putTargetItem (item) {\n      await bot.moveSlotItem(item.slot, 0)\n    }\n\n    async function putLapis (item) {\n      await bot.moveSlotItem(item.slot, 1)\n    }\n  }\n\n  bot.openEnchantmentTable = openEnchantmentTable\n}\n"
  },
  {
    "path": "lib/plugins/entities.js",
    "content": "const { Vec3 } = require('vec3')\nconst conv = require('../conversions')\n// These values are only accurate for versions 1.14 and above (crouch hitbox changes)\n// Todo: hitbox sizes for sleeping, swimming/crawling, and flying with elytra\nconst PLAYER_HEIGHT = 1.8\nconst CROUCH_HEIGHT = 1.5\nconst PLAYER_WIDTH = 0.6\nconst PLAYER_EYEHEIGHT = 1.62\nconst CROUCH_EYEHEIGHT = 1.27\n\nmodule.exports = inject\n\nconst animationEvents = {\n  0: 'entitySwingArm',\n  1: 'entityHurt',\n  2: 'entityWake',\n  3: 'entityEat',\n  4: 'entityCriticalEffect',\n  5: 'entityMagicCriticalEffect'\n}\n\nconst entityStatusEvents = {\n  2: 'entityHurt',\n  3: 'entityDead',\n  6: 'entityTaming',\n  7: 'entityTamed',\n  8: 'entityShakingOffWater',\n  10: 'entityEatingGrass',\n  55: 'entityHandSwap'\n}\n\nfunction inject (bot) {\n  const { mobs } = bot.registry\n  const Entity = require('prismarine-entity')(bot.version)\n  const Item = require('prismarine-item')(bot.version)\n  const ChatMessage = require('prismarine-chat')(bot.registry)\n\n  // ONLY 1.17 has this destroy_entity packet which is the same thing as entity_destroy packet except the entity is singular\n  // 1.17.1 reverted this change so this is just a simpler fix\n  bot._client.on('destroy_entity', (packet) => {\n    bot._client.emit('entity_destroy', { entityIds: [packet.entityId] })\n  })\n\n  bot.findPlayer = bot.findPlayers = (filter) => {\n    const filterFn = (entity) => {\n      if (entity.type !== 'player') return false\n      if (filter === null) return true\n      if (typeof filter === 'object' && filter instanceof RegExp) {\n        return entity.username.search(filter) !== -1\n      } else if (typeof filter === 'function') {\n        return filter(entity)\n      } else if (typeof filter === 'string') {\n        return entity.username.toLowerCase() === filter.toLowerCase()\n      }\n      return false\n    }\n    const resultSet = Object.values(bot.entities)\n      .filter(filterFn)\n\n    if (typeof filter === 'string') {\n      switch (resultSet.length) {\n        case 0:\n          return null\n        case 1:\n          return resultSet[0]\n        default:\n          return resultSet\n      }\n    }\n    return resultSet\n  }\n\n  bot.players = {}\n  bot.uuidToUsername = {}\n  bot.entities = {}\n\n  bot._playerFromUUID = (uuid) => Object.values(bot.players).find(player => player.uuid === uuid)\n\n  bot.nearestEntity = (match = (entity) => { return true }) => {\n    let best = null\n    let bestDistance = Number.MAX_VALUE\n\n    for (const entity of Object.values(bot.entities)) {\n      if (entity === bot.entity || !match(entity)) {\n        continue\n      }\n\n      const dist = bot.entity.position.distanceSquared(entity.position)\n      if (dist < bestDistance) {\n        best = entity\n        bestDistance = dist\n      }\n    }\n\n    return best\n  }\n\n  // Reset list of players and entities on login\n  bot._client.on('login', (packet) => {\n    bot.players = {}\n    bot.uuidToUsername = {}\n    bot.entities = {}\n    // login\n    bot.entity = fetchEntity(packet.entityId)\n    bot.username = bot._client.username\n    bot.entity.username = bot._client.username\n    bot.entity.type = 'player'\n    bot.entity.name = 'player'\n    bot.entity.height = PLAYER_HEIGHT\n    bot.entity.width = PLAYER_WIDTH\n    bot.entity.eyeHeight = PLAYER_EYEHEIGHT\n  })\n\n  bot._client.on('entity_equipment', (packet) => {\n    // entity equipment\n    const entity = fetchEntity(packet.entityId)\n    if (packet.equipments !== undefined) {\n      packet.equipments.forEach(equipment => entity.setEquipment(equipment.slot, equipment.item ? Item.fromNotch(equipment.item) : null))\n    } else {\n      entity.setEquipment(packet.slot, packet.item ? Item.fromNotch(packet.item) : null)\n    }\n    bot.emit('entityEquip', entity)\n  })\n\n  bot._client.on('bed', (packet) => {\n    // use bed\n    const entity = fetchEntity(packet.entityId)\n    entity.position.set(packet.location.x, packet.location.y, packet.location.z)\n    bot.emit('entitySleep', entity)\n  })\n\n  bot._client.on('animation', (packet) => {\n    // animation\n    const entity = fetchEntity(packet.entityId)\n    const eventName = animationEvents[packet.animation]\n    if (eventName) bot.emit(eventName, entity)\n  })\n\n  bot.on('entityCrouch', (entity) => {\n    entity.eyeHeight = CROUCH_EYEHEIGHT\n    entity.height = CROUCH_HEIGHT\n  })\n\n  bot.on('entityUncrouch', (entity) => {\n    entity.eyeHeight = PLAYER_EYEHEIGHT\n    entity.height = PLAYER_HEIGHT\n  })\n\n  bot._client.on('collect', (packet) => {\n    // collect item\n    const collector = fetchEntity(packet.collectorEntityId)\n    const collected = fetchEntity(packet.collectedEntityId)\n    bot.emit('playerCollect', collector, collected)\n  })\n\n  // What is internalId?\n  const entityDataByInternalId = Object.fromEntries(bot.registry.entitiesArray.map((e) => [e.internalId, e]))\n\n  function setEntityData (entity, type, entityData) {\n    entityData ??= entityDataByInternalId[type]\n    if (entityData) {\n      entity.type = entityData.type || 'object'\n      entity.displayName = entityData.displayName\n      entity.entityType = entityData.id\n      entity.name = entityData.name\n      entity.kind = entityData.category\n      entity.height = entityData.height\n      entity.width = entityData.width\n    } else {\n      // unknown entity\n      entity.type = 'other'\n      entity.entityType = type\n      entity.displayName = 'unknown'\n      entity.name = 'unknown'\n      entity.kind = 'unknown'\n    }\n  }\n\n  function updateEntityPos (entity, pos) {\n    if (bot.supportFeature('fixedPointPosition')) {\n      entity.position.set(pos.x / 32, pos.y / 32, pos.z / 32)\n    } else if (bot.supportFeature('doublePosition')) {\n      entity.position.set(pos.x, pos.y, pos.z)\n    }\n    entity.yaw = conv.fromNotchianYawByte(pos.yaw)\n    entity.pitch = conv.fromNotchianPitchByte(pos.pitch)\n  }\n\n  function addNewPlayer (entityId, uuid, pos) {\n    const entity = fetchEntity(entityId)\n    entity.type = 'player'\n    entity.name = 'player'\n    entity.username = bot.uuidToUsername[uuid]\n    entity.uuid = uuid\n    updateEntityPos(entity, pos)\n    entity.eyeHeight = PLAYER_EYEHEIGHT\n    entity.height = PLAYER_HEIGHT\n    entity.width = PLAYER_WIDTH\n    if (bot.players[entity.username] !== undefined && !bot.players[entity.username].entity) {\n      bot.players[entity.username].entity = entity\n    }\n    return entity\n  }\n\n  function addNewNonPlayer (entityId, uuid, entityType, pos) {\n    const entity = fetchEntity(entityId)\n    const entityData = bot.registry.entities[entityType]\n    setEntityData(entity, entityType, entityData)\n    updateEntityPos(entity, pos)\n    entity.uuid = uuid\n    return entity\n  }\n\n  bot._client.on('named_entity_spawn', (packet) => {\n    // in case player_info packet was not sent before named_entity_spawn : ignore named_entity_spawn (see #213)\n    if (packet.playerUUID in bot.uuidToUsername) {\n      // spawn named entity\n      const entity = addNewPlayer(packet.entityId, packet.playerUUID, packet, packet.metadata)\n      entity.dataBlobs = packet.data // this field doesn't appear to be listed on any version\n      entity.metadata = parseMetadata(packet.metadata, entity.metadata) // 1.8\n      bot.emit('entitySpawn', entity)\n    }\n  })\n\n  // spawn object/vehicle on versions < 1.19, on versions > 1.19 handles all non-player entities\n  // on versions >= 1.20.2, this also handles player entities\n  bot._client.on('spawn_entity', (packet) => {\n    const entityData = entityDataByInternalId[packet.type]\n    const entity = entityData?.type === 'player'\n      ? addNewPlayer(packet.entityId, packet.objectUUID, packet)\n      : addNewNonPlayer(packet.entityId, packet.objectUUID, packet.type, packet)\n    bot.emit('entitySpawn', entity)\n  })\n\n  // spawn_entity_experience_orb packet was removed in 1.21.5+\n  // XP orbs are now handled through the general spawn_entity packet\n  bot._client.on('spawn_entity_experience_orb', (packet) => {\n    const entity = fetchEntity(packet.entityId)\n    entity.type = 'orb'\n    entity.name = 'experience_orb'\n    entity.width = 0.5\n    entity.height = 0.5\n\n    if (bot.supportFeature('fixedPointPosition')) {\n      entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)\n    } else if (bot.supportFeature('doublePosition')) {\n      entity.position.set(packet.x, packet.y, packet.z)\n    }\n\n    entity.count = packet.count\n    bot.emit('entitySpawn', entity)\n  })\n\n  // This packet is removed since 1.19 and merged into spawn_entity\n  bot._client.on('spawn_entity_living', (packet) => {\n    // spawn mob\n    const entity = fetchEntity(packet.entityId)\n    entity.type = 'mob'\n    entity.uuid = packet.entityUUID\n    const entityData = mobs[packet.type]\n\n    setEntityData(entity, packet.type, entityData)\n\n    if (bot.supportFeature('fixedPointPosition')) {\n      entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)\n    } else if (bot.supportFeature('doublePosition')) {\n      entity.position.set(packet.x, packet.y, packet.z)\n    }\n\n    entity.yaw = conv.fromNotchianYawByte(packet.yaw)\n    entity.pitch = conv.fromNotchianPitchByte(packet.pitch)\n    entity.headPitch = conv.fromNotchianPitchByte(packet.headPitch)\n\n    let notchVel\n    if (bot.supportFeature('entityVelocityIsLpVec3')) {\n      notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)\n    } else {\n      notchVel = new Vec3(packet.velocityX, packet.velocityY, packet.velocityZ)\n    }\n    entity.velocity.update(conv.fromNotchVelocity(notchVel))\n    entity.metadata = parseMetadata(packet.metadata, entity.metadata)\n\n    bot.emit('entitySpawn', entity)\n  })\n\n  bot._client.on('entity_velocity', (packet) => {\n    // entity velocity\n    const entity = fetchEntity(packet.entityId)\n    let notchVel\n    if (bot.supportFeature('entityVelocityIsLpVec3')) {\n      notchVel = new Vec3(packet.velocity.x, packet.velocity.y, packet.velocity.z)\n    } else {\n      notchVel = new Vec3(packet.velocityX, packet.velocityY, packet.velocityZ)\n    }\n    entity.velocity.update(conv.fromNotchVelocity(notchVel))\n  })\n\n  bot._client.on('entity_destroy', (packet) => {\n    // destroy entity\n    packet.entityIds.forEach((id) => {\n      const entity = fetchEntity(id)\n      bot.emit('entityGone', entity)\n      entity.isValid = false\n      if (entity.username && bot.players[entity.username]) {\n        bot.players[entity.username].entity = null\n      }\n      delete bot.entities[id]\n    })\n  })\n\n  bot._client.on('rel_entity_move', (packet) => {\n    // entity relative move\n    const entity = fetchEntity(packet.entityId)\n    if (bot.supportFeature('fixedPointDelta')) {\n      entity.position.translate(packet.dX / 32, packet.dY / 32, packet.dZ / 32)\n    } else if (bot.supportFeature('fixedPointDelta128')) {\n      entity.position.translate(packet.dX / (128 * 32), packet.dY / (128 * 32), packet.dZ / (128 * 32))\n    }\n    bot.emit('entityMoved', entity)\n  })\n\n  bot._client.on('entity_look', (packet) => {\n    // entity look\n    const entity = fetchEntity(packet.entityId)\n    entity.yaw = conv.fromNotchianYawByte(packet.yaw)\n    entity.pitch = conv.fromNotchianPitchByte(packet.pitch)\n    bot.emit('entityMoved', entity)\n  })\n\n  bot._client.on('entity_move_look', (packet) => {\n    // entity look and relative move\n    const entity = fetchEntity(packet.entityId)\n    if (bot.supportFeature('fixedPointDelta')) {\n      entity.position.translate(packet.dX / 32, packet.dY / 32, packet.dZ / 32)\n    } else if (bot.supportFeature('fixedPointDelta128')) {\n      entity.position.translate(packet.dX / (128 * 32), packet.dY / (128 * 32), packet.dZ / (128 * 32))\n    }\n    entity.yaw = conv.fromNotchianYawByte(packet.yaw)\n    entity.pitch = conv.fromNotchianPitchByte(packet.pitch)\n    bot.emit('entityMoved', entity)\n  })\n\n  bot._client.on('entity_teleport', (packet) => {\n    // entity teleport\n    const entity = fetchEntity(packet.entityId)\n    if (bot.supportFeature('fixedPointPosition')) {\n      entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)\n    }\n    if (bot.supportFeature('doublePosition')) {\n      entity.position.set(packet.x, packet.y, packet.z)\n    }\n    entity.yaw = conv.fromNotchianYawByte(packet.yaw)\n    entity.pitch = conv.fromNotchianPitchByte(packet.pitch)\n    bot.emit('entityMoved', entity)\n  })\n\n  // 1.21.3 - merges the packets above\n  bot._client.on('sync_entity_position', (packet) => {\n    const entity = fetchEntity(packet.entityId)\n    entity.position.set(packet.x, packet.y, packet.z)\n    entity.velocity.set(packet.dx, packet.dy, packet.dz)\n    entity.yaw = packet.yaw\n    entity.pitch = packet.pitch\n    bot.emit('entityMoved', entity)\n  })\n\n  bot._client.on('entity_head_rotation', (packet) => {\n    // entity head look\n    const entity = fetchEntity(packet.entityId)\n    entity.headYaw = conv.fromNotchianYawByte(packet.headYaw)\n    bot.emit('entityMoved', entity)\n  })\n\n  bot._client.on('entity_status', (packet) => {\n    // entity status\n    const entity = fetchEntity(packet.entityId)\n    const eventName = entityStatusEvents[packet.entityStatus]\n\n    if (eventName === 'entityHandSwap' && entity.equipment) {\n      [entity.equipment[0], entity.equipment[1]] = [entity.equipment[1], entity.equipment[0]]\n      entity.heldItem = entity.equipment[0] // Update held item like prismarine-entity does upon equipment updates\n    }\n\n    if (eventName) bot.emit(eventName, entity)\n  })\n\n  bot._client.on('damage_event', (packet) => { // 1.20+\n    const entity = bot.entities[packet.entityId]\n    const source = bot.entities[packet.sourceCauseId - 1] // damage_event : SourceCauseId : The ID + 1 of the entity responsible for the damage, if present. If not present, the value is 0\n    bot.emit('entityHurt', entity, source)\n  })\n\n  bot._client.on('attach_entity', (packet) => {\n    // attach entity\n    const entity = fetchEntity(packet.entityId)\n    if (packet.vehicleId === -1) {\n      const vehicle = entity.vehicle\n      delete entity.vehicle\n      bot.emit('entityDetach', entity, vehicle)\n    } else {\n      entity.vehicle = fetchEntity(packet.vehicleId)\n      bot.emit('entityAttach', entity, entity.vehicle)\n    }\n  })\n\n  bot.fireworkRocketDuration = 0\n  function setElytraFlyingState (entity, elytraFlying) {\n    let startedFlying = false\n    if (elytraFlying) {\n      startedFlying = !entity.elytraFlying\n      entity.elytraFlying = true\n    } else if (entity.elytraFlying) {\n      entity.elytraFlying = false\n    }\n    if (bot.fireworkRocketDuration !== 0 && entity.id === bot.entity?.id && !elytraFlying) {\n      bot.fireworkRocketDuration = 0\n      knownFireworks.clear()\n    }\n\n    if (startedFlying) {\n      bot.emit('entityElytraFlew', entity)\n    }\n  }\n\n  const knownFireworks = new Set()\n  function handleBotUsedFireworkRocket (fireworkEntityId, fireworkInfo) {\n    if (knownFireworks.has(fireworkEntityId)) return\n    knownFireworks.add(fireworkEntityId)\n    let flightDur = fireworkInfo?.nbtData?.value?.Fireworks?.value?.Flight.value ?? 1\n    if (typeof flightDur !== 'number') { flightDur = 1 }\n    const baseDuration = 10 * (flightDur + 1)\n    const randomDuration = Math.floor(Math.random() * 6) + Math.floor(Math.random() * 7)\n    bot.fireworkRocketDuration = baseDuration + randomDuration\n\n    bot.emit('usedFirework', fireworkEntityId)\n  }\n\n  let fireworkEntityName\n  if (bot.supportFeature('fireworkNamePlural')) {\n    fireworkEntityName = 'fireworks_rocket'\n  } else if (bot.supportFeature('fireworkNameSingular')) {\n    fireworkEntityName = 'firework_rocket'\n  }\n\n  let fireworkMetadataIdx\n  let fireworkMetadataIsOpt\n  if (bot.supportFeature('fireworkMetadataVarInt7')) {\n    fireworkMetadataIdx = 7\n    fireworkMetadataIsOpt = false\n  } else if (bot.supportFeature('fireworkMetadataOptVarInt8')) {\n    fireworkMetadataIdx = 8\n    fireworkMetadataIsOpt = true\n  } else if (bot.supportFeature('fireworkMetadataOptVarInt9')) {\n    fireworkMetadataIdx = 9\n    fireworkMetadataIsOpt = true\n  }\n  const hasFireworkSupport = fireworkEntityName !== undefined && fireworkMetadataIdx !== undefined && fireworkMetadataIsOpt !== undefined\n\n  bot._client.on('entity_metadata', (packet) => {\n    // entity metadata\n    const entity = fetchEntity(packet.entityId)\n    const metadata = parseMetadata(packet.metadata, entity.metadata)\n    entity.metadata = metadata\n    bot.emit('entityUpdate', entity)\n\n    if (bot.supportFeature('mcDataHasEntityMetadata')) {\n      const metadataKeys = bot.registry.entitiesByName[entity.name]?.metadataKeys\n      const metas = metadataKeys ? Object.fromEntries(packet.metadata.map(e => [metadataKeys[e.key], e.value])) : {}\n      if (packet.metadata.some(m => m.type === 'item_stack')) {\n        bot.emit('itemDrop', entity)\n      }\n      if (metas.sleeping_pos || metas.pose === 2) {\n        bot.emit('entitySleep', entity)\n      }\n\n      if (hasFireworkSupport && fireworkEntityName === entity.name && metas.attached_to_target !== undefined) {\n        // fireworkMetadataOptVarInt9 and later is implied by\n        // mcDataHasEntityMetadata, so no need to check metadata index and type\n        // (eg fireworkMetadataOptVarInt8)\n        if (metas.attached_to_target !== 0) {\n          const entityId = metas.attached_to_target - 1\n          if (entityId === bot.entity?.id) {\n            handleBotUsedFireworkRocket(entity.id, metas.fireworks_item)\n          }\n        }\n      }\n\n      if (metas.shared_flags != null) {\n        if (bot.supportFeature('hasElytraFlying')) {\n          const elytraFlying = metas.shared_flags & 0x80\n          setElytraFlyingState(entity, Boolean(elytraFlying))\n        }\n\n        if (metas.shared_flags & 2) {\n          entity.crouching = true\n          bot.emit('entityCrouch', entity)\n        } else if (entity.crouching) { // prevent the initial entity_metadata packet from firing off an uncrouch event\n          entity.crouching = false\n          bot.emit('entityUncrouch', entity)\n        }\n      }\n\n      // Breathing (formerly in breath.js)\n      if (metas.air_supply != null) {\n        bot.oxygenLevel = Math.round(metas.air_supply / 15)\n        bot.emit('breath')\n      }\n    } else {\n      const typeSlot = (bot.supportFeature('itemsAreAlsoBlocks') ? 5 : 6) + (bot.supportFeature('entityMetadataHasLong') ? 1 : 0)\n      const slot = packet.metadata.find(e => e.type === typeSlot)\n      if (entity.name && (entity.name.toLowerCase() === 'item' || entity.name === 'item_stack') && slot) {\n        bot.emit('itemDrop', entity)\n      }\n\n      const typePose = bot.supportFeature('entityMetadataHasLong') ? 19 : 18\n      const pose = packet.metadata.find(e => e.type === typePose)\n      if (pose && pose.value === 2) {\n        bot.emit('entitySleep', entity)\n      }\n\n      if (hasFireworkSupport && fireworkEntityName === entity.name) {\n        const attachedToTarget = packet.metadata.find(e => e.key === fireworkMetadataIdx)\n        if (attachedToTarget !== undefined) {\n          let entityId\n          if (fireworkMetadataIsOpt) {\n            if (attachedToTarget.value !== 0) {\n              entityId = attachedToTarget.value - 1\n            } // else, not attached to an entity\n          } else {\n            entityId = attachedToTarget.value\n          }\n          if (entityId !== undefined && entityId === bot.entity?.id) {\n            const fireworksItem = packet.metadata.find(e => e.key === (fireworkMetadataIdx - 1))\n            handleBotUsedFireworkRocket(entity.id, fireworksItem?.value)\n          }\n        }\n      }\n\n      const bitField = packet.metadata.find(p => p.key === 0)\n      if (bitField !== undefined) {\n        if (bot.supportFeature('hasElytraFlying')) {\n          const elytraFlying = bitField.value & 0x80\n          setElytraFlyingState(entity, Boolean(elytraFlying))\n        }\n\n        if ((bitField.value & 2) !== 0) {\n          entity.crouching = true\n          bot.emit('entityCrouch', entity)\n        } else if (entity.crouching) { // prevent the initial entity_metadata packet from firing off an uncrouch event\n          entity.crouching = false\n          bot.emit('entityUncrouch', entity)\n        }\n      }\n    }\n  })\n\n  bot._client.on('entity_effect', (packet) => {\n    // entity effect\n    const entity = fetchEntity(packet.entityId)\n    const effect = {\n      id: packet.effectId,\n      amplifier: packet.amplifier,\n      duration: packet.duration\n    }\n    entity.effects[effect.id] = effect\n    bot.emit('entityEffect', entity, effect)\n  })\n\n  bot._client.on('remove_entity_effect', (packet) => {\n    // remove entity effect\n    const entity = fetchEntity(packet.entityId)\n    let effect = entity.effects[packet.effectId]\n    if (effect) {\n      delete entity.effects[effect.id]\n    } else {\n      // unknown effect\n      effect = {\n        id: packet.effectId,\n        amplifier: -1,\n        duration: -1\n      }\n    }\n    bot.emit('entityEffectEnd', entity, effect)\n  })\n\n  const updateAttributes = (packet) => {\n    const entity = fetchEntity(packet.entityId)\n    if (!entity.attributes) entity.attributes = {}\n    for (const prop of packet.properties) {\n      entity.attributes[prop.key] = {\n        value: prop.value,\n        modifiers: prop.modifiers\n      }\n    }\n    bot.emit('entityAttributes', entity)\n  }\n  bot._client.on('update_attributes', updateAttributes) // 1.8\n  bot._client.on('entity_update_attributes', updateAttributes) // others\n\n  bot._client.on('spawn_entity_weather', (packet) => {\n    // spawn global entity\n    const entity = fetchEntity(packet.entityId)\n    entity.type = 'global'\n    entity.globalType = 'thunderbolt'\n    entity.uuid = packet.entityUUID\n    entity.position.set(packet.x / 32, packet.y / 32, packet.z / 32)\n    bot.emit('entitySpawn', entity)\n  })\n\n  bot.on('spawn', () => {\n    bot.emit('entitySpawn', bot.entity)\n  })\n\n  function handlePlayerInfoBitfield (packet) {\n    for (const item of packet.data) {\n      let player = bot._playerFromUUID(item.uuid)\n      const newPlayer = !player\n\n      if (newPlayer) {\n        player = { uuid: item.uuid }\n      }\n\n      if (packet.action.add_player) {\n        player.username = item.player.name\n        player.displayName = new ChatMessage({ text: '', extra: [{ text: item.player.name }] })\n        player.skinData = extractSkinInformation(item.player.properties)\n      }\n      if (packet.action.initialize_chat && item.chatSession) {\n        player.chatSession = {\n          publicKey: item.chatSession.publicKey,\n          sessionUuid: item.chatSession.uuid\n        }\n      }\n      if (packet.action.update_game_mode) {\n        player.gamemode = item.gamemode\n      }\n      if (packet.action.update_listed) {\n        player.listed = item.listed\n      }\n      if (packet.action.update_latency) {\n        player.ping = item.latency\n      }\n      if (packet.action.update_display_name) {\n        player.displayName = item.displayName ? ChatMessage.fromNotch(item.displayName) : new ChatMessage({ text: '', extra: [{ text: player.username }] })\n      }\n\n      if (newPlayer) {\n        if (!player.username) continue // Should be unreachable if add_player is always sent for new players\n        bot.players[player.username] = player\n        bot.uuidToUsername[player.uuid] = player.username\n      }\n\n      const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === player.username)\n      player.entity = playerEntity\n\n      if (playerEntity === bot.entity) {\n        bot.player = player\n      }\n\n      if (newPlayer) {\n        bot.emit('playerJoined', player)\n      } else {\n        bot.emit('playerUpdated', player)\n      }\n    }\n  }\n\n  function handlePlayerInfoLegacy (packet) {\n    for (const item of packet.data) {\n      let player = bot._playerFromUUID(item.uuid)\n\n      switch (packet.action) {\n        case 'add_player': {\n          const newPlayer = !player\n          if (newPlayer) {\n            player = bot.players[item.name] = {\n              username: item.name,\n              uuid: item.uuid\n            }\n            bot.uuidToUsername[item.uuid] = item.name\n          }\n\n          player.ping = item.ping\n          player.gamemode = item.gamemode\n          player.displayName = item.displayName ? ChatMessage.fromNotch(item.displayName) : new ChatMessage({ text: '', extra: [{ text: item.name }] })\n          if (item.properties) {\n            player.skinData = extractSkinInformation(item.properties)\n          }\n          if (item.crypto) {\n            player.profileKeys = {\n              publicKey: item.crypto.publicKey,\n              signature: item.crypto.signature\n            }\n          }\n\n          const playerEntity = Object.values(bot.entities).find(e => e.type === 'player' && e.username === item.name)\n          player.entity = playerEntity\n          if (playerEntity === bot.entity) {\n            bot.player = player\n          }\n\n          if (newPlayer) bot.emit('playerJoined', player)\n          else bot.emit('playerUpdated', player)\n          break\n        }\n        case 'update_gamemode': {\n          if (player) {\n            player.gamemode = item.gamemode\n            bot.emit('playerUpdated', player)\n          }\n          break\n        }\n        case 'update_latency': {\n          if (player) {\n            player.ping = item.ping\n            bot.emit('playerUpdated', player)\n          }\n          break\n        }\n        case 'update_display_name': {\n          if (player) {\n            player.displayName = item.displayName ? ChatMessage.fromNotch(item.displayName) : new ChatMessage({ text: '', extra: [{ text: player.username }] })\n            bot.emit('playerUpdated', player)\n          }\n          break\n        }\n        case 'remove_player': {\n          if (player) {\n            if (player.entity === bot.entity) continue\n            player.entity = null\n            delete bot.players[player.username]\n            delete bot.uuidToUsername[item.uuid]\n            bot.emit('playerLeft', player)\n          }\n          break\n        }\n      }\n    }\n  }\n\n  bot._client.on('player_info', bot.supportFeature('playerInfoActionIsBitfield') ? handlePlayerInfoBitfield : handlePlayerInfoLegacy)\n\n  // 1.19.3+ - player(s) leave the game\n  bot._client.on('player_remove', (packet) => {\n    for (const uuid of packet.players) {\n      const player = bot._playerFromUUID(uuid)\n      if (!player || player.entity === bot.entity) continue\n\n      player.entity = null\n      delete bot.players[player.username]\n      delete bot.uuidToUsername[uuid]\n      bot.emit('playerLeft', player)\n    }\n  })\n\n  // attaching to a vehicle\n  bot._client.on('attach_entity', (packet) => {\n    const passenger = fetchEntity(packet.entityId)\n    const vehicle = packet.vehicleId === -1 ? null : fetchEntity(packet.vehicleId)\n\n    const originalVehicle = passenger.vehicle\n    if (originalVehicle) {\n      const index = originalVehicle.passengers.indexOf(passenger)\n      originalVehicle.passengers.splice(index, 1)\n    }\n    passenger.vehicle = vehicle\n    if (vehicle) {\n      vehicle.passengers.push(passenger)\n    }\n\n    if (packet.entityId === bot.entity.id) {\n      const vehicle = bot.vehicle\n      if (packet.vehicleId === -1) {\n        bot.vehicle = null\n        bot.emit('dismount', vehicle)\n      } else {\n        bot.vehicle = bot.entities[packet.vehicleId]\n        bot.emit('mount')\n      }\n    }\n  })\n\n  bot._client.on('set_passengers', ({ entityId, passengers }) => {\n    const passengerEntities = passengers.map((passengerId) => fetchEntity(passengerId))\n    const vehicle = entityId === -1 ? null : bot.entities[entityId]\n\n    for (const passengerEntity of passengerEntities) {\n      const originalVehicle = passengerEntity.vehicle\n      if (originalVehicle) {\n        const index = originalVehicle.passengers.indexOf(passengerEntity)\n        originalVehicle.passengers.splice(index, 1)\n      }\n      passengerEntity.vehicle = vehicle\n      if (vehicle) {\n        vehicle.passengers.push(passengerEntity)\n      }\n    }\n\n    if (passengers.includes(bot.entity.id)) {\n      const originalVehicle = bot.vehicle\n      if (entityId === -1) {\n        bot.vehicle = null\n        bot.emit('dismount', originalVehicle)\n      } else {\n        bot.vehicle = bot.entities[entityId]\n        bot.emit('mount')\n      }\n    }\n  })\n\n  // dismounting when the vehicle is gone\n  bot._client.on('entityGone', (entity) => {\n    if (bot.vehicle === entity) {\n      bot.vehicle = null\n      bot.emit('dismount', (entity))\n    }\n    if (entity.passengers) {\n      for (const passenger of entity.passengers) {\n        passenger.vehicle = null\n      }\n    }\n    if (entity.vehicle) {\n      const index = entity.vehicle.passengers.indexOf(entity)\n      if (index !== -1) {\n        entity.vehicle.passengers.splice(index, 1)\n      }\n    }\n  })\n\n  bot.swingArm = swingArm\n  bot.attack = attack\n  bot.mount = mount\n  bot.dismount = dismount\n  bot.useOn = useOn\n  bot.moveVehicle = moveVehicle\n\n  function swingArm (arm = 'right', showHand = true) {\n    const hand = arm === 'right' ? 0 : 1\n    const packet = {}\n    if (showHand) packet.hand = hand\n    bot._client.write('arm_animation', packet)\n  }\n\n  function useOn (target) {\n    // TODO: check if not crouching will make make this action always use the item\n    useEntity(target, 0)\n  }\n\n  function attack (target, swing = true) {\n    // arm animation comes before the use_entity packet on 1.8\n    if (bot.supportFeature('armAnimationBeforeUse')) {\n      if (swing) {\n        swingArm()\n      }\n      useEntity(target, 1)\n    } else {\n      useEntity(target, 1)\n      if (swing) {\n        swingArm()\n      }\n    }\n  }\n\n  function mount (target) {\n    // TODO: check if crouching will make make this action always mount\n    useEntity(target, 0)\n  }\n\n  function moveVehicle (left, forward) {\n    if (bot.supportFeature('newPlayerInputPacket')) {\n      // docs:\n      // * left can take -1 or 1 : -1 means right, 1 means left\n      // * forward can take -1 or 1 : -1 means backward, 1 means forward\n      bot._client.write('player_input', {\n        inputs: {\n          forward: forward > 0,\n          backward: forward < 0,\n          left: left > 0,\n          right: left < 0\n        }\n      })\n    } else {\n      bot._client.write('steer_vehicle', {\n        sideways: left,\n        forward,\n        jump: 0x01\n      })\n    }\n  }\n\n  function dismount () {\n    if (bot.vehicle) {\n      if (bot.supportFeature('newPlayerInputPacket')) {\n        bot._client.write('player_input', {\n          inputs: {\n            jump: true\n          }\n        })\n      } else {\n        bot._client.write('steer_vehicle', {\n          sideways: 0.0,\n          forward: 0.0,\n          jump: 0x02\n        })\n      }\n    } else {\n      bot.emit('error', new Error('dismount: not mounted'))\n    }\n  }\n\n  function useEntity (target, leftClick, x, y, z) {\n    const sneaking = bot.getControlState('sneak')\n    if (x && y && z) {\n      bot._client.write('use_entity', {\n        target: target.id,\n        mouse: leftClick,\n        x,\n        y,\n        z,\n        sneaking\n      })\n    } else {\n      bot._client.write('use_entity', {\n        target: target.id,\n        mouse: leftClick,\n        sneaking\n      })\n    }\n  }\n\n  function fetchEntity (id) {\n    return bot.entities[id] || (bot.entities[id] = new Entity(id))\n  }\n}\n\nfunction parseMetadata (metadata, entityMetadata = {}) {\n  if (metadata !== undefined) {\n    for (const { key, value } of metadata) {\n      entityMetadata[key] = value\n    }\n  }\n\n  return entityMetadata\n}\n\nfunction extractSkinInformation (properties) {\n  if (!properties) {\n    return undefined\n  }\n\n  const props = Object.fromEntries(properties.map((e) => [e.name, e]))\n  if (!props.textures || !props.textures.value) {\n    return undefined\n  }\n\n  const skinTexture = JSON.parse(Buffer.from(props.textures.value, 'base64').toString('utf8'))\n\n  const skinTextureUrl = skinTexture?.textures?.SKIN?.url ?? undefined\n  const skinTextureModel = skinTexture?.textures?.SKIN?.metadata?.model ?? undefined\n\n  if (!skinTextureUrl) {\n    return undefined\n  }\n\n  return { url: skinTextureUrl, model: skinTextureModel }\n}\n"
  },
  {
    "path": "lib/plugins/experience.js",
    "content": "module.exports = inject\n\nfunction inject (bot) {\n  bot.experience = {\n    level: null,\n    points: null,\n    progress: null\n  }\n  bot._client.on('experience', (packet) => {\n    bot.experience.level = packet.level\n    bot.experience.points = packet.totalExperience\n    bot.experience.progress = packet.experienceBar\n    bot.emit('experience')\n  })\n}\n"
  },
  {
    "path": "lib/plugins/explosion.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\n// https://minecraft.wiki/w/Explosion\nfunction calcExposure (playerPos, explosionPos, world) {\n  const dx = 1 / (0.6 * 2 + 1)\n  const dy = 1 / (1.8 * 2 + 1)\n  const dz = 1 / (0.6 * 2 + 1)\n\n  const d3 = (1 - Math.floor(1 / dx) * dx) / 2\n  const d4 = (1 - Math.floor(1 / dz) * dz) / 2\n\n  let sampled = 0\n  let exposed = 0\n  const pos = new Vec3(0, 0, 0)\n  for (pos.y = playerPos.y; pos.y <= playerPos.y + 1.8; pos.y += 1.8 * dy) {\n    for (pos.x = playerPos.x - 0.3 + d3; pos.x <= playerPos.x + 0.3; pos.x += 0.6 * dx) {\n      for (pos.z = playerPos.z - 0.3 + d4; pos.z <= playerPos.z + 0.3; pos.z += 0.6 * dz) {\n        const dir = pos.minus(explosionPos)\n        const range = dir.norm()\n        if (world.raycast(explosionPos, dir.normalize(), range) === null) {\n          exposed++\n        }\n        sampled++\n      }\n    }\n  }\n  return exposed / sampled\n}\n\n// https://minecraft.wiki/w/Armor#Damage_protection\nfunction getDamageAfterAbsorb (damages, armorValue, toughness) {\n  const var3 = 2 + toughness / 4\n  const var4 = Math.min(Math.max(armorValue - damages / var3, armorValue * 0.2), 20)\n  return damages * (1 - var4 / 25)\n}\n\n// https://minecraft.wiki/w/Attribute#Operations\nfunction getAttributeValue (prop) {\n  let X = prop.value\n  for (const mod of prop.modifiers) {\n    if (mod.operation !== 0) continue\n    X += mod.amount\n  }\n  let Y = X\n  for (const mod of prop.modifiers) {\n    if (mod.operation !== 1) continue\n    Y += X * mod.amount\n  }\n  for (const mod of prop.modifiers) {\n    if (mod.operation !== 2) continue\n    Y += Y * mod.amount\n  }\n  return Y\n}\n\nfunction inject (bot) {\n  const damageMultiplier = 7 // for 1.12+ 8 for 1.8 TODO check when the change occur (likely 1.9)\n  const armorThoughnessKey = 'generic.armorToughness' // was renamed in 1.16\n\n  const difficultyValues = {\n    peaceful: 0,\n    easy: 1,\n    normal: 2,\n    hard: 3\n  }\n\n  bot.getExplosionDamages = (targetEntity, sourcePos, power, rawDamages = false) => {\n    const distance = targetEntity.position.distanceTo(sourcePos)\n    const radius = 2 * power\n    if (distance >= radius) return 0\n    const exposure = calcExposure(targetEntity.position, sourcePos, bot.world)\n    const impact = (1 - distance / radius) * exposure\n    let damages = Math.floor((impact * impact + impact) * damageMultiplier * power + 1)\n\n    // The following modifiers are constant for the input targetEntity and doesnt depend\n    // on the source position, so if the goal is to compare between positions they can be\n    // ignored to save computations\n    if (!rawDamages && targetEntity.attributes['generic.armor']) {\n      const armor = getAttributeValue(targetEntity.attributes['generic.armor'])\n      const armorToughness = getAttributeValue(targetEntity.attributes[armorThoughnessKey])\n      damages = getDamageAfterAbsorb(damages, armor, armorToughness)\n\n      // TODO: protection enchantment and resistance effects\n\n      if (targetEntity.type === 'player') damages *= difficultyValues[bot.game.difficulty] * 0.5\n    } else if (!rawDamages && !targetEntity.attributes['generic.armor']) {\n      return null\n    }\n    return Math.floor(damages)\n  }\n}\n"
  },
  {
    "path": "lib/plugins/fishing.js",
    "content": "const { Vec3 } = require('vec3')\nconst { createDoneTask, createTask } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  let bobberId = 90\n  // Before 1.14 the bobber entity keep changing name at each version (but the id stays 90)\n  // 1.14 changes the id, but hopefully we can stick with the name: fishing_bobber\n  // the alternative would be to rename it in all version of mcData\n  if (bot.supportFeature('fishingBobberCorrectlyNamed')) {\n    bobberId = bot.registry.entitiesByName.fishing_bobber.id\n  }\n\n  let fishingTask = createDoneTask()\n  let lastBobber = null\n\n  bot._client.on('spawn_entity', (packet) => {\n    if (packet.type === bobberId && !fishingTask.done && !lastBobber) {\n      lastBobber = bot.entities[packet.entityId]\n    }\n  })\n\n  bot._client.on('world_particles', (packet) => {\n    if (!lastBobber || fishingTask.done) return\n\n    const pos = lastBobber.position\n\n    const bobberCondition = bot.registry.supportFeature('updatedParticlesPacket')\n      ? ((packet.particle.type === 'fishing' || packet.particle.type === 'bubble') && packet.amount === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23)\n      // This \"(particles.fishing ?? particles.bubble).id\" condition doesn't make sense (these are both valid types)\n      : (packet.particleId === (bot.registry.particlesByName.fishing ?? bot.registry.particlesByName.bubble).id && packet.particles === 6 && pos.distanceTo(new Vec3(packet.x, pos.y, packet.z)) <= 1.23)\n\n    if (bobberCondition) {\n      bot.activateItem()\n      lastBobber = undefined\n      fishingTask.finish()\n    }\n  })\n  bot._client.on('entity_destroy', (packet) => {\n    if (!lastBobber) return\n    if (packet.entityIds.some(id => id === lastBobber.id)) {\n      lastBobber = undefined\n      fishingTask.cancel(new Error('Fishing cancelled'))\n    }\n  })\n\n  async function fish () {\n    if (!fishingTask.done) {\n      fishingTask.cancel(new Error('Fishing cancelled due to calling bot.fish() again'))\n    }\n\n    fishingTask = createTask()\n\n    bot.activateItem()\n\n    await fishingTask.promise\n  }\n\n  bot.fish = fish\n}\n"
  },
  {
    "path": "lib/plugins/furnace.js",
    "content": "const assert = require('assert')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const allowedWindowTypes = ['minecraft:furnace', 'minecraft:blast_furnace', 'minecraft:smoker']\n\n  function matchWindowType (window) {\n    for (const type of allowedWindowTypes) {\n      if (window.type.startsWith(type)) return true\n    }\n    return false\n  }\n\n  async function openFurnace (furnaceBlock) {\n    const furnace = await bot.openBlock(furnaceBlock)\n    if (!matchWindowType(furnace)) {\n      throw new Error('This is not a furnace-like window')\n    }\n\n    furnace.totalFuel = null\n    furnace.fuel = null\n    furnace.fuelSeconds = null\n    furnace.totalProgress = null\n    furnace.progress = null\n    furnace.progressSeconds = null\n    furnace.takeInput = takeInput\n    furnace.takeFuel = takeFuel\n    furnace.takeOutput = takeOutput\n    furnace.putInput = putInput\n    furnace.putFuel = putFuel\n    furnace.inputItem = function () { return this.slots[0] }\n    furnace.fuelItem = function () { return this.slots[1] }\n    furnace.outputItem = function () { return this.slots[2] }\n\n    bot._client.on('craft_progress_bar', onUpdateWindowProperty)\n    furnace.once('close', () => {\n      bot._client.removeListener('craft_progress_bar', onUpdateWindowProperty)\n    })\n\n    return furnace\n\n    function onUpdateWindowProperty (packet) {\n      if (packet.windowId !== furnace.id) return\n\n      switch (packet.property) {\n        case 0: // Current fuel\n          furnace.fuel = 0\n          furnace.fuelSeconds = 0\n          if (furnace.totalFuel) {\n            furnace.fuel = packet.value / furnace.totalFuel\n            furnace.fuelSeconds = furnace.fuel * furnace.totalFuelSeconds\n          }\n          break\n        case 1: // Total fuel\n          furnace.totalFuel = packet.value\n          furnace.totalFuelSeconds = ticksToSeconds(furnace.totalFuel)\n          break\n        case 2: // Current progress\n          furnace.progress = 0\n          furnace.progressSeconds = 0\n          if (furnace.totalProgress) {\n            furnace.progress = packet.value / furnace.totalProgress\n            furnace.progressSeconds = furnace.totalProgressSeconds - (furnace.progress * furnace.totalProgressSeconds)\n          }\n          break\n        case 3: // Total progress\n          furnace.totalProgress = packet.value\n          furnace.totalProgressSeconds = ticksToSeconds(furnace.totalProgress)\n      }\n\n      furnace.emit('update')\n    }\n\n    async function takeSomething (item) {\n      assert.ok(item)\n      await bot.putAway(item.slot)\n      return item\n    }\n\n    async function takeInput () {\n      return takeSomething(furnace.inputItem())\n    }\n\n    async function takeFuel () {\n      return takeSomething(furnace.fuelItem())\n    }\n\n    async function takeOutput () {\n      return takeSomething(furnace.outputItem())\n    }\n\n    async function putSomething (destSlot, itemType, metadata, count) {\n      const options = {\n        window: furnace,\n        itemType,\n        metadata,\n        count,\n        sourceStart: furnace.inventoryStart,\n        sourceEnd: furnace.inventoryEnd,\n        destStart: destSlot,\n        destEnd: destSlot + 1\n      }\n      await bot.transfer(options)\n    }\n\n    async function putInput (itemType, metadata, count) {\n      await putSomething(0, itemType, metadata, count)\n    }\n\n    async function putFuel (itemType, metadata, count) {\n      await putSomething(1, itemType, metadata, count)\n    }\n  }\n\n  function ticksToSeconds (ticks) {\n    return ticks * 0.05\n  }\n\n  bot.openFurnace = openFurnace\n}\n"
  },
  {
    "path": "lib/plugins/game.js",
    "content": "const nbt = require('prismarine-nbt')\nmodule.exports = inject\n\nconst difficultyNames = ['peaceful', 'easy', 'normal', 'hard']\nconst gameModes = ['survival', 'creative', 'adventure', 'spectator']\n\nconst dimensionNames = {\n  '-1': 'the_nether',\n  0: 'overworld',\n  1: 'the_end'\n}\n\nconst parseGameMode = gameModeBits => {\n  if (gameModeBits < 0 || gameModeBits > 0b11) {\n    return 'survival'\n  }\n  return gameModes[(gameModeBits & 0b11)] // lower two bits\n}\n\nfunction inject (bot, options) {\n  function getBrandCustomChannelName () {\n    if (bot.supportFeature('customChannelMCPrefixed')) {\n      return 'MC|Brand'\n    } else if (bot.supportFeature('customChannelIdentifier')) {\n      return 'minecraft:brand'\n    }\n    throw new Error('Unsupported brand channel name')\n  }\n\n  function handleRespawnPacketData (packet) {\n    bot.game.levelType = packet.levelType ?? (packet.isFlat ? 'flat' : 'default')\n    bot.game.hardcore = packet.isHardcore ?? Boolean(packet.gameMode & 0b100)\n    // Either a respawn packet or a login packet. Depending on the packet it can be \"gamemode\" or \"gameMode\"\n    if (bot.supportFeature('spawnRespawnWorldDataField')) { // 1.20.5\n      bot.game.gameMode = packet.gamemode\n    } else {\n      bot.game.gameMode = parseGameMode(packet.gamemode ?? packet.gameMode)\n    }\n    if (bot.supportFeature('segmentedRegistryCodecData')) { // 1.20.5\n      if (typeof packet.dimension === 'number') {\n        bot.game.dimension = bot.registry.dimensionsArray[packet.dimension]?.name?.replace('minecraft:', '')\n      } else if (typeof packet.dimension === 'string') { // iirc, in 1.21 it's back to a string\n        bot.game.dimension = packet.dimension.replace('minecraft:', '')\n      }\n    } else if (bot.supportFeature('dimensionIsAnInt')) {\n      bot.game.dimension = dimensionNames[packet.dimension]\n    } else if (bot.supportFeature('dimensionIsAString')) {\n      bot.game.dimension = packet.dimension.replace('minecraft:', '')\n    } else if (bot.supportFeature('dimensionIsAWorld')) {\n      bot.game.dimension = packet.worldName.replace('minecraft:', '')\n    } else {\n      throw new Error('Unsupported dimension type in login packet')\n    }\n\n    if (packet.dimensionCodec) {\n      bot.registry.loadDimensionCodec(packet.dimensionCodec)\n    }\n\n    bot.game.minY = 0\n    bot.game.height = 256\n\n    if (bot.supportFeature('dimensionDataInCodec')) { // 1.19+\n      // pre 1.20.5 before we consolidated login and respawn's SpawnInfo structure into one type,\n      // \"dimension\" was called \"worldType\" in login_packet's payload but not respawn.\n      if (packet.worldType && !bot.game.dimension) {\n        bot.game.dimension = packet.worldType.replace('minecraft:', '')\n      }\n      const dimData = bot.registry.dimensionsByName[bot.game.dimension]\n      if (dimData) {\n        bot.game.minY = dimData.minY\n        bot.game.height = dimData.height\n      }\n    } else if (bot.supportFeature('dimensionDataIsAvailable')) { // 1.16.2+\n      const dimensionData = nbt.simplify(packet.dimension)\n      bot.game.minY = dimensionData.min_y\n      bot.game.height = dimensionData.height\n    }\n\n    if (packet.difficulty) {\n      bot.game.difficulty = difficultyNames[packet.difficulty]\n    }\n  }\n\n  bot.game = {}\n\n  const brandChannel = getBrandCustomChannelName()\n  bot._client.registerChannel(brandChannel, ['string', []])\n\n  // 1.20.2\n  bot._client.on('registry_data', (packet) => {\n    bot.registry.loadDimensionCodec(packet.codec || packet)\n  })\n\n  bot._client.on('login', (packet) => {\n    handleRespawnPacketData(packet.worldState || packet)\n\n    bot.game.maxPlayers = packet.maxPlayers\n    if (packet.enableRespawnScreen) {\n      bot.game.enableRespawnScreen = packet.enableRespawnScreen\n    }\n    if (packet.viewDistance) {\n      bot.game.serverViewDistance = packet.viewDistance\n    }\n\n    bot.emit('login')\n    bot.emit('game')\n\n    // varint length-prefixed string as data\n    bot._client.writeChannel(brandChannel, options.brand)\n  })\n\n  bot._client.on('respawn', (packet) => {\n    // in 1.20.5+ protocol we move the shared spawn data into one SpawnInfo type under .worldState\n    handleRespawnPacketData(packet.worldState || packet)\n    bot.emit('game')\n  })\n\n  bot._client.on('game_state_change', (packet) => {\n    if ((packet.reason === 4 || packet.reason === 'win_game') && packet.gameMode === 1) {\n      bot._client.write('client_command', { action: 0 })\n    }\n    if ((packet.reason === 3) || (packet.reason === 'change_game_mode')) {\n      bot.game.gameMode = parseGameMode(packet.gameMode)\n      bot.emit('game')\n    }\n  })\n\n  bot._client.on('difficulty', (packet) => {\n    bot.game.difficulty = difficultyNames[packet.difficulty]\n  })\n\n  bot._client.on(brandChannel, (serverBrand) => {\n    bot.game.serverBrand = serverBrand\n  })\n\n  // mimic the vanilla 1.17 client to prevent anticheat kicks\n  bot._client.on('ping', (data) => {\n    bot._client.write('pong', {\n      id: data.id\n    })\n  })\n}\n"
  },
  {
    "path": "lib/plugins/generic_place.js",
    "content": "const assert = require('assert')\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n  /**\n   *\n   * @param {import('prismarine-block').Block} referenceBlock\n   * @param {import('vec3').Vec3} faceVector\n   * @param {{half?: 'top'|'bottom', delta?: import('vec3').Vec3, forceLook?: boolean | 'ignore', offhand?: boolean, swingArm?: 'right' | 'left', showHand?: boolean}} options\n   */\n  async function _genericPlace (referenceBlock, faceVector, options) {\n    let handToPlaceWith = 0\n    if (options.offhand) {\n      if (!bot.inventory.slots[45]) {\n        throw new Error('must be holding an item in the off-hand to place')\n      }\n      handToPlaceWith = 1\n    } else if (!bot.heldItem) {\n      throw new Error('must be holding an item to place')\n    }\n\n    // Look at the center of the face\n    let dx = 0.5 + faceVector.x * 0.5\n    let dy = 0.5 + faceVector.y * 0.5\n    let dz = 0.5 + faceVector.z * 0.5\n    if (dy === 0.5) {\n      if (options.half === 'top') dy += 0.25\n      else if (options.half === 'bottom') dy -= 0.25\n    }\n    if (options.delta) {\n      dx = options.delta.x\n      dy = options.delta.y\n      dz = options.delta.z\n    }\n    if (options.forceLook !== 'ignore') {\n      await bot.lookAt(referenceBlock.position.offset(dx, dy, dz), options.forceLook)\n    }\n    // TODO: tell the server that we are sneaking while doing this\n    const pos = referenceBlock.position\n\n    if (options.swingArm) {\n      bot.swingArm(options.swingArm, options.showHand)\n    }\n\n    if (bot.supportFeature('blockPlaceHasHeldItem')) {\n      const packet = {\n        location: pos,\n        direction: vectorToDirection(faceVector),\n        heldItem: Item.toNotch(bot.heldItem),\n        cursorX: Math.floor(dx * 16),\n        cursorY: Math.floor(dy * 16),\n        cursorZ: Math.floor(dz * 16)\n      }\n      bot._client.write('block_place', packet)\n    } else if (bot.supportFeature('blockPlaceHasHandAndIntCursor')) {\n      bot._client.write('block_place', {\n        location: pos,\n        direction: vectorToDirection(faceVector),\n        hand: handToPlaceWith,\n        cursorX: Math.floor(dx * 16),\n        cursorY: Math.floor(dy * 16),\n        cursorZ: Math.floor(dz * 16)\n      })\n    } else if (bot.supportFeature('blockPlaceHasHandAndFloatCursor')) {\n      bot._client.write('block_place', {\n        location: pos,\n        direction: vectorToDirection(faceVector),\n        hand: handToPlaceWith,\n        cursorX: dx,\n        cursorY: dy,\n        cursorZ: dz\n      })\n    } else if (bot.supportFeature('blockPlaceHasInsideBlock')) {\n      bot._client.write('block_place', {\n        location: pos,\n        direction: vectorToDirection(faceVector),\n        hand: handToPlaceWith,\n        cursorX: dx,\n        cursorY: dy,\n        cursorZ: dz,\n        insideBlock: false,\n        sequence: 0, // 1.19.0\n        worldBorderHit: false // 1.21.3\n      })\n    }\n\n    return pos\n  }\n  bot._genericPlace = _genericPlace\n}\n\nfunction vectorToDirection (v) {\n  if (v.y < 0) {\n    return 0\n  } else if (v.y > 0) {\n    return 1\n  } else if (v.z < 0) {\n    return 2\n  } else if (v.z > 0) {\n    return 3\n  } else if (v.x < 0) {\n    return 4\n  } else if (v.x > 0) {\n    return 5\n  }\n  assert.ok(false, `invalid direction vector ${v}`)\n}\n"
  },
  {
    "path": "lib/plugins/health.js",
    "content": "module.exports = inject\n\nfunction inject (bot, options) {\n  bot.isAlive = true\n\n  bot._client.on('respawn', (packet) => {\n    bot.isAlive = false\n    bot.emit('respawn')\n  })\n\n  bot._client.once('update_health', (packet) => {\n    if (packet.health > 0) {\n      bot.emit('spawn')\n    }\n  })\n\n  bot._client.on('update_health', (packet) => {\n    bot.health = packet.health\n    bot.food = packet.food\n    bot.foodSaturation = packet.foodSaturation\n    bot.emit('health')\n    if (bot.health <= 0) {\n      if (bot.isAlive) {\n        bot.isAlive = false\n        bot.emit('death')\n      }\n      if (!options.respawn) return\n      bot.respawn()\n    } else if (bot.health > 0 && !bot.isAlive) {\n      bot.isAlive = true\n      bot.emit('spawn')\n    }\n  })\n\n  const respawn = () => {\n    if (bot.isAlive) return\n    bot._client.write('client_command', bot.supportFeature('respawnIsPayload') ? { payload: 0 } : { actionId: 0 })\n  }\n\n  bot.respawn = respawn\n}\n"
  },
  {
    "path": "lib/plugins/inventory.js",
    "content": "const assert = require('assert')\nconst { Vec3 } = require('vec3')\nconst { once, sleep, createDoneTask, createTask, withTimeout } = require('../promise_utils')\n\nmodule.exports = inject\n\n// ms to wait before clicking on a tool so the server can send the new\n// damage information\nconst DIG_CLICK_TIMEOUT = 500\n// The number of milliseconds to wait for the server to respond with consume completion.\n// This number is larger than the eat time of 1.61 seconds to account for latency and low tps.\n// The eat time comes from https://minecraft.wiki/w/Food#Usage\nconst CONSUME_TIMEOUT = 2500\n// milliseconds to wait for the server to respond to a window click transaction\nconst WINDOW_TIMEOUT = 5000\n\nconst ALWAYS_CONSUMABLES = [\n  'potion',\n  'milk_bucket',\n  'enchanted_golden_apple',\n  'golden_apple'\n]\n\nfunction inject (bot, { hideErrors }) {\n  const Item = require('prismarine-item')(bot.registry)\n  const windows = require('prismarine-windows')(bot.version)\n\n  let eatingTask = createDoneTask()\n  let sequence = 0\n\n  let nextActionNumber = 0 // < 1.17\n  let stateId = -1\n  if (bot.supportFeature('stateIdUsed')) {\n    const listener = packet => { stateId = packet.stateId }\n    bot._client.on('window_items', listener)\n    bot._client.on('set_slot', listener)\n  }\n  const windowClickQueue = []\n  let windowItems\n\n  // 0-8, null = uninitialized\n  // which quick bar slot is selected\n  bot.quickBarSlot = null\n  bot.inventory = windows.createWindow(0, 'minecraft:inventory', 'Inventory')\n  bot.currentWindow = null\n  bot.usingHeldItem = false\n\n  Object.defineProperty(bot, 'heldItem', {\n    get: function () {\n      return bot.inventory.slots[bot.QUICK_BAR_START + bot.quickBarSlot]\n    }\n  })\n\n  bot.on('spawn', () => {\n    Object.defineProperty(bot.entity, 'equipment', {\n      get: bot.supportFeature('doesntHaveOffHandSlot')\n        ? function () {\n          return [bot.heldItem, bot.inventory.slots[8], bot.inventory.slots[7],\n            bot.inventory.slots[6], bot.inventory.slots[5]]\n        }\n        : function () {\n          return [bot.heldItem, bot.inventory.slots[45], bot.inventory.slots[8],\n            bot.inventory.slots[7], bot.inventory.slots[6], bot.inventory.slots[5]]\n        }\n    })\n  })\n\n  bot._client.on('entity_status', (packet) => {\n    if (packet.entityId === bot.entity.id && packet.entityStatus === 9 && !eatingTask.done) {\n      eatingTask.finish()\n    }\n    bot.usingHeldItem = false\n  })\n\n  let previousHeldItem = null\n  bot.on('heldItemChanged', (heldItem) => {\n    // we only disable the item if the item type or count changes\n    if (\n      heldItem?.type === previousHeldItem?.type && heldItem?.count === previousHeldItem?.count\n    ) {\n      previousHeldItem = heldItem\n      return\n    }\n    if (!eatingTask.done) {\n      eatingTask.finish()\n    }\n    bot.usingHeldItem = false\n  })\n\n  bot._client.on('set_cooldown', (packet) => {\n    if (bot.heldItem && bot.heldItem.type !== packet.itemID) return\n    if (!eatingTask.done) {\n      eatingTask.finish()\n    }\n    bot.usingHeldItem = false\n  })\n\n  async function consume () {\n    if (!eatingTask.done) {\n      eatingTask.cancel(new Error('Consuming cancelled due to calling bot.consume() again'))\n    }\n\n    if (bot.game.gameMode !== 'creative' && !ALWAYS_CONSUMABLES.includes(bot.heldItem.name) && bot.food === 20) {\n      throw new Error('Food is full')\n    }\n\n    eatingTask = createTask()\n\n    activateItem()\n\n    await withTimeout(eatingTask.promise, CONSUME_TIMEOUT)\n  }\n\n  function activateItem (offHand = false) {\n    bot.usingHeldItem = true\n    sequence++\n\n    if (bot.supportFeature('useItemWithBlockPlace')) {\n      bot._client.write('block_place', {\n        location: new Vec3(-1, 255, -1),\n        direction: -1,\n        heldItem: Item.toNotch(bot.heldItem),\n        cursorX: -1,\n        cursorY: -1,\n        cursorZ: -1\n      })\n    } else if (bot.supportFeature('useItemWithOwnPacket')) {\n      bot._client.write('use_item', {\n        hand: offHand ? 1 : 0,\n        sequence,\n        rotation: { x: 0, y: 0 }\n      })\n    }\n  }\n\n  function deactivateItem () {\n    const body = {\n      status: 5,\n      location: new Vec3(0, 0, 0),\n      face: 5\n    }\n\n    if (bot.supportFeature('useItemWithOwnPacket')) {\n      body.face = 0\n      body.sequence = 0\n    }\n\n    bot._client.write('block_dig', body)\n\n    bot.usingHeldItem = false\n  }\n\n  async function putSelectedItemRange (start, end, window, slot) {\n    // put the selected item back indow the slot range in window\n\n    // try to put it in an item that already exists and just increase\n    // the count.\n\n    while (window.selectedItem) {\n      const item = window.findItemRange(start, end, window.selectedItem.type, window.selectedItem.metadata, true, window.selectedItem.nbt)\n\n      if (item && item.stackSize !== item.count) { // something to join with\n        await clickWindow(item.slot, 0, 0)\n      } else { // nothing to join with\n        const emptySlot = window.firstEmptySlotRange(start, end)\n        if (emptySlot === null) { // no room left\n          if (slot === null) { // no room => drop it\n            await tossLeftover()\n          } else { // if there is still some leftover and slot is not null, click slot\n            await clickWindow(slot, 0, 0)\n            await tossLeftover()\n          }\n        } else {\n          await clickWindow(emptySlot, 0, 0)\n        }\n      }\n    }\n\n    async function tossLeftover () {\n      if (window.selectedItem) {\n        await clickWindow(-999, 0, 0)\n      }\n    }\n  }\n\n  async function activateBlock (block, direction, cursorPos) {\n    direction = direction ?? new Vec3(0, 1, 0)\n    const directionNum = vectorToDirection(direction) // The packet needs a number as the direction\n    cursorPos = cursorPos ?? new Vec3(0.5, 0.5, 0.5)\n    // TODO: tell the server that we are not sneaking while doing this\n    await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), false)\n    // place block message\n    // TODO: logic below can likely be simplified\n    if (bot.supportFeature('blockPlaceHasHeldItem')) {\n      bot._client.write('block_place', {\n        location: block.position,\n        direction: directionNum,\n        heldItem: Item.toNotch(bot.heldItem),\n        cursorX: cursorPos.scaled(16).x,\n        cursorY: cursorPos.scaled(16).y,\n        cursorZ: cursorPos.scaled(16).z\n      })\n    } else if (bot.supportFeature('blockPlaceHasHandAndIntCursor')) {\n      bot._client.write('block_place', {\n        location: block.position,\n        direction: directionNum,\n        hand: 0,\n        cursorX: cursorPos.scaled(16).x,\n        cursorY: cursorPos.scaled(16).y,\n        cursorZ: cursorPos.scaled(16).z\n      })\n    } else if (bot.supportFeature('blockPlaceHasHandAndFloatCursor')) {\n      bot._client.write('block_place', {\n        location: block.position,\n        direction: directionNum,\n        hand: 0,\n        cursorX: cursorPos.x,\n        cursorY: cursorPos.y,\n        cursorZ: cursorPos.z\n      })\n    } else if (bot.supportFeature('blockPlaceHasInsideBlock')) {\n      bot._client.write('block_place', {\n        location: block.position,\n        direction: directionNum,\n        hand: 0,\n        cursorX: cursorPos.x,\n        cursorY: cursorPos.y,\n        cursorZ: cursorPos.z,\n        insideBlock: false,\n        sequence: 0, // 1.19.0+\n        worldBorderHit: false // 1.21.3+\n      })\n    }\n\n    // swing arm animation\n    bot.swingArm()\n  }\n\n  async function activateEntity (entity) {\n    // TODO: tell the server that we are not sneaking while doing this\n    await bot.lookAt(entity.position.offset(0, 1, 0), false)\n    bot._client.write('use_entity', {\n      target: entity.id,\n      mouse: 0, // interact with entity\n      sneaking: false,\n      hand: 0 // interact with the main hand\n    })\n  }\n\n  async function activateEntityAt (entity, position) {\n    // TODO: tell the server that we are not sneaking while doing this\n    await bot.lookAt(position, false)\n    bot._client.write('use_entity', {\n      target: entity.id,\n      mouse: 2, // interact with entity at\n      sneaking: false,\n      hand: 0, // interact with the main hand\n      x: position.x - entity.position.x,\n      y: position.y - entity.position.y,\n      z: position.z - entity.position.z\n    })\n  }\n\n  async function transfer (options) {\n    const window = options.window || bot.currentWindow || bot.inventory\n    const itemType = options.itemType\n    const metadata = options.metadata\n    const nbt = options.nbt\n    let count = (options.count === undefined || options.count === null) ? 1 : options.count\n    let firstSourceSlot = null\n\n    // ranges\n    const sourceStart = options.sourceStart\n    const destStart = options.destStart\n    assert.notStrictEqual(sourceStart, null)\n    assert.notStrictEqual(destStart, null)\n    const sourceEnd = options.sourceEnd === null ? sourceStart + 1 : options.sourceEnd\n    const destEnd = options.destEnd === null ? destStart + 1 : options.destEnd\n\n    await transferOne()\n\n    async function transferOne () {\n      if (count === 0) {\n        await putSelectedItemRange(sourceStart, sourceEnd, window, firstSourceSlot)\n        return\n      }\n      if (!window.selectedItem || window.selectedItem.type !== itemType ||\n        (metadata != null && window.selectedItem.metadata !== metadata) ||\n        (nbt != null && window.selectedItem.nbt !== nbt)) {\n        // we are not holding the item we need. click it.\n        const sourceItem = window.findItemRange(sourceStart, sourceEnd, itemType, metadata, false, nbt)\n        const mcDataEntry = bot.registry.itemsArray.find(x => x.id === itemType)\n        assert(mcDataEntry, 'Invalid itemType')\n        if (!sourceItem) throw new Error(`Can't find ${mcDataEntry.name} in slots [${sourceStart} - ${sourceEnd}], (item id: ${itemType})`)\n        if (firstSourceSlot === null) firstSourceSlot = sourceItem.slot\n        // number of item that can be moved from that slot\n        await clickWindow(sourceItem.slot, 0, 0)\n      }\n      await clickDest()\n\n      async function clickDest () {\n        assert.notStrictEqual(window.selectedItem.type, null)\n        assert.notStrictEqual(window.selectedItem.metadata, null)\n        let destItem\n        let destSlot\n        // special case for tossing\n        if (destStart === -999) {\n          destSlot = -999\n        } else {\n          // find a non full item that we can drop into\n          destItem = window.findItemRange(destStart, destEnd,\n            window.selectedItem.type, window.selectedItem.metadata, true, nbt)\n          // if that didn't work find an empty slot to drop into\n          destSlot = destItem\n            ? destItem.slot\n            : window.firstEmptySlotRange(destStart, destEnd)\n          // if that didn't work, give up\n          if (destSlot === null) {\n            throw new Error('destination full')\n          }\n        }\n        // move the maximum number of item that can be moved\n        const destSlotCount = destItem && destItem.count ? destItem.count : 0\n        const movedItems = Math.min(window.selectedItem.stackSize - destSlotCount, window.selectedItem.count)\n        // if the number of item the left click moves is less than the number of item we want to move\n        // several at the same time (left click)\n        if (movedItems <= count) {\n          await clickWindow(destSlot, 0, 0)\n          // update the number of item we want to move (count)\n          count -= movedItems\n          await transferOne()\n        } else {\n          // one by one (right click)\n          await clickWindow(destSlot, 1, 0)\n          count -= 1\n          await transferOne()\n        }\n      }\n    }\n  }\n\n  function extendWindow (window) {\n    window.close = () => {\n      closeWindow(window)\n      window.emit('close')\n    }\n\n    window.withdraw = async (itemType, metadata, count, nbt) => {\n      if (bot.inventory.emptySlotCount() === 0) {\n        throw new Error('Unable to withdraw, Bot inventory is full.')\n      }\n      const options = {\n        window,\n        itemType,\n        metadata,\n        count,\n        nbt,\n        sourceStart: 0,\n        sourceEnd: window.inventoryStart,\n        destStart: window.inventoryStart,\n        destEnd: window.inventoryEnd\n      }\n      await transfer(options)\n    }\n    window.deposit = async (itemType, metadata, count, nbt) => {\n      const options = {\n        window,\n        itemType,\n        metadata,\n        count,\n        nbt,\n        sourceStart: window.inventoryStart,\n        sourceEnd: window.inventoryEnd,\n        destStart: 0,\n        destEnd: window.inventoryStart\n      }\n      await transfer(options)\n    }\n  }\n\n  async function openBlock (block, direction, cursorPos) {\n    bot.activateBlock(block, direction, cursorPos)\n    const [window] = await once(bot, 'windowOpen')\n    extendWindow(window)\n    return window\n  }\n\n  async function openEntity (entity) {\n    bot.activateEntity(entity)\n    const [window] = await once(bot, 'windowOpen')\n    extendWindow(window)\n    return window\n  }\n\n  function createActionNumber () {\n    nextActionNumber = nextActionNumber === 32767 ? 1 : nextActionNumber + 1\n    return nextActionNumber\n  }\n\n  function updateHeldItem () {\n    bot.emit('heldItemChanged', bot.heldItem)\n  }\n\n  function closeWindow (window) {\n    bot._client.write('close_window', {\n      windowId: window.id\n    })\n    copyInventory(window)\n    bot.currentWindow = null\n    bot.emit('windowClose', window)\n  }\n\n  function copyInventory (window) {\n    const slotOffset = window.inventoryStart - bot.inventory.inventoryStart\n    for (let i = window.inventoryStart; i < window.inventoryEnd; i++) {\n      const item = window.slots[i]\n      const slot = i - slotOffset\n      if (item) {\n        item.slot = slot\n      }\n      if (!Item.equal(bot.inventory.slots[slot], item, true)) bot.inventory.updateSlot(slot, item)\n    }\n  }\n\n  function tradeMatch (limitItem, targetItem) {\n    return (\n      targetItem !== null &&\n      limitItem !== null &&\n      targetItem.type === limitItem.type &&\n      targetItem.count >= limitItem.count\n    )\n  }\n\n  function expectTradeUpdate (window) {\n    const trade = window.selectedTrade\n    const hasItem = !!window.slots[2]\n\n    if (hasItem !== tradeMatch(trade.inputItem1, window.slots[0])) {\n      if (trade.hasItem2) {\n        return hasItem !== tradeMatch(trade.inputItem2, window.slots[1])\n      }\n      return true\n    }\n    return false\n  }\n\n  async function waitForWindowUpdate (window, slot) {\n    if (window.type === 'minecraft:inventory') {\n      if (slot >= 1 && slot <= 4) {\n        await once(bot.inventory, 'updateSlot:0')\n      }\n    } else if (window.type === 'minecraft:crafting') {\n      if (slot >= 1 && slot <= 9) {\n        await once(bot.currentWindow, 'updateSlot:0')\n      }\n    } else if (window.type === 'minecraft:merchant') {\n      const toUpdate = []\n      if (slot <= 1 && !window.selectedTrade.tradeDisabled && expectTradeUpdate(window)) {\n        toUpdate.push(once(bot.currentWindow, 'updateSlot:2'))\n      }\n      if (slot === 2) {\n        for (const item of bot.currentWindow.containerItems()) {\n          toUpdate.push(once(bot.currentWindow, `updateSlot:${item.slot}`))\n        }\n      }\n      await Promise.all(toUpdate)\n\n      if (slot === 2 && !window.selectedTrade.tradeDisabled && expectTradeUpdate(window)) {\n        // After the trade goes through, if the inputs are still satisfied,\n        // expect another update in slot 2\n        await once(bot.currentWindow, 'updateSlot:2')\n      }\n    }\n  }\n\n  function confirmTransaction (windowId, actionId, accepted) {\n    // drop the queue entries for all the clicks that the server did not send\n    // transaction packets for.\n    // Also reject transactions that aren't sent from mineflayer\n    let click = windowClickQueue[0]\n    if (click === undefined || !windowClickQueue.some(clicks => clicks.id === actionId)) {\n      // mimic vanilla client and send a rejection for faulty transaction packets\n      bot._client.write('transaction', {\n        windowId,\n        action: actionId,\n        accepted: true\n        // bot.emit(`confirmTransaction${click.id}`, false)\n      })\n      return\n    }\n    // shift it later if packets are sent out of order\n    click = windowClickQueue.shift()\n\n    assert.ok(click.id <= actionId)\n    while (actionId > click.id) {\n      onAccepted()\n      click = windowClickQueue.shift()\n    }\n    assert.ok(click)\n\n    if (accepted) {\n      onAccepted()\n    } else {\n      onRejected()\n    }\n    updateHeldItem()\n\n    function onAccepted () {\n      const window = windowId === 0 ? bot.inventory : bot.currentWindow\n      if (!window || window.id !== click.windowId) return\n      window.acceptClick(click)\n      bot.emit(`confirmTransaction${click.id}`, true)\n    }\n\n    function onRejected () {\n      bot._client.write('transaction', {\n        windowId: click.windowId,\n        action: click.id,\n        accepted: true\n      })\n      bot.emit(`confirmTransaction${click.id}`, false)\n    }\n  }\n\n  function getChangedSlots (oldSlots, newSlots) {\n    assert.equal(oldSlots.length, newSlots.length)\n\n    const changedSlots = []\n\n    for (let i = 0; i < newSlots.length; i++) {\n      if (!Item.equal(oldSlots[i], newSlots[i])) {\n        changedSlots.push(i)\n      }\n    }\n\n    return changedSlots\n  }\n\n  async function clickWindow (slot, mouseButton, mode) {\n    // if you click on the quick bar and have dug recently,\n    // wait a bit\n    if (slot >= bot.QUICK_BAR_START && bot.lastDigTime != null) {\n      let timeSinceLastDig\n      while ((timeSinceLastDig = new Date() - bot.lastDigTime) < DIG_CLICK_TIMEOUT) {\n        await sleep(DIG_CLICK_TIMEOUT - timeSinceLastDig)\n      }\n    }\n    const window = bot.currentWindow || bot.inventory\n\n    assert.ok(mode >= 0 && mode <= 4)\n    const actionId = createActionNumber()\n\n    const click = {\n      slot,\n      mouseButton,\n      mode,\n      id: actionId,\n      windowId: window.id,\n      item: slot === -999 ? null : window.slots[slot]\n    }\n\n    let changedSlots\n    if (bot.supportFeature('transactionPacketExists')) {\n      windowClickQueue.push(click)\n    } else {\n      if (\n      // this array indicates the clicks that return changedSlots\n        [\n          0,\n          // 1,\n          // 2,\n          3,\n          4\n          // 5,\n          // 6\n        ].includes(click.mode)) {\n        changedSlots = window.acceptClick(click)\n      } else {\n        // this is used as a fallback\n        const oldSlots = JSON.parse(JSON.stringify(window.slots))\n\n        window.acceptClick(click)\n\n        changedSlots = getChangedSlots(oldSlots, window.slots)\n      }\n\n      changedSlots = changedSlots.map(slot => {\n        return {\n          location: slot,\n          item: Item.toNotch(window.slots[slot])\n        }\n      })\n    }\n\n    // WHEN ADDING SUPPORT FOR OTHER CLICKS, MAKE SURE TO CHANGE changedSlots TO SUPPORT THEM\n    if (bot.supportFeature('stateIdUsed')) { // 1.17.1 +\n      bot._client.write('window_click', {\n        windowId: window.id,\n        stateId,\n        slot,\n        mouseButton,\n        mode,\n        changedSlots,\n        cursorItem: Item.toNotch(window.selectedItem)\n      })\n    } else if (bot.supportFeature('actionIdUsed')) { // <= 1.16.5\n      bot._client.write('window_click', {\n        windowId: window.id,\n        slot,\n        mouseButton,\n        action: actionId,\n        mode,\n        // protocol expects null even if there is an item at the slot in mode 2 and 4\n        item: Item.toNotch((mode === 2 || mode === 4) ? null : click.item)\n      })\n    } else { // 1.17\n      bot._client.write('window_click', {\n        windowId: window.id,\n        slot,\n        mouseButton,\n        mode,\n        changedSlots,\n        cursorItem: Item.toNotch(window.selectedItem)\n      })\n    }\n\n    if (bot.supportFeature('transactionPacketExists')) {\n      const response = once(bot, `confirmTransaction${actionId}`)\n      if (!window.transactionRequiresConfirmation(click)) {\n        confirmTransaction(window.id, actionId, true)\n      }\n      const [success] = await withTimeout(response, WINDOW_TIMEOUT)\n        .catch(() => {\n          throw new Error(`Server didn't respond to transaction for clicking on slot ${slot} on window with id ${window?.id}.`)\n        })\n      if (!success) {\n        throw new Error(`Server rejected transaction for clicking on slot ${slot}, on window with id ${window?.id}.`)\n      }\n    } else {\n      await waitForWindowUpdate(window, slot)\n    }\n  }\n\n  async function putAway (slot) {\n    const window = bot.currentWindow || bot.inventory\n    const promisePutAway = once(window, `updateSlot:${slot}`)\n    await clickWindow(slot, 0, 0)\n    const start = window.inventoryStart\n    const end = window.inventoryEnd\n    await putSelectedItemRange(start, end, window, null)\n    await promisePutAway\n  }\n\n  async function moveSlotItem (sourceSlot, destSlot) {\n    await clickWindow(sourceSlot, 0, 0)\n    await clickWindow(destSlot, 0, 0)\n    // if we're holding an item, put it back where the source item was.\n    // otherwise we're done.\n    updateHeldItem()\n    if (bot.inventory.selectedItem) {\n      await clickWindow(sourceSlot, 0, 0)\n    }\n  }\n\n  bot._client.on('transaction', (packet) => {\n    // confirm transaction\n    confirmTransaction(packet.windowId, packet.action, packet.accepted)\n  })\n\n  bot._client.on('held_item_slot', (packet) => {\n    // held item change\n    bot.setQuickBarSlot(packet.slot)\n  })\n\n  function prepareWindow (window) {\n    if (!windowItems || window.id !== windowItems.windowId) {\n      // don't emit windowOpen until we have the slot data\n      bot.once(`setWindowItems:${window.id}`, () => {\n        extendWindow(window)\n        bot.emit('windowOpen', window)\n      })\n    } else {\n      for (let i = 0; i < windowItems.items.length; ++i) {\n        const item = Item.fromNotch(windowItems.items[i])\n        window.updateSlot(i, item)\n      }\n      updateHeldItem()\n      extendWindow(window)\n      bot.emit('windowOpen', window)\n    }\n  }\n\n  bot._client.on('open_window', (packet) => {\n    // open window\n    bot.currentWindow = windows.createWindow(packet.windowId,\n      packet.inventoryType, packet.windowTitle, packet.slotCount)\n    prepareWindow(bot.currentWindow)\n  })\n  bot._client.on('open_horse_window', (packet) => {\n    // open window\n    bot.currentWindow = windows.createWindow(packet.windowId,\n      'HorseWindow', 'Horse', packet.nbSlots)\n    prepareWindow(bot.currentWindow)\n  })\n  bot._client.on('close_window', (packet) => {\n    // close window\n    const oldWindow = bot.currentWindow\n    bot.currentWindow = null\n    bot.emit('windowClose', oldWindow)\n  })\n  bot._client.on('login', () => {\n    // close window when switch subserver\n    const oldWindow = bot.currentWindow\n    if (!oldWindow) return\n    bot.currentWindow = null\n    bot.emit('windowClose', oldWindow)\n  })\n  bot._setSlot = (slotId, newItem, window = bot.inventory) => {\n    // set slot\n    const oldItem = window.slots[slotId]\n    window.updateSlot(slotId, newItem)\n    updateHeldItem()\n    bot.emit(`setSlot:${window.id}`, oldItem, newItem)\n  }\n  bot._client.on('set_slot', (packet) => {\n    const window = packet.windowId === 0 ? bot.inventory : bot.currentWindow\n    if (!window || window.id !== packet.windowId) return\n    const newItem = Item.fromNotch(packet.item)\n    bot._setSlot(packet.slot, newItem, window)\n  })\n  bot._client.on('window_items', (packet) => {\n    const window = packet.windowId === 0 ? bot.inventory : bot.currentWindow\n    if (!window || window.id !== packet.windowId) {\n      windowItems = packet\n      return\n    }\n\n    // set window items\n    for (let i = 0; i < packet.items.length; ++i) {\n      const item = Item.fromNotch(packet.items[i])\n      window.updateSlot(i, item)\n    }\n    updateHeldItem()\n    bot.emit(`setWindowItems:${window.id}`)\n  })\n\n  /**\n   * Convert a vector direction to minecraft packet number direction\n   * @param {Vec3} v\n   * @returns {number}\n   */\n  function vectorToDirection (v) {\n    if (v.y < 0) {\n      return 0\n    } else if (v.y > 0) {\n      return 1\n    } else if (v.z < 0) {\n      return 2\n    } else if (v.z > 0) {\n      return 3\n    } else if (v.x < 0) {\n      return 4\n    } else if (v.x > 0) {\n      return 5\n    }\n    assert.ok(false, `invalid direction vector ${v}`)\n  }\n\n  bot.activateBlock = activateBlock\n  bot.activateEntity = activateEntity\n  bot.activateEntityAt = activateEntityAt\n  bot.consume = consume\n  bot.activateItem = activateItem\n  bot.deactivateItem = deactivateItem\n\n  // not really in the public API\n  bot.clickWindow = clickWindow\n  bot.putSelectedItemRange = putSelectedItemRange\n  bot.putAway = putAway\n  bot.closeWindow = closeWindow\n  bot.transfer = transfer\n  bot.openBlock = openBlock\n  bot.openEntity = openEntity\n  bot.moveSlotItem = moveSlotItem\n  bot.updateHeldItem = updateHeldItem\n}\n"
  },
  {
    "path": "lib/plugins/kick.js",
    "content": "module.exports = inject\n\nfunction inject (bot) {\n  bot._client.on('kick_disconnect', (packet) => {\n    bot.emit('kicked', packet.reason, true)\n  })\n  bot._client.on('disconnect', (packet) => {\n    bot.emit('kicked', packet.reason, false)\n  })\n  bot.quit = (reason) => {\n    reason = reason ?? 'disconnect.quitting'\n    bot.end(reason)\n  }\n}\n"
  },
  {
    "path": "lib/plugins/particle.js",
    "content": "module.exports = inject\n\nfunction inject (bot, { version }) {\n  const Particle = require('../particle')(bot.registry)\n\n  bot._client.on('world_particles', (packet) => {\n    bot.emit('particle', Particle.fromNetwork(packet))\n  })\n}\n"
  },
  {
    "path": "lib/plugins/physics.js",
    "content": "const { Vec3 } = require('vec3')\nconst assert = require('assert')\nconst math = require('../math')\nconst conv = require('../conversions')\nconst { performance } = require('perf_hooks')\nconst { createDoneTask, createTask } = require('../promise_utils')\n\nconst { Physics, PlayerState } = require('prismarine-physics')\n\nmodule.exports = inject\n\nconst PI = Math.PI\nconst PI_2 = Math.PI * 2\nconst PHYSICS_INTERVAL_MS = 50\nconst PHYSICS_TIMESTEP = PHYSICS_INTERVAL_MS / 1000 // 0.05\n\nfunction inject (bot, { physicsEnabled, maxCatchupTicks }) {\n  const PHYSICS_CATCHUP_TICKS = maxCatchupTicks ?? 4\n  const world = { getBlock: (pos) => { return bot.blockAt(pos, false) } }\n  const physics = Physics(bot.registry, world)\n\n  const positionUpdateSentEveryTick = bot.supportFeature('positionUpdateSentEveryTick')\n\n  bot.jumpQueued = false\n  bot.jumpTicks = 0 // autojump cooldown\n\n  const controlState = {\n    forward: false,\n    back: false,\n    left: false,\n    right: false,\n    jump: false,\n    sprint: false,\n    sneak: false\n  }\n  let lastSentYaw = null\n  let lastSentPitch = null\n  let doPhysicsTimer = null\n  let lastPhysicsFrameTime = null\n  let shouldUsePhysics = false\n  bot.physicsEnabled = physicsEnabled ?? true\n  let deadTicks = 21\n\n  const lastSent = {\n    x: 0,\n    y: 0,\n    z: 0,\n    yaw: 0,\n    pitch: 0,\n    onGround: false,\n    time: 0,\n    flags: { onGround: false, hasHorizontalCollision: false }\n  }\n\n  // This function should be executed each tick (every 0.05 seconds)\n  // How it works: https://gafferongames.com/post/fix_your_timestep/\n\n  // WARNING: THIS IS NOT ACCURATE ON WINDOWS (15.6 Timer Resolution)\n  // use WSL or switch to Linux\n  // see: https://discord.com/channels/413438066984747026/519952494768685086/901948718255833158\n  let timeAccumulator = 0\n  let catchupTicks = 0\n  function doPhysics () {\n    const now = performance.now()\n    const deltaSeconds = (now - lastPhysicsFrameTime) / 1000\n    lastPhysicsFrameTime = now\n\n    timeAccumulator += deltaSeconds\n    catchupTicks = 0\n    while (timeAccumulator >= PHYSICS_TIMESTEP) {\n      tickPhysics(now)\n      timeAccumulator -= PHYSICS_TIMESTEP\n      catchupTicks++\n      if (catchupTicks >= PHYSICS_CATCHUP_TICKS) break\n    }\n  }\n\n  function tickPhysics (now) {\n    if (bot.blockAt(bot.entity.position) == null) return // check if chunk is unloaded\n    if (bot.physicsEnabled && shouldUsePhysics) {\n      physics.simulatePlayer(new PlayerState(bot, controlState), world).apply(bot)\n      bot.emit('physicsTick')\n      bot.emit('physicTick') // Deprecated, only exists to support old plugins. May be removed in the future\n    }\n    if (shouldUsePhysics) {\n      updatePosition(now)\n    }\n  }\n\n  // remove this when 'physicTick' is removed\n  bot.on('newListener', (name) => {\n    if (name === 'physicTick') console.warn('Mineflayer detected that you are using a deprecated event (physicTick)! Please use this event (physicsTick) instead.')\n  })\n\n  function cleanup () {\n    clearInterval(doPhysicsTimer)\n    doPhysicsTimer = null\n  }\n\n  function sendPacketPosition (position, onGround) {\n    // sends data, no logic\n    const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z)\n    lastSent.x = position.x\n    lastSent.y = position.y\n    lastSent.z = position.z\n    lastSent.onGround = onGround\n    lastSent.flags = { onGround, hasHorizontalCollision: undefined } // 1.21.3+\n    bot._client.write('position', lastSent)\n    bot.emit('move', oldPos)\n  }\n\n  function sendPacketLook (yaw, pitch, onGround) {\n    // sends data, no logic\n    const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z)\n    lastSent.yaw = yaw\n    lastSent.pitch = pitch\n    lastSent.onGround = onGround\n    lastSent.flags = { onGround, hasHorizontalCollision: undefined } // 1.21.3+\n    bot._client.write('look', lastSent)\n    bot.emit('move', oldPos)\n  }\n\n  function sendPacketPositionAndLook (position, yaw, pitch, onGround) {\n    // sends data, no logic\n    const oldPos = new Vec3(lastSent.x, lastSent.y, lastSent.z)\n    lastSent.x = position.x\n    lastSent.y = position.y\n    lastSent.z = position.z\n    lastSent.yaw = yaw\n    lastSent.pitch = pitch\n    lastSent.onGround = onGround\n    lastSent.flags = { onGround, hasHorizontalCollision: undefined } // 1.21.3+\n    bot._client.write('position_look', lastSent)\n    bot.emit('move', oldPos)\n  }\n\n  function deltaYaw (yaw1, yaw2) {\n    let dYaw = (yaw1 - yaw2) % PI_2\n    if (dYaw < -PI) dYaw += PI_2\n    else if (dYaw > PI) dYaw -= PI_2\n\n    return dYaw\n  }\n\n  // returns false if bot should send position packets\n  function isEntityRemoved () {\n    if (bot.isAlive === true) deadTicks = 0\n    if (bot.isAlive === false && deadTicks <= 20) deadTicks++\n    if (deadTicks >= 20) return true\n    return false\n  }\n\n  function updatePosition (now) {\n    // Only send updates for 20 ticks after death\n    if (isEntityRemoved()) return\n\n    // Increment the yaw in baby steps so that notchian clients (not the server) can keep up.\n    const dYaw = deltaYaw(bot.entity.yaw, lastSentYaw)\n    const dPitch = bot.entity.pitch - (lastSentPitch || 0)\n\n    // Vanilla doesn't clamp yaw, so we don't want to do it either\n    const maxDeltaYaw = PHYSICS_TIMESTEP * physics.yawSpeed\n    const maxDeltaPitch = PHYSICS_TIMESTEP * physics.pitchSpeed\n    lastSentYaw += math.clamp(-maxDeltaYaw, dYaw, maxDeltaYaw)\n    lastSentPitch += math.clamp(-maxDeltaPitch, dPitch, maxDeltaPitch)\n\n    const yaw = Math.fround(conv.toNotchianYaw(lastSentYaw))\n    const pitch = Math.fround(conv.toNotchianPitch(lastSentPitch))\n    const position = bot.entity.position\n    const onGround = bot.entity.onGround\n\n    // Only send a position update if necessary, select the appropriate packet\n    const positionUpdated = lastSent.x !== position.x || lastSent.y !== position.y || lastSent.z !== position.z ||\n      // Send a position update every second, even if no other update was made\n      // This function rounds to the nearest 50ms (or PHYSICS_INTERVAL_MS) and checks if a second has passed.\n      (Math.round((now - lastSent.time) / PHYSICS_INTERVAL_MS) * PHYSICS_INTERVAL_MS) >= 1000\n    const lookUpdated = lastSent.yaw !== yaw || lastSent.pitch !== pitch\n\n    if (positionUpdated && lookUpdated) {\n      sendPacketPositionAndLook(position, yaw, pitch, onGround)\n      lastSent.time = now // only reset if positionUpdated is true\n    } else if (positionUpdated) {\n      sendPacketPosition(position, onGround)\n      lastSent.time = now // only reset if positionUpdated is true\n    } else if (lookUpdated) {\n      sendPacketLook(yaw, pitch, onGround)\n    } else if (positionUpdateSentEveryTick || onGround !== lastSent.onGround) {\n      // For versions < 1.12, one player packet should be sent every tick\n      // for the server to update health correctly\n      // For versions >= 1.12, onGround !== lastSent.onGround should be used, but it doesn't ever trigger outside of login\n      bot._client.write('flying', {\n        onGround: bot.entity.onGround,\n        flags: { onGround: bot.entity.onGround, hasHorizontalCollision: undefined } // 1.21.3+\n      })\n    }\n\n    lastSent.onGround = bot.entity.onGround // onGround is always set\n  }\n\n  bot.physics = physics\n\n  function getEffectLevel (mcData, effectName, effects) {\n    const effectDescriptor = mcData.effectsByName[effectName]\n    if (!effectDescriptor) {\n      return 0\n    }\n    const effectInfo = effects[effectDescriptor.id]\n    if (!effectInfo) {\n      return 0\n    }\n    return effectInfo.amplifier + 1\n  }\n\n  bot.elytraFly = async () => {\n    if (bot.entity.elytraFlying) {\n      throw new Error('Already elytra flying')\n    } else if (bot.entity.onGround) {\n      throw new Error('Unable to fly from ground')\n    } else if (bot.entity.isInWater) {\n      throw new Error('Unable to elytra fly while in water')\n    }\n\n    const mcData = require('minecraft-data')(bot.version)\n    if (getEffectLevel(mcData, 'Levitation', bot.entity.effects) > 0) {\n      throw new Error('Unable to elytra fly with levitation effect')\n    }\n\n    const torsoSlot = bot.getEquipmentDestSlot('torso')\n    const item = bot.inventory.slots[torsoSlot]\n    if (item == null || item.name !== 'elytra') {\n      throw new Error('Elytra must be equip to start flying')\n    }\n    bot._client.write('entity_action', {\n      entityId: bot.entity.id,\n      actionId: bot.supportFeature('entityActionUsesStringMapper') ? 'start_elytra_flying' : 8,\n      jumpBoost: 0\n    })\n  }\n\n  bot.setControlState = (control, state) => {\n    assert.ok(control in controlState, `invalid control: ${control}`)\n    assert.ok(typeof state === 'boolean', `invalid state: ${state}`)\n    if (controlState[control] === state) return\n    controlState[control] = state\n    if (control === 'jump' && state) {\n      bot.jumpQueued = true\n    } else if (control === 'sprint') {\n      bot._client.write('entity_action', {\n        entityId: bot.entity.id,\n        actionId: bot.supportFeature('entityActionUsesStringMapper')\n          ? (state ? 'start_sprinting' : 'stop_sprinting')\n          : (state ? 3 : 4),\n        jumpBoost: 0\n      })\n    } else if (control === 'sneak') {\n      if (bot.supportFeature('newPlayerInputPacket')) {\n        // In 1.21.6+, sneak is handled via player_input packet\n        bot._client.write('player_input', {\n          inputs: {\n            shift: state\n          }\n        })\n      } else {\n        // Legacy entity_action approach for older versions\n        bot._client.write('entity_action', {\n          entityId: bot.entity.id,\n          actionId: state ? 0 : 1,\n          jumpBoost: 0\n        })\n      }\n    }\n  }\n\n  bot.getControlState = (control) => {\n    assert.ok(control in controlState, `invalid control: ${control}`)\n    return controlState[control]\n  }\n\n  bot.clearControlStates = () => {\n    for (const control in controlState) {\n      bot.setControlState(control, false)\n    }\n  }\n\n  bot.controlState = {}\n\n  for (const control of Object.keys(controlState)) {\n    Object.defineProperty(bot.controlState, control, {\n      get () {\n        return controlState[control]\n      },\n      set (state) {\n        bot.setControlState(control, state)\n        return state\n      }\n    })\n  }\n\n  let lookingTask = createDoneTask()\n\n  bot.on('move', () => {\n    if (!lookingTask.done && Math.abs(deltaYaw(bot.entity.yaw, lastSentYaw)) < 0.001) {\n      lookingTask.finish()\n    }\n  })\n\n  bot._client.on('explosion', explosion => {\n    // TODO: emit an explosion event with more info\n    if (bot.physicsEnabled && bot.game.gameMode !== 'creative') {\n      if (explosion.playerKnockback) { // 1.21.3+\n        // Fixes issue #3635\n        bot.entity.velocity.x += explosion.playerKnockback.x\n        bot.entity.velocity.y += explosion.playerKnockback.y\n        bot.entity.velocity.z += explosion.playerKnockback.z\n      }\n      if ('playerMotionX' in explosion) {\n        bot.entity.velocity.x += explosion.playerMotionX\n        bot.entity.velocity.y += explosion.playerMotionY\n        bot.entity.velocity.z += explosion.playerMotionZ\n      }\n    }\n  })\n\n  bot.look = async (yaw, pitch, force) => {\n    if (!lookingTask.done) {\n      lookingTask.finish() // finish the previous one\n    }\n    lookingTask = createTask()\n\n    // this is done to bypass certain anticheat checks that detect the player's sensitivity\n    // by calculating the gcd of how much they move the mouse each tick\n    const sensitivity = conv.fromNotchianPitch(0.15) // this is equal to 100% sensitivity in vanilla\n    const yawChange = Math.round((yaw - bot.entity.yaw) / sensitivity) * sensitivity\n    const pitchChange = Math.round((pitch - bot.entity.pitch) / sensitivity) * sensitivity\n\n    if (yawChange === 0 && pitchChange === 0) {\n      return\n    }\n\n    bot.entity.yaw += yawChange\n    bot.entity.pitch += pitchChange\n\n    if (force) {\n      lastSentYaw = yaw\n      lastSentPitch = pitch\n      return\n    }\n\n    await lookingTask.promise\n  }\n\n  bot.lookAt = async (point, force) => {\n    const delta = point.minus(bot.entity.position.offset(0, bot.entity.eyeHeight, 0))\n    const yaw = Math.atan2(-delta.x, -delta.z)\n    const groundDistance = Math.sqrt(delta.x * delta.x + delta.z * delta.z)\n    const pitch = Math.atan2(delta.y, groundDistance)\n    await bot.look(yaw, pitch, force)\n  }\n\n  // 1.21.3+\n  bot._client.on('player_rotation', (packet) => {\n    bot.entity.yaw = conv.fromNotchianYaw(packet.yaw)\n    bot.entity.pitch = conv.fromNotchianPitch(packet.pitch)\n  })\n\n  // player position and look (clientbound)\n  bot._client.on('position', (packet) => {\n    // Is this necessary? Feels like it might wrongly overwrite hitbox size sometimes\n    // e.g. when crouching/crawling/swimming. Can someone confirm?\n    bot.entity.height = 1.8\n\n    const vel = bot.entity.velocity\n    const pos = bot.entity.position\n    let newYaw, newPitch\n\n    // Note: 1.20.5+ uses a bitflags object, older versions use a bitmask number\n    if (typeof packet.flags === 'object') {\n      // Modern path with bitflags object\n      // Velocity is only set to 0 if the flag is not set, otherwise keep current velocity\n      vel.set(\n        packet.flags.x ? vel.x : 0,\n        packet.flags.y ? vel.y : 0,\n        packet.flags.z ? vel.z : 0\n      )\n      // If flag is set, then the corresponding value is relative, else it is absolute\n      pos.set(\n        packet.flags.x ? (pos.x + packet.x) : packet.x,\n        packet.flags.y ? (pos.y + packet.y) : packet.y,\n        packet.flags.z ? (pos.z + packet.z) : packet.z\n      )\n      newYaw = (packet.flags.yaw ? conv.toNotchianYaw(bot.entity.yaw) : 0) + packet.yaw\n      newPitch = (packet.flags.pitch ? conv.toNotchianPitch(bot.entity.pitch) : 0) + packet.pitch\n    } else {\n      // Legacy path with bitmask number\n      // Velocity is only set to 0 if the flag is not set, otherwise keep current velocity\n      vel.set(\n        packet.flags & 1 ? vel.x : 0,\n        packet.flags & 2 ? vel.y : 0,\n        packet.flags & 4 ? vel.z : 0\n      )\n      // If flag is set, then the corresponding value is relative, else it is absolute\n      pos.set(\n        packet.flags & 1 ? (pos.x + packet.x) : packet.x,\n        packet.flags & 2 ? (pos.y + packet.y) : packet.y,\n        packet.flags & 4 ? (pos.z + packet.z) : packet.z\n      )\n      newYaw = (packet.flags & 8 ? conv.toNotchianYaw(bot.entity.yaw) : 0) + packet.yaw\n      newPitch = (packet.flags & 16 ? conv.toNotchianPitch(bot.entity.pitch) : 0) + packet.pitch\n    }\n\n    bot.entity.yaw = conv.fromNotchianYaw(newYaw)\n    bot.entity.pitch = conv.fromNotchianPitch(newPitch)\n    bot.entity.onGround = false\n\n    if (bot.supportFeature('teleportUsesOwnPacket')) {\n      bot._client.write('teleport_confirm', { teleportId: packet.teleportId })\n    }\n    sendPacketPositionAndLook(pos, newYaw, newPitch, bot.entity.onGround)\n\n    shouldUsePhysics = true\n    bot.jumpTicks = 0\n    lastSentYaw = bot.entity.yaw\n    lastSentPitch = bot.entity.pitch\n\n    bot.emit('forcedMove')\n  })\n\n  bot.waitForTicks = async function (ticks) {\n    if (ticks <= 0) return\n    await new Promise((resolve, reject) => {\n      // Assuming 20 ticks per second, add extra time for lag\n      const timeout = setTimeout(() => {\n        bot.removeListener('physicsTick', tickListener)\n        reject(new Error(`Timeout waiting for ${ticks} ticks after ${(ticks * 50 + 5000)}ms`))\n      }, ticks * 50 + 5000) // 50ms per tick + 5s buffer\n\n      const tickListener = () => {\n        ticks--\n        if (ticks === 0) {\n          clearTimeout(timeout)\n          bot.removeListener('physicsTick', tickListener)\n          resolve()\n        }\n      }\n\n      bot.on('physicsTick', tickListener)\n    })\n  }\n\n  bot.on('mount', () => { shouldUsePhysics = false })\n  bot.on('respawn', () => { shouldUsePhysics = false })\n  bot.on('login', () => {\n    shouldUsePhysics = false\n    if (doPhysicsTimer === null) {\n      lastPhysicsFrameTime = performance.now()\n      doPhysicsTimer = setInterval(doPhysics, PHYSICS_INTERVAL_MS)\n    }\n  })\n  bot.on('end', cleanup)\n}\n"
  },
  {
    "path": "lib/plugins/place_block.js",
    "content": "const { onceWithCleanup } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  async function placeBlockWithOptions (referenceBlock, faceVector, options) {\n    const dest = referenceBlock.position.plus(faceVector)\n    let oldBlock = bot.blockAt(dest)\n    await bot._genericPlace(referenceBlock, faceVector, options)\n\n    let newBlock = bot.blockAt(dest)\n    if (oldBlock.type === newBlock.type) {\n      [oldBlock, newBlock] = await onceWithCleanup(bot, `blockUpdate:${dest}`, {\n        timeout: 5000,\n        // Condition to wait to receive block update actually changing the block type, in case the bot receives block updates with no changes\n        // oldBlock and newBlock will both be null when the world unloads\n        checkCondition: (oldBlock, newBlock) => !oldBlock || !newBlock || oldBlock.type !== newBlock.type\n      })\n    }\n\n    // blockUpdate emits (null, null) when the world unloads\n    if (!oldBlock && !newBlock) {\n      return\n    }\n    if (oldBlock?.type === newBlock.type) {\n      throw new Error(`No block has been placed : the block is still ${oldBlock?.name}`)\n    } else {\n      bot.emit('blockPlaced', oldBlock, newBlock)\n    }\n  }\n\n  async function placeBlock (referenceBlock, faceVector) {\n    await placeBlockWithOptions(referenceBlock, faceVector, { swingArm: 'right' })\n  }\n\n  bot.placeBlock = placeBlock\n  bot._placeBlockWithOptions = placeBlockWithOptions\n}\n"
  },
  {
    "path": "lib/plugins/place_entity.js",
    "content": "const assert = require('assert')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  const Item = require('prismarine-item')(bot.registry)\n\n  /**\n   *\n   * @param {import('prismarine-block').Block} referenceBlock\n   * @param {import('vec3').Vec3} faceVector\n   * @param {{forceLook?: boolean | 'ignore', offhand?: boolean, swingArm?: 'right' | 'left', showHand?: boolean}} options\n   */\n  async function placeEntityWithOptions (referenceBlock, faceVector, options) {\n    if (!bot.heldItem) throw new Error('must be holding an item to place an entity')\n\n    const type = bot.heldItem.name // used for assert\n      .replace(/.+_boat/, 'boat')\n      .replace(/.+_spawn_egg/, 'spawn_egg')\n    assert(['end_crystal', 'boat', 'spawn_egg', 'armor_stand'].includes(type), 'Unimplemented')\n\n    let name = bot.heldItem.name // used for finding entity after spawn\n      .replace(/.+_boat/, 'boat')\n\n    if (name.endsWith('spawn_egg')) {\n      name = bot.heldItem.spawnEggMobName\n    }\n\n    if (type === 'spawn_egg') {\n      options.showHand = false\n    }\n\n    if (!options.swingArm) options.swingArm = options.offhand ? 'left' : 'right'\n\n    const pos = await bot._genericPlace(referenceBlock, faceVector, options)\n\n    if (type === 'boat') {\n      if (bot.supportFeature('useItemWithOwnPacket')) {\n        bot._client.write('use_item', {\n          hand: options.offhand ? 1 : 0\n        })\n      } else {\n        bot._client.write('block_place', {\n          location: { x: -1, y: -1, z: -1 },\n          direction: -1,\n          heldItem: Item.toNotch(bot.heldItem),\n          cursorX: 0,\n          cursorY: 0,\n          cursorZ: 0\n        })\n      }\n    }\n\n    const dest = pos.plus(faceVector)\n    const entity = await waitForEntitySpawn(name, dest)\n    bot.emit('entityPlaced', entity)\n    return entity\n  }\n\n  async function placeEntity (referenceBlock, faceVector) {\n    return await placeEntityWithOptions(referenceBlock, faceVector, {})\n  }\n\n  function waitForEntitySpawn (name, placePosition) {\n    const maxDistance = name === 'bat' ? 4 : name === 'boat' ? 3 : 2\n    let mobName = name\n    if (name === 'end_crystal') {\n      if (bot.supportFeature('enderCrystalNameEndsInErNoCaps')) {\n        mobName = 'ender_crystal'\n      } else if (bot.supportFeature('entityNameLowerCaseNoUnderscore')) {\n        mobName = 'endercrystal'\n      } else if (bot.supportFeature('enderCrystalNameNoCapsWithUnderscore')) {\n        mobName = 'end_crystal'\n      } else {\n        mobName = 'EnderCrystal'\n      }\n    } else if (name === 'boat') {\n      mobName = bot.supportFeature('entityNameUpperCaseNoUnderscore') ? 'Boat' : 'boat'\n    } else if (name === 'armor_stand') {\n      if (bot.supportFeature('entityNameUpperCaseNoUnderscore')) {\n        mobName = 'ArmorStand'\n      } else if (bot.supportFeature('entityNameLowerCaseNoUnderscore')) {\n        mobName = 'armorstand'\n      } else {\n        mobName = 'armor_stand'\n      }\n    }\n\n    return new Promise((resolve, reject) => {\n      function listener (entity) {\n        const dist = entity.position.distanceTo(placePosition)\n        if (entity.name === mobName && dist < maxDistance) {\n          resolve(entity)\n        }\n        bot.off('entitySpawn', listener)\n      }\n\n      setTimeout(() => {\n        bot.off('entitySpawn', listener)\n        reject(new Error('Failed to place entity'))\n      }, 5000) // reject after 5s\n\n      bot.on('entitySpawn', listener)\n    })\n  }\n\n  bot.placeEntity = placeEntity\n  bot._placeEntityWithOptions = placeEntityWithOptions\n}\n"
  },
  {
    "path": "lib/plugins/rain.js",
    "content": "module.exports = inject\nconst states = ['no_respawn_block_available', 'start_raining', 'stop_raining', 'change_game_mode', 'win_game', 'demo_event', 'play_arrow_hit_sound', 'rain_level_change', 'thunder_level_change', 'puffer_fish_sting', 'guardian_elder_effect', 'immediate_respawn', 'limited_crafting', 'level_chunks_load_start']\n\nfunction inject (bot) {\n  bot.isRaining = false\n  bot.thunderState = 0\n  bot.rainState = 0\n  bot._client.on('game_state_change', (packet) => {\n    const reason = states[packet.reason] ?? packet.reason\n    if (reason === 'start_raining') {\n      bot.isRaining = true\n      bot.emit('rain')\n    } else if (reason === 'stop_raining') {\n      bot.isRaining = false\n      bot.emit('rain')\n    } else if (reason === 'rain_level_change') {\n      bot.rainState = packet.gameMode\n      bot.emit('weatherUpdate')\n    } else if (reason === 'thunder_level_change') {\n      bot.thunderState = packet.gameMode\n      bot.emit('weatherUpdate')\n    }\n  })\n}\n"
  },
  {
    "path": "lib/plugins/ray_trace.js",
    "content": "const { Vec3 } = require('vec3')\nconst { RaycastIterator } = require('prismarine-world').iterators\n\nmodule.exports = (bot) => {\n  function getViewDirection (pitch, yaw) {\n    const csPitch = Math.cos(pitch)\n    const snPitch = Math.sin(pitch)\n    const csYaw = Math.cos(yaw)\n    const snYaw = Math.sin(yaw)\n    return new Vec3(-snYaw * csPitch, snPitch, -csYaw * csPitch)\n  }\n\n  bot.blockInSight = (maxSteps = 256, vectorLength = 5 / 16) => {\n    const block = bot.blockAtCursor(maxSteps * vectorLength)\n    if (block) return block\n  }\n\n  bot.blockAtCursor = (maxDistance = 256, matcher = null) => {\n    return bot.blockAtEntityCursor(bot.entity, maxDistance, matcher)\n  }\n\n  bot.entityAtCursor = (maxDistance = 3.5) => {\n    const block = bot.blockAtCursor(maxDistance)\n    maxDistance = block?.intersect.distanceTo(bot.entity.position) ?? maxDistance\n\n    const entities = Object.values(bot.entities)\n      .filter(entity => entity.type !== 'object' && entity.username !== bot.username && entity.position.distanceTo(bot.entity.position) <= maxDistance)\n\n    const dir = new Vec3(-Math.sin(bot.entity.yaw) * Math.cos(bot.entity.pitch), Math.sin(bot.entity.pitch), -Math.cos(bot.entity.yaw) * Math.cos(bot.entity.pitch))\n    const iterator = new RaycastIterator(bot.entity.position.offset(0, bot.entity.eyeHeight, 0), dir.normalize(), maxDistance)\n\n    let targetEntity = null\n    let targetDist = maxDistance\n\n    for (let i = 0; i < entities.length; i++) {\n      const entity = entities[i]\n      const w = entity.width / 2\n\n      const shapes = [[-w, 0, -w, w, entity.height, w]]\n      const intersect = iterator.intersect(shapes, entity.position)\n      if (intersect) {\n        const entityDir = entity.position.minus(bot.entity.position) // Can be combined into 1 line\n        const sign = Math.sign(entityDir.dot(dir))\n        if (sign !== -1) {\n          const dist = bot.entity.position.distanceTo(intersect.pos)\n          if (dist < targetDist) {\n            targetEntity = entity\n            targetDist = dist\n          }\n        }\n      }\n    }\n\n    return targetEntity\n  }\n\n  bot.blockAtEntityCursor = (entity = bot.entity, maxDistance = 256, matcher = null) => {\n    if (!entity.position || !entity.height || !entity.pitch || !entity.yaw) return null\n    const { position, height, pitch, yaw } = entity\n\n    const eyePosition = position.offset(0, height, 0)\n    const viewDirection = getViewDirection(pitch, yaw)\n\n    return bot.world.raycast(eyePosition, viewDirection, maxDistance, matcher)\n  }\n}\n"
  },
  {
    "path": "lib/plugins/resource_pack.js",
    "content": "const UUID = require('uuid-1345')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  let uuid\n  let latestHash\n  let latestUUID\n  let activeResourcePacks = {}\n  const TEXTURE_PACK_RESULTS = {\n    SUCCESSFULLY_LOADED: 0,\n    DECLINED: 1,\n    FAILED_DOWNLOAD: 2,\n    ACCEPTED: 3\n  }\n\n  bot._client.on('add_resource_pack', (data) => { // Emits the same as resource_pack_send but sends uuid rather than hash because that's how active packs are tracked\n    const uuid = new UUID(data.uuid)\n    // Adding the pack to a set by uuid\n    latestUUID = uuid\n    activeResourcePacks[uuid] = data.url\n\n    bot.emit('resourcePack', data.url, uuid)\n  })\n\n  bot._client.on('remove_resource_pack', (data) => { // Doesn't emit  anything because it is removing rather than adding\n    // if uuid isn't provided remove all packs\n    if (data.uuid === undefined) {\n      activeResourcePacks = {}\n    } else {\n      // Try to remove uuid from set\n      try {\n        delete activeResourcePacks[new UUID(data.uuid)]\n      } catch (error) {\n        console.error('Tried to remove UUID but it was not in the active list.')\n      }\n    }\n  })\n\n  bot._client.on('resource_pack_send', (data) => {\n    if (bot.supportFeature('resourcePackUsesUUID')) {\n      uuid = new UUID(data.uuid)\n      bot.emit('resourcePack', uuid, data.url)\n      latestUUID = uuid\n    } else {\n      bot.emit('resourcePack', data.url, data.hash)\n      latestHash = data.hash\n    }\n  })\n\n  function acceptResourcePack () {\n    if (bot.supportFeature('resourcePackUsesHash')) {\n      bot._client.write('resource_pack_receive', {\n        result: TEXTURE_PACK_RESULTS.ACCEPTED,\n        hash: latestHash\n      })\n      bot._client.write('resource_pack_receive', {\n        result: TEXTURE_PACK_RESULTS.SUCCESSFULLY_LOADED,\n        hash: latestHash\n      })\n    } else if (bot.supportFeature('resourcePackUsesUUID')) {\n      bot._client.write('resource_pack_receive', {\n        uuid: latestUUID,\n        result: TEXTURE_PACK_RESULTS.ACCEPTED\n      })\n      bot._client.write('resource_pack_receive', {\n        uuid: latestUUID,\n        result: TEXTURE_PACK_RESULTS.SUCCESSFULLY_LOADED\n      })\n    } else {\n      bot._client.write('resource_pack_receive', {\n        result: TEXTURE_PACK_RESULTS.ACCEPTED\n      })\n      bot._client.write('resource_pack_receive', {\n        result: TEXTURE_PACK_RESULTS.SUCCESSFULLY_LOADED\n      })\n    }\n  }\n\n  function denyResourcePack () {\n    if (bot.supportFeature('resourcePackUsesUUID')) {\n      bot._client.write('resource_pack_receive', {\n        uuid: latestUUID,\n        result: TEXTURE_PACK_RESULTS.DECLINED\n      })\n    }\n    bot._client.write('resource_pack_receive', {\n      result: TEXTURE_PACK_RESULTS.DECLINED\n    })\n  }\n\n  bot.acceptResourcePack = acceptResourcePack\n  bot.denyResourcePack = denyResourcePack\n}\n"
  },
  {
    "path": "lib/plugins/scoreboard.js",
    "content": "module.exports = inject\n\nfunction inject (bot) {\n  const ScoreBoard = require('../scoreboard')(bot)\n  const scoreboards = {}\n\n  bot._client.on('scoreboard_objective', (packet) => {\n    if (packet.action === 0) {\n      const { name } = packet\n      const scoreboard = new ScoreBoard(packet)\n      scoreboards[name] = scoreboard\n\n      bot.emit('scoreboardCreated', scoreboard)\n    }\n\n    if (packet.action === 1) {\n      bot.emit('scoreboardDeleted', scoreboards[packet.name])\n      delete scoreboards[packet.name]\n\n      for (const position in ScoreBoard.positions) {\n        if (!ScoreBoard.positions[position]) continue\n        const scoreboard = ScoreBoard.positions[position]\n\n        if (scoreboard && scoreboard.name === packet.name) {\n          delete ScoreBoard.positions[position]\n          break\n        }\n      }\n    }\n\n    if (packet.action === 2) {\n      if (!Object.hasOwn(scoreboards, packet.name)) {\n        bot.emit('error', new Error(`Received update for unknown objective ${packet.name}`))\n        return\n      }\n      scoreboards[packet.name].setTitle(packet.displayText)\n      bot.emit('scoreboardTitleChanged', scoreboards[packet.name])\n    }\n  })\n\n  bot._client.on('scoreboard_score', (packet) => {\n    const scoreboard = scoreboards[packet.scoreName]\n    if (scoreboard !== undefined && packet.action === 0) {\n      const updated = scoreboard.add(packet.itemName, packet.value)\n      bot.emit('scoreUpdated', scoreboard, updated)\n    }\n\n    if (packet.action === 1) {\n      if (scoreboard !== undefined) {\n        const removed = scoreboard.remove(packet.itemName)\n        return bot.emit('scoreRemoved', scoreboard, removed)\n      }\n\n      for (const sb of Object.values(scoreboards)) {\n        if (packet.itemName in sb.itemsMap) {\n          const removed = sb.remove(packet.itemName)\n          return bot.emit('scoreRemoved', sb, removed)\n        }\n      }\n    }\n  })\n\n  bot._client.on('scoreboard_display_objective', (packet) => {\n    const { name, position } = packet\n    const scoreboard = scoreboards[name]\n\n    if (scoreboard !== undefined) {\n      bot.emit('scoreboardPosition', position, scoreboard, ScoreBoard.positions[position])\n      ScoreBoard.positions[position] = scoreboard\n    }\n  })\n\n  bot.scoreboards = scoreboards\n  bot.scoreboard = ScoreBoard.positions\n}\n"
  },
  {
    "path": "lib/plugins/settings.js",
    "content": "const assert = require('assert')\n\nmodule.exports = inject\n\nconst chatToBits = {\n  enabled: 0,\n  commandsOnly: 1,\n  disabled: 2\n}\n\nconst handToBits = {\n  left: 0,\n  right: 1\n}\n\nconst viewDistanceToBits = {\n  far: 12,\n  normal: 10,\n  short: 8,\n  tiny: 6\n}\n\nfunction inject (bot, options) {\n  function setSettings (settings) {\n    extend(bot.settings, settings)\n\n    // chat\n    const chatBits = chatToBits[bot.settings.chat]\n    assert.ok(chatBits != null, `invalid chat setting: ${bot.settings.chat}`)\n\n    // view distance\n    let viewDistanceBits = null\n    if (typeof bot.settings.viewDistance === 'string') {\n      viewDistanceBits = viewDistanceToBits[bot.settings.viewDistance]\n    } else if (typeof bot.settings.viewDistance === 'number' && bot.settings.viewDistance > 0) { // Make sure view distance is a valid # || should be 2 or more\n      viewDistanceBits = bot.settings.viewDistance\n    }\n    assert.ok(viewDistanceBits != null, `invalid view distance setting: ${bot.settings.viewDistance}`)\n\n    // hand\n    const handBits = handToBits[bot.settings.mainHand]\n    assert.ok(handBits != null, `invalid main hand: ${bot.settings.mainHand}`)\n\n    // skin\n    // cape is inverted, not used at all (legacy?)\n    // bot.settings.showCape = !!bot.settings.showCape\n    const skinParts = bot.settings.skinParts.showCape << 0 |\n          bot.settings.skinParts.showJacket << 1 |\n          bot.settings.skinParts.showLeftSleeve << 2 |\n          bot.settings.skinParts.showRightSleeve << 3 |\n          bot.settings.skinParts.showLeftPants << 4 |\n          bot.settings.skinParts.showRightPants << 5 |\n          bot.settings.skinParts.showHat << 6\n\n    // write the packet\n    bot._client.write('settings', {\n      locale: bot.settings.locale || 'en_US',\n      viewDistance: viewDistanceBits,\n      chatFlags: chatBits,\n      chatColors: bot.settings.colorsEnabled,\n      skinParts,\n      mainHand: handBits,\n      enableTextFiltering: bot.settings.enableTextFiltering,\n      enableServerListing: bot.settings.enableServerListing\n    })\n  }\n\n  bot.settings = {\n    chat: options.chat || 'enabled',\n    colorsEnabled: options.colorsEnabled == null\n      ? true\n      : options.colorsEnabled,\n    viewDistance: options.viewDistance || 'far',\n    difficulty: options.difficulty == null\n      ? 2\n      : options.difficulty,\n    skinParts: options.skinParts == null\n      ? {\n          showCape: true,\n          showJacket: true,\n          showLeftSleeve: true,\n          showRightSleeve: true,\n          showLeftPants: true,\n          showRightPants: true,\n          showHat: true\n        }\n      : options.skinParts,\n    mainHand: options.mainHand || 'right',\n    enableTextFiltering: options.enableTextFiltering || false,\n    enableServerListing: options.enableServerListing || true,\n    particleStatus: 'all'\n  }\n\n  bot._client.on('login', () => {\n    setSettings({})\n  })\n\n  bot.setSettings = setSettings\n}\n\nconst hasOwn = {}.hasOwnProperty\nfunction extend (obj, src) {\n  for (const key in src) {\n    if (hasOwn.call(src, key)) obj[key] = src[key]\n  }\n  return obj\n}\n"
  },
  {
    "path": "lib/plugins/simple_inventory.js",
    "content": "const assert = require('assert')\n\nmodule.exports = inject\n\nconst QUICK_BAR_COUNT = 9\nconst QUICK_BAR_START = 36\n\nfunction inject (bot) {\n  let nextQuickBarSlot = 0\n\n  const armorSlots = {\n    head: 5,\n    torso: 6,\n    legs: 7,\n    feet: 8\n  }\n\n  if (!bot.supportFeature('doesntHaveOffHandSlot')) {\n    armorSlots['off-hand'] = 45\n  }\n\n  async function tossStack (item) {\n    assert.ok(item)\n    await bot.clickWindow(item.slot, 0, 0)\n    await bot.clickWindow(-999, 0, 0)\n    bot.closeWindow(bot.currentWindow || bot.inventory)\n  }\n\n  async function toss (itemType, metadata, count) {\n    const window = bot.currentWindow || bot.inventory\n    const options = {\n      window,\n      itemType,\n      metadata,\n      count,\n      sourceStart: window.inventoryStart,\n      sourceEnd: window.inventoryEnd,\n      destStart: -999\n    }\n    await bot.transfer(options)\n  }\n\n  async function unequip (destination) {\n    if (destination === 'hand') {\n      await equipEmpty()\n    } else {\n      await disrobe(destination)\n    }\n  }\n\n  function setQuickBarSlot (slot) {\n    assert.ok(slot >= 0)\n    assert.ok(slot < 9)\n    if (bot.quickBarSlot === slot) return\n    bot.quickBarSlot = slot\n    bot._client.write('held_item_slot', {\n      slotId: slot\n    })\n    bot.updateHeldItem()\n  }\n\n  async function equipEmpty () {\n    for (let i = 0; i < QUICK_BAR_COUNT; ++i) {\n      if (!bot.inventory.slots[QUICK_BAR_START + i]) {\n        setQuickBarSlot(i)\n        return\n      }\n    }\n    const slot = bot.inventory.firstEmptyInventorySlot()\n    if (!slot) {\n      await bot.tossStack(bot.heldItem)\n      return\n    }\n    const equipSlot = QUICK_BAR_START + bot.quickBarSlot\n    await bot.clickWindow(equipSlot, 0, 0)\n    await bot.clickWindow(slot, 0, 0)\n    if (bot.inventory.selectedItem) {\n      await bot.clickWindow(-999, 0, 0)\n    }\n  }\n\n  async function disrobe (destination) {\n    assert.strictEqual(bot.currentWindow, null)\n    const destSlot = getDestSlot(destination)\n    await bot.putAway(destSlot)\n  }\n\n  async function equip (item, destination) {\n    if (typeof item === 'number') {\n      item = bot.inventory.findInventoryItem(item)\n    }\n    if (item == null || typeof item !== 'object') {\n      throw new Error('Invalid item object in equip (item is null or typeof item is not object)')\n    }\n    if (!destination || destination === null) {\n      destination = 'hand'\n    }\n    const sourceSlot = item.slot\n    let destSlot = getDestSlot(destination)\n\n    if (sourceSlot === destSlot) {\n      // don't need to do anything\n      return\n    }\n\n    if (destination !== 'hand') {\n      await bot.moveSlotItem(sourceSlot, destSlot)\n      return\n    }\n\n    if (destSlot >= QUICK_BAR_START && destSlot < (QUICK_BAR_START + QUICK_BAR_COUNT) && sourceSlot >= QUICK_BAR_START && sourceSlot < (QUICK_BAR_START + QUICK_BAR_COUNT)) {\n      // all we have to do is change the quick bar selection\n      bot.setQuickBarSlot(sourceSlot - QUICK_BAR_START)\n      return\n    }\n\n    // find an empty slot on the quick bar to put the source item in\n    destSlot = bot.inventory.firstEmptySlotRange(QUICK_BAR_START, QUICK_BAR_START + QUICK_BAR_COUNT)\n    if (destSlot == null) {\n      // LRU cache for the quick bar items\n      destSlot = QUICK_BAR_START + nextQuickBarSlot\n      nextQuickBarSlot = (nextQuickBarSlot + 1) % QUICK_BAR_COUNT\n    }\n    setQuickBarSlot(destSlot - QUICK_BAR_START)\n    await bot.moveSlotItem(sourceSlot, destSlot)\n  }\n\n  function getDestSlot (destination) {\n    if (destination === 'hand') {\n      return QUICK_BAR_START + bot.quickBarSlot\n    } else {\n      const destSlot = armorSlots[destination]\n      assert.ok(destSlot != null, `invalid destination: ${destination}`)\n      return destSlot\n    }\n  }\n\n  function leftMouse (slot) {\n    return bot.clickWindow(slot, 0, 0)\n  }\n\n  function rightMouse (slot) {\n    return bot.clickWindow(slot, 1, 0)\n  }\n\n  bot.equip = equip\n  bot.unequip = unequip\n  bot.toss = toss\n  bot.tossStack = tossStack\n  bot.setQuickBarSlot = setQuickBarSlot\n  bot.getEquipmentDestSlot = getDestSlot\n  bot.simpleClick = { leftMouse, rightMouse }\n\n  // constants\n  bot.QUICK_BAR_START = QUICK_BAR_START\n}\n"
  },
  {
    "path": "lib/plugins/sound.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  bot._client.on('named_sound_effect', (packet) => {\n    const soundName = packet.soundName\n    const pt = new Vec3(packet.x / 8, packet.y / 8, packet.z / 8)\n    const volume = packet.volume\n    const pitch = packet.pitch\n\n    // In 1.8.8, sound names are in the format \"note.harp\" or \"random.click\"\n    // We need to convert them to the format expected by the test\n    const normalizedSoundName = bot.supportFeature('playsoundUsesResourceLocation')\n      ? `minecraft:${soundName.replace(/\\./g, '_')}`\n      : soundName\n\n    // Emit both events for compatibility with tests\n    bot.emit('soundEffectHeard', normalizedSoundName, pt, volume, pitch)\n    // Emit hardcodedSoundEffectHeard for compatibility (use 0, 'master' as dummy values)\n    bot.emit('hardcodedSoundEffectHeard', 0, 'master', pt, volume, pitch)\n  })\n\n  bot._client.on('sound_effect', (packet) => {\n    const soundCategory = packet.soundCategory\n    const pt = new Vec3(packet.x / 8, packet.y / 8, packet.z / 8)\n    const volume = packet.volume\n    const pitch = packet.pitch\n\n    let soundId, soundName\n\n    if (packet.sound) { // ItemSoundHolder\n      if (packet.sound.data) soundName = packet.sound.data.soundName\n      else soundId = packet.sound.soundId // Sound specified by ID (registry reference)\n    } else { // Legacy packet\n      soundId = packet.soundId\n    }\n\n    // If we have an ID but no name yet, try to look it up in the registry\n    soundName ??= bot.registry?.sounds?.[soundId]?.name\n\n    if (soundName) {\n      bot.emit('soundEffectHeard', soundName, pt, volume, pitch)\n    } else if (soundId !== null) {\n      bot.emit('hardcodedSoundEffectHeard', soundId, soundCategory, pt, volume, pitch)\n    }\n  })\n}\n"
  },
  {
    "path": "lib/plugins/spawn_point.js",
    "content": "const { Vec3 } = require('vec3')\n\nmodule.exports = inject\n\nfunction inject (bot) {\n  bot.spawnPoint = new Vec3(0, 0, 0)\n  bot._client.on('spawn_position', (packet) => {\n    const pos = bot.supportFeature('spawnPositionIsGlobal') ? packet.globalPos.location : packet.location\n    bot.spawnPoint = new Vec3(pos.x, pos.y, pos.z)\n    bot.emit('game')\n  })\n}\n"
  },
  {
    "path": "lib/plugins/tablist.js",
    "content": "module.exports = inject\n\nconst escapeValueNewlines = str => {\n  return str.replace(/(\": *\"(?:\\\\\"|[^\"])+\")/g, (_, match) => match.replace(/\\n/g, '\\\\n'))\n}\n\nfunction inject (bot) {\n  const ChatMessage = require('prismarine-chat')(bot.registry)\n\n  bot.tablist = {\n    header: new ChatMessage(''),\n    footer: new ChatMessage('')\n  }\n\n  bot._client.on('playerlist_header', (packet) => {\n    if (bot.supportFeature('chatPacketsUseNbtComponents')) { // 1.20.3+\n      bot.tablist.header = ChatMessage.fromNotch(packet.header)\n      bot.tablist.footer = ChatMessage.fromNotch(packet.footer)\n    } else {\n      if (packet.header) {\n        const header = escapeValueNewlines(packet.header)\n        bot.tablist.header = ChatMessage.fromNotch(header)\n      }\n\n      if (packet.footer) {\n        const footer = escapeValueNewlines(packet.footer)\n        bot.tablist.footer = ChatMessage.fromNotch(footer)\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "lib/plugins/team.js",
    "content": "module.exports = inject\n\n// TODO: apply this to all versions and rename scoreboard_team -> teams in minecraft-data\nconst TEAM_MODES = ['add', 'remove', 'change', 'join', 'leave']\n\nfunction inject (bot) {\n  const Team = require('../team')(bot.registry)\n  const teams = {}\n\n  function teamHandler (packet) {\n    const { team: teamName, players = [] } = packet\n    const mode = typeof packet.mode === 'number' ? TEAM_MODES[packet.mode] : packet.mode\n\n    let team = teams[teamName]\n\n    switch (mode) {\n      case 'add':\n        team = new Team(\n          teamName,\n          packet.name,\n          packet.friendlyFire,\n          packet.nameTagVisibility,\n          packet.collisionRule,\n          packet.formatting,\n          packet.prefix,\n          packet.suffix\n        )\n        for (const player of players) {\n          team.add(player)\n          bot.teamMap[player] = team\n        }\n        teams[teamName] = team\n        bot.emit('teamCreated', teams[teamName])\n        break\n\n      case 'remove':\n        if (!team) break\n        team.members.forEach((member) => {\n          delete bot.teamMap[member]\n        })\n        delete teams[teamName]\n        bot.emit('teamRemoved', teams[teamName])\n        break\n\n      case 'change':\n        if (!team) break\n        team.update(\n          packet.name,\n          packet.friendlyFire,\n          packet.nameTagVisibility,\n          packet.collisionRule,\n          packet.formatting,\n          packet.prefix,\n          packet.suffix\n        )\n        bot.emit('teamUpdated', teams[teamName])\n        break\n\n      case 'join':\n        if (!team) break\n        for (const player of players) {\n          team.add(player)\n          bot.teamMap[player] = team\n        }\n        bot.emit('teamMemberAdded', teams[teamName])\n        break\n\n      case 'leave':\n        if (!team) break\n        for (const player of players) {\n          team.remove(player)\n          delete bot.teamMap[player]\n        }\n        bot.emit('teamMemberRemoved', teams[teamName])\n        break\n\n      default:\n        bot._warn(`Unknown team mode handling team update: ${mode}`)\n    }\n  }\n\n  if (bot.supportFeature('teamUsesScoreboard')) {\n    bot._client.on('scoreboard_team', teamHandler)\n  } else {\n    bot._client.on('teams', teamHandler)\n  }\n\n  bot.teams = teams\n  bot.teamMap = {}\n}\n"
  },
  {
    "path": "lib/plugins/time.js",
    "content": "module.exports = inject\n\nfunction inject (bot) {\n  bot.time = {\n    doDaylightCycle: null,\n    bigTime: null,\n    time: null,\n    timeOfDay: null,\n    day: null,\n    isDay: null,\n    moonPhase: null,\n    bigAge: null,\n    age: null\n  }\n  bot._client.on('update_time', (packet) => {\n    const time = longToBigInt(packet.time)\n    const age = longToBigInt(packet.age)\n    const doDaylightCycle = packet.tickDayTime !== undefined ? !!packet.tickDayTime : time >= 0n\n    // When doDaylightCycle is false, we need to take the absolute value of time\n    const finalTime = doDaylightCycle ? time : (time < 0n ? -time : time)\n\n    bot.time.doDaylightCycle = doDaylightCycle\n    bot.time.bigTime = finalTime\n    bot.time.time = Number(finalTime)\n    bot.time.timeOfDay = bot.time.time % 24000\n    bot.time.day = Math.floor(bot.time.time / 24000)\n    bot.time.isDay = bot.time.timeOfDay >= 0 && bot.time.timeOfDay < 13000\n    bot.time.moonPhase = bot.time.day % 8\n    bot.time.bigAge = age\n    bot.time.age = Number(age)\n\n    bot.emit('time')\n  })\n}\n\nfunction longToBigInt (arr) {\n  return BigInt.asIntN(64, (BigInt(arr[0]) << 32n)) | BigInt(arr[1])\n}\n"
  },
  {
    "path": "lib/plugins/title.js",
    "content": "module.exports = inject\nfunction inject (bot) {\n  function parseTitle (text) {\n    try {\n      const parsed = JSON.parse(text)\n      return typeof parsed === 'string' ? parsed : (parsed.text || text)\n    } catch {\n      return typeof text === 'string' ? text.replace(/^\"|\"$/g, '') : text\n    }\n  }\n\n  if (bot.supportFeature('titleUsesLegacyPackets')) {\n    bot._client.on('title', (packet) => {\n      if (packet.action === 0) bot.emit('title', parseTitle(packet.text), 'title')\n      else if (packet.action === 1) bot.emit('title', parseTitle(packet.text), 'subtitle')\n      else if (packet.action === 2) bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)\n      else if (packet.action === 3) {\n        if (packet.fadeIn !== undefined) bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)\n        else bot.emit('title_clear')\n      } else if (packet.action === 4) bot.emit('title_clear')\n    })\n  } else if (bot.supportFeature('titleUsesNewPackets')) {\n    function getText (packet) {\n      let text = packet.text\n      if (typeof text === 'object' && text.value !== undefined) text = text.value\n      return parseTitle(text)\n    }\n    bot._client.on('set_title_text', (packet) => bot.emit('title', getText(packet), 'title'))\n    bot._client.on('set_title_subtitle', (packet) => bot.emit('title', getText(packet), 'subtitle'))\n    bot._client.on('set_title_time', (packet) => {\n      if (typeof packet.fadeIn === 'number' && typeof packet.stay === 'number' && typeof packet.fadeOut === 'number') {\n        bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)\n      }\n    })\n    bot._client.on('clear_titles', () => bot.emit('title_clear'))\n  }\n}\n"
  },
  {
    "path": "lib/plugins/villager.js",
    "content": "const assert = require('assert')\nconst { once } = require('../promise_utils')\n\nmodule.exports = inject\n\nfunction inject (bot, { version }) {\n  const { entitiesByName } = bot.registry\n  const Item = require('prismarine-item')(bot.registry)\n\n  let selectTrade\n  if (bot.supportFeature('useMCTrSel')) {\n    bot._client.registerChannel('MC|TrSel', 'i32')\n    selectTrade = (choice) => {\n      bot._client.writeChannel('MC|TrSel', choice)\n    }\n  } else {\n    selectTrade = (choice) => {\n      bot._client.write('select_trade', { slot: choice })\n    }\n  }\n\n  const tradeListSchema = [\n    'container',\n    [\n      { type: 'i32', name: 'windowId' },\n      {\n        name: 'trades',\n        type: [\n          'array',\n          {\n            countType: 'i8',\n            type: [\n              'container',\n              [\n                { type: 'slot', name: 'inputItem1' },\n                { type: 'slot', name: 'outputItem' },\n                { type: 'bool', name: 'hasItem2' },\n                {\n                  name: 'inputItem2',\n                  type: [\n                    'switch',\n                    {\n                      compareTo: 'hasItem2',\n                      fields: {\n                        true: 'slot',\n                        false: 'void'\n                      }\n                    }\n                  ]\n                },\n                { type: 'bool', name: 'tradeDisabled' },\n                { type: 'i32', name: 'nbTradeUses' },\n                { type: 'i32', name: 'maximumNbTradeUses' }\n              ]\n            ]\n          }]\n      }\n    ]\n  ]\n\n  let tradeListPacket\n  if (bot.supportFeature('useMCTrList')) {\n    tradeListPacket = 'MC|TrList'\n    bot._client.registerChannel('MC|TrList', tradeListSchema)\n  } else if (bot.supportFeature('usetraderlist')) {\n    tradeListPacket = 'minecraft:trader_list'\n    bot._client.registerChannel('minecraft:trader_list', tradeListSchema)\n  } else {\n    tradeListPacket = 'trade_list'\n  }\n\n  async function openVillager (villagerEntity) {\n    const villagerType = entitiesByName.villager ? entitiesByName.villager.id : entitiesByName.Villager.id\n    assert.strictEqual(villagerEntity.entityType, villagerType)\n    let ready = false\n\n    const villagerPromise = bot.openEntity(villagerEntity)\n    bot._client.on(tradeListPacket, gotTrades)\n    const villager = await villagerPromise\n    if (villager.type !== 'minecraft:villager' && villager.type !== 'minecraft:merchant') {\n      throw new Error('Expected minecraft:villager or minecraft:mechant type, but got ' + villager.type)\n    }\n\n    villager.trades = null\n    villager.selectedTrade = null\n\n    villager.once('close', () => {\n      bot._client.removeListener(tradeListPacket, gotTrades)\n    })\n\n    villager.trade = async (index, count) => {\n      await bot.trade(villager, index, count)\n    }\n\n    if (!ready) await once(villager, 'ready')\n    return villager\n\n    async function gotTrades (packet) {\n      const villager = await villagerPromise\n      if (packet.windowId !== villager.id) return\n      assert.ok(packet.trades)\n      villager.trades = packet.trades.map(trade => {\n        trade.inputs = [trade.inputItem1 = Item.fromNotch(trade.inputItem1 || { blockId: -1 })]\n        if (trade.inputItem2?.itemCount != null) {\n          trade.inputs.push(trade.inputItem2 = Item.fromNotch(trade.inputItem2 || { blockId: -1 }))\n        }\n\n        trade.hasItem2 = !!(trade.inputItem2 && trade.inputItem2.type && trade.inputItem2.count)\n        trade.outputs = [trade.outputItem = Item.fromNotch(trade.outputItem || { blockId: -1 })]\n\n        if (trade.demand !== undefined && trade.specialPrice !== undefined) { // the price is affected by demand and reputation\n          const demandDiff = Math.max(0, Math.floor(trade.inputItem1.count * trade.demand * trade.priceMultiplier))\n          trade.realPrice = Math.min(Math.max((trade.inputItem1.count + trade.specialPrice + demandDiff), 1), trade.inputItem1.stackSize)\n        } else {\n          trade.realPrice = trade.inputItem1.count\n        }\n        return trade\n      })\n      if (!ready) {\n        ready = true\n        villager.emit('ready')\n      }\n    }\n  }\n\n  async function trade (villager, index, count) {\n    const choice = parseInt(index, 10) // allow string argument\n    assert.notStrictEqual(villager.trades, null)\n    assert.notStrictEqual(villager.trades[choice], null)\n    const Trade = villager.trades[choice]\n    villager.selectedTrade = Trade\n    count = count || Trade.maximumNbTradeUses - Trade.nbTradeUses\n    assert.ok(Trade.maximumNbTradeUses - Trade.nbTradeUses > 0, 'trade blocked')\n    assert.ok(Trade.maximumNbTradeUses - Trade.nbTradeUses >= count)\n\n    const itemCount1 = villager.count(Trade.inputItem1.type, Trade.inputItem1.metadata)\n    const hasEnoughItem1 = itemCount1 >= Trade.realPrice * count\n    let hasEnoughItem2 = true\n    let itemCount2 = 0\n    if (Trade.hasItem2) {\n      itemCount2 = villager.count(Trade.inputItem2.type, Trade.inputItem2.metadata)\n      hasEnoughItem2 = itemCount2 >= Trade.inputItem2.count * count\n    }\n    if (!hasEnoughItem1) {\n      throw new Error('Not enough item 1 to trade')\n    }\n    if (!hasEnoughItem2) {\n      throw new Error('Not enough item 2 to trade')\n    }\n\n    selectTrade(choice)\n    if (bot.supportFeature('selectingTradeMovesItems')) { // 1.14+ the server moves items around by itself after selecting a trade\n      const proms = []\n      proms.push(once(villager, 'updateSlot:0'))\n      if (Trade.hasItem2) proms.push(once(villager, 'updateSlot:1'))\n      if (bot.supportFeature('setSlotAsTransaction')) {\n        proms.push(once(villager, 'updateSlot:2'))\n      }\n      await Promise.all(proms)\n    }\n\n    for (let i = 0; i < count; i++) {\n      await putRequirements(villager, Trade)\n      // ToDo: See if this does anything kappa\n      Trade.nbTradeUses++\n      if (Trade.maximumNbTradeUses - Trade.nbTradeUses === 0) {\n        Trade.tradeDisabled = true\n      }\n      if (!bot.supportFeature('setSlotAsTransaction')) {\n        villager.updateSlot(2, Object.assign({}, Trade.outputItem))\n\n        const [slot1, slot2] = villager.slots\n        if (slot1) {\n          assert.strictEqual(slot1.type, Trade.inputItem1.type)\n          const updatedCount1 = slot1.count - Trade.realPrice\n          const updatedSlot1 = updatedCount1 <= 0\n            ? null\n            : { ...slot1, count: updatedCount1 }\n          villager.updateSlot(0, updatedSlot1)\n        }\n\n        if (slot2) {\n          assert.strictEqual(slot2.type, Trade.inputItem2.type)\n          const updatedCount2 = slot2.count - Trade.inputItem2.count\n          const updatedSlot2 = updatedCount2 <= 0\n            ? null\n            : { ...slot2, count: updatedCount2 }\n          villager.updateSlot(1, updatedSlot2)\n        }\n      }\n\n      await bot.putAway(2)\n    }\n\n    for (const i of [0, 1]) {\n      if (villager.slots[i]) {\n        await bot.putAway(i) // 1.14+ whole stacks of items will automatically be placed , so there might be some left over\n      }\n    }\n  }\n\n  async function putRequirements (window, Trade) {\n    const [slot1, slot2] = window.slots\n    const { type: type1, metadata: metadata1 } = Trade.inputItem1\n\n    const input1 = slot1\n      ? Math.max(0, Trade.realPrice - slot1.count)\n      : Trade.realPrice\n    if (input1) {\n      await deposit(window, type1, metadata1, input1, 0)\n    }\n    if (Trade.hasItem2) {\n      const { count: tradeCount2, type: type2, metadata: metadata2 } = Trade.inputItem2\n\n      const input2 = slot2\n        ? Math.max(0, tradeCount2 - slot2.count)\n        : tradeCount2\n      if (input2) {\n        await deposit(window, type2, metadata2, input2, 1)\n      }\n    }\n  }\n\n  async function deposit (window, itemType, metadata, count, slot) {\n    const options = {\n      window,\n      itemType,\n      metadata,\n      count,\n      sourceStart: window.inventoryStart,\n      sourceEnd: window.inventoryEnd,\n      destStart: slot,\n      destEnd: slot + 1\n    }\n    await bot.transfer(options)\n  }\n\n  bot.openVillager = openVillager\n  bot.trade = trade\n}\n"
  },
  {
    "path": "lib/promise_utils.js",
    "content": "function sleep (ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nfunction createTask () {\n  const task = {\n    done: false\n  }\n  task.promise = new Promise((resolve, reject) => {\n    task.cancel = (err) => {\n      if (!task.done) {\n        task.done = true\n        reject(err)\n      }\n    }\n    task.finish = (result) => {\n      if (!task.done) {\n        task.done = true\n        resolve(result)\n      }\n    }\n  })\n  return task\n}\n\nfunction createDoneTask () {\n  const task = {\n    done: true,\n    promise: Promise.resolve(),\n    cancel: () => {},\n    finish: () => {}\n  }\n  return task\n}\n\n/**\n * Similar to the 'once' function from the 'events' module, but allows you to add a condition for when you want to\n * actually handle the event, as well as a timeout. The listener is additionally removed if a timeout occurs, instead\n * of with 'once' where a listener might stay forever if it never triggers.\n * Note that timeout and checkCondition, both optional, are in the third parameter as an object.\n * @param emitter - The event emitter to listen to\n * @param event - The name of the event you want to listen for\n * @param [timeout=0] - An amount, in milliseconds, for which to wait before considering the promise failed. <0 = none.\n * @param [checkCondition] - A function which matches the same signature of an event emitter handler, and should return something truthy if you want the event to be handled. If this is not provided, all events are handled.\n * @returns {Promise} A promise which will either resolve to an *array* of values in the handled event, or will reject on timeout if applicable. This may never resolve if no timeout is set and the event does not fire.\n */\nfunction onceWithCleanup (emitter, event, { timeout = 0, checkCondition = undefined } = {}) {\n  const task = createTask()\n\n  const onEvent = (...data) => {\n    if (typeof checkCondition === 'function' && !checkCondition(...data)) {\n      return\n    }\n\n    task.finish(data)\n  }\n\n  emitter.addListener(event, onEvent)\n\n  if (typeof timeout === 'number' && timeout > 0) {\n    // For some reason, the call stack gets lost if we don't create the error outside of the .then call\n    const timeoutError = new Error(`Event ${event} did not fire within timeout of ${timeout}ms`)\n    sleep(timeout).then(() => {\n      if (!task.done) {\n        task.cancel(timeoutError)\n      }\n    })\n  }\n\n  task.promise.catch(() => {}).finally(() => emitter.removeListener(event, onEvent))\n\n  return task.promise\n}\n\nfunction once (emitter, event, timeout = 20000) {\n  return onceWithCleanup(emitter, event, { timeout })\n}\n\nfunction withTimeout (promise, timeout) {\n  return Promise.race([\n    promise,\n    sleep(timeout).then(() => {\n      throw new Error('Promise timed out.')\n    })\n  ])\n}\n\nmodule.exports = {\n  once,\n  sleep,\n  createTask,\n  createDoneTask,\n  onceWithCleanup,\n  withTimeout\n}\n"
  },
  {
    "path": "lib/scoreboard.js",
    "content": "const sortItems = (a, b) => {\n  if (a.value > b.value) return -1\n  if (a.value < b.value) return 1\n  return 1\n}\n\nmodule.exports = (bot) => {\n  const ChatMessage = require('prismarine-chat')(bot.registry)\n\n  class ScoreBoard {\n    constructor (packet) {\n      this.name = packet.name\n      this.setTitle(packet.displayText)\n      this.itemsMap = {}\n    }\n\n    setTitle (title) {\n      try {\n        this.title = JSON.parse(title).text // version>1.13\n      } catch {\n        this.title = title\n      }\n    }\n\n    add (name, value) {\n      this.itemsMap[name] = { name, value }\n      this.itemsMap[name] = {\n        name,\n        value,\n        get displayName () {\n          if (name in bot.teamMap) {\n            return bot.teamMap[name].displayName(name)\n          }\n          return new ChatMessage(name)\n        }\n      }\n      return this.itemsMap[name]\n    }\n\n    remove (name) {\n      const removed = this.itemsMap[name]\n      delete this.itemsMap[name]\n      return removed\n    }\n\n    get items () {\n      return Object.values(this.itemsMap).sort(sortItems)\n    }\n  }\n\n  ScoreBoard.positions = {\n    get list () {\n      return this[0]\n    },\n\n    get sidebar () {\n      return this[1]\n    },\n\n    get belowName () {\n      return this[2]\n    }\n  }\n  return ScoreBoard\n}\n"
  },
  {
    "path": "lib/team.js",
    "content": "function colorString (color) {\n  const formatting = [\n    'black',\n    'dark_blue',\n    'dark_green',\n    'dark_aqua',\n    'dark_red',\n    'dark_purple',\n    'gold',\n    'gray',\n    'dark_gray',\n    'blue',\n    'green',\n    'aqua',\n    'red',\n    'light_purple',\n    'yellow',\n    'white',\n    'obfuscated',\n    'bold',\n    'strikethrough',\n    'underlined',\n    'italic',\n    'reset'\n  ]\n  if (color === undefined || color > 21 || color === -1) return 'reset'\n  return formatting[color]\n}\n\nfunction loader (registry) {\n  const ChatMessage = require('prismarine-chat')(registry)\n  const MessageBuilder = ChatMessage.MessageBuilder\n  return class Team {\n    constructor (team, name, friendlyFire, nameTagVisibility, collisionRule, formatting, prefix, suffix) {\n      this.team = team\n      this.update(name, friendlyFire, nameTagVisibility, collisionRule, formatting, prefix, suffix)\n      this.membersMap = {}\n    }\n\n    parseMessage (value) {\n      if (registry.supportFeature('teamUsesChatComponents')) { // 1.13+\n        return ChatMessage.fromNotch(value)\n      } else {\n        const result = MessageBuilder.fromString(value, { colorSeparator: '§' })\n        if (result === null) {\n          return new ChatMessage('')\n        }\n        return new ChatMessage(result.toJSON())\n      }\n    }\n\n    add (name) {\n      this.membersMap[name] = ''\n      return this.membersMap[name]\n    }\n\n    remove (name) {\n      const removed = this.membersMap[name]\n      delete this.membersMap[name]\n      return removed\n    }\n\n    update (name, friendlyFire, nameTagVisibility, collisionRule, formatting, prefix, suffix) {\n      this.name = this.parseMessage(name)\n      this.friendlyFire = friendlyFire\n      this.nameTagVisibility = nameTagVisibility\n      this.collisionRule = collisionRule\n      this.color = colorString(formatting)\n      this.prefix = this.parseMessage(prefix)\n      this.suffix = this.parseMessage(suffix)\n    }\n\n    // Return a chat component with prefix + color + name + suffix\n    displayName (member) {\n      const name = this.prefix.clone()\n      name.append(new ChatMessage({ text: member, color: this.color }), this.suffix)\n      return name\n    }\n\n    get members () {\n      return Object.keys(this.membersMap)\n    }\n  }\n}\n\nmodule.exports = loader\n"
  },
  {
    "path": "lib/version.js",
    "content": "const testedVersions = ['1.8.8', '1.9.4', '1.10.2', '1.11.2', '1.12.2', '1.13.2', '1.14.4', '1.15.2', '1.16.5', '1.17.1', '1.18.2', '1.19', '1.19.2', '1.19.3', '1.19.4', '1.20.1', '1.20.2', '1.20.4', '1.20.6', '1.21.1', '1.21.3', '1.21.4', '1.21.5', '1.21.6', '1.21.8', '1.21.9', '1.21.11']\nmodule.exports = {\n\n  testedVersions,\n  latestSupportedVersion: testedVersions[testedVersions.length - 1],\n  oldestSupportedVersion: testedVersions[0]\n\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"mineflayer\",\n  \"version\": \"4.35.0\",\n  \"description\": \"create minecraft bots with a stable, high level API\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\",\n  \"scripts\": {\n    \"mocha_test\": \"mocha --reporter spec --exit\",\n    \"test\": \"npm run mocha_test\",\n    \"pretest\": \"npm run lint\",\n    \"lint\": \"standard && standard-markdown\",\n    \"fix\": \"standard --fix && standard-markdown --fix\",\n    \"prepublishOnly\": \"cp docs/README.md README.md\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/PrismarineJS/mineflayer.git\"\n  },\n  \"engines\": {\n    \"node\": \">=22\"\n  },\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"minecraft-data\": \"^3.98.0\",\n    \"minecraft-protocol\": \"^1.64.0\",\n    \"prismarine-biome\": \"^1.1.1\",\n    \"prismarine-block\": \"^1.22.0\",\n    \"prismarine-chat\": \"^1.7.1\",\n    \"prismarine-chunk\": \"^1.39.0\",\n    \"prismarine-entity\": \"^2.5.0\",\n    \"prismarine-item\": \"^1.17.0\",\n    \"prismarine-nbt\": \"^2.0.0\",\n    \"prismarine-physics\": \"^1.9.0\",\n    \"prismarine-recipe\": \"^1.3.0\",\n    \"prismarine-registry\": \"^1.10.0\",\n    \"prismarine-windows\": \"^2.9.0\",\n    \"prismarine-world\": \"^3.6.0\",\n    \"protodef\": \"^1.18.0\",\n    \"typed-emitter\": \"^1.0.0\",\n    \"uuid-1345\": \"^1.0.2\",\n    \"vec3\": \"^0.1.7\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^25.2.1\",\n    \"doctoc\": \"^2.0.1\",\n    \"minecraft-wrap\": \"^1.3.0\",\n    \"mineflayer\": \"file:\",\n    \"mocha\": \"^11.0.1\",\n    \"protodef-yaml\": \"^1.5.3\",\n    \"standard\": \"^17.0.0\",\n    \"standard-markdown\": \"^7.1.0\",\n    \"typescript\": \"^5.4.5\"\n  }\n}\n"
  },
  {
    "path": "test/common/util.js",
    "content": "const net = require('net')\n\nconst getPort = () => new Promise(resolve => {\n  const server = net.createServer()\n  server.listen(0, '127.0.0.1')\n  server.on('listening', () => {\n    const { port } = server.address()\n    server.close(() => resolve(port))\n  })\n})\n\nmodule.exports = { getPort }\n"
  },
  {
    "path": "test/externalTest.js",
    "content": "/* eslint-env mocha */\n\nconst assert = require('assert')\nconst mineflayer = require('../')\nconst commonTest = require('./externalTests/plugins/testCommon')\nconst mc = require('minecraft-protocol')\nconst fs = require('fs')\nconst path = require('path')\n\nconst { getPort } = require('./common/util')\n\n// set this to false if you want to test without starting a server automatically\nconst START_THE_SERVER = true\n// if you want to have time to look what's happening increase this (milliseconds)\nconst TEST_TIMEOUT_MS = 90000\n\nconst excludedTests = ['digEverything', 'book', 'anvil', 'placeEntity']\n\nconst propOverrides = {\n  'level-type': 'FLAT',\n  'spawn-npcs': 'true',\n  'spawn-animals': 'false',\n  'online-mode': 'false',\n  gamemode: '1',\n  'spawn-monsters': 'false',\n  'generate-structures': 'false',\n  'enable-command-block': 'true',\n  'use-native-transport': 'false' // java 16 throws errors without this, https://www.spigotmc.org/threads/unable-to-access-address-of-buffer.311602\n}\n\nconst Wrap = require('minecraft-wrap').Wrap\nconst download = require('minecraft-wrap').download\n\nconst MC_SERVER_PATH = path.join(__dirname, 'server')\n\nfor (const supportedVersion of mineflayer.testedVersions) {\n  let PORT = 25565\n  const registry = require('prismarine-registry')(supportedVersion)\n  const version = registry.version\n  const MC_SERVER_JAR_DIR = process.env.MC_SERVER_JAR_DIR || `${process.cwd()}/server_jars`\n  const MC_SERVER_JAR = `${MC_SERVER_JAR_DIR}/minecraft_server.${version.minecraftVersion}.jar`\n  const wrap = new Wrap(MC_SERVER_JAR, `${MC_SERVER_PATH}_${supportedVersion}`)\n  wrap.on('line', (line) => {\n    console.log(line)\n  })\n\n  describe(`mineflayer_external ${supportedVersion}v`, function () {\n    let bot\n    this.timeout(10 * 60 * 1000)\n    before(async function () {\n      PORT = await getPort()\n      console.log(`Port chosen: ${PORT}`)\n    })\n    before(function (done) {\n      this.timeout(1000 * 120)\n      function begin () {\n        bot = mineflayer.createBot({\n          username: 'flatbot',\n          viewDistance: 'tiny',\n          port: PORT,\n          host: '127.0.0.1',\n          version: supportedVersion\n        })\n        commonTest(bot)\n        bot.test.port = PORT\n\n        console.log('starting bot')\n        bot.once('spawn', () => {\n          console.log('bot spawned, opping...')\n          wrap.writeServer('op flatbot\\n')\n          if (bot.supportFeature('gameRuleUsesResourceLocation')) {\n            wrap.writeServer('gamerule minecraft:spawn_monsters false\\n')\n          } else {\n            wrap.writeServer('gamerule spawnMonsters false\\n')\n          }\n          bot.once('messagestr', msg => {\n            if (msg.includes('Made flatbot a server operator') || msg === '[Server: Opped flatbot]') {\n              done()\n            }\n          })\n        })\n      }\n\n      if (START_THE_SERVER) {\n        console.log('downloading and starting server')\n        download(version.minecraftVersion, MC_SERVER_JAR, (err) => {\n          if (err) {\n            console.log(err)\n            done(err)\n            return\n          }\n          propOverrides['server-port'] = PORT\n          wrap.startServer(propOverrides, (err) => {\n            if (err) return done(err)\n            console.log(`pinging ${version.minecraftVersion} port : ${PORT}`)\n            mc.ping({\n              port: PORT,\n              host: '127.0.0.1',\n              version: supportedVersion\n            }, (err, results) => {\n              if (err) return done(err)\n              console.log('pong')\n              assert.ok(results.latency >= 0)\n              assert.ok(results.latency <= 1000)\n              begin()\n            })\n          })\n        })\n      } else begin()\n    })\n\n    beforeEach(async () => {\n      console.log('Resetting state')\n      await bot.test.resetState()\n      console.log('State reset')\n    })\n\n    after((done) => {\n      if (bot) bot.quit()\n      wrap.stopServer((err) => {\n        if (err) {\n          console.log(err)\n        }\n        wrap.deleteServerData((err) => {\n          if (err) {\n            console.log(err)\n          }\n          done(err)\n        })\n      })\n    })\n\n    const externalTestsFolder = path.resolve(__dirname, './externalTests')\n    fs.readdirSync(externalTestsFolder)\n      .filter(file => fs.statSync(path.join(externalTestsFolder, file)).isFile())\n      .forEach((test) => {\n        test = path.basename(test, '.js')\n        const testFunctions = require(`./externalTests/${test}`)(supportedVersion)\n        const runTest = (testName, testFunction) => {\n          return function (done) {\n            this.timeout(TEST_TIMEOUT_MS)\n            bot.test.sayEverywhere(`### Starting ${testName}`)\n            testFunction(bot, done).then(res => done()).catch(e => done(e))\n          }\n        }\n        if (excludedTests.indexOf(test) === -1) {\n          if (typeof testFunctions === 'object') {\n            for (const testFunctionName in testFunctions) {\n              if (testFunctions[testFunctionName] !== undefined) {\n                it(`${test} ${testFunctionName}`, (testFunctionName => runTest(`${test} ${testFunctionName}`, testFunctions[testFunctionName]))(testFunctionName))\n              }\n            }\n          } else {\n            it(test, runTest(test, testFunctions))\n          }\n        }\n      })\n  })\n}\n"
  },
  {
    "path": "test/externalTests/anvil.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => {\n  async function runTest (bot, testFunction) {\n    const Item = require('prismarine-item')(bot.registry)\n    const renameCost = () => bot.registry.isNewerOrEqualTo('1.8.9') ? 0 : 1 // weird quirk of anvils\n    const renameName = (name) => bot.registry.isOlderThan('1.13.2') ? name : JSON.stringify({ text: name }) // weird quirk of anvils\n    await bot.test.becomeCreative()\n    await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.anvil.id, 1))\n    await bot.test.becomeSurvival()\n    await bot.test.placeBlock(36, bot.entity.position.offset(1, 0, 0))\n\n    if (bot.registry.isNewerOrEqualTo('1.13')) bot.chat(`/xp set ${bot.username} 999 levels`)\n    else {\n      bot.chat(`/xp -2147483648L ${bot.username}`)\n      await once(bot, 'experience')\n      bot.chat(`/xp 999L ${bot.username}`)\n    }\n\n    await once(bot, 'experience')\n\n    const b = bot.findBlock({ matching: bot.registry.blocksByName.anvil.id }) // find anvil before tests so all tests can use it\n\n    function makeBook (enchants) {\n      return makeItem({ type: bot.registry.itemsByName.enchanted_book.id, count: 1, enchants })\n    }\n\n    function makeItem (opts) {\n      const { type, count = 1, enchants, repairCost } = opts\n      const item = new Item(type, count)\n      if (enchants) item.enchants = enchants\n      if (repairCost) item.repairCost = repairCost\n      return item\n    }\n    await testFunction(b, renameCost, renameName, Item, bot, makeBook, makeItem)\n  }\n\n  const tests = []\n\n  function addTest (name, f) {\n    tests[name] = bot => runTest(bot, f)\n  }\n\n  addTest('combine two items', async (b, renameCost, renameName, Item, bot, makeBook, makeItem) => { // combine two items\n    await bot.test.becomeCreative()\n    // get items\n    await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.diamond_sword.id, 1))\n    await bot.test.setInventorySlot(37, makeBook([{ name: 'sharpness', lvl: 5 }]))\n    await bot.test.becomeSurvival()\n\n    const anvil = await bot.openAnvil(b)\n\n    const sword = anvil.findInventoryItem(bot.registry.itemsByName.diamond_sword.id)\n    const book = anvil.findInventoryItem(bot.registry.itemsByName.enchanted_book.id)\n\n    await anvil.combine(sword, book)\n    // test result\n    assert.strictEqual(bot.experience.level, 994)\n    assert.strictEqual(anvil.slots[3].repairCost, 1)\n    assert.deepStrictEqual(anvil.slots[3].enchants, [{ name: 'sharpness', lvl: 5 }])\n    anvil.close()\n    await bot.test.wait(1000)\n  })\n\n  addTest('combine with nbt selection two items', async (b, renameCost, renameName, Item, bot, makeBook, makeItem) => { // combining two items in inventory, but there are three items, so this is more a test of using nbt when picking the item in inventory\n    bot.chat(`/clear ${bot.username}`)\n    await bot.test.becomeCreative()\n\n    await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.diamond_sword.id, 1))\n    await bot.test.setInventorySlot(37, makeItem({ type: bot.registry.itemsByName.diamond_sword.id, enchants: [{ name: 'sharpness', lvl: 5 }] }))\n    await bot.test.setInventorySlot(38, makeBook([{ name: 'unbreaking', lvl: 3 }]))\n\n    await bot.test.becomeSurvival()\n\n    const anvil = await bot.openAnvil(b)\n\n    const sword = bot.inventory.slots[37]\n    const book = anvil.findInventoryItem(bot.registry.itemsByName.enchanted_book.id)\n\n    await anvil.combine(sword, book)\n    // test result\n    assert.strictEqual(bot.experience.level, 996)\n    assert.strictEqual(anvil.slots[3].repairCost, 1)\n    assert.deepStrictEqual(anvil.slots[3].enchants, [{ name: 'sharpness', lvl: 5 }, { name: 'unbreaking', lvl: 3 }])\n    anvil.close()\n    await bot.test.wait(1000)\n  })\n\n  addTest('using anvil.rename', async (b, renameCost, renameName, Item, bot, makeBook, makeItem) => { // using anvil.rename\n    bot.chat(`/clear ${bot.username}`)\n    await bot.test.becomeCreative()\n\n    await bot.test.setInventorySlot(36, makeItem({ type: bot.registry.itemsByName.diamond_sword.id }))\n\n    await bot.test.becomeSurvival()\n\n    const anvil = await bot.openAnvil(b)\n\n    const sword = anvil.findInventoryItem(bot.registry.itemsByName.diamond_sword.id)\n    await anvil.rename(sword, 'hello')\n    // test result\n    assert.strictEqual(bot.experience.level, 998)\n    assert.strictEqual(anvil.slots[3].repairCost, renameCost())\n    assert.deepStrictEqual(anvil.slots[3].customName, renameName('hello'))\n    anvil.close()\n    await bot.test.wait(1000)\n  })\n\n  addTest('two item + rename', async (b, renameCost, renameName, Item, bot, makeBook, makeItem) => { // test 2 + a rename\n    bot.chat(`/clear ${bot.username}`)\n    await bot.test.becomeCreative()\n\n    await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.diamond_sword.id, 1))\n    await bot.test.setInventorySlot(37, makeItem({ type: bot.registry.itemsByName.diamond_sword.id, enchants: [{ name: 'sharpness', lvl: 5 }] }))\n    await bot.test.setInventorySlot(38, makeBook([{ name: 'unbreaking', lvl: 3 }]))\n\n    await bot.test.becomeSurvival()\n\n    const anvil = await bot.openAnvil(b)\n\n    const sword = bot.inventory.slots[37]\n    const book = anvil.findInventoryItem(bot.registry.itemsByName.enchanted_book.id)\n\n    await anvil.combine(sword, book, 'lol')\n    // test result\n    assert.strictEqual(bot.experience.level, 995)\n    assert.strictEqual(anvil.slots[3].repairCost, 1)\n    assert.deepStrictEqual(anvil.slots[3].enchants, [{ name: 'sharpness', lvl: 5 }, { name: 'unbreaking', lvl: 3 }])\n    assert.strictEqual(anvil.slots[3].customName, renameName('lol'))\n    anvil.close()\n    await bot.test.wait(1000)\n  })\n\n  return tests\n}\n"
  },
  {
    "path": "test/externalTests/bed.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Wait a few seconds for chunks\n  await bot.test.wait(3000)\n  const midnight = 18000\n  const bedItem = bot.registry.itemsArray.find(item => item.name.endsWith('bed'))\n  const bedPos1 = bot.entity.position.offset(2, 0, 0).floored()\n  const bedPos2 = bedPos1.offset(0, 0, 1)\n\n  assert(bedItem)\n\n  // Put the bed\n  if (bot.supportFeature('setBlockUsesMetadataNumber', bot.version)) {\n    bot.chat(`/setblock ${bedPos1.toArray().join(' ')} ${bedItem.name} 0`) // Footer\n    bot.chat(`/setblock ${bedPos2.toArray().join(' ')} ${bedItem.name} 8`) // Head\n  } else {\n    bot.chat(`/setblock ${bedPos1.toArray().join(' ')} ${bedItem.name}[part=foot,facing=south]`)\n    bot.chat(`/setblock ${bedPos2.toArray().join(' ')} ${bedItem.name}[part=head,facing=south]`)\n  }\n  bot.chat(`/time set ${midnight}`)\n  await once(bot, 'time')\n  await bot.test.wait(1000)\n\n  console.log(bot.time.timeOfDay, bot.blockAt(bedPos1).name, bot.blockAt(bedPos2).name)\n  const blockAtBed1 = bot.blockAt(bedPos1)\n  const blockAtBed2 = bot.blockAt(bedPos2)\n  assert(bot.time.timeOfDay >= midnight)\n  assert(blockAtBed1?.name?.endsWith('bed'), `Expected ${bedPos1} to be bed, got ${JSON.stringify(blockAtBed1)}`)\n  assert(blockAtBed2?.name?.endsWith('bed'), `Expected ${bedPos2} to be bed, got ${JSON.stringify(blockAtBed2)}`)\n\n  // Sleep\n  assert(!bot.isSleeping)\n  const wakePromise = once(bot, 'wake')\n  await bot.sleep(bot.blockAt(bedPos1))\n\n  // Wake\n  assert(bot.isSleeping)\n  await bot.wake()\n  await wakePromise\n  assert(!bot.isSleeping)\n}\n"
  },
  {
    "path": "test/externalTests/book.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  const pages = [\n    'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n    'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',\n    'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.',\n    'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'\n  ].map(page => page\n    .split(' ')\n    .map((word, i) => `§${(i % 13 + 1).toString(16)}${i % 2 ? '§l' : ''}${word}`)\n    .join(' '))\n\n  await bot.test.setInventorySlot(30, new Item(bot.registry.itemsByName.writable_book.id, 1, 0))\n\n  await bot.writeBook(30, pages)\n  let book = bot.inventory.slots[30]\n  book.nbt.value.pages.value.value.forEach((page, i) => assert.strictEqual(page, pages[i]))\n\n  await bot.signBook(30, pages, bot.username, 'My Very First Book')\n  book = bot.inventory.slots[30]\n  assert.strictEqual(book.type, bot.registry.itemsByName.written_book.id)\n  assert.strictEqual(book.nbt.value.author.value, bot.username)\n  assert.strictEqual(book.nbt.value.title.value, 'My Very First Book')\n}\n"
  },
  {
    "path": "test/externalTests/bossBar.js",
    "content": "const assert = require('assert')\nconst { once, onceWithCleanup } = require('../../lib/promise_utils')\n\nmodule.exports = (version) => async (bot) => {\n  // Skip test for versions older than 1.13 (bossbar command not available)\n  if (bot.registry.isOlderThan('1.13')) return\n\n  console.log('[bossBar test] Starting boss bar tests')\n\n  // Test boss bar creation\n  const createBossBar = async () => {\n    const uuid = 'test:bar1'\n    const title = 'Test Boss Bar'\n    const colorName = 'red'\n    const styleName = 'notched_6'\n    const health = 0.5\n\n    bot.test.sayEverywhere(`/bossbar add ${uuid} \"${title}\"`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} players ${bot.username}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} color ${colorName}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} style ${styleName}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} value ${health * 100}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} visible true`)\n\n    // Wait for the boss bar to be created\n    const [bossBar] = await once(bot, 'bossBarCreated')\n    console.log('DEBUG bossBar:', bossBar)\n    console.log('DEBUG bossBar own properties:', Object.getOwnPropertyNames(bossBar))\n    console.log('DEBUG bossBar prototype:', Object.getPrototypeOf(bossBar))\n    console.log('DEBUG bossBar.title:', bossBar.title, 'type:', typeof bossBar.title)\n    assert.strictEqual(bossBar.title.toString(), title)\n    // Do not check dividers or color here; they will be updated in the next step\n  }\n\n  // Test boss bar update\n  const updateBossBar = async () => {\n    const uuid = 'test:bar1'\n    const newHealth = 0.75\n    const newColor = 'blue'\n    const newStyle = 'notched_10'\n\n    bot.test.sayEverywhere(`/bossbar set ${uuid} color ${newColor}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} style ${newStyle}`)\n    bot.test.sayEverywhere(`/bossbar set ${uuid} value ${newHealth * 100}`)\n\n    // Wait for the boss bar to have the expected state\n    const [bossBar] = await onceWithCleanup(bot, 'bossBarUpdated', {\n      timeout: 5000,\n      checkCondition: (bossBar) =>\n        bossBar.health === newHealth &&\n        bossBar.color === newColor &&\n        bossBar.dividers === 10\n    })\n    assert.strictEqual(bossBar.health, newHealth)\n    assert.strictEqual(bossBar.color, newColor)\n    assert.strictEqual(bossBar.dividers, 10)\n  }\n\n  // Test boss bar deletion\n  const deleteBossBar = async () => {\n    const uuid = 'test:bar1'\n    bot.test.sayEverywhere(`/bossbar remove ${uuid}`)\n    await once(bot, 'bossBarDeleted')\n    assert.strictEqual(bot.bossBars.length, 0)\n  }\n\n  try {\n    await createBossBar()\n    await updateBossBar()\n    await deleteBossBar()\n    console.log('[bossBar test] All tests passed!')\n  } catch (err) {\n    console.error('[bossBar test] Test failed:', err)\n    throw err\n  }\n}\n"
  },
  {
    "path": "test/externalTests/breath.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  await bot.waitForChunksToLoad()\n  // TODO: ** Fix in 1.17\n  if (bot.oxygenLevel) assert.strictEqual(bot.oxygenLevel, 20, 'Wrong oxygen level')\n}\n"
  },
  {
    "path": "test/externalTests/chat.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => {\n  async function runTest (bot, testFunction) {\n    await testFunction(bot)\n  }\n\n  const tests = []\n\n  function addTest (name, f) {\n    tests[name] = bot => runTest(bot, f)\n  }\n\n  addTest('start tests', async (bot) => {\n    await once(bot, 'message') // => <flatbot> starting chat test message event\n  })\n\n  addTest('test message event', async (bot) => {\n    await bot.test.wait(500)\n    bot.chat('/tellraw @p {\"translate\":\"language.name\"}')\n    const [json] = await once(bot, 'message')\n    const str = json.toString()\n    assert.strictEqual(str, 'English')\n  })\n\n  addTest('test chatAddPattern', async (bot) => {\n    await once(bot, 'message') // => starting chat test chatAddPattern\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"Hello World!\"]}')\n    const [username, message, translate, chatMessage] = await once(bot, 'chat')\n    assert.strictEqual(username, 'U9G')\n    assert.strictEqual(message, 'Hello World!')\n    assert.strictEqual(translate, 'chat.type.text')\n    assert.strictEqual(chatMessage.constructor.name, 'ChatMessage')\n  })\n\n  addTest('test addChatPattern', async (bot) => {\n    await once(bot, 'message') // => starting chat test chatAddPattern\n    bot.addChatPattern('theTest', /<.+> Hello World!!!!/, { repeat: false })\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"Hello World!!!!\"]}')\n    const [[match]] = await once(bot, 'chat:theTest')\n    assert.strictEqual(match, '<U9G> Hello World!!!!')\n  })\n\n  addTest('test parse', async (bot) => {\n    await once(bot, 'message') // => starting chat test chatAddPattern\n    bot.addChatPattern('theTest', /<.+> Hello World(!!!!)/, { repeat: false, parse: true })\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"Hello World!!!!\"]}')\n    const [[matches]] = await once(bot, 'chat:theTest')\n    assert.strictEqual(matches[0], '!!!!')\n  })\n\n  addTest('test addChatPatterns', async (bot) => {\n    await once(bot, 'message') // => starting chat test chatAddPattern\n    bot.addChatPatternSet('theTest', [/<.+> Hello/, /<.+> World/], { repeat: false })\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"Hello\"]}')\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"World\"]}')\n    const [[partOne, partTwo]] = await once(bot, 'chat:theTest')\n    assert.strictEqual(partOne, '<U9G> Hello')\n    assert.strictEqual(partTwo, '<U9G> World')\n  })\n\n  addTest('test removeChatPattern', async (bot) => {\n    await once(bot, 'message') // => starting chat test removeChatPattern\n    bot.addChatPattern('test', /<.+> Hello/)\n    bot.removeChatPattern('test')\n    let triggered = false\n    const listener = () => { triggered = true }\n    bot.once('chat:test', listener)\n    bot.chat('/tellraw @p {\"translate\":\"chat.type.text\", \"with\":[\"U9G\", \"Hello\"]}')\n    await once(bot, 'message')\n    assert.ok(triggered === false)\n    bot.off('chat:test', listener)\n  })\n\n  addTest('test awaitMessage', async (bot) => {\n    const p1 = bot.awaitMessage('<flatbot> hello')\n    bot.chat('hello')\n    await p1\n    const p2 = bot.awaitMessage(['<flatbot> hello', '<flatbot> world'])\n    bot.chat('world')\n    await p2\n    const p3 = bot.awaitMessage(/<.+> hello/)\n    bot.chat('hello')\n    await p3\n    const p4 = bot.awaitMessage([/<.+> hello/, /<.+> world/])\n    bot.chat('world')\n    await p4\n  })\n\n  addTest('test removechatpattern with a number input', async (bot) => {\n    const patternIndex = bot.addChatPattern('hello', /hello/)\n    bot.chat('hello')\n    await once(bot, 'chat:hello')\n    bot.removeChatPattern(patternIndex)\n    let listener\n    await new Promise((resolve, reject) => {\n      listener = (msg) => {\n        console.log('reacting to msg: ')\n        console.log(msg)\n        reject(new Error(\"Hello event shouldn't work after removing it\"))\n      }\n      bot.on('chat:hello', listener)\n      bot.once('message', () => {\n        // wait half a second to make sure we aren't going to react to the msg\n        setTimeout(() => resolve(), 500)\n      })\n      bot.chat('hello')\n    })\n    bot.off('chat:hello', listener)\n  })\n\n  return tests\n}\n"
  },
  {
    "path": "test/externalTests/commandBlock.js",
    "content": "const assert = require('assert')\nconst { Vec3 } = require('vec3')\nconst { once, onceWithCleanup } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  const command = `/say ${Math.floor(Math.random() * 1000)}`\n  const commandBlockPos = new Vec3(1, 5, 1)\n  const commandBlockPosText = commandBlockPos.toArray().join(' ')\n\n  // Put and activate the command block\n  const p = once(bot.world, `blockUpdate:(${commandBlockPos.x}, ${commandBlockPos.y}, ${commandBlockPos.z})`)\n  bot.test.sayEverywhere(`/setblock ${commandBlockPosText} minecraft:command_block`)\n  await p\n  bot.setCommandBlock(commandBlockPos, command, false)\n\n  const [message] = await onceWithCleanup(bot, 'message', {\n    timeout: 5000,\n    checkCondition: (message) => message.json.with[0] === command\n  })\n  assert(message.json.translate === 'advMode.setCommand.success')\n}\n"
  },
  {
    "path": "test/externalTests/complete.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const matches = await bot.tabComplete('/weather ')\n  if (bot.supportFeature('tabCompleteHasAToolTip')) {\n    assert.deepStrictEqual(matches, [\n      { match: 'clear', tooltip: undefined },\n      { match: 'rain', tooltip: undefined },\n      { match: 'thunder', tooltip: undefined }\n    ])\n  } else if (bot.supportFeature('tabCompleteHasNoToolTip')) {\n    assert.deepStrictEqual(matches, [\n      'clear',\n      'rain',\n      'thunder'\n    ])\n  }\n\n  if (bot.supportFeature('tabCompleteHasNoToolTip')) {\n    const matches = await bot.tabComplete('/weather')\n    assert.deepStrictEqual(matches, ['/weather'])\n  }\n}\n"
  },
  {
    "path": "test/externalTests/consume.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.bread.id, 5, 0))\n  await bot.test.becomeSurvival()\n  // Cannot consume if bot.food === 20\n  await assert.rejects(bot.consume, (err) => {\n    if (!err) {\n      // log the conditions that made this not throw\n      console.log({ a: bot.game.gameMode !== 'creative', b: !['potion', 'milk_bucket', 'enchanted_golden_apple', 'golden_apple'].includes(bot.heldItem.name), c: bot.food === 20 })\n    }\n    assert.notStrictEqual(err, undefined)\n    return true\n  })\n\n  await bot.test.becomeSurvival()\n\n  while (bot.food > 0) {\n    if (bot.supportFeature('effectAreNotPrefixed')) bot.test.sayEverywhere('/effect give @s hunger 1 255')\n    else if (bot.supportFeature('effectAreMinecraftPrefixed')) bot.test.sayEverywhere(`/effect ${bot.username} minecraft:hunger 1 255`)\n    await bot.test.wait(500)\n  }\n\n  assert.ok(!bot.usingHeldItem)\n  while (bot.food < 20) {\n    const consume = bot.consume()\n    assert.ok(bot.usingHeldItem)\n    await consume\n    assert.ok(!bot.usingHeldItem)\n    await bot.test.wait(100)\n  }\n}\n"
  },
  {
    "path": "test/externalTests/crafting.js",
    "content": "const { once } = require('../../lib/promise_utils')\nconst { Vec3 } = require('vec3')\n\nmodule.exports = () => async (bot) => {\n  const { blocksByName, itemsByName } = bot.registry\n  const Item = require('prismarine-item')(bot.registry)\n\n  let populateBlockInventory\n  let craftItem\n  if (bot.supportFeature('oneBlockForSeveralVariations')) {\n    populateBlockInventory = blocksByName.log\n    craftItem = 'planks'\n  } else if (bot.supportFeature('blockSchemeIsFlat')) {\n    populateBlockInventory = itemsByName.birch_log\n    craftItem = 'birch_planks'\n  }\n\n  function findCraftingTable () {\n    const cursor = new Vec3(0, 0, 0)\n    for (cursor.x = bot.entity.position.x - 4; cursor.x < bot.entity.position.x + 4; cursor.x++) {\n      for (cursor.y = bot.entity.position.y - 4; cursor.y < bot.entity.position.y + 4; cursor.y++) {\n        for (cursor.z = bot.entity.position.z - 4; cursor.z < bot.entity.position.z + 4; cursor.z++) {\n          const block = bot.blockAt(cursor)\n          if (block.type === blocksByName.crafting_table.id) return block\n        }\n      }\n    }\n  }\n\n  async function craft (amount, name) {\n    const item = itemsByName[name]\n    const craftingTable = findCraftingTable()\n    const wbText = craftingTable ? 'with a crafting table, ' : 'without a crafting table, '\n    if (item == null) {\n      bot.test.sayEverywhere(`${wbText}unknown item: ${name}`)\n      throw new Error(`${wbText}unknown item: ${name}`)\n    } else {\n      const recipes = bot.recipesFor(item.id, null, 1, craftingTable) // doesn't check if it's possible to do it amount times\n      if (recipes.length) {\n        bot.test.sayEverywhere(`${wbText}I can make ${item.name}`)\n        await bot.craft(recipes[0], amount, craftingTable)\n        bot.test.sayEverywhere(`did the recipe for ${item.name} ${amount} times`)\n      } else {\n        bot.test.sayEverywhere(`${wbText}I can't make ${item.name}`)\n        throw new Error(`${wbText}I can't make ${item.name}`)\n      }\n    }\n  }\n\n  await bot.test.setInventorySlot(36, new Item(populateBlockInventory.id, 1, 0))\n  await bot.test.becomeSurvival()\n  await craft(1, craftItem)\n  await bot.test.setBlock({ x: 1, y: 0, z: 0, relative: true, blockName: 'crafting_table' })\n  bot.chat('/give @p stick 7')\n  await once(bot.inventory, 'updateSlot')\n  await bot.test.wait(500)\n  const craftingTable = bot.findBlock({ matching: blocksByName.crafting_table.id })\n  await bot.craft(bot.recipesFor(itemsByName.ladder.id, null, null, true)[0], 1, craftingTable)\n}\n"
  },
  {
    "path": "test/externalTests/creative.js",
    "content": "const assert = require('assert')\nconst wait = require('util').promisify(setTimeout)\nconst SLOT = 36\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  const item1 = new Item(1, 1, 0)\n  const item2 = new Item(2, 1, 0)\n\n  const promise = bot.creative.setInventorySlot(SLOT, item2)\n\n  try {\n    bot.creative.setInventorySlot(SLOT, item1)\n  } catch (err) {\n    assert.ok(err instanceof Error, 'The error has not been passed')\n    assert.ok(bot.inventory.slots[SLOT] == null)\n  }\n\n  // setting a slot once works\n  await promise\n  assert.ok(bot.inventory.slots[SLOT] != null)\n  assert.ok(bot.inventory.slots[SLOT].type === item2.type)\n  // set the same item in the same slot again to ensure we don't hang\n  const returnValue = await Promise.race([\n    bot.creative.setInventorySlot(SLOT, item2),\n    (async () => {\n      await wait(5000) // after 5 seconds just fail the test\n      return 'Setting the same item in the same slot took too long'\n    })()\n  ])\n  if (typeof returnValue === 'string') {\n    throw new Error(returnValue)\n  }\n  // setting that same slot again works\n  await bot.creative.setInventorySlot(SLOT, new Item(3, 1, 0))\n  assert.strictEqual(bot.inventory.slots[SLOT].type, 3)\n  // and again works\n  await bot.creative.setInventorySlot(SLOT, new Item(4, 1, 0))\n  assert.strictEqual(bot.inventory.slots[SLOT].type, 4)\n  // setting a slot to null\n  await bot.creative.setInventorySlot(SLOT, null)\n  assert.strictEqual(bot.inventory.slots[SLOT], null)\n  // clear slot\n  await bot.creative.setInventorySlot(SLOT, new Item(4, 1, 0))\n  assert.strictEqual(bot.inventory.slots[SLOT].type, 4)\n  await bot.creative.clearSlot(SLOT)\n  assert.strictEqual(bot.inventory.slots[SLOT], null)\n  // clear inventory\n  for (let i = 0; i < 9; i++) {\n    await bot.creative.setInventorySlot(36 + i, new Item(1, 1, 0))\n  }\n  assert.strictEqual(bot.inventory.slots.filter(item => item).length, 9)\n  await bot.creative.clearInventory()\n  assert.strictEqual(bot.inventory.slots.filter(item => item).length, 0)\n}\n"
  },
  {
    "path": "test/externalTests/digAndBuild.js",
    "content": "const { Vec3 } = require('vec3')\nconst assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.dirt.id, 1, 0))\n  await bot.test.fly(new Vec3(0, 2, 0))\n  await bot.test.placeBlock(36, bot.entity.position.plus(new Vec3(0, -2, 0)))\n  await bot.test.clearInventory()\n  await bot.creative.stopFlying()\n  await waitForFall()\n  await bot.test.becomeSurvival()\n  // we are bare handed\n  await bot.dig(bot.blockAt(bot.entity.position.plus(new Vec3(0, -1, 0))))\n  // make sure we collected das dirt\n  await bot.test.wait(1000)\n  assert(Item.equal(bot.inventory.slots[36], new Item(bot.registry.itemsByName.dirt.id, 1, 0)))\n  bot.test.sayEverywhere('dirt collect test: pass')\n\n  async function waitForFall () {\n    return new Promise((resolve, reject) => {\n      assert(!bot.entity.onGround, 'waitForFall called when we were already on the ground')\n      const startingPosition = bot.entity.position.clone()\n      bot.on('move', function onMove () {\n        if (bot.entity.onGround) {\n          const distance = startingPosition.distanceTo(bot.entity.position)\n          assert(distance > 0.2, `waitForFall didn't fall very far: ${distance}`)\n          bot.removeListener('move', onMove)\n          resolve()\n        }\n      })\n    })\n  }\n}\n"
  },
  {
    "path": "test/externalTests/digEverything.js",
    "content": "const { Vec3 } = require('vec3')\nconst assert = require('assert')\n\n// this test takes about 20min\n\nconst excludedBlocks = [\n  // broken\n  'bed',\n  'double_stone_slab',\n  'wooden_door',\n  'iron_door',\n  'redstone_ore',\n  'lit_redstone_ore',\n  'trapdoor',\n  'double_wooden_slab',\n  'jungle_stairs',\n  'flower_pot',\n  'carrots',\n  'potatoes',\n  'skull',\n  'unpowered_comparator',\n  'standing_banner',\n  'wall_banner',\n  'daylight_detector',\n  'stone_slab2',\n  'spruce_door',\n  'birch_door',\n  'jungle_door',\n  'acacia_door',\n  'dark_oak_door',\n\n  // cannot be placed\n  'piston_extension',\n  'fire',\n  'standing_sign',\n  'reeds',\n  'powered_repeater',\n  'pumpkin_stem',\n  'melon_stem',\n  'brewing_stand',\n  'cauldron',\n  'lit_redstone_lamp',\n  'tripwire',\n\n  // cause problems\n  'mob_spawner',\n  'obsidian'\n]\n\nmodule.exports = (version) => {\n  const registry = require('prismarine-registry')(version)\n\n  const funcs = {}\n  for (const id in registry.blocks) {\n    if (registry.blocks[id] !== undefined) {\n      const block = registry.blocks[id]\n      if (block.diggable && excludedBlocks.indexOf(block.name) === -1) {\n        funcs[block.name] = (blockId => async (bot) => {\n          await digSomething(blockId, bot)\n        })(block.id)\n      }\n    }\n  }\n\n  return funcs\n}\n\nasync function digSomething (blockId, bot) {\n  const Item = require('prismarine-item')(bot.registry)\n\n  await bot.test.setInventorySlot(36, new Item(blockId, 1, 0))\n  await bot.test.placeBlock(36, bot.entity.position.plus(new Vec3(1, 0, 0)))\n  // TODO: find a better way than this bot.test.wait(200)\n  await bot.test.wait(200)\n  await bot.test.clearInventory()\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.diamond_pickaxe.id, 1, 0))\n  await bot.test.becomeSurvival()\n  // we are bare handed\n  await bot.dig(bot.blockAt(bot.entity.position.plus(new Vec3(1, 0, 0))))\n  // make sure that block is gone\n  assert.strictEqual(bot.blockAt(bot.entity.position.plus(new Vec3(1, 0, 0))).type, 0)\n}\n"
  },
  {
    "path": "test/externalTests/dimensionName.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  assert.strictEqual(bot._getDimensionName(), 'minecraft:overworld')\n}\n"
  },
  {
    "path": "test/externalTests/displayName.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const player = bot.players[bot.username]\n  assert.strictEqual(player.displayName.toString(), bot.username)\n}\n"
  },
  {
    "path": "test/externalTests/elytra.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  // don't continue unless this version supports elytra\n  if (!bot.supportFeature('hasElytraFlying')) return\n  const supportsFireworkRockets = bot.supportFeature('fireworkNamePlural') || bot.supportFeature('fireworkNameSingular')\n\n  const Item = require('prismarine-item')(bot.registry)\n\n  await bot.test.setInventorySlot(6, new Item(bot.registry.itemsByName.elytra.id, 1))\n  if (supportsFireworkRockets) {\n    const fireworkItem = bot.registry.itemsArray.find(item => item.displayName === 'Firework Rocket')\n    assert.ok(fireworkItem !== undefined)\n    await bot.test.setInventorySlot(36, new Item(fireworkItem.id, 64))\n  }\n  await bot.test.teleport(bot.entity.position.offset(0, 100, 0))\n  await bot.test.becomeSurvival()\n  await bot.creative.stopFlying()\n\n  await bot.look(bot.entity.yaw, 0)\n  await bot.waitForTicks(5)\n  await assert.doesNotReject(bot.elytraFly())\n  await bot.waitForTicks(20) // wait for server to accept\n  assert.ok(bot.entity.elytraFlying)\n\n  if (!supportsFireworkRockets) return\n\n  // use rocket\n  await bot.look(bot.entity.yaw, 30 * Math.PI / 180)\n  const activationTicks = 20\n  for (let i = 0; i < 20; i++) {\n    bot.activateItem()\n    assert.ok(bot.entity.elytraFlying)\n    await bot.waitForTicks(1)\n  }\n  await bot.waitForTicks(3)\n  let lateActivations = 0\n  assert.ok(bot.fireworkRocketDuration > 0)\n  for (let i = bot.fireworkRocketDuration; i > 0; --i) {\n    await bot.waitForTicks(1)\n    assert.ok(bot.entity.elytraFlying)\n    if (bot.fireworkRocketDuration > i) {\n      i = bot.fireworkRocketDuration\n      ++lateActivations\n    }\n    assert.ok(lateActivations <= activationTicks)\n  }\n  assert.ok(bot.fireworkRocketDuration === 0)\n}\n"
  },
  {
    "path": "test/externalTests/enchanting.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  const lapisId = bot.registry.itemsByName.lapis_lazuli ? bot.registry.itemsByName.lapis_lazuli.id : bot.registry.itemsByName.dye.id\n  const lapisData = bot.registry.itemsByName.lapis_lazuli ? 0 : 4\n\n  const enchantSlot = 2\n\n  if (bot.registry.isNewerOrEqualTo('1.13')) {\n    bot.chat(`/xp set ${bot.username} 999 levels`)\n  } else {\n    bot.chat(`/xp 999L ${bot.username}`)\n  }\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.bookshelf.id, 15))\n  await bot.test.setInventorySlot(37, new Item(bot.registry.itemsByName.enchanting_table.id, 1))\n  await bot.test.setInventorySlot(38, new Item(bot.registry.itemsByName.diamond_sword.id, 1))\n  await bot.test.setInventorySlot(39, new Item(lapisId, enchantSlot + 1, lapisData))\n\n  await bot.test.becomeSurvival()\n\n  // Place enchanting table\n  await bot.test.placeBlock(37, bot.entity.position.offset(1, 0, 0))\n\n  // Place bookshelfs\n  await bot.test.placeBlock(36, bot.entity.position.offset(3, 0, 2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(3, 0, 1))\n  await bot.test.placeBlock(36, bot.entity.position.offset(3, 0, 0))\n  await bot.test.placeBlock(36, bot.entity.position.offset(3, 0, -1))\n  await bot.test.placeBlock(36, bot.entity.position.offset(3, 0, -2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(2, 0, -2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(1, 0, -2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(0, 0, -2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(-1, 0, -2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(-1, 0, -1))\n  await bot.test.placeBlock(36, bot.entity.position.offset(-1, 0, 1))\n  await bot.test.placeBlock(36, bot.entity.position.offset(-1, 0, 2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(0, 0, 2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(1, 0, 2))\n  await bot.test.placeBlock(36, bot.entity.position.offset(2, 0, 2))\n\n  const b = bot.findBlock({ matching: bot.registry.blocksByName.enchanting_table.id })\n  const enchantingTable = await bot.openEnchantmentTable(b)\n\n  console.log('Opened enchanting table')\n\n  const lapis = enchantingTable.findInventoryItem(lapisId)\n  await enchantingTable.putLapis(lapis)\n\n  const sword = enchantingTable.findInventoryItem(bot.registry.itemsByName.diamond_sword.id)\n\n  await enchantingTable.putTargetItem(sword)\n\n  console.log('Table ready')\n  await enchantingTable.enchant(enchantSlot)\n  await bot.test.wait(500)\n  const result = await enchantingTable.takeTargetItem()\n\n  assert.notStrictEqual(result.nbt, undefined)\n\n  enchantingTable.close()\n}\n"
  },
  {
    "path": "test/externalTests/exampleBee.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  await bot.test.runExample('examples/bee.js', async (name) => {\n    assert.strictEqual(name, 'bee')\n    bot.chat('/op bee') // to counteract spawn protection\n    await bot.test.wait(2000)\n    await bot.test.tellAndListen(name, 'fly', (message) => {\n      if (message !== 'My flight was amazing !') {\n        assert.fail(`Unexpected message: ${message}`) // error\n      }\n      return true // stop listening\n    })\n  })\n}\n"
  },
  {
    "path": "test/externalTests/exampleBlockFinder.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  await bot.test.runExample('examples/blockfinder.js', async (name) => {\n    assert.strictEqual(name, 'finder')\n    await bot.test.wait(2000)\n    await bot.test.tellAndListen(name, 'find dirt', (message) => {\n      const matches = message.match(/I found ([0-9]+) (.+?) blocks in (.+?) ms/)\n      if (matches.length !== 4 || matches[1] === '0' || matches[2] !== 'dirt' || parseFloat(matches[3]) > 500) {\n        assert.fail(`Unexpected message: ${message}`) // error\n      }\n      return true // stop listening\n    })\n  })\n}\n"
  },
  {
    "path": "test/externalTests/exampleDigger.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  await bot.test.runExample('examples/digger.js', async (name) => {\n    assert.strictEqual(name, 'digger')\n    bot.chat('/op digger') // to counteract spawn protection\n    bot.chat('/give digger dirt 64')\n    await bot.test.wait(2000)\n    await bot.test.tellAndListen(name, 'dig', (message) => {\n      if (message.startsWith('starting')) {\n        return false // continue to listen\n      } else if (message.startsWith('finished')) {\n        return true // stop listening\n      }\n      assert.fail(`Unexpected message: ${message}`) // error\n    })\n    await bot.test.tellAndListen(name, 'equip dirt', (message) => {\n      if (!message.startsWith('equipped dirt')) {\n        assert.fail(`Unexpected message: ${message}`) // error\n      }\n      return true // stop listening\n    })\n    await bot.test.tellAndListen(name, 'build', (message) => {\n      if (message !== 'Placing a block was successful') {\n        assert.fail(`Unexpected message: ${message}`) // error\n      }\n      return true // stop listening\n    })\n  })\n}\n"
  },
  {
    "path": "test/externalTests/exampleInventory.js",
    "content": "const assert = require('assert')\n\nconst tests = [\n  {\n    command: 'list',\n    wantedMessage: 'dirt x 64, stick x 7, iron_ore x 64, diamond_boots x 1'\n  },\n  {\n    command: 'equip off-hand dirt',\n    wantedMessage: 'equipped dirt'\n  },\n  {\n    command: 'list',\n    wantedMessage: 'stick x 7, iron_ore x 64, diamond_boots x 1, dirt x 64'\n  },\n  {\n    command: 'equip hand dirt',\n    wantedMessage: 'equipped dirt'\n  },\n  {\n    command: 'toss 64 dirt',\n    wantedMessage: 'tossed 64 x dirt'\n  },\n  {\n    command: 'craft 1 ladder',\n    wantedMessage: 'I can make ladder'\n  },\n  {\n    command: '',\n    wantedMessage: 'did the recipe for ladder 1 times'\n  },\n  {\n    command: 'equip feet diamond_boots',\n    wantedMessage: 'equipped diamond_boots'\n  },\n  {\n    command: 'toss iron_ore',\n    wantedMessage: 'tossed iron_ore'\n  },\n  {\n    command: 'unequip feet',\n    wantedMessage: 'unequipped'\n  },\n  { // after tests layout\n    command: 'list',\n    wantedMessage: 'ladder x 3, diamond_boots x 1'\n  }\n]\nmodule.exports = () => async (bot) => {\n  await bot.test.runExample('examples/inventory.js', async (name) => {\n    assert.strictEqual(name, 'inventory')\n    bot.chat('/op inventory') // to counteract spawn protection\n    bot.chat('/clear inventory')\n    bot.chat(`/setblock 52 ${bot.test.groundY} 0 crafting_table`) // to make stone bricks stairs\n    bot.chat('/give inventory dirt 64')\n    bot.chat('/give inventory stick 7')\n    bot.chat('/give inventory iron_ore 64')\n    bot.chat('/give inventory diamond_boots 1')\n    await bot.test.wait(2000)\n    if (bot.registry.isOlderThan('1.9')) {\n      tests.splice(tests.indexOf(tests.find(t => t.command.includes('off-hand'))), 2) // Delete off-hand command and the command after it as they don't work in 1.9\n    }\n    const testFuncs = tests.map(test => makeTest(test.command, test.wantedMessage))\n    for (const test of testFuncs) {\n      await test()\n      await bot.test.wait(100)\n    }\n    // cleanup\n    bot.chat(`/setblock 52 ${bot.test.groundY} 0 air`)\n\n    function makeTest (inStr, outStr) {\n      return () => bot.test.tellAndListen(name, inStr, makeListener(outStr))\n    }\n  })\n}\n\nfunction makeListener (wantedMessage) {\n  return (message) => {\n    if (!message.startsWith(wantedMessage)) {\n      assert.fail(`Unexpected message: ${message}, wanted ${wantedMessage}`) // error\n    }\n    return true // stop listening\n  }\n}\n"
  },
  {
    "path": "test/externalTests/experience.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  await bot.test.becomeSurvival()\n  await bot.test.wait(1000)\n\n  // Initial state\n  const initialState = {\n    level: bot.experience.level,\n    points: bot.experience.points,\n    progress: bot.experience.progress\n  }\n  assert(initialState.level >= 0, 'Initial experience level should be non-negative')\n  assert(initialState.points >= 0, 'Initial experience points should be non-negative')\n  assert(initialState.progress >= 0 && initialState.progress <= 1, 'Initial experience progress should be between 0 and 1')\n\n  // Test experience points\n  const xpCommand = bot.registry.isOlderThan('1.13')\n    ? `/xp 10 ${bot.username}`\n    : `/xp add ${bot.username} 10 points`\n\n  await bot.chat(xpCommand)\n  await once(bot, 'experience')\n\n  // Verify after points\n  assert(bot.experience.points >= 10, 'Experience points should be at least 10 after adding points')\n  assert(bot.experience.level >= initialState.level, 'Experience level should not decrease after adding points')\n  assert(bot.experience.progress >= 0 && bot.experience.progress <= 1, 'Experience progress should be between 0 and 1 after adding points')\n\n  // Test experience levels\n  const levelCommand = bot.registry.isOlderThan('1.13')\n    ? `/xp 100L ${bot.username}`\n    : `/xp add ${bot.username} 100 levels`\n\n  await bot.chat(levelCommand)\n  await once(bot, 'experience')\n\n  // Verify after levels\n  assert(bot.experience.level >= 100, 'Experience level should be at least 100 after adding levels')\n  assert(bot.experience.points > 0, 'Experience points should be positive after adding levels')\n  assert(bot.experience.progress >= 0 && bot.experience.progress <= 1, 'Experience progress should be between 0 and 1 after adding levels')\n}\n"
  },
  {
    "path": "test/externalTests/fishing.js",
    "content": "module.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  bot.test.sayEverywhere('/fill ~-10 ~-1 ~-10 ~10 ~-1 ~10 water')\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.fishing_rod.id, 1, 0))\n  await bot.lookAt(bot.entity.position) // dont force the position\n  bot.fish()\n\n  return new Promise((resolve, reject) => {\n    function onPlayerCollect (collector, collected) {\n      if (collected.name.toLowerCase() === 'item' || collected.type === 'object') {\n        bot.test.sayEverywhere('I caught: ' + collected.displayName)\n        bot.removeListener('playerCollect', onPlayerCollect)\n        resolve()\n      }\n    }\n    bot.on('playerCollect', onPlayerCollect)\n  })\n}\n"
  },
  {
    "path": "test/externalTests/furnace.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  const furnacePos = bot.entity.position.offset(2, 0, 0).floored()\n  const coalId = bot.registry.itemsByName.coal.id\n  const porkchopId = bot.registry.itemsByName.porkchop.id\n  const cookedPorkchopId = bot.registry.itemsByName.cooked_porkchop.id\n  const coalInputCount = 2\n  const porkchopInputCount = 2\n\n  // Test setup\n  await bot.test.setInventorySlot(36, new Item(bot.registry.itemsByName.furnace.id, 1))\n  await bot.test.placeBlock(36, furnacePos)\n  await bot.test.setInventorySlot(37, new Item(porkchopId, porkchopInputCount))\n  await bot.test.setInventorySlot(38, new Item(coalId, coalInputCount)) // Get coal\n  if (bot.supportFeature('itemsAreAlsoBlocks')) {\n    assert.strictEqual(bot.blockAt(furnacePos).type, bot.registry.itemsByName.furnace.id)\n  } else {\n    assert.strictEqual(bot.blockAt(furnacePos).type, bot.registry.blocksByName.furnace.id)\n  }\n\n  // Put inputs\n  const furnace = await bot.openFurnace(bot.blockAt(furnacePos))\n  assert.strictEqual(furnace.inputItem(), furnace.slots[0])\n  assert.strictEqual(furnace.fuelItem(), furnace.slots[1])\n  assert.strictEqual(furnace.outputItem(), furnace.slots[2])\n  assert.strictEqual(furnace.inputItem(), null)\n  assert.strictEqual(furnace.fuelItem(), null)\n  assert.strictEqual(furnace.outputItem(), null)\n\n  await furnace.putFuel(coalId, null, coalInputCount)\n\n  assert.strictEqual(furnace.fuelItem(), furnace.slots[1])\n  assert.strictEqual(furnace.fuelItem().type, coalId)\n  assert.strictEqual(furnace.fuelItem().count, coalInputCount)\n\n  await furnace.putInput(porkchopId, null, porkchopInputCount)\n\n  assert.strictEqual(furnace.inputItem(), furnace.slots[0])\n  assert.strictEqual(furnace.inputItem().type, porkchopId)\n  assert.strictEqual(furnace.inputItem().count, porkchopInputCount)\n\n  // Wait and take the output and inputs\n  await bot.test.wait(500)\n  assert(furnace.fuel > 0 && furnace.fuel < 1)\n  assert(furnace.progress > 0 && furnace.progress < 1)\n\n  await bot.test.wait(furnace.progressSeconds * 1000 + 500)\n  assert.strictEqual(furnace.outputItem(), furnace.slots[2])\n  assert.strictEqual(furnace.outputItem().type, cookedPorkchopId)\n  assert.strictEqual(furnace.outputItem().count, 1)\n\n  assert.strictEqual(furnace.inputItem().type, porkchopId)\n  assert.strictEqual(furnace.inputItem().count, porkchopInputCount - 1)\n\n  assert.strictEqual(furnace.fuelItem().type, coalId)\n  assert.strictEqual(furnace.fuelItem().count, coalInputCount - 1)\n\n  await furnace.takeOutput()\n  await furnace.takeInput()\n  await furnace.takeFuel()\n  furnace.close()\n\n  await bot.test.wait(500)\n\n  // Check inventory\n  const cookedPorkchopCount = bot.inventory.count(cookedPorkchopId)\n  const porkchopCount = bot.inventory.count(porkchopId)\n  const coalCount = bot.inventory.count(coalId)\n\n  assert.strictEqual(cookedPorkchopCount, 1)\n  assert.strictEqual(porkchopCount, porkchopInputCount - 1)\n  assert.strictEqual(coalCount, coalInputCount - 1)\n}\n"
  },
  {
    "path": "test/externalTests/gamemode.js",
    "content": "// test to see if bot retains creative gamemode in bot object on death\n\nconst assert = require('assert')\nconst { onceWithCleanup } = require('../../lib/promise_utils')\n\nmodule.exports = () => {\n  const tests = []\n\n  function addTest (name, f) {\n    tests[name] = (bot) => f(bot)\n  }\n\n  addTest('change', async (bot) => {\n    await bot.test.becomeSurvival()\n    assert.strictEqual(bot.game.gameMode, 'survival', 'Wrong gamemode after switching gamemode')\n    await bot.test.becomeCreative()\n    assert.strictEqual(bot.game.gameMode, 'creative', 'Wrong gamemode after switching gamemode')\n  })\n\n  addTest('after respawn', async (bot) => {\n    await bot.test.becomeCreative()\n    bot.test.selfKill()\n    await onceWithCleanup(bot, 'respawn', { timeout: 5000 })\n    // Respawn packets send the gamemode. If the bot is in creative mode, it should respawn in creative mode. Tested <1.20\n    assert.strictEqual(bot.game.gameMode, 'creative', 'Wrong gamemode after respawn')\n  })\n\n  return tests\n}\n"
  },
  {
    "path": "test/externalTests/heldItem.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  await bot.test.becomeCreative()\n  await bot.test.clearInventory()\n  await bot.test.wait(100)\n  assert.equal(bot.heldItem, null)\n\n  const stoneId = bot.registry.itemsByName.stone.id\n  await bot.test.setInventorySlot(36, new Item(stoneId, 1))\n  assert.strictEqual(bot.heldItem.id, bot.stoneId)\n\n  await bot.tossStack(bot.heldItem)\n  assert.equal(bot.heldItem, null)\n}\n"
  },
  {
    "path": "test/externalTests/nether.js",
    "content": "const assert = require('assert')\nconst Vec3 = require('vec3')\nconst { once, sleep } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test spawn event on death\n  const Item = require('prismarine-item')(bot.registry)\n\n  let signItem = null\n  for (const name in bot.registry.itemsByName) {\n    if (name.includes('sign') && !name.includes('hanging')) signItem = bot.registry.itemsByName[name]\n  }\n  assert.notStrictEqual(signItem, null)\n\n  const p = new Promise((resolve, reject) => {\n    bot._client.once('open_sign_entity', (packet) => {\n      console.log('Open sign', packet)\n      const sign = bot.blockAt(new Vec3(packet.location))\n      bot.updateSign(sign, '1\\n2\\n3\\n')\n\n      setTimeout(() => {\n        // Get updated sign\n        const sign = bot.blockAt(bot.entity.position)\n        console.log('Updated sign', sign)\n\n        assert.strictEqual(sign.signText.trimEnd(), '1\\n2\\n3')\n\n        if (sign.blockEntity) {\n          // Check block update\n          bot.activateBlock(sign)\n          assert.notStrictEqual(sign.blockEntity, undefined)\n        }\n\n        bot.test.sayEverywhere('/setblock ~ ~ ~ portal')\n        bot.test.sayEverywhere('/setblock ~ ~ ~ nether_portal')\n        once(bot, 'spawn').then(resolve)\n      }, 500)\n    })\n  })\n\n  bot.test.sayEverywhere('/setblock ~ ~ ~ nether_portal')\n  bot.test.sayEverywhere('/setblock ~ ~ ~ portal')\n  await once(bot, 'spawn')\n  bot.test.sayEverywhere('/tp 0 128 0')\n\n  await once(bot, 'forcedMove')\n  await bot.waitForChunksToLoad()\n\n  // Poll until the block below is loaded and non-air before placing.\n  // On slow CI, chunks may report as loaded before block data is ready.\n  let lowerBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0))\n  while (!lowerBlock || lowerBlock.name === 'air') {\n    await sleep(100)\n    lowerBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0))\n  }\n\n  await bot.lookAt(lowerBlock.position, true)\n  await bot.test.setInventorySlot(36, new Item(signItem.id, 1, 0))\n  await bot.placeBlock(lowerBlock, new Vec3(0, 1, 0))\n  await p\n}\n"
  },
  {
    "path": "test/externalTests/particles.js",
    "content": "const assert = require('assert')\n\nmodule.exports = () => async (bot) => {\n  const particleData = bot.registry.particles[0]\n\n  return new Promise((resolve, reject) => {\n    function onParticleEvent (particle) {\n      if (typeof particle.id === 'number') {\n        assert.strictEqual(particle.id, particleData.id)\n      } else {\n        assert.strictEqual(particle.id, particleData.name)\n      }\n      assert.strictEqual(particle.name, particleData.name)\n      assert.strictEqual(particle.position.x, bot.entity.position.x)\n      assert.strictEqual(particle.position.y, bot.entity.position.y)\n      assert.strictEqual(particle.position.z, bot.entity.position.z)\n      assert.strictEqual(particle.offset.x, 5)\n      assert.strictEqual(particle.offset.y, 5)\n      assert.strictEqual(particle.offset.z, 5)\n      assert.strictEqual(particle.count, 100)\n      assert.strictEqual(particle.movementSpeed, 0.5)\n      assert.strictEqual(particle.longDistanceRender, true)\n\n      resolve()\n    }\n\n    bot.on('particle', onParticleEvent)\n\n    bot.chat(`/particle ${particleData.name} ~ ~ ~ 5 5 5 0.5 100 force`)\n  })\n}\n"
  },
  {
    "path": "test/externalTests/placeEntity.js",
    "content": "const assert = require('assert')\nconst { Vec3 } = require('vec3')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = (version) => {\n  async function runTest (bot, testFunction) {\n    await testFunction(bot)\n  }\n\n  const tests = []\n\n  function addTest (name, f) {\n    tests[name] = bot => runTest(bot, f)\n  }\n\n  addTest('place crystal', async (bot) => {\n    if (!bot.registry.itemsByName.end_crystal) return // unsupported\n    await bot.test.setBlock({ z: 1, relative: true, blockName: 'obsidian' })\n    await bot.test.awaitItemReceived(`/give ${bot.username} end_crystal`)\n    const crystal = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, 1)), new Vec3(0, 1, 0))\n    assert(crystal !== null)\n    let name = 'EnderCrystal'\n    if (bot.supportFeature('enderCrystalNameEndsInErNoCaps')) {\n      name = 'ender_crystal'\n    } else if (bot.supportFeature('entityNameLowerCaseNoUnderscore')) {\n      name = 'endercrystal'\n    } else if (bot.supportFeature('enderCrystalNameNoCapsWithUnderscore')) {\n      name = 'end_crystal'\n    }\n    const entity = bot.nearestEntity(o => o.name === name)\n    assert(entity?.name === name)\n    bot.attack(entity)\n    await once(bot, 'entityGone')\n    await bot.test.setBlock({ z: 1, blockName: 'air', relative: true })\n  })\n\n  addTest('place boat', async (bot) => {\n    async function placeBlocksForTest (blockName) {\n      for (let z = -1; z >= -3; z--) {\n        const y = -1\n        for (let x = -1; x <= 1; x++) {\n          await bot.test.setBlock({ x, y, z, blockName, relative: true })\n        }\n      }\n    }\n\n    await placeBlocksForTest('water')\n    await bot.test.awaitItemReceived(`/give ${bot.username} ${bot.registry.oak_boat ? 'oak_boat' : 'boat'}`)\n    const boat = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, -1, -2)), new Vec3(0, -1, 0))\n    assert(boat !== null)\n    const name = bot.supportFeature('entityNameUpperCaseNoUnderscore') ? 'Boat' : 'boat'\n    const entity = bot.nearestEntity(o => o.name === name)\n    assert(entity?.name === name)\n    await placeBlocksForTest('air')\n    bot.attack(entity)\n    await once(bot, 'entityGone')\n  })\n\n  addTest('place summon egg', async (bot) => {\n    let command\n    if (bot.registry.isOlderThan('1.9')) {\n      command = '/give @p spawn_egg 1 54' // 1.8\n    } else if (bot.registry.isOlderThan('1.11')) {\n      command = '/give @p spawn_egg 1 0 {EntityTag:{id:Zombie}}' // 1.9 / 1.10\n    } else if (bot.registry.isOlderThan('1.12')) {\n      command = '/give @p spawn_egg 1 0 {EntityTag:{id:minecraft:zombie}}' // 1.11\n    } else if (bot.registry.isOlderThan('1.13')) {\n      command = '/give @p spawn_egg 1 0 {EntityTag:{id:zombie}}' // 1.12\n    } else {\n      command = '/give @p zombie_spawn_egg 1' // >1.12\n    }\n    await bot.test.awaitItemReceived(command)\n    const zombie = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, 1)), new Vec3(0, 1, 0))\n    assert(zombie !== null)\n    const name = bot.supportFeature('entityNameUpperCaseNoUnderscore') ? 'Zombie' : 'zombie'\n    const entity = bot.nearestEntity(o => o.name === name)\n    assert(entity?.name === name)\n    bot.chat(`/kill @e[type=${name}]`) // use /kill instead of bot.attack() because it takes more than one hit to kill\n    await once(bot, 'entityGone')\n  })\n\n  addTest('place armor stand', async (bot) => {\n    await bot.test.awaitItemReceived(`/give ${bot.username} armor_stand`)\n    const armorStand = await bot.placeEntity(bot.blockAt(bot.entity.position.offset(0, 0, 1)), new Vec3(0, 1, 0))\n    assert(armorStand !== null)\n    let name\n    if (bot.supportFeature('entityNameUpperCaseNoUnderscore')) {\n      name = 'ArmorStand'\n    } else if (bot.supportFeature('entityNameLowerCaseNoUnderscore')) {\n      name = 'armorstand'\n    } else {\n      name = 'armor_stand'\n    }\n    const entity = bot.nearestEntity(o => o.name === name)\n    assert(entity?.name === name)\n    bot.attack(entity)\n    await once(bot, 'entityGone')\n  })\n\n  return tests\n}\n"
  },
  {
    "path": "test/externalTests/plugins/testCommon.js",
    "content": "const { Vec3 } = require('vec3')\n\nconst { spawn } = require('child_process')\nconst { once } = require('../../../lib/promise_utils')\nconst process = require('process')\nconst assert = require('assert')\nconst { sleep, onceWithCleanup } = require('../../../lib/promise_utils')\n\nconst timeout = 20000\nmodule.exports = inject\n\nfunction inject (bot) {\n  console.log(bot.version)\n\n  bot.test = {}\n  bot.test.groundY = bot.supportFeature('tallWorld') ? -60 : 4\n  bot.test.sayEverywhere = sayEverywhere\n  bot.test.clearInventory = clearInventory\n  bot.test.becomeSurvival = becomeSurvival\n  bot.test.becomeCreative = becomeCreative\n  bot.test.fly = fly\n  bot.test.teleport = teleport\n  bot.test.resetState = resetState\n  bot.test.setInventorySlot = setInventorySlot\n  bot.test.placeBlock = placeBlock\n  bot.test.runExample = runExample\n  bot.test.tellAndListen = tellAndListen\n  bot.test.selfKill = selfKill\n  bot.test.wait = function (ms) {\n    return new Promise((resolve) => { setTimeout(resolve, ms) })\n  }\n\n  bot.test.awaitItemReceived = async (command) => {\n    const p = once(bot.inventory, 'updateSlot')\n    bot.chat(command)\n    await p // await getting the item\n  }\n  // setting relative to true makes x, y, & z relative using ~\n  bot.test.setBlock = async ({ x = 0, y = 0, z = 0, relative, blockName }) => {\n    const { x: _x, y: _y, z: _z } = relative ? bot.entity.position.floored().offset(x, y, z) : { x, y, z }\n    const block = bot.blockAt(new Vec3(_x, _y, _z))\n    if (block.name === blockName) {\n      return\n    }\n    const p = once(bot.world, `blockUpdate:(${_x}, ${_y}, ${_z})`)\n    const prefix = relative ? '~' : ''\n    bot.chat(`/setblock ${prefix}${x} ${prefix}${y} ${prefix}${z} ${blockName}`)\n    await p\n  }\n\n  let grassName\n  if (bot.supportFeature('itemsAreNotBlocks')) {\n    grassName = 'grass_block'\n  } else if (bot.supportFeature('itemsAreAlsoBlocks')) {\n    grassName = 'grass'\n  }\n\n  const layerNames = [\n    'bedrock',\n    'dirt',\n    'dirt',\n    grassName,\n    'air',\n    'air',\n    'air',\n    'air',\n    'air'\n  ]\n\n  async function resetBlocksToSuperflat () {\n    const groundY = 4\n    for (let y = groundY + 4; y >= groundY - 1; y--) {\n      const realY = y + bot.test.groundY - 4\n      bot.chat(`/fill ~-5 ${realY} ~-5 ~5 ${realY} ~5 ` + layerNames[y])\n    }\n    await bot.test.wait(100)\n  }\n\n  async function placeBlock (slot, position) {\n    bot.setQuickBarSlot(slot - 36)\n    // always place the block on the top of the block below it, i guess.\n    const referenceBlock = bot.blockAt(position.plus(new Vec3(0, -1, 0)))\n    return bot.placeBlock(referenceBlock, new Vec3(0, 1, 0))\n  }\n\n  // always leaves you in creative mode\n  async function resetState () {\n    await becomeCreative()\n    await clearInventory()\n    bot.creative.startFlying()\n    await teleport(new Vec3(0, bot.test.groundY, 0))\n    await bot.waitForChunksToLoad()\n    await resetBlocksToSuperflat()\n    await sleep(1000)\n    await clearInventory()\n  }\n\n  async function becomeCreative () {\n    // console.log('become creative')\n    return setCreativeMode(true)\n  }\n\n  async function becomeSurvival () {\n    return setCreativeMode(false)\n  }\n\n  const gameModeChangedMessages = ['commands.gamemode.success.self', 'gameMode.changed']\n\n  async function setCreativeMode (value) {\n    const getGM = val => val ? 'creative' : 'survival'\n    // this function behaves the same whether we start in creative mode or not.\n    // also, creative mode is always allowed for ops, even if server.properties says force-gamemode=true in survival mode.\n    let i = 0\n    const msgProm = onceWithCleanup(bot, 'message', {\n      timeout,\n      checkCondition: msg => gameModeChangedMessages.includes(msg.translate) && i++ > 0 && bot.game.gameMode === getGM(value)\n    })\n\n    // do it three times to ensure that we get feedback\n    bot.chat(`/gamemode ${getGM(value)}`)\n    bot.chat(`/gamemode ${getGM(!value)}`)\n    bot.chat(`/gamemode ${getGM(value)}`)\n    return msgProm\n  }\n\n  async function clearInventory () {\n    const giveStone = onceWithCleanup(bot.inventory, 'updateSlot', { timeout: 1000 * 20, checkCondition: (slot, oldItem, newItem) => newItem?.name === 'stone' })\n    await bot.test.wait(500)\n    bot.chat('/give @a stone 1')\n    bot.inventory.on('updateSlot', (...e) => {\n      // console.log('inventory.updateSlot', e)\n    })\n    await giveStone\n\n    const clearInv = onceWithCleanup(bot, 'message', {\n      timeout,\n      checkCondition: msg => msg.translate === 'commands.clear.success.single' || msg.translate === 'commands.clear.success'\n    })\n    bot.chat('/clear') // don't rely on the message (as it'll come to early), wait for the result of /clear instead\n    await clearInv\n\n    // Check that the inventory is clear\n    for (const slot of bot.inventory.slots) {\n      if (slot && slot.itemCount <= 0) throw new Error('Inventory was not cleared: ' + JSON.stringify(bot.inventory.slots))\n    }\n  }\n\n  // you need to be in creative mode for this to work\n  async function setInventorySlot (targetSlot, item) {\n    assert(item === null || item.name !== 'unknown', `item should not be unknown ${JSON.stringify(item)}`)\n    return bot.creative.setInventorySlot(targetSlot, item)\n  }\n\n  async function teleport (position) {\n    if (bot.supportFeature('hasExecuteCommand')) {\n      bot.test.sayEverywhere(`/execute in overworld run teleport ${bot.username} ${position.x} ${position.y} ${position.z}`)\n    } else {\n      bot.test.sayEverywhere(`/tp ${bot.username} ${position.x} ${position.y} ${position.z}`)\n    }\n    return onceWithCleanup(bot, 'move', {\n      timeout,\n      checkCondition: () => bot.entity.position.distanceTo(position) < 0.9\n    })\n  }\n\n  function sayEverywhere (message) {\n    bot.chat(message)\n    console.log(message)\n  }\n\n  async function fly (delta) {\n    return bot.creative.flyTo(bot.entity.position.plus(delta))\n  }\n\n  async function tellAndListen (to, what, listen) {\n    const chatMessagePromise = onceWithCleanup(bot, 'chat', {\n      timeout,\n      checkCondition: (username, message) => username === to && listen(message)\n    })\n\n    bot.chat(what)\n\n    return chatMessagePromise\n  }\n\n  async function runExample (file, run) {\n    let childBotName\n\n    const detectChildJoin = async () => {\n      const [message] = await onceWithCleanup(bot, 'message', {\n        checkCondition: message => message.json.translate === 'multiplayer.player.joined'\n      })\n      childBotName = message.json.with[0].insertion\n      bot.chat(`/tp ${childBotName} 50 ${bot.test.groundY} 0`)\n      // Wait for the child entity to arrive at the teleport target,\n      // confirming the server has processed the TP\n      const targetPos = new Vec3(50, bot.test.groundY, 0)\n      while (!bot.players[childBotName]?.entity ||\n             bot.players[childBotName].entity.position.distanceTo(targetPos) > 5) {\n        await sleep(100)\n      }\n      // Let the child's physics engine initialize at the new position\n      // (ground detection, chunk processing) before starting the test\n      await bot.waitForTicks(60)\n      bot.chat('loaded')\n    }\n\n    const runExampleOnReady = async () => {\n      await onceWithCleanup(bot, 'chat', {\n        checkCondition: (username, message) => message === 'Ready!'\n      })\n      return run(childBotName)\n    }\n\n    const child = spawn('node', [file, '127.0.0.1', `${bot.test.port}`])\n\n    // Useful to debug child processes:\n    child.stdout.on('data', (data) => { console.log(`${data}`) })\n    child.stderr.on('data', (data) => { console.error(`${data}`) })\n\n    const closeExample = async (err) => {\n      console.log('kill process ' + child.pid)\n\n      try {\n        process.kill(child.pid, 'SIGTERM')\n        const [code] = await onceWithCleanup(child, 'close', { timeout: 5000 })\n        console.log('close requested', code)\n      } catch (e) {\n        console.log(e)\n        console.log('process termination failed, process may already be closed')\n      }\n\n      if (err) {\n        throw err\n      }\n    }\n\n    // Let mocha's test-level timeout (90s) be the backstop instead of\n    // an inner withTimeout, which was causing premature failures on\n    // slow CI runners.\n    try {\n      await Promise.all([detectChildJoin(), runExampleOnReady()])\n    } catch (err) {\n      console.log(err)\n      return closeExample(err)\n    }\n    return closeExample()\n  }\n\n  function selfKill () {\n    bot.chat('/kill @p')\n  }\n\n  // Debug packet IO when tests are re-run with \"Enable debug logging\" - https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables#default-environment-variables\n  if (process.env.RUNNER_DEBUG) {\n    bot._client.on('packet', function (data, meta) {\n      if (['chunk', 'time', 'light', 'alive'].some(e => meta.name.includes(e))) return\n      console.log('->', meta.name, JSON.stringify(data)?.slice(0, 250))\n    })\n    const oldWrite = bot._client.write\n    bot._client.write = function (name, data) {\n      if (['alive', 'pong', 'ping'].some(e => name.includes(e))) return\n      console.log('<-', name, JSON.stringify(data)?.slice(0, 250))\n      oldWrite.apply(bot._client, arguments)\n    }\n      BigInt.prototype.toJSON ??= function () { // eslint-disable-line\n      return this.toString()\n    }\n  }\n}\n"
  },
  {
    "path": "test/externalTests/rain.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  bot.test.sayEverywhere('/weather clear')\n  await bot.test.wait(1000)\n  bot.test.sayEverywhere('/weather rain')\n\n  await once(bot, 'rain')\n  assert.strictEqual(bot.isRaining, true)\n  bot.test.sayEverywhere('/weather clear')\n\n  await once(bot, 'rain')\n  assert.strictEqual(bot.isRaining, false)\n}\n"
  },
  {
    "path": "test/externalTests/rayTrace.js",
    "content": "const assert = require('assert')\nconst { BlockFace } = require('prismarine-world').iterators\n\nmodule.exports = () => async (bot) => {\n  const { position } = bot.entity\n  await bot.lookAt(position.offset(0, 3, 0), true)\n\n  let block = bot.blockAtCursor()\n  assert.strictEqual(block, null)\n\n  block = bot.blockInSight()\n  assert.strictEqual(block, undefined)\n\n  await bot.lookAt(position.offset(0, -3, 0), true)\n\n  block = bot.blockAtCursor()\n  const relBlock = bot.blockAt(position.offset(0, -1, 0))\n  relBlock.face = BlockFace.TOP\n\n  assert.deepStrictEqual(block.position, relBlock.position)\n  assert.deepStrictEqual(block.face, relBlock.face)\n\n  block = bot.blockInSight()\n  assert.deepStrictEqual(block.position, relBlock.position)\n  assert.deepStrictEqual(block.face, relBlock.face)\n}\n"
  },
  {
    "path": "test/externalTests/scoreboard.js",
    "content": "// const assert = require('assert')\n// const { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // TODO: This is failing randomly, investigate and fix\n  /* bot.test.sayEverywhere('/scoreboard objectives add test1 health')\n  bot.test.sayEverywhere('/scoreboard objectives add test2 deathCount')\n  bot.test.sayEverywhere('/scoreboard objectives add test3 dummy')\n  bot.test.sayEverywhere('/scoreboard objectives setdisplay sidebar test1')\n  bot.test.sayEverywhere('/scoreboard objectives setdisplay belowName test1')\n  bot.test.sayEverywhere('/scoreboard objectives setdisplay list test2')\n  bot.test.sayEverywhere(`/scoreboard players add ${bot.username} test3 1`)\n  bot.test.sayEverywhere(`/scoreboard players reset ${bot.username}`)\n\n  let scoreboards = Object.keys(bot.scoreboards).length\n  if (scoreboards !== 2) {\n    await once(bot, 'scoreboardCreated')\n    scoreboards++\n    if (scoreboards !== 2) {\n      await once(bot, 'scoreboardCreated')\n    }\n  }\n  await bot.test.wait(500)\n\n  assert.notStrictEqual(bot.scoreboards.test1, undefined)\n  assert.notStrictEqual(bot.scoreboards.test2, undefined)\n\n  const { test1, test2 } = bot.scoreboards\n  assert.strictEqual(test2.name, test2.title)\n  assert.strictEqual(test1, bot.scoreboard.sidebar)\n\n  const promise = once(bot, 'scoreUpdated')\n  bot.test.sayEverywhere(`/kill ${bot.username}`)\n  const [scoreboard, updated] = await promise\n  assert.strictEqual(scoreboard.itemsMap[bot.username], updated) */\n}\n"
  },
  {
    "path": "test/externalTests/sign.js",
    "content": "const assert = require('assert')\nconst Vec3 = require('vec3')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n  const lowerBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0))\n\n  let signItem = null\n  for (const name in bot.registry.itemsByName) {\n    if (name.includes('sign') && !name.includes('hanging')) signItem = bot.registry.itemsByName[name]\n  }\n  assert.notStrictEqual(signItem, null)\n\n  const p = new Promise((resolve) => {\n    bot._client.once('open_sign_entity', (packet) => {\n      const sign = bot.blockAt(new Vec3(packet.location))\n      bot.updateSign(sign, '1\\n2\\n3\\n')\n\n      setTimeout(() => {\n        // Get updated sign\n        const sign = bot.blockAt(bot.entity.position)\n\n        assert.strictEqual(sign.signText.trimEnd(), '1\\n2\\n3')\n\n        if (sign.blockEntity) {\n          // Check block update\n          bot.activateBlock(sign)\n          assert.notStrictEqual(sign.blockEntity, undefined)\n        }\n\n        resolve()\n      }, 500)\n    })\n  })\n\n  await bot.lookAt(lowerBlock.position, true)\n  await bot.test.setInventorySlot(36, new Item(signItem.id, 1, 0))\n  await bot.placeBlock(lowerBlock, new Vec3(0, 1, 0))\n  return p\n}\n"
  },
  {
    "path": "test/externalTests/sound.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Helper function to check if positions are close enough\n  const positionsAreClose = (pos1, pos2, tolerance = 1.0) => {\n    return Math.abs(pos1.x - pos2.x) <= tolerance &&\n           Math.abs(pos1.y - pos2.y) <= tolerance &&\n           Math.abs(pos1.z - pos2.z) <= tolerance\n  }\n\n  // Helper function to retry an operation\n  const retry = async (operation, maxAttempts = 1, delay = 2000) => {\n    let lastError\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      try {\n        return await operation()\n      } catch (error) {\n        lastError = error\n        if (attempt < maxAttempts) {\n          await new Promise(resolve => setTimeout(resolve, delay))\n        }\n      }\n    }\n    throw lastError\n  }\n\n  // Test sound effect events\n  const soundTest = async () => {\n    await new Promise(resolve => setTimeout(resolve, 2000))\n\n    return retry(async () => {\n      const soundPromise = once(bot, 'soundEffectHeard', 5000)\n\n      if (bot.supportFeature('playsoundUsesResourceLocation')) {\n        // 1.9+ syntax\n        let soundName\n        if (bot.supportFeature('noteBlockNameIsNoteBlock')) {\n          soundName = 'minecraft:block.note_block.harp'\n        } else {\n          soundName = 'block.note.harp'\n        }\n        bot.chat(`/playsound ${soundName} master ${bot.username} ~ ~ ~ 1 1`)\n      } else {\n        // 1.8.8 syntax\n        bot.chat(`/playsound note.harp ${bot.username} ~ ~ ~ 1 1`)\n      }\n\n      const [soundName, position, volume, pitch] = await soundPromise\n\n      assert.ok(typeof soundName === 'string' || typeof soundName === 'number',\n        `Invalid soundName type: ${typeof soundName}`)\n      assert.strictEqual(typeof position, 'object', 'Position should be an object')\n      assert.strictEqual(typeof volume, 'number', 'Volume should be a number')\n      assert.strictEqual(typeof pitch, 'number', 'Pitch should be a number')\n\n      const isClose = positionsAreClose(position, bot.entity.position)\n      assert.ok(isClose,\n        `Position mismatch: expected ${JSON.stringify(bot.entity.position)}, got ${JSON.stringify(position)}`)\n    })\n  }\n\n  // Test note block sounds\n  const noteTest = async () => {\n    const pos = bot.entity.position.offset(1, 0, 0).floored()\n    const noteBlockName = bot.supportFeature('noteBlockNameIsNoteBlock') ? 'note_block' : 'noteblock'\n\n    return retry(async () => {\n      await bot.test.setBlock({ x: pos.x, y: pos.y, z: pos.z, blockName: noteBlockName, relative: false })\n      await new Promise(resolve => setTimeout(resolve, 250))\n\n      const noteHeardPromise = once(bot, 'noteHeard', 5000)\n      await bot.test.setBlock({ x: pos.x, y: pos.y - 1, z: pos.z, blockName: 'redstone_block', relative: false })\n\n      const [block, instrument, pitch] = await noteHeardPromise\n\n      assert.strictEqual(block.name, noteBlockName, 'Wrong block name')\n\n      if (typeof instrument === 'string') {\n        assert.ok(typeof instrument === 'string', 'Instrument should be a string')\n      } else if (typeof instrument === 'object' && instrument !== null) {\n        assert.ok(typeof instrument.name === 'string', 'Instrument name should be a string')\n        assert.ok(typeof instrument.id === 'number', 'Instrument id should be a number')\n      } else {\n        throw new Error(`Unexpected instrument type: ${typeof instrument}`)\n      }\n\n      assert.strictEqual(typeof pitch, 'number', 'Pitch should be a number')\n      assert.ok(pitch >= 0 && pitch <= 24, `Pitch out of range: ${pitch}`)\n    })\n  }\n\n  // Test hardcoded sound effects\n  const hardcodedTest = async () => {\n    return retry(async () => {\n      const soundPromise = Promise.race([\n        once(bot, 'hardcodedSoundEffectHeard', 5000),\n        once(bot, 'soundEffectHeard', 5000).then(([soundName, position, volume, pitch]) => {\n          return [0, 'master', position, volume, pitch]\n        })\n      ])\n\n      if (bot.supportFeature('playsoundUsesResourceLocation')) {\n        bot.chat(`/playsound minecraft:ui.button.click master ${bot.username} ~ ~ ~ 1 1`)\n      } else {\n        bot.chat(`/playsound gui.button.press ${bot.username} ~ ~ ~ 1 1`)\n      }\n\n      const [soundId, soundCategory, position, volume, pitch] = await soundPromise\n\n      assert.strictEqual(typeof soundId, 'number', 'SoundId should be a number')\n      assert.ok(typeof soundCategory === 'string' || typeof soundCategory === 'number',\n        `Invalid soundCategory type: ${typeof soundCategory}`)\n      assert.strictEqual(typeof position, 'object', 'Position should be an object')\n      assert.strictEqual(typeof volume, 'number', 'Volume should be a number')\n      assert.strictEqual(typeof pitch, 'number', 'Pitch should be a number')\n    })\n  }\n\n  try {\n    bot.chat('### Starting sound')\n\n    // Run all tests\n    await soundTest()\n    await noteTest()\n    await hardcodedTest()\n  } finally {\n    // Cleanup: remove the note block and redstone block\n    const pos = bot.entity.position.offset(1, 0, 0).floored()\n    await bot.test.setBlock({ x: pos.x, y: pos.y, z: pos.z, blockName: 'air' })\n    await bot.test.setBlock({ x: pos.x, y: pos.y - 1, z: pos.z, blockName: 'air' })\n  }\n}\n"
  },
  {
    "path": "test/externalTests/spawnEvent.js",
    "content": "const mineflayer = require('mineflayer')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test spawn event on login\n  const spawnBot = mineflayer.createBot({\n    username: 'spawnbot',\n    viewDistance: 'tiny',\n    port: bot.test.port,\n    host: '127.0.0.1',\n    version: bot.version\n  })\n  await once(spawnBot, 'spawn')\n  spawnBot.end()\n\n  // Test spawn event on death\n  bot.test.sayEverywhere(`/kill ${bot.username}`)\n  await once(bot, 'spawn')\n}\n"
  },
  {
    "path": "test/externalTests/team.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  const p = once(bot, 'teamMemberAdded')\n  if (bot.supportFeature('teamUsesChatComponents')) {\n    bot.test.sayEverywhere('/team add test \"test\"')\n    bot.test.sayEverywhere('/team modify test color dark_green')\n    bot.test.sayEverywhere(`/team join test ${bot.username}`)\n  } else {\n    bot.test.sayEverywhere('/scoreboard teams add test')\n    bot.test.sayEverywhere('/scoreboard teams option test color dark_green')\n    bot.test.sayEverywhere('/scoreboard teams join test')\n  }\n\n  await p\n\n  assert.notStrictEqual(bot.teams.test, undefined)\n  assert.notStrictEqual(bot.teamMap[bot.username], undefined, 'teamMap is not undefined')\n\n  const { test } = bot.teams\n\n  assert.strictEqual(test.name.toString(), 'test')\n}\n"
  },
  {
    "path": "test/externalTests/time.js",
    "content": "const assert = require('assert')\nconst { once, onceWithCleanup } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test time properties and ranges\n  const timeProps = {\n    doDaylightCycle: 'boolean',\n    bigTime: 'bigint',\n    time: 'number',\n    timeOfDay: 'number',\n    day: 'number',\n    isDay: 'boolean',\n    moonPhase: 'number',\n    bigAge: 'bigint',\n    age: 'number'\n  }\n\n  // Verify all properties exist and have correct types\n  Object.entries(timeProps).forEach(([prop, type]) => {\n    assert.strictEqual(typeof bot.time[prop], type, `Property ${prop} should be of type ${type}`)\n  })\n\n  // Verify ranges\n  assert(bot.time.timeOfDay >= 0 && bot.time.timeOfDay < 24000, 'timeOfDay should be between 0 and 24000')\n  assert(bot.time.moonPhase >= 0 && bot.time.moonPhase < 8, 'moonPhase should be between 0 and 7')\n  assert(bot.time.day >= 0, 'day should be non-negative')\n  assert(bot.time.age >= 0, 'age should be non-negative')\n  assert(bot.time.bigAge >= 0n, 'bigAge should be non-negative')\n\n  // Helper functions\n  const isTimeClose = (current, target) => Math.abs(current - target) < 510\n  const isTimeInRange = (current, start, end) => start <= end ? current >= start && current <= end : current >= start || current <= end\n  const waitForTime = async (expectedTime) => {\n    // Wait for a time event that matches our expectation (if provided)\n    // This helps avoid race conditions where we catch an old time update\n    if (expectedTime !== undefined) {\n      await onceWithCleanup(bot, 'time', {\n        timeout: 5000,\n        checkCondition: () => isTimeClose(bot.time.timeOfDay, expectedTime)\n      })\n    } else {\n      await once(bot, 'time')\n    }\n  }\n\n  // Helper to set gamerule using the correct name for the version\n  const setDaylightCycle = (value) => {\n    if (bot.supportFeature('gameRuleUsesResourceLocation')) {\n      bot.test.sayEverywhere(`/gamerule minecraft:advance_time ${value}`)\n    } else {\n      bot.test.sayEverywhere(`/gamerule doDaylightCycle ${value}`)\n    }\n  }\n\n  // Disable daylight cycle before time transition tests to prevent\n  // time from drifting between /time set and the assertion\n  const originalDaylightCycle = bot.time.doDaylightCycle\n  setDaylightCycle(false)\n  await waitForTime()\n\n  // Test time transitions\n  const timeTests = [\n    { time: 18000, name: 'midnight', isDay: false },\n    { time: 6000, name: 'noon', isDay: true },\n    { time: 12000, name: 'sunset', isDay: true },\n    { time: 0, name: 'sunrise', isDay: true }\n  ]\n\n  for (const test of timeTests) {\n    bot.test.sayEverywhere(`/time set ${test.time}`)\n    await waitForTime(test.time)\n    assert(isTimeClose(bot.time.timeOfDay, test.time), `Expected time to be close to ${test.time}, got ${bot.time.timeOfDay}`)\n    assert.strictEqual(bot.time.isDay, test.isDay, `${test.name} should be ${test.isDay ? 'day' : 'night'}`)\n  }\n\n  // Re-enable daylight cycle for progression test\n  setDaylightCycle(true)\n  await waitForTime()\n\n  // Test day and moon phase progression\n  const currentDay = bot.time.day\n  const currentPhase = bot.time.moonPhase\n  bot.test.sayEverywhere('/time add 24000')\n  await waitForTime()\n  assert(bot.time.day >= currentDay + 1, `Expected day to be at least ${currentDay + 1}, got ${bot.time.day}`)\n  assert.notStrictEqual(bot.time.moonPhase, currentPhase, 'Moon phase should change after a full day')\n\n  // Test daylight cycle toggle\n  setDaylightCycle(false)\n  await waitForTime()\n  assert.strictEqual(bot.time.doDaylightCycle, false)\n\n  setDaylightCycle(originalDaylightCycle)\n  await waitForTime()\n  assert.strictEqual(bot.time.doDaylightCycle, originalDaylightCycle)\n\n  // Disable daylight cycle again for day/night range tests\n  setDaylightCycle(false)\n  await waitForTime()\n\n  // Test day/night transitions\n  const dayNightTests = [\n    { command: 'day', range: [0, 12000], isDay: true },\n    { command: 'night', range: [12000, 24000], isDay: false }\n  ]\n\n  for (const test of dayNightTests) {\n    bot.test.sayEverywhere(`/time set ${test.command}`)\n    await waitForTime()\n    assert(isTimeInRange(bot.time.timeOfDay, test.range[0], test.range[1]), `Time should be in ${test.command} range`)\n    assert.strictEqual(bot.time.isDay, test.isDay, `${test.command} should be ${test.isDay ? 'day' : 'night'}`)\n  }\n\n  // Restore original daylight cycle setting\n  setDaylightCycle(originalDaylightCycle)\n  await waitForTime()\n}\n"
  },
  {
    "path": "test/externalTests/title.js",
    "content": "const { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  // Test title\n  bot.chat('/title @a title {\"text\":\"Test Title\"}')\n  const [title, type] = await once(bot, 'title', 2000)\n  if (title !== 'Test Title' || type !== 'title') {\n    throw new Error(`Title test failed: expected \"Test Title\" but got \"${title}\" with type \"${type}\"`)\n  }\n\n  // Test subtitle\n  bot.chat('/title @a subtitle {\"text\":\"Test Subtitle\"}')\n  const [subtitle, subtitleType] = await once(bot, 'title', 20000)\n  if (subtitle !== 'Test Subtitle' || subtitleType !== 'subtitle') {\n    throw new Error(`Subtitle test failed: expected \"Test Subtitle\" but got \"${subtitle}\" with type \"${subtitleType}\"`)\n  }\n\n  // Test title_times event\n  bot.chat('/title @a times 10 20 30')\n  const [fadeIn, stay, fadeOut] = await once(bot, 'title_times', 20000)\n  if (fadeIn !== 10 || stay !== 20 || fadeOut !== 30) {\n    throw new Error(`title_times event failed: expected (10,20,30) but got (${fadeIn},${stay},${fadeOut})`)\n  }\n\n  // Test combined title and subtitle\n  bot.chat('/title @a title {\"text\":\"Test Title\"}')\n  const [combinedTitle, combinedTitleType] = await once(bot, 'title', 20000)\n  if (combinedTitle !== 'Test Title' || combinedTitleType !== 'title') {\n    throw new Error(`Combined title test failed: expected \"Test Title\" but got \"${combinedTitle}\" with type \"${combinedTitleType}\"`)\n  }\n\n  bot.chat('/title @a subtitle {\"text\":\"Test Subtitle\"}')\n  const [combinedSubtitle, combinedSubtitleType] = await once(bot, 'title', 20000)\n  if (combinedSubtitle !== 'Test Subtitle' || combinedSubtitleType !== 'subtitle') {\n    throw new Error(`Combined subtitle test failed: expected \"Test Subtitle\" but got \"${combinedSubtitle}\" with type \"${combinedSubtitleType}\"`)\n  }\n\n  // Test clearing title\n  bot.chat('/title @a clear')\n  await once(bot, 'title_clear', 2000)\n}\n"
  },
  {
    "path": "test/externalTests/trade.js",
    "content": "const assert = require('assert')\nconst { once } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  function expectAmount (amount, greaterThan) {\n    // TODO: 1.20.5+ does not seem to respect \"Count\" NBT anymore in /summon\n    // ...as NBT was removed in favor of components that may have something to do\n    if (bot.registry.version['>=']('1.20.5')) {\n      if (amount < 1) throw new Error(`${amount} < 1`) // accept anything >=1\n    } else {\n      assert.strictEqual(amount, greaterThan)\n    }\n  }\n\n  const Item = require('prismarine-item')(bot.registry)\n\n  const villagerType = bot.registry.entitiesByName.villager ? 'villager' : 'Villager'\n  const testFluctuations = bot.supportFeature('selectingTradeMovesItems')\n\n  const summonCommand = bot.supportFeature('indexesVillagerRecipes')\n    ? `/summon ${villagerType} ~ ~1 ~ {NoAI:1, Offers:{Recipes:[0:{maxUses:12,buy:{id:\"minecraft:emerald\",Count:2},sell:{id:\"minecraft:pumpkin_pie\",Count:2},uses: 1},1:{maxUses:12,buy:{id:\"minecraft:emerald\",Count:2},buyB:{id:\"minecraft:pumpkin_pie\",Count:2},sell:{id:\"minecraft:wheat\",Count:2}, uses:1},2:{maxUses:12,buy:{id:\"minecraft:emerald\",Count:1},sell:{id:\"minecraft:glass\",Count:4},uses: 1},3:{maxUses:12,buy:{id:\"minecraft:emerald\",Count:36},buyB:{id:\"minecraft:book\",Count:1},sell:{id:\"minecraft:wooden_sword\",Count:1},uses: 1}]}}`\n    : `/summon ${villagerType} ~ ~1 ~ {NoAI:1, Offers:{Recipes:[{maxUses:12,buy:{id:\"minecraft:emerald\",Count:2},sell:{id:\"minecraft:pumpkin_pie\",Count:2},${testFluctuations ? 'demand:60,priceMultiplier:0.05f,specialPrice:-4,' : ''}uses: 1},{maxUses:12,buy:{id:\"minecraft:emerald\",Count:2},buyB:{id:\"minecraft:pumpkin_pie\",Count:2},sell:{id:\"minecraft:wheat\",Count:2}, uses:1},{maxUses:12,buy:{id:\"minecraft:emerald\",Count:1},sell:{id:\"minecraft:glass\",Count:4},uses: 1},{maxUses:12,buy:{id:\"minecraft:emerald\",Count:36},buyB:{id:\"minecraft:book\",Count:1},sell:{id:\"minecraft:wooden_sword\",Count:1},uses: 1}]}}`\n\n  const commandBlockPos = bot.entity.position.offset(0.5, 0, 0.5)\n  const redstoneBlockPos = commandBlockPos.offset(1, 0, 0)\n\n  let shouldHaveEmeralds = 0\n  for (let slot = 9; slot <= 17; slot += 1) {\n    await bot.test.setInventorySlot(slot, new Item(bot.registry.itemsByName.emerald.id, 64, 0))\n    shouldHaveEmeralds += 64\n  }\n  await bot.test.setInventorySlot(18, new Item(bot.registry.itemsByName.book.id, 11, 0))\n\n  // A command block is needed to spawn the villager due to the chat's character limit in some versions\n  bot.test.sayEverywhere(`/setblock ${commandBlockPos.toArray().join(' ')} command_block`)\n  await bot.test.wait(500)\n  bot.setCommandBlock(commandBlockPos, summonCommand)\n  await bot.test.wait(500)\n  bot.test.sayEverywhere(`/setblock ${redstoneBlockPos.toArray().join(' ')} redstone_block`) // Activate the command block\n\n  const [entity] = await once(bot, 'entitySpawn')\n  assert(entity.name === villagerType)\n\n  const villager = await bot.openVillager(entity)\n  console.log('Opened villager')\n  // console.dir(villager, { depth: null })\n\n  // Handle trade #1 -- takes 2x emerald and returns 2x pumpkin_pie\n  {\n    const trade = villager.trades[0]\n    assert.strictEqual(trade.inputs.length, 1, 'Expected single input from villager on first trade')\n    verifyTrade(trade)\n\n    const [input] = trade.inputs\n    assert.strictEqual(input.name, 'emerald')\n    expectAmount(input.count, 2)\n\n    const [output] = trade.outputs\n    assert.strictEqual(output.name, 'pumpkin_pie')\n    expectAmount(output.count, 2)\n\n    await bot.trade(villager, 0, 11)\n    shouldHaveEmeralds -= testFluctuations ? (2 * 2 * 11) : (2 * 11)\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.pumpkin_pie.id), 22)\n  }\n\n  // Handle trade #2 -- takes [2x emerald, 2x pumpkin_pie] and returns 2x wheat\n  {\n    const trade = villager.trades[1]\n    assert.strictEqual(trade.inputs.length, 2, 'Expected two inputs from villager on second trade')\n    verifyTrade(trade)\n\n    const [input1, input2] = trade.inputs\n    assert.strictEqual(input1.name, 'emerald')\n    expectAmount(input1.count, 2)\n    assert.strictEqual(input2.name, 'pumpkin_pie')\n    expectAmount(input2.count, 2)\n\n    const [output] = trade.outputs\n    assert.strictEqual(output.name, 'wheat')\n    expectAmount(output.count, 2)\n\n    await bot.trade(villager, 1, 11)\n    shouldHaveEmeralds -= 11 * 2\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)\n    assert.strictEqual(bot.currentWindow.count(bot.registry.itemsByName.pumpkin_pie.id), 0)\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.wheat.id), 22)\n  }\n\n  // Handle trade #3 -- takes 1x emerald and returns 4x glass\n  {\n    const trade = villager.trades[2]\n    assert.strictEqual(trade.inputs.length, 1, 'Expected single input from villager on first trade')\n    verifyTrade(trade)\n\n    const [input] = trade.inputs\n    assert.strictEqual(input.name, 'emerald')\n    expectAmount(input.count, 1)\n\n    const [output] = trade.outputs\n    assert.strictEqual(output.name, 'glass')\n    expectAmount(output.count, 4)\n\n    await bot.trade(villager, 2, 11)\n    shouldHaveEmeralds -= 11\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.glass.id), 44)\n  }\n\n  // Handle trade #4 -- takes [36x emerald, 1x book] and returns 1x wooden sword\n  {\n    const trade = villager.trades[3]\n    assert.strictEqual(trade.inputs.length, 2, 'Expected two inputs from villager on second trade')\n    verifyTrade(trade)\n\n    const [input1, input2] = trade.inputs\n    assert.strictEqual(input1.name, 'emerald')\n    expectAmount(input1.count, 36)\n    assert.strictEqual(input2.name, 'book')\n    assert.strictEqual(input2.count, 1)\n\n    const [output] = trade.outputs\n    assert.strictEqual(output.name, 'wooden_sword')\n    assert.strictEqual(output.count, 1)\n\n    await bot.trade(villager, 3, 11)\n    shouldHaveEmeralds -= 11 * 36\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.emerald.id), shouldHaveEmeralds)\n    assert.strictEqual(bot.currentWindow.count(bot.registry.itemsByName.book.id), 0)\n    expectAmount(bot.currentWindow.count(bot.registry.itemsByName.wooden_sword.id), 11)\n  }\n\n  function verifyTrade (trade) {\n    assert.strictEqual(trade.nbTradeUses, 1)\n    assert.strictEqual(trade.maximumNbTradeUses, 12)\n    assert.strictEqual(trade.tradeDisabled, false)\n\n    const printCountInv = function (item) {\n      return `${bot.currentWindow.count(bot.registry.itemsByName[item.name].id)}x ${item.displayName}`\n    }\n    const printCountTrade = function (item) {\n      return `${item.count}x ${item.displayName}`\n    }\n\n    bot.test.sayEverywhere(`I have ${printCountInv(trade.inputItem1)} ${trade.hasItem2 ? 'and ' + printCountInv(trade.inputItem2) : ''}`)\n    bot.test.sayEverywhere(`I can trade ${printCountTrade(trade.inputItem1)} ${trade.hasItem2 ? 'and ' + printCountTrade(trade.inputItem2) : ''} for ${printCountTrade(trade.outputItem)}`)\n  }\n\n  assert.rejects(bot.trade(villager, 1, 1)) // Shouldn't be able, the trade is blocked!\n  villager.close()\n  bot.test.sayEverywhere(`/kill @e[type=${villagerType}]`)\n}\n"
  },
  {
    "path": "test/externalTests/useChests.js",
    "content": "const { Vec3 } = require('vec3')\nconst assert = require('assert')\nconst { once, onceWithCleanup } = require('../../lib/promise_utils')\n\nmodule.exports = () => async (bot) => {\n  const Item = require('prismarine-item')(bot.registry)\n\n  bot.test.groundY = bot.supportFeature('tallWorld') ? -60 : 4\n\n  const smallChestLocation = new Vec3(0, bot.test.groundY, -1)\n  const largeChestLocations = [new Vec3(0, bot.test.groundY, 1), new Vec3(1, bot.test.groundY, 1)]\n  const smallTrappedChestLocation = new Vec3(1, bot.test.groundY, 0)\n  const largeTrappedChestLocations = [\n    new Vec3(-1, bot.test.groundY, 1),\n    new Vec3(-1, bot.test.groundY, 0)\n  ]\n  const chestSlot = 36\n  const trappedChestSlot = 37\n  const boneSlot = 38\n\n  let blockItemsByName\n  if (bot.supportFeature('itemsAreNotBlocks')) {\n    blockItemsByName = 'itemsByName'\n  } else if (bot.supportFeature('itemsAreAlsoBlocks')) {\n    blockItemsByName = 'blocksByName'\n  }\n\n  const chestBlockId = bot.registry.blocksByName.chest.id\n  const trappedChestBlockId = bot.registry.blocksByName.trapped_chest.id\n\n  function itemByName (items, name) {\n    for (let i = 0; i < items.length; ++i) {\n      const item = items[i]\n      if (item && item.name === name) return item\n    }\n    return null\n  }\n\n  async function depositBones (chestLocation, count) {\n    const chest = await bot.openContainer(bot.blockAt(chestLocation))\n    assert(chest.containerItems().length === 0)\n    assert(chest.items().length > 0)\n    const name = 'bone'\n    const item = itemByName(chest.items(), name)\n    if (!item) {\n      bot.test.sayEverywhere(`unknown item ${name}`)\n      throw new Error(`unknown item ${name}`)\n    }\n    await chest.deposit(item.type, null, count)\n    chest.close()\n  }\n\n  async function withdrawBones (chestLocation, count) {\n    const chest = await bot.openContainer(bot.blockAt(chestLocation))\n    const name = 'bone'\n    const item = itemByName(chest.containerItems(), name)\n    if (!item) {\n      bot.test.sayEverywhere(`unknown item ${name}`)\n      throw new Error(`unknown item ${name}`)\n    }\n    await chest.withdraw(item.type, null, count)\n    assert(chest.containerItems().length === 0)\n    assert(chest.items().length > 0)\n    chest.close()\n  }\n\n  await bot.test.setInventorySlot(chestSlot, new Item(bot.registry[blockItemsByName].chest.id, 3, 0))\n  await bot.test.setInventorySlot(trappedChestSlot, new Item(bot.registry[blockItemsByName].trapped_chest.id, 3, 0))\n  await bot.test.setInventorySlot(boneSlot, new Item(bot.registry.itemsByName.bone.id, 3, 0))\n\n  await bot.test.becomeSurvival()\n\n  // place the chests around us\n  await bot.test.placeBlock(chestSlot, largeChestLocations[0])\n  await bot.test.placeBlock(chestSlot, largeChestLocations[1])\n  await bot.test.placeBlock(chestSlot, smallChestLocation)\n  await bot.test.placeBlock(trappedChestSlot, largeTrappedChestLocations[0])\n  await bot.test.placeBlock(trappedChestSlot, largeTrappedChestLocations[1])\n  await bot.test.placeBlock(trappedChestSlot, smallTrappedChestLocation)\n\n  assert.strictEqual(bot.blockAt(largeChestLocations[0]).type, chestBlockId)\n  assert.strictEqual(bot.blockAt(largeChestLocations[1]).type, chestBlockId)\n  assert.strictEqual(bot.blockAt(smallChestLocation).type, chestBlockId)\n  assert.strictEqual(bot.blockAt(largeTrappedChestLocations[0]).type, trappedChestBlockId)\n  assert.strictEqual(bot.blockAt(largeTrappedChestLocations[1]).type, trappedChestBlockId)\n  assert.strictEqual(bot.blockAt(smallTrappedChestLocation).type, trappedChestBlockId)\n\n  // Test that \"chestLidMove\" is emitted only once when opening a double chest\n  let emitted = false\n  bot.on('chestLidMove', handler)\n  async function handler (block, isOpen, block2) {\n    if (emitted) {\n      assert.fail(new Error('chestLidMove emitted twice'))\n    } else {\n      emitted = true\n\n      let blockAssert = false; let block2Assert = false\n      for (const location of largeChestLocations) {\n        if (location.equals(block.position)) blockAssert = true\n        if (location.equals(block2.position)) block2Assert = true\n      }\n      assert(blockAssert && block2Assert, new Error('The block instance emitted by chestLidMove is not part of the chest oppened'))\n      assert.strictEqual(isOpen, 1, new Error('isOpen should be 1 when opened by one only player'))\n\n      await bot.test.wait(500)\n\n      bot.removeListener('chestLidMove', handler)\n      chest.close()\n    }\n  }\n  const chest = await bot.openContainer(bot.blockAt(largeChestLocations[0]))\n  await once(chest, 'close')\n\n  await depositBones(smallChestLocation, 1)\n  await depositBones(largeChestLocations[0], 2)\n\n  assert(bot.inventory.items().length === 0)\n\n  await withdrawBones(smallChestLocation, 1)\n  await withdrawBones(largeChestLocations[0], 2)\n\n  await depositBones(smallTrappedChestLocation, 1)\n  await depositBones(largeTrappedChestLocations[0], 2)\n\n  assert(bot.inventory.items().length === 0)\n\n  await withdrawBones(smallTrappedChestLocation, 1)\n  await withdrawBones(largeTrappedChestLocations[0], 2)\n\n  const itemsWithStackSize = {\n    64: ['stone', 'mycelium'],\n    16: ['ender_pearl', 'egg'],\n    1: ['fishing_rod', 'bow']\n  }\n\n  function getRandomStackableItem () {\n    if (Math.random() < 0.75) {\n      return itemsWithStackSize[64][~~(Math.random() * itemsWithStackSize[64].length)]\n    } else {\n      if (Math.random() < 0.5) {\n        return itemsWithStackSize[16][~~(Math.random() * itemsWithStackSize[16].length)]\n      } else {\n        return itemsWithStackSize[1][~~(Math.random() * itemsWithStackSize[1].length)]\n      }\n    }\n  }\n\n  async function createRandomLayout (window, slotPopulationFactor) {\n    await bot.test.becomeCreative()\n\n    for (let slot = 0; slot < window.inventoryStart; slot++) {\n      if (Math.random() < slotPopulationFactor) {\n        const randomItem = getRandomStackableItem()\n        const item = bot.registry.itemsByName[randomItem]\n        bot.chat(`/give ${bot.username} ${item.name} ${Math.ceil(Math.random() * item.stackSize)}`)\n        await onceWithCleanup(window, 'updateSlot', {\n          timeout: 5000,\n          checkCondition: (slot, oldItem, newItem) => slot === window.hotbarStart && newItem?.name === item.name\n        })\n\n        // await bot.clickWindow(slot, 0, 2)\n        await bot.moveSlotItem(window.hotbarStart, slot)\n        await bot.test.wait(100)\n      }\n    }\n\n    await bot.test.becomeSurvival()\n  }\n\n  async function testMouseClick (window, clicks) {\n    let iterations = 0\n    while (iterations++ < clicks) {\n      await bot.clickWindow(~~(Math.random() * window.inventoryStart), 0, 0)\n    }\n  }\n\n  function clearLargeChest () {\n    bot.chat(`/setblock ${largeChestLocations[0].x} ${largeChestLocations[0].y} ${largeChestLocations[0].z} chest`)\n    bot.chat(`/setblock ${largeChestLocations[1].x} ${largeChestLocations[1].y} ${largeChestLocations[1].z} chest`)\n  }\n\n  const window = await bot.openContainer(bot.blockAt(largeChestLocations[0]))\n  await createRandomLayout(window, 0.95)\n\n  await testMouseClick(window, 250)\n\n  window.close()\n  clearLargeChest()\n}\n"
  },
  {
    "path": "test/internalTest.js",
    "content": "/* eslint-env mocha */\n\nconst mineflayer = require('../')\nconst vec3 = require('vec3')\nconst mc = require('minecraft-protocol')\nconst assert = require('assert')\nconst { sleep } = require('../lib/promise_utils')\nconst nbt = require('prismarine-nbt')\nconst { once } = require('../lib/promise_utils')\n\nfor (const supportedVersion of mineflayer.testedVersions) {\n  const registry = require('prismarine-registry')(supportedVersion)\n  const version = registry.version\n  const Chunk = require('prismarine-chunk')(supportedVersion)\n\n  const hasSignedChat = registry.supportFeature('signedChat')\n  function chatText (text) {\n    // TODO: move this to prismarine-chat in a new ChatMessage(text).toNotch(asNbt) method\n    return registry.supportFeature('chatPacketsUseNbtComponents')\n      ? nbt.comp({ text: nbt.string(text) })\n      : JSON.stringify({ text })\n  }\n\n  function generateChunkPacket (chunk) {\n    const lights = chunk.dumpLight()\n    return {\n      x: 0,\n      z: 0,\n      groundUp: true,\n      biomes: chunk.dumpBiomes !== undefined ? chunk.dumpBiomes() : undefined,\n      heightmaps: {\n        type: 'compound',\n        name: '',\n        value: {\n          MOTION_BLOCKING: { type: 'longArray', value: new Array(36).fill([0, 0]) }\n        }\n      }, // send fake heightmap\n      bitMap: chunk.getMask(),\n      chunkData: chunk.dump(),\n      blockEntities: [],\n      trustEdges: false,\n      skyLightMask: lights?.skyLightMask,\n      blockLightMask: lights?.blockLightMask,\n      emptySkyLightMask: lights?.emptySkyLightMask,\n      emptyBlockLightMask: lights?.emptyBlockLightMask,\n      skyLight: lights?.skyLight,\n      blockLight: lights?.blockLight\n    }\n  }\n\n  describe(`mineflayer_internal ${supportedVersion}v`, function () {\n    this.timeout(10 * 1000)\n    let bot\n    let server\n    beforeEach((done) => {\n      server = mc.createServer({\n        'online-mode': false,\n        version: supportedVersion,\n        // 25565 - local server, 25566 - proxy server\n        port: 25567\n      })\n      server.on('listening', () => {\n        bot = mineflayer.createBot({\n          username: 'player',\n          version: supportedVersion,\n          port: 25567\n        })\n        bot.test = {}\n\n        bot.test.buildChunk = () => {\n          if (bot.supportFeature('tallWorld')) {\n            return new Chunk({ minY: -64, worldHeight: 384 })\n          } else {\n            return new Chunk()\n          }\n        }\n\n        bot.test.generateLoginPacket = () => {\n          let loginPacket\n          if (bot.supportFeature('usesLoginPacket')) {\n            loginPacket = registry.loginPacket\n            loginPacket.entityId = 0 // Default login packet in minecraft-data 1.16.5 is 1, so set it to 0\n          } else {\n            loginPacket = {\n              entityId: 0,\n              levelType: 'fogetaboutit',\n              gameMode: 0,\n              previousGameMode: 255,\n              worldNames: ['minecraft:overworld'],\n              dimension: 0,\n              worldName: 'minecraft:overworld',\n              hashedSeed: [0, 0],\n              difficulty: 0,\n              maxPlayers: 20,\n              reducedDebugInfo: 1,\n              enableRespawnScreen: true\n            }\n          }\n          return loginPacket\n        }\n        done()\n      })\n    })\n    afterEach((done) => {\n      bot.on('end', () => {\n        done()\n      })\n      server.close()\n    })\n    it('chat', (done) => {\n      bot.once('chat', (username, message) => {\n        assert.strictEqual(username, 'gary')\n        assert.strictEqual(message, 'hello')\n        bot.chat('hi')\n      })\n      server.on('playerJoin', (client) => {\n        client.write('login', bot.test.generateLoginPacket())\n        const message = hasSignedChat\n          ? JSON.stringify({ text: 'hello' })\n          : JSON.stringify({\n            translate: 'chat.type.text',\n            with: [{\n              text: 'gary'\n            },\n            'hello'\n            ]\n          })\n\n        if (hasSignedChat) {\n          const uuid = 'd3527a0b-bc03-45d5-a878-2aafdd8c8a43' // random\n          const networkName = chatText('gary')\n\n          if (registry.supportFeature('incrementedChatType')) {\n            client.write('player_chat', {\n              plainMessage: 'hello',\n              filterType: 0,\n              type: { chatType: 0 },\n              networkName,\n              previousMessages: [],\n              senderUuid: uuid,\n              timestamp: Date.now(),\n              index: 0,\n              salt: 1n\n            })\n          } else if (registry.supportFeature('useChatSessions')) {\n            client.write('player_chat', {\n              plainMessage: 'hello',\n              filterType: 0,\n              type: { chatType: 0 },\n              networkName,\n              previousMessages: [],\n              senderUuid: uuid,\n              timestamp: Date.now(),\n              index: 0,\n              salt: 2n\n            })\n          } else if (registry.supportFeature('chainedChatWithHashing')) {\n            client.write('player_chat', {\n              plainMessage: 'hello',\n              filterType: 0,\n              type: 0,\n              networkName,\n              previousMessages: [],\n              senderUuid: uuid,\n              timestamp: Date.now(),\n              salt: 3n,\n              signature: Buffer.alloc(0)\n            })\n          } else {\n            client.write('player_chat', {\n              signedChatContent: '',\n              unsignedChatContent: message,\n              type: 0,\n              senderUuid: uuid,\n              senderName: JSON.stringify({ text: 'gary' }),\n              senderTeam: undefined,\n              timestamp: Date.now(),\n              salt: 4n,\n              signature: Buffer.alloc(0)\n            })\n          }\n        } else {\n          client.write('chat', { message, position: 0, sender: '0' })\n        }\n        function onChat (packet) {\n          const msg = packet.message || packet.unsignedChatContent || packet.signedChatContent\n          assert.strictEqual(msg, 'hi')\n          done()\n        }\n        client.on('chat_message', onChat)\n        client.on('chat', onChat)\n      })\n    })\n    it('entity effects', (done) => {\n      bot.once('entityEffect', (entity, effect) => {\n        assert.strictEqual(entity.id, 8)\n        assert.strictEqual(effect.id, 10)\n        assert.strictEqual(effect.amplifier, 1)\n        assert.strictEqual(effect.duration, 11)\n        done()\n      })\n      // Versions prior to 1.11 have capital first letter\n      const entities = bot.registry.entitiesByName\n      const creeperId = entities.creeper ? entities.creeper.id : entities.Creeper.id\n      server.on('playerJoin', (client) => {\n        client.write(bot.registry.supportFeature('consolidatedEntitySpawnPacket') ? 'spawn_entity' : 'spawn_entity_living', {\n          entityId: 8, // random\n          entityUUID: '00112233-4455-6677-8899-aabbccddeeff',\n          objectUUID: '00112233-4455-6677-8899-aabbccddeeff',\n          type: creeperId,\n          x: 10,\n          y: 11,\n          z: 12,\n          yaw: 13,\n          pitch: 14,\n          headPitch: 14,\n          velocity: { x: 15, y: 16, z: 17 },\n          velocityX: 16,\n          velocityY: 17,\n          velocityZ: 18,\n          metadata: []\n        })\n        client.write('entity_effect', {\n          entityId: 8,\n          effectId: 10,\n          amplifier: 1,\n          duration: 11,\n          hideParticles: false\n        })\n      })\n    })\n    it('blockAt', (done) => {\n      const pos = vec3(1, 65, 1)\n      const goldId = bot.registry.blocksByName.gold_block.id\n      bot.on('chunkColumnLoad', (columnPoint) => {\n        assert.strictEqual(columnPoint.x, 0)\n        assert.strictEqual(columnPoint.z, 0)\n        assert.strictEqual(bot.blockAt(pos).type, goldId)\n        done()\n      })\n      server.on('playerJoin', (client) => {\n        client.write('login', bot.test.generateLoginPacket())\n        const chunk = bot.test.buildChunk()\n        chunk.setBlockType(pos, goldId)\n        client.write('map_chunk', generateChunkPacket(chunk))\n      })\n    })\n\n    describe('physics', () => {\n      const pos = vec3(1, 65, 1)\n      const goldId = 41\n      it('no physics if there is no chunk', (done) => {\n        let fail = 0\n        const basePosition = {\n          x: 1.5,\n          y: 66,\n          z: 1.5,\n          dx: 0, // 1.21.3\n          dy: 0, // 1.21.3\n          dz: 0, // 1.21.3\n          pitch: 0,\n          yaw: 0,\n          flags: bot.registry.version['>=']('1.21.3') ? {} : 0,\n          teleportId: 0\n        }\n        server.on('playerJoin', async (client) => {\n          await client.write('login', bot.test.generateLoginPacket())\n          await client.write('position', basePosition)\n          client.on('packet', (data, meta) => {\n            const packetName = meta.name\n            switch (packetName) {\n              case 'position':\n                fail++\n                break\n              case 'position_look':\n                fail++\n                break\n              case 'look':\n                fail++\n                break\n            }\n            if (fail > 1) assert.fail('position packet sent')\n          })\n          await sleep(2000)\n          done()\n        })\n      })\n      it('absolute position & relative position (velocity)', (done) => {\n        server.on('playerJoin', async (client) => {\n          await client.write('login', bot.test.generateLoginPacket())\n          const chunk = bot.test.buildChunk()\n          chunk.setBlockType(pos, goldId)\n          await client.write('map_chunk', generateChunkPacket(chunk))\n\n          await once(bot, 'chunkColumnLoad')\n\n          // --- Test 1: Absolute Position ---\n          const absolutePositionPacket = {\n            x: 1.5,\n            y: 80,\n            z: 1.5,\n            pitch: 0,\n            yaw: 0,\n            teleportId: 1,\n            flags: bot.supportFeature('positionPacketHasBitflags') ? { x: false, y: false, z: false, yaw: false, pitch: false } : 0\n          }\n\n          bot.entity.velocity.y = -1.0 // Give bot some velocity\n\n          const p1 = once(bot, 'forcedMove')\n          client.write('position', absolutePositionPacket)\n          await p1\n\n          // Assertions for absolute teleport\n          assert.strictEqual(bot.entity.velocity.y, 0, 'Velocity should be reset to 0 after an absolute teleport')\n          assert.deepStrictEqual(bot.entity.position, vec3(1.5, 80, 1.5), 'Position should be set absolutely')\n\n          // --- Test 2: Relative Position ---\n          const relativePositionPacket = {\n            x: 1.0,\n            y: -2.0,\n            z: 0.5,\n            pitch: 0,\n            yaw: 0,\n            teleportId: 2,\n            flags: bot.supportFeature('positionPacketHasBitflags') ? { x: true, y: true, z: true, yaw: false, pitch: false } : 7\n          }\n\n          // Set a known velocity *before* the relative update\n          bot.entity.velocity.y = -1.0\n          const initialPosition = bot.entity.position.clone()\n          const expectedPosition = initialPosition.plus(vec3(1.0, -2.0, 0.5))\n\n          const p2 = once(bot, 'forcedMove')\n          client.write('position', relativePositionPacket)\n          await p2\n\n          // Assertions for relative teleport\n          assert.notStrictEqual(bot.entity.velocity.y, 0, 'Velocity should be preserved after a relative teleport')\n          assert.deepStrictEqual(bot.entity.position, expectedPosition, 'Position should be updated relatively')\n\n          done()\n        })\n      })\n      it('gravity + land on solid block + jump', (done) => {\n        let y = 80\n        let landed = false\n        bot.on('move', () => {\n          if (landed) return\n          assert.ok(bot.entity.position.y <= y)\n          assert.ok(bot.entity.position.y >= pos.y)\n          y = bot.entity.position.y\n          if (bot.entity.position.y <= pos.y + 1) {\n            assert.strictEqual(bot.entity.position.y, pos.y + 1)\n            assert.strictEqual(bot.entity.onGround, true)\n            landed = true\n            done()\n          } else {\n            assert.strictEqual(bot.entity.onGround, false)\n          }\n        })\n        server.on('playerJoin', (client) => {\n          client.write('login', bot.test.generateLoginPacket())\n          const chunk = bot.test.buildChunk()\n\n          chunk.setBlockType(pos, goldId)\n          client.write('map_chunk', generateChunkPacket(chunk))\n          client.write('position', {\n            x: 1.5,\n            y: 80,\n            z: 1.5,\n            pitch: 0,\n            yaw: 0,\n            flags: bot.supportFeature('positionPacketHasBitflags') ? { x: false, y: false, z: false, yaw: false, pitch: false } : 0,\n            teleportId: 0\n          })\n        })\n      })\n    })\n\n    describe('world', () => {\n      const pos = vec3(1, 65, 1)\n      const goldId = 41\n      it('switchWorld respawn', (done) => {\n        const loginPacket = bot.test.generateLoginPacket()\n        let respawnPacket\n        if (bot.supportFeature('usesLoginPacket')) {\n          loginPacket.worldName = 'minecraft:overworld'\n          loginPacket.hashedSeed = [0, 0]\n          loginPacket.entityId = 0\n          respawnPacket = {\n            // 1.19+ the `dimension` filed is a string in respawn packet and undefined in login packet, in previous versions it's same NBT data in login/respawn\n            dimension: bot.supportFeature('dimensionDataInCodec') ? 'minecraft:overworld' : loginPacket.dimension,\n            worldName: loginPacket.worldName,\n            hashedSeed: loginPacket.hashedSeed,\n            gamemode: 0,\n            previousGamemode: 255,\n            isDebug: false,\n            isFlat: false,\n            copyMetadata: true,\n            death: {\n              dimensionName: '',\n              location: {\n                x: 0,\n                y: 0,\n                z: 0\n              }\n            }\n          }\n          if (bot.supportFeature('spawnRespawnWorldDataField')) {\n            respawnPacket = {\n              worldState: respawnPacket\n            }\n            respawnPacket.worldState.name = loginPacket.worldName\n            respawnPacket.worldState.dimension = loginPacket.dimension\n          }\n        } else {\n          respawnPacket = {\n            dimension: 0,\n            hashedSeed: [0, 0],\n            gamemode: 0,\n            levelType: 'default'\n          }\n        }\n        const chunk = bot.test.buildChunk()\n        chunk.setBlockType(pos, goldId)\n        const chunkPacket = generateChunkPacket(chunk)\n        const positionPacket = {\n          x: 1.5,\n          y: 80,\n          z: 1.5,\n          pitch: 0,\n          yaw: 0,\n          flags: 0,\n          teleportId: 0\n        }\n        server.on('playerJoin', async (client) => {\n          bot.once('respawn', () => {\n            assert.ok(bot.world.getColumn(0, 0) !== undefined)\n            bot.once('respawn', () => {\n              assert.ok(bot.world.getColumn(0, 0) === undefined)\n              done()\n            })\n            if (bot.supportFeature('spawnRespawnWorldDataField')) {\n              respawnPacket.worldState.name = 'minecraft:nether'\n            } else {\n              respawnPacket.worldName = 'minecraft:nether'\n            }\n            if (bot.supportFeature('spawnRespawnWorldDataField')) {\n              respawnPacket.worldState.dimension = 1\n            } else if (bot.supportFeature('usesLoginPacket')) {\n              respawnPacket.dimension.name = 'e'\n            } else {\n              respawnPacket.dimension = 1\n            }\n            client.write('respawn', respawnPacket)\n          })\n          await client.write('login', loginPacket)\n          await client.write('map_chunk', chunkPacket)\n          await client.write('position', positionPacket)\n          await client.write('update_health', {\n            health: 20,\n            food: 20,\n            foodSaturation: 0\n          })\n          await bot.waitForTicks(1)\n          await client.write('respawn', respawnPacket)\n        })\n      })\n    })\n\n    describe('game', () => {\n      it('responds to ping / transaction packets', (done) => { // only on 1.17\n        server.on('playerJoin', async (client) => {\n          if (bot.supportFeature('transactionPacketExists')) {\n            const transactionPacket = { windowId: 0, action: 42, accepted: false }\n            client.once('transaction', (data, meta) => {\n              assert.ok(meta.name === 'transaction')\n              assert.ok(data.action === 42)\n              assert.ok(data.accepted === true)\n              done()\n            })\n            client.write('transaction', transactionPacket)\n          } else {\n            client.once('pong', (data) => {\n              assert(data.id === 42)\n              done()\n            })\n            client.write('ping', { id: 42 })\n          }\n        })\n      })\n    })\n\n    describe('entities', () => {\n      it('entity id changes on login', (done) => {\n        const loginPacket = bot.test.generateLoginPacket()\n        server.on('playerJoin', (client) => {\n          if (bot.supportFeature('usesLoginPacket')) {\n            loginPacket.entityId = 0 // Default login packet in minecraft-data 1.16.5 is 1, so set it to 0\n          }\n          client.write('login', loginPacket)\n          bot.once('login', () => {\n            assert.ok(bot.entity.id === 0)\n            loginPacket.entityId = 42\n            bot.once('login', () => {\n              assert.ok(bot.entity.id === 42)\n              done()\n            })\n            client.write('login', loginPacket)\n          })\n        })\n      })\n\n      it('player displayName', (done) => {\n        server.on('playerJoin', (client) => {\n          bot.on('entitySpawn', (entity) => {\n            const player = bot.players[entity.username]\n            assert.strictEqual(entity.username, player.displayName.toString())\n            if (registry.supportFeature('playerInfoActionIsBitfield')) {\n              client.write('player_info', {\n                action: { update_display_name: true },\n                data: [{\n                  uuid: '1-2-3-4',\n                  displayName: chatText('wvffle')\n                }]\n              })\n            } else {\n              client.write('player_info', {\n                action: 'update_display_name',\n                data: [{\n                  uuid: '1-2-3-4',\n                  displayName: chatText('wvffle')\n                }]\n              })\n            }\n          })\n\n          bot.once('playerUpdated', (player) => {\n            assert.strictEqual('wvffle', player.displayName.toString())\n            if (registry.supportFeature('playerInfoActionIsBitfield')) {\n              client.write('player_info', {\n                action: { update_display_name: true },\n                data: [{\n                  uuid: '1-2-3-4',\n                  displayName: null\n                }]\n              })\n            } else {\n              client.write('player_info', {\n                action: 'update_display_name',\n                data: [{\n                  uuid: '1-2-3-4',\n                  displayName: null\n                }]\n              })\n            }\n\n            bot.once('playerUpdated', (player) => {\n              assert.strictEqual(player.entity.username, player.displayName.toString())\n              done()\n            })\n          })\n\n          if (registry.supportFeature('playerInfoActionIsBitfield')) {\n            client.write('player_info', {\n              action: { add_player: true },\n              data: [{\n                uuid: '1-2-3-4',\n                player: {\n                  name: 'bot5',\n                  properties: []\n                },\n                gamemode: 0,\n                latency: 0\n              }]\n            })\n          } else {\n            client.write('player_info', {\n              action: 'add_player',\n              data: [{\n                uuid: '1-2-3-4',\n                name: 'bot5',\n                properties: [],\n                gamemode: 0,\n                ping: 0\n              }]\n            })\n          }\n\n          if (bot.registry.supportFeature('unifiedPlayerAndEntitySpawnPacket')) {\n            client.write('spawn_entity', {\n              entityId: 56,\n              objectUUID: '1-2-3-4',\n              type: bot.registry.entitiesByName.player.internalId,\n              x: 1,\n              y: 2,\n              z: 3,\n              pitch: 0,\n              yaw: 0,\n              headPitch: 0,\n              objectData: 1,\n              velocity: { x: 0, y: 0, z: 0 },\n              velocityX: 0,\n              velocityY: 0,\n              velocityZ: 0\n            })\n          } else {\n            client.write('named_entity_spawn', {\n              entityId: 56,\n              playerUUID: '1-2-3-4',\n              x: 1,\n              y: 2,\n              z: 3,\n              yaw: 0,\n              pitch: 0,\n              currentItem: -1,\n              metadata: []\n            })\n          }\n        })\n      })\n\n      it('sets players[player].entity to null upon despawn', (done) => {\n        let serverClient = null\n        bot.once('entitySpawn', (entity) => {\n          if (bot.version !== '1.17') {\n            serverClient.write('entity_destroy', {\n              entityIds: [8]\n            })\n          } else {\n            serverClient.write('destroy_entity', {\n              entityIds: 8\n            })\n          }\n        })\n        bot.once('entityGone', (entity) => {\n          assert.strictEqual(bot.players[entity.username], undefined)\n          done()\n        })\n        server.on('playerJoin', (client) => {\n          serverClient = client\n\n          if (registry.supportFeature('playerInfoActionIsBitfield')) {\n            client.write('player_info', {\n              action: { add_player: true },\n              data: [{\n                uuid: '1-2-3-4',\n                player: { name: 'bot5', properties: [] },\n                gamemode: 0,\n                latency: 0\n              }]\n            })\n          } else {\n            client.write('player_info', {\n              id: 56,\n              state: 'play',\n              action: 'add_player',\n              length: 1,\n              data: [{\n                uuid: '1-2-3-4',\n                name: 'bot5',\n                propertiesLength: 0,\n                properties: [],\n                gamemode: 0,\n                ping: 0,\n                hasDisplayName: false\n              }]\n            })\n          }\n\n          if (bot.registry.supportFeature('unifiedPlayerAndEntitySpawnPacket')) {\n            client.write('spawn_entity', {\n              entityId: 56,\n              objectUUID: '1-2-3-4',\n              type: bot.registry.entitiesByName.player.internalId,\n              x: 1,\n              y: 2,\n              z: 3,\n              pitch: 0,\n              yaw: 0,\n              headPitch: 0,\n              objectData: 1,\n              velocity: { x: 0, y: 0, z: 0 },\n              velocityX: 0,\n              velocityY: 0,\n              velocityZ: 0\n            })\n          } else {\n            client.write('named_entity_spawn', {\n              entityId: 56,\n              playerUUID: '1-2-3-4',\n              x: 1,\n              y: 2,\n              z: 3,\n              yaw: 0,\n              pitch: 0,\n              currentItem: -1,\n              metadata: []\n            })\n          }\n        })\n      })\n\n      it('metadata', (done) => {\n        server.on('playerJoin', (client) => {\n          bot.on('entitySpawn', (entity) => {\n            assert.strictEqual(entity.displayName, 'Creeper')\n\n            const lastMeta = entity.metadata\n            bot.on('entityUpdate', (entity) => {\n              assert.ok('0' in entity.metadata)\n              assert.strictEqual(entity.metadata[0], 1)\n              assert.strictEqual(entity.metadata[1], lastMeta[1])\n              done()\n            })\n\n            client.write('entity_metadata', {\n              entityId: 8,\n              metadata: [\n                { key: 0, type: bot.registry.supportFeature('mcDataHasEntityMetadata') ? 'int' : 0, value: 1 }\n              ]\n            })\n          })\n\n          // Versions prior to 1.11 have capital first letter\n          const entities = bot.registry.entitiesByName\n          const creeperId = entities.creeper ? entities.creeper.id : entities.Creeper.id\n          client.write(bot.registry.supportFeature('consolidatedEntitySpawnPacket') ? 'spawn_entity' : 'spawn_entity_living', {\n            entityId: 8, // random\n            entityUUID: '00112233-4455-6677-8899-aabbccddeeff',\n            objectUUID: '00112233-4455-6677-8899-aabbccddeeff',\n            type: creeperId,\n            x: 10,\n            y: 11,\n            z: 12,\n            yaw: 13,\n            pitch: 14,\n            headPitch: 14,\n            velocity: { x: 15, y: 16, z: 17 },\n            velocityX: 16,\n            velocityY: 17,\n            velocityZ: 18,\n            metadata: [\n              { type: 0, key: bot.registry.supportFeature('mcDataHasEntityMetadata') ? 'byte' : 0, value: 0 },\n              { type: 0, key: bot.registry.supportFeature('mcDataHasEntityMetadata') ? 'int' : 1, value: 1 }\n            ]\n          })\n        })\n      })\n\n      it('\\'itemDrop\\' event', function (done) {\n        const itemData = {\n          itemId: 149,\n          itemCount: 5\n        }\n\n        server.on('playerJoin', (client) => {\n          bot.on('itemDrop', (entity) => {\n            const slotPosition = metadataPacket.metadata[0].key\n\n            if (bot.supportFeature('itemsAreAlsoBlocks')) {\n              assert.strictEqual(entity.metadata[slotPosition].blockId, itemData.itemId)\n            } else if (bot.supportFeature('itemsAreNotBlocks')) {\n              assert.strictEqual(entity.metadata[slotPosition].itemId, itemData.itemId)\n            }\n            assert.strictEqual(entity.metadata[slotPosition].itemCount, itemData.itemCount)\n\n            done()\n          })\n\n          let entityType\n          if (['1.8', '1.9', '1.10', '1.11', '1.12'].includes(bot.majorVersion)) {\n            entityType = 2\n          } else {\n            entityType = bot.registry.entitiesArray.find(e => e.name.toLowerCase() === 'item' || e.name.toLowerCase() === 'item_stack').id\n          }\n          client.write('spawn_entity', {\n            entityId: 16,\n            objectUUID: '00112233-4455-6677-8899-aabbccddeeff',\n            type: Number(entityType),\n            x: 0,\n            y: 0,\n            z: 0,\n            pitch: 0,\n            yaw: 0,\n            headPitch: 0,\n            objectData: 1,\n            velocity: { x: 0, y: 0, z: 0 },\n            velocityX: 0,\n            velocityY: 0,\n            velocityZ: 0\n          })\n\n          const metadataPacket = {\n            entityId: 16,\n            metadata: [\n              { key: 7, type: 6, value: { itemCount: itemData.itemCount } }\n            ]\n          }\n          // Versions prior to 1.13 use 5 as type field value of metadata for storing a slot. 1.13 and so on, use 6\n          // Also the structure of a slot changes from 1.12 to 1.13\n          if (bot.supportFeature('itemsAreAlsoBlocks')) {\n            metadataPacket.metadata[0].key = 6\n            metadataPacket.metadata[0].type = 5\n            metadataPacket.metadata[0].value.blockId = itemData.itemId\n            metadataPacket.metadata[0].value.itemDamage = 0\n          } else if (bot.supportFeature('itemsAreNotBlocks')) {\n            if (bot.majorVersion === '1.13') metadataPacket.metadata[0].key = 6\n            metadataPacket.metadata[0].value.itemId = itemData.itemId\n            metadataPacket.metadata[0].value.present = true\n          }\n\n          if (bot.supportFeature('entityMetadataHasLong')) {\n            metadataPacket.metadata[0].type = 7\n          }\n\n          if (bot.registry.supportFeature('mcDataHasEntityMetadata')) {\n            metadataPacket.metadata[0].type = 'item_stack'\n          }\n          metadataPacket.metadata[0].value.addedComponentCount = 0\n          metadataPacket.metadata[0].value.removedComponentCount = 0\n          metadataPacket.metadata[0].value.components = []\n          metadataPacket.metadata[0].value.removeComponents = []\n\n          client.write('entity_metadata', metadataPacket)\n        })\n      })\n    })\n\n    it('bed', (done) => {\n      const blocks = bot.registry.blocksByName\n      const entities = bot.registry.entitiesByName\n\n      const playerPos = vec3(10, 0, 0)\n      const zombiePos = vec3(0, 0, 0)\n      const beds = [\n        { head: vec3(10, 0, 3), foot: vec3(10, 0, 2), facing: 2, throws: false },\n        { head: vec3(9, 0, 4), foot: vec3(10, 0, 4), facing: 3, throws: true, error: new Error('the bed is too far') },\n        { head: vec3(8, 0, 0), foot: vec3(8, 0, 1), facing: 0, throws: true, error: new Error('there are monsters nearby') },\n        { head: vec3(12, 0, 0), foot: vec3(11, 0, 0), facing: 1, throws: false }\n      ]\n\n      const zombieId = entities.zombie ? entities.zombie.id : entities.Zombie.id\n      let bedBlock\n      if (bot.supportFeature('oneBlockForSeveralVariations', version.majorVersion)) {\n        bedBlock = blocks.bed\n      } else if (bot.supportFeature('blockSchemeIsFlat', version.majorVersion)) {\n        bedBlock = blocks.red_bed\n      }\n      const bedId = bedBlock.id\n\n      bot.once('chunkColumnLoad', (columnPoint) => {\n        for (const bed in beds) {\n          const bedBock = bot.blockAt(beds[bed].foot)\n          const bedBockMetadata = bot.parseBedMetadata(bedBock)\n          assert.strictEqual(bedBockMetadata.facing, beds[bed].facing, 'The facing property seems to be wrong')\n          assert.strictEqual(bedBockMetadata.part, false, 'The part property seems to be wrong') // Is the foot\n\n          if (beds[bed].throws) {\n            bot.sleep(bedBock).catch(err => assert.strictEqual(err, beds[bed].error))\n          } else {\n            bot.sleep(bedBock).catch(err => assert.ifError(err))\n          }\n        }\n\n        done()\n      })\n\n      server.once('playerJoin', (client) => {\n        bot.time.timeOfDay = 18000\n        const loginPacket = bot.test.generateLoginPacket()\n        client.write('login', loginPacket)\n\n        const chunk = bot.test.buildChunk()\n\n        for (const bed in beds) {\n          chunk.setBlockType(beds[bed].head, bedId)\n          chunk.setBlockType(beds[bed].foot, bedId)\n        }\n\n        if (bot.supportFeature('blockStateId', version.majorVersion)) {\n          chunk.setBlockStateId(beds[0].foot, 3 + bedBlock.minStateId) // { facing: north, occupied: false, part: foot }\n          chunk.setBlockStateId(beds[0].head, 2 + bedBlock.minStateId) // { facing:north, occupied: false, part: head }\n\n          chunk.setBlockStateId(beds[1].foot, 15 + bedBlock.minStateId) // { facing: east, occupied:false, part:foot }\n          chunk.setBlockStateId(beds[1].head, 14 + bedBlock.minStateId) // { facing: east, occupied: false, part: head }\n\n          chunk.setBlockStateId(beds[2].foot, 7 + bedBlock.minStateId) // { facing: south, occupied: false, part: foot }\n          chunk.setBlockStateId(beds[2].head, 6 + bedBlock.minStateId) // { facing: south, occupied: false, part: head }\n\n          chunk.setBlockStateId(beds[3].foot, 11 + bedBlock.minStateId) // { facing: west, occupied: false, part: foot }\n          chunk.setBlockStateId(beds[3].head, 10 + bedBlock.minStateId) // { facing: west, occupied: false, part: head }\n        } else if (bot.supportFeature('blockMetadata', version.majorVersion)) {\n          chunk.setBlockData(beds[0].foot, 2) // { facing: north, occupied: false, part: foot }\n          chunk.setBlockData(beds[0].head, 10) // { facing:north, occupied: false, part: head }\n\n          chunk.setBlockData(beds[1].foot, 3) // { facing: east, occupied:false, part:foot }\n          chunk.setBlockData(beds[1].head, 11) // { facing: east, occupied: false, part: head }\n\n          chunk.setBlockData(beds[2].foot, 0) // { facing: south, occupied: false, part: foot }\n          chunk.setBlockData(beds[2].head, 8) // { facing: south, occupied: false, part: head }\n\n          chunk.setBlockData(beds[3].foot, 1) // { facing: west, occupied: false, part: foot }\n          chunk.setBlockData(beds[3].head, 9) // { facing: west, occupied: false, part: head }\n        }\n\n        client.write('position', {\n          x: playerPos.x,\n          y: playerPos.y,\n          z: playerPos.z,\n          yaw: 0,\n          pitch: 0,\n          flags: 0,\n          teleportId: 1\n        })\n\n        client.write(bot.registry.supportFeature('consolidatedEntitySpawnPacket') ? 'spawn_entity' : 'spawn_entity_living', {\n          entityId: 8,\n          entityUUID: '00112233-4455-6677-8899-aabbccddeeff',\n          objectUUID: '00112233-4455-6677-8899-aabbccddeeff',\n          type: zombieId,\n          x: zombiePos.x,\n          y: zombiePos.y,\n          z: zombiePos.z,\n          yaw: 0,\n          pitch: 0,\n          headPitch: 0,\n          velocity: { x: 0, y: 0, z: 0 },\n          velocityX: 0,\n          velocityY: 0,\n          velocityZ: 0,\n          metadata: []\n        })\n\n        client.write('map_chunk', generateChunkPacket(chunk))\n      })\n    })\n\n    describe('tablist', () => {\n      it('handles newlines in header and footer', (done) => {\n        const HEADER = 'asd\\ndsa'\n        const FOOTER = '\\nas\\nas\\nas\\n'\n        bot._client.on('playerlist_header', (packet) => {\n          setImmediate(() => {\n            assert.strictEqual(bot.tablist.header.toString(), HEADER)\n            assert.strictEqual(bot.tablist.footer.toString(), FOOTER)\n            done()\n          })\n        })\n        // TODO: figure out how the \"extra\" should be encoded in NBT so this branch can be removed\n        if (registry.supportFeature('chatPacketsUseNbtComponents')) {\n          server.on('playerJoin', (client) => {\n            client.write('playerlist_header', {\n              header: chatText(HEADER),\n              footer: chatText(FOOTER)\n            })\n          })\n        } else {\n          server.on('playerJoin', (client) => {\n            client.write('playerlist_header', {\n              header: JSON.stringify({ text: '', extra: [{ text: HEADER, color: 'yellow' }] }),\n              footer: JSON.stringify({ text: '', extra: [{ text: FOOTER, color: 'yellow' }] })\n            })\n          })\n        }\n      })\n    })\n  })\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n    \"compilerOptions\": {\n      \"module\": \"commonjs\",\n      \"strictNullChecks\": true\n    },\n    \"files\": [\n      \"index.d.ts\"\n    ]\n}"
  }
]