Skip to content

Latest commit

 

History

History
667 lines (491 loc) · 24.2 KB

tutorial.md

File metadata and controls

667 lines (491 loc) · 24.2 KB

Tutorial

Table of Contents

Introduction

This tutorial will help you get started with Mineflayer, even if you know nothing about coding.
If you already know some things about Node and NPM, you can go to the Create a bot section, otherwise start here.

Basics

The following sections are about basics concepts you need to know to get started using Mineflayer.

Javascript basics

Installing Node

In this section you will learn the basics about Javascript, Node and NPM.

Javascript, often abbreviated to JS, is a programming language designed for the web. It is what makes most interactivity on the web possible.
Node.js, often just Node, makes it possible to use Javascript outside of web browsers.

So the first thing you have to do to get started is to install Node. You can get it here.
After it is installed, open a command prompt (also known as a terminal) and then type node -v
If you have installed Node correctly, it should return a version number. If it says it can't find the command, try installing it again.

Now you have Node, you could start writing code, but we need to do 1 more thing.
Javascript can be written in any basic text editor, but it is much easier if you use what is called an Integrated development environment(IDE)
An 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(VSCode)
Once 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
This will let VSCode know we are working with Javascript, and give you the correct suggestions.

Javascript variables

Start by typing the following:

const test = 5

This will create a new variable named test and assign it the value 5
Variable are used to save data and use it later in the code.

Now 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
Once your terminal is in the same folder as your Javascript file, you can run node filename.js
If you have done everything correctly, you should see nothing.
In the next chapter we will show you how you can 'print' things to the terminal.

In 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.
Javascript 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.
If you want a modifiable variable, you will still have to use let of course.

const test = 5
// eslint-disable-next-line
test = 10 // This line is invalid.

The second line is invallid because you can't reassign the test variable.

If you want to help yourself and other people understand your code better, you can use comments.
Comments can be created using // and everything after that is completely ignored by Javascript.

Show output

A lot of times you want to see the current value of a variable, to make sure your program is running correctly.
You do this by printing the variables to the terminal.
In Javascript, we can do this using the console.log() function.

const test = 5

console.log(test)

Now when you save and run this code, you should finally see something:

5

Javascript functions

Next you will learn about functions. Functions are a piece of code that can be used multiple times throughout your code.
These can be useful because you don't have to type something multiple times.

const addition = (a, b) => {
  return a + b
}

const test1 = addition(5, 10)
const test2 = addition(1, 0)

console.log(test1)
console.log(test2)

The => is used to define a function, called the arrow operator.
Before the arrow operator is the parameter list, everything between the round brackets () are parameters, separated by a comma.
Parameters are variables you can give to your function so that your function can work with them.
Then after the arrow operator comes the function body, this is everything between the curly brackets {}
This is where you put the code of the function.
Now that the function is complete, we assign it to a variable to give it a name, in this case addition

As you can see, this code takes the parameters a and b and adds them together.
Then the function will return the result.
When a function is defined, the code in the function body is not yet executed. To run a function you have to call it.
You can call a function by using the name of a function followed by round brackets. In this case addition()
However, the addition function requires 2 parameters. These can be passed along by putting them inside the round brackets, comma separated: addition(1, 2)
When 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)

Sometimes 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')

The above should output the following:

15
1

Javascript types

So far we have only worked with numbers, but Javascript can work with more variable types:

  • A string is a piece of text that can contain multiple characters. Strings are defined by using the quotes ''
const string = 'This is a string' // string type
  • An array is a type that can hold multiple variables inside itself. Arrays are defined by using the square brackets []
const array = [1, 2, 3] // array type
  • Object are basically advanced arrays, you will learn more about it later in this tutorial. Their defined by curly brackets {}
const object = {} // object type
  • Functions are also their own type.
const adder = (a, b) => { return a + b } // function type
  • A boolean is a type that can only be true or false
const boolean = true // boolean type
  • When something is not (yet) defined, its type is undefined
let nothing // undefined type
const notDefined = undefined // undefined type

If-statements

Sometimes you want to do different things based on a certain condition.
This can be achieved using if-statements.

const name = 'Bob'

if (name === 'Bob') {
  console.log('Your name is Bob')
} else if (name === 'Alice') {
  console.log('Your name is Alice')
} else {
  console.log('Your name is not Bob or Alice')
}

An 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 {} A condition has to be something that computes to a boolean.
In 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 If the condition is true the code in the body will be executed.
You can chain an if-statement with an else-if-statement or an else-statement.
You can have as many else-if-statements as you want, but only 1 if and else statement.
If you have an else-statement, it will be called only if all the chained statements before it are false

Loops

Loops are used to repeat certain code until a certain conditional is met.

let countDown = 5

while (countDown > 0) {
  console.log(countDown)
  countDown = countDown - 1 // Decrement countDown by 1
}

console.log('Finished!')

The above code will print the following

5
4
3
2
1
Finished!

The while loop has a condition () and a body {}
When the code reaches the loop, it will check the condition. If the condition is true, the code in the body will be executed.
After the end of the body is reached, the condition is checked again, and if true, the body executed again.
This will happen for as long as the condition check is still true
Each loop, this code prints the current countDown number, and then decrements it by 1.
After the 5th loop, the condition 0 > 0 will be false, and thus the code will move on.

A for loop is also often used, and differs slightly from a while loop.

for (let countDown = 5; countDown > 0; countDown = countDown - 1) {
  console.log(countDown)
}

Instead of only a condition, the for loops has 3 different parts
These parts are separated by a semi-column.
The first parts let countDown = 5 is only executed once, at the start of the loop.
The second part countDown > 0 is the condition, this is the same as the while loop.
The third part countDown = countDown - 1 is executed after each loop.:

If you want to do something for every item in an array, a for of loop can be useful.

const array = [1, 2, 3]

for (const item of array) {
  console.log(item)
}

A for of loop needs to have a variable before the of, this is the variable that can be used to access the current item.
The variable after the of needs to be something that contains other variable. These are mostly arrays, but also some objects.
The 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

Node Package manager

The last thing you need to know is how to use the Node Package Manager.
NPM is automatically installed when you install Node.
NPM is used to get useful packages that other people created that can do useful things for you.
You can search for packages on their website, and then install them using the npm install command in your terminal.
To install Mineflayer for example, run npm install mineflayer

Then, Node can access installed modules by using the require() function.

const mineflayer = require('mineflayer')

After this, the mineflayer variable can be used to access all the features of Mineflayer.

Creating a bot

Now that you know the basics of Javascript, Node and NPM, you're ready to start creating your first bot!
If you don't know any of the terms above, you should go back to the previous section

Below is the absolute minimum necessary to create a Mineflayer bot.

const mineflayer = require('mineflayer')

const bot = mineflayer.createBot()

If 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
However, this bot isn't quite useful, as by default this will connect to a Minecraft server running on your machine with the port 25565.
If you want to choose which server you want your bot to connect to, you have to pass along a few options.

const mineflayer = require('mineflayer')

const options = {
  host: 'localhost', // Change this to the ip you want.
  port: 25565 // Change this to the port you want.
}

const bot = mineflayer.createBot(options)

Javascript objects

The curly brackets {} are used to create an object.
Objects contain what is called a key-value pair.
A key-value pair consist of a colon : and a key before the colon, and the value of that key after the colon.
The keys can then be used to retrieve their value.
You can have multiple key-value pairs by separating them by commas.

const object = {
  number: 10,
  another: 5
}

console.log(object.number) // This will print the value 10

This concept is often used to create what is named 'named parameters'
The advantage of this is that you don't have to use all the options available, and their position does not matter.
The value can be anything, even other object. If the value is a function, that function is often called a method for that object.
You can also create the object in-line.

const bot = mineflayer.createBot({ host: 'localhost', port: 25565 })

Logging in

Without any parameters, the bot will have the name Player and can only log into offline servers. (Cracked & open-to-lan)
If you supply the createBot with an username option, it will log in with that username. (Still only in offline server)
To log into a specific account, you have to supply both the username and the password

const bot = mineflayer.createBot({
  host: 'localhost',
  port: 25565,
  username: 'Player',
  password: 'password'
})

Command line arguments

What if somebody else likes your bot and wants to use it, but uses it on a different server and with a different account?
This 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)
To counter this, a lot of people use command line arguments.

const bot = mineflayer.createBot({
  host: process.argv[2],
  port: parseInt(process.argv[3]),
  username: process.argv[4],
  password: process.argv[5]
})

As you can see, no more sensitive data in your code! But now, how do you run it?
Now, instead of starting your program with just node filename.js you start it with node filename.js host port username password
Node will automatically split the whole command line into an array, separated by spaces.
This array is process.argv
The 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.

First item Second item Third Item Fourth item Fifth item Sixth item
Value node filename.js host port username password
Index [0] [1] [2] [3] [4] [5]

Passing along functions

Not only basics variables like numbers and strings can be given as an argument.
Functions can also be passed as a variable.

const welcome = () => {
  bot.chat('hi!')
}

bot.once('spawn', welcome)

As you can see, the bot.once() method takes 2 parameters.
The first parameter is an event name, the second parameter is the function to call when that event happens.
Remember, when passing along a function, only use the name and not the round brackets ()

bot.chat() is the method for sending message to the chat.

You can also simplify this code by using a anonymous function.
An anonymous function doesn't have a name, and is created at the position where the function name used to go.
They still have to have a parameter list () and a function body {}, even if it isn't used.

bot.once('spawn', () => {
  bot.chat('hi!')
})

Listening for an event

The bot object has many useful events. You 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. To remove specific listener you can use bot.removeListener() method.

  • bot.on(eventName, listener) Execute the listener function for each time the event named eventName triggered.
  • bot.once(eventName, listener) Execute the listener function, only once, the first time the event named eventName triggered.
  • bot.removeListener(eventName, listener) 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.

Not only bot object, Chest, Furnace, Dispenser, EnchantmentTable, Villager object also have their own events!

Promises

A promise 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)

async function consume (bot) {
  try {
    await bot.consume()
    console.log('Finished consuming')
  } catch (err) {
    console.log(error)
  }
}

The above code will try to consume what the bot is currently holding.
When the consuming ends, the function that is passed along is called.
We can then do other things that we want to do after.
The function could also be called when an error occurs.

Correct and incorrect approach

Below is an example of a bot that will craft oak logs into oak planks and then into sticks.

Incorect approach ❌:

function craft (bot) {
  const mcData = require('minecraft-data')(bot.version)
  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0] // Get the first recipe for oak planks
  bot.craft(plankRecipe, 1) // ❌ start crafting oak planks.

  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0] // Get the first recipe for sticks
  bot.craft(stickRecipe, 1) // ❌ start crafting sticks.
}

Correct approach with promises ✔️:

async function craft (bot) {
  const mcData = require('minecraft-data')(bot.version)
  const plankRecipe = bot.recipesFor(mcData.itemsByName.oak_planks.id ?? mcData.itemsByName.planks.id)[0]
  await bot.craft(plankRecipe, 1, null)
  const stickRecipe = bot.recipesFor(mcData.itemsByName.sticks.id)[0]
  await bot.craft(stickRecipe, 1, null)
  bot.chat('Crafting Sticks finished')
}

The reason the incorrect approach is wrong is because when bot.craft() is called, the code will continue below while the bot is crafting.
By 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.
Using promises can fix this because they will only be called after the bot.craft() is finished.

More on the bot.craft() method.

Advanced

The following concepts aren't necessary to create a Mineflayer bot, but they can be useful to understand and create more advanced bots.
We assume you have understood the Basics tutorial.

Loop over an object

The for of loop described in the loops chapter can also be used to loop over an object.

If we have the following object:

const obj = {
  a: 1,
  b: 2,
  c: 3
}

The following will loop over all the values of the object.

for (const value of Object.values(obj)) {
  console.log(value)
}
1
2
3

This will loop over all the keys of the object.

for (const key of Object.keys(obj)) {
  console.log(key)
}
a
b
c

You can also loop over the keys and values at the same time. You will have to destructure the variables first, explained here.

for (const [key, value] of Object.entries(obj)) {
  console.log(key + ', ' + value)
}
a, 1
b, 2
c, 3

These loops are possible because Object.values(obj) and Object.keys(obj) both return an array of the objects values and keys respectively.
Object.entries(obj) returns an array where each item is an array with 2 items: a key and its corresponding value.
It'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.

There 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.
The for in loop loops over the keys of an object instead of the values. (The index in case it is an array) However, 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. In general, you'll want to use for of instead of for in so make sure you don't confuse the two.

Creating an event from chat

You can create your own event from chat using bot.chatAddPattern() method. Useful for Bukkit servers where the chat format changes a lot. bot.chatAddPattern() method takes three arguments :

  • pattern - regular expression (regex) to match chat
  • chatType - the event the bot emits when the pattern matches. e.g. "chat" or "whisper"
  • description - Optional, describes what the pattern is for

You can add Groups and Range into the pattern, then the listener will spread the captured groups into arguments of your callback sequentially.

Read more about regular expression.

Examples :

Answer Hello Bot

Here we're creating a bot that answer 'hello' from the other player.

bot.chatAddPattern(
  /(helo|hello|Hello)/,
  'hello',
  'Someone says hello'
)

const hi = () => {
  bot.chat('Hi!')
}

bot.on('hello', hi)

Custom chat

Creating an event based on custom chat format.
Custom chat example:

[Player] Player1 > Hello
[Admin] Alex > Hi
[Player] Player2 > Help me, im stuck
[Mod] Jim > On my way
bot.chatAddPattern(
  /^\[(.+)\] (\S+) > (.+)$/,
  'my_chat_event',
  'Custom chat event'
)

const logger = (rank, username, message) => {
  console.log(`${username} said ${message}`)
}

bot.on('my_chat_event', logger)

Explanation on the regex ^\[(.+)\] (\S+) > (.+)$ can be found here.

FAQ

How to run a bot on android

Here is a quick setup for running a bot on an android device using Termux.

Install Termux

Install Termux and start it.

Setup

Install Node.js:

pkg update -y
pkg install nodejs -y

❗️ Allow Storage permission for Termux on app settings. Create new folder on internal storage :

cd /sdcard
mkdir my_scripts
cd my_scripts

Install mineflayer:

npm install mineflayer

Now you can copy / store all of your scripts into my_scripts folder inside Internal Storage.

Start your bot

To start the bot, run Node with the name of your script.

node script_name.js

❗️ For each time opening Termux you must change the cwd into /sdcard/my_scripts, before starting the bot:

cd /sdcard/my_scripts