Add probe to try to attack the entity behind the block

This commit is contained in:
Redstone1024 2024-08-28 13:24:24 +08:00
parent fd19d4bf63
commit 4d16c1f7a1

View File

@ -23,14 +23,12 @@ import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.AnimalEntity; import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.fluid.FluidState; import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids; import net.minecraft.fluid.Fluids;
import net.minecraft.item.BowItem; import net.minecraft.item.BowItem;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items; import net.minecraft.item.Items;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult; import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import net.minecraft.world.RaycastContext; import net.minecraft.world.RaycastContext;
@ -38,11 +36,14 @@ import org.joml.Vector3d;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Set; import java.util.Set;
public class Prediction extends Module { public class Prediction extends Module {
private final SettingGroup sgGeneral = settings.getDefaultGroup(); private final SettingGroup sgGeneral = settings.getDefaultGroup();
private final SettingGroup sgTarget = settings.createGroup("Target"); private final SettingGroup sgTarget = settings.createGroup("Target");
private final SettingGroup sgSimulation = settings.createGroup("Simulation");
private final SettingGroup sgProbe = settings.createGroup("Probe");
private final SettingGroup sgSpeed = settings.createGroup("Aim Speed"); private final SettingGroup sgSpeed = settings.createGroup("Aim Speed");
private final SettingGroup sgRender = settings.createGroup("Render"); private final SettingGroup sgRender = settings.createGroup("Render");
@ -55,14 +56,6 @@ public class Prediction extends Module {
.build() .build()
); );
public final Setting<Integer> simulationSteps = sgGeneral.add(new IntSetting.Builder()
.name("simulation-steps")
.description("How many steps to simulate projectiles. Zero for no limit.")
.defaultValue(250)
.sliderMax(5000)
.build()
);
public final Setting<Integer> iterationSteps = sgGeneral.add(new IntSetting.Builder() public final Setting<Integer> iterationSteps = sgGeneral.add(new IntSetting.Builder()
.name("iteration-steps") .name("iteration-steps")
.description("How many iterations to aim projectiles. Zero for no limit.") .description("How many iterations to aim projectiles. Zero for no limit.")
@ -77,7 +70,7 @@ public class Prediction extends Module {
.description("How much accuracy is needed to aim a projectile.") .description("How much accuracy is needed to aim a projectile.")
.defaultValue(0.5) .defaultValue(0.5)
.sliderMax(1) .sliderMax(1)
.visible(() -> iterationSteps.get() == 0) .visible(() -> predictionLevel.get() >= 1 && iterationSteps.get() == 0)
.build() .build()
); );
@ -148,6 +141,78 @@ public class Prediction extends Module {
.build() .build()
); );
public final Setting<Integer> simulationSteps = sgSimulation.add(new IntSetting.Builder()
.name("simulation-steps")
.description("How many steps to simulate projectiles. Zero for no limit.")
.defaultValue(250)
.sliderMax(5000)
.build()
);
public final Setting<Double> eyeHeightOffset = sgSimulation.add(new DoubleSetting.Builder()
.name("eye-height-offset")
.description("What is the offset of the actual projectile launch position from eye height.")
.defaultValue(-0.1)
.sliderMin(-1.0)
.sliderMax(1.0)
.build()
);
public final Setting<Double> gravity = sgSimulation.add(new DoubleSetting.Builder()
.name("gravity")
.description("What is the acceleration of gravity on the projectile.")
.defaultValue(0.05000000074505806)
.sliderMin(0.04)
.sliderMax(0.06)
.build()
);
public final Setting<Double> airDrag = sgSimulation.add(new DoubleSetting.Builder()
.name("air-drag")
.description("What is the drag value of the projectile in air.")
.defaultValue(0.99)
.sliderMin(0.95)
.sliderMax(1.0)
.build()
);
public final Setting<Double> waterDrag = sgSimulation.add(new DoubleSetting.Builder()
.name("water-drag")
.description("What is the drag value of the projectile in water.")
.defaultValue(0.6)
.sliderMin(0)
.sliderMax(1)
.build()
);
private final Setting<Boolean> enableProbe = sgProbe.add(new BoolSetting.Builder()
.name("enable-probe")
.description("Enable/disable block probes.")
.defaultValue(false)
.visible(() -> predictionLevel.get() >= 1)
.build()
);
private final Setting<Double> probeRange = sgProbe.add(new DoubleSetting.Builder()
.name("probe-range")
.description("The maximum range of probe placement.")
.defaultValue(1)
.range(0, 4)
.sliderMax(4)
.visible(enableProbe::get)
.build()
);
private final Setting<Double> probeInterval = sgProbe.add(new DoubleSetting.Builder()
.name("probe-interval")
.description("The minimum interval of probe placement.")
.defaultValue(0.5)
.range(0, 1)
.sliderMax(1)
.visible(enableProbe::get)
.build()
);
private final Setting<Boolean> instant = sgSpeed.add(new BoolSetting.Builder() private final Setting<Boolean> instant = sgSpeed.add(new BoolSetting.Builder()
.name("instant-look") .name("instant-look")
.description("Instantly looks at the entity.") .description("Instantly looks at the entity.")
@ -166,7 +231,7 @@ public class Prediction extends Module {
private final Setting<Boolean> enableRender = sgRender.add(new BoolSetting.Builder() private final Setting<Boolean> enableRender = sgRender.add(new BoolSetting.Builder()
.name("enable-render") .name("enable-render")
.description("Enable/Disable Render Indication.") .description("Enable/disable render indication.")
.defaultValue(true) .defaultValue(true)
.build() .build()
); );
@ -220,11 +285,8 @@ public class Prediction extends Module {
@EventHandler @EventHandler
private void onTick(TickEvent.Post event) { private void onTick(TickEvent.Post event) {
if (mc.options.attackKey.isPressed() || !isSelectableTarget(targetEntity)) {
targetEntity = TargetUtils.get(this::isSelectableTarget, priority.get());
}
clearPath(); clearPath();
calculateTarget();
if (targetEntity != null) calculateAngle(); if (targetEntity != null) calculateAngle();
} }
@ -232,9 +294,7 @@ public class Prediction extends Module {
private void onRender(Render3DEvent event) { private void onRender(Render3DEvent event) {
float tickDelta = mc.world.getTickManager().isFrozen() ? 1 : event.tickDelta; float tickDelta = mc.world.getTickManager().isFrozen() ? 1 : event.tickDelta;
boolean canAim = aimAssist.get() && (isHitTarget || !aimOnlyHit.get()) && mc.options.useKey.isPressed() && InvUtils.testInHands(Items.BOW); if (aimAssist.get()) aim(event.tickDelta);
if (canAim) aim(event.tickDelta);
if (enableRender.get()) renderPath(event); if (enableRender.get()) renderPath(event);
} }
@ -268,29 +328,22 @@ public class Prediction extends Module {
return BowItem.getPullProgress(mc.player.getItemUseTime()); return BowItem.getPullProgress(mc.player.getItemUseTime());
} }
private static final double gravity = 0.05000000074505806; // These variables are set by the calculateTarget()
private static final double airDrag = 0.99;
private static final double waterDrag = 0.6;
// These variables are set by the onTick()
private Entity targetEntity; private Entity targetEntity;
private Box targetBox;
// These variables are set by the calculateAngle() // These variables are set by the calculateAngle()
private boolean targetCompleted;
private double targetYaw; private double targetYaw;
private double targetPitch; private double targetPitch;
private double targetCharge; private double targetCharge;
// These variables are set by the calculatePath() for prediction level >= 1
private double targetHighPitch;
private double targetLowPitch;
// These variables are set by the calculatePath() // These variables are set by the calculatePath()
private final Pool<Vector3d> vectorPool = new Pool<>(Vector3d::new); private final Pool<Vector3d> vectorPool = new Pool<>(Vector3d::new);
private final List<Vector3d> points = new ArrayList<>(); private final List<Vector3d> points = new ArrayList<>();
private boolean hitQuad = false, hitQuadHorizontal = false; private boolean hitQuad = false, hitQuadHorizontal = false;
private final Vector3d hitQuad1 = new Vector3d(); private final Vector3d hitQuad1 = new Vector3d();
private final Vector3d hitQuad2 = new Vector3d(); private final Vector3d hitQuad2 = new Vector3d();
private Entity collidingEntity = null;
private boolean isHitTarget; private boolean isHitTarget;
private void clearPath() { private void clearPath() {
@ -298,7 +351,6 @@ public class Prediction extends Module {
points.clear(); points.clear();
hitQuad = false; hitQuad = false;
collidingEntity = null;
isHitTarget = false; isHitTarget = false;
} }
@ -310,7 +362,7 @@ public class Prediction extends Module {
Vector3d lastPosition = new Vector3d(0.0, 0.0, 0.0); Vector3d lastPosition = new Vector3d(0.0, 0.0, 0.0);
Vector3d position = new Vector3d(0.0, 0.0, 0.0); Vector3d position = new Vector3d(0.0, 0.0, 0.0);
Vector3d velocity = new Vector3d(0.0, 0.0, 0.0); Vector3d velocity = new Vector3d(0.0, 0.0, 0.0);
position.set(mc.player.getX(), mc.player.getY(), mc.player.getZ()).add(0, mc.player.getEyeHeight(mc.player.getPose()), 0); position.set(mc.player.getX(), mc.player.getY(), mc.player.getZ()).add(0, mc.player.getEyeHeight(mc.player.getPose()) + eyeHeightOffset.get(), 0);
double yaw = targetYaw; double yaw = targetYaw;
double pitch = targetPitch; double pitch = targetPitch;
@ -323,8 +375,9 @@ public class Prediction extends Module {
velocity.add(mc.player.getVelocity().x, mc.player.isOnGround() ? 0.0D : mc.player.getVelocity().y, mc.player.getVelocity().z); velocity.add(mc.player.getVelocity().x, mc.player.isOnGround() ? 0.0D : mc.player.getVelocity().y, mc.player.getVelocity().z);
HitResult hitResult = null; HitResult hitResult = null;
Direction hitDirection = null;
for (int i = 0; i < (simulationSteps.get() > 0 ? simulationSteps.get() : Integer.MAX_VALUE) && hitResult == null; i++) { for (int i = 0; i < (simulationSteps.get() > 0 ? simulationSteps.get() : Integer.MAX_VALUE) && !hitQuad && !isHitTarget; i++) {
points.add(vectorPool.get().set(position)); points.add(vectorPool.get().set(position));
lastPosition.set(position); lastPosition.set(position);
@ -335,8 +388,8 @@ public class Prediction extends Module {
if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER) if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER)
isTouchingWater = position.y - (int) position.y <= fluidState.getHeight(); isTouchingWater = position.y - (int) position.y <= fluidState.getHeight();
velocity.mul(isTouchingWater ? waterDrag : airDrag); velocity.mul(isTouchingWater ? waterDrag.get() : airDrag.get());
velocity.sub(0, gravity, 0); velocity.sub(0, gravity.get(), 0);
if (position.y < mc.world.getBottomY()) { if (position.y < mc.world.getBottomY()) {
hitResult = MissHitResult.INSTANCE; hitResult = MissHitResult.INSTANCE;
@ -356,43 +409,79 @@ public class Prediction extends Module {
); );
if (hitResult.getType() != HitResult.Type.MISS) { if (hitResult.getType() != HitResult.Type.MISS) {
position = new Vector3d(hitResult.getPos().x, hitResult.getPos().y, hitResult.getPos().z); position = new Vector3d(hitResult.getPos().x, hitResult.getPos().y, hitResult.getPos().z);
}
Box box = new Box(
lastPosition.x - (EntityType.ARROW.getWidth() / 2f),
lastPosition.y,
lastPosition.z - (EntityType.ARROW.getWidth() / 2f),
lastPosition.x + (EntityType.ARROW.getWidth() / 2f),
lastPosition.y + EntityType.ARROW.getHeight(),
lastPosition.z + (EntityType.ARROW.getWidth() / 2f)
).stretch(velocity.x, velocity.y, velocity.z).expand(1.0D);
HitResult hitResultEntity = ProjectileUtil.getEntityCollision(mc.world, null,
new Vec3d(lastPosition.x, lastPosition.y, lastPosition.z), new Vec3d(position.x, position.y, position.z),
box, entity -> !entity.isSpectator() && entity.isAlive() && entity.canHit() && entity != mc.player
);
if (hitResultEntity != null) {
hitResult = hitResultEntity;
}
hitResult = hitResult.getType() == HitResult.Type.MISS ? null : hitResult;
}
if (hitResult != null) {
if (hitResult.getType() == HitResult.Type.BLOCK) {
BlockHitResult r = (BlockHitResult) hitResult;
hitQuad = true; hitQuad = true;
hitQuad1.set(r.getPos().x, r.getPos().y, r.getPos().z); hitQuad1.set(position);
hitQuad2.set(r.getPos().x, r.getPos().y, r.getPos().z); hitQuad2.set(position);
hitDirection = ((BlockHitResult) hitResult).getSide();
}
if (r.getSide() == Direction.UP || r.getSide() == Direction.DOWN) { if (!targetBox.stretch(velocity.x, velocity.y, velocity.z).expand(4.0).contains(position.x, position.y, position.z))
continue;
Box extendedBox = targetBox;
if (enableProbe.get()) {
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add(-(targetBox.getLengthX() + EntityType.ARROW.getWidth()) / 2.0, 0, 0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMinX = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().x : targetBox.minX - EntityType.ARROW.getWidth() / 2.0;
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add(0, -(targetBox.getLengthY() + EntityType.ARROW.getHeight()) / 2.0, 0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMinY = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().y : targetBox.minY - EntityType.ARROW.getHeight() / 2.0;
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add(0, 0, -(targetBox.getLengthZ() + EntityType.ARROW.getWidth()) / 2.0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMinZ = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().z : targetBox.minZ - EntityType.ARROW.getWidth() / 2.0;
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add((targetBox.getLengthX() + EntityType.ARROW.getWidth()) / 2.0, 0, 0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMaxX = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().x : targetBox.maxX + EntityType.ARROW.getWidth() / 2.0;
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add(0, (targetBox.getLengthY() + EntityType.ARROW.getHeight()) / 2.0, 0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMaxY = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().y : targetBox.maxY + EntityType.ARROW.getHeight() / 2.0;
hitResult = mc.world.raycast(new RaycastContext(
targetBox.getCenter(), targetBox.getCenter().add(0, 0, (targetBox.getLengthZ() + EntityType.ARROW.getWidth()) / 2.0),
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
);
double extendedMaxZ = hitResult.getType() != HitResult.Type.MISS ? hitResult.getPos().z : targetBox.maxZ + EntityType.ARROW.getWidth() / 2.0;
extendedBox = new Box(extendedMinX, extendedMinY, extendedMinZ, extendedMaxX, extendedMaxY, extendedMaxZ);
}
Optional<Vec3d> optional = extendedBox.raycast(new Vec3d(lastPosition.x, lastPosition.y, lastPosition.z), new Vec3d(position.x, position.y, position.z));
if (optional.isPresent()) {
isHitTarget = true;
}
}
if (hitQuad) {
if (hitDirection == Direction.UP || hitDirection == Direction.DOWN) {
hitQuadHorizontal = true; hitQuadHorizontal = true;
hitQuad1.x -= 0.25; hitQuad1.x -= 0.25;
hitQuad1.z -= 0.25; hitQuad1.z -= 0.25;
hitQuad2.x += 0.25; hitQuad2.x += 0.25;
hitQuad2.z += 0.25; hitQuad2.z += 0.25;
} }
else if (r.getSide() == Direction.NORTH || r.getSide() == Direction.SOUTH) { else if (hitDirection == Direction.NORTH || hitDirection == Direction.SOUTH) {
hitQuadHorizontal = false; hitQuadHorizontal = false;
hitQuad1.x -= 0.25; hitQuad1.x -= 0.25;
hitQuad1.y -= 0.25; hitQuad1.y -= 0.25;
@ -409,12 +498,6 @@ public class Prediction extends Module {
points.add(Utils.set(vectorPool.get(), hitResult.getPos())); points.add(Utils.set(vectorPool.get(), hitResult.getPos()));
} }
else if (hitResult.getType() == HitResult.Type.ENTITY) {
collidingEntity = ((EntityHitResult) hitResult).getEntity();
points.add(Utils.set(vectorPool.get(), hitResult.getPos()).add(0, collidingEntity.getHeight() / 2, 0));
isHitTarget = collidingEntity == targetEntity;
}
}
} }
private void renderPath(Render3DEvent event) { private void renderPath(Render3DEvent event) {
@ -448,37 +531,31 @@ public class Prediction extends Module {
} }
} }
if (collidingEntity != null) { if (targetEntity != null) {
double x = (collidingEntity.getX() - collidingEntity.prevX) * event.tickDelta; Box box = targetEntity.getBoundingBox();
double y = (collidingEntity.getY() - collidingEntity.prevY) * event.tickDelta;
double z = (collidingEntity.getZ() - collidingEntity.prevZ) * event.tickDelta;
Box box = collidingEntity.getBoundingBox();
event.renderer.box( event.renderer.box(
x + box.minX, y + box.minY, z + box.minZ, x + box.maxX, y + box.maxY, z + box.maxZ, targetBox,
isHitTarget ? hitSideColor.get() : missSideColor.get(), isHitTarget ? hitSideColor.get() : missSideColor.get(),
isHitTarget ? hitLineColor.get() : missLineColor.get(), isHitTarget ? hitLineColor.get() : missLineColor.get(),
shapeMode.get(), 0 shapeMode.get(), 0
); );
} }
if (!isHitTarget && targetEntity != null) {
double x = (targetEntity.getX() - targetEntity.prevX) * event.tickDelta;
double y = (targetEntity.getY() - targetEntity.prevY) * event.tickDelta;
double z = (targetEntity.getZ() - targetEntity.prevZ) * event.tickDelta;
Box box = targetEntity.getBoundingBox();
event.renderer.box(
x + box.minX, y + box.minY, z + box.minZ, x + box.maxX, y + box.maxY, z + box.maxZ,
missSideColor.get(), missLineColor.get(), shapeMode.get(), 0
);
}
} }
private double calculateHeightOffset(Vector3d targetPosition, double pitch) { private void calculateTarget() {
if (mc.options.attackKey.isPressed() || !isSelectableTarget(targetEntity)) {
targetEntity = TargetUtils.get(this::isSelectableTarget, priority.get());
}
if (targetEntity == null) return;
targetBox = targetEntity.getBoundingBox();
}
private double calculateHeightOffset(double pitch) {
double targetDistance = Math.sqrt( double targetDistance = Math.sqrt(
(targetPosition.x - mc.player.getX()) * (targetPosition.x - mc.player.getX()) + (targetBox.getCenter().x - mc.player.getX()) * (targetBox.getCenter().x - mc.player.getX()) +
(targetPosition.z - mc.player.getZ()) * (targetPosition.z - mc.player.getZ()) (targetBox.getCenter().z - mc.player.getZ()) * (targetBox.getCenter().z - mc.player.getZ())
); );
if (getCurrentCharge() <= 0) return Double.NaN; if (getCurrentCharge() <= 0) return Double.NaN;
@ -487,9 +564,9 @@ public class Prediction extends Module {
Vector3d lastPosition = new Vector3d(0.0, 0.0, 0.0); Vector3d lastPosition = new Vector3d(0.0, 0.0, 0.0);
Vector3d position = new Vector3d(0.0, 0.0, 0.0); Vector3d position = new Vector3d(0.0, 0.0, 0.0);
Vector3d velocity = new Vector3d(0.0, 0.0, 0.0); Vector3d velocity = new Vector3d(0.0, 0.0, 0.0);
position.set(mc.player.getX(), mc.player.getY(), mc.player.getZ()).add(0, mc.player.getEyeHeight(mc.player.getPose()), 0); position.set(mc.player.getX(), mc.player.getY(), mc.player.getZ()).add(0, mc.player.getEyeHeight(mc.player.getPose()) + eyeHeightOffset.get(), 0);
double yaw = Rotations.getYaw(new Vec3d(targetPosition.x, targetPosition.y, targetPosition.z)); double yaw = Rotations.getYaw(new Vec3d(targetBox.getCenter().x, targetBox.getCenter().y, targetBox.getCenter().z));
double x = -Math.sin(yaw * 0.017453292) * Math.cos(pitch * 0.017453292); double x = -Math.sin(yaw * 0.017453292) * Math.cos(pitch * 0.017453292);
double y = -Math.sin(pitch * 0.017453292); double y = -Math.sin(pitch * 0.017453292);
@ -507,8 +584,8 @@ public class Prediction extends Module {
if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER) if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER)
isTouchingWater = position.y - (int) position.y <= fluidState.getHeight(); isTouchingWater = position.y - (int) position.y <= fluidState.getHeight();
velocity.mul(isTouchingWater ? waterDrag : airDrag); velocity.mul(isTouchingWater ? waterDrag.get() : airDrag.get());
velocity.sub(0, gravity, 0); velocity.sub(0, gravity.get(), 0);
if (position.y < mc.world.getBottomY()) return Double.NEGATIVE_INFINITY; if (position.y < mc.world.getBottomY()) return Double.NEGATIVE_INFINITY;
@ -523,7 +600,7 @@ public class Prediction extends Module {
); );
if (distance > targetDistance) { if (distance > targetDistance) {
return MathHelper.lerp((targetDistance - laseDistance) / (distance - laseDistance), lastPosition.y, position.y) - targetPosition.y; return MathHelper.lerp((targetDistance - laseDistance) / (distance - laseDistance), lastPosition.y, position.y) - targetBox.getCenter().y;
} }
} }
@ -533,6 +610,8 @@ public class Prediction extends Module {
private void calculateAngle() { private void calculateAngle() {
if (targetEntity == null) return; if (targetEntity == null) return;
targetCompleted = false;
// parabolic prediction // parabolic prediction
if (predictionLevel.get() == 0) { if (predictionLevel.get() == 0) {
double posX = targetEntity.getPos().getX(); double posX = targetEntity.getPos().getX();
@ -559,42 +638,43 @@ public class Prediction extends Module {
} }
targetCharge = 1.0; targetCharge = 1.0;
targetCompleted = true;
calculatePath(); calculatePath();
return; return;
} }
Vector3d targetPosition = new Vector3d(targetEntity.getX(), targetEntity.getY() + targetEntity.getHeight() / 2.0, targetEntity.getZ()); double highestPitch = 0.0;
boolean findPitch = false;
// Basic physics prediction // Basic physics prediction
if (predictionLevel.get() == 1) { if (predictionLevel.get() >= 1) {
// Solve for the highest pitch // Solve for the highest pitch
double highestPitch;
{ {
double minPitch = -90.0; double minPitch = -90.0;
double maxPitch = 90.0; double maxPitch = 90.0;
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) { for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
double mid1 = minPitch + (maxPitch - minPitch) / 3.0; double mid1 = minPitch + (maxPitch - minPitch) / 3.0;
double mid2 = maxPitch - (maxPitch - minPitch) / 3.0; double mid2 = maxPitch - (maxPitch - minPitch) / 3.0;
double mid1Height = calculateHeightOffset(targetPosition, mid1); double mid1Height = calculateHeightOffset(mid1);
double mid2Height = calculateHeightOffset(targetPosition, mid2); double mid2Height = calculateHeightOffset(mid2);
if (Double.isNaN(mid1Height) || Double.isNaN(mid2Height)) return; if (Double.isNaN(mid1Height) || Double.isNaN(mid2Height)) return;
if (mid1Height < mid2Height) if (mid1Height < mid2Height)
minPitch = mid1; minPitch = mid1;
else maxPitch = mid2; else maxPitch = mid2;
} }
highestPitch = (minPitch + maxPitch) / 2.0; highestPitch = (minPitch + maxPitch) / 2.0;
if (calculateHeightOffset(targetPosition, highestPitch) < 0.0) return; if (calculateHeightOffset(highestPitch) < 0.0) return;
} }
// Solve for the low pitch // Solve for the low pitch
double targetLowPitch = highestPitch;
{ {
targetLowPitch = highestPitch;
double minPitch = highestPitch; double minPitch = highestPitch;
double maxPitch = 90.0; double maxPitch = 90.0;
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) { for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
double mid = (minPitch + maxPitch) / 2.0; double mid = (minPitch + maxPitch) / 2.0;
double midHeight = calculateHeightOffset(targetPosition, mid); double midHeight = calculateHeightOffset(mid);
if (Double.isNaN(midHeight)) { if (Double.isNaN(midHeight)) {
targetLowPitch = Double.NaN; targetLowPitch = Double.NaN;
break; break;
@ -606,23 +686,88 @@ public class Prediction extends Module {
if (!Double.isNaN(targetLowPitch)) targetLowPitch = (minPitch + maxPitch) / 2.0; if (!Double.isNaN(targetLowPitch)) targetLowPitch = (minPitch + maxPitch) / 2.0;
} }
if (!Double.isNaN(targetLowPitch)) if (!Double.isNaN(targetLowPitch)) {
{ findPitch = true;
targetPitch = targetLowPitch; targetPitch = targetLowPitch;
targetYaw = Rotations.getYaw(targetEntity); targetYaw = Rotations.getYaw(targetEntity);
targetCharge = getCurrentCharge(); targetCharge = getCurrentCharge();
targetCompleted = true;
calculatePath();
}
}
// If you can't hit because a block is blocking, try to use a probe.
if (targetCompleted && !isHitTarget && findPitch && enableProbe.get()) {
int numProbe = (int) (probeRange.get() / probeInterval.get());
boolean[][] arrayProbe = new boolean[numProbe * 2 + 1][numProbe * 2 + 1];
double targetDistance = Math.sqrt(
(targetBox.getCenter().x - mc.player.getX()) * (targetBox.getCenter().x - mc.player.getX()) +
(targetBox.getCenter().z - mc.player.getZ()) * (targetBox.getCenter().z - mc.player.getZ())
);
double delta = Math.atan2(targetDistance, probeInterval.get());
double centerYaw = targetYaw;
double centerPitch = targetPitch;
for (int i = 0; i < numProbe * 2 + 1; ++i) {
for (int j = 0; j < numProbe * 2 + 1; ++j) {
targetYaw = centerYaw - (i - numProbe) * delta;
targetPitch = centerPitch - (j - numProbe) * delta;
calculatePath();
arrayProbe[i][j] = isHitTarget;
}
}
int[][][] validProbe = new int[numProbe * 2 + 1][numProbe * 2 + 1][4];
for (int i = 0; i < numProbe * 2 + 1; ++i) {
for (int j = 0; j < numProbe * 2 + 1; ++j) {
if (i == 0) validProbe[i][j][0] = arrayProbe[i][j] ? 1 : 0;
else validProbe[i][j][0] = (arrayProbe[i][j] ? 1 : 0) + validProbe[i - 1][j][0];
if (j == 0) validProbe[i][j][1] = arrayProbe[i][j] ? 1 : 0;
else validProbe[i][j][1] = (arrayProbe[i][j] ? 1 : 0) + validProbe[i][j - 1][1];
}
}
for (int i = numProbe * 2; i >= 0; --i) {
for (int j = numProbe * 2; j >= 0; --j) {
if (i == numProbe * 2) validProbe[i][j][2] = arrayProbe[i][j] ? 1 : 0;
else validProbe[i][j][2] = (arrayProbe[i][j] ? 1 : 0) + validProbe[i + 1][j][2];
if (j == numProbe * 2) validProbe[i][j][3] = arrayProbe[i][j] ? 1 : 0;
else validProbe[i][j][3] = (arrayProbe[i][j] ? 1 : 0) + validProbe[i][j + 1][3];
}
}
int maxProbe = 0;
targetYaw = centerYaw;
targetPitch = centerPitch;
for (int i = numProbe * 2; i >= 0; --i) {
for (int j = numProbe * 2; j >= 0; --j) {
int x = Math.max(Math.min(validProbe[i][j][0], validProbe[i][j][1]), Math.min(validProbe[i][j][2], validProbe[i][j][3]));
if (x > maxProbe) {
maxProbe = x;
targetYaw = centerYaw - (i - numProbe) * delta;
targetPitch = centerPitch - (j - numProbe) * delta;
}
}
}
calculatePath(); calculatePath();
} }
// Solve for the high pitch // Solve for the high pitch if allowed
if (!isHitTarget && allowHighThrows.get()) { if (!isHitTarget && allowHighThrows.get()) {
targetHighPitch = highestPitch; double targetHighPitch = highestPitch;
double minPitch = -90.0; double minPitch = -90.0;
double maxPitch = highestPitch; double maxPitch = highestPitch;
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) { for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
double mid = (minPitch + maxPitch) / 2.0; double mid = (minPitch + maxPitch) / 2.0;
double midHeight = calculateHeightOffset(targetPosition, mid); double midHeight = calculateHeightOffset(mid);
if (Double.isNaN(midHeight)) { if (Double.isNaN(midHeight)) {
targetHighPitch = Double.NaN; targetHighPitch = Double.NaN;
break; break;
@ -631,23 +776,26 @@ public class Prediction extends Module {
minPitch = mid; minPitch = mid;
else maxPitch = mid; else maxPitch = mid;
} }
if (!Double.isNaN(targetHighPitch)) targetHighPitch = (minPitch + maxPitch) / 2.0;
}
if (!isHitTarget && !Double.isNaN(targetHighPitch) && allowHighThrows.get()) { if (!Double.isNaN(targetHighPitch)) {
targetHighPitch = (minPitch + maxPitch) / 2.0;
targetPitch = targetHighPitch; targetPitch = targetHighPitch;
targetYaw = Rotations.getYaw(targetEntity); targetYaw = Rotations.getYaw(targetEntity);
targetCharge = getCurrentCharge(); targetCharge = getCurrentCharge();
targetCompleted = true;
calculatePath(); calculatePath();
} }
return;
} }
} }
private void aim(double tickDelta) { private void aim(double tickDelta) {
if (targetEntity == null) return; if (targetEntity == null) return;
if (!targetCompleted) return;
if (!isHitTarget && aimOnlyHit.get()) return;
if (!mc.options.useKey.isPressed()) return;
if (!InvUtils.testInHands(Items.BOW)) return;
if (instant.get()) { if (instant.get()) {
mc.player.setYaw((float) targetYaw); mc.player.setYaw((float) targetYaw);