mineflayer 4.27.0 → 4.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -205,6 +205,7 @@ higher level API on top of Mineflayer.
205
205
 
206
206
  The most updated and useful are :
207
207
 
208
+ * [minecraft-mcp-server](https://github.com/yuniko-software/minecraft-mcp-server) A MCP server for mineflayer, allowing using mineflayer from an LLM
208
209
  * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - advanced A* pathfinding with a lot of configurable features
209
210
  * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - simple web chunk viewer
210
211
  * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web based inventory viewer
package/docs/README.md CHANGED
@@ -205,6 +205,7 @@ higher level API on top of Mineflayer.
205
205
 
206
206
  The most updated and useful are :
207
207
 
208
+ * [minecraft-mcp-server](https://github.com/yuniko-software/minecraft-mcp-server) A MCP server for mineflayer, allowing using mineflayer from an LLM
208
209
  * [pathfinder](https://github.com/Karang/mineflayer-pathfinder) - advanced A* pathfinding with a lot of configurable features
209
210
  * [prismarine-viewer](https://github.com/PrismarineJS/prismarine-viewer) - simple web chunk viewer
210
211
  * [web-inventory](https://github.com/ImHarvol/mineflayer-web-inventory) - web based inventory viewer
package/docs/api.md CHANGED
@@ -170,6 +170,8 @@
170
170
  - ["game"](#game)
171
171
  - ["resourcePack" (url, hash)](#resourcepack-url-hash)
172
172
  - ["title" (title, type)](#title-title-type)
173
+ - ["title_times" (fadeIn, stay, fadeOut)](#title_times-fadein-stay-fadeout)
174
+ - ["title_clear"](#title_clear)
173
175
  - ["rain"](#rain)
174
176
  - ["weatherUpdate"](#weatherupdate)
175
177
  - ["time"](#time)
@@ -1089,7 +1091,7 @@ Day of the world.
1089
1091
 
1090
1092
  Whether it is day or not.
1091
1093
 
1092
- Based on whether the current time of day is between 13000 and 23000 ticks.
1094
+ Based on whether the current time of day is between 0 and 13000 ticks (day + sunset).
1093
1095
 
1094
1096
  #### bot.time.moonPhase
1095
1097
 
@@ -1241,8 +1243,28 @@ Emitted when the server sends a resource pack.
1241
1243
 
1242
1244
  Emitted when the server sends a title
1243
1245
 
1244
- * `title` - title's text
1245
- * `type` - title's type "subtitle" or "title"
1246
+ * `title` - title's text
1247
+ * `type` - title's type "subtitle", "title"
1248
+
1249
+ #### "title_times" (fadeIn, stay, fadeOut)
1250
+
1251
+ Emitted 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).
1252
+
1253
+ * `fadeIn` - fade-in time in ticks (number)
1254
+ * `stay` - stay time in ticks (number)
1255
+ * `fadeOut` - fade-out time in ticks (number)
1256
+
1257
+ Example:
1258
+
1259
+ ```js
1260
+ bot.on('title_times', (fadeIn, stay, fadeOut) => {
1261
+ console.log(`Title times: fadeIn=${fadeIn}, stay=${stay}, fadeOut=${fadeOut}`)
1262
+ })
1263
+ ```
1264
+
1265
+ #### "title_clear"
1266
+
1267
+ Emitted when the server clears all titles.
1246
1268
 
1247
1269
  #### "rain"
1248
1270
 
package/docs/br/api_br.md CHANGED
@@ -941,7 +941,7 @@ Dia do mundo.
941
941
 
942
942
  Se é dia ou não.
943
943
 
944
- Baseado no horário atual estar entre 13.000 e 23.000 ticks.
944
+ Baseado no horário atual estar entre 0 e 13000 ticks (dia + pôr do sol).
945
945
 
946
946
  #### bot.time.moonPhase
947
947
 
package/docs/es/api_es.md CHANGED
@@ -943,9 +943,9 @@ Día del mundo
943
943
 
944
944
  #### bot.time.isDay
945
945
 
946
- Si es de día o no
946
+ Si es de día o no.
947
947
 
948
- Basado en si la hora actual está entre los 13000 y 23000 ticks.
948
+ Basado en si la hora actual está entre 0 y 13000 ticks (día + atardecer).
949
949
 
950
950
  #### bot.time.moonPhase
951
951
 
package/docs/history.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 4.28.0
2
+ * [Add a test for title and improve the title functionality in mineflayer (#3653)](https://github.com/PrismarineJS/mineflayer/commit/4593da148afd84d9a298074123c5e022f1f8d3e4) (thanks @rom1504)
3
+ * [Add experience test (#3652)](https://github.com/PrismarineJS/mineflayer/commit/32d9d8434465bcea6705d5d6b073a8497adb7c34) (thanks @rom1504)
4
+ * [Add new external test for time. (#3650)](https://github.com/PrismarineJS/mineflayer/commit/52938fe604096887872a831a7ed0c8feca7ee272) (thanks @rom1504)
5
+ * [Add minecraft-mcp-server: mineflayer mcp server to readme](https://github.com/PrismarineJS/mineflayer/commit/cab65b115f0f8737b6756e811995ea095e776858) (thanks @rom1504)
6
+ * [Add Entity Attacker Detection into EntityHurt emitter (#3631)](https://github.com/PrismarineJS/mineflayer/commit/5688f18df4a7a5e47e6a3435902be1c7226e0b0a) (thanks @1tsMeMario)
7
+ * [Added if(vehicle) check (#3619)](https://github.com/PrismarineJS/mineflayer/commit/52c622a4f006e3631f20e6cded236e4424c38d36) (thanks @SinanAkkoyun)
8
+
1
9
  ## 4.27.0
2
10
  * [Entity Passengers get pushed wrongly (#3601)](https://github.com/PrismarineJS/mineflayer/commit/deb03b52d1e015ece9df1f14536f168f64895c81) (thanks @SinanAkkoyun)
3
11
  * [Update bot.clickWindow documentation (#3574)](https://github.com/PrismarineJS/mineflayer/commit/188db17bbb95461743aec2823695c360685559b0) (thanks @kaduvert)
@@ -0,0 +1,245 @@
1
+ # Contributing to Mineflayer Tests as an LLM
2
+
3
+ This 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.
4
+
5
+ ## Test Structure
6
+
7
+ ### Location
8
+ - Tests are located in `test/externalTests/`
9
+ - Each test file corresponds to a specific functionality
10
+ - Test files follow the naming convention of the feature they test (e.g., `time.js` for time-related tests)
11
+
12
+ ### Basic Test Template
13
+ ```javascript
14
+ const assert = require('assert')
15
+ const { once } = require('../../lib/promise_utils')
16
+
17
+ module.exports = () => async (bot) => {
18
+ // Test implementation
19
+ }
20
+ ```
21
+
22
+ ## Writing Tests
23
+
24
+ ### 1. Property Testing
25
+ - Define expected properties and their types
26
+ - Use `assert.strictEqual` for type checking
27
+ - Verify value ranges where applicable
28
+
29
+ Example:
30
+ ```javascript
31
+ const timeProps = {
32
+ doDaylightCycle: 'boolean',
33
+ bigTime: 'bigint',
34
+ time: 'number'
35
+ }
36
+
37
+ Object.entries(timeProps).forEach(([prop, type]) => {
38
+ assert.strictEqual(typeof bot.time[prop], type)
39
+ })
40
+ ```
41
+
42
+ ### 2. Helper Functions
43
+ - Create reusable helper functions for common operations
44
+ - Include functions for waiting and state verification
45
+ - Use descriptive names that explain their purpose
46
+
47
+ Example:
48
+ ```javascript
49
+ const waitForTime = async () => {
50
+ await once(bot, 'time')
51
+ await bot.test.wait(200)
52
+ }
53
+ ```
54
+
55
+ ### 3. Test Cases
56
+ - Organize test cases in arrays for better maintainability
57
+ - Include descriptive names and expected outcomes
58
+ - Group related tests together
59
+
60
+ Example:
61
+ ```javascript
62
+ const timeTests = [
63
+ { time: 18000, name: 'midnight', isDay: false },
64
+ { time: 6000, name: 'noon', isDay: true }
65
+ ]
66
+ ```
67
+
68
+ ## Running Tests
69
+
70
+ ### Basic Test Execution
71
+ ```bash
72
+ npm run mocha_test -- -g "mineflayer_external 1.20.4v.*time"
73
+ ```
74
+
75
+ ### Version-Specific Testing
76
+ - Test against multiple Minecraft versions
77
+ - Common versions to test: 1.14.4, 1.20.4, 1.21.3
78
+ - Example:
79
+ ```bash
80
+ # Test for 1.14.4
81
+ npm run mocha_test -- -g "mineflayer_external 1.14.4v.*time"
82
+
83
+ # Test for 1.21.3
84
+ npm run mocha_test -- -g "mineflayer_external 1.21.3v.*time"
85
+ ```
86
+
87
+ ## Debugging Tests
88
+
89
+ ### 1. Adding Debug Logs
90
+ - Use `console.log` for debugging (remove before final commit)
91
+ - Log important state changes and values
92
+ - Example:
93
+ ```javascript
94
+ console.log('Time properties:', bot.time)
95
+ ```
96
+
97
+ ### 2. Common Issues
98
+ - Timing issues: Adjust wait times if needed (default 200ms)
99
+ - Version compatibility: Check packet formats across versions
100
+ - State synchronization: Ensure proper event handling
101
+
102
+ ### 3. Test Output
103
+ - Watch for server startup messages
104
+ - Monitor bot commands and responses
105
+ - Check for any error messages or warnings
106
+
107
+ ## Best Practices
108
+
109
+ 1. **Test Organization**
110
+ - Group related tests together
111
+ - Use descriptive test names
112
+ - Keep tests focused and atomic
113
+
114
+ 2. **Error Handling**
115
+ - Include clear error messages
116
+ - Test edge cases
117
+ - Verify state after each operation
118
+
119
+ 3. **Performance**
120
+ - Minimize wait times
121
+ - Clean up resources
122
+ - Avoid redundant tests
123
+
124
+ 4. **Documentation**
125
+ - Comment complex logic
126
+ - Explain test purposes
127
+ - Document version-specific behavior
128
+
129
+ ## Common Commands
130
+
131
+ ### Server Commands
132
+ ```javascript
133
+ bot.test.sayEverywhere('/time set 0') // Set time
134
+ bot.test.sayEverywhere('/gamerule doDaylightCycle false') // Toggle game rules
135
+ ```
136
+
137
+ ### Bot Operations
138
+ ```javascript
139
+ async function f () {
140
+ await bot.test.wait(200) // Wait for specified milliseconds
141
+ await once(bot, 'time') // Wait for specific event
142
+ }
143
+ ```
144
+
145
+ ## Version Compatibility
146
+
147
+ - Test against multiple Minecraft versions
148
+ - Handle version-specific packet formats
149
+ - Consider backward compatibility
150
+ - Document version-specific behavior
151
+
152
+ ## Adding a New Test
153
+
154
+ When adding a new test, follow these steps:
155
+
156
+ 1. **Create a new test file** in the `test/externalTests` directory. For example, `experience.js`.
157
+ 2. **Write the test logic** using async/await. Avoid using the `done` callback if possible.
158
+ 3. **Handle version differences** if necessary. For example, the experience command syntax differs between Minecraft versions:
159
+ - For versions older than 1.13, use `/xp <amount> [player]`.
160
+ - For versions 1.13 and newer, use `/xp add <player> <amount> points` or `/xp add <player> <amount> levels`.
161
+ 4. **Add event listeners** for debugging if needed, and ensure they are removed at the end of the test to prevent memory leaks.
162
+ 5. **Use `bot.chat`** to issue commands directly instead of `bot.test.runCommand`.
163
+ 6. **Run the test** for different Minecraft versions to ensure compatibility.
164
+
165
+ Example test structure:
166
+ ```javascript
167
+ const assert = require('assert')
168
+ const { once } = require('../../lib/promise_utils')
169
+
170
+ module.exports = () => async (bot) => {
171
+ // Test logic here
172
+ // Example: Check bot's experience state
173
+ console.log('[experience test] Bot username:', bot.username)
174
+ await bot.test.becomeSurvival()
175
+ // ... more test logic ...
176
+ // Remove event listeners at the end
177
+ bot.removeListener('experience', expListener)
178
+ console.log('[experience test] All checks passed!')
179
+ }
180
+ ```
181
+
182
+ ## Specific Details from Recent Experience
183
+
184
+ - **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.
185
+ - **Event Listener Cleanup**: Always remove event listeners at the end of the test to prevent memory leaks. Use `bot.removeListener('eventName', listenerFunction)`.
186
+ - **Use `bot.chat`**: For issuing commands, use `bot.chat` directly instead of `bot.test.runCommand` to ensure commands are sent correctly.
187
+ - **Debugging**: Use `console.log` for debugging, but remove these statements before finalizing the test.
188
+
189
+ ## Title Plugin Implementation Details
190
+
191
+ ### Version-Specific Title Handling
192
+ - Title packets changed significantly between versions:
193
+ - 1.8.8 uses a single `title` packet with an action field
194
+ - 1.14.4+ uses separate packets for different title operations
195
+ - Use `bot.supportFeature('titleUsesLegacyPackets')` to detect version
196
+ - Handle both JSON and plain text title formats
197
+
198
+ ### Title Testing Strategy
199
+ ```javascript
200
+ async function f () {
201
+ // Example of testing title functionality
202
+ const titleTests = [
203
+ { type: 'title', text: 'Main Title' },
204
+ { type: 'subtitle', text: 'Subtitle Text' },
205
+ { type: 'clear' }
206
+ ]
207
+ for (const test of titleTests) {
208
+ if (test.type === 'clear') {
209
+ bot.test.sayEverywhere('/title @a clear')
210
+ } else {
211
+ bot.test.sayEverywhere(`/title @a ${test.type} {"text":"${test.text}"}`)
212
+ }
213
+ await once(bot, 'title')
214
+ // Verify title state
215
+ }
216
+ }
217
+ ```
218
+
219
+ ### Title-Specific Best Practices
220
+ 1. **Event Handling**
221
+ - Listen for both legacy and modern title events
222
+ - Handle title clear events separately
223
+ - Parse JSON title text properly
224
+
225
+ 2. **Version Compatibility**
226
+ - Test title display, subtitle, and clear operations
227
+ - Verify title timing settings work
228
+ - Check title text parsing across versions
229
+
230
+ 3. **Error Prevention**
231
+ - Handle malformed JSON in title text
232
+ - Provide fallbacks for unsupported operations
233
+ - Log title-related errors for debugging
234
+
235
+ ## Conclusion
236
+
237
+ When adding or modifying tests:
238
+ 1. Understand the feature being tested
239
+ 2. Write clear, focused tests
240
+ 3. Test across multiple versions
241
+ 4. Include proper error handling
242
+ 5. Clean up debug code before committing
243
+ 6. Document any version-specific behavior
244
+
245
+ Remember to remove any debugging `console.log` statements before finalizing the changes.
package/docs/ru/api_ru.md CHANGED
@@ -1121,7 +1121,7 @@ UUID существа, который определяется боссом.
1121
1121
 
1122
1122
  Определяет, сейчас день (`true`) или ночь (`false`).
1123
1123
 
1124
- Основано на времени между `13000` и `23000` тиками.
1124
+ Основано на времени между `0` и `13000` тиками (день + закат).
1125
1125
 
1126
1126
  #### bot.time.moonPhase
1127
1127
 
@@ -1,5 +1,6 @@
1
1
  /*
2
2
  * An example of how to handle title events from the server.
3
+ * Demonstrates title, subtitle, timing, and clearing functionality.
3
4
  */
4
5
  const mineflayer = require('mineflayer')
5
6
 
@@ -15,8 +16,26 @@ const bot = mineflayer.createBot({
15
16
  password: process.argv[5]
16
17
  })
17
18
 
18
- // This event is triggered when the server sends a title to the client.
19
+ // This event is triggered when the server sends a title or subtitle
19
20
  bot.on('title', (text, type) => {
20
21
  // type is either "title" or "subtitle"
21
22
  console.log(`Received ${type}: ${text}`)
22
23
  })
24
+
25
+ // This event is triggered when the server sets title display times
26
+ bot.on('title_times', (fadeIn, stay, fadeOut) => {
27
+ console.log(`Title timing: fadeIn=${fadeIn}ms, stay=${stay}ms, fadeOut=${fadeOut}ms`)
28
+ })
29
+
30
+ // This event is triggered when the server clears all titles
31
+ bot.on('title_clear', () => {
32
+ console.log('All titles cleared')
33
+ })
34
+
35
+ bot.on('spawn', () => {
36
+ console.log('Bot spawned! Try these commands:')
37
+ console.log('/title @a title {"text":"Hello World"}')
38
+ console.log('/title @a subtitle {"text":"Welcome!"}')
39
+ console.log('/title @a times 10 20 30')
40
+ console.log('/title @a clear')
41
+ })
package/index.d.ts CHANGED
@@ -81,7 +81,7 @@ export interface BotEvents {
81
81
  health: () => Promise<void> | void
82
82
  breath: () => Promise<void> | void
83
83
  entitySwingArm: (entity: Entity) => Promise<void> | void
84
- entityHurt: (entity: Entity) => Promise<void> | void
84
+ entityHurt: (entity: Entity, source: Entity) => Promise<void> | void
85
85
  entityDead: (entity: Entity) => Promise<void> | void
86
86
  entityTaming: (entity: Entity) => Promise<void> | void
87
87
  entityTamed: (entity: Entity) => Promise<void> | void
@@ -374,7 +374,8 @@ function inject (bot) {
374
374
 
375
375
  bot._client.on('damage_event', (packet) => { // 1.20+
376
376
  const entity = bot.entities[packet.entityId]
377
- bot.emit('entityHurt', entity)
377
+ 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
378
+ bot.emit('entityHurt', entity, source)
378
379
  })
379
380
 
380
381
  bot._client.on('attach_entity', (packet) => {
@@ -813,7 +814,9 @@ function inject (bot) {
813
814
  originalVehicle.passengers.splice(index, 1)
814
815
  }
815
816
  passenger.vehicle = vehicle
816
- vehicle.passengers.push(passenger)
817
+ if (vehicle) {
818
+ vehicle.passengers.push(passenger)
819
+ }
817
820
 
818
821
  if (packet.entityId === bot.entity.id) {
819
822
  const vehicle = bot.vehicle
@@ -13,23 +13,21 @@ function inject (bot) {
13
13
  age: null
14
14
  }
15
15
  bot._client.on('update_time', (packet) => {
16
- let time = longToBigInt(packet.time)
16
+ const time = longToBigInt(packet.time)
17
+ const age = longToBigInt(packet.age)
18
+ const doDaylightCycle = packet.tickDayTime !== undefined ? !!packet.tickDayTime : time >= 0n
19
+ // When doDaylightCycle is false, we need to take the absolute value of time
20
+ const finalTime = doDaylightCycle ? time : (time < 0n ? -time : time)
17
21
 
18
- if (time < 0) {
19
- bot.time.doDaylightCycle = false
20
- time *= -1n
21
- } else {
22
- bot.time.doDaylightCycle = true
23
- }
24
-
25
- bot.time.bigTime = time
26
- bot.time.time = Number(time)
22
+ bot.time.doDaylightCycle = doDaylightCycle
23
+ bot.time.bigTime = finalTime
24
+ bot.time.time = Number(finalTime)
27
25
  bot.time.timeOfDay = bot.time.time % 24000
28
26
  bot.time.day = Math.floor(bot.time.time / 24000)
29
- bot.time.isDay = bot.time.timeOfDay < 13000 || bot.time.timeOfDay >= 23000
27
+ bot.time.isDay = bot.time.timeOfDay >= 0 && bot.time.timeOfDay < 13000
30
28
  bot.time.moonPhase = bot.time.day % 8
31
- bot.time.bigAge = longToBigInt(packet.age)
32
- bot.time.age = Number(bot.time.bigAge)
29
+ bot.time.bigAge = age
30
+ bot.time.age = Number(age)
33
31
 
34
32
  bot.emit('time')
35
33
  })
@@ -1,14 +1,37 @@
1
1
  module.exports = inject
2
2
  function inject (bot) {
3
- bot._client.on('title', (packet) => {
4
- if (packet.action === 0 || packet.action === 1) {
5
- bot.emit('title', packet.text, 'title')
3
+ function parseTitle (text) {
4
+ try {
5
+ const parsed = JSON.parse(text)
6
+ return typeof parsed === 'string' ? parsed : (parsed.text || text)
7
+ } catch {
8
+ return typeof text === 'string' ? text.replace(/^"|"$/g, '') : text
6
9
  }
7
- })
8
- bot._client.on('set_title_text', packet => {
9
- bot.emit('title', packet.text, 'title')
10
- })
11
- bot._client.on('set_title_subtitle', packet => {
12
- bot.emit('title', packet.text, 'subtitle')
13
- })
10
+ }
11
+
12
+ if (bot.supportFeature('titleUsesLegacyPackets')) {
13
+ bot._client.on('title', (packet) => {
14
+ if (packet.action === 0) bot.emit('title', parseTitle(packet.text), 'title')
15
+ else if (packet.action === 1) bot.emit('title', parseTitle(packet.text), 'subtitle')
16
+ else if (packet.action === 2) bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)
17
+ else if (packet.action === 3) {
18
+ if (packet.fadeIn !== undefined) bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)
19
+ else bot.emit('title_clear')
20
+ } else if (packet.action === 4) bot.emit('title_clear')
21
+ })
22
+ } else if (bot.supportFeature('titleUsesNewPackets')) {
23
+ function getText (packet) {
24
+ let text = packet.text
25
+ if (typeof text === 'object' && text.value !== undefined) text = text.value
26
+ return parseTitle(text)
27
+ }
28
+ bot._client.on('set_title_text', (packet) => bot.emit('title', getText(packet), 'title'))
29
+ bot._client.on('set_title_subtitle', (packet) => bot.emit('title', getText(packet), 'subtitle'))
30
+ bot._client.on('set_title_time', (packet) => {
31
+ if (typeof packet.fadeIn === 'number' && typeof packet.stay === 'number' && typeof packet.fadeOut === 'number') {
32
+ bot.emit('title_times', packet.fadeIn, packet.stay, packet.fadeOut)
33
+ }
34
+ })
35
+ bot._client.on('clear_titles', () => bot.emit('title_clear'))
36
+ }
14
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mineflayer",
3
- "version": "4.27.0",
3
+ "version": "4.28.0",
4
4
  "description": "create minecraft bots with a stable, high level API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",