@nxg-org/mineflayer-custom-pvp
Version:
Intermediate functionality for bow and sword pvp.
197 lines (196 loc) • 9.55 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShotPlanner = void 0;
const mineflayer_trajectories_1 = require("@nxg-org/mineflayer-trajectories");
const mathUtils_1 = require("../calc/mathUtils");
const vec3_1 = require("vec3");
const mineflayer_util_plugin_1 = require("@nxg-org/mineflayer-util-plugin");
const emptyVec = new vec3_1.Vec3(0, 0, 0);
const dv = Math.PI / 360;
const PIOver2 = Math.PI / 2;
const PIOver3 = Math.PI / 3;
class ShotPlanner {
constructor(bot) {
this.bot = bot;
this.weapon = "bow";
this.intercepter = new mineflayer_trajectories_1.InterceptFunctions(bot);
}
isShotValid(shotInfo1, target, pitch) {
let shotInfo = shotInfo1.shotInfo;
if (!shotInfo)
shotInfo = shotInfo1;
//@ts-expect-error
if (shotInfo.shotInfo)
shotInfo = shotInfo.shotInfo;
if (!shotInfo)
return false;
if (shotInfo.blockingBlock && pitch > PIOver3) {
return shotInfo.blockingBlock.position.y <= target.y - 1;
}
else {
return shotInfo.intersectPos && !shotInfo.blockingBlock;
}
}
/**
* Better optimization. Still about 5x more expensive than hawkeye (no clue what I did) but its more accurate so whatever.
*
* Note: The increased cost comes from the increased checks made (1440 vs 100). This will be fixed.
*
* @param target
* @param avgSpeed
* @param pitch
* @returns {CheckedShot} the shot.
*/
shotToEntity(target, avgSpeed = emptyVec, pitch = -PIOver2) {
const yaw = (0, mathUtils_1.getTargetYaw)(this.bot.entity.position, target.position);
while (pitch < PIOver2) {
const initInfo = this.getNextShot(target, yaw, pitch);
pitch = initInfo.pitch;
if (avgSpeed.equals(emptyVec)) {
const correctShot = this.checkForBlockIntercepts(target, initInfo);
if (this.isShotValid(correctShot, target.position, pitch))
return correctShot;
const yawShot = this.getAlternativeYawShots(target, initInfo);
if (this.isShotValid(yawShot, target.position, pitch))
return yawShot;
}
else {
const newInfo = this.shiftTargetPositions(target, avgSpeed, initInfo);
for (const i of newInfo) {
const correctShot = this.checkForBlockIntercepts(i.target, ...i.info);
if (!correctShot.shotInfo)
continue;
if (this.isShotValid(correctShot, i.target.position, pitch))
return correctShot;
const yawShot = this.getAlternativeYawShots(i.target, initInfo);
if (this.isShotValid(yawShot, i.target.position, pitch))
return yawShot;
}
}
}
return null;
}
shiftTargetPositions(target, avgSpeed, ...shotInfo) {
avgSpeed.y = 0;
const newInfo = shotInfo.map((i) => i.shift ? target.position.clone().add(avgSpeed.scaled(i.ticks + 4)) : target.position); //weird monkey patch.
const allInfo = [];
for (const position of newInfo) {
const yaw = (0, mathUtils_1.getTargetYaw)(this.bot.entity.position, position);
const res = this.getAllPossibleShots({ position, height: target.height, width: target.width }, yaw);
const info = res.map((i) => {
return { yaw, pitch: i.pitch, ticks: i.ticks };
});
allInfo.push({ target: { position, height: target.height, width: target.width }, info });
}
return allInfo;
}
checkForBlockIntercepts(target, ...shots) {
var _a;
for (const { pitch, ticks, yaw } of shots) {
const initShot = mineflayer_trajectories_1.ShotFactory.fromPlayer({
position: this.bot.entity.position,
yaw,
pitch,
velocity: this.bot.entity.velocity,
onGround: this.bot.entity.onGround,
}, this.intercepter, this.weapon);
const shot = (_a = initShot.hitsEntity(target, { yawChecked: false, blockCheck: true })) === null || _a === void 0 ? void 0 : _a.shotInfo;
if (!!shot && this.isShotValid(shot, target.position, Number(pitch)))
return { hit: true, yaw, pitch: Number(pitch), ticks, shotInfo: shot };
}
return { hit: false, yaw: NaN, pitch: NaN, ticks: NaN, shotInfo: null };
}
getNextShot(target, yaw, minPitch = -PIOver2) {
var _a;
let shift = true;
let hittingData = [];
for (let pitch = minPitch + dv; pitch < PIOver2; pitch += dv) {
if (pitch > PIOver3)
shift = true;
const initShot = mineflayer_trajectories_1.ShotFactory.fromPlayer({
position: this.bot.entity.position,
yaw,
pitch,
velocity: this.bot.entity.velocity,
onGround: this.bot.entity.onGround,
}, this.intercepter, this.weapon);
const shot = (_a = initShot.hitsEntity(target, { yawChecked: false, blockCheck: false })) === null || _a === void 0 ? void 0 : _a.shotInfo;
if (!shot)
continue;
if (!shot.intersectPos) {
if (hittingData.length !== 0) {
const pitch = hittingData.map((e) => e.pitch).reduce((a, b) => a + b) / hittingData.length; //monkeypatch to hit feet.
const ticks = Math.round(hittingData.map((e) => e.ticks).reduce((a, b) => a + b) / hittingData.length);
return { yaw, pitch, ticks, shift };
}
else if (pitch > PIOver3 && shot.nearestDistance < 1) {
hittingData.push({ pitch, ticks: shot.totalTicks });
}
continue;
}
hittingData.push({ pitch, ticks: shot.totalTicks });
}
return { yaw: NaN, pitch: NaN, ticks: NaN };
}
getAlternativeYawShots(target, ...shots) {
var _a;
for (const { pitch, yaw: orgYaw } of shots) {
const yaws = mineflayer_util_plugin_1.AABBUtils.getEntityAABBRaw(target)
.toVertices()
.map((p) => (0, mathUtils_1.getTargetYaw)(this.bot.entity.position, p))
.sort((a, b) => orgYaw - Math.abs(a) - (orgYaw - Math.abs(b)));
let inbetween = [yaws.pop(), yaws.pop()];
inbetween = inbetween.map((y) => y + Math.sign(orgYaw - y) * 0.02);
for (const yaw of inbetween) {
const initShot = mineflayer_trajectories_1.ShotFactory.fromShootingPlayer({
position: this.bot.entity.position,
yaw,
pitch,
velocity: this.bot.entity.velocity,
onGround: this.bot.entity.onGround,
}, this.intercepter, this.weapon);
const shot = (_a = initShot.hitsEntity(target, { yawChecked: false, blockCheck: true })) === null || _a === void 0 ? void 0 : _a.shotInfo;
if (!!shot && (shot.intersectPos || (pitch > PIOver3 && shot.nearestDistance < 1))) {
return { hit: true, yaw, pitch, ticks: shot.totalTicks, shotInfo: shot };
}
}
}
return { hit: false, yaw: NaN, pitch: NaN, ticks: NaN, shotInfo: null };
}
//TODO: This is too expensive. Will aim at offset off foot instead of calc'ing all hits and averaging.
getAllPossibleShots(target, yaw) {
var _a;
let possibleShotData = [];
let shift = true;
let hittingData = [];
for (let pitch = -PIOver2; pitch < PIOver2; pitch += dv) {
if (pitch > PIOver3)
shift = true;
const initShot = mineflayer_trajectories_1.ShotFactory.fromPlayer({
position: this.bot.entity.position,
yaw,
pitch,
velocity: this.bot.entity.velocity,
onGround: this.bot.entity.onGround,
}, this.intercepter, this.weapon);
const shot = (_a = initShot.hitsEntity(target, { yawChecked: false, blockCheck: false })) === null || _a === void 0 ? void 0 : _a.shotInfo;
if (!shot)
continue;
if (!shot.intersectPos) {
if (hittingData.length !== 0) {
const pitch = hittingData.map((e) => e.pitch).reduce((a, b) => a + b) / hittingData.length; //monkeypatch to hit feet.
const ticks = Math.round(hittingData.map((e) => e.ticks).reduce((a, b) => a + b) / hittingData.length);
possibleShotData.push({ yaw, pitch, ticks, shift });
hittingData = [];
}
else if (pitch > PIOver3 && shot.nearestDistance < 1) {
hittingData.push({ pitch, ticks: shot.totalTicks });
}
continue;
}
hittingData.push({ pitch, ticks: shot.totalTicks });
}
return possibleShotData;
}
}
exports.ShotPlanner = ShotPlanner;