124 lines
3.9 KiB
JavaScript
124 lines
3.9 KiB
JavaScript
const { PlayerState } = require('prismarine-physics')
|
|
|
|
class Physics {
|
|
constructor (bot) {
|
|
this.bot = bot
|
|
this.world = { getBlock: (pos) => { return bot.blockAt(pos, false) } }
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {function} goal A function is the goal has been reached or not
|
|
* @param {function} controller Controller that can change the current control State for the next tick
|
|
* @param {number} ticks Number of ticks to simulate
|
|
* @param {object} state Starting control state to begin the simulation with
|
|
* @returns { import('prismarine-physics').PlayerState } A player state of the final simulation tick
|
|
*/
|
|
simulateUntil (goal, controller = () => {}, ticks = 1, state = null) {
|
|
if (!state) {
|
|
const simulationControl = {
|
|
forward: this.bot.controlState.forward,
|
|
back: this.bot.controlState.back,
|
|
left: this.bot.controlState.left,
|
|
right: this.bot.controlState.right,
|
|
jump: this.bot.controlState.jump,
|
|
sprint: this.bot.controlState.sprint,
|
|
sneak: this.bot.controlState.sneak
|
|
}
|
|
state = new PlayerState(this.bot, simulationControl)
|
|
}
|
|
|
|
for (let i = 0; i < ticks; i++) {
|
|
controller(state, i)
|
|
this.bot.physics.simulatePlayer(state, this.world)
|
|
if (state.isInLava) return state
|
|
if (goal(state)) return state
|
|
}
|
|
|
|
return state
|
|
}
|
|
|
|
simulateUntilNextTick () {
|
|
return this.simulateUntil(() => false, () => {}, 1)
|
|
}
|
|
|
|
simulateUntilOnGround (ticks = 5) {
|
|
return this.simulateUntil(state => state.onGround, () => {}, ticks)
|
|
}
|
|
|
|
canStraightLine (path, sprint = false) {
|
|
const reached = this.getReached(path)
|
|
const state = this.simulateUntil(reached, this.getController(path[0], false, sprint), 200)
|
|
if (reached(state)) return true
|
|
|
|
if (sprint) {
|
|
if (this.canSprintJump(path, 0)) return false
|
|
} else {
|
|
if (this.canWalkJump(path, 0)) return false
|
|
}
|
|
|
|
for (let i = 1; i < 7; i++) {
|
|
if (sprint) {
|
|
if (this.canSprintJump(path, i)) return true
|
|
} else {
|
|
if (this.canWalkJump(path, i)) return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
canStraightLineBetween (n1, n2) {
|
|
const reached = (state) => {
|
|
const delta = n2.minus(state.pos)
|
|
const r2 = 0.15 * 0.15
|
|
return (delta.x * delta.x + delta.z * delta.z) <= r2 && Math.abs(delta.y) < 0.001 && (state.onGround || state.isInWater)
|
|
}
|
|
const simulationControl = {
|
|
forward: this.bot.controlState.forward,
|
|
back: this.bot.controlState.back,
|
|
left: this.bot.controlState.left,
|
|
right: this.bot.controlState.right,
|
|
jump: this.bot.controlState.jump,
|
|
sprint: this.bot.controlState.sprint,
|
|
sneak: this.bot.controlState.sneak
|
|
}
|
|
const state = new PlayerState(this.bot, simulationControl)
|
|
state.pos.update(n1)
|
|
this.simulateUntil(reached, this.getController(n2, false, true), Math.floor(5 * n1.distanceTo(n2)), state)
|
|
return reached(state)
|
|
}
|
|
|
|
canSprintJump (path, jumpAfter = 0) {
|
|
const reached = this.getReached(path)
|
|
const state = this.simulateUntil(reached, this.getController(path[0], true, true, jumpAfter), 20)
|
|
return reached(state)
|
|
}
|
|
|
|
canWalkJump (path, jumpAfter = 0) {
|
|
const reached = this.getReached(path)
|
|
const state = this.simulateUntil(reached, this.getController(path[0], true, false, jumpAfter), 20)
|
|
return reached(state)
|
|
}
|
|
|
|
getReached (path) {
|
|
return (state) => {
|
|
const delta = path[0].minus(state.pos)
|
|
return Math.abs(delta.x) <= 0.35 && Math.abs(delta.z) <= 0.35 && Math.abs(delta.y) < 1
|
|
}
|
|
}
|
|
|
|
getController (nextPoint, jump, sprint, jumpAfter = 0) {
|
|
return (state, tick) => {
|
|
const dx = nextPoint.x - state.pos.x
|
|
const dz = nextPoint.z - state.pos.z
|
|
state.yaw = Math.atan2(-dx, -dz)
|
|
|
|
state.control.forward = true
|
|
state.control.jump = jump && tick >= jumpAfter
|
|
state.control.sprint = sprint
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Physics
|