Add parabolic prediction and auto-aiming

This commit is contained in:
Redstone1024 2024-08-27 16:10:26 +08:00
parent 2d79d78562
commit 5b4a9fb908

View File

@ -2,22 +2,34 @@ package com.example.addon.modules;
import com.example.addon.AddonTemplate;
import meteordevelopment.meteorclient.events.render.Render3DEvent;
import meteordevelopment.meteorclient.events.world.TickEvent;
import meteordevelopment.meteorclient.renderer.ShapeMode;
import meteordevelopment.meteorclient.settings.*;
import meteordevelopment.meteorclient.systems.friends.Friends;
import meteordevelopment.meteorclient.systems.modules.Module;
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;
import meteordevelopment.meteorclient.utils.player.Rotations;
import meteordevelopment.meteorclient.utils.render.color.SettingColor;
import meteordevelopment.orbit.EventHandler;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.BowItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
@ -27,12 +39,76 @@ import org.joml.Vector3d;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class Prediction extends Module {
private final SettingGroup sgGeneral = settings.getDefaultGroup();
private final SettingGroup sgTarget = settings.createGroup("Target");
private final SettingGroup sgSpeed = settings.createGroup("Aim Speed");
private final SettingGroup sgRender = settings.createGroup("Render");
public final Setting<Integer> simulationSteps = sgGeneral.add(new IntSetting.Builder()
private final Setting<Double> predictionLevel = sgGeneral.add(new DoubleSetting.Builder()
.name("prediction-level")
.description("The intelligence level for entity position prediction.")
.defaultValue(0)
.range(0, 0)
.sliderMax(0)
.build()
);
private final Setting<Boolean> aimAssist = sgGeneral.add(new BoolSetting.Builder()
.name("aim-assist")
.description("Automatically aims at entities.")
.defaultValue(true)
.build()
);
private final Setting<Double> range = sgTarget.add(new DoubleSetting.Builder()
.name("range")
.description("The maximum range the entity can be to aim at it.")
.defaultValue(32)
.range(0, 128)
.sliderMax(128)
.build()
);
private final Setting<Set<EntityType<?>>> entities = sgTarget.add(new EntityTypeListSetting.Builder()
.name("entities")
.description("Entities to attack.")
.defaultValue(EntityType.PLAYER)
.onlyAttackable()
.build()
);
private final Setting<SortPriority> priority = sgTarget.add(new EnumSetting.Builder<SortPriority>()
.name("priority")
.description("What type of entities to targetEntity.")
.defaultValue(SortPriority.LowestHealth)
.build()
);
private final Setting<Boolean> babies = sgTarget.add(new BoolSetting.Builder()
.name("babies")
.description("Whether or not to attack baby variants of the entity.")
.defaultValue(true)
.build()
);
private final Setting<Boolean> nametagged = sgTarget.add(new BoolSetting.Builder()
.name("nametagged")
.description("Whether or not to attack mobs with a name tag.")
.defaultValue(false)
.build()
);
private final Setting<Boolean> ignoreWalls = sgTarget.add(new BoolSetting.Builder()
.name("ignore-walls")
.description("Whether or not to ignore aiming through walls.")
.defaultValue(false)
.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)
@ -40,22 +116,121 @@ public class Prediction extends Module {
.build()
);
private final Setting<SettingColor> sideColor = sgRender.add(new ColorSetting.Builder()
.name("side-color")
.description("The side color.")
.defaultValue(new SettingColor(255, 150, 0, 35))
private final Setting<Boolean> instant = sgSpeed.add(new BoolSetting.Builder()
.name("instant-look")
.description("Instantly looks at the entity.")
.defaultValue(false)
.build()
);
private final Setting<SettingColor> lineColor = sgRender.add(new ColorSetting.Builder()
.name("line-color")
.description("The line color.")
private final Setting<Double> speed = sgSpeed.add(new DoubleSetting.Builder()
.name("speed")
.description("How fast to aim at the entity.")
.defaultValue(5)
.min(0)
.visible(() -> !instant.get())
.build()
);
private final Setting<Boolean> enableRender = sgRender.add(new BoolSetting.Builder()
.name("enable-render")
.description("Enable/Disable Render Indication.")
.defaultValue(true)
.build()
);
private final Setting<ShapeMode> shapeMode = sgRender.add(new EnumSetting.Builder<ShapeMode>()
.name("shape-mode")
.description("How the shapes are rendered.")
.defaultValue(ShapeMode.Both)
.visible(enableRender::get)
.build()
);
private final Setting<SettingColor> missSideColor = sgRender.add(new ColorSetting.Builder()
.name("miss-side-color")
.description("The side color for miss.")
.defaultValue(new SettingColor(255, 150, 0, 35))
.visible(enableRender::get)
.build()
);
private final Setting<SettingColor> missLineColor = sgRender.add(new ColorSetting.Builder()
.name("miss-line-color")
.description("The line color for miss.")
.defaultValue(new SettingColor(255, 150, 0))
.visible(enableRender::get)
.build()
);
private final Setting<SettingColor> hitSideColor = sgRender.add(new ColorSetting.Builder()
.name("hit-side-color")
.description("The side color for hit.")
.defaultValue(new SettingColor(128, 255, 0, 35))
.visible(enableRender::get)
.build()
);
private final Setting<SettingColor> hitLineColor = sgRender.add(new ColorSetting.Builder()
.name("hit-line-color")
.description("The line color for hit.")
.defaultValue(new SettingColor(128, 255, 0))
.visible(enableRender::get)
.build()
);
public Prediction() { super(AddonTemplate.CATEGORY, "bow-prediction", "Predicting arrow trajectories."); }
@Override
public void onDeactivate() {
targetEntity = null;
isHitTarget = false;
}
@EventHandler
private void onTick(TickEvent.Post event) { }
@EventHandler
private void onRender(Render3DEvent event) {
float tickDelta = mc.world.getTickManager().isFrozen() ? 1 : event.tickDelta;
if (mc.options.attackKey.isPressed() || !isSelectableTarget(targetEntity)) {
targetEntity = TargetUtils.get(this::isSelectableTarget, priority.get());
isHitTarget = false;
}
calculatePath(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);
}
@Override
public String getInfoString() {
return EntityUtils.getName(targetEntity);
}
private boolean isSelectableTarget(Entity entity) {
if (entity == null) return false;
if (entity == mc.player || entity == mc.cameraEntity) return false;
if ((entity instanceof LivingEntity && ((LivingEntity) entity).isDead()) || !entity.isAlive()) return false;
if (!PlayerUtils.isWithin(entity, range.get())) return false;
if (!entities.get().contains(entity.getType())) return false;
if (!nametagged.get() && entity.hasCustomName()) return false;
if (!ignoreWalls.get() && !PlayerUtils.canSeeEntity(entity)) return false;
if (entity instanceof PlayerEntity) {
if (((PlayerEntity) entity).isCreative()) return false;
if (!Friends.get().shouldAttack((PlayerEntity) entity)) return false;
}
return !(entity instanceof AnimalEntity) || babies.get() || !((AnimalEntity) entity).isBaby();
}
private Entity targetEntity;
private boolean isHitTarget;
private double targetYaw;
private double targetPitch;
private final Pool<Vector3d> vectorPool = new Pool<>(Vector3d::new);
private final List<Vector3d> points = new ArrayList<>();
private boolean hitQuad = false, hitQuadHorizontal = false;
@ -73,6 +248,7 @@ public class Prediction extends Module {
private void calculatePath(double tickDelta) {
clearPath();
isHitTarget = false;
ItemStack itemStack = mc.player.getMainHandStack();
if (!(itemStack.getItem() instanceof BowItem)) {
@ -193,6 +369,7 @@ public class Prediction extends Module {
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;
}
}
}
@ -200,13 +377,32 @@ public class Prediction extends Module {
private void renderPath(Render3DEvent event) {
Vector3d lastPoint = null;
for (Vector3d point : points) {
if (lastPoint != null) { event.renderer.line(lastPoint.x, lastPoint.y, lastPoint.z, point.x, point.y, point.z, lineColor.get()); }
if (lastPoint != null) {
event.renderer.line(
lastPoint.x, lastPoint.y, lastPoint.z, point.x, point.y, point.z,
isHitTarget ? hitLineColor.get() : missLineColor.get()
);
}
lastPoint = point;
}
if (hitQuad) {
if (hitQuadHorizontal) event.renderer.sideHorizontal(hitQuad1.x, hitQuad1.y, hitQuad1.z, hitQuad1.x + 0.5, hitQuad1.z + 0.5, sideColor.get(), lineColor.get(), ShapeMode.Both);
else event.renderer.sideVertical(hitQuad1.x, hitQuad1.y, hitQuad1.z, hitQuad2.x, hitQuad2.y, hitQuad2.z, sideColor.get(), lineColor.get(), ShapeMode.Both);
if (hitQuadHorizontal) {
event.renderer.sideHorizontal(
hitQuad1.x, hitQuad1.y, hitQuad1.z, hitQuad1.x + 0.5, hitQuad1.z + 0.5,
isHitTarget ? hitSideColor.get() : missSideColor.get(),
isHitTarget ? hitLineColor.get() : missLineColor.get(),
shapeMode.get()
);
}
else {
event.renderer.sideVertical(
hitQuad1.x, hitQuad1.y, hitQuad1.z, hitQuad2.x, hitQuad2.y, hitQuad2.z,
isHitTarget ? hitSideColor.get() : missSideColor.get(),
isHitTarget ? hitLineColor.get() : missLineColor.get(),
shapeMode.get()
);
}
}
if (collidingEntity != null) {
@ -215,15 +411,78 @@ public class Prediction extends Module {
double z = (collidingEntity.getZ() - collidingEntity.prevZ) * event.tickDelta;
Box box = collidingEntity.getBoundingBox();
event.renderer.box(x + box.minX, y + box.minY, z + box.minZ, x + box.maxX, y + box.maxY, z + box.maxZ, sideColor.get(), lineColor.get(), ShapeMode.Both, 0);
event.renderer.box(
x + box.minX, y + box.minY, z + box.minZ, x + box.maxX, y + box.maxY, z + box.maxZ,
isHitTarget ? hitSideColor.get() : missSideColor.get(),
isHitTarget ? hitLineColor.get() : missLineColor.get(),
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
);
}
}
@EventHandler
private void onRender(Render3DEvent event) {
float tickDelta = mc.world.getTickManager().isFrozen() ? 1 : event.tickDelta;
calculatePath(tickDelta);
renderPath(event);
private void calculateAngle(double tickDelta) {
if (targetEntity == null) return;
float velocity = (mc.player.getItemUseTime() - mc.player.getItemUseTimeLeft()) / 20f;
velocity = (velocity * velocity + velocity * 2) / 3;
if (velocity > 1) velocity = 1;
double posX = targetEntity.getPos().getX() + (targetEntity.getPos().getX() - targetEntity.prevX) * tickDelta;
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 hDistance = Math.sqrt(relativeX * relativeX + relativeZ * relativeZ);
double hDistanceSq = hDistance * hDistance;
float g = 0.006f;
float velocitySq = velocity * velocity;
float pitch = (float) -Math.toDegrees(Math.atan((velocitySq - Math.sqrt(velocitySq * velocitySq - g * (g * hDistanceSq + 2 * relativeY * velocitySq))) / (g * hDistance)));
if (Float.isNaN(pitch)) {
targetYaw = Rotations.getYaw(targetEntity);
targetPitch = Rotations.getPitch(targetEntity);
} else {
targetYaw = Rotations.getYaw(new Vec3d(posX, posY, posZ));
targetPitch = pitch;
}
}
private void aim(double tickDelta) {
if (targetEntity == null) return;
if (instant.get()) {
mc.player.setYaw((float) targetYaw);
} else {
double deltaAngle = MathHelper.wrapDegrees(targetYaw - 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) targetPitch);
} else {
double deltaAngle = MathHelper.wrapDegrees(targetPitch - mc.player.getPitch());
double toRotate = speed.get() * (deltaAngle >= 0 ? 1 : -1) * tickDelta;
if ((toRotate >= 0 && toRotate > deltaAngle) || (toRotate < 0 && toRotate < deltaAngle)) toRotate = deltaAngle;
mc.player.setPitch(mc.player.getPitch() + (float) toRotate);
}
}
}