90 lines
2.6 KiB
JavaScript
90 lines
2.6 KiB
JavaScript
|
const assert = require('assert')
|
||
|
const { Vec3 } = require('vec3')
|
||
|
const { sleep, onceWithCleanup } = require('../promise_utils')
|
||
|
const { once } = require('events')
|
||
|
|
||
|
module.exports = inject
|
||
|
|
||
|
function inject (bot) {
|
||
|
const Item = require('prismarine-item')(bot.registry)
|
||
|
|
||
|
// these features only work when you are in creative mode.
|
||
|
bot.creative = {
|
||
|
setInventorySlot,
|
||
|
flyTo,
|
||
|
startFlying,
|
||
|
stopFlying,
|
||
|
clearSlot: slotNum => setInventorySlot(slotNum, null),
|
||
|
clearInventory
|
||
|
}
|
||
|
|
||
|
const creativeSlotsUpdates = []
|
||
|
|
||
|
// WARN: This method should not be called twice on the same slot before first promise succeeds
|
||
|
async function setInventorySlot (slot, item) {
|
||
|
assert(slot >= 0 && slot <= 44)
|
||
|
|
||
|
if (Item.equal(bot.inventory.slots[slot], item, true)) return
|
||
|
if (creativeSlotsUpdates[slot]) {
|
||
|
throw new Error(`Setting slot ${slot} cancelled due to calling bot.creative.setInventorySlot(${slot}, ...) again`)
|
||
|
}
|
||
|
creativeSlotsUpdates[slot] = true
|
||
|
|
||
|
bot._client.write('set_creative_slot', {
|
||
|
slot,
|
||
|
item: Item.toNotch(item)
|
||
|
})
|
||
|
|
||
|
await onceWithCleanup(bot.inventory, `updateSlot:${slot}`, { checkCondition: (oldItem, newItem) => item === null ? newItem === null : newItem?.name === item.name && newItem?.count === item.count && newItem?.metadata === item.metadata })
|
||
|
creativeSlotsUpdates[slot] = false
|
||
|
}
|
||
|
|
||
|
async function clearInventory () {
|
||
|
return Promise.all(bot.inventory.slots.filter(item => item).map(item => setInventorySlot(item.slot, null)))
|
||
|
}
|
||
|
|
||
|
let normalGravity = null
|
||
|
const flyingSpeedPerUpdate = 0.5
|
||
|
|
||
|
// straight line, so make sure there's a clear path.
|
||
|
async function flyTo (destination) {
|
||
|
// TODO: consider sending 0x13
|
||
|
startFlying()
|
||
|
|
||
|
let vector = destination.minus(bot.entity.position)
|
||
|
let magnitude = vecMagnitude(vector)
|
||
|
|
||
|
while (magnitude > flyingSpeedPerUpdate) {
|
||
|
bot.physics.gravity = 0
|
||
|
bot.entity.velocity = new Vec3(0, 0, 0)
|
||
|
|
||
|
// small steps
|
||
|
const normalizedVector = vector.scaled(1 / magnitude)
|
||
|
bot.entity.position.add(normalizedVector.scaled(flyingSpeedPerUpdate))
|
||
|
|
||
|
await sleep(50)
|
||
|
|
||
|
vector = destination.minus(bot.entity.position)
|
||
|
magnitude = vecMagnitude(vector)
|
||
|
}
|
||
|
|
||
|
// last step
|
||
|
bot.entity.position = destination
|
||
|
await once(bot, 'move')
|
||
|
}
|
||
|
|
||
|
function startFlying () {
|
||
|
if (normalGravity == null) normalGravity = bot.physics.gravity
|
||
|
bot.physics.gravity = 0
|
||
|
}
|
||
|
|
||
|
function stopFlying () {
|
||
|
bot.physics.gravity = normalGravity
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// this should be in the vector library
|
||
|
function vecMagnitude (vec) {
|
||
|
return Math.sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z)
|
||
|
}
|