Created
July 18, 2021 08:02
-
-
Save extremeheat/65c34acb132ec097ea53247647609b5a to your computer and use it in GitHub Desktop.
mineflayer.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"name": "mineflayer.ipynb", | |
"provenance": [], | |
"collapsed_sections": [], | |
"authorship_tag": "ABX9TyM8AtSLPYrH5PrqIp20R7e8", | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/extremeheat/65c34acb132ec097ea53247647609b5a/mineflayer.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "2BAYqsdOgKNJ" | |
}, | |
"source": [ | |
"# Using mineflayer in Python\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 **95.111.249.143:10000**.\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. " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "qM2rVyxGf2Yv" | |
}, | |
"source": [ | |
"## Setup" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "K2ol06QOhL6s" | |
}, | |
"source": [ | |
"First, make sure you have Python version 3.7 and Node.js version 14 or newer installed" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "8zCSpx8Bif5m", | |
"outputId": "2be51f05-2099-4c15-8d38-ecf82ac227d3" | |
}, | |
"source": [ | |
"!python --version\n", | |
"!node --version" | |
], | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"Python 3.7.11\n", | |
"v14.16.0\n" | |
], | |
"name": "stdout" | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "C7omnDs3lNaV" | |
}, | |
"source": [ | |
"Now, we can use pip to install the `javascript` Python package to access Node.js libraries from Python." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "DKnwzSZQ8Taf", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "d3035663-02e4-40ca-916c-78a9d0da92ca" | |
}, | |
"source": [ | |
" !pip install javascript" | |
], | |
"execution_count": 1, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"Collecting javascript\n", | |
" Downloading https://files.pythonhosted.org/packages/3c/fb/57d13463e6b975883747d8556449fc0a0b40dcc202b681b5f8df414f6115/javascript-1%210.2.5-py3-none-any.whl\n", | |
"Installing collected packages: javascript\n", | |
"Successfully installed javascript-1!0.2.5\n" | |
], | |
"name": "stdout" | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "_RAKlcScgKtV" | |
}, | |
"source": [ | |
"## Usage" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "bxAdFbBfmdCd" | |
}, | |
"source": [ | |
"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", | |
"You may notice the extra imports : On, Once, off and AsyncTask. These will be discussed later on. \n", | |
"\n", | |
"\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "54Lnq3aH4Tee" | |
}, | |
"source": [ | |
"from javascript import require, On, Once, AsyncTask" | |
], | |
"execution_count": 2, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "cy7-0cWxdhU8" | |
}, | |
"source": [ | |
"We can now import Mineflayer" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "8jgkTVniDPUZ", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "bf37ddf5-6d23-4be4-ef7e-088c1a91e10f" | |
}, | |
"source": [ | |
"mineflayer = require('mineflayer')" | |
], | |
"execution_count": 3, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"\u001b[1m Installing 'mineflayer' version 'latest'... This will only happen once. \u001b[0m\n", | |
"\n", | |
"[JSE] npm notice created a lockfile as package-lock.json. You should commit this file.\n", | |
"[JSE] npm WARN js-modules@ No repository field.\n", | |
"[JSE] npm WARN js-modules@ No license field.\n", | |
"added 75 packages from 56 contributors and audited 75 packages in 4.47s\n", | |
"\n", | |
"\n", | |
"\n", | |
"4 packages are looking for funding\n", | |
"\n", | |
" run `npm fund` for details\n", | |
"\n", | |
"\n", | |
"\n", | |
"found 0 vulnerabilities\n", | |
"\n", | |
"\n", | |
"\n", | |
"\n", | |
"\n", | |
"\u001b[1m OK. \u001b[0m\n", | |
"\n" | |
], | |
"name": "stdout" | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "WBAj5rSkgjKX" | |
}, | |
"source": [ | |
"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", | |
"Below that, we also an event handlers, one that gets called on \"spawn\" event and sends a chat message." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "1gfZSAUCDVMg" | |
}, | |
"source": [ | |
"random_number = id([]) % 1000 # Give us a random number upto 1000\n", | |
"BOT_USERNAME = f'colab_{random_number}'\n", | |
"\n", | |
"bot = mineflayer.createBot({ 'host': '95.111.249.143', 'port': 10000, 'username': BOT_USERNAME, 'hideErrors': False })\n", | |
"\n", | |
"# The spawn event \n", | |
"@Once(bot, 'login')\n", | |
"def spawn(*a):\n", | |
" bot.chat('I spawned')" | |
], | |
"execution_count": 4, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "yvYZYbi0k8Za" | |
}, | |
"source": [ | |
"If your bot spawned, we can now take a look at the bot's position" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "swMd1VvXYuKn", | |
"outputId": "3655292d-0495-40fd-f390-3cd3c1c3cc37" | |
}, | |
"source": [ | |
"bot.entity.position" | |
], | |
"execution_count": 5, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"Vec3 { \u001b[94mx\u001b[39m: \u001b[33m-152.5\u001b[39m, \u001b[94my\u001b[39m: \u001b[33m93\u001b[39m, \u001b[94mz\u001b[39m: \u001b[33m507.5\u001b[39m }" | |
] | |
}, | |
"metadata": { | |
"tags": [] | |
}, | |
"execution_count": 5 | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "EdSjlgmilZ3O" | |
}, | |
"source": [ | |
"### Listening to events" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "23FTp0XrioMg" | |
}, | |
"source": [ | |
"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.*\n", | |
"\n", | |
"A decroator 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", | |
"In the code below, we create an event emitter on `bot` that listens to `playerJoin` events, then print that out." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "s8QGmC4nHjnH" | |
}, | |
"source": [ | |
"@On(bot, 'playerJoin')\n", | |
"def end(this, player):\n", | |
" bot.chat('Someone joined!')" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "Onkn-TDsne9P" | |
}, | |
"source": [ | |
"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", | |
"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" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "S4y9qAe6oh8H" | |
}, | |
"source": [ | |
"@On(bot, 'chat')\n", | |
"def onChat(this, user, message, *rest):\n", | |
" print(f'{user} said \"{message}\"')\n", | |
"\n", | |
" # If the message contains stop, remove the event listener and stop logging.\n", | |
" if 'stop' in message:\n", | |
" off(bot, 'chat', onChat)" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "OybQNxGAq4P2" | |
}, | |
"source": [ | |
"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." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "iOzZeWfHozeX" | |
}, | |
"source": [ | |
"## Asynchronous tasks\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." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "xJUk8b21pOzg" | |
}, | |
"source": [ | |
"### Block breaking\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\"." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "yhoAlhAhpSTL" | |
}, | |
"source": [ | |
"@On(bot, 'chat')\n", | |
"def breakListener(this, sender, message, *args):\n", | |
" if sender and (sender != BOT_USERNAME):\n", | |
" if 'break' in message:\n", | |
" pos = bot.entity.position.offset(0, -1, 0)\n", | |
" blockUnder = bot.blockAt(pos)\n", | |
" if bot.canDigBlock(blockUnder):\n", | |
" bot.chat(f\"I'm breaking the '{blockUnder.name}' block underneath {bot.canDigBlock(blockUnder)}\")\n", | |
" # The start=True parameter means to immediately invoke the function underneath\n", | |
" # If left blank, you can start it with the `start()` function later on.\n", | |
" try:\n", | |
" @AsyncTask(start=True)\n", | |
" def break_block(task):\n", | |
" bot.dig(blockUnder)\n", | |
" bot.chat('I started digging!')\n", | |
" except Exception as e:\n", | |
" bot.chat(f\"I had an error {e}\")\n", | |
" else:\n", | |
" bot.chat(f\"I can't break the '{blockUnder.name}' block underneath\")\n", | |
" if 'stop' in message:\n", | |
" off(bot, 'chat', breakListener)" | |
], | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "JMgoMA-MriAt" | |
}, | |
"source": [ | |
"## Using mineflayer plugins\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." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "OVAJCyxcsfig" | |
}, | |
"source": [ | |
"### mineflayer-pathfinder\n", | |
"\n", | |
"`mineflayer-pathfinder` is a essential plugin that helps your bot move between places through A* pathfinding. Let's import it:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "mH6eXm8TtTKh", | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"outputId": "7c8f68ea-d8d8-4aae-f9b9-dcb26700e40f" | |
}, | |
"source": [ | |
"pathfinder = require('mineflayer-pathfinder')\n", | |
"bot.loadPlugin(pathfinder.pathfinder)\n", | |
"# Create a new minecraft-data instance with the bot's version\n", | |
"mcData = require('minecraft-data')(bot.version)\n", | |
"# Create a new movements class\n", | |
"movements = pathfinder.Movements(bot, mcData)\n", | |
"# How far to be fromt the goal\n", | |
"RANGE_GOAL = 1" | |
], | |
"execution_count": 6, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"\u001b[1m Installing 'mineflayer-pathfinder' version 'latest'... This will only happen once. \u001b[0m\n", | |
"\n", | |
"[JSE] npm WARN js-modules@ No repository field.\n", | |
"[JSE] npm WARN js-modules@ No license field.\n", | |
"added 1 package from 1 contributor and audited 76 packages in 1.172s\n", | |
"\n", | |
"\n", | |
"\n", | |
"4 packages are looking for funding\n", | |
"\n", | |
" run `npm fund` for details\n", | |
"\n", | |
"\n", | |
"\n", | |
"found 0 vulnerabilities\n", | |
"\n", | |
"\n", | |
"\n", | |
"\n", | |
"\n", | |
"\u001b[1m OK. \u001b[0m\n", | |
"\n" | |
], | |
"name": "stdout" | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "Ju8MPkSauTBb" | |
}, | |
"source": [ | |
"Now let's have create a goal for the bot to move to where another player wants, based on a chat message." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "8jIp8bxnudDK" | |
}, | |
"source": [ | |
"bot.removeAllListeners('chat')\n", | |
"@On(bot, 'chat')\n", | |
"def handleMsg(this, sender, message, *args):\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", | |
" target = player.entity\n", | |
" if not target:\n", | |
" bot.chat(\"I don't see you !\")\n", | |
" return\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", | |
" if 'stop' in message:\n", | |
" off(bot, 'chat', handleMsg)" | |
], | |
"execution_count": 15, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "K36XDP09k1aH" | |
}, | |
"source": [ | |
"## Analyzing the world" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "xK1Ww1ACmLZl" | |
}, | |
"source": [ | |
"You can also interact with mineflayer through any other Python package." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "5QatUqxeW6b_" | |
}, | |
"source": [ | |
"Let's analyze some block frequencies..." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 354 | |
}, | |
"id": "k2XyRgzi8otw", | |
"outputId": "028048ad-554f-4d8b-b3d0-6c1daa562902" | |
}, | |
"source": [ | |
"import matplotlib.pyplot as plt\n", | |
"figure = plt.figure()\n", | |
"axes = figure.add_axes([0,0,1,1])\n", | |
"Vec3 = require('vec3').Vec3\n", | |
"\n", | |
"columns = bot.world.getColumns()\n", | |
"block_freqs = {}\n", | |
"for c in range(0, 4): # iterate through some of the loaded chunk columns\n", | |
" cc = columns[c].column\n", | |
" for y in range(1, 40):\n", | |
" for x in range(1, 16):\n", | |
" for z in range(1, 16):\n", | |
" block = cc.getBlock(Vec3(x, y, z))\n", | |
" if block.name in block_freqs:\n", | |
" block_freqs[block.name] += 1\n", | |
" else:\n", | |
" block_freqs[block.name] = 1\n", | |
"\n", | |
"print(block_freqs)\n", | |
"axes.bar(block_freqs.keys(), block_freqs.values())\n", | |
"plt.show()" | |
], | |
"execution_count": null, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"text": [ | |
"{'stone': 32200, 'bedrock': 1807, 'dirt': 665, 'gravel': 340, 'lava': 56, 'coal_ore': 1, 'air': 30, 'torch': 1}\n" | |
], | |
"name": "stdout" | |
}, | |
{ | |
"output_type": "display_data", | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<Figure size 432x288 with 1 Axes>" | |
] | |
}, | |
"metadata": { | |
"tags": [], | |
"needs_background": "light" | |
} | |
} | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "q2IkKpXZzRiP" | |
}, | |
"source": [ | |
"## Exiting the bot\n", | |
"\n", | |
"Once you're done, you can call `bot.quit()` or `bot.end()` to disconnect and stop the bot." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"id": "1-NxvPk1YuGw" | |
}, | |
"source": [ | |
"bot.quit()" | |
], | |
"execution_count": 16, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "SpwlmlCBc90Q" | |
}, | |
"source": [ | |
"## Read more\n", | |
"\n", | |
"* **API** - https://github.com/PrismarineJS/mineflayer/blob/master/docs/api.md\n", | |
"* **Type Definitions** - https://github.com/PrismarineJS/mineflayer/blob/master/index.d.ts\n", | |
"* FAQ - https://github.com/PrismarineJS/mineflayer/blob/master/docs/FAQ.md\n", | |
"* JS tutorial - https://github.com/PrismarineJS/mineflayer/blob/master/docs/tutorial.md\n" | |
] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment