UNPKG

@nxg-org/mineflayer-util-plugin

Version:

mineflayer utils for NextGEN mineflayer plugins.

189 lines (188 loc) 8.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PredictiveFunctions = void 0; const vec3_1 = require("vec3"); const predictiveWorld_1 = require("./worldRelated/predictiveWorld"); const static_1 = require("./static"); const armorPieces = ["head", "torso", "legs", "feet"]; // https://minecraft.fandom.com/wiki/Explosion // Use bot.world, there's no typing yet. function calcExposure(playerPos, explosionPos, world) { const dx = 1 / (0.6 * 2 + 1); const dy = 1 / (1.8 * 2 + 1); const dz = 1 / (0.6 * 2 + 1); const d3 = (1 - Math.floor(1 / dx) * dx) / 2; const d4 = (1 - Math.floor(1 / dz) * dz) / 2; let sampled = 0; let exposed = 0; const pos = new vec3_1.Vec3(0, 0, 0); for (pos.y = playerPos.y; pos.y <= playerPos.y + 1.8; pos.y += 1.8 * dy) { for (pos.x = playerPos.x - 0.3 + d3; pos.x <= playerPos.x + 0.3; pos.x += 0.6 * dx) { for (pos.z = playerPos.z - 0.3 + d4; pos.z <= playerPos.z + 0.3; pos.z += 0.6 * dz) { const dir = pos.minus(explosionPos); const range = dir.norm(); if (world.raycast(explosionPos, dir.normalize(), range) === null) { exposed++; } sampled++; } } } return exposed / sampled; } function calcExposureAABB(entityBB, explosionPos, world /* prismarine-world*/) { const xWidth = entityBB.maxX - entityBB.minX; const yWidth = entityBB.maxY - entityBB.minY; const zWidth = entityBB.maxZ - entityBB.minZ; const dx = 1 / (xWidth * 2 + 1); const dy = 1 / (yWidth * 2 + 1); const dz = 1 / (zWidth * 2 + 1); const d3 = (1 - Math.floor(1 / dx) * dx) / 2; const d4 = (1 - Math.floor(1 / dz) * dz) / 2; let sampled = 0; let exposed = 0; const pos = new vec3_1.Vec3(0, 0, 0); for (pos.y = entityBB.minY; pos.y <= entityBB.maxY; pos.y += yWidth * dy) { for (pos.x = entityBB.minX + d3; pos.x <= entityBB.maxX; pos.x += xWidth * dx) { for (pos.z = entityBB.minZ + d4; pos.z <= entityBB.maxZ; pos.z += zWidth * dz) { const dir = pos.minus(explosionPos); const range = dir.norm(); if (world.raycast(explosionPos, dir.normalize(), range) === null) { exposed++; } sampled++; } } } return exposed / sampled; } // https://minecraft.fandom.com/wiki/Armor#Damage_protection function getDamageAfterAbsorb(damages, armorValue, toughness) { const var3 = 2 + toughness / 4; const var4 = Math.min(Math.max(armorValue - damages / var3, armorValue * 0.2), 20); return damages * (1 - var4 / 25); } // https://minecraft.fandom.com/wiki/Attribute#Operations function getAttributeValue(prop) { let X = prop.value; for (const mod of prop.modifiers) { if (mod.operation !== 0) continue; X += mod.amount; } let Y = X; for (const mod of prop.modifiers) { if (mod.operation !== 1) continue; Y += X * mod.amount; } for (const mod of prop.modifiers) { if (mod.operation !== 2) continue; Y += Y * mod.amount; } return Y; } function getDamageWithEnchantments(damage, equipment) { const enchantments = equipment.some((e) => !!e) ? equipment .map((armor) => { var _a; return (_a = armor === null || armor === void 0 ? void 0 : armor.enchants.map((enchant) => { switch (enchant === null || enchant === void 0 ? void 0 : enchant.name) { case "protection": return enchant.lvl; case "blast_protection": return enchant.lvl * 2; default: return 0; } }).reduce((b, a) => b + a, 0)) !== null && _a !== void 0 ? _a : [0]; }) .reduce((b, a) => b + a, 0) : 0; return damage * (1 - Math.min(enchantments, 20) / 25); } const DIFFICULTY_VALUES = { peaceful: 0, easy: 1, normal: 2, hard: 3, }; class PredictiveFunctions { constructor(bot) { this.bot = bot; this.resistanceIndex = 11; const effects = bot.registry.effects; for (const effectId in effects) { const effect = effects[effectId]; if (effect.name.includes("esistance")) { this.resistanceIndex = Number(effectId); break; } } this.damageMultiplier = bot.registry.version[">="]("1.9") ? 8 : 7; // for 1.12+ 8 for 1.8 TODO check when the change occur (likely 1.9) this.armorToughnessKey = bot.registry.version[">="]("1.16") ? "minecraft:generic.armor_toughness" : "generic.armorToughness"; // was renamed in 1.16 this.armorProtectionKey = bot.registry.version[">="]("1.16") ? "minecraft:generic.armor" : "generic.armor"; // was renamed in 1.16 this.world = new predictiveWorld_1.PredictiveWorld(bot); } //There's a mistyping in mineflayer. Effect[] is not accurate. You cannot map over it. getDamageWithEffects(damage, effects) { var _a, _b; const resistanceLevel = (_b = (_a = effects === null || effects === void 0 ? void 0 : effects[this.resistanceIndex]) === null || _a === void 0 ? void 0 : _a.amplifier) !== null && _b !== void 0 ? _b : 0; return damage * (1 - resistanceLevel / 5); } placeBlocks(blocks) { this.world.setBlocks(blocks); } removePredictedBlocks(positions, force = false) { this.world.removeBlocks(positions, force); } selfExplosionDamage(sourcePos, power, rawDamages = false) { const distance = this.bot.entity.position.distanceTo(sourcePos); const radius = 2 * power; if (distance >= radius) return 0; const exposure = calcExposure(this.bot.entity.position, sourcePos, this.world); const impact = (1 - distance / radius) * exposure; let damages = Math.floor((impact * impact + impact) * this.damageMultiplier * power + 1); // The following modifiers are constant for the input bot.entity and doesnt depend // on the source position, so if the goal is to compare between positions they can be // ignored to save computations if (!rawDamages && this.bot.entity.attributes[this.armorProtectionKey]) { const armor = getAttributeValue(this.bot.entity.attributes[this.armorProtectionKey]); const armorToughness = getAttributeValue(this.bot.entity.attributes[this.armorToughnessKey]); damages = getDamageAfterAbsorb(damages, armor, armorToughness); damages = getDamageWithEnchantments(damages, this.bot.entity.equipment); damages = this.getDamageWithEffects(damages, this.bot.entity.effects); damages *= DIFFICULTY_VALUES[this.bot.game.difficulty] * 0.5; } return Math.floor(damages); } getExplosionDamage(targetEntity, sourcePos, power, rawDamages = false) { const distance = targetEntity.position.distanceTo(sourcePos); const radius = 2 * power; if (distance >= radius) return 0; const exposure = calcExposureAABB(static_1.AABBUtils.getEntityAABB(targetEntity), sourcePos, this.world); const impact = (1 - distance / radius) * exposure; let damages = Math.floor((impact * impact + impact) * this.damageMultiplier * power + 1); // The following modifiers are constant for the input targetEntity and doesnt depend // on the source position, so if the goal is to compare between positions they can be // ignored to save computations if (!rawDamages && targetEntity.attributes[this.armorProtectionKey]) { const armor = getAttributeValue(targetEntity.attributes[this.armorProtectionKey]); const armorToughness = getAttributeValue(targetEntity.attributes[this.armorToughnessKey]); damages = getDamageAfterAbsorb(damages, armor, armorToughness); damages = getDamageWithEnchantments(damages, targetEntity.equipment); damages = this.getDamageWithEffects(damages, targetEntity.effects); if (targetEntity.type === "player") { damages *= DIFFICULTY_VALUES[this.bot.game.difficulty] * 0.5; } } return Math.floor(damages); } } exports.PredictiveFunctions = PredictiveFunctions;