mineflayer 4.26.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
 
@@ -2122,7 +2144,19 @@ These are lower level methods for the inventory, they can be useful sometimes bu
2122
2144
 
2123
2145
  This function returns a `Promise`, with `void` as its argument upon completion.
2124
2146
 
2125
- The only valid mode option at the moment is 0. Shift clicking or mouse dragging is not implemented.
2147
+ mode support:
2148
+ - stable:
2149
+ - mouse clicks (0)
2150
+
2151
+ - experimental:
2152
+ - shift clicks (1)
2153
+ - number clicks (2)
2154
+ - middle clicks (3)
2155
+ - drop clicks (4)
2156
+
2157
+ - unimplemented:
2158
+ - drag clicks (5)
2159
+ - double clicks (6)
2126
2160
 
2127
2161
  Click on the current window. See details at https://wiki.vg/Protocol#Click_Container
2128
2162
 
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,16 @@
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
+
9
+ ## 4.27.0
10
+ * [Entity Passengers get pushed wrongly (#3601)](https://github.com/PrismarineJS/mineflayer/commit/deb03b52d1e015ece9df1f14536f168f64895c81) (thanks @SinanAkkoyun)
11
+ * [Update bot.clickWindow documentation (#3574)](https://github.com/PrismarineJS/mineflayer/commit/188db17bbb95461743aec2823695c360685559b0) (thanks @kaduvert)
12
+ * [Saving uuid for non-players too (#3603)](https://github.com/PrismarineJS/mineflayer/commit/9937be9b49bb3dd7cd5502c0424809fa66eb60b3) (thanks @SinanAkkoyun)
13
+
1
14
  ## 4.26.0
2
15
  * [Use node 22 (#3570)](https://github.com/PrismarineJS/mineflayer/commit/dbff9314418d30df203c32fe83f2a1b56653d0a6) (thanks @rom1504)
3
16
  * [Fix infinity setTimeout by throwing error (#3561)](https://github.com/PrismarineJS/mineflayer/commit/69539494c88c2ca718330142839a35414ecd3bda) (thanks @BBpezsgo)
@@ -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
@@ -207,6 +207,7 @@ function inject (bot) {
207
207
  const entityData = bot.registry.entities[entityType]
208
208
  setEntityData(entity, entityType, entityData)
209
209
  updateEntityPos(entity, pos)
210
+ entity.uuid = uuid
210
211
  return entity
211
212
  }
212
213
 
@@ -373,7 +374,8 @@ function inject (bot) {
373
374
 
374
375
  bot._client.on('damage_event', (packet) => { // 1.20+
375
376
  const entity = bot.entities[packet.entityId]
376
- 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)
377
379
  })
378
380
 
379
381
  bot._client.on('attach_entity', (packet) => {
@@ -807,12 +809,14 @@ function inject (bot) {
807
809
  const vehicle = packet.vehicleId === -1 ? null : fetchEntity(packet.vehicleId)
808
810
 
809
811
  const originalVehicle = passenger.vehicle
810
- if (originalVehicle !== null) {
812
+ if (originalVehicle) {
811
813
  const index = originalVehicle.passengers.indexOf(passenger)
812
- originalVehicle.passengers = originalVehicle.passengers.splice(index, 1)
814
+ originalVehicle.passengers.splice(index, 1)
813
815
  }
814
816
  passenger.vehicle = vehicle
815
- vehicle.passengers.push(passenger)
817
+ if (vehicle) {
818
+ vehicle.passengers.push(passenger)
819
+ }
816
820
 
817
821
  if (packet.entityId === bot.entity.id) {
818
822
  const vehicle = bot.vehicle
@@ -832,12 +836,12 @@ function inject (bot) {
832
836
 
833
837
  for (const passengerEntity of passengerEntities) {
834
838
  const originalVehicle = passengerEntity.vehicle
835
- if (originalVehicle !== null) {
839
+ if (originalVehicle) {
836
840
  const index = originalVehicle.passengers.indexOf(passengerEntity)
837
- originalVehicle.passengers = originalVehicle.passengers.splice(index, 1)
841
+ originalVehicle.passengers.splice(index, 1)
838
842
  }
839
843
  passengerEntity.vehicle = vehicle
840
- if (vehicle !== null) {
844
+ if (vehicle) {
841
845
  vehicle.passengers.push(passengerEntity)
842
846
  }
843
847
  }
@@ -868,7 +872,7 @@ function inject (bot) {
868
872
  if (entity.vehicle) {
869
873
  const index = entity.vehicle.passengers.indexOf(entity)
870
874
  if (index !== -1) {
871
- entity.vehicle.passengers = entity.vehicle.passengers.splice(index, 1)
875
+ entity.vehicle.passengers.splice(index, 1)
872
876
  }
873
877
  }
874
878
  })
@@ -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.26.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",