diff --git a/src/main/java/com/example/addon/modules/Prediction.java b/src/main/java/com/example/addon/modules/Prediction.java index dc54da3..7a901ca 100644 --- a/src/main/java/com/example/addon/modules/Prediction.java +++ b/src/main/java/com/example/addon/modules/Prediction.java @@ -11,7 +11,6 @@ import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.meteorclient.utils.entity.EntityUtils; import meteordevelopment.meteorclient.utils.entity.SortPriority; import meteordevelopment.meteorclient.utils.entity.TargetUtils; -import meteordevelopment.meteorclient.utils.misc.MissHitResult; import meteordevelopment.meteorclient.utils.misc.Pool; import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.meteorclient.utils.player.PlayerUtils; @@ -49,8 +48,8 @@ public class Prediction extends Module { .name("prediction-level") .description("The intelligence level for entity position prediction.") .defaultValue(0) - .range(0, 2) - .sliderMax(2) + .range(0, 3) + .sliderMax(3) .build() ); @@ -90,6 +89,26 @@ public class Prediction extends Module { .build() ); + public final Setting speedSample = sgGeneral.add(new IntSetting.Builder() + .name("speed-sample") + .description("How many ticks are used to sample the speed.") + .defaultValue(4) + .sliderMin(0) + .sliderMax(20) + .visible(() -> predictionLevel.get() >= 2) + .build() + ); + + public final Setting directionSample = sgGeneral.add(new IntSetting.Builder() + .name("direction-sample") + .description("How many ticks are used to sample the direction.") + .defaultValue(1) + .sliderMin(0) + .sliderMax(20) + .visible(() -> predictionLevel.get() >= 2) + .build() + ); + public final Setting chargeOffset = sgGeneral.add(new IntSetting.Builder() .name("charge-offset") .description("What is the offset of the charge tick.") @@ -99,8 +118,8 @@ public class Prediction extends Module { .build() ); - public final Setting tickOffset = sgGeneral.add(new IntSetting.Builder() - .name("tick-offset") + public final Setting tickXZOffset = sgGeneral.add(new IntSetting.Builder() + .name("tick-x-z-offset") .description("What is the offset of the target tick.") .defaultValue(4) .sliderMin(0) @@ -109,6 +128,16 @@ public class Prediction extends Module { .build() ); + public final Setting tickYOffset = sgGeneral.add(new IntSetting.Builder() + .name("tick-y-offset") + .description("What is the offset of the target tick.") + .defaultValue(2) + .sliderMin(0) + .sliderMax(20) + .visible(() -> predictionLevel.get() >= 3) + .build() + ); + public final Setting dynamicMultiplier = sgGeneral.add(new BoolSetting.Builder() .name("dynamic-multiplier") .description("Whether to dynamically correct the target Tick multiplier.") @@ -140,6 +169,14 @@ public class Prediction extends Module { .build() ); + private final Setting aimOnlyPitch = sgGeneral.add(new BoolSetting.Builder() + .name("aim-only-pitch") + .description("Whether to target only through pitch.") + .defaultValue(false) + .visible(aimAssist::get) + .build() + ); + private final Setting range = sgTarget.add(new DoubleSetting.Builder() .name("range") .description("The maximum range the entity can be to aim at it.") @@ -411,24 +448,33 @@ public class Prediction extends Module { private class TargetContext { final Entity entity; int entityTick; - Vector3d lastPosition; int lastChargeTick; int lastPredictedTick; Vector3d lastPredictedPosition; double multiplier; + final List positionList; + // For dynamic multiplier - final List predictedTick = new ArrayList(); - final List originalPosition = new ArrayList(); - final List predictedPosition = new ArrayList(); + final List predictedTick = new ArrayList<>(); + final List originalPosition = new ArrayList<>(); + final List predictedPosition = new ArrayList<>(); TargetContext(Entity entity) { this.entity = entity; entityTick = 0; - lastPosition = new Vector3d(entity.getX(), entity.getY(), entity.getZ()); lastChargeTick = -1; - lastPredictedPosition = new Vector3d(lastPosition); + + lastPredictedPosition = new Vector3d( + entity.getBoundingBox().getCenter().x, + entity.getBoundingBox().getCenter().y, + entity.getBoundingBox().getCenter().z + ); + multiplier = 1.0; + + positionList = new ArrayList<>(); + positionList.add(new Vector3d(lastPredictedPosition)); } } @@ -447,21 +493,44 @@ public class Prediction extends Module { ++context.entityTick; + context.positionList.add( + new Vector3d( + context.entity.getBoundingBox().getCenter().x, + context.entity.getBoundingBox().getCenter().y, + context.entity.getBoundingBox().getCenter().z + ) + ); + + if (context.positionList.size() > 40) context.positionList.removeFirst(); + if (predictionLevel.get() >= 2) { Box lastTargetBox = mc.player.getBoundingBox(); if (chargeTick >= 3) { int predictedTick = -1; + double speed = 0.0; + int numSample = 0; + + for (; numSample < speedSample.get(); numSample++) { + if (context.positionList.size() - numSample - 2 < 0) break; + speed += new Vector3d( + context.positionList.get(context.positionList.size() - numSample - 1).x - context.positionList.get(context.positionList.size() - numSample - 2).x, + context.positionList.get(context.positionList.size() - numSample - 1).y - context.positionList.get(context.positionList.size() - numSample - 2).y, + context.positionList.get(context.positionList.size() - numSample - 1).z - context.positionList.get(context.positionList.size() - numSample - 2).z + ).length(); + } + + speed /= numSample; + + Vector3d velocity = new Vector3d(context.positionList.getLast()) + .sub(context.positionList.get(Math.max(context.positionList.size() - directionSample.get() - 1, 0))); + + if (velocity.length() > 1e-6) velocity.normalize().mul(speed); + for (int i = 0; simulationTargetSteps.get() > 0 ? i < simulationTargetSteps.get() : result.predicted.getCenter().distanceTo(lastTargetBox.getCenter()) > targetEpsilon.get(); i++) { - Vec3d velocity = new Vec3d( - context.entity.getBoundingBox().getCenter().x - context.lastPosition.x, - 0, - context.entity.getBoundingBox().getCenter().z - context.lastPosition.z - ); - AngleResult angleResult = calculateAngle(result.predicted, chargeTick); if (!angleResult.successed) { @@ -471,8 +540,60 @@ public class Prediction extends Module { PathResult pathResult = calculatePath(result.predicted, angleResult.yaw, angleResult.pitch, chargeTick, false, null); - predictedTick = pathResult.hitTick + tickOffset.get(); - result.predicted = context.entity.getBoundingBox().offset(velocity.multiply(predictedTick * context.multiplier)); + predictedTick = pathResult.hitTick; + + if (predictionLevel.get() == 2) { + result.predicted = context.entity.getBoundingBox().offset( + new Vec3d(velocity.x, velocity.y, velocity.z).multiply(1.0, 0.0, 1.0).multiply((predictedTick + tickXZOffset.get()) * context.multiplier) + ); + } + else { + Vector3d predictedOffset = new Vector3d(velocity).mul(1.0, 0.0, 1.0) + .mul((predictedTick + tickXZOffset.get()) * context.multiplier); + + for (int j = 0; j <= (predictedTick + tickYOffset.get()) * context.multiplier; ++j) { + predictedOffset.add(0.0, velocity.y, 0.0); + velocity.y *= 0.98; + velocity.y -= 0.08; + } + + predictedOffset.mul(context.multiplier); + + double[] raycastX = new double[] { + context.entity.getBoundingBox().minX, + context.entity.getBoundingBox().minX, + context.entity.getBoundingBox().maxX, + context.entity.getBoundingBox().maxX, + }; + + double[] raycastZ = new double[] { + context.entity.getBoundingBox().minZ, + context.entity.getBoundingBox().maxZ, + context.entity.getBoundingBox().minZ, + context.entity.getBoundingBox().maxZ, + }; + + for (int k = 0; k < 4; k++) { + HitResult hitResult = mc.world.raycast(new RaycastContext( + new Vec3d( + raycastX[k] + predictedOffset.x, + context.entity.getBoundingBox().minY, + raycastZ[k] + predictedOffset.z + ), + new Vec3d( + raycastX[k] + predictedOffset.x, + context.entity.getBoundingBox().minY + predictedOffset.y, + raycastZ[k] + predictedOffset.z + ), + RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player) + ); + + if (hitResult.getType() != HitResult.Type.MISS) + predictedOffset.y = Math.max(predictedOffset.y, hitResult.getPos().y - context.entity.getBoundingBox().minY); + } + + result.predicted = context.entity.getBoundingBox().offset(predictedOffset.x, predictedOffset.y, predictedOffset.z); + } } context.lastPredictedTick = predictedTick; @@ -482,7 +603,7 @@ public class Prediction extends Module { if (dynamicMultiplier.get()) { if (context.lastChargeTick >= 3 && context.lastChargeTick > chargeTick && chargeTick != -1 && context.lastPredictedTick != -1) { context.predictedTick.add(context.entityTick + context.lastPredictedTick); - context.originalPosition.add(new Vector3d(context.lastPosition)); + context.originalPosition.add(new Vector3d(context.positionList.get(context.positionList.size() - 2))); context.predictedPosition.add(new Vector3d(context.lastPredictedPosition)); } @@ -502,7 +623,6 @@ public class Prediction extends Module { } } - context.lastPosition.set(context.entity.getBoundingBox().getCenter().x, context.entity.getBoundingBox().getCenter().y, context.entity.getBoundingBox().getCenter().z); context.lastChargeTick = chargeTick; context.lastPredictedPosition.set(result.predicted.getCenter().x, result.predicted.getCenter().y, result.predicted.getCenter().z); } @@ -967,15 +1087,6 @@ public class Prediction extends Module { if (!mc.options.useKey.isPressed()) return; if (!InvUtils.testInHands(Items.BOW)) return; - if (instant.get()) { - mc.player.setYaw((float) aimData.yaw); - } else { - double deltaAngle = MathHelper.wrapDegrees(aimData.yaw - mc.player.getYaw()); - double toRotate = speed.get() * (deltaAngle >= 0 ? 1 : -1) * tickDelta; - if ((toRotate >= 0 && toRotate > deltaAngle) || (toRotate < 0 && toRotate < deltaAngle)) toRotate = deltaAngle; - mc.player.setYaw(mc.player.getYaw() + (float) toRotate); - } - if (instant.get()) { mc.player.setPitch((float) aimData.pitch); } else { @@ -984,5 +1095,16 @@ public class Prediction extends Module { if ((toRotate >= 0 && toRotate > deltaAngle) || (toRotate < 0 && toRotate < deltaAngle)) toRotate = deltaAngle; mc.player.setPitch(mc.player.getPitch() + (float) toRotate); } + + if (aimOnlyPitch.get()) return; + + if (instant.get()) { + mc.player.setYaw((float) aimData.yaw); + } else { + double deltaAngle = MathHelper.wrapDegrees(aimData.yaw - mc.player.getYaw()); + double toRotate = speed.get() * (deltaAngle >= 0 ? 1 : -1) * tickDelta; + if ((toRotate >= 0 && toRotate > deltaAngle) || (toRotate < 0 && toRotate < deltaAngle)) toRotate = deltaAngle; + mc.player.setYaw(mc.player.getYaw() + (float) toRotate); + } } }