Repository navigation
Expand file tree
/
Copy pathsample-bot.js
More file actions
96 lines (82 loc) · 2.85 KB
/
Copy pathsample-bot.js
File metadata and controls
96 lines (82 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Starter bot demonstrating the core Mineflayer patterns: connecting, chat
// commands, entity lookup, and movement via the pathfinder plugin. Copy this
// as the starting point for real bots.
//
// Usage: node sample-bot.js (or: npm run bot:sample)
// Config via env vars: MC_HOST, MC_PORT, BOT_USERNAME
//
// In-game chat commands (type as any player): ping | pos | come | follow | stop | jump | quit
const mineflayer = require('mineflayer')
const { pathfinder, Movements, goals } = require('mineflayer-pathfinder')
const bot = mineflayer.createBot({
host: process.env.MC_HOST || 'localhost',
port: Number(process.env.MC_PORT || 25565),
username: process.env.BOT_USERNAME || 'SampleBot',
auth: 'offline',
// Pin explicitly: offline-mode auto-detection can misreport the version.
version: '1.21.11',
})
bot.loadPlugin(pathfinder)
bot.once('spawn', () => {
bot.pathfinder.setMovements(new Movements(bot))
console.log(`spawned as ${bot.username} at ${bot.entity.position}`)
bot.chat('SampleBot online. Commands: ping | pos | come | follow | stop | jump | quit')
})
// Returns the speaking player's entity, or null (and tells them why) if the
// bot can't see them — entities only load within the server's view distance.
function speakerEntity (username) {
const player = bot.players[username]
if (!player || !player.entity) {
bot.chat(`I can't see you, ${username} — come closer.`)
return null
}
return player.entity
}
bot.on('chat', (username, message) => {
if (username === bot.username) return
switch (message.trim().toLowerCase()) {
case 'ping':
bot.chat('pong')
break
case 'pos': {
const p = bot.entity.position
bot.chat(`I'm at ${p.x.toFixed(1)}, ${p.y.toFixed(1)}, ${p.z.toFixed(1)}`)
break
}
case 'come': {
const target = speakerEntity(username)
if (!target) break
const p = target.position
bot.chat(`On my way, ${username}.`)
bot.pathfinder.setGoal(new goals.GoalNear(p.x, p.y, p.z, 1))
break
}
case 'follow': {
const target = speakerEntity(username)
if (!target) break
bot.chat(`Following ${username}. Say "stop" to release me.`)
// Second arg true = dynamic goal: keeps chasing as the target moves.
bot.pathfinder.setGoal(new goals.GoalFollow(target, 2), true)
break
}
case 'stop':
bot.pathfinder.setGoal(null)
bot.clearControlStates()
bot.chat('Stopped.')
break
case 'jump':
bot.setControlState('jump', true)
setTimeout(() => bot.setControlState('jump', false), 500)
break
case 'quit':
bot.chat('Bye!')
bot.quit()
break
}
})
bot.on('kicked', (reason) => console.error('kicked:', JSON.stringify(reason)))
bot.on('error', (err) => console.error('error:', err.message))
bot.on('end', () => {
console.log('disconnected')
process.exit(0)
})