# 使用教程 **目录** - [基础](#基础) - [Javascript 基础](#Javascript 基础知识) - [Installing Node](#installing-node) - [Javascript variables](#javascript-variables) - [Show output](#show-output) - [Javascript functions](#javascript-functions) - [Javascript 数据类型](#Javascript 数据类型) - [If-statements](#if-statements) - [Loops](#loops) - [Node 包管理器](#Node 包管理器) - [Creating a bot](#creating-a-bot) - [Javascript objects](#javascript-objects) - [Logging in](#logging-in) - [Passing along functions](#passing-along-functions) - [Listening for an event](#listening-for-an-event) - [Callbacks](#callbacks) - [Correct and incorrect approach](#correct-and-incorrect-approach) - [高级](#高级) - [Asynchronousy](#asynchronousy) - [Loop over an object](#loop-over-an-object) - [Creating an event from chat](#creating-an-event-from-chat) - [Answer Hello Bot](#answer-hello-bot) - [Custom Chat](#custom-chat) - [FAQ](#faq) - [How to run a bot on android](#how-to-run-a-bot-on-android) - [Install Termux](#install-termux) - [Setup](#setup) - [Start your bot](#start-your-bot) ## 介绍 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](#creating-a-bot) section, otherwise start here. ## 基础 以下几节是关于开始使用Mineflayer需要知道的基本概念。 ### Javascript 基础知识 #### 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](https://nodejs.org/en/download/). 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](https://en.wikipedia.org/wiki/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](https://code.visualstudio.com/)(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 首先输入以下内容: ```js 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. ```js 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. #### 显示输出 A lot of times you want to see the current value of a variable, to make sure your program is running correctly. 您可以通过将变量打印到终端来实现这一点. 在Javascript中,我们可以使用 `console.log()` 函数 ```js const test = 5 console.log(test) ``` 现在,当您保存并运行此代码时,您最终应该会看到: ```txt 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. ```js 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: ```txt 15 1 ``` #### Javascript 数据类型 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 `''` ```js 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 `[]` ```js 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 `{}` ```js const object = {} // object type ``` - Functions are also their own type. ```js const adder = (a, b) => { return a + b } // function type ``` - A boolean is a type that can only be `true` or `false` ```js const boolean = true // boolean type ``` - When something is not (yet) defined, its type is `undefined` ```js 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. ```js const name = 'Bob' if (name === 'Bob') { console.log('你的名字是 Bob') } else if (name === 'Alice') { console.log('你的名字是 Alice') } else { console.log('你的名字不是Bob或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. ```js let countDown = 5 while (countDown > 0) { console.log(countDown) countDown = countDown - 1 // 从1递减 } console.log('已完成!') ``` 上述代码将打印以下内容 ```txt 5 4 3 2 1 已完成! ``` 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. ```js 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. ```js 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 包管理器 The last thing you need to know is how to use the [Node Package Manager](https://www.npmjs.com/). 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](https://www.npmjs.com/), 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. ```js const mineflayer = require('mineflayer') ``` After this, the `mineflayer` variable can be used to access all the features of Mineflayer. ### 创建机器人 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](#javascript-basics) 下面是创建Mineflayer机器人所需的绝对最少代码 ```js 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. ```js const mineflayer = require('mineflayer') const options = { host: 'localhost', // 将此项更改为所需的ip port: 25565 // 将此项更改为所需的端口 } 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. ```js const object = { number: 10, another: 5 } console.log(object.number) // 这将打印值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. ```js const bot = mineflayer.createBot({ host: 'localhost', port: 25565 }) ``` #### 登录 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` ```js 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. ```js 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. ```js const welcome = () => { bot.chat('你好!') } 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. ```js bot.once('spawn', () => { bot.chat('你好!') }) ``` ### Listening for an event The bot object has many useful [events](http://prismarinejs.github.io/mineflayer/#/api?id=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`](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! ### Callbacks A [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. In Mineflayer, callbacks are often used to handle errors. ```js bot.consume((error) => { if (error) { // 这将检查是否发生错误 console.log(error) } else { console.log('Finished consuming') } }) ``` 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 ❌: ```js const plankRecipe = bot.recipesFor(5)[0] // Get the first recipe for item id 5, which is oak planks. bot.craft(plankRecipe, 1) // ❌ start crafting oak planks. const stickRecipe = bot.recipesFor(280)[0] // Get the first recipe for item id 5, which is sticks. bot.craft(stickRecipe, 1) // ❌ start crafting sticks. ``` 回调的正确方法 ✔️: ```js const plankRecipe = bot.recipesFor(5)[0] bot.craft(plankRecipe, 1, null, (error) => { // After bot.craft(plankRecipe, ...) is finished, this callback is called and we continue. ✔️ if (error) { // 检查是否发生了错误 console.log(error) } else { const stickRecipe = bot.recipesFor(280)[0] bot.craft(stickRecipe, 1, null, (error) => { // After bot.craft(stickRecipe, ...) is finished, this callback is called and we continue. ✔️ if (error) { // Check if an error happened. console.log(error) } else { 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 callbacks can fix this because they will only be called after the `bot.craft()` is finished. More on the [bot.craft()](https://prismarinejs.github.io/mineflayer/#/api?id=botcraftrecipe-count-craftingtable-callback) method. ## 高级 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](#basics) tutorial. ### Asynchronousy In Javascript, asynchronousy is an important concept. By 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. However, 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. Interacting with the filesystem is often done using asynchronousy, because reading and writing large files can take a long time. ```js const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Success!') // 耶!一切都很顺利! }, 1000) }) myPromise.then((successMessage) => { console.log(successMessage) }) myPromise.catch((error) => { console.log(error) }) ``` The above codes uses what is called a Promise. A promise promises it will eventually complete. The function given you a promise always has 2 parameters, a `resolve` function and a `reject` function. If the promise is successful, it will call the `resolve` function, otherwise it will call the `reject` function. The above code uses a `setTimeout`, which calls the given function after the set amount of milliseconds, 1000 in this case. You can then tell the promise what it should do when it succeeds with `.then(function)` or when it fails with `.catch(function)` The `.then` and `.catch` function can also be chained together with the promise to simplify the code. ```js const myPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Success!') // Yay! Everything went well! }, 1000) }).then((successMessage) => { console.log(successMessage) }).catch((error) => { console.log(error) }) ``` ### Loop over an object The `for of` loop described in the [loops](#loops) chapter can also be used to loop over an object. If we have the following object: ```js const obj = { a: 1, b: 2, c: 3 } ``` The following will loop over all the values of the object. ```js for (const value of Object.values(obj)) { console.log(value) } ``` ```txt 1 2 3 ``` This will loop over all the keys of the object. ```js for (const key of Object.keys(obj)) { console.log(key) } ``` ```txt 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.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) ```js for (const [key, value] of Object.entries(obj)) { console.log(key + ', ' + value) } ``` ```txt 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.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) In general, you'll want to use `for of` instead of `for in` so make sure you don't confuse the two. ### 从聊天中创建事件 You 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. [`bot.chatAddPattern()`](http://prismarinejs.github.io/mineflayer/#/api?id=botchataddpatternpattern-chattype-description) 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](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. 阅读有关[正则表达式](https://en.wikipedia.org/wiki/Regular_expression)的更多信息 例子 : #### 回答你好 机器人 在这里,我们创建一个机器人,从另一个玩家那里回答“你好”。 ```js bot.chatAddPattern( /(helo|hello|Hello)/, 'hello', 'Someone says hello' ) const hi = () => { bot.chat('Hi!') } bot.on('hello', hi) ``` #### 自定义聊天 基于自定义聊天格式创建事件 自定义聊天示例: ```txt [Player] 路人甲 > 你好 [Admin] 李四 > Hi [Player] 法外狂徒张三 > 焯!我卡住了 [Mod] Jim > 我马上到 ``` ```js bot.chatAddPattern( /^\[(.+)\] (\S+) > (.+)$/, 'my_chat_event', 'Custom chat event' ) const logger = (rank, username, message) => { console.log(`${username} 说 ${message}`) } bot.on('my_chat_event', logger) ``` 关于 `^\[(.+)\] (\S+) > (.+)$` 正则表达式的解释可在[此处](https://regex101.com/r/VDUrDC/2)找到 ## FAQ ### 如何在Android上运行机器人 下面是在Android设备上用 [Termux](https://termux.com/)运行bot的快速设置教程 #### 安装Termux 安装[Termux](https://termux.com/) 并启动 #### Setup 安装 `Node.js`: ```bash pkg update -y pkg install nodejs -y ``` ❗️ 允许应用程序设置上Termux的存储权限. 在内部存储上创建新文件夹: ```bash cd /sdcard mkdir my_scripts cd my_scripts ``` 安装 `mineflayer`: ```bash npm install mineflayer ``` 现在,您可以将所有脚本复制/存储到内部存储器中的`my_scripts`文件夹中。 #### 启动你的机器人 要启动机器人,请使用Node运行脚本名称 ```bash node script_name.js ``` ❗️ 每次打开 Termux 时,您都必须在启动机器人之前将 cwd 更改为 `/sdcard/my_scripts`: ```bash cd /sdcard/my_scripts ```