Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PrismarineJS
GitHub Repository: PrismarineJS/mineflayer
Path: blob/master/lib/plugins/creative.js
1467 views
1
const assert = require('assert')
2
const { Vec3 } = require('vec3')
3
const { sleep, onceWithCleanup } = require('../promise_utils')
4
const { once } = require('../promise_utils')
5
6
module.exports = inject
7
8
function inject (bot) {
9
const Item = require('prismarine-item')(bot.registry)
10
11
// these features only work when you are in creative mode.
12
bot.creative = {
13
setInventorySlot,
14
flyTo,
15
startFlying,
16
stopFlying,
17
clearSlot: slotNum => setInventorySlot(slotNum, null),
18
clearInventory
19
}
20
21
const creativeSlotsUpdates = []
22
23
// WARN: This method should not be called twice on the same slot before first promise succeeds
24
async function setInventorySlot (slot, item, waitTimeout = 400) {
25
assert(slot >= 0 && slot <= 44)
26
27
if (Item.equal(bot.inventory.slots[slot], item, true)) return
28
if (creativeSlotsUpdates[slot]) {
29
throw new Error(`Setting slot ${slot} cancelled due to calling bot.creative.setInventorySlot(${slot}, ...) again`)
30
}
31
creativeSlotsUpdates[slot] = true
32
bot._client.write('set_creative_slot', {
33
slot,
34
item: Item.toNotch(item)
35
})
36
37
if (bot.supportFeature('noAckOnCreateSetSlotPacket')) {
38
// No ack
39
bot._setSlot(slot, item)
40
if (waitTimeout === 0) return // no wait
41
// allow some time to see if server rejects
42
return new Promise((resolve, reject) => {
43
function updateSlot (oldItem, newItem) {
44
if (newItem.itemId !== item.itemId) {
45
creativeSlotsUpdates[slot] = false
46
reject(Error('Server rejected'))
47
}
48
}
49
bot.inventory.once(`updateSlot:${slot}`, updateSlot)
50
setTimeout(() => {
51
bot.inventory.off(`updateSlot:${slot}`, updateSlot)
52
creativeSlotsUpdates[slot] = false
53
resolve()
54
}, waitTimeout)
55
})
56
}
57
58
await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, {
59
timeout: 5000,
60
checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata
61
})
62
creativeSlotsUpdates[slot] = false
63
}
64
65
async function clearInventory () {
66
return Promise.all(bot.inventory.slots.filter(item => item).map(item => setInventorySlot(item.slot, null)))
67
}
68
69
let normalGravity = null
70
const flyingSpeedPerUpdate = 0.5
71
72
// straight line, so make sure there's a clear path.
73
async function flyTo (destination) {
74
// TODO: consider sending 0x13
75
startFlying()
76
77
let vector = destination.minus(bot.entity.position)
78
let magnitude = vecMagnitude(vector)
79
80
while (magnitude > flyingSpeedPerUpdate) {
81
bot.physics.gravity = 0
82
bot.entity.velocity = new Vec3(0, 0, 0)
83
84
// small steps
85
const normalizedVector = vector.scaled(1 / magnitude)
86
bot.entity.position.add(normalizedVector.scaled(flyingSpeedPerUpdate))
87
88
await sleep(50)
89
90
vector = destination.minus(bot.entity.position)
91
magnitude = vecMagnitude(vector)
92
}
93
94
// last step
95
bot.entity.position = destination
96
await once(bot, 'move', /* no timeout */ 0)
97
}
98
99
function startFlying () {
100
if (normalGravity == null) normalGravity = bot.physics.gravity
101
bot.physics.gravity = 0
102
}
103
104
function stopFlying () {
105
bot.physics.gravity = normalGravity
106
}
107
}
108
109
// this should be in the vector library
110
function vecMagnitude (vec) {
111
return Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z)
112
}
113
114