Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqtoday authored May 22, 2024
2 parents 56a019c + ec76468 commit c5bb6d1
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 28 deletions.
7 changes: 7 additions & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 4.20.1
* [Add bossBarCreated event in index.d.ts (#3340)](https://github.com/PrismarineJS/mineflayer/commit/8299288526cd7ff24bcd87511814221f8ad62507) (thanks @gguio)
* [Update scoreboard.js (#3318)](https://github.com/PrismarineJS/mineflayer/commit/195b3cbd70a110080af9b77a4659991c5d9e484a) (thanks @vicdum)
* [Fix hardcoded diggingface for cancel digging (#3322)](https://github.com/PrismarineJS/mineflayer/commit/ab78bf855929a476386b5eb6efcf3b271d02455e) (thanks @Vinciepincie)
* [Fix 1.20.4 server resource pack error (#3320)](https://github.com/PrismarineJS/mineflayer/commit/7c01eeb970647ed2933c10cb2b94fd7b44c777f5) (thanks @TerminalCalamitas)
* [Fix scoreboard delete handler not first checking if scoreboard exists (#3324)](https://github.com/PrismarineJS/mineflayer/commit/d9e9e15aeb646d81da2a3e2987566de47e3bae04) (thanks @Ynfuien)

## 4.20.0
* [Update api.md - addChatPattern[Set] link to example of usage (#3304)](https://github.com/PrismarineJS/mineflayer/commit/bb3e5877b7b3b8ab063b39a5b47d103b819da1c2) (thanks @boly38)
* [Fixed deleted scoreboards not being removed from ScoreBoard.positions (#3306)](https://github.com/PrismarineJS/mineflayer/commit/643023df91bf428d3e7d30e8f2eab97e3238b0b2) (thanks @Ynfuien)
Expand Down
13 changes: 11 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ export interface BotEvents {
teamUpdated: (team: Team) => Promise<void> | void
teamMemberAdded: (team: Team) => Promise<void> | void
teamMemberRemoved: (team: Team) => Promise<void> | void
bossBarCreated: (bossBar: BossBar) => Promise<void> | void
bossBarDeleted: (bossBar: BossBar) => Promise<void> | void
bossBarUpdated: (bossBar: BossBar) => Promise<void> | void
resourcePack: (url: string, hash: string) => Promise<void> | void
resourcePack: (url: string, hash?: string, uuid?: string) => Promise<void> | void
particle: (particle: Particle) => Promise<void> | void
}

Expand Down Expand Up @@ -380,7 +381,14 @@ export interface Bot extends TypedEmitter<BotEvents> {
times?: number
) => Promise<void>

setCommandBlock: (pos: Vec3, command: string, trackOutput: boolean) => void

export interface CommandBlockOptions {
mode: number,
trackOutput: boolean,
conditional: boolean,
alwaysActive: boolean
}
export function setCommandBlock(pos: Vec3, command: string, options: CommandBlockOptions) => void

clickWindow: (
slot: number,
Expand Down Expand Up @@ -458,6 +466,7 @@ export interface GameState {
dimension: Dimension
difficulty: Difficulty
maxPlayers: number
serverBrand: string
}

export type LevelType =
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,9 +455,10 @@ function inject (bot, { version, storageBuilder, hideErrors }) {
bot.emit('error', new Error('too many lines for sign text'))
return
}

for (let i = 0; i < lines.length; ++i) {
if (lines[i].length > 15) {
bot.emit('error', new Error('signs have max line length 15'))
if (lines[i].length > 45) {
bot.emit('error', new Error('Signs have a maximum of 45 characters per line'))
return
}
}
Expand Down
45 changes: 30 additions & 15 deletions lib/plugins/digging.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@ function inject (bot) {
let diggingTask = createDoneTask()

bot.targetDigBlock = null
bot.targetDigFace = null
bot.lastDigTime = null

async function dig (block, forceLook, digFace) {
if (block === null || block === undefined) {
throw new Error('dig was called with an undefined or null block')
}

if (!digFace || typeof digFace === 'function') {
digFace = 'auto'
}

if (bot.targetDigBlock) bot.stopDigging()

let diggingFace = 1 // Default (top)
bot.targetDigFace = 1 // Default (top)

if (forceLook !== 'ignore') {
if (digFace?.x || digFace?.y || digFace?.z) {
// Determine the block face the bot should mine
if (digFace.x) {
diggingFace = digFace.x > 0 ? BlockFaces.EAST : BlockFaces.WEST
bot.targetDigFace = digFace.x > 0 ? BlockFaces.EAST : BlockFaces.WEST
} else if (digFace.y) {
diggingFace = digFace.y > 0 ? BlockFaces.TOP : BlockFaces.BOTTOM
bot.targetDigFace = digFace.y > 0 ? BlockFaces.TOP : BlockFaces.BOTTOM
} else if (digFace.z) {
diggingFace = digFace.z > 0 ? BlockFaces.SOUTH : BlockFaces.NORTH
bot.targetDigFace = digFace.z > 0 ? BlockFaces.SOUTH : BlockFaces.NORTH
}
await bot.lookAt(
block.position.offset(0.5, 0.5, 0.5).offset(digFace.x * 0.5, digFace.y * 0.5, digFace.z * 0.5),
Expand Down Expand Up @@ -76,8 +76,8 @@ function inject (bot) {
const rayPos = rayBlock.position
if (
rayPos.x === block.position.x &&
rayPos.y === block.position.y &&
rayPos.z === block.position.z
rayPos.y === block.position.y &&
rayPos.z === block.position.z
) {
validFaces.push({
face: rayBlock.face,
Expand All @@ -86,6 +86,7 @@ function inject (bot) {
}
}
}

if (validFaces.length > 0) {
// Chose closest valid face
let closest
Expand All @@ -101,11 +102,11 @@ function inject (bot) {
}
}
await bot.lookAt(closest.targetPos, forceLook)
diggingFace = closest.face
bot.targetDigFace = closest.face
} else if (closerBlocks.length === 0 && block.shapes.length === 0) {
// no other blocks were detected and the block has no shapes.
// The block in question is replaceable (like tall grass) so we can just dig it
// TODO: do AABB + ray intercept check to this position for diggingFace.
// TODO: do AABB + ray intercept check to this position for digFace.
await bot.lookAt(block.position.offset(0.5, 0.5, 0.5), forceLook)
} else {
// Block is obstructed return error?
Expand All @@ -116,11 +117,15 @@ function inject (bot) {
}
}

// In vanilla the client will cancel digging the current block once the other block is at the crosshair.
// Todo: don't wait until lookAt is at middle of the block, but at the edge of it.
if (bot.targetDigBlock) bot.stopDigging()

diggingTask = createTask()
bot._client.write('block_dig', {
status: 0, // start digging
location: block.position,
face: diggingFace // default face is 1 (top)
face: bot.targetDigFace // default face is 1 (top)
})
const waitTime = bot.digTime(block)
waitTimeout = setTimeout(finishDigging, waitTime)
Expand All @@ -140,19 +145,27 @@ function inject (bot) {
bot._client.write('block_dig', {
status: 2, // finish digging
location: bot.targetDigBlock.position,
face: diggingFace // hard coded to always dig from the top
face: bot.targetDigFace // always the same as the start face
})
}
bot.targetDigBlock = null
bot.targetDigFace = null
bot.lastDigTime = performance.now()
bot._updateBlockState(block.position, 0)
}

const eventName = `blockUpdate:${block.position}`
bot.on(eventName, onBlockUpdate)

const currentBlock = block
bot.stopDigging = () => {
if (!bot.targetDigBlock) return

// Replicate the odd vanilla cancellation face value.
// When the cancellation is because of a new dig request on another block it's the same as the new dig start face. In all other cases it's 0.
const stoppedBecauseOfNewDigRequest = !currentBlock.position.equals(bot.targetDigBlock.position)
const cancellationDiggingFace = !stoppedBecauseOfNewDigRequest ? bot.targetDigFace : 0

bot.removeListener(eventName, onBlockUpdate)
clearInterval(swingInterval)
clearTimeout(waitTimeout)
Expand All @@ -161,10 +174,11 @@ function inject (bot) {
bot._client.write('block_dig', {
status: 1, // cancel digging
location: bot.targetDigBlock.position,
face: 1 // hard coded to always dig from the top
face: cancellationDiggingFace
})
const block = bot.targetDigBlock
bot.targetDigBlock = null
bot.targetDigFace = null
bot.lastDigTime = performance.now()
bot.emit('diggingAborted', block)
bot.stopDigging = noop
Expand All @@ -182,6 +196,7 @@ function inject (bot) {
swingInterval = null
waitTimeout = null
bot.targetDigBlock = null
bot.targetDigFace = null
bot.lastDigTime = performance.now()
bot.emit('diggingCompleted', newBlock)
diggingTask.finish()
Expand All @@ -199,8 +214,8 @@ function inject (bot) {
function canDigBlock (block) {
return (
block &&
block.diggable &&
block.position.offset(0.5, 0.5, 0.5).distanceTo(bot.entity.position.offset(0, 1.65, 0)) <= 5.1
block.diggable &&
block.position.offset(0.5, 0.5, 0.5).distanceTo(bot.entity.position.offset(0, 1.65, 0)) <= 5.1
)
}

Expand Down
7 changes: 1 addition & 6 deletions lib/plugins/ray_trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,7 @@ module.exports = (bot) => {
}

bot.blockAtCursor = (maxDistance = 256, matcher = null) => {
const { position, height, pitch, yaw } = bot.entity

const eyePosition = position.offset(0, height, 0)
const viewDirection = getViewDirection(pitch, yaw)

return bot.world.raycast(eyePosition, viewDirection, maxDistance, matcher)
return bot.blockAtEntityCursor(bot.entity, maxDistance, matcher)
}

bot.entityAtCursor = (maxDistance = 3.5) => {
Expand Down
53 changes: 51 additions & 2 deletions lib/plugins/resource_pack.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,51 @@
const UUID = require('uuid-1345')

module.exports = inject

function inject (bot) {
let uuid
let latestHash
let latestUUID
let activeResourcePacks = {}
const TEXTURE_PACK_RESULTS = {
SUCCESSFULLY_LOADED: 0,
DECLINED: 1,
FAILED_DOWNLOAD: 2,
ACCEPTED: 3
}

bot._client.on('add_resource_pack', (data) => { // Emits the same as resource_pack_send but sends uuid rather than hash because that's how active packs are tracked
const uuid = new UUID(data.uuid)
// Adding the pack to a set by uuid
latestUUID = uuid
activeResourcePacks[uuid] = data.url

bot.emit('resourcePack', data.url, uuid)
})

bot._client.on('remove_resource_pack', (data) => { // Doesn't emit anything because it is removing rather than adding
// if uuid isn't provided remove all packs
if (data.uuid === undefined) {
activeResourcePacks = {}
} else {
// Try to remove uuid from set
try {
delete activeResourcePacks[new UUID(data.uuid)]
} catch (error) {
console.error('Tried to remove UUID but it was not in the active list.')
}
}
})

bot._client.on('resource_pack_send', (data) => {
bot.emit('resourcePack', data.url, data.hash)
latestHash = data.hash
if (bot.supportFeature('resourcePackUsesUUID')) {
uuid = new UUID(data.uuid)
bot.emit('resourcePack', uuid, data.url)
latestUUID = uuid
} else {
bot.emit('resourcePack', data.url, data.hash)
latestHash = data.hash
}
})

function acceptResourcePack () {
Expand All @@ -24,6 +58,15 @@ function inject (bot) {
result: TEXTURE_PACK_RESULTS.SUCCESSFULLY_LOADED,
hash: latestHash
})
} else if (bot.supportFeature('resourcePackUsesUUID')) {
bot._client.write('resource_pack_receive', {
uuid: latestUUID,
result: TEXTURE_PACK_RESULTS.ACCEPTED
})
bot._client.write('resource_pack_receive', {
uuid: latestUUID,
result: TEXTURE_PACK_RESULTS.SUCCESSFULLY_LOADED
})
} else {
bot._client.write('resource_pack_receive', {
result: TEXTURE_PACK_RESULTS.ACCEPTED
Expand All @@ -35,6 +78,12 @@ function inject (bot) {
}

function denyResourcePack () {
if (bot.supportFeature('resourcePackUsesUUID')) {
bot._client.write('resource_pack_receive', {
uuid: latestUUID,
result: TEXTURE_PACK_RESULTS.DECLINED
})
}
bot._client.write('resource_pack_receive', {
result: TEXTURE_PACK_RESULTS.DECLINED
})
Expand Down
1 change: 1 addition & 0 deletions lib/plugins/scoreboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function inject (bot) {
delete scoreboards[packet.name]

for (const position in ScoreBoard.positions) {
if (!ScoreBoard.positions[position]) continue
const scoreboard = ScoreBoard.positions[position]

if (scoreboard && scoreboard.name === packet.name) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mineflayer",
"version": "4.20.0",
"version": "4.20.1",
"description": "create minecraft bots with a stable, high level API",
"main": "index.js",
"types": "index.d.ts",
Expand Down

0 comments on commit c5bb6d1

Please sign in to comment.