Add prediction based on physics simulations
This commit is contained in:
parent
5b4a9fb908
commit
fd19d4bf63
@ -27,7 +27,6 @@ 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.Item;
|
|
||||||
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;
|
||||||
@ -47,12 +46,45 @@ public class Prediction extends Module {
|
|||||||
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");
|
||||||
|
|
||||||
private final Setting<Double> predictionLevel = sgGeneral.add(new DoubleSetting.Builder()
|
private final Setting<Integer> predictionLevel = sgGeneral.add(new IntSetting.Builder()
|
||||||
.name("prediction-level")
|
.name("prediction-level")
|
||||||
.description("The intelligence level for entity position prediction.")
|
.description("The intelligence level for entity position prediction.")
|
||||||
.defaultValue(0)
|
.defaultValue(0)
|
||||||
.range(0, 0)
|
.range(0, 1)
|
||||||
.sliderMax(0)
|
.sliderMax(1)
|
||||||
|
.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()
|
||||||
|
.name("iteration-steps")
|
||||||
|
.description("How many iterations to aim projectiles. Zero for no limit.")
|
||||||
|
.defaultValue(20)
|
||||||
|
.sliderMax(100)
|
||||||
|
.visible(() -> predictionLevel.get() >= 1)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
public final Setting<Double> iterationEpsilon = sgGeneral.add(new DoubleSetting.Builder()
|
||||||
|
.name("iteration-epsilon")
|
||||||
|
.description("How much accuracy is needed to aim a projectile.")
|
||||||
|
.defaultValue(0.5)
|
||||||
|
.sliderMax(1)
|
||||||
|
.visible(() -> iterationSteps.get() == 0)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Setting<Boolean> allowHighThrows = sgGeneral.add(new BoolSetting.Builder()
|
||||||
|
.name("allow-high-throws")
|
||||||
|
.description("Whether or not to allow high throw prediction.")
|
||||||
|
.defaultValue(false)
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -63,6 +95,14 @@ public class Prediction extends Module {
|
|||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private final Setting<Boolean> aimOnlyHit = sgGeneral.add(new BoolSetting.Builder()
|
||||||
|
.name("aim-only-hit")
|
||||||
|
.description("Whether to aim only when there is a chance of a hit.")
|
||||||
|
.defaultValue(true)
|
||||||
|
.visible(aimAssist::get)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
private final Setting<Double> range = sgTarget.add(new DoubleSetting.Builder()
|
private final Setting<Double> range = sgTarget.add(new DoubleSetting.Builder()
|
||||||
.name("range")
|
.name("range")
|
||||||
.description("The maximum range the entity can be to aim at it.")
|
.description("The maximum range the entity can be to aim at it.")
|
||||||
@ -108,14 +148,6 @@ public class Prediction extends Module {
|
|||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
public final Setting<Integer> simulationSteps = sgTarget.add(new IntSetting.Builder()
|
|
||||||
.name("simulation-steps")
|
|
||||||
.description("How many steps to simulate projectiles. Zero for no limit")
|
|
||||||
.defaultValue(500)
|
|
||||||
.sliderMax(5000)
|
|
||||||
.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.")
|
||||||
@ -184,24 +216,25 @@ public class Prediction extends Module {
|
|||||||
@Override
|
@Override
|
||||||
public void onDeactivate() {
|
public void onDeactivate() {
|
||||||
targetEntity = null;
|
targetEntity = null;
|
||||||
isHitTarget = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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();
|
||||||
|
if (targetEntity != null) calculateAngle();
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
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;
|
||||||
|
|
||||||
if (mc.options.attackKey.isPressed() || !isSelectableTarget(targetEntity)) {
|
boolean canAim = aimAssist.get() && (isHitTarget || !aimOnlyHit.get()) && mc.options.useKey.isPressed() && InvUtils.testInHands(Items.BOW);
|
||||||
targetEntity = TargetUtils.get(this::isSelectableTarget, priority.get());
|
|
||||||
isHitTarget = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
calculatePath(tickDelta);
|
if (canAim) aim(event.tickDelta);
|
||||||
if (aimAssist.get()) calculateAngle(tickDelta);
|
|
||||||
if (aimAssist.get() && mc.options.useKey.isPressed() && InvUtils.testInHands(Items.BOW)) aim(event.tickDelta);
|
|
||||||
if (enableRender.get()) renderPath(event);
|
if (enableRender.get()) renderPath(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,18 +258,40 @@ public class Prediction extends Module {
|
|||||||
return !(entity instanceof AnimalEntity) || babies.get() || !((AnimalEntity) entity).isBaby();
|
return !(entity instanceof AnimalEntity) || babies.get() || !((AnimalEntity) entity).isBaby();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Entity targetEntity;
|
private double getCurrentCharge(){
|
||||||
private boolean isHitTarget;
|
ItemStack itemStack = mc.player.getMainHandStack();
|
||||||
|
if (!(itemStack.getItem() instanceof BowItem)) {
|
||||||
|
itemStack = mc.player.getOffHandStack();
|
||||||
|
if (!(itemStack.getItem() instanceof BowItem)) return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BowItem.getPullProgress(mc.player.getItemUseTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final double gravity = 0.05000000074505806;
|
||||||
|
private static final double airDrag = 0.99;
|
||||||
|
private static final double waterDrag = 0.6;
|
||||||
|
|
||||||
|
// These variables are set by the onTick()
|
||||||
|
private Entity targetEntity;
|
||||||
|
|
||||||
|
// These variables are set by the calculateAngle()
|
||||||
private double targetYaw;
|
private double targetYaw;
|
||||||
private double targetPitch;
|
private double targetPitch;
|
||||||
|
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()
|
||||||
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 Entity collidingEntity = null;
|
||||||
|
private boolean isHitTarget;
|
||||||
|
|
||||||
private void clearPath() {
|
private void clearPath() {
|
||||||
for (Vector3d point : points) vectorPool.free(point);
|
for (Vector3d point : points) vectorPool.free(point);
|
||||||
@ -244,40 +299,28 @@ public class Prediction extends Module {
|
|||||||
|
|
||||||
hitQuad = false;
|
hitQuad = false;
|
||||||
collidingEntity = null;
|
collidingEntity = null;
|
||||||
|
isHitTarget = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculatePath(double tickDelta) {
|
private void calculatePath() {
|
||||||
clearPath();
|
clearPath();
|
||||||
isHitTarget = false;
|
|
||||||
|
|
||||||
ItemStack itemStack = mc.player.getMainHandStack();
|
double speed = targetCharge * 3;
|
||||||
if (!(itemStack.getItem() instanceof BowItem)) {
|
|
||||||
itemStack = mc.player.getOffHandStack();
|
|
||||||
if (!(itemStack.getItem() instanceof BowItem)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item item = itemStack.getItem();
|
|
||||||
double charge = BowItem.getPullProgress(mc.player.getItemUseTime());
|
|
||||||
if (charge <= 0) return;
|
|
||||||
|
|
||||||
double speed = charge * 3;
|
|
||||||
double gravity = 0.05000000074505806;
|
|
||||||
double airDrag = 0.99;
|
|
||||||
double waterDrag = 0.6;
|
|
||||||
|
|
||||||
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);
|
||||||
Utils.set(position, mc.player, tickDelta).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()), 0);
|
||||||
|
|
||||||
double yaw = MathHelper.lerp(tickDelta, mc.player.prevYaw, mc.player.getYaw());
|
double yaw = targetYaw;
|
||||||
double pitch = MathHelper.lerp(tickDelta, mc.player.prevPitch, mc.player.getPitch());
|
double pitch = targetPitch;
|
||||||
|
|
||||||
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);
|
||||||
double z = Math.cos(yaw * 0.017453292) * Math.cos(pitch * 0.017453292);
|
double z = Math.cos(yaw * 0.017453292) * Math.cos(pitch * 0.017453292);
|
||||||
|
|
||||||
velocity.set(x, y, z).normalize().mul(speed);
|
velocity.set(x, y, z).normalize().mul(speed);
|
||||||
|
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;
|
||||||
|
|
||||||
@ -312,7 +355,7 @@ public class Prediction extends Module {
|
|||||||
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
|
RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player)
|
||||||
);
|
);
|
||||||
if (hitResult.getType() != HitResult.Type.MISS) {
|
if (hitResult.getType() != HitResult.Type.MISS) {
|
||||||
lastPosition = 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(
|
Box box = new Box(
|
||||||
@ -432,35 +475,174 @@ public class Prediction extends Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculateAngle(double tickDelta) {
|
private double calculateHeightOffset(Vector3d targetPosition, double pitch) {
|
||||||
|
double targetDistance = Math.sqrt(
|
||||||
|
(targetPosition.x - mc.player.getX()) * (targetPosition.x - mc.player.getX()) +
|
||||||
|
(targetPosition.z - mc.player.getZ()) * (targetPosition.z - mc.player.getZ())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (getCurrentCharge() <= 0) return Double.NaN;
|
||||||
|
double speed = getCurrentCharge() * 3;
|
||||||
|
|
||||||
|
Vector3d lastPosition = 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);
|
||||||
|
position.set(mc.player.getX(), mc.player.getY(), mc.player.getZ()).add(0, mc.player.getEyeHeight(mc.player.getPose()), 0);
|
||||||
|
|
||||||
|
double yaw = Rotations.getYaw(new Vec3d(targetPosition.x, targetPosition.y, targetPosition.z));
|
||||||
|
|
||||||
|
double x = -Math.sin(yaw * 0.017453292) * Math.cos(pitch * 0.017453292);
|
||||||
|
double y = -Math.sin(pitch * 0.017453292);
|
||||||
|
double z = Math.cos(yaw * 0.017453292) * Math.cos(pitch * 0.017453292);
|
||||||
|
|
||||||
|
velocity.set(x, y, z).normalize().mul(speed);
|
||||||
|
velocity.add(mc.player.getVelocity().x, mc.player.isOnGround() ? 0.0D : mc.player.getVelocity().y, mc.player.getVelocity().z);
|
||||||
|
|
||||||
|
for (int i = 0; i < (simulationSteps.get() > 0 ? simulationSteps.get() : Integer.MAX_VALUE); i++) {
|
||||||
|
lastPosition.set(position);
|
||||||
|
position.add(velocity);
|
||||||
|
|
||||||
|
boolean isTouchingWater = false;
|
||||||
|
FluidState fluidState = mc.world.getFluidState(new BlockPos((int) position.x, (int) position.y, (int) position.z));
|
||||||
|
if (fluidState.getFluid() == Fluids.WATER || fluidState.getFluid() == Fluids.FLOWING_WATER)
|
||||||
|
isTouchingWater = position.y - (int) position.y <= fluidState.getHeight();
|
||||||
|
|
||||||
|
velocity.mul(isTouchingWater ? waterDrag : airDrag);
|
||||||
|
velocity.sub(0, gravity, 0);
|
||||||
|
|
||||||
|
if (position.y < mc.world.getBottomY()) return Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
double laseDistance = Math.sqrt(
|
||||||
|
(lastPosition.x - mc.player.getX()) * (lastPosition.x - mc.player.getX()) +
|
||||||
|
(lastPosition.z - mc.player.getZ()) * (lastPosition.z - mc.player.getZ())
|
||||||
|
);
|
||||||
|
|
||||||
|
double distance = Math.sqrt(
|
||||||
|
(position.x - mc.player.getX()) * (position.x - mc.player.getX()) +
|
||||||
|
(position.z - mc.player.getZ()) * (position.z - mc.player.getZ())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (distance > targetDistance) {
|
||||||
|
return MathHelper.lerp((targetDistance - laseDistance) / (distance - laseDistance), lastPosition.y, position.y) - targetPosition.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateAngle() {
|
||||||
if (targetEntity == null) return;
|
if (targetEntity == null) return;
|
||||||
|
|
||||||
float velocity = (mc.player.getItemUseTime() - mc.player.getItemUseTimeLeft()) / 20f;
|
// parabolic prediction
|
||||||
velocity = (velocity * velocity + velocity * 2) / 3;
|
if (predictionLevel.get() == 0) {
|
||||||
if (velocity > 1) velocity = 1;
|
double posX = targetEntity.getPos().getX();
|
||||||
|
double posY = targetEntity.getPos().getY();
|
||||||
|
double posZ = targetEntity.getPos().getZ();
|
||||||
|
|
||||||
double posX = targetEntity.getPos().getX() + (targetEntity.getPos().getX() - targetEntity.prevX) * tickDelta;
|
posY -= 1.9f - targetEntity.getHeight();
|
||||||
double posY = targetEntity.getPos().getY() + (targetEntity.getPos().getY() - targetEntity.prevY) * tickDelta;
|
|
||||||
double posZ = targetEntity.getPos().getZ() + (targetEntity.getPos().getZ() - targetEntity.prevZ) * tickDelta;
|
|
||||||
|
|
||||||
posY -= 1.9f - targetEntity.getHeight();
|
double relativeX = posX - mc.player.getX();
|
||||||
|
double relativeY = posY - mc.player.getY();
|
||||||
|
double relativeZ = posZ - mc.player.getZ();
|
||||||
|
|
||||||
double relativeX = posX - mc.player.getX();
|
double hDistance = Math.sqrt(relativeX * relativeX + relativeZ * relativeZ);
|
||||||
double relativeY = posY - mc.player.getY();
|
double hDistanceSq = hDistance * hDistance;
|
||||||
double relativeZ = posZ - mc.player.getZ();
|
float g = 0.006f;
|
||||||
|
float pitch = (float) -Math.toDegrees(Math.atan((1.0 - Math.sqrt(1.0 - g * (g * hDistanceSq + 2 * relativeY))) / (g * hDistance)));
|
||||||
|
|
||||||
double hDistance = Math.sqrt(relativeX * relativeX + relativeZ * relativeZ);
|
if (Float.isNaN(pitch)) {
|
||||||
double hDistanceSq = hDistance * hDistance;
|
targetYaw = Rotations.getYaw(targetEntity);
|
||||||
float g = 0.006f;
|
targetPitch = Rotations.getPitch(targetEntity);
|
||||||
float velocitySq = velocity * velocity;
|
} else {
|
||||||
float pitch = (float) -Math.toDegrees(Math.atan((velocitySq - Math.sqrt(velocitySq * velocitySq - g * (g * hDistanceSq + 2 * relativeY * velocitySq))) / (g * hDistance)));
|
targetYaw = Rotations.getYaw(targetEntity);
|
||||||
|
targetPitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
if (Float.isNaN(pitch)) {
|
targetCharge = 1.0;
|
||||||
targetYaw = Rotations.getYaw(targetEntity);
|
|
||||||
targetPitch = Rotations.getPitch(targetEntity);
|
calculatePath();
|
||||||
} else {
|
return;
|
||||||
targetYaw = Rotations.getYaw(new Vec3d(posX, posY, posZ));
|
}
|
||||||
targetPitch = pitch;
|
|
||||||
|
Vector3d targetPosition = new Vector3d(targetEntity.getX(), targetEntity.getY() + targetEntity.getHeight() / 2.0, targetEntity.getZ());
|
||||||
|
|
||||||
|
// Basic physics prediction
|
||||||
|
if (predictionLevel.get() == 1) {
|
||||||
|
// Solve for the highest pitch
|
||||||
|
double highestPitch;
|
||||||
|
{
|
||||||
|
double minPitch = -90.0;
|
||||||
|
double maxPitch = 90.0;
|
||||||
|
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
|
||||||
|
double mid1 = minPitch + (maxPitch - minPitch) / 3.0;
|
||||||
|
double mid2 = maxPitch - (maxPitch - minPitch) / 3.0;
|
||||||
|
double mid1Height = calculateHeightOffset(targetPosition, mid1);
|
||||||
|
double mid2Height = calculateHeightOffset(targetPosition, mid2);
|
||||||
|
if (Double.isNaN(mid1Height) || Double.isNaN(mid2Height)) return;
|
||||||
|
if (mid1Height < mid2Height)
|
||||||
|
minPitch = mid1;
|
||||||
|
else maxPitch = mid2;
|
||||||
|
}
|
||||||
|
highestPitch = (minPitch + maxPitch) / 2.0;
|
||||||
|
if (calculateHeightOffset(targetPosition, highestPitch) < 0.0) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solve for the low pitch
|
||||||
|
{
|
||||||
|
targetLowPitch = highestPitch;
|
||||||
|
double minPitch = highestPitch;
|
||||||
|
double maxPitch = 90.0;
|
||||||
|
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
|
||||||
|
double mid = (minPitch + maxPitch) / 2.0;
|
||||||
|
double midHeight = calculateHeightOffset(targetPosition, mid);
|
||||||
|
if (Double.isNaN(midHeight)) {
|
||||||
|
targetLowPitch = Double.NaN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (midHeight <= 0)
|
||||||
|
maxPitch = mid;
|
||||||
|
else minPitch = mid;
|
||||||
|
}
|
||||||
|
if (!Double.isNaN(targetLowPitch)) targetLowPitch = (minPitch + maxPitch) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Double.isNaN(targetLowPitch))
|
||||||
|
{
|
||||||
|
targetPitch = targetLowPitch;
|
||||||
|
targetYaw = Rotations.getYaw(targetEntity);
|
||||||
|
targetCharge = getCurrentCharge();
|
||||||
|
|
||||||
|
calculatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solve for the high pitch
|
||||||
|
if (!isHitTarget && allowHighThrows.get()) {
|
||||||
|
targetHighPitch = highestPitch;
|
||||||
|
double minPitch = -90.0;
|
||||||
|
double maxPitch = highestPitch;
|
||||||
|
for (int i = 0; iterationSteps.get() > 0 ? i < iterationSteps.get() : maxPitch - minPitch > iterationEpsilon.get(); i++) {
|
||||||
|
double mid = (minPitch + maxPitch) / 2.0;
|
||||||
|
double midHeight = calculateHeightOffset(targetPosition, mid);
|
||||||
|
if (Double.isNaN(midHeight)) {
|
||||||
|
targetHighPitch = Double.NaN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (midHeight <= 0)
|
||||||
|
minPitch = mid;
|
||||||
|
else maxPitch = mid;
|
||||||
|
}
|
||||||
|
if (!Double.isNaN(targetHighPitch)) targetHighPitch = (minPitch + maxPitch) / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHitTarget && !Double.isNaN(targetHighPitch) && allowHighThrows.get()) {
|
||||||
|
targetPitch = targetHighPitch;
|
||||||
|
targetYaw = Rotations.getYaw(targetEntity);
|
||||||
|
targetCharge = getCurrentCharge();
|
||||||
|
|
||||||
|
calculatePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user