minecrafthawkeye
Version:
Minecraft bot for equations when shooting an arrow
261 lines (242 loc) • 10 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _types = require("./types");
var _vec = require("vec3");
var _intercept = require("./intercept");
var _loadBot = require("./loadBot");
var _constants = require("./constants");
var _mathHelper = require("./mathHelper");
// // TODO: Pending to remove these global variables
// let target: Entity | OptionsMasterGrade
// let speed: Vec3
// let startPosition: Vec3
// let targetPosition: Vec3
// let BaseVo: number // Power of shot, Depends of weapon have different value
// let GRAVITY: number // Depends of weapon have different gravity
const getMasterGrade = (targetIn, speedIn, weapon) => {
if (!Object.keys(_types.Weapons).includes(weapon)) {
throw new Error(`${weapon} is not valid weapon for calculate the grade!`);
}
const weaponProp = _types.weaponsProps[weapon];
const BaseVo = weaponProp.BaseVo;
const GRAVITY = weaponProp.GRAVITY;
const target = targetIn;
const speed = speedIn;
const startPosition = _loadBot.bot.entity.position.offset(0, 1.6, 0); // Bow offset position
// Calculate target Height, for shot in the heart =P
const targetHeight = !(0, _types.isEntity)(target) ? 0 : target.type === 'player' ? 1.16 : target.height ?? 0;
const targetPosition = target.position.offset(0, targetHeight, 0);
// Check the first best trayectory
let distances = (0, _mathHelper.getTargetDistance)(startPosition, targetPosition);
let shotCalculation = geBaseCalculation(distances.hDistance, distances.yDistance, GRAVITY, startPosition, targetPosition, BaseVo);
if (!shotCalculation) {
return undefined;
}
// Recalculate the new target based on speed + first trayectory
const premonition = getPremonition(shotCalculation.totalTicks, speed, startPosition, targetPosition);
distances = premonition.distances;
const newTarget = premonition.newTarget;
// Recalculate the trayectory based on new target location
shotCalculation = geBaseCalculation(distances.hDistance, distances.yDistance, GRAVITY, startPosition, targetPosition, BaseVo);
if (!shotCalculation) {
return undefined;
}
// Get more precision on shot
const precisionShot = getPrecisionShot(shotCalculation.grade, distances.hDistance, distances.yDistance, 1, GRAVITY, startPosition, targetPosition, BaseVo);
const {
arrowTrajectoryPoints,
blockInTrayect,
nearestDistance,
nearestGrade
} = precisionShot;
// Calculate yaw
const yaw = (0, _mathHelper.calculateYaw)(startPosition, newTarget);
if (nearestDistance > 4) {
return undefined;
} // Too far
return {
pitch: (0, _mathHelper.degreesToRadians)(nearestGrade / 10),
yaw,
grade: nearestGrade / 10,
nearestDistance,
target: newTarget,
arrowTrajectoryPoints,
blockInTrayect
};
};
// Simulate Arrow Trayectory
const tryGrade = (grade, xDestination, yDestination, VoIn, tryIntercetpBlock = false, GRAVITY, startPosition, targetPosition) => {
let precisionFactor = 1; // !Danger More precision increse the calc! => !More Slower!
let Vo = VoIn;
let gravity = GRAVITY / precisionFactor;
let factorY = _constants.FACTOR_Y / precisionFactor;
let factorH = _constants.FACTOR_H / precisionFactor;
// Vo => Vector total velocity (X,Y,Z)
// For arrow trayectory only need the horizontal discante (X,Z) and verticla (Y)
let Voy = (0, _mathHelper.getVoy)(Vo, (0, _mathHelper.degreesToRadians)(grade)); // Vector Y
let Vox = (0, _mathHelper.getVox)(Vo, (0, _mathHelper.degreesToRadians)(grade)); // Vector X
let Vy = Voy / precisionFactor;
let Vx = Vox / precisionFactor;
let Alfa;
let nearestDistance;
let totalTicks = 0;
let blockInTrayect = null;
const arrowTrajectoryPoints = [];
arrowTrajectoryPoints.push(startPosition);
const yaw = (0, _mathHelper.calculateYaw)(startPosition, targetPosition);
while (true) {
const firstDistance = Math.sqrt(Math.pow(Vy - yDestination, 2) + Math.pow(Vx - xDestination, 2));
if (nearestDistance === undefined) {
nearestDistance = firstDistance;
}
if (firstDistance < nearestDistance) {
nearestDistance = firstDistance;
}
// Increse precission when arrow is near over target,
// Dynamic Precission, when arrow is near target increse * the precission !Danger with this number
if (nearestDistance < 4) {
precisionFactor = 5;
}
if (nearestDistance > 4) {
precisionFactor = 1;
}
totalTicks += 1 / precisionFactor;
gravity = GRAVITY / precisionFactor;
factorY = _constants.FACTOR_Y / precisionFactor;
factorH = _constants.FACTOR_H / precisionFactor;
Vo = (0, _mathHelper.getVo)(Vox, Voy, gravity);
Alfa = (0, _mathHelper.applyGravityToVoy)(Vo, Voy, gravity);
Voy = (0, _mathHelper.getVoy)(Vo, Alfa, Voy * factorY);
Vox = (0, _mathHelper.getVox)(Vo, Alfa, Vox * factorH);
Vy += Voy / precisionFactor;
Vx += Vox / precisionFactor;
const x = startPosition.x - Math.sin(yaw) * Vx;
const z = yaw === 0 ? startPosition.z : startPosition.z - Math.sin(yaw) * Vx / Math.tan(yaw);
const y = startPosition.y + Vy;
const currentArrowPosition = new _vec.Vec3(x, y, z);
arrowTrajectoryPoints.push(currentArrowPosition);
const previusArrowPositionIntercept = arrowTrajectoryPoints[arrowTrajectoryPoints.length === 1 ? 0 : arrowTrajectoryPoints.length - 2];
if (tryIntercetpBlock) {
blockInTrayect = (0, _intercept.check)(previusArrowPositionIntercept, currentArrowPosition);
}
// Arrow passed player || Voy (arrow is going down and passed player) || Detected solid block
if (Vx > xDestination || Voy < 0 && yDestination > Vy || blockInTrayect !== null) {
return {
nearestDistance,
totalTicks,
blockInTrayect,
arrowTrajectoryPoints
};
}
}
};
// Get more precision on shot
const getPrecisionShot = (grade, xDestination, yDestination, decimals, GRAVITY, startPosition, targetPosition, BaseVo) => {
let nearestDistance;
let nearestGrade;
let arrowTrajectoryPoints;
let blockInTrayect = null;
decimals = Math.pow(10, decimals);
for (let iGrade = grade * 10 - 10; iGrade <= grade * 10 + 10; iGrade += 1) {
const distance = tryGrade(iGrade / decimals, xDestination, yDestination, BaseVo, true, GRAVITY, startPosition, targetPosition);
if (nearestDistance === undefined || distance.nearestDistance < nearestDistance) {
nearestDistance = distance.nearestDistance;
nearestGrade = iGrade;
arrowTrajectoryPoints = distance.arrowTrajectoryPoints;
blockInTrayect = distance.blockInTrayect;
}
}
if (nearestDistance === undefined || nearestGrade === undefined || arrowTrajectoryPoints === undefined) {
throw Error('Error con calc getPrecisionShot');
}
return {
nearestGrade,
nearestDistance,
arrowTrajectoryPoints,
blockInTrayect
};
};
// Calculate all 180º first grades
// Calculate the 2 most aproax shots
// https://es.qwe.wiki/wiki/Trajectory
const getFirstGradeAproax = (xDestination, yDestination, GRAVITY, startPosition, targetPosition, BaseVo) => {
let firstFound = false;
let nearestGradeFirst;
let nearestGradeSecond;
for (let grade = -89; grade < 90; grade++) {
const calculatedTryGrade = tryGrade(grade, xDestination, yDestination, BaseVo, false, GRAVITY, startPosition, targetPosition);
const tryGradeShot = {
...calculatedTryGrade,
grade
};
if (tryGradeShot.nearestDistance > 4) {
continue;
}
if (nearestGradeFirst === undefined) {
nearestGradeFirst = tryGradeShot;
}
if (nearestGradeSecond === undefined) {
nearestGradeSecond = tryGradeShot;
}
if (tryGradeShot.grade - nearestGradeFirst.grade > 10 && firstFound === false) {
firstFound = true;
nearestGradeSecond = tryGradeShot;
}
if (nearestGradeFirst.nearestDistance > tryGradeShot.nearestDistance && firstFound === false) {
nearestGradeFirst = tryGradeShot;
}
if (nearestGradeSecond.nearestDistance > tryGradeShot.nearestDistance && firstFound) {
nearestGradeSecond = tryGradeShot;
}
}
if (nearestGradeFirst === undefined && nearestGradeSecond === undefined) {
return false;
}
if (nearestGradeFirst === undefined || nearestGradeSecond === undefined) {
throw Error('Error on calculate getFirstGradeAproax');
}
return {
nearestGradeFirst,
nearestGradeSecond
};
};
const getPremonition = (totalTicks, targetSpeed, startPosition, targetPosition) => {
totalTicks = totalTicks + Math.ceil(totalTicks / 10);
const velocity = targetSpeed.clone();
const newTarget = targetPosition.clone();
for (let i = 1; i <= totalTicks; i++) {
newTarget.add(velocity);
}
const distances = (0, _mathHelper.getTargetDistance)(startPosition, newTarget);
return {
distances,
newTarget
};
};
// For parabola of Y you have 2 times for found the Y position if Y original are downside of Y destination
const geBaseCalculation = (xDestination, yDestination, GRAVITY, startPosition, targetPosition, BaseVo) => {
const grade = getFirstGradeAproax(xDestination, yDestination, GRAVITY, startPosition, targetPosition, BaseVo);
let gradeShot;
if (!grade) {
return false;
} // No aviable trayectory
// Check blocks in trayectory
const checkFirst = tryGrade(grade.nearestGradeFirst.grade, xDestination, yDestination, BaseVo, true, GRAVITY, startPosition, targetPosition);
if (!checkFirst.blockInTrayect && checkFirst.nearestDistance < 4) {
gradeShot = grade.nearestGradeFirst;
} else {
if (!grade.nearestGradeSecond) {
return false; // No aviable trayectory
}
const checkSecond = tryGrade(grade.nearestGradeSecond.grade, xDestination, yDestination, BaseVo, true, GRAVITY, startPosition, targetPosition);
if (checkSecond.blockInTrayect) {
return false; // No aviable trayectory
}
gradeShot = grade.nearestGradeSecond;
}
return gradeShot;
};
var _default = exports.default = getMasterGrade;